You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

642 lines
20 KiB
JavaScript

import { Cartesian3 } from "../../Source/Cesium.js";
import { clone } from "../../Source/Cesium.js";
import { HeadingPitchRoll } from "../../Source/Cesium.js";
import { Math as CesiumMath } from "../../Source/Cesium.js";
import { Matrix3 } from "../../Source/Cesium.js";
import { Matrix4 } from "../../Source/Cesium.js";
import { Rectangle } from "../../Source/Cesium.js";
import { Transforms } from "../../Source/Cesium.js";
import { Cesium3DTile } from "../../Source/Cesium.js";
import { Cesium3DTilePass } from "../../Source/Cesium.js";
import { Cesium3DTileRefine } from "../../Source/Cesium.js";
import { Cesium3DTilesetHeatmap } from "../../Source/Cesium.js";
import { TileBoundingRegion } from "../../Source/Cesium.js";
import { TileOrientedBoundingBox } from "../../Source/Cesium.js";
import createScene from "../createScene.js";
describe(
"Scene/Cesium3DTile",
function () {
var tileWithBoundingSphere = {
geometricError: 1,
refine: "REPLACE",
children: [],
boundingVolume: {
sphere: [0.0, 0.0, 0.0, 5.0],
},
};
var tileWithContentBoundingSphere = {
geometricError: 1,
refine: "REPLACE",
content: {
url: "0/0.b3dm",
boundingVolume: {
sphere: [0.0, 0.0, 1.0, 5.0],
},
},
children: [],
boundingVolume: {
sphere: [0.0, 0.0, 1.0, 5.0],
},
};
var tileWithBoundingRegion = {
geometricError: 1,
refine: "REPLACE",
children: [],
boundingVolume: {
region: [-1.2, -1.2, 0.0, 0.0, -30, -34],
},
};
var tileWithContentBoundingRegion = {
geometricError: 1,
refine: "REPLACE",
children: [],
content: {
url: "0/0.b3dm",
boundingVolume: {
region: [-1.2, -1.2, 0, 0, -30, -34],
},
},
boundingVolume: {
region: [-1.2, -1.2, 0, 0, -30, -34],
},
};
var tileWithBoundingBox = {
geometricError: 1,
refine: "REPLACE",
children: [],
boundingVolume: {
box: [0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0],
},
};
var tileWithContentBoundingBox = {
geometricError: 1,
refine: "REPLACE",
children: [],
content: {
url: "0/0.b3dm",
boundingVolume: {
box: [0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 2.0],
},
},
boundingVolume: {
box: [0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 2.0],
},
};
var tileWithViewerRequestVolume = {
geometricError: 1,
refine: "REPLACE",
children: [],
boundingVolume: {
box: [0.0, 0.0, 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 2.0],
},
viewerRequestVolume: {
box: [0.0, 0.0, 1.0, 2.0, 0.0, 0.0, 0.0, 2.0, 0.0, 0.0, 0.0, 2.0],
},
};
var mockTileset = {
debugShowBoundingVolume: true,
debugShowViewerRequestVolume: true,
modelMatrix: Matrix4.IDENTITY,
_geometricError: 2,
_heatmap: new Cesium3DTilesetHeatmap(),
};
var centerLongitude = -1.31968;
var centerLatitude = 0.698874;
function getTileTransform(longitude, latitude) {
var transformCenter = Cartesian3.fromRadians(longitude, latitude, 0.0);
var hpr = new HeadingPitchRoll();
var transformMatrix = Transforms.headingPitchRollToFixedFrame(
transformCenter,
hpr
);
return Matrix4.pack(transformMatrix, new Array(16));
}
it("destroys", function () {
var tile = new Cesium3DTile(
mockTileset,
"/some_url",
tileWithBoundingSphere,
undefined
);
expect(tile.isDestroyed()).toEqual(false);
tile.destroy();
expect(tile.isDestroyed()).toEqual(true);
});
it("throws if boundingVolume is undefined", function () {
var tileWithoutBoundingVolume = clone(tileWithBoundingSphere, true);
delete tileWithoutBoundingVolume.boundingVolume;
expect(function () {
return new Cesium3DTile(
mockTileset,
"/some_url",
tileWithoutBoundingVolume,
undefined
);
}).toThrowRuntimeError();
});
it("throws if boundingVolume does not contain a sphere, region, or box", function () {
var tileWithoutBoundingVolume = clone(tileWithBoundingSphere, true);
delete tileWithoutBoundingVolume.boundingVolume.sphere;
expect(function () {
return new Cesium3DTile(
mockTileset,
"/some_url",
tileWithoutBoundingVolume,
undefined
);
}).toThrowRuntimeError();
});
it("logs deprecation warning if refine is lowercase", function () {
spyOn(Cesium3DTile, "_deprecationWarning");
var header = clone(tileWithBoundingSphere, true);
header.refine = "replace";
var tile = new Cesium3DTile(mockTileset, "/some_url", header, undefined);
expect(tile.refine).toBe(Cesium3DTileRefine.REPLACE);
expect(Cesium3DTile._deprecationWarning).toHaveBeenCalled();
});
it("logs deprecation warning if geometric error is undefined", function () {
spyOn(Cesium3DTile, "_deprecationWarning");
var geometricErrorMissing = clone(tileWithBoundingSphere, true);
delete geometricErrorMissing.geometricError;
var parent = new Cesium3DTile(
mockTileset,
"/some_url",
tileWithBoundingSphere,
undefined
);
var child = new Cesium3DTile(
mockTileset,
"/some_url",
geometricErrorMissing,
parent
);
expect(child.geometricError).toBe(parent.geometricError);
expect(child.geometricError).toBe(1);
var tile = new Cesium3DTile(
mockTileset,
"/some_url",
geometricErrorMissing,
undefined
);
expect(tile.geometricError).toBe(mockTileset._geometricError);
expect(tile.geometricError).toBe(2);
expect(Cesium3DTile._deprecationWarning.calls.count()).toBe(2);
});
describe("bounding volumes", function () {
it("returns the tile bounding volume if the content bounding volume is undefined", function () {
var tile = new Cesium3DTile(
mockTileset,
"/some_url",
tileWithBoundingSphere,
undefined
);
expect(tile.boundingVolume).toBeDefined();
expect(tile.contentBoundingVolume).toBe(tile.boundingVolume);
});
it("can have a bounding sphere", function () {
var tile = new Cesium3DTile(
mockTileset,
"/some_url",
tileWithBoundingSphere,
undefined
);
var radius = tileWithBoundingSphere.boundingVolume.sphere[3];
expect(tile.boundingVolume).toBeDefined();
expect(tile.boundingVolume.boundingVolume.radius).toEqual(radius);
expect(tile.boundingVolume.boundingVolume.center).toEqual(
Cartesian3.ZERO
);
});
it("can have a content bounding sphere", function () {
var tile = new Cesium3DTile(
mockTileset,
"/some_url",
tileWithContentBoundingSphere,
undefined
);
var radius =
tileWithContentBoundingSphere.content.boundingVolume.sphere[3];
expect(tile.contentBoundingVolume).toBeDefined();
expect(tile.contentBoundingVolume.boundingVolume.radius).toEqual(
radius
);
expect(tile.contentBoundingVolume.boundingVolume.center).toEqual(
new Cartesian3(0.0, 0.0, 1.0)
);
});
it("can have a bounding region", function () {
var box = tileWithBoundingRegion.boundingVolume.region;
var rectangle = new Rectangle(box[0], box[1], box[2], box[3]);
var minimumHeight = tileWithBoundingRegion.boundingVolume.region[4];
var maximumHeight = tileWithBoundingRegion.boundingVolume.region[5];
var tile = new Cesium3DTile(
mockTileset,
"/some_url",
tileWithBoundingRegion,
undefined
);
var tbr = new TileBoundingRegion({
rectangle: rectangle,
minimumHeight: minimumHeight,
maximumHeight: maximumHeight,
});
expect(tile.boundingVolume).toBeDefined();
expect(tile.boundingVolume).toEqual(tbr);
});
it("can have a content bounding region", function () {
var region =
tileWithContentBoundingRegion.content.boundingVolume.region;
var tile = new Cesium3DTile(
mockTileset,
"/some_url",
tileWithContentBoundingRegion,
undefined
);
expect(tile.contentBoundingVolume).toBeDefined();
var tbb = new TileBoundingRegion({
rectangle: new Rectangle(region[0], region[1], region[2], region[3]),
minimumHeight: region[4],
maximumHeight: region[5],
});
expect(tile.contentBoundingVolume).toEqual(tbb);
});
it("can have an oriented bounding box", function () {
var box = tileWithBoundingBox.boundingVolume.box;
var tile = new Cesium3DTile(
mockTileset,
"/some_url",
tileWithBoundingBox,
undefined
);
expect(tile.boundingVolume).toBeDefined();
var center = new Cartesian3(box[0], box[1], box[2]);
var halfAxes = Matrix3.fromArray(box, 3);
var obb = new TileOrientedBoundingBox(center, halfAxes);
expect(tile.boundingVolume).toEqual(obb);
});
it("does not crash for bounding box with 0 volume", function () {
// Create a copy of the tile with bounding box.
var tileWithBoundingBox0Volume = JSON.parse(
JSON.stringify(tileWithBoundingBox)
);
// Generate all the combinations of missing axes.
var boxes = [];
for (var x = 0; x < 2; ++x) {
for (var y = 0; y < 2; ++y) {
for (var z = 0; z < 2; ++z) {
boxes.push([
0.0,
0.0,
0.0,
x,
0.0,
0.0,
0.0,
y,
0.0,
0.0,
0.0,
z,
]);
}
}
}
for (var i = 0; i < boxes.length; ++i) {
var box = boxes[i];
tileWithBoundingBox0Volume.boundingVolume.box = box;
var tile = new Cesium3DTile(
mockTileset,
"/some_url",
tileWithBoundingBox0Volume,
undefined
);
expect(tile.boundingVolume).toBeDefined();
var center = new Cartesian3(box[0], box[1], box[2]);
var halfAxes = Matrix3.fromArray(box, 3);
var obb = new TileOrientedBoundingBox(center, halfAxes);
expect(tile.boundingVolume).toEqual(obb);
}
});
it("can have a content oriented bounding box", function () {
var box = tileWithContentBoundingBox.boundingVolume.box;
var tile = new Cesium3DTile(
mockTileset,
"/some_url",
tileWithContentBoundingBox,
undefined
);
expect(tile.contentBoundingVolume).toBeDefined();
var center = new Cartesian3(box[0], box[1], box[2]);
var halfAxes = Matrix3.fromArray(box, 3);
var obb = new TileOrientedBoundingBox(center, halfAxes);
expect(tile.contentBoundingVolume).toEqual(obb);
});
it("tile transform affects bounding sphere", function () {
var header = clone(tileWithContentBoundingSphere, true);
header.transform = getTileTransform(centerLongitude, centerLatitude);
var tile = new Cesium3DTile(
mockTileset,
"/some_url",
header,
undefined
);
var boundingSphere = tile.boundingVolume.boundingVolume;
var contentBoundingSphere = tile.contentBoundingVolume.boundingVolume;
var boundingVolumeCenter = Cartesian3.fromRadians(
centerLongitude,
centerLatitude,
1.0
);
expect(boundingSphere.center).toEqualEpsilon(
boundingVolumeCenter,
CesiumMath.EPSILON4
);
expect(boundingSphere.radius).toEqual(5.0); // No change
expect(contentBoundingSphere.center).toEqualEpsilon(
boundingVolumeCenter,
CesiumMath.EPSILON4
);
expect(contentBoundingSphere.radius).toEqual(5.0); // No change
});
it("tile transform affects oriented bounding box", function () {
var header = clone(tileWithContentBoundingBox, true);
header.transform = getTileTransform(centerLongitude, centerLatitude);
var tile = new Cesium3DTile(
mockTileset,
"/some_url",
header,
undefined
);
var boundingBox = tile.boundingVolume.boundingVolume;
var contentBoundingBox = tile.contentBoundingVolume.boundingVolume;
var boundingVolumeCenter = Cartesian3.fromRadians(
centerLongitude,
centerLatitude,
1.0
);
expect(boundingBox.center).toEqualEpsilon(
boundingVolumeCenter,
CesiumMath.EPSILON7
);
expect(contentBoundingBox.center).toEqualEpsilon(
boundingVolumeCenter,
CesiumMath.EPSILON7
);
});
it("tile transform does not affect bounding region", function () {
var header = clone(tileWithContentBoundingRegion, true);
header.transform = getTileTransform(centerLongitude, centerLatitude);
var tile = new Cesium3DTile(
mockTileset,
"/some_url",
header,
undefined
);
var boundingRegion = tile.boundingVolume;
var contentBoundingRegion = tile.contentBoundingVolume;
var region = header.boundingVolume.region;
var rectangle = Rectangle.unpack(region);
expect(boundingRegion.rectangle).toEqual(rectangle);
expect(contentBoundingRegion.rectangle).toEqual(rectangle);
});
it("tile transform affects viewer request volume", function () {
var header = clone(tileWithViewerRequestVolume, true);
header.transform = getTileTransform(centerLongitude, centerLatitude);
var tile = new Cesium3DTile(
mockTileset,
"/some_url",
header,
undefined
);
var requestVolume = tile._viewerRequestVolume.boundingVolume;
var requestVolumeCenter = Cartesian3.fromRadians(
centerLongitude,
centerLatitude,
1.0
);
expect(requestVolume.center).toEqualEpsilon(
requestVolumeCenter,
CesiumMath.EPSILON7
);
});
it("tile transform changes", function () {
var mockTileset = {
modelMatrix: Matrix4.IDENTITY,
};
var header = clone(tileWithBoundingSphere, true);
header.transform = getTileTransform(centerLongitude, centerLatitude);
var tile = new Cesium3DTile(
mockTileset,
"/some_url",
header,
undefined
);
var boundingSphere = tile.boundingVolume.boundingVolume;
// Check the original transform
var boundingVolumeCenter = Cartesian3.fromRadians(
centerLongitude,
centerLatitude
);
expect(boundingSphere.center).toEqualEpsilon(
boundingVolumeCenter,
CesiumMath.EPSILON7
);
// Change the transform
var newLongitude = -1.012;
var newLatitude = 0.698874;
tile.transform = getTileTransform(newLongitude, newLatitude);
tile.updateTransform();
// Check the new transform
var newCenter = Cartesian3.fromRadians(newLongitude, newLatitude);
expect(boundingSphere.center).toEqualEpsilon(
newCenter,
CesiumMath.EPSILON7
);
});
});
describe("debug bounding volumes", function () {
var scene;
beforeEach(function () {
scene = createScene();
scene.frameState.passes.render = true;
});
afterEach(function () {
scene.destroyForSpecs();
});
it("can be a bounding region", function () {
var tile = new Cesium3DTile(
mockTileset,
"/some_url",
tileWithBoundingRegion,
undefined
);
var passOptions = Cesium3DTilePass.getPassOptions(
Cesium3DTilePass.RENDER
);
tile.update(mockTileset, scene.frameState, passOptions);
expect(tile._debugBoundingVolume).toBeDefined();
});
it("can be an oriented bounding box", function () {
var tile = new Cesium3DTile(
mockTileset,
"/some_url",
tileWithBoundingBox,
undefined
);
var passOptions = Cesium3DTilePass.getPassOptions(
Cesium3DTilePass.RENDER
);
tile.update(mockTileset, scene.frameState, passOptions);
expect(tile._debugBoundingVolume).toBeDefined();
});
it("can be a bounding sphere", function () {
var tile = new Cesium3DTile(
mockTileset,
"/some_url",
tileWithBoundingSphere,
undefined
);
var passOptions = Cesium3DTilePass.getPassOptions(
Cesium3DTilePass.RENDER
);
tile.update(mockTileset, scene.frameState, passOptions);
expect(tile._debugBoundingVolume).toBeDefined();
});
it("creates debug bounding volume for viewer request volume", function () {
var tile = new Cesium3DTile(
mockTileset,
"/some_url",
tileWithViewerRequestVolume,
undefined
);
var passOptions = Cesium3DTilePass.getPassOptions(
Cesium3DTilePass.RENDER
);
tile.update(mockTileset, scene.frameState, passOptions);
expect(tile._debugViewerRequestVolume).toBeDefined();
});
});
it("updates priority", function () {
var tile1 = new Cesium3DTile(
mockTileset,
"/some_url",
tileWithBoundingSphere,
undefined
);
tile1._priorityHolder = tile1;
tile1._foveatedFactor = 0.0;
tile1._distanceToCamera = 1.0;
tile1._depth = 0.0;
tile1._priorityProgressiveResolution = true;
var tile2 = new Cesium3DTile(
mockTileset,
"/some_url",
tileWithBoundingSphere,
undefined
);
tile2._priorityHolder = tile1;
tile2._foveatedFactor = 1.0; // foveatedFactor (when considered for priority in certain modes) is actually 0 since its linked up to tile1
tile2._distanceToCamera = 0.0;
tile2._depth = 1.0;
tile2._priorityProgressiveResolution = true;
mockTileset._minimumPriority = {
depth: 0.0,
distance: 0.0,
foveatedFactor: 0.0,
};
mockTileset._maximumPriority = {
depth: 1.0,
distance: 1.0,
foveatedFactor: 1.0,
};
tile1.updatePriority();
tile2.updatePriority();
var nonPreloadFlightPenalty = 10000000000.0;
var tile1ExpectedPriority = nonPreloadFlightPenalty + 0.0;
var tile2ExpectedPriority = nonPreloadFlightPenalty + 1.0;
expect(
CesiumMath.equalsEpsilon(
tile1._priority,
tile1ExpectedPriority,
CesiumMath.EPSILON2
)
).toBe(true);
expect(
CesiumMath.equalsEpsilon(
tile2._priority,
tile2ExpectedPriority,
CesiumMath.EPSILON2
)
).toBe(true);
// Penalty for not being a progressive resolution
tile2._priorityProgressiveResolution = false;
tile2.updatePriority();
var nonProgressiveResoutionPenalty = 100000000.0;
expect(tile2._priority).toBeGreaterThan(nonProgressiveResoutionPenalty);
tile2._priorityProgressiveResolution = true;
// Penalty for being a foveated deferral
tile2.priorityDeferred = true;
tile2.updatePriority();
var foveatedDeferralPenalty = 10000000.0;
expect(tile2._priority).toBeGreaterThanOrEqualTo(foveatedDeferralPenalty);
tile2._priorityDeferred = false;
});
},
"WebGL"
);