import { Cartesian3 } from "../../Source/Cesium.js"; import { Cartographic } from "../../Source/Cesium.js"; import { Color } from "../../Source/Cesium.js"; import { Ellipsoid } from "../../Source/Cesium.js"; import { FeatureDetection } from "../../Source/Cesium.js"; import { GeometryInstance } from "../../Source/Cesium.js"; import { Math as CesiumMath } from "../../Source/Cesium.js"; import { Matrix4 } from "../../Source/Cesium.js"; import { OrthographicFrustum } from "../../Source/Cesium.js"; import { PerspectiveFrustum } from "../../Source/Cesium.js"; import { Ray } from "../../Source/Cesium.js"; import { Rectangle } from "../../Source/Cesium.js"; import { RectangleGeometry } from "../../Source/Cesium.js"; import { ShowGeometryInstanceAttribute } from "../../Source/Cesium.js"; import { Transforms } from "../../Source/Cesium.js"; import { Cesium3DTileStyle } from "../../Source/Cesium.js"; import { EllipsoidSurfaceAppearance } from "../../Source/Cesium.js"; import { Globe } from "../../Source/Cesium.js"; import { PointPrimitiveCollection } from "../../Source/Cesium.js"; import { Primitive } from "../../Source/Cesium.js"; import { SceneMode } from "../../Source/Cesium.js"; import Cesium3DTilesTester from "../Cesium3DTilesTester.js"; import createCanvas from "../createCanvas.js"; import createScene from "../createScene.js"; import pollToPromise from "../pollToPromise.js"; import { when } from "../../Source/Cesium.js"; describe( "Scene/Pick", function () { // It's not easily possible to mock the most detailed pick functions // so don't run those tests when using the WebGL stub var webglStub = !!window.webglStub; var scene; var primitives; var camera; var largeRectangle = Rectangle.fromDegrees(-1.0, -1.0, 1.0, 1.0); var smallRectangle = Rectangle.fromDegrees( -0.0001, -0.0001, 0.0001, 0.0001 ); var offscreenRectangle = Rectangle.fromDegrees( -45.0002, -1.0002, -45.0001, -1.0001 ); var primitiveRay; var offscreenRay; var batchedTilesetUrl = "Data/Cesium3DTiles/Batched/BatchedWithTransformBox/tileset.json"; var pointCloudTilesetUrl = "Data/Cesium3DTiles/PointCloud/PointCloudWithTransform/tileset.json"; beforeAll(function () { scene = createScene({ canvas: createCanvas(10, 10), }); primitives = scene.primitives; camera = scene.camera; camera.setView({ destination: largeRectangle, }); primitiveRay = new Ray(camera.positionWC, camera.directionWC); camera.setView({ destination: offscreenRectangle, }); offscreenRay = new Ray(camera.positionWC, camera.directionWC); }); afterAll(function () { scene.destroyForSpecs(); }); beforeEach(function () { scene.mode = SceneMode.SCENE3D; scene.morphTime = SceneMode.getMorphTime(scene.mode); camera.setView({ destination: largeRectangle, }); camera.frustum = new PerspectiveFrustum(); camera.frustum.fov = CesiumMath.toRadians(60.0); camera.frustum.aspectRatio = 1.0; }); afterEach(function () { primitives.removeAll(); scene.globe = undefined; }); function createRectangle(height, rectangle) { var e = new Primitive({ geometryInstances: new GeometryInstance({ geometry: new RectangleGeometry({ rectangle: rectangle, vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT, granularity: CesiumMath.toRadians(20.0), height: height, }), }), appearance: new EllipsoidSurfaceAppearance({ aboveGround: false, }), asynchronous: false, }); primitives.add(e); return e; } function createLargeRectangle(height) { return createRectangle(height, largeRectangle); } function createSmallRectangle(height) { return createRectangle(height, smallRectangle); } function createTileset(url) { var options = { maximumScreenSpaceError: 0, }; return Cesium3DTilesTester.loadTileset(scene, url, options).then( function (tileset) { var cartographic = Rectangle.center(largeRectangle); var cartesian = Cartographic.toCartesian(cartographic); tileset.root.transform = Matrix4.IDENTITY; tileset.modelMatrix = Transforms.eastNorthUpToFixedFrame(cartesian); return Cesium3DTilesTester.waitForTilesLoaded(scene, tileset); } ); } function createGlobe() { var globe = new Globe(); scene.globe = globe; globe.depthTestAgainstTerrain = true; return pollToPromise(function () { scene.render(); return globe.tilesLoaded; }); } describe("pick", function () { it("does not pick undefined window positions", function () { expect(function () { scene.pick(undefined); }).toThrowDeveloperError(); }); it("picks a primitive", function () { if (FeatureDetection.isInternetExplorer()) { // Workaround IE 11.0.9. This test fails when all tests are ran without a breakpoint here. return; } var rectangle = createLargeRectangle(0.0); expect(scene).toPickPrimitive(rectangle); }); it("picks a primitive with a modified pick search area", function () { if (FeatureDetection.isInternetExplorer()) { // Workaround IE 11.0.9. This test fails when all tests are ran without a breakpoint here. return; } camera.setView({ destination: Rectangle.fromDegrees(-10.0, -10.0, 10.0, 10.0), }); var rectangle = createLargeRectangle(0.0); expect(scene).toPickPrimitive(rectangle, 7, 7, 5); expect(scene).notToPick(7, 7, 3); }); it("does not pick primitives when show is false", function () { var rectangle = createLargeRectangle(0.0); rectangle.show = false; expect(scene).notToPick(); }); it("does not pick primitives when alpha is zero", function () { var rectangle = createLargeRectangle(0.0); rectangle.appearance.material.uniforms.color.alpha = 0.0; expect(scene).notToPick(); }); it("picks the top primitive", function () { createLargeRectangle(0.0); var rectangle2 = createLargeRectangle(1.0); expect(scene).toPickPrimitive(rectangle2); }); it("picks in 2D", function () { scene.morphTo2D(0.0); camera.setView({ destination: largeRectangle }); var rectangle = createLargeRectangle(0.0); scene.renderForSpecs(); expect(scene).toPickPrimitive(rectangle); }); it("picks in 3D with orthographic projection", function () { var frustum = new OrthographicFrustum(); frustum.aspectRatio = 1.0; frustum.width = 20.0; camera.frustum = frustum; // force off center update expect(frustum.projectionMatrix).toBeDefined(); camera.setView({ destination: largeRectangle }); var rectangle = createLargeRectangle(0.0); scene.renderForSpecs(); expect(scene).toPickPrimitive(rectangle); }); }); describe("drillPick", function () { it("drill picks a primitive with a modified pick search area", function () { if (FeatureDetection.isInternetExplorer()) { // Workaround IE 11.0.9. This test fails when all tests are ran without a breakpoint here. return; } camera.setView({ destination: Rectangle.fromDegrees(-10.0, -10.0, 10.0, 10.0), }); var rectangle = createLargeRectangle(0.0); expect(scene).toDrillPickPrimitive(rectangle, 7, 7, 5); expect(scene).notToDrillPick(7, 7, 3); }); it("does not drill pick undefined window positions", function () { expect(function () { scene.pick(undefined); }).toThrowDeveloperError(); }); it("drill picks multiple objects", function () { var rectangle1 = createLargeRectangle(0.0); var rectangle2 = createLargeRectangle(1.0); expect(scene).toDrillPickAndCall(function (pickedObjects) { expect(pickedObjects.length).toEqual(2); expect(pickedObjects[0].primitive).toEqual(rectangle2); expect(pickedObjects[1].primitive).toEqual(rectangle1); }); }); it("does not drill pick when show is false", function () { var rectangle1 = createLargeRectangle(0.0); var rectangle2 = createLargeRectangle(1.0); rectangle2.show = false; expect(scene).toDrillPickAndCall(function (pickedObjects) { expect(pickedObjects.length).toEqual(1); expect(pickedObjects[0].primitive).toEqual(rectangle1); }); }); it("does not drill pick when alpha is zero", function () { var rectangle1 = createLargeRectangle(0.0); var rectangle2 = createLargeRectangle(1.0); rectangle2.appearance.material.uniforms.color.alpha = 0.0; expect(scene).toDrillPickAndCall(function (pickedObjects) { expect(pickedObjects.length).toEqual(1); expect(pickedObjects[0].primitive).toEqual(rectangle1); }); }); it("can drill pick batched Primitives with show attribute", function () { var geometry = new RectangleGeometry({ rectangle: Rectangle.fromDegrees(-50.0, -50.0, 50.0, 50.0), granularity: CesiumMath.toRadians(20.0), vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT, height: 0.0, }); var geometryWithHeight = new RectangleGeometry({ rectangle: Rectangle.fromDegrees(-50.0, -50.0, 50.0, 50.0), granularity: CesiumMath.toRadians(20.0), vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT, height: 20.0, }); var instance1 = new GeometryInstance({ id: 1, geometry: geometry, attributes: { show: new ShowGeometryInstanceAttribute(true), }, }); var instance2 = new GeometryInstance({ id: 2, geometry: geometry, attributes: { show: new ShowGeometryInstanceAttribute(false), }, }); var instance3 = new GeometryInstance({ id: 3, geometry: geometryWithHeight, attributes: { show: new ShowGeometryInstanceAttribute(true), }, }); var primitive = primitives.add( new Primitive({ geometryInstances: [instance1, instance2, instance3], asynchronous: false, appearance: new EllipsoidSurfaceAppearance(), }) ); expect(scene).toDrillPickAndCall(function (pickedObjects) { expect(pickedObjects.length).toEqual(2); expect(pickedObjects[0].primitive).toEqual(primitive); expect(pickedObjects[0].id).toEqual(3); expect(pickedObjects[1].primitive).toEqual(primitive); expect(pickedObjects[1].id).toEqual(1); }); }); it("can drill pick without ID", function () { var geometry = new RectangleGeometry({ rectangle: Rectangle.fromDegrees(-50.0, -50.0, 50.0, 50.0), granularity: CesiumMath.toRadians(20.0), vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT, }); var instance1 = new GeometryInstance({ geometry: geometry, attributes: { show: new ShowGeometryInstanceAttribute(true), }, }); var instance2 = new GeometryInstance({ geometry: geometry, attributes: { show: new ShowGeometryInstanceAttribute(true), }, }); var primitive = primitives.add( new Primitive({ geometryInstances: [instance1, instance2], asynchronous: false, appearance: new EllipsoidSurfaceAppearance(), }) ); expect(scene).toDrillPickAndCall(function (pickedObjects) { expect(pickedObjects.length).toEqual(1); expect(pickedObjects[0].primitive).toEqual(primitive); }); }); it("can drill pick batched Primitives without show attribute", function () { var geometry = new RectangleGeometry({ rectangle: Rectangle.fromDegrees(-50.0, -50.0, 50.0, 50.0), granularity: CesiumMath.toRadians(20.0), vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT, height: 0.0, }); var geometryWithHeight = new RectangleGeometry({ rectangle: Rectangle.fromDegrees(-50.0, -50.0, 50.0, 50.0), granularity: CesiumMath.toRadians(20.0), vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT, height: 20.0, }); var instance1 = new GeometryInstance({ id: 1, geometry: geometry, }); var instance2 = new GeometryInstance({ id: 2, geometry: geometry, }); var instance3 = new GeometryInstance({ id: 3, geometry: geometryWithHeight, }); var primitive = primitives.add( new Primitive({ geometryInstances: [instance1, instance2, instance3], asynchronous: false, appearance: new EllipsoidSurfaceAppearance(), }) ); expect(scene).toDrillPickAndCall(function (pickedObjects) { expect(pickedObjects.length).toEqual(1); expect(pickedObjects[0].primitive).toEqual(primitive); expect(pickedObjects[0].id).toEqual(3); }); }); it("stops drill picking when the limit is reached.", function () { createLargeRectangle(0.0); var rectangle2 = createLargeRectangle(1.0); var rectangle3 = createLargeRectangle(2.0); var rectangle4 = createLargeRectangle(3.0); expect(scene).toDrillPickAndCall(function (pickedObjects) { expect(pickedObjects.length).toEqual(3); expect(pickedObjects[0].primitive).toEqual(rectangle4); expect(pickedObjects[1].primitive).toEqual(rectangle3); expect(pickedObjects[2].primitive).toEqual(rectangle2); }, 3); }); }); function picksFromRayTileset(style) { return createTileset(batchedTilesetUrl).then(function (tileset) { tileset.style = style; expect(scene).toPickFromRayAndCall(function (result) { var primitive = result.object.primitive; var position = result.position; expect(primitive).toBe(tileset); if (scene.context.depthTexture) { var minimumHeight = Cartesian3.fromRadians(0.0, 0.0).x; var maximumHeight = minimumHeight + 20.0; // Rough height of tile expect(position.x).toBeGreaterThan(minimumHeight); expect(position.x).toBeLessThan(maximumHeight); expect(position.y).toEqualEpsilon(0.0, CesiumMath.EPSILON5); expect(position.z).toEqualEpsilon(0.0, CesiumMath.EPSILON5); } }, primitiveRay); }); } describe("pickFromRay", function () { it("picks a tileset", function () { return picksFromRayTileset(); }); it("picks a translucent tileset", function () { var style = new Cesium3DTileStyle({ color: 'color("white", 0.5)', }); return picksFromRayTileset(style); }); it("picks the globe", function () { if (!scene.context.depthTexture) { return; } return createGlobe().then(function () { expect(scene).toPickFromRayAndCall(function (result) { expect(result.object).toBeUndefined(); expect(result.position).toBeDefined(); expect(result.position.x).toBeGreaterThan( Ellipsoid.WGS84.minimumRadius ); expect(result.position.y).toEqualEpsilon(0.0, CesiumMath.EPSILON5); expect(result.position.z).toEqualEpsilon(0.0, CesiumMath.EPSILON5); }, primitiveRay); }); }); it("picks a primitive", function () { var rectangle = createSmallRectangle(0.0); expect(scene).toPickFromRayAndCall(function (result) { var primitive = result.object.primitive; var position = result.position; expect(primitive).toBe(rectangle); if (scene.context.depthTexture) { var expectedPosition = Cartesian3.fromRadians(0.0, 0.0); expect(position).toEqualEpsilon( expectedPosition, CesiumMath.EPSILON5 ); } }, primitiveRay); }); it("returns undefined if no primitives are picked", function () { createLargeRectangle(0.0); expect(scene).toPickFromRayAndCall(function (result) { expect(result).toBeUndefined(); }, offscreenRay); }); it("does not pick primitives when show is false", function () { var rectangle = createLargeRectangle(0.0); rectangle.show = false; expect(scene).toPickFromRayAndCall(function (result) { expect(result).toBeUndefined(); }, primitiveRay); }); it("does not pick primitives when alpha is zero", function () { var rectangle = createLargeRectangle(0.0); rectangle.appearance.material.uniforms.color.alpha = 0.0; expect(scene).toPickFromRayAndCall(function (result) { expect(result).toBeUndefined(); }, primitiveRay); }); it("picks the top primitive", function () { createLargeRectangle(0.0); var rectangle2 = createLargeRectangle(1.0); expect(scene).toPickFromRayAndCall(function (result) { expect(result.object.primitive).toBe(rectangle2); }, primitiveRay); }); it("excludes objects", function () { var rectangle1 = createLargeRectangle(0.0); var rectangle2 = createLargeRectangle(1.0); var rectangle3 = createLargeRectangle(2.0); var rectangle4 = createLargeRectangle(3.0); rectangle4.show = false; expect(scene).toPickFromRayAndCall( function (result) { expect(result.object.primitive).toBe(rectangle1); }, primitiveRay, [rectangle2, rectangle3, rectangle4] ); // Tests that rectangle4 does not get un-hidden expect(scene).toPickFromRayAndCall(function (result) { expect(result.object.primitive).toBe(rectangle3); }, primitiveRay); }); it("picks primitive that doesn't write depth", function () { var collection = scene.primitives.add(new PointPrimitiveCollection()); var point = collection.add({ position: Cartographic.fromRadians(0.0, 0.0, 100.0), disableDepthTestDistance: Number.POSITIVE_INFINITY, }); expect(scene).toPickFromRayAndCall( function (result) { expect(result.object.primitive).toBe(point); expect(result.position).toBeUndefined(); }, primitiveRay, [], 0.01 ); }); it("changes width", function () { return createTileset(pointCloudTilesetUrl).then(function (tileset) { expect(scene).toPickFromRayAndCall( function (result) { expect(result).toBeUndefined(); }, primitiveRay, [], 0.1 ); expect(scene).toPickFromRayAndCall( function (result) { expect(result).toBeDefined(); }, primitiveRay, [], 1.0 ); }); }); it("throws if ray is undefined", function () { expect(function () { scene.pickFromRay(undefined); }).toThrowDeveloperError(); }); it("throws if scene camera is in 2D", function () { scene.morphTo2D(0.0); expect(function () { scene.pickFromRay(primitiveRay); }).toThrowDeveloperError(); }); it("throws if scene camera is in CV", function () { scene.morphToColumbusView(0.0); expect(function () { scene.pickFromRay(primitiveRay); }).toThrowDeveloperError(); }); }); describe("drillPickFromRay", function () { it("drill picks a primitive", function () { var rectangle = createSmallRectangle(0.0); expect(scene).toDrillPickFromRayAndCall(function (results) { expect(results.length).toBe(1); var primitive = results[0].object.primitive; var position = results[0].position; expect(primitive).toBe(rectangle); if (scene.context.depthTexture) { var expectedPosition = Cartesian3.fromRadians(0.0, 0.0); expect(position).toEqualEpsilon( expectedPosition, CesiumMath.EPSILON5 ); } else { expect(position).toBeUndefined(); } }, primitiveRay); }); it("drill picks multiple primitives", function () { var rectangle1 = createSmallRectangle(0.0); var rectangle2 = createSmallRectangle(1.0); expect(scene).toDrillPickFromRayAndCall(function (results) { expect(results.length).toBe(2); // rectangle2 is picked before rectangle1 expect(results[0].object.primitive).toBe(rectangle2); expect(results[1].object.primitive).toBe(rectangle1); if (scene.context.depthTexture) { var rectangleCenter1 = Cartesian3.fromRadians(0.0, 0.0, 0.0); var rectangleCenter2 = Cartesian3.fromRadians(0.0, 0.0, 1.0); expect(results[0].position).toEqualEpsilon( rectangleCenter2, CesiumMath.EPSILON5 ); expect(results[1].position).toEqualEpsilon( rectangleCenter1, CesiumMath.EPSILON5 ); } else { expect(results[0].position).toBeUndefined(); expect(results[1].position).toBeUndefined(); } }, primitiveRay); }); it("does not drill pick when show is false", function () { var rectangle1 = createLargeRectangle(0.0); var rectangle2 = createLargeRectangle(1.0); rectangle2.show = false; expect(scene).toDrillPickFromRayAndCall(function (results) { expect(results.length).toEqual(1); expect(results[0].object.primitive).toEqual(rectangle1); }, primitiveRay); }); it("does not drill pick when alpha is zero", function () { var rectangle1 = createLargeRectangle(0.0); var rectangle2 = createLargeRectangle(1.0); rectangle2.appearance.material.uniforms.color.alpha = 0.0; expect(scene).toDrillPickFromRayAndCall(function (results) { expect(results.length).toEqual(1); expect(results[0].object.primitive).toEqual(rectangle1); }, primitiveRay); }); it("returns empty array if no primitives are picked", function () { createLargeRectangle(0.0); createLargeRectangle(1.0); expect(scene).toDrillPickFromRayAndCall(function (results) { expect(results.length).toEqual(0); }, offscreenRay); }); it("can drill pick batched Primitives with show attribute", function () { var geometry = new RectangleGeometry({ rectangle: Rectangle.fromDegrees(-50.0, -50.0, 50.0, 50.0), granularity: CesiumMath.toRadians(20.0), vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT, height: 0.0, }); var geometryWithHeight = new RectangleGeometry({ rectangle: Rectangle.fromDegrees(-50.0, -50.0, 50.0, 50.0), granularity: CesiumMath.toRadians(20.0), vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT, height: 1.0, }); var instance1 = new GeometryInstance({ id: 1, geometry: geometry, attributes: { show: new ShowGeometryInstanceAttribute(true), }, }); var instance2 = new GeometryInstance({ id: 2, geometry: geometry, attributes: { show: new ShowGeometryInstanceAttribute(false), }, }); var instance3 = new GeometryInstance({ id: 3, geometry: geometryWithHeight, attributes: { show: new ShowGeometryInstanceAttribute(true), }, }); var primitive = primitives.add( new Primitive({ geometryInstances: [instance1, instance2, instance3], asynchronous: false, appearance: new EllipsoidSurfaceAppearance(), }) ); expect(scene).toDrillPickFromRayAndCall(function (results) { expect(results.length).toEqual(2); expect(results[0].object.primitive).toEqual(primitive); expect(results[0].object.id).toEqual(3); expect(results[1].object.primitive).toEqual(primitive); expect(results[1].object.id).toEqual(1); }, primitiveRay); }); it("can drill pick without ID", function () { var geometry = new RectangleGeometry({ rectangle: Rectangle.fromDegrees(-50.0, -50.0, 50.0, 50.0), granularity: CesiumMath.toRadians(20.0), vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT, }); var instance1 = new GeometryInstance({ geometry: geometry, attributes: { show: new ShowGeometryInstanceAttribute(true), }, }); var instance2 = new GeometryInstance({ geometry: geometry, attributes: { show: new ShowGeometryInstanceAttribute(true), }, }); var primitive = primitives.add( new Primitive({ geometryInstances: [instance1, instance2], asynchronous: false, appearance: new EllipsoidSurfaceAppearance(), }) ); expect(scene).toDrillPickFromRayAndCall(function (results) { expect(results.length).toEqual(1); expect(results[0].object.primitive).toEqual(primitive); }, primitiveRay); }); it("can drill pick batched Primitives without show attribute", function () { var geometry = new RectangleGeometry({ rectangle: Rectangle.fromDegrees(-50.0, -50.0, 50.0, 50.0), granularity: CesiumMath.toRadians(20.0), vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT, height: 0.0, }); var geometryWithHeight = new RectangleGeometry({ rectangle: Rectangle.fromDegrees(-50.0, -50.0, 50.0, 50.0), granularity: CesiumMath.toRadians(20.0), vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT, height: 1.0, }); var instance1 = new GeometryInstance({ id: 1, geometry: geometry, }); var instance2 = new GeometryInstance({ id: 2, geometry: geometry, }); var instance3 = new GeometryInstance({ id: 3, geometry: geometryWithHeight, }); var primitive = primitives.add( new Primitive({ geometryInstances: [instance1, instance2, instance3], asynchronous: false, appearance: new EllipsoidSurfaceAppearance(), }) ); expect(scene).toDrillPickFromRayAndCall(function (results) { expect(results.length).toEqual(1); expect(results[0].object.primitive).toEqual(primitive); expect(results[0].object.id).toEqual(3); }, primitiveRay); }); it("stops drill picking when the limit is reached.", function () { createLargeRectangle(0.0); var rectangle2 = createLargeRectangle(1.0); var rectangle3 = createLargeRectangle(2.0); var rectangle4 = createLargeRectangle(3.0); expect(scene).toDrillPickFromRayAndCall( function (results) { expect(results.length).toEqual(3); expect(results[0].object.primitive).toEqual(rectangle4); expect(results[1].object.primitive).toEqual(rectangle3); expect(results[2].object.primitive).toEqual(rectangle2); }, primitiveRay, 3 ); }); it("excludes objects", function () { createLargeRectangle(0.0); var rectangle2 = createLargeRectangle(1.0); var rectangle3 = createLargeRectangle(2.0); var rectangle4 = createLargeRectangle(3.0); var rectangle5 = createLargeRectangle(4.0); expect(scene).toDrillPickFromRayAndCall( function (results) { expect(results.length).toBe(2); expect(results[0].object.primitive).toBe(rectangle4); expect(results[1].object.primitive).toBe(rectangle2); }, primitiveRay, 2, [rectangle5, rectangle3] ); }); it("changes width", function () { return createTileset(pointCloudTilesetUrl).then(function (tileset) { expect(scene).toDrillPickFromRayAndCall( function (result) { expect(result.length).toBe(0); }, primitiveRay, [], 0.1 ); expect(scene).toDrillPickFromRayAndCall( function (result) { expect(result.length).toBe(1); }, primitiveRay, Number.POSITIVE_INFINITY, [], 1.0 ); }); }); it("throws if ray is undefined", function () { expect(function () { scene.drillPickFromRay(undefined); }).toThrowDeveloperError(); }); it("throws if scene camera is in 2D", function () { scene.morphTo2D(0.0); expect(function () { scene.drillPickFromRay(primitiveRay); }).toThrowDeveloperError(); }); it("throws if scene camera is in CV", function () { scene.morphToColumbusView(0.0); expect(function () { scene.drillPickFromRay(primitiveRay); }).toThrowDeveloperError(); }); }); describe("sampleHeight", function () { it("samples height from tileset", function () { if (!scene.sampleHeightSupported) { return; } var cartographic = new Cartographic(0.0, 0.0); return createTileset(batchedTilesetUrl).then(function (tileset) { expect(scene).toSampleHeightAndCall(function (height) { expect(height).toBeGreaterThan(0.0); expect(height).toBeLessThan(20.0); // Rough height of tile }, cartographic); }); }); it("samples height from the globe", function () { if (!scene.sampleHeightSupported) { return; } var cartographic = new Cartographic(0.0, 0.0); return createGlobe().then(function () { expect(scene).toSampleHeightAndCall(function (height) { expect(height).toBeDefined(); }, cartographic); }); }); it("samples height from primitive", function () { if (!scene.sampleHeightSupported) { return; } createSmallRectangle(0.0); var cartographic = new Cartographic(0.0, 0.0); expect(scene).toSampleHeightAndCall(function (height) { expect(height).toEqualEpsilon(0.0, CesiumMath.EPSILON3); }, cartographic); }); it("samples height from the top primitive", function () { if (!scene.sampleHeightSupported) { return; } createSmallRectangle(0.0); createSmallRectangle(1.0); var cartographic = new Cartographic(0.0, 0.0); expect(scene).toSampleHeightAndCall(function (height) { expect(height).toEqualEpsilon(1.0, CesiumMath.EPSILON3); }, cartographic); }); it("returns undefined if no height is sampled", function () { if (!scene.sampleHeightSupported) { return; } createSmallRectangle(0.0); var cartographic = new Cartographic(1.0, 0.0); expect(scene).toSampleHeightAndCall(function (height) { expect(height).toBeUndefined(); }, cartographic); }); it("excludes objects", function () { if (!scene.sampleHeightSupported) { return; } createSmallRectangle(0.0); var rectangle2 = createSmallRectangle(1.0); var rectangle3 = createSmallRectangle(2.0); var cartographic = new Cartographic(0.0, 0.0); expect(scene).toSampleHeightAndCall( function (height) { expect(height).toEqualEpsilon(0.0, CesiumMath.EPSILON3); }, cartographic, [rectangle2, rectangle3] ); }); it("excludes primitive that doesn't write depth", function () { if (!scene.sampleHeightSupported) { return; } var rectangle = createSmallRectangle(0.0); var height = 100.0; var cartographic = new Cartographic(0.0, 0.0, height); var collection = scene.primitives.add(new PointPrimitiveCollection()); var point = collection.add({ position: Cartographic.toCartesian(cartographic), }); expect(scene).toSampleHeightAndCall(function (height) { expect(height).toEqualEpsilon(height, CesiumMath.EPSILON3); }, cartographic); point.disableDepthTestDistance = Number.POSITIVE_INFINITY; expect(scene).toSampleHeightAndCall(function (height) { expect(height).toEqualEpsilon(0.0, CesiumMath.EPSILON3); }, cartographic); rectangle.show = false; expect(scene).toSampleHeightAndCall(function (height) { expect(height).toBeUndefined(); }, cartographic); }); it("changes width", function () { if (!scene.sampleHeightSupported) { return; } var cartographic = new Cartographic(0.0, 0.0); return createTileset(pointCloudTilesetUrl).then(function (tileset) { expect(scene).toSampleHeightAndCall( function (height) { expect(height).toBeUndefined(); }, cartographic, [], 0.1 ); expect(scene).toSampleHeightAndCall( function (height) { expect(height).toBeDefined(); }, cartographic, [], 1.0 ); }); }); it("throws if position is undefined", function () { if (!scene.sampleHeightSupported) { return; } expect(function () { scene.sampleHeight(undefined); }).toThrowDeveloperError(); }); it("throws if scene camera is in 2D", function () { if (!scene.sampleHeightSupported) { return; } scene.morphTo2D(0.0); var cartographic = new Cartographic(0.0, 0.0); expect(function () { scene.sampleHeight(cartographic); }).toThrowDeveloperError(); }); it("throws if scene camera is in CV", function () { if (!scene.sampleHeightSupported) { return; } scene.morphToColumbusView(0.0); var cartographic = new Cartographic(0.0, 0.0); expect(function () { scene.sampleHeight(cartographic); }).toThrowDeveloperError(); }); it("throws if sampleHeight is not supported", function () { if (!scene.sampleHeightSupported) { return; } // Disable extension var depthTexture = scene.context._depthTexture; scene.context._depthTexture = false; var cartographic = new Cartographic(0.0, 0.0); expect(function () { scene.sampleHeight(cartographic); }).toThrowDeveloperError(); // Re-enable extension scene.context._depthTexture = depthTexture; }); }); describe("clampToHeight", function () { it("clamps to tileset", function () { if (!scene.clampToHeightSupported) { return; } var cartesian = Cartesian3.fromRadians(0.0, 0.0, 100000.0); return createTileset(batchedTilesetUrl).then(function (tileset) { expect(scene).toClampToHeightAndCall(function (position) { var minimumHeight = Cartesian3.fromRadians(0.0, 0.0).x; var maximumHeight = minimumHeight + 20.0; // Rough height of tile expect(position.x).toBeGreaterThan(minimumHeight); expect(position.x).toBeLessThan(maximumHeight); expect(position.y).toEqualEpsilon(0.0, CesiumMath.EPSILON5); expect(position.z).toEqualEpsilon(0.0, CesiumMath.EPSILON5); }, cartesian); }); }); it("clamps to the globe", function () { if (!scene.clampToHeightSupported) { return; } var cartesian = Cartesian3.fromRadians(0.0, 0.0, 100000.0); return createGlobe().then(function () { expect(scene).toClampToHeightAndCall(function (position) { expect(position).toBeDefined(); }, cartesian); }); }); it("clamps to primitive", function () { if (!scene.clampToHeightSupported) { return; } createSmallRectangle(0.0); var cartesian = Cartesian3.fromRadians(0.0, 0.0, 100000.0); expect(scene).toClampToHeightAndCall(function (cartesian) { var expectedCartesian = Cartesian3.fromRadians(0.0, 0.0); expect(cartesian).toEqualEpsilon( expectedCartesian, CesiumMath.EPSILON5 ); }, cartesian); }); it("clamps to top primitive", function () { if (!scene.clampToHeightSupported) { return; } createSmallRectangle(0.0); createSmallRectangle(1.0); var cartesian = Cartesian3.fromRadians(0.0, 0.0, 100000.0); expect(scene).toClampToHeightAndCall(function (cartesian) { var expectedCartesian = Cartesian3.fromRadians(0.0, 0.0, 1.0); expect(cartesian).toEqualEpsilon( expectedCartesian, CesiumMath.EPSILON5 ); }, cartesian); }); it("returns undefined if there was nothing to clamp to", function () { if (!scene.clampToHeightSupported) { return; } createSmallRectangle(0.0); var cartesian = Cartesian3.fromRadians(1.0, 0.0, 100000.0); expect(scene).toClampToHeightAndCall(function (cartesian) { expect(cartesian).toBeUndefined(); }, cartesian); }); it("excludes objects", function () { if (!scene.clampToHeightSupported) { return; } createSmallRectangle(0.0); var rectangle2 = createSmallRectangle(1.0); var rectangle3 = createSmallRectangle(2.0); var cartesian = Cartesian3.fromRadians(0.0, 0.0, 100000.0); expect(scene).toClampToHeightAndCall( function (cartesian) { var expectedCartesian = Cartesian3.fromRadians(0.0, 0.0); expect(cartesian).toEqualEpsilon( expectedCartesian, CesiumMath.EPSILON5 ); }, cartesian, [rectangle2, rectangle3] ); }); it("excludes primitive that doesn't write depth", function () { if (!scene.clampToHeightSupported) { return; } var rectangle = createSmallRectangle(0.0); var cartesian = Cartesian3.fromRadians(0.0, 0.0, 100.0); var collection = scene.primitives.add(new PointPrimitiveCollection()); var point = collection.add({ position: cartesian, }); expect(scene).toClampToHeightAndCall(function (clampedCartesian) { expect(clampedCartesian).toEqualEpsilon( cartesian, CesiumMath.EPSILON3 ); }, cartesian); point.disableDepthTestDistance = Number.POSITIVE_INFINITY; expect(scene).toClampToHeightAndCall(function (clampedCartesian) { expect(clampedCartesian).toEqualEpsilon( cartesian, CesiumMath.EPSILON3 ); }, cartesian); rectangle.show = false; expect(scene).toClampToHeightAndCall(function (clampedCartesian) { expect(clampedCartesian).toBeUndefined(); }, cartesian); }); it("changes width", function () { if (!scene.clampToHeightSupported) { return; } var cartesian = Cartesian3.fromRadians(0.0, 0.0, 100.0); return createTileset(pointCloudTilesetUrl).then(function (tileset) { expect(scene).toClampToHeightAndCall( function (clampedCartesian) { expect(clampedCartesian).toBeUndefined(); }, cartesian, [], 0.1 ); expect(scene).toClampToHeightAndCall( function (clampedCartesian) { expect(clampedCartesian).toBeDefined(); }, cartesian, [], 1.0 ); }); }); it("throws if cartesian is undefined", function () { if (!scene.clampToHeightSupported) { return; } expect(function () { scene.clampToHeight(undefined); }).toThrowDeveloperError(); }); it("throws if scene camera is in 2D", function () { if (!scene.clampToHeightSupported) { return; } scene.morphTo2D(0.0); var cartesian = Cartesian3.fromRadians(0.0, 0.0, 100000.0); expect(function () { scene.clampToHeight(cartesian); }).toThrowDeveloperError(); }); it("throws if scene camera is in CV", function () { if (!scene.clampToHeightSupported) { return; } scene.morphToColumbusView(0.0); var cartesian = Cartesian3.fromRadians(0.0, 0.0, 100000.0); expect(function () { scene.clampToHeight(cartesian); }).toThrowDeveloperError(); }); it("throws if clampToHeight is not supported", function () { if (!scene.clampToHeightSupported) { return; } // Disable extension var depthTexture = scene.context._depthTexture; scene.context._depthTexture = false; var cartesian = Cartesian3.fromRadians(0.0, 0.0, 100000.0); expect(function () { scene.clampToHeight(cartesian); }).toThrowDeveloperError(); // Re-enable extension scene.context._depthTexture = depthTexture; }); }); function pickFromRayMostDetailed(ray, objectsToExclude, width) { var result; var completed = false; scene .pickFromRayMostDetailed(ray, objectsToExclude, width) .then(function (pickResult) { result = pickResult; completed = true; }); return pollToPromise(function () { // Scene requires manual updates in the tests to move along the promise scene.render(); return completed; }).then(function () { return result; }); } function drillPickFromRayMostDetailed(ray, limit, objectsToExclude, width) { var result; var completed = false; scene .drillPickFromRayMostDetailed(ray, limit, objectsToExclude, width) .then(function (pickResult) { result = pickResult; completed = true; }); return pollToPromise(function () { // Scene requires manual updates in the tests to move along the promise scene.render(); return completed; }).then(function () { return result; }); } function sampleHeightMostDetailed(cartographics, objectsToExclude, width) { var result; var completed = false; scene .sampleHeightMostDetailed(cartographics, objectsToExclude, width) .then(function (pickResult) { result = pickResult; completed = true; }); return pollToPromise(function () { // Scene requires manual updates in the tests to move along the promise scene.render(); return completed; }).then(function () { return result; }); } function clampToHeightMostDetailed(cartesians, objectsToExclude, width) { var result; var completed = false; scene .clampToHeightMostDetailed(cartesians, objectsToExclude, width) .then(function (pickResult) { result = pickResult; completed = true; }); return pollToPromise(function () { // Scene requires manual updates in the tests to move along the promise scene.render(); return completed; }).then(function () { return result; }); } describe("pickFromRayMostDetailed", function () { it("picks a tileset", function () { if (webglStub) { return; } scene.camera.setView({ destination: offscreenRectangle }); return createTileset(batchedTilesetUrl).then(function (tileset) { return pickFromRayMostDetailed(primitiveRay).then(function (result) { var primitive = result.object.primitive; var position = result.position; expect(primitive).toBe(tileset); if (scene.context.depthTexture) { var minimumHeight = Cartesian3.fromRadians(0.0, 0.0).x; var maximumHeight = minimumHeight + 20.0; // Rough height of tile expect(position.x).toBeGreaterThan(minimumHeight); expect(position.x).toBeLessThan(maximumHeight); expect(position.y).toEqualEpsilon(0.0, CesiumMath.EPSILON5); expect(position.z).toEqualEpsilon(0.0, CesiumMath.EPSILON5); } }); }); }); it("excludes tileset in objectsToExclude list", function () { if (webglStub) { return; } scene.camera.setView({ destination: offscreenRectangle }); return createTileset(batchedTilesetUrl).then(function (tileset) { var objectsToExclude = [tileset]; return pickFromRayMostDetailed(primitiveRay, objectsToExclude).then( function (result) { expect(result).toBeUndefined(); } ); }); }); it("excludes tileset whose show is false", function () { if (webglStub) { return; } scene.camera.setView({ destination: offscreenRectangle }); return createTileset(batchedTilesetUrl).then(function (tileset) { tileset.show = false; return pickFromRayMostDetailed(primitiveRay).then(function (result) { expect(result).toBeUndefined(); }); }); }); it("picks a primitive", function () { if (webglStub) { return; } var rectangle = createSmallRectangle(0.0); scene.camera.setView({ destination: offscreenRectangle }); return pickFromRayMostDetailed(primitiveRay).then(function (result) { var primitive = result.object.primitive; var position = result.position; expect(primitive).toBe(rectangle); if (scene.context.depthTexture) { var expectedPosition = Cartesian3.fromRadians(0.0, 0.0); expect(position).toEqualEpsilon( expectedPosition, CesiumMath.EPSILON5 ); } }); }); it("returns undefined if no primitives are picked", function () { if (webglStub) { return; } createLargeRectangle(0.0); scene.camera.setView({ destination: offscreenRectangle }); return pickFromRayMostDetailed(offscreenRay).then(function (result) { expect(result).toBeUndefined(); }); }); it("picks the top primitive", function () { if (webglStub) { return; } createLargeRectangle(0.0); var rectangle2 = createLargeRectangle(1.0); scene.camera.setView({ destination: offscreenRectangle }); return pickFromRayMostDetailed(primitiveRay).then(function (result) { expect(result.object.primitive).toBe(rectangle2); }); }); it("excludes objects", function () { if (webglStub) { return; } var rectangle1 = createLargeRectangle(0.0); var rectangle2 = createLargeRectangle(1.0); var rectangle3 = createLargeRectangle(2.0); var rectangle4 = createLargeRectangle(3.0); rectangle4.show = false; scene.camera.setView({ destination: offscreenRectangle }); return pickFromRayMostDetailed(primitiveRay, [ rectangle2, rectangle3, rectangle4, ]) .then(function (result) { expect(result.object.primitive).toBe(rectangle1); }) .then(function () { return pickFromRayMostDetailed(primitiveRay).then(function ( result ) { expect(result.object.primitive).toBe(rectangle3); }); }); }); it("picks primitive that doesn't write depth", function () { if (webglStub) { return; } var collection = scene.primitives.add(new PointPrimitiveCollection()); var point = collection.add({ position: Cartographic.fromRadians(0.0, 0.0, 100.0), disableDepthTestDistance: Number.POSITIVE_INFINITY, }); scene.camera.setView({ destination: offscreenRectangle }); return pickFromRayMostDetailed(primitiveRay, [], 0.01).then(function ( result ) { expect(result.object.primitive).toBe(point); expect(result.position).toBeUndefined(); }); }); it("changes width", function () { if (webglStub) { return; } return createTileset(pointCloudTilesetUrl).then(function (tileset) { var promise1 = pickFromRayMostDetailed(primitiveRay, [], 0.1).then( function (result) { expect(result).toBeUndefined(); } ); var promise2 = pickFromRayMostDetailed(primitiveRay, [], 1.0).then( function (result) { expect(result).toBeDefined(); } ); return when.all([promise1, promise2]); }); }); it("throws if ray is undefined", function () { expect(function () { scene.pickFromRayMostDetailed(undefined); }).toThrowDeveloperError(); }); it("throws if scene camera is in 2D", function () { scene.morphTo2D(0.0); expect(function () { scene.pickFromRayMostDetailed(undefined); }).toThrowDeveloperError(); }); it("throws if scene camera is in CV", function () { scene.morphToColumbusView(0.0); expect(function () { scene.pickFromRayMostDetailed(undefined); }).toThrowDeveloperError(); }); }); describe("drillPickFromRayMostDetailed", function () { it("drill picks a primitive", function () { if (webglStub) { return; } var rectangle = createSmallRectangle(0.0); scene.camera.setView({ destination: offscreenRectangle }); return drillPickFromRayMostDetailed(primitiveRay).then(function ( results ) { expect(results.length).toBe(1); var primitive = results[0].object.primitive; var position = results[0].position; expect(primitive).toBe(rectangle); if (scene.context.depthTexture) { var expectedPosition = Cartesian3.fromRadians(0.0, 0.0); expect(position).toEqualEpsilon( expectedPosition, CesiumMath.EPSILON5 ); } else { expect(position).toBeUndefined(); } }); }); it("drill picks multiple primitives", function () { if (webglStub) { return; } var rectangle1 = createSmallRectangle(0.0); var rectangle2 = createSmallRectangle(1.0); scene.camera.setView({ destination: offscreenRectangle }); return drillPickFromRayMostDetailed(primitiveRay).then(function ( results ) { expect(results.length).toBe(2); // rectangle2 is picked before rectangle1 expect(results[0].object.primitive).toBe(rectangle2); expect(results[1].object.primitive).toBe(rectangle1); if (scene.context.depthTexture) { var rectangleCenter1 = Cartesian3.fromRadians(0.0, 0.0, 0.0); var rectangleCenter2 = Cartesian3.fromRadians(0.0, 0.0, 1.0); expect(results[0].position).toEqualEpsilon( rectangleCenter2, CesiumMath.EPSILON5 ); expect(results[1].position).toEqualEpsilon( rectangleCenter1, CesiumMath.EPSILON5 ); } else { expect(results[0].position).toBeUndefined(); expect(results[1].position).toBeUndefined(); } }); }); it("does not drill pick when show is false", function () { if (webglStub) { return; } var rectangle1 = createLargeRectangle(0.0); var rectangle2 = createLargeRectangle(1.0); rectangle2.show = false; scene.camera.setView({ destination: offscreenRectangle }); return drillPickFromRayMostDetailed(primitiveRay).then(function ( results ) { expect(results.length).toEqual(1); expect(results[0].object.primitive).toEqual(rectangle1); }); }); it("does not drill pick when alpha is zero", function () { if (webglStub) { return; } var rectangle1 = createLargeRectangle(0.0); var rectangle2 = createLargeRectangle(1.0); rectangle2.appearance.material.uniforms.color.alpha = 0.0; scene.camera.setView({ destination: offscreenRectangle }); return drillPickFromRayMostDetailed(primitiveRay).then(function ( results ) { expect(results.length).toEqual(1); expect(results[0].object.primitive).toEqual(rectangle1); }); }); it("returns empty array if no primitives are picked", function () { if (webglStub) { return; } createLargeRectangle(0.0); createLargeRectangle(1.0); scene.camera.setView({ destination: offscreenRectangle }); return drillPickFromRayMostDetailed(offscreenRay).then(function ( results ) { expect(results.length).toEqual(0); }); }); it("can drill pick batched Primitives with show attribute", function () { if (webglStub) { return; } var geometry = new RectangleGeometry({ rectangle: Rectangle.fromDegrees(-50.0, -50.0, 50.0, 50.0), granularity: CesiumMath.toRadians(20.0), vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT, height: 0.0, }); var geometryWithHeight = new RectangleGeometry({ rectangle: Rectangle.fromDegrees(-50.0, -50.0, 50.0, 50.0), granularity: CesiumMath.toRadians(20.0), vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT, height: 1.0, }); var instance1 = new GeometryInstance({ id: 1, geometry: geometry, attributes: { show: new ShowGeometryInstanceAttribute(true), }, }); var instance2 = new GeometryInstance({ id: 2, geometry: geometry, attributes: { show: new ShowGeometryInstanceAttribute(false), }, }); var instance3 = new GeometryInstance({ id: 3, geometry: geometryWithHeight, attributes: { show: new ShowGeometryInstanceAttribute(true), }, }); var primitive = primitives.add( new Primitive({ geometryInstances: [instance1, instance2, instance3], asynchronous: false, appearance: new EllipsoidSurfaceAppearance(), }) ); scene.camera.setView({ destination: offscreenRectangle }); return drillPickFromRayMostDetailed(primitiveRay).then(function ( results ) { expect(results.length).toEqual(2); expect(results[0].object.primitive).toEqual(primitive); expect(results[0].object.id).toEqual(3); expect(results[1].object.primitive).toEqual(primitive); expect(results[1].object.id).toEqual(1); }); }); it("can drill pick without ID", function () { if (webglStub) { return; } var geometry = new RectangleGeometry({ rectangle: Rectangle.fromDegrees(-50.0, -50.0, 50.0, 50.0), granularity: CesiumMath.toRadians(20.0), vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT, }); var instance1 = new GeometryInstance({ geometry: geometry, attributes: { show: new ShowGeometryInstanceAttribute(true), }, }); var instance2 = new GeometryInstance({ geometry: geometry, attributes: { show: new ShowGeometryInstanceAttribute(true), }, }); var primitive = primitives.add( new Primitive({ geometryInstances: [instance1, instance2], asynchronous: false, appearance: new EllipsoidSurfaceAppearance(), }) ); scene.camera.setView({ destination: offscreenRectangle }); return drillPickFromRayMostDetailed(primitiveRay).then(function ( results ) { expect(results.length).toEqual(1); expect(results[0].object.primitive).toEqual(primitive); }); }); it("can drill pick batched Primitives without show attribute", function () { if (webglStub) { return; } var geometry = new RectangleGeometry({ rectangle: Rectangle.fromDegrees(-50.0, -50.0, 50.0, 50.0), granularity: CesiumMath.toRadians(20.0), vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT, height: 0.0, }); var geometryWithHeight = new RectangleGeometry({ rectangle: Rectangle.fromDegrees(-50.0, -50.0, 50.0, 50.0), granularity: CesiumMath.toRadians(20.0), vertexFormat: EllipsoidSurfaceAppearance.VERTEX_FORMAT, height: 1.0, }); var instance1 = new GeometryInstance({ id: 1, geometry: geometry, }); var instance2 = new GeometryInstance({ id: 2, geometry: geometry, }); var instance3 = new GeometryInstance({ id: 3, geometry: geometryWithHeight, }); var primitive = primitives.add( new Primitive({ geometryInstances: [instance1, instance2, instance3], asynchronous: false, appearance: new EllipsoidSurfaceAppearance(), }) ); scene.camera.setView({ destination: offscreenRectangle }); return drillPickFromRayMostDetailed(primitiveRay).then(function ( results ) { expect(results.length).toEqual(1); expect(results[0].object.primitive).toEqual(primitive); expect(results[0].object.id).toEqual(3); }); }); it("stops drill picking when the limit is reached.", function () { if (webglStub) { return; } createLargeRectangle(0.0); var rectangle2 = createLargeRectangle(1.0); var rectangle3 = createLargeRectangle(2.0); var rectangle4 = createLargeRectangle(3.0); scene.camera.setView({ destination: offscreenRectangle }); return drillPickFromRayMostDetailed(primitiveRay, 3).then(function ( results ) { expect(results.length).toEqual(3); expect(results[0].object.primitive).toEqual(rectangle4); expect(results[1].object.primitive).toEqual(rectangle3); expect(results[2].object.primitive).toEqual(rectangle2); }); }); it("excludes objects", function () { if (webglStub) { return; } createLargeRectangle(0.0); var rectangle2 = createLargeRectangle(1.0); var rectangle3 = createLargeRectangle(2.0); var rectangle4 = createLargeRectangle(3.0); var rectangle5 = createLargeRectangle(4.0); scene.camera.setView({ destination: offscreenRectangle }); return drillPickFromRayMostDetailed(primitiveRay, 2, [ rectangle5, rectangle3, ]).then(function (results) { expect(results.length).toBe(2); expect(results[0].object.primitive).toBe(rectangle4); expect(results[1].object.primitive).toBe(rectangle2); }); }); it("changes width", function () { if (webglStub) { return; } return createTileset(pointCloudTilesetUrl).then(function (tileset) { var promise1 = drillPickFromRayMostDetailed( primitiveRay, 1, [], 0.1 ).then(function (result) { expect(result.length).toBe(0); }); var promise2 = drillPickFromRayMostDetailed( primitiveRay, 1, [], 1.0 ).then(function (result) { expect(result.length).toBe(1); }); return when.all([promise1, promise2]); }); }); it("throws if ray is undefined", function () { expect(function () { scene.drillPickFromRayMostDetailed(undefined); }).toThrowDeveloperError(); }); it("throws if scene camera is in 2D", function () { scene.morphTo2D(0.0); expect(function () { scene.drillPickFromRayMostDetailed(primitiveRay); }).toThrowDeveloperError(); }); it("throws if scene camera is in CV", function () { scene.morphToColumbusView(0.0); expect(function () { scene.drillPickFromRayMostDetailed(primitiveRay); }).toThrowDeveloperError(); }); }); describe("sampleHeightMostDetailed", function () { it("samples height from tileset", function () { if (!scene.sampleHeightSupported) { return; } var cartographics = [new Cartographic(0.0, 0.0)]; return createTileset(batchedTilesetUrl).then(function () { return sampleHeightMostDetailed(cartographics).then(function ( updatedCartographics ) { var height = updatedCartographics[0].height; expect(height).toBeGreaterThan(0.0); expect(height).toBeLessThan(20.0); // Rough height of tile }); }); }); it("samples height from the globe", function () { if (!scene.sampleHeightSupported) { return; } var cartographics = [ new Cartographic(0.0, 0.0), new Cartographic(0.0001, 0.0001), new Cartographic(0.0002, 0.0002), ]; var clonedCartographics = [ new Cartographic(0.0, 0.0), new Cartographic(0.0001, 0.0001), new Cartographic(0.0002, 0.0002), ]; return createGlobe().then(function () { return sampleHeightMostDetailed(cartographics).then(function ( updatedCartographics ) { expect(updatedCartographics).toBe(cartographics); expect(updatedCartographics.length).toBe(3); var previousHeight; for (var i = 0; i < 3; ++i) { var longitude = updatedCartographics[i].longitude; var latitude = updatedCartographics[i].latitude; var height = updatedCartographics[i].height; expect(longitude).toBe(clonedCartographics[i].longitude); expect(latitude).toBe(clonedCartographics[i].latitude); expect(height).toBeDefined(); expect(height).not.toBe(previousHeight); previousHeight = height; } }); }); }); it("does not sample offscreen globe tiles", function () { if (!scene.sampleHeightSupported) { return; } var cartographics = [new Cartographic(0.0, 0.0)]; scene.camera.setView({ destination: offscreenRectangle }); return createGlobe().then(function () { return sampleHeightMostDetailed(cartographics).then(function ( updatedCartographics ) { expect(updatedCartographics[0].height).toBeUndefined(); }); }); }); it("samples height from multiple primitives", function () { if (!scene.sampleHeightSupported) { return; } createRectangle(0.0, smallRectangle); createRectangle(0.0, offscreenRectangle); var cartographics = [ Rectangle.center(smallRectangle), Rectangle.center(offscreenRectangle), new Cartographic(-2.0, -2.0), ]; scene.camera.setView({ destination: offscreenRectangle }); return sampleHeightMostDetailed(cartographics).then(function ( updatedCartographics ) { expect(updatedCartographics[0].height).toBeDefined(); expect(updatedCartographics[1].height).toBeDefined(); expect(updatedCartographics[2].height).toBeUndefined(); // No primitive occupies this space }); }); it("samples multiple heights from primitive", function () { if (!scene.sampleHeightSupported) { return; } createSmallRectangle(0.0); var cartographics = [ new Cartographic(0.0, 0.0), new Cartographic(-0.000001, -0.000001), new Cartographic(0.0000005, 0.0000005), ]; scene.camera.setView({ destination: offscreenRectangle }); return sampleHeightMostDetailed(cartographics).then(function ( updatedCartographics ) { var previousHeight; for (var i = 0; i < 3; ++i) { var height = updatedCartographics[i].height; expect(height).toEqualEpsilon(0.0, CesiumMath.EPSILON3); expect(height).not.toBe(previousHeight); previousHeight = height; } }); }); it("samples height from the top primitive", function () { if (!scene.sampleHeightSupported) { return; } createSmallRectangle(0.0); createSmallRectangle(1.0); var cartographics = [new Cartographic(0.0, 0.0)]; scene.camera.setView({ destination: offscreenRectangle }); return sampleHeightMostDetailed(cartographics).then(function ( updatedCartographics ) { expect(updatedCartographics[0].height).toEqualEpsilon( 1.0, CesiumMath.EPSILON3 ); }); }); it("excludes objects", function () { if (!scene.sampleHeightSupported) { return; } var rectangle1 = createRectangle(0.0, smallRectangle); createRectangle(0.0, offscreenRectangle); var rectangle3 = createRectangle(1.0, offscreenRectangle); var cartographics = [ Rectangle.center(smallRectangle), Rectangle.center(offscreenRectangle), new Cartographic(-2.0, -2.0), ]; scene.camera.setView({ destination: offscreenRectangle }); return sampleHeightMostDetailed(cartographics, [ rectangle1, rectangle3, ]).then(function (updatedCartographics) { expect(updatedCartographics[0].height).toBeUndefined(); // This rectangle was excluded expect(updatedCartographics[1].height).toEqualEpsilon( 0.0, CesiumMath.EPSILON2 ); expect(updatedCartographics[2].height).toBeUndefined(); // No primitive occupies this space }); }); it("excludes primitive that doesn't write depth", function () { if (!scene.sampleHeightSupported) { return; } var rectangle = createSmallRectangle(0.0); var height = 100.0; var cartographics = [new Cartographic(0.0, 0.0, height)]; var collection = scene.primitives.add(new PointPrimitiveCollection()); var point = collection.add({ position: Cartographic.toCartesian(cartographics[0]), }); scene.camera.setView({ destination: offscreenRectangle }); return sampleHeightMostDetailed(cartographics) .then(function (updatedCartographics) { expect(updatedCartographics[0].height).toEqualEpsilon( height, CesiumMath.EPSILON3 ); }) .then(function () { point.disableDepthTestDistance = Number.POSITIVE_INFINITY; return sampleHeightMostDetailed(cartographics).then(function ( updatedCartographics ) { expect(updatedCartographics[0].height).toEqualEpsilon( 0.0, CesiumMath.EPSILON3 ); }); }) .then(function () { rectangle.show = false; return sampleHeightMostDetailed(cartographics).then(function ( updatedCartographics ) { expect(updatedCartographics[0].height).toBeUndefined(); }); }); }); it("changes width", function () { if (!scene.sampleHeightSupported) { return; } var cartographics1 = [new Cartographic(0.0, 0.0)]; var cartographics2 = [new Cartographic(0.0, 0.0)]; return createTileset(pointCloudTilesetUrl).then(function (tileset) { var promise1 = sampleHeightMostDetailed(cartographics1, [], 0.1).then( function (updatedCartographics1) { expect(updatedCartographics1[0].height).toBeUndefined(); } ); var promise2 = sampleHeightMostDetailed(cartographics2, [], 1.0).then( function (updatedCartographics2) { expect(updatedCartographics2[0].height).toBeDefined(); } ); return when.all([promise1, promise2]); }); }); it("handles empty array", function () { if (!scene.sampleHeightSupported) { return; } var cartographics = []; return sampleHeightMostDetailed(cartographics).then(function ( updatedCartographics ) { expect(updatedCartographics.length).toBe(0); }); }); it("throws if positions is undefined", function () { if (!scene.sampleHeightSupported) { return; } expect(function () { scene.sampleHeightMostDetailed(undefined); }).toThrowDeveloperError(); }); it("throws if scene camera is in 2D", function () { if (!scene.sampleHeightSupported) { return; } scene.morphTo2D(0.0); var cartographics = [new Cartographic(0.0, 0.0)]; expect(function () { scene.sampleHeightMostDetailed(cartographics); }).toThrowDeveloperError(); }); it("throws if scene camera is in CV", function () { if (!scene.sampleHeightSupported) { return; } scene.morphToColumbusView(0.0); var cartographics = [new Cartographic(0.0, 0.0)]; expect(function () { scene.sampleHeightMostDetailed(cartographics); }).toThrowDeveloperError(); }); it("throws if sampleHeight is not supported", function () { if (!scene.sampleHeightSupported) { return; } // Disable extension var depthTexture = scene.context._depthTexture; scene.context._depthTexture = false; var cartographics = [new Cartographic(0.0, 0.0)]; expect(function () { scene.sampleHeightMostDetailed(cartographics); }).toThrowDeveloperError(); // Re-enable extension scene.context._depthTexture = depthTexture; }); }); describe("clampToHeightMostDetailed", function () { it("clamps to tileset", function () { if (!scene.clampToHeightSupported) { return; } var cartesians = [Cartesian3.fromRadians(0.0, 0.0, 100000.0)]; return createTileset(batchedTilesetUrl).then(function () { return clampToHeightMostDetailed(cartesians).then(function ( updatedCartesians ) { var minimumHeight = Cartesian3.fromRadians(0.0, 0.0).x; var maximumHeight = minimumHeight + 20.0; // Rough height of tile var position = updatedCartesians[0]; expect(position.x).toBeGreaterThan(minimumHeight); expect(position.x).toBeLessThan(maximumHeight); expect(position.y).toEqualEpsilon(0.0, CesiumMath.EPSILON5); expect(position.z).toEqualEpsilon(0.0, CesiumMath.EPSILON5); }); }); }); it("clamps to the globe", function () { if (!scene.clampToHeightSupported) { return; } var cartesians = [ Cartesian3.fromRadians(0.0, 0.0, 100000.0), Cartesian3.fromRadians(0.0001, 0.0001, 100000.0), Cartesian3.fromRadians(0.0002, 0.0002, 100000.0), ]; var clonedCartesians = [ Cartesian3.fromRadians(0.0, 0.0, 100000.0), Cartesian3.fromRadians(0.0001, 0.0001, 100000.0), Cartesian3.fromRadians(0.0002, 0.0002, 100000.0), ]; return createGlobe().then(function () { return clampToHeightMostDetailed(cartesians).then(function ( updatedCartesians ) { expect(updatedCartesians).toBe(cartesians); expect(updatedCartesians.length).toBe(3); var previousCartesian; for (var i = 0; i < 3; ++i) { expect(updatedCartesians[i]).not.toEqual(clonedCartesians[i]); expect(updatedCartesians[i]).not.toEqual(previousCartesian); previousCartesian = updatedCartesians[i]; } }); }); }); it("does not clamp to offscreen globe tiles", function () { if (!scene.clampToHeightSupported) { return; } var cartesians = [Cartesian3.fromRadians(0.0, 0.0, 100000.0)]; scene.camera.setView({ destination: offscreenRectangle }); return createGlobe().then(function () { return clampToHeightMostDetailed(cartesians).then(function ( updatedCartesians ) { expect(updatedCartesians[0]).toBeUndefined(); }); }); }); it("clamps to multiple primitives", function () { if (!scene.clampToHeightSupported) { return; } createRectangle(0.0, smallRectangle); createRectangle(0.0, offscreenRectangle); var cartesians = [ Cartographic.toCartesian(Rectangle.center(smallRectangle)), Cartographic.toCartesian(Rectangle.center(offscreenRectangle)), Cartesian3.fromRadians(-2.0, -2.0), ]; scene.camera.setView({ destination: offscreenRectangle }); return clampToHeightMostDetailed(cartesians).then(function ( updatedCartesians ) { expect(updatedCartesians[0]).toBeDefined(); expect(updatedCartesians[1]).toBeDefined(); expect(updatedCartesians[2]).toBeUndefined(); // No primitive occupies this space }); }); it("clamps to primitive", function () { if (!scene.clampToHeightSupported) { return; } createSmallRectangle(0.0); var cartesians = [ Cartesian3.fromRadians(0.0, 0.0, 100000.0), Cartesian3.fromRadians(-0.000001, -0.000001, 100000.0), Cartesian3.fromRadians(0.0000005, 0.0000005, 100000.0), ]; var expectedCartesians = [ Cartesian3.fromRadians(0.0, 0.0, 0.0), Cartesian3.fromRadians(-0.000001, -0.000001, 0.0), Cartesian3.fromRadians(0.0000005, 0.0000005, 0.0), ]; scene.camera.setView({ destination: offscreenRectangle }); return clampToHeightMostDetailed(cartesians).then(function ( updatedCartesians ) { var previousCartesian; for (var i = 0; i < 3; ++i) { expect(updatedCartesians[i]).toEqualEpsilon( expectedCartesians[i], CesiumMath.EPSILON5 ); expect(updatedCartesians[i]).not.toEqual(previousCartesian); previousCartesian = updatedCartesians[i]; } }); }); it("clamps to top primitive", function () { if (!scene.clampToHeightSupported) { return; } createSmallRectangle(0.0); createSmallRectangle(1.0); var cartesians = [Cartesian3.fromRadians(0.0, 0.0)]; scene.camera.setView({ destination: offscreenRectangle }); return clampToHeightMostDetailed(cartesians).then(function ( updatedCartesians ) { var expectedCartesian = Cartesian3.fromRadians(0.0, 0.0, 1.0); expect(updatedCartesians[0]).toEqualEpsilon( expectedCartesian, CesiumMath.EPSILON5 ); }); }); it("excludes objects", function () { if (!scene.clampToHeightSupported) { return; } var rectangle1 = createRectangle(0.0, smallRectangle); createRectangle(0.0, offscreenRectangle); var rectangle3 = createRectangle(1.0, offscreenRectangle); var cartesians = [ Cartographic.toCartesian(Rectangle.center(smallRectangle)), Cartographic.toCartesian(Rectangle.center(offscreenRectangle)), Cartesian3.fromRadians(-2.0, -2.0), ]; scene.camera.setView({ destination: offscreenRectangle }); return clampToHeightMostDetailed(cartesians, [ rectangle1, rectangle3, ]).then(function (updatedCartesians) { var expectedCartesian = Cartographic.toCartesian( Rectangle.center(offscreenRectangle) ); expect(updatedCartesians[0]).toBeUndefined(); // This rectangle was excluded expect(updatedCartesians[1]).toEqualEpsilon( expectedCartesian, CesiumMath.EPSILON2 ); expect(updatedCartesians[2]).toBeUndefined(); // No primitive occupies this space }); }); it("excludes primitive that doesn't write depth", function () { if (!scene.clampToHeightSupported) { return; } var rectangle = createSmallRectangle(0.0); var height = 100.0; var cartesian = Cartesian3.fromRadians(0.0, 0.0, height); var cartesians1 = [Cartesian3.clone(cartesian)]; var cartesians2 = [Cartesian3.clone(cartesian)]; var cartesians3 = [Cartesian3.clone(cartesian)]; var collection = scene.primitives.add(new PointPrimitiveCollection()); var point = collection.add({ position: cartesian, }); scene.camera.setView({ destination: offscreenRectangle }); return clampToHeightMostDetailed(cartesians1) .then(function (updatedCartesians) { expect(updatedCartesians[0]).toEqualEpsilon( cartesian, CesiumMath.EPSILON3 ); }) .then(function () { point.disableDepthTestDistance = Number.POSITIVE_INFINITY; return clampToHeightMostDetailed(cartesians2).then(function ( updatedCartesians ) { expect(updatedCartesians[0]).toEqualEpsilon( cartesian, CesiumMath.EPSILON3 ); }); }) .then(function () { rectangle.show = false; return clampToHeightMostDetailed(cartesians3).then(function ( updatedCartesians ) { expect(updatedCartesians[0]).toBeUndefined(); }); }); }); it("changes width", function () { if (!scene.clampToHeightSupported) { return; } var cartesian = Cartesian3.fromRadians(0.0, 0.0, 100.0); var cartesians1 = [Cartesian3.clone(cartesian)]; var cartesians2 = [Cartesian3.clone(cartesian)]; return createTileset(pointCloudTilesetUrl).then(function (tileset) { var promise1 = clampToHeightMostDetailed(cartesians1, [], 0.1).then( function (clampedCartesians1) { expect(clampedCartesians1[0]).toBeUndefined(); } ); var promise2 = clampToHeightMostDetailed(cartesians2, [], 1.0).then( function (clampedCartesians2) { expect(clampedCartesians2[0]).toBeDefined(); } ); return when.all([promise1, promise2]); }); }); it("handles empty array", function () { if (!scene.clampToHeightSupported) { return; } var cartesians = []; return sampleHeightMostDetailed(cartesians).then(function ( updatedCartesians ) { expect(updatedCartesians.length).toBe(0); }); }); it("throws if cartesians is undefined", function () { if (!scene.clampToHeightSupported) { return; } expect(function () { scene.clampToHeightMostDetailed(undefined); }).toThrowDeveloperError(); }); it("throws if scene camera is in 2D", function () { if (!scene.clampToHeightSupported) { return; } scene.morphTo2D(0.0); var cartesians = [Cartesian3.fromRadians(0.0, 0.0)]; expect(function () { scene.clampToHeightMostDetailed(cartesians); }).toThrowDeveloperError(); }); it("throws if scene camera is in CV", function () { if (!scene.clampToHeightSupported) { return; } scene.morphToColumbusView(0.0); var cartesians = [Cartesian3.fromRadians(0.0, 0.0)]; expect(function () { scene.clampToHeightMostDetailed(cartesians); }).toThrowDeveloperError(); }); it("throws if clampToHeight is not supported", function () { if (!scene.clampToHeightSupported) { return; } // Disable extension var depthTexture = scene.context._depthTexture; scene.context._depthTexture = false; var cartesians = [Cartesian3.fromRadians(0.0, 0.0)]; expect(function () { scene.clampToHeightMostDetailed(cartesians); }).toThrowDeveloperError(); // Re-enable extension scene.context._depthTexture = depthTexture; }); }); it("calls multiple picking functions within the same frame", function () { if (!scene.clampToHeightSupported || !scene.pickPositionSupported) { return; } createSmallRectangle(0.0); var offscreenRectanglePrimitive = createRectangle( 0.0, offscreenRectangle ); offscreenRectanglePrimitive.appearance.material.uniforms.color = new Color( 1.0, 0.0, 0.0, 1.0 ); scene.camera.setView({ destination: offscreenRectangle }); // Call render. Lays down depth for the pickPosition call scene.renderForSpecs(); var cartographic = Cartographic.fromRadians(0.0, 0.0, 100000.0); var cartesian = Cartographic.toCartesian(cartographic); var cartesians = [Cartesian3.clone(cartesian)]; var cartographics = [cartographic]; // Call clampToHeight expect(scene).toClampToHeightAndCall(function (cartesian) { var expectedCartesian = Cartesian3.fromRadians(0.0, 0.0); expect(cartesian).toEqualEpsilon( expectedCartesian, CesiumMath.EPSILON5 ); }, cartesian); // Call pickPosition expect(scene).toPickPositionAndCall(function (cartesian) { var expectedCartesian = Cartographic.toCartesian( Rectangle.center(offscreenRectangle) ); expect(cartesian).toEqualEpsilon( expectedCartesian, CesiumMath.EPSILON5 ); }); // Call clampToHeight again expect(scene).toClampToHeightAndCall(function (cartesian) { var expectedCartesian = Cartesian3.fromRadians(0.0, 0.0); expect(cartesian).toEqualEpsilon( expectedCartesian, CesiumMath.EPSILON5 ); }, cartesian); // Call pick expect(scene).toPickPrimitive(offscreenRectanglePrimitive); // Call clampToHeight again expect(scene).toClampToHeightAndCall(function (cartesian) { var expectedCartesian = Cartesian3.fromRadians(0.0, 0.0); expect(cartesian).toEqualEpsilon( expectedCartesian, CesiumMath.EPSILON5 ); }, cartesian); // Call pickPosition on translucent primitive and returns undefined offscreenRectanglePrimitive.appearance.material.uniforms.color = new Color( 1.0, 0.0, 0.0, 0.5 ); scene.renderForSpecs(); expect(scene).toPickPositionAndCall(function (cartesian) { expect(cartesian).toBeUndefined(); }); // Call clampToHeight again expect(scene).toClampToHeightAndCall(function (cartesian) { var expectedCartesian = Cartesian3.fromRadians(0.0, 0.0); expect(cartesian).toEqualEpsilon( expectedCartesian, CesiumMath.EPSILON5 ); }, cartesian); // Call pickPosition on translucent primitive with pickTranslucentDepth scene.pickTranslucentDepth = true; scene.renderForSpecs(); expect(scene).toPickPositionAndCall(function (cartesian) { var expectedCartesian = Cartographic.toCartesian( Rectangle.center(offscreenRectangle) ); expect(cartesian).toEqualEpsilon( expectedCartesian, CesiumMath.EPSILON5 ); }); // Mix async and sync requests var results = []; var completed = 0; scene .clampToHeightMostDetailed(cartesians) .then(function (updatedCartesians) { results.push(updatedCartesians); completed++; }); scene .sampleHeightMostDetailed(cartographics) .then(function (updatedCartographics) { results.push(updatedCartographics); completed++; }); // Call clampToHeight again expect(scene).toClampToHeightAndCall(function (cartesian) { var expectedCartesian = Cartesian3.fromRadians(0.0, 0.0); expect(cartesian).toEqualEpsilon( expectedCartesian, CesiumMath.EPSILON5 ); }, cartesian); return pollToPromise(function () { // Scene requires manual updates in the tests to move along the promise scene.render(); return completed === 2; }).then(function () { expect(results[0][0]).toBeDefined(); expect(results[1][0].height).toBeDefined(); }); }); }, "WebGL" );