import { BoundingSphere } from "../../Source/Cesium.js"; import { Cartesian2 } from "../../Source/Cesium.js"; import { Cartesian3 } from "../../Source/Cesium.js"; import { Color } from "../../Source/Cesium.js"; import { defined } from "../../Source/Cesium.js"; import { DistanceDisplayCondition } from "../../Source/Cesium.js"; import { JulianDate } from "../../Source/Cesium.js"; import { Math as CesiumMath } from "../../Source/Cesium.js"; import { Matrix4 } from "../../Source/Cesium.js"; import { Quaternion } from "../../Source/Cesium.js"; import { Resource } from "../../Source/Cesium.js"; import { Transforms } from "../../Source/Cesium.js"; import { BoundingSphereState } from "../../Source/Cesium.js"; import { ConstantPositionProperty } from "../../Source/Cesium.js"; import { ConstantProperty } from "../../Source/Cesium.js"; import { EntityCollection } from "../../Source/Cesium.js"; import { ModelGraphics } from "../../Source/Cesium.js"; import { ModelVisualizer } from "../../Source/Cesium.js"; import { NodeTransformationProperty } from "../../Source/Cesium.js"; import { ClippingPlane } from "../../Source/Cesium.js"; import { ClippingPlaneCollection } from "../../Source/Cesium.js"; import { Globe } from "../../Source/Cesium.js"; import createScene from "../createScene.js"; import pollToPromise from "../pollToPromise.js"; describe( "DataSources/ModelVisualizer", function () { var boxUrl = "./Data/Models/Box/CesiumBoxTest.gltf"; var boxArticulationsUrl = "./Data/Models/Box-Articulations/Box-Articulations.gltf"; var scene; var visualizer; beforeAll(function () { scene = createScene(); scene.globe = new Globe(); }); afterAll(function () { scene.destroyForSpecs(); }); afterEach(function () { if (defined(visualizer)) { visualizer = visualizer.destroy(); } }); it("constructor throws if no scene is passed.", function () { expect(function () { return new ModelVisualizer(); }).toThrowDeveloperError(); }); it("update throws if no time specified.", function () { var entityCollection = new EntityCollection(); visualizer = new ModelVisualizer(scene, entityCollection); expect(function () { visualizer.update(); }).toThrowDeveloperError(); }); it("isDestroy returns false until destroyed.", function () { var entityCollection = new EntityCollection(); visualizer = new ModelVisualizer(scene, entityCollection); expect(visualizer.isDestroyed()).toEqual(false); visualizer.destroy(); expect(visualizer.isDestroyed()).toEqual(true); visualizer = undefined; }); it("removes the listener from the entity collection when destroyed", function () { var entityCollection = new EntityCollection(); visualizer = new ModelVisualizer(scene, entityCollection); expect(entityCollection.collectionChanged.numberOfListeners).toEqual(1); visualizer.destroy(); expect(entityCollection.collectionChanged.numberOfListeners).toEqual(0); visualizer = undefined; }); it("object with no model does not create one.", function () { var entityCollection = new EntityCollection(); visualizer = new ModelVisualizer(scene, entityCollection); var testObject = entityCollection.getOrCreateEntity("test"); testObject.position = new ConstantProperty( new Cartesian3(1234, 5678, 9101112) ); visualizer.update(JulianDate.now()); expect(scene.primitives.length).toEqual(0); }); it("object with no position does not create a model.", function () { var entityCollection = new EntityCollection(); visualizer = new ModelVisualizer(scene, entityCollection); var testObject = entityCollection.getOrCreateEntity("test"); var model = (testObject.model = new ModelGraphics()); model.uri = new ConstantProperty(boxUrl); visualizer.update(JulianDate.now()); expect(scene.primitives.length).toEqual(0); }); it("A ModelGraphics causes a primitive to be created and updated.", function () { var time = JulianDate.now(); var entityCollection = new EntityCollection(); visualizer = new ModelVisualizer(scene, entityCollection); var model = new ModelGraphics(); model.show = new ConstantProperty(true); model.scale = new ConstantProperty(2); model.minimumPixelSize = new ConstantProperty(24.0); model.uri = new ConstantProperty(boxUrl); model.distanceDisplayCondition = new ConstantProperty( new DistanceDisplayCondition(10.0, 100.0) ); var translation = new Cartesian3(1.0, 2.0, 3.0); var rotation = new Quaternion(0.0, 0.707, 0.0, 0.707); var scale = new Cartesian3(2.0, 2.0, 2.0); var nodeTransforms = { Mesh: new NodeTransformationProperty({ translation: new ConstantProperty(translation), rotation: new ConstantProperty(rotation), scale: new ConstantProperty(scale), }), }; model.nodeTransformations = nodeTransforms; var clippingPlanes = new ClippingPlaneCollection({ planes: [new ClippingPlane(Cartesian3.UNIT_X, 0.0)], }); model.clippingPlanes = new ConstantProperty(clippingPlanes); model.imageBasedLightingFactor = new ConstantProperty( new Cartesian2(0.5, 0.5) ); model.lightColor = new ConstantProperty(new Color(1.0, 1.0, 0.0, 1.0)); var testObject = entityCollection.getOrCreateEntity("test"); testObject.position = new ConstantPositionProperty( Cartesian3.fromDegrees(1, 2, 3) ); testObject.model = model; visualizer.update(time); expect(scene.primitives.length).toEqual(1); var primitive = scene.primitives.get(0); visualizer.update(time); expect(primitive.show).toEqual(true); expect(primitive.scale).toEqual(2); expect(primitive.minimumPixelSize).toEqual(24.0); expect(primitive.modelMatrix).toEqual( Transforms.eastNorthUpToFixedFrame( Cartesian3.fromDegrees(1, 2, 3), scene.globe.ellipsoid ) ); expect(primitive.distanceDisplayCondition).toEqual( new DistanceDisplayCondition(10.0, 100.0) ); expect(primitive.clippingPlanes._planes.length).toEqual( clippingPlanes._planes.length ); expect( Cartesian3.equals( primitive.clippingPlanes._planes[0].normal, clippingPlanes._planes[0].normal ) ).toBe(true); expect(primitive.clippingPlanes._planes[0].distance).toEqual( clippingPlanes._planes[0].distance ); expect(primitive.imageBasedLightingFactor).toEqual( new Cartesian2(0.5, 0.5) ); expect(primitive.lightColor).toEqual(new Color(1.0, 1.0, 0.0, 1.0)); // wait till the model is loaded before we can check node transformations return pollToPromise(function () { scene.render(); return primitive.ready; }).then(function () { visualizer.update(time); var node = primitive.getNode("Mesh"); expect(node).toBeDefined(); var transformationMatrix = Matrix4.fromTranslationQuaternionRotationScale( translation, rotation, scale ); expect(node.matrix).toEqual(transformationMatrix); }); }); it("can apply model articulations", function () { var time = JulianDate.now(); var entityCollection = new EntityCollection(); visualizer = new ModelVisualizer(scene, entityCollection); var model = new ModelGraphics(); model.uri = new ConstantProperty(boxArticulationsUrl); var articulations = { "SampleArticulation MoveX": 1.0, "SampleArticulation MoveY": 2.0, "SampleArticulation MoveZ": 3.0, "SampleArticulation Yaw": 4.0, "SampleArticulation Pitch": 5.0, "SampleArticulation Roll": 6.0, "SampleArticulation Size": 0.9, "SampleArticulation SizeX": 0.8, "SampleArticulation SizeY": 0.7, "SampleArticulation SizeZ": 0.6, }; model.articulations = articulations; var testObject = entityCollection.getOrCreateEntity("test"); testObject.position = new ConstantPositionProperty( Cartesian3.fromDegrees(1, 2, 3) ); testObject.model = model; visualizer.update(time); expect(scene.primitives.length).toEqual(1); var primitive = scene.primitives.get(0); // wait till the model is loaded before we can check articulations return pollToPromise(function () { scene.render(); return primitive.ready; }).then(function () { visualizer.update(time); var node = primitive.getNode("Root"); expect(node.useMatrix).toBe(true); var expected = [ 0.7147690483240505, -0.04340611926232735, -0.0749741046529782, 0, -0.06188330295778636, 0.05906797312763484, -0.6241645867602773, 0, 0.03752515582279579, 0.5366347296529127, 0.04706410108373541, 0, 1, 3, -2, 1, ]; expect(node.matrix).toEqualEpsilon(expected, CesiumMath.EPSILON14); }); }); it("A ModelGraphics with a Resource causes a primitive to be created.", function () { var time = JulianDate.now(); var entityCollection = new EntityCollection(); visualizer = new ModelVisualizer(scene, entityCollection); var model = new ModelGraphics(); model.show = new ConstantProperty(true); model.uri = new ConstantProperty( new Resource({ url: boxUrl, }) ); var testObject = entityCollection.getOrCreateEntity("test"); testObject.position = new ConstantPositionProperty( Cartesian3.fromDegrees(1, 2, 3) ); testObject.model = model; visualizer.update(time); expect(scene.primitives.length).toEqual(1); var primitive = scene.primitives.get(0); // wait till the model is loaded before we can check node transformations return pollToPromise(function () { scene.render(); return primitive.ready; }).then(function () { visualizer.update(time); var node = primitive.getNode("Mesh"); expect(node).toBeDefined(); }); }); it("removing removes primitives.", function () { var entityCollection = new EntityCollection(); visualizer = new ModelVisualizer(scene, entityCollection); var model = new ModelGraphics(); model.uri = new ConstantProperty(boxUrl); var time = JulianDate.now(); var testObject = entityCollection.getOrCreateEntity("test"); testObject.position = new ConstantProperty( new Cartesian3(5678, 1234, 1101112) ); testObject.model = model; visualizer.update(time); expect(scene.primitives.length).toEqual(1); visualizer.update(time); entityCollection.removeAll(); visualizer.update(time); expect(scene.primitives.length).toEqual(0); }); it("Visualizer sets id property.", function () { var entityCollection = new EntityCollection(); visualizer = new ModelVisualizer(scene, entityCollection); var time = JulianDate.now(); var testObject = entityCollection.getOrCreateEntity("test"); var model = new ModelGraphics(); testObject.model = model; testObject.position = new ConstantProperty( new Cartesian3(5678, 1234, 1101112) ); model.uri = new ConstantProperty(boxUrl); visualizer.update(time); var modelPrimitive = scene.primitives.get(0); expect(modelPrimitive.id).toEqual(testObject); }); it("Computes bounding sphere.", function () { var entityCollection = new EntityCollection(); visualizer = new ModelVisualizer(scene, entityCollection); var time = JulianDate.now(); var testObject = entityCollection.getOrCreateEntity("test"); var model = new ModelGraphics(); testObject.model = model; testObject.position = new ConstantProperty( new Cartesian3(5678, 1234, 1101112) ); model.uri = new ConstantProperty(boxUrl); visualizer.update(time); var modelPrimitive = scene.primitives.get(0); var result = new BoundingSphere(); var state = visualizer.getBoundingSphere(testObject, result); expect(state).toBe(BoundingSphereState.PENDING); return pollToPromise(function () { scene.render(); state = visualizer.getBoundingSphere(testObject, result); return state !== BoundingSphereState.PENDING; }).then(function () { expect(state).toBe(BoundingSphereState.DONE); var expected = BoundingSphere.transform( modelPrimitive.boundingSphere, modelPrimitive.modelMatrix, new BoundingSphere() ); expect(result).toEqual(expected); }); }); it("Fails bounding sphere for entity without billboard.", function () { var entityCollection = new EntityCollection(); var testObject = entityCollection.getOrCreateEntity("test"); visualizer = new ModelVisualizer(scene, entityCollection); visualizer.update(JulianDate.now()); var result = new BoundingSphere(); var state = visualizer.getBoundingSphere(testObject, result); expect(state).toBe(BoundingSphereState.FAILED); }); it("Fails bounding sphere when model fails to load.", function () { var entityCollection = new EntityCollection(); visualizer = new ModelVisualizer(scene, entityCollection); var time = JulianDate.now(); var testObject = entityCollection.getOrCreateEntity("test"); var model = new ModelGraphics(); testObject.model = model; testObject.position = new ConstantProperty( new Cartesian3(5678, 1234, 1101112) ); model.uri = new ConstantProperty("/path/to/incorrect/file"); visualizer.update(time); var result = new BoundingSphere(); var state = visualizer.getBoundingSphere(testObject, result); expect(state).toBe(BoundingSphereState.PENDING); return pollToPromise(function () { scene.render(); state = visualizer.getBoundingSphere(testObject, result); return state !== BoundingSphereState.PENDING; }).then(function () { expect(state).toBe(BoundingSphereState.FAILED); }); }); it("Compute bounding sphere throws without entity.", function () { var entityCollection = new EntityCollection(); visualizer = new ModelVisualizer(scene, entityCollection); var result = new BoundingSphere(); expect(function () { visualizer.getBoundingSphere(undefined, result); }).toThrowDeveloperError(); }); it("Compute bounding sphere throws without result.", function () { var entityCollection = new EntityCollection(); var testObject = entityCollection.getOrCreateEntity("test"); visualizer = new ModelVisualizer(scene, entityCollection); expect(function () { visualizer.getBoundingSphere(testObject, undefined); }).toThrowDeveloperError(); }); }, "WebGL" );