import { ApproximateTerrainHeights } from "../../Source/Cesium.js"; import { ArcType } from "../../Source/Cesium.js"; import { arraySlice } from "../../Source/Cesium.js"; import { Cartesian3 } from "../../Source/Cesium.js"; import { Cartographic } from "../../Source/Cesium.js"; import { Ellipsoid } from "../../Source/Cesium.js"; import { GeographicProjection } from "../../Source/Cesium.js"; import { GroundPolylineGeometry } from "../../Source/Cesium.js"; import { Math as CesiumMath } from "../../Source/Cesium.js"; import { WebMercatorProjection } from "../../Source/Cesium.js"; import createPackableSpecs from "../createPackableSpecs.js"; describe("Core/GroundPolylineGeometry", function () { beforeAll(function () { return ApproximateTerrainHeights.initialize(); }); afterAll(function () { ApproximateTerrainHeights._initPromise = undefined; ApproximateTerrainHeights._terrainHeights = undefined; }); function verifyAttributeValuesIdentical(attribute) { var values = attribute.values; var componentsPerAttribute = attribute.componentsPerAttribute; var vertexCount = values.length / componentsPerAttribute; var firstVertex = arraySlice(values, 0, componentsPerAttribute); var identical = true; for (var i = 1; i < vertexCount; i++) { var index = i * componentsPerAttribute; var vertex = arraySlice(values, index, index + componentsPerAttribute); for (var j = 0; j < componentsPerAttribute; j++) { if (vertex[j] !== firstVertex[j]) { identical = false; break; } } } expect(identical).toBe(true); } it("computes positions and additional attributes for polylines", function () { var startCartographic = Cartographic.fromDegrees(0.01, 0.0); var endCartographic = Cartographic.fromDegrees(0.02, 0.0); var groundPolylineGeometry = new GroundPolylineGeometry({ positions: Cartesian3.fromRadiansArray([ startCartographic.longitude, startCartographic.latitude, endCartographic.longitude, endCartographic.latitude, ]), granularity: 0.0, }); var geometry = GroundPolylineGeometry.createGeometry( groundPolylineGeometry ); expect(geometry.indices.length).toEqual(36); expect(geometry.attributes.position.values.length).toEqual(24); var startHiAndForwardOffsetX = geometry.attributes.startHiAndForwardOffsetX; var startLoAndForwardOffsetY = geometry.attributes.startLoAndForwardOffsetY; var startNormalAndForwardOffsetZ = geometry.attributes.startNormalAndForwardOffsetZ; var endNormalAndTextureCoordinateNormalizationX = geometry.attributes.endNormalAndTextureCoordinateNormalizationX; var rightNormalAndTextureCoordinateNormalizationY = geometry.attributes.rightNormalAndTextureCoordinateNormalizationY; var startHiLo2D = geometry.attributes.startHiLo2D; var offsetAndRight2D = geometry.attributes.offsetAndRight2D; var startEndNormals2D = geometry.attributes.startEndNormals2D; var texcoordNormalization2D = geometry.attributes.texcoordNormalization2D; // Expect each entry in the additional attributes to be identical across all vertices since this is a single segment, // except endNormalAndTextureCoordinateNormalizationX and texcoordNormalization2D, which should be "sided" verifyAttributeValuesIdentical(startHiAndForwardOffsetX); verifyAttributeValuesIdentical(startLoAndForwardOffsetY); verifyAttributeValuesIdentical(startNormalAndForwardOffsetZ); verifyAttributeValuesIdentical(startHiLo2D); verifyAttributeValuesIdentical(offsetAndRight2D); verifyAttributeValuesIdentical(startEndNormals2D); // Expect endNormalAndTextureCoordinateNormalizationX and texcoordNormalization2D.x to encode the "side" of the geometry var i; var index; var values = endNormalAndTextureCoordinateNormalizationX.values; for (i = 0; i < 4; i++) { index = i * 4 + 3; expect(CesiumMath.sign(values[index])).toEqual(1.0); } for (i = 4; i < 8; i++) { index = i * 4 + 3; expect(CesiumMath.sign(values[index])).toEqual(-1.0); } values = texcoordNormalization2D.values; for (i = 0; i < 4; i++) { index = i * 2; expect(CesiumMath.sign(values[index])).toEqual(1.0); } for (i = 4; i < 8; i++) { index = i * 2; expect(CesiumMath.sign(values[index])).toEqual(-1.0); } // Expect rightNormalAndTextureCoordinateNormalizationY and texcoordNormalization2D.y to encode if the vertex is on the bottom values = rightNormalAndTextureCoordinateNormalizationY.values; expect(values[3]).toBeGreaterThan(1.0); expect(values[1 * 4 + 3]).toBeGreaterThan(1.0); expect(values[4 * 4 + 3]).toBeGreaterThan(1.0); expect(values[5 * 4 + 3]).toBeGreaterThan(1.0); values = texcoordNormalization2D.values; expect(values[1]).toBeGreaterThan(1.0); expect(values[1 * 2 + 1]).toBeGreaterThan(1.0); expect(values[4 * 2 + 1]).toBeGreaterThan(1.0); expect(values[5 * 2 + 1]).toBeGreaterThan(1.0); // Line segment geometry is encoded as: // - start position // - offset to the end position // - normal for a mitered plane at each end // - a right-facing normal // - parameters for localizing the position along the line to texture coordinates var startPosition3D = new Cartesian3(); startPosition3D.x = startHiAndForwardOffsetX.values[0] + startLoAndForwardOffsetY.values[0]; startPosition3D.y = startHiAndForwardOffsetX.values[1] + startLoAndForwardOffsetY.values[1]; startPosition3D.z = startHiAndForwardOffsetX.values[2] + startLoAndForwardOffsetY.values[2]; var reconstructedCarto = Cartographic.fromCartesian(startPosition3D); reconstructedCarto.height = 0.0; expect( Cartographic.equalsEpsilon( reconstructedCarto, startCartographic, CesiumMath.EPSILON7 ) ).toBe(true); var endPosition3D = new Cartesian3(); endPosition3D.x = startPosition3D.x + startHiAndForwardOffsetX.values[3]; endPosition3D.y = startPosition3D.y + startLoAndForwardOffsetY.values[3]; endPosition3D.z = startPosition3D.z + startNormalAndForwardOffsetZ.values[3]; reconstructedCarto = Cartographic.fromCartesian(endPosition3D); reconstructedCarto.height = 0.0; expect( Cartographic.equalsEpsilon( reconstructedCarto, endCartographic, CesiumMath.EPSILON7 ) ).toBe(true); var startNormal3D = Cartesian3.unpack(startNormalAndForwardOffsetZ.values); expect( Cartesian3.equalsEpsilon( startNormal3D, new Cartesian3(0.0, 1.0, 0.0), CesiumMath.EPSILON2 ) ).toBe(true); var endNormal3D = Cartesian3.unpack( endNormalAndTextureCoordinateNormalizationX.values ); expect( Cartesian3.equalsEpsilon( endNormal3D, new Cartesian3(0.0, -1.0, 0.0), CesiumMath.EPSILON2 ) ).toBe(true); var rightNormal3D = Cartesian3.unpack( rightNormalAndTextureCoordinateNormalizationY.values ); expect( Cartesian3.equalsEpsilon( rightNormal3D, new Cartesian3(0.0, 0.0, -1.0), CesiumMath.EPSILON2 ) ).toBe(true); var texcoordNormalizationX = endNormalAndTextureCoordinateNormalizationX.values[3]; expect(texcoordNormalizationX).toEqualEpsilon(1.0, CesiumMath.EPSILON3); // 2D var projection = new GeographicProjection(); var startPosition2D = new Cartesian3(); startPosition2D.x = startHiLo2D.values[0] + startHiLo2D.values[2]; startPosition2D.y = startHiLo2D.values[1] + startHiLo2D.values[3]; reconstructedCarto = projection.unproject(startPosition2D); reconstructedCarto.height = 0.0; expect( Cartographic.equalsEpsilon( reconstructedCarto, startCartographic, CesiumMath.EPSILON7 ) ).toBe(true); var endPosition2D = new Cartesian3(); endPosition2D.x = startPosition2D.x + offsetAndRight2D.values[0]; endPosition2D.y = startPosition2D.y + offsetAndRight2D.values[1]; reconstructedCarto = projection.unproject(endPosition2D); reconstructedCarto.height = 0.0; expect( Cartographic.equalsEpsilon( reconstructedCarto, endCartographic, CesiumMath.EPSILON7 ) ).toBe(true); var startNormal2D = new Cartesian3(); startNormal2D.x = startEndNormals2D.values[0]; startNormal2D.y = startEndNormals2D.values[1]; expect( Cartesian3.equalsEpsilon( startNormal2D, new Cartesian3(1.0, 0.0, 0.0), CesiumMath.EPSILON2 ) ).toBe(true); var endNormal2D = new Cartesian3(); endNormal2D.x = startEndNormals2D.values[2]; endNormal2D.y = startEndNormals2D.values[3]; expect( Cartesian3.equalsEpsilon( endNormal2D, new Cartesian3(-1.0, 0.0, 0.0), CesiumMath.EPSILON2 ) ).toBe(true); var rightNormal2D = new Cartesian3(); rightNormal2D.x = offsetAndRight2D.values[2]; rightNormal2D.y = offsetAndRight2D.values[3]; expect( Cartesian3.equalsEpsilon( rightNormal2D, new Cartesian3(0.0, -1.0, 0.0), CesiumMath.EPSILON2 ) ).toBe(true); texcoordNormalizationX = texcoordNormalization2D.values[0]; expect(texcoordNormalizationX).toEqualEpsilon(1.0, CesiumMath.EPSILON3); }); it("does not generate 2D attributes when scene3DOnly is true", function () { var startCartographic = Cartographic.fromDegrees(0.01, 0.0); var endCartographic = Cartographic.fromDegrees(0.02, 0.0); var groundPolylineGeometry = new GroundPolylineGeometry({ positions: Cartesian3.fromRadiansArray([ startCartographic.longitude, startCartographic.latitude, endCartographic.longitude, endCartographic.latitude, ]), granularity: 0.0, }); groundPolylineGeometry._scene3DOnly = true; var geometry = GroundPolylineGeometry.createGeometry( groundPolylineGeometry ); expect(geometry.attributes.startHiAndForwardOffsetX).toBeDefined(); expect(geometry.attributes.startLoAndForwardOffsetY).toBeDefined(); expect(geometry.attributes.startNormalAndForwardOffsetZ).toBeDefined(); expect( geometry.attributes.endNormalAndTextureCoordinateNormalizationX ).toBeDefined(); expect( geometry.attributes.rightNormalAndTextureCoordinateNormalizationY ).toBeDefined(); expect(geometry.attributes.startHiLo2D).not.toBeDefined(); expect(geometry.attributes.offsetAndRight2D).not.toBeDefined(); expect(geometry.attributes.startEndNormals2D).not.toBeDefined(); expect(geometry.attributes.texcoordNormalization2D).not.toBeDefined(); }); it("removes adjacent positions with the same latitude/longitude", function () { var startCartographic = Cartographic.fromDegrees(0.01, 0.0); var endCartographic = Cartographic.fromDegrees(0.02, 0.0); var groundPolylineGeometry = new GroundPolylineGeometry({ positions: Cartesian3.fromRadiansArrayHeights([ startCartographic.longitude, startCartographic.latitude, 0.0, endCartographic.longitude, endCartographic.latitude, 0.0, endCartographic.longitude, endCartographic.latitude, 0.0, endCartographic.longitude, endCartographic.latitude, 10.0, ]), granularity: 0.0, }); var geometry = GroundPolylineGeometry.createGeometry( groundPolylineGeometry ); expect(geometry.indices.length).toEqual(36); expect(geometry.attributes.position.values.length).toEqual(24); }); it("returns undefined if filtered points are not a valid geometry", function () { var startCartographic = Cartographic.fromDegrees(0.01, 0.0); var groundPolylineGeometry = new GroundPolylineGeometry({ positions: Cartesian3.fromRadiansArrayHeights([ startCartographic.longitude, startCartographic.latitude, 0.0, startCartographic.longitude, startCartographic.latitude, 0.0, ]), granularity: 0.0, }); var geometry = GroundPolylineGeometry.createGeometry( groundPolylineGeometry ); expect(geometry).toBeUndefined(); }); it("miters turns", function () { var groundPolylineGeometry = new GroundPolylineGeometry({ positions: Cartesian3.fromDegreesArray([ 0.01, 0.0, 0.02, 0.0, 0.02, 0.01, ]), granularity: 0.0, }); var geometry = GroundPolylineGeometry.createGeometry( groundPolylineGeometry ); expect(geometry.indices.length).toEqual(72); expect(geometry.attributes.position.values.length).toEqual(48); var startNormalAndForwardOffsetZvalues = geometry.attributes.startNormalAndForwardOffsetZ.values; var endNormalAndTextureCoordinateNormalizationXvalues = geometry.attributes.endNormalAndTextureCoordinateNormalizationX.values; var miteredStartNormal = Cartesian3.unpack( startNormalAndForwardOffsetZvalues, 32 ); var miteredEndNormal = Cartesian3.unpack( endNormalAndTextureCoordinateNormalizationXvalues, 0 ); var reverseMiteredEndNormal = Cartesian3.multiplyByScalar( miteredEndNormal, -1.0, new Cartesian3() ); expect( Cartesian3.equalsEpsilon( miteredStartNormal, reverseMiteredEndNormal, CesiumMath.EPSILON7 ) ).toBe(true); var approximateExpectedMiterNormal = new Cartesian3(0.0, 1.0, 1.0); Cartesian3.normalize( approximateExpectedMiterNormal, approximateExpectedMiterNormal ); expect( Cartesian3.equalsEpsilon( approximateExpectedMiterNormal, miteredStartNormal, CesiumMath.EPSILON2 ) ).toBe(true); }); it("breaks miters for tight turns", function () { var groundPolylineGeometry = new GroundPolylineGeometry({ positions: Cartesian3.fromDegreesArray([ 0.01, 0.0, 0.02, 0.0, 0.01, CesiumMath.EPSILON7, ]), granularity: 0.0, }); var geometry = GroundPolylineGeometry.createGeometry( groundPolylineGeometry ); var startNormalAndForwardOffsetZvalues = geometry.attributes.startNormalAndForwardOffsetZ.values; var endNormalAndTextureCoordinateNormalizationXvalues = geometry.attributes.endNormalAndTextureCoordinateNormalizationX.values; var miteredStartNormal = Cartesian3.unpack( startNormalAndForwardOffsetZvalues, 32 ); var miteredEndNormal = Cartesian3.unpack( endNormalAndTextureCoordinateNormalizationXvalues, 0 ); expect( Cartesian3.equalsEpsilon( miteredStartNormal, miteredEndNormal, CesiumMath.EPSILON7 ) ).toBe(true); var approximateExpectedMiterNormal = new Cartesian3(0.0, -1.0, 0.0); Cartesian3.normalize( approximateExpectedMiterNormal, approximateExpectedMiterNormal ); expect( Cartesian3.equalsEpsilon( approximateExpectedMiterNormal, miteredStartNormal, CesiumMath.EPSILON2 ) ).toBe(true); // Break miter on loop end groundPolylineGeometry = new GroundPolylineGeometry({ positions: Cartesian3.fromDegreesArray([ 0.01, 0.0, 0.02, 0.0, 0.015, CesiumMath.EPSILON7, ]), granularity: 0.0, loop: true, }); geometry = GroundPolylineGeometry.createGeometry(groundPolylineGeometry); startNormalAndForwardOffsetZvalues = geometry.attributes.startNormalAndForwardOffsetZ.values; endNormalAndTextureCoordinateNormalizationXvalues = geometry.attributes.endNormalAndTextureCoordinateNormalizationX.values; // Check normals at loop end miteredStartNormal = Cartesian3.unpack( startNormalAndForwardOffsetZvalues, 0 ); miteredEndNormal = Cartesian3.unpack( endNormalAndTextureCoordinateNormalizationXvalues, 32 * 2 ); expect( Cartesian3.equalsEpsilon( miteredStartNormal, miteredEndNormal, CesiumMath.EPSILON7 ) ).toBe(true); approximateExpectedMiterNormal = new Cartesian3(0.0, 1.0, 0.0); Cartesian3.normalize( approximateExpectedMiterNormal, approximateExpectedMiterNormal ); expect( Cartesian3.equalsEpsilon( approximateExpectedMiterNormal, miteredStartNormal, CesiumMath.EPSILON2 ) ).toBe(true); }); it("interpolates long polyline segments", function () { var groundPolylineGeometry = new GroundPolylineGeometry({ positions: Cartesian3.fromDegreesArray([0.01, 0.0, 0.02, 0.0]), granularity: 600.0, // 0.01 to 0.02 is about 1113 meters with default ellipsoid, expect two segments }); var geometry = GroundPolylineGeometry.createGeometry( groundPolylineGeometry ); expect(geometry.indices.length).toEqual(72); expect(geometry.attributes.position.values.length).toEqual(48); // Interpolate one segment but not the other groundPolylineGeometry = new GroundPolylineGeometry({ positions: Cartesian3.fromDegreesArray([ 0.01, 0.0, 0.02, 0.0, 0.0201, 0.0, ]), granularity: 600.0, }); geometry = GroundPolylineGeometry.createGeometry(groundPolylineGeometry); expect(geometry.indices.length).toEqual(36 * 3); expect(geometry.attributes.position.values.length).toEqual(24 * 3); }); it("interpolates long polyline segments for rhumb lines", function () { // rhumb distance = 289020, geodesic distance = 288677 var positions = Cartesian3.fromDegreesArray([10, 75, 20, 75]); var rhumbGroundPolylineGeometry = new GroundPolylineGeometry({ positions: positions, granularity: 2890.0, arcType: ArcType.RHUMB, }); var geodesicGroundPolylineGeometry = new GroundPolylineGeometry({ positions: positions, granularity: 2890.0, arcType: ArcType.GEODESIC, }); var rhumbGeometry = GroundPolylineGeometry.createGeometry( rhumbGroundPolylineGeometry ); var geodesicGeometry = GroundPolylineGeometry.createGeometry( geodesicGroundPolylineGeometry ); expect(rhumbGeometry.indices.length).toEqual(3636); expect(geodesicGeometry.indices.length).toEqual(3600); expect(geodesicGeometry.attributes.position.values.length).toEqual(2400); expect(rhumbGeometry.attributes.position.values.length).toEqual(2424); // Interpolate one segment but not the other positions = Cartesian3.fromDegreesArray([10, 75, 20, 75, 20.01, 75]); rhumbGroundPolylineGeometry = new GroundPolylineGeometry({ positions: positions, granularity: 2890.0, arcType: ArcType.RHUMB, }); geodesicGroundPolylineGeometry = new GroundPolylineGeometry({ positions: positions, granularity: 2890.0, arcType: ArcType.GEODESIC, }); rhumbGeometry = GroundPolylineGeometry.createGeometry( rhumbGroundPolylineGeometry ); geodesicGeometry = GroundPolylineGeometry.createGeometry( geodesicGroundPolylineGeometry ); expect(rhumbGeometry.indices.length).toEqual(3636 + 36); expect(geodesicGeometry.indices.length).toEqual(3600 + 36); expect(geodesicGeometry.attributes.position.values.length).toEqual( 2400 + 24 ); expect(rhumbGeometry.attributes.position.values.length).toEqual(2424 + 24); }); it("loops when there are enough positions and loop is specified", function () { var groundPolylineGeometry = new GroundPolylineGeometry({ positions: Cartesian3.fromDegreesArray([0.01, 0.0, 0.02, 0.0]), granularity: 0.0, loop: true, }); // Not enough positions to loop, should still be a single segment var geometry = GroundPolylineGeometry.createGeometry( groundPolylineGeometry ); expect(geometry.indices.length).toEqual(36); groundPolylineGeometry = new GroundPolylineGeometry({ positions: Cartesian3.fromDegreesArray([ 0.01, 0.0, 0.02, 0.0, 0.02, 0.02, ]), granularity: 0.0, loop: true, }); // Loop should produce 3 segments geometry = GroundPolylineGeometry.createGeometry(groundPolylineGeometry); expect(geometry.indices.length).toEqual(108); }); it("subdivides geometry across the IDL and Prime Meridian", function () { // Cross PM var groundPolylineGeometry = new GroundPolylineGeometry({ positions: Cartesian3.fromDegreesArray([-1.0, 0.0, 1.0, 0.0]), granularity: 0.0, // no interpolative subdivision }); var geometry = GroundPolylineGeometry.createGeometry( groundPolylineGeometry ); expect(geometry.indices.length).toEqual(72); expect(geometry.attributes.position.values.length).toEqual(48); // Cross IDL groundPolylineGeometry = new GroundPolylineGeometry({ positions: Cartesian3.fromDegreesArray([-179.0, 0.0, 179.0, 0.0]), granularity: 0.0, // no interpolative subdivision }); geometry = GroundPolylineGeometry.createGeometry(groundPolylineGeometry); expect(geometry.indices.length).toEqual(72); expect(geometry.attributes.position.values.length).toEqual(48); // Cross IDL going opposite direction and loop groundPolylineGeometry = new GroundPolylineGeometry({ positions: Cartesian3.fromDegreesArray([ 179.0, 0.0, 179.0, 1.0, -179.0, 1.0, -179.0, 0.0, ]), granularity: 0.0, // no interpolative subdivision loop: true, }); geometry = GroundPolylineGeometry.createGeometry(groundPolylineGeometry); expect(geometry.indices.length).toEqual(6 * 36); expect(geometry.attributes.position.values.length).toEqual(6 * 24); // Near-IDL case groundPolylineGeometry = new GroundPolylineGeometry({ positions: Cartesian3.fromDegreesArray([179.999, 80.0, -179.999, 80.0]), granularity: 0.0, // no interpolative subdivision }); geometry = GroundPolylineGeometry.createGeometry(groundPolylineGeometry); expect(geometry.indices.length).toEqual(72); expect(geometry.attributes.position.values.length).toEqual(48); }); it("throws errors if not enough positions have been provided", function () { expect(function () { return new GroundPolylineGeometry({ positions: Cartesian3.fromDegreesArray([0.01, 0.0]), granularity: 0.0, loop: true, }); }).toThrowDeveloperError(); }); it("can unpack onto an existing instance", function () { var groundPolylineGeometry = new GroundPolylineGeometry({ positions: Cartesian3.fromDegreesArray([-1.0, 0.0, 1.0, 0.0]), loop: true, granularity: 10.0, // no interpolative subdivision }); groundPolylineGeometry._scene3DOnly = true; GroundPolylineGeometry.setProjectionAndEllipsoid( groundPolylineGeometry, new WebMercatorProjection(Ellipsoid.UNIT_SPHERE) ); var packedArray = [0]; GroundPolylineGeometry.pack(groundPolylineGeometry, packedArray, 1); var scratch = new GroundPolylineGeometry({ positions: Cartesian3.fromDegreesArray([-1.0, 0.0, 1.0, 0.0]), }); GroundPolylineGeometry.unpack(packedArray, 1, scratch); var scratchPositions = scratch._positions; expect(scratchPositions.length).toEqual(2); expect( Cartesian3.equals( scratchPositions[0], groundPolylineGeometry._positions[0] ) ).toBe(true); expect( Cartesian3.equals( scratchPositions[1], groundPolylineGeometry._positions[1] ) ).toBe(true); expect(scratch.loop).toBe(true); expect(scratch.granularity).toEqual(10.0); expect(scratch._ellipsoid.equals(Ellipsoid.UNIT_SPHERE)).toBe(true); expect(scratch._scene3DOnly).toBe(true); expect(scratch._projectionIndex).toEqual(1); }); it("can unpack onto a new instance", function () { var groundPolylineGeometry = new GroundPolylineGeometry({ positions: Cartesian3.fromDegreesArray([-1.0, 0.0, 1.0, 0.0]), loop: true, granularity: 10.0, // no interpolative subdivision }); groundPolylineGeometry._scene3DOnly = true; GroundPolylineGeometry.setProjectionAndEllipsoid( groundPolylineGeometry, new WebMercatorProjection(Ellipsoid.UNIT_SPHERE) ); var packedArray = [0]; GroundPolylineGeometry.pack(groundPolylineGeometry, packedArray, 1); var result = GroundPolylineGeometry.unpack(packedArray, 1); var scratchPositions = result._positions; expect(scratchPositions.length).toEqual(2); expect( Cartesian3.equals( scratchPositions[0], groundPolylineGeometry._positions[0] ) ).toBe(true); expect( Cartesian3.equals( scratchPositions[1], groundPolylineGeometry._positions[1] ) ).toBe(true); expect(result.loop).toBe(true); expect(result.granularity).toEqual(10.0); expect(result._ellipsoid.equals(Ellipsoid.UNIT_SPHERE)).toBe(true); expect(result._scene3DOnly).toBe(true); expect(result._projectionIndex).toEqual(1); }); it("provides a method for setting projection and ellipsoid", function () { var groundPolylineGeometry = new GroundPolylineGeometry({ positions: Cartesian3.fromDegreesArray([-1.0, 0.0, 1.0, 0.0]), loop: true, granularity: 10.0, // no interpolative subdivision }); GroundPolylineGeometry.setProjectionAndEllipsoid( groundPolylineGeometry, new WebMercatorProjection(Ellipsoid.UNIT_SPHERE) ); expect(groundPolylineGeometry._projectionIndex).toEqual(1); expect( groundPolylineGeometry._ellipsoid.equals(Ellipsoid.UNIT_SPHERE) ).toBe(true); }); var positions = Cartesian3.fromDegreesArray([ 0.01, 0.0, 0.02, 0.0, 0.02, 0.1, ]); var polyline = new GroundPolylineGeometry({ positions: positions, granularity: 1000.0, loop: true, }); it("projects normals that cross the IDL", function () { var projection = new GeographicProjection(); var cartographic = new Cartographic( CesiumMath.PI - CesiumMath.EPSILON11, 0.0 ); var normal = new Cartesian3(0.0, -1.0, 0.0); var projectedPosition = projection.project(cartographic, new Cartesian3()); var result = new Cartesian3(); GroundPolylineGeometry._projectNormal( projection, cartographic, normal, projectedPosition, result ); expect( Cartesian3.equalsEpsilon( result, new Cartesian3(1.0, 0.0, 0.0), CesiumMath.EPSILON7 ) ).toBe(true); }); it("creates bounding spheres that cover the entire polyline volume height", function () { var positions = Cartesian3.fromDegreesArray([ -122.17580380403314, 46.19984918190237, -122.17581380403314, 46.19984918190237, ]); // Mt. St. Helens - provided coordinates are a few meters apart var groundPolylineGeometry = new GroundPolylineGeometry({ positions: positions, granularity: 0.0, // no interpolative subdivision }); var geometry = GroundPolylineGeometry.createGeometry( groundPolylineGeometry ); var boundingSphere = geometry.boundingSphere; var pointsDistance = Cartesian3.distance(positions[0], positions[1]); expect(boundingSphere.radius).toBeGreaterThan(pointsDistance); expect(boundingSphere.radius).toBeGreaterThan(1000.0); // starting top/bottom height }); var packedInstance = [positions.length]; Cartesian3.pack(positions[0], packedInstance, packedInstance.length); Cartesian3.pack(positions[1], packedInstance, packedInstance.length); Cartesian3.pack(positions[2], packedInstance, packedInstance.length); packedInstance.push(polyline.granularity); packedInstance.push(polyline.loop ? 1.0 : 0.0); packedInstance.push(polyline.arcType); Ellipsoid.pack(Ellipsoid.WGS84, packedInstance, packedInstance.length); packedInstance.push(0.0); // projection index for Geographic (default) packedInstance.push(0.0); // scene3DModeOnly = false createPackableSpecs(GroundPolylineGeometry, polyline, packedInstance); });