import { ArcType } from "../../Source/Cesium.js"; import { arrayFill } from "../../Source/Cesium.js"; import { BoundingSphere } from "../../Source/Cesium.js"; import { Cartesian3 } from "../../Source/Cesium.js"; import { Cartographic } from "../../Source/Cesium.js"; import { Ellipsoid } from "../../Source/Cesium.js"; import { GeometryOffsetAttribute } from "../../Source/Cesium.js"; import { GeometryPipeline } from "../../Source/Cesium.js"; import { Math as CesiumMath } from "../../Source/Cesium.js"; import { PolygonGeometry } from "../../Source/Cesium.js"; import { Rectangle } from "../../Source/Cesium.js"; import { VertexFormat } from "../../Source/Cesium.js"; import createPackableSpecs from "../createPackableSpecs.js"; describe("Core/PolygonGeometry", function () { it("throws without hierarchy", function () { expect(function () { return new PolygonGeometry(); }).toThrowDeveloperError(); }); it("throws with height when perPositionHeight is true", function () { expect(function () { return new PolygonGeometry({ height: 30, perPositionHeight: true, }); }).toThrowDeveloperError(); }); it("throws without positions", function () { expect(function () { return PolygonGeometry.fromPositions(); }).toThrowDeveloperError(); }); it("returns undefined with less than three positions", function () { expect( PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ positions: [new Cartesian3()], }) ) ).toBeUndefined(); }); it("returns undefined with polygon hierarchy with less than three positions", function () { expect( PolygonGeometry.createGeometry( new PolygonGeometry({ polygonHierarchy: { positions: [Cartesian3.fromDegrees(0, 0)], }, }) ) ).toBeUndefined(); }); it("throws if arcType is not valid", function () { expect(function () { return new PolygonGeometry({ positions: [ Cartesian3.fromDegrees(0, 0), Cartesian3.fromDegrees(1, 0), Cartesian3.fromDegrees(1, 1), ], arcType: ArcType.NONE, }); }).toThrowDeveloperError(); }); it("createGeometry returns undefined due to duplicate positions", function () { var geometry = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ positions: Cartesian3.fromDegreesArray([0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), }) ); expect(geometry).toBeUndefined(); }); it("createGeometry returns undefined due to duplicate positions extruded", function () { var geometry = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ positions: Cartesian3.fromDegreesArray([0.0, 0.0, 0.0, 0.0, 0.0, 0.0]), extrudedHeight: 2, }) ); expect(geometry).toBeUndefined(); }); it("createGeometry returns undefined due to duplicate hierarchy positions", function () { var hierarchy = { positions: Cartesian3.fromDegreesArray([1.0, 1.0, 1.0, 1.0, 1.0, 1.0]), holes: [ { positions: Cartesian3.fromDegreesArray([ 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, ]), }, ], }; var geometry = PolygonGeometry.createGeometry( new PolygonGeometry({ polygonHierarchy: hierarchy }) ); expect(geometry).toBeUndefined(); }); it("createGeometry returns undefined due to duplicate hierarchy positions with different heights", function () { var hierarchy = { positions: Cartesian3.fromDegreesArrayHeights([ 1.0, 1.0, 10.0, 1.0, 1.0, 20.0, 1.0, 1.0, 30.0, ]), holes: [ { positions: Cartesian3.fromDegreesArrayHeights([ 0.0, 0.0, 10.0, 0.0, 0.0, 20.0, 0.0, 0.0, 30.0, ]), }, ], }; var geometry = PolygonGeometry.createGeometry( new PolygonGeometry({ polygonHierarchy: hierarchy }) ); expect(geometry).toBeUndefined(); }); it("createGeometry returns geometry if duplicate hierarchy positions with different heights and perPositionHeight is true", function () { var hierarchy = { positions: Cartesian3.fromDegreesArrayHeights([ 1.0, 1.0, 10.0, 1.0, 1.0, 20.0, 1.0, 1.0, 30.0, ]), holes: [ { positions: Cartesian3.fromDegreesArrayHeights([ 0.0, 0.0, 10.0, 0.0, 0.0, 20.0, 0.0, 0.0, 30.0, ]), }, ], }; var geometry = PolygonGeometry.createGeometry( new PolygonGeometry({ polygonHierarchy: hierarchy, perPositionHeight: true, }) ); expect(geometry).toBeDefined(); }); it("computes positions", function () { var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: Cartesian3.fromDegreesArray([ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, ]), granularity: CesiumMath.RADIANS_PER_DEGREE, }) ); expect(p.attributes.position.values.length).toEqual(13 * 3); // 8 around edge + 5 in the middle expect(p.indices.length).toEqual(16 * 3); //4 squares * 4 triangles per square }); it("computes positions with per position heights", function () { var ellipsoid = Ellipsoid.WGS84; var height = 100.0; var positions = Cartesian3.fromDegreesArrayHeights([ -1.0, -1.0, height, 1.0, -1.0, 0.0, 1.0, 1.0, 0.0, -1.0, 1.0, 0.0, ]); var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ positions: positions, perPositionHeight: true, }) ); expect( ellipsoid.cartesianToCartographic( Cartesian3.fromArray(p.attributes.position.values, 0) ).height ).toEqualEpsilon(height, CesiumMath.EPSILON6); expect( ellipsoid.cartesianToCartographic( Cartesian3.fromArray(p.attributes.position.values, 3) ).height ).toEqualEpsilon(0, CesiumMath.EPSILON6); }); it("create geometry creates with rhumb lines", function () { var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: Cartesian3.fromDegreesArray([ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, ]), granularity: CesiumMath.RADIANS_PER_DEGREE, arcType: ArcType.RHUMB, }) ); expect(p.attributes.position.values.length).toEqual(15 * 3); // 8 around edge + 7 in the middle expect(p.indices.length).toEqual(20 * 3); //5 squares * 4 triangles per square }); it("create geometry throws if arcType is STRAIGHT", function () { expect(function () { PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: Cartesian3.fromDegreesArray([ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, ]), granularity: CesiumMath.RADIANS_PER_DEGREE, arcType: ArcType.NONE, }) ); }).toThrowDeveloperError(); }); it("create geometry creates with lines with different number of subdivisions for geodesic and rhumb", function () { var positions = Cartesian3.fromDegreesArray([ -30.0, -30.0, 30.0, -30.0, 30.0, 30.0, -30.0, 30.0, ]); var geodesic = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: positions, granularity: CesiumMath.RADIANS_PER_DEGREE, arcType: ArcType.GEODESIC, }) ); var rhumb = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: positions, granularity: CesiumMath.RADIANS_PER_DEGREE, arcType: ArcType.RHUMB, }) ); expect(geodesic.attributes.position.values.length).not.toEqual( rhumb.attributes.position.values.length ); expect(geodesic.indices.length).not.toEqual(rhumb.indices.length); }); it("computes positions with per position heights for rhumb lines", function () { var ellipsoid = Ellipsoid.WGS84; var height = 100.0; var positions = Cartesian3.fromDegreesArrayHeights([ -1.0, -1.0, height, 1.0, -1.0, 0.0, 1.0, 1.0, 0.0, -1.0, 1.0, 0.0, ]); var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ positions: positions, perPositionHeight: true, arcType: ArcType.RHUMB, }) ); expect( ellipsoid.cartesianToCartographic( Cartesian3.fromArray(p.attributes.position.values, 0) ).height ).toEqualEpsilon(height, CesiumMath.EPSILON6); expect( ellipsoid.cartesianToCartographic( Cartesian3.fromArray(p.attributes.position.values, 3) ).height ).toEqualEpsilon(0, CesiumMath.EPSILON6); }); it("computes all attributes", function () { var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.ALL, positions: Cartesian3.fromDegreesArray([ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, ]), }) ); var numVertices = 13; var numTriangles = 16; expect(p.attributes.position.values.length).toEqual(numVertices * 3); expect(p.attributes.st.values.length).toEqual(numVertices * 2); expect(p.attributes.normal.values.length).toEqual(numVertices * 3); expect(p.attributes.tangent.values.length).toEqual(numVertices * 3); expect(p.attributes.bitangent.values.length).toEqual(numVertices * 3); expect(p.indices.length).toEqual(numTriangles * 3); }); it("creates a polygon from hierarchy", function () { var hierarchy = { positions: Cartesian3.fromDegreesArray([ -124.0, 35.0, -110.0, 35.0, -110.0, 40.0, -124.0, 40.0, ]), holes: [ { positions: Cartesian3.fromDegreesArray([ -122.0, 36.0, -122.0, 39.0, -112.0, 39.0, -112.0, 36.0, ]), holes: [ { positions: Cartesian3.fromDegreesArray([ -120.0, 36.5, -114.0, 36.5, -114.0, 38.5, -120.0, 38.5, ]), }, ], }, ], }; var p = PolygonGeometry.createGeometry( new PolygonGeometry({ vertexFormat: VertexFormat.POSITION_ONLY, polygonHierarchy: hierarchy, granularity: CesiumMath.PI_OVER_THREE, }) ); expect(p.attributes.position.values.length).toEqual(12 * 3); // 4 points * 3 rectangles expect(p.indices.length).toEqual(10 * 3); }); it("creates a polygon from hierarchy with rhumb lines", function () { var hierarchy = { positions: Cartesian3.fromDegreesArray([ -124.0, 35.0, -110.0, 35.0, -110.0, 40.0, -124.0, 40.0, ]), holes: [ { positions: Cartesian3.fromDegreesArray([ -122.0, 36.0, -122.0, 39.0, -112.0, 39.0, -112.0, 36.0, ]), holes: [ { positions: Cartesian3.fromDegreesArray([ -120.0, 36.5, -114.0, 36.5, -114.0, 38.5, -120.0, 38.5, ]), }, ], }, ], }; var p = PolygonGeometry.createGeometry( new PolygonGeometry({ vertexFormat: VertexFormat.POSITION_ONLY, polygonHierarchy: hierarchy, granularity: CesiumMath.PI_OVER_THREE, arcType: ArcType.RHUMB, }) ); expect(p.attributes.position.values.length).toEqual(12 * 3); // 4 points * 3 rectangles expect(p.indices.length).toEqual(10 * 3); }); it("removes duplicates in polygon hierarchy", function () { var hierarchy = { positions: Cartesian3.fromDegreesArray([ -124.0, 35.0, -110.0, 35.0, -110.0, 35.0, -110.0, 40.0, -124.0, 40.0, ]), holes: [ { positions: Cartesian3.fromDegreesArray([ -122.0, 36.0, -122.0, 39.0, -122.0, 39.0, -112.0, 39.0, -112.0, 36.0, ]), holes: [ { positions: Cartesian3.fromDegreesArray([ -120.0, 36.5, -114.0, 36.5, -114.0, 36.5, -114.0, 38.5, -120.0, 38.5, ]), }, ], }, ], }; var p = PolygonGeometry.createGeometry( new PolygonGeometry({ vertexFormat: VertexFormat.POSITION_ONLY, polygonHierarchy: hierarchy, granularity: CesiumMath.PI_OVER_THREE, }) ); expect(p.attributes.position.values.length).toEqual(12 * 3); expect(p.indices.length).toEqual(10 * 3); }); it("creates a polygon from clockwise hierarchy", function () { var hierarchy = { positions: Cartesian3.fromDegreesArray([ -124.0, 35.0, -124.0, 40.0, -110.0, 40.0, -110.0, 35.0, ]), holes: [ { positions: Cartesian3.fromDegreesArray([ -122.0, 36.0, -112.0, 36.0, -112.0, 39.0, -122.0, 39.0, ]), holes: [ { positions: Cartesian3.fromDegreesArray([ -120.0, 36.5, -120.0, 38.5, -114.0, 38.5, -114.0, 36.5, ]), }, ], }, ], }; var p = PolygonGeometry.createGeometry( new PolygonGeometry({ vertexFormat: VertexFormat.POSITION_ONLY, polygonHierarchy: hierarchy, granularity: CesiumMath.PI_OVER_THREE, }) ); expect(p.attributes.position.values.length).toEqual(12 * 3); expect(p.indices.length).toEqual(10 * 3); }); it("doesn't reverse clockwise input array", function () { var p = Cartesian3.fromDegreesArray([ -124.0, 35.0, -124.0, 40.0, -110.0, 40.0, -110.0, 35.0, ]); var h1 = Cartesian3.fromDegreesArray([ -122.0, 36.0, -112.0, 36.0, -112.0, 39.0, -122.0, 39.0, ]); var h2 = Cartesian3.fromDegreesArray([ -120.0, 36.5, -120.0, 38.5, -114.0, 38.5, -114.0, 36.5, ]); var hierarchy = { positions: p, holes: [ { positions: h1, holes: [ { positions: h2, }, ], }, ], }; PolygonGeometry.createGeometry( new PolygonGeometry({ vertexFormat: VertexFormat.POSITION_ONLY, polygonHierarchy: hierarchy, granularity: CesiumMath.PI_OVER_THREE, }) ); var i; var pExpected = Cartesian3.fromDegreesArray([ -124.0, 35.0, -124.0, 40.0, -110.0, 40.0, -110.0, 35.0, ]); for (i = 0; i < p.length; i++) { expect(p[i]).toEqualEpsilon(pExpected[i], CesiumMath.EPSILON7); } var h1Expected = Cartesian3.fromDegreesArray([ -122.0, 36.0, -112.0, 36.0, -112.0, 39.0, -122.0, 39.0, ]); for (i = 0; i < h1.length; i++) { expect(h1[i]).toEqualEpsilon(h1Expected[i], CesiumMath.EPSILON7); } var h2Expected = Cartesian3.fromDegreesArray([ -120.0, 36.5, -120.0, 38.5, -114.0, 38.5, -114.0, 36.5, ]); for (i = 0; i < h2.length; i++) { expect(h2[i]).toEqualEpsilon(h2Expected[i], CesiumMath.EPSILON7); } }); it("computes correct bounding sphere at height 0", function () { var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.ALL, positions: Cartesian3.fromDegreesArray([ -108.0, 1.0, -108.0, -1.0, -106.0, -1.0, -106.0, 1.0, ]), granularity: CesiumMath.PI_OVER_THREE, }) ); var bs = BoundingSphere.fromVertices(p.attributes.position.values); expect(p.boundingSphere.center).toEqualEpsilon( bs.center, CesiumMath.EPSILON9 ); expect(p.boundingSphere.radius).toEqualEpsilon( bs.radius, CesiumMath.EPSILON9 ); }); it("computes correct bounding sphere at height >>> 0", function () { var height = 40000000.0; var positions = Cartesian3.fromDegreesArray([ -108.0, 1.0, -108.0, -1.0, -106.0, -1.0, -106.0, 1.0, ]); var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITIONS_ONLY, positions: positions, height: height, }) ); var bs = BoundingSphere.fromPoints( Cartesian3.fromDegreesArrayHeights([ -108.0, 1.0, height, -108.0, -1.0, height, -106.0, -1.0, height, -106.0, 1.0, height, ]) ); expect(Math.abs(p.boundingSphere.radius - bs.radius)).toBeLessThan(100.0); }); it("computes positions extruded", function () { var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: Cartesian3.fromDegreesArray([ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, ]), extrudedHeight: 30000, }) ); var numVertices = 50; // 13 top + 13 bottom + 8 top edge + 8 bottom edge + 4 top corner + 4 bottom corner var numTriangles = 48; // 16 top fill + 16 bottom fill + 2 triangles * 4 sides expect(p.attributes.position.values.length).toEqual(numVertices * 3); expect(p.indices.length).toEqual(numTriangles * 3); }); it("computes positions extruded and not closeTop", function () { var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: Cartesian3.fromDegreesArray([ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, ]), extrudedHeight: 30000, closeTop: false, }) ); var numVertices = 37; // 13 bottom + 8 top edge + 8 bottom edge + 4 top corner + 4 bottom corner var numTriangles = 32; // 16 bottom fill + 2 triangles * 4 sides expect(p.attributes.position.values.length).toEqual(numVertices * 3); expect(p.indices.length).toEqual(numTriangles * 3); }); it("computes positions extruded and not closeBottom", function () { var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: Cartesian3.fromDegreesArray([ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, ]), extrudedHeight: 30000, closeBottom: false, }) ); var numVertices = 37; // 13 top + 8 top edge + 8 bottom edge + 4 top corner + 4 bottom corner var numTriangles = 32; // 16 top fill + 2 triangles * 4 sides expect(p.attributes.position.values.length).toEqual(numVertices * 3); expect(p.indices.length).toEqual(numTriangles * 3); }); it("computes positions extruded and not closeBottom or closeTop", function () { var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: Cartesian3.fromDegreesArray([ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, ]), extrudedHeight: 30000, closeTop: false, closeBottom: false, }) ); var numVertices = 24; // 8 top edge + 8 bottom edge + 4 top corner + 4 bottom corner var numTriangles = 16; // 2 triangles * 4 sides expect(p.attributes.position.values.length).toEqual(numVertices * 3); expect(p.indices.length).toEqual(numTriangles * 3); }); it("computes offset attribute", function () { var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: Cartesian3.fromDegreesArray([ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, ]), granularity: CesiumMath.RADIANS_PER_DEGREE, offsetAttribute: GeometryOffsetAttribute.TOP, }) ); var numVertices = 13; expect(p.attributes.position.values.length).toEqual(numVertices * 3); var offset = p.attributes.applyOffset.values; expect(offset.length).toEqual(numVertices); var expected = new Array(offset.length); expected = arrayFill(expected, 1); expect(offset).toEqual(expected); }); it("computes offset attribute extruded for top vertices", function () { var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: Cartesian3.fromDegreesArray([ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, ]), extrudedHeight: 30000, offsetAttribute: GeometryOffsetAttribute.TOP, }) ); var numVertices = 50; expect(p.attributes.position.values.length).toEqual(numVertices * 3); var offset = p.attributes.applyOffset.values; expect(offset.length).toEqual(numVertices); var expected = new Array(offset.length); expected = arrayFill(expected, 0); expected = arrayFill(expected, 1, 0, 13); expected = arrayFill(expected, 1, 26, 38); expect(offset).toEqual(expected); }); it("computes offset attribute extruded and not closeTop for top vertices", function () { var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: Cartesian3.fromDegreesArray([ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, ]), extrudedHeight: 30000, closeTop: false, offsetAttribute: GeometryOffsetAttribute.TOP, }) ); var numVertices = 37; // 13 bottom + 8 top edge + 8 bottom edge + 4 top corner + 4 bottom corner expect(p.attributes.position.values.length).toEqual(numVertices * 3); var offset = p.attributes.applyOffset.values; expect(offset.length).toEqual(numVertices); var expected = new Array(offset.length); expected = arrayFill(expected, 0); expected = arrayFill(expected, 1, 13, 25); expect(offset).toEqual(expected); }); it("computes offset attribute extruded and not closeBottom for top vertcies", function () { var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: Cartesian3.fromDegreesArray([ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, ]), extrudedHeight: 30000, closeBottom: false, offsetAttribute: GeometryOffsetAttribute.TOP, }) ); var numVertices = 37; expect(p.attributes.position.values.length).toEqual(numVertices * 3); var offset = p.attributes.applyOffset.values; expect(offset.length).toEqual(numVertices); var expected = new Array(offset.length); expected = arrayFill(expected, 0); expected = arrayFill(expected, 1, 0, 25); expect(offset).toEqual(expected); }); it("computes offset attribute extruded and not closeBottom or closeTop for top vertices", function () { var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: Cartesian3.fromDegreesArray([ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, ]), extrudedHeight: 30000, closeTop: false, closeBottom: false, offsetAttribute: GeometryOffsetAttribute.TOP, }) ); var numVertices = 24; expect(p.attributes.position.values.length).toEqual(numVertices * 3); var offset = p.attributes.applyOffset.values; expect(offset.length).toEqual(numVertices); var expected = new Array(offset.length); expected = arrayFill(expected, 0); expected = arrayFill(expected, 1, 0, 12); expect(offset).toEqual(expected); }); it("computes offset attribute extruded for all vertices", function () { var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: Cartesian3.fromDegreesArray([ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, ]), extrudedHeight: 30000, offsetAttribute: GeometryOffsetAttribute.ALL, }) ); var numVertices = 50; expect(p.attributes.position.values.length).toEqual(numVertices * 3); var offset = p.attributes.applyOffset.values; expect(offset.length).toEqual(numVertices); var expected = new Array(offset.length); expected = arrayFill(expected, 1); expect(offset).toEqual(expected); }); it("computes offset attribute extruded and not closeTop for all vertices", function () { var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: Cartesian3.fromDegreesArray([ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, ]), extrudedHeight: 30000, closeTop: false, offsetAttribute: GeometryOffsetAttribute.ALL, }) ); var numVertices = 37; // 13 bottom + 8 top edge + 8 bottom edge + 4 top corner + 4 bottom corner expect(p.attributes.position.values.length).toEqual(numVertices * 3); var offset = p.attributes.applyOffset.values; expect(offset.length).toEqual(numVertices); var expected = new Array(offset.length); expected = arrayFill(expected, 1); expect(offset).toEqual(expected); }); it("computes offset attribute extruded and not closeBottom for all vertcies", function () { var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: Cartesian3.fromDegreesArray([ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, ]), extrudedHeight: 30000, closeBottom: false, offsetAttribute: GeometryOffsetAttribute.ALL, }) ); var numVertices = 37; expect(p.attributes.position.values.length).toEqual(numVertices * 3); var offset = p.attributes.applyOffset.values; expect(offset.length).toEqual(numVertices); var expected = new Array(offset.length); expected = arrayFill(expected, 1); expect(offset).toEqual(expected); }); it("computes offset attribute extruded and not closeBottom or closeTop for all vertices", function () { var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: Cartesian3.fromDegreesArray([ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, ]), extrudedHeight: 30000, closeTop: false, closeBottom: false, offsetAttribute: GeometryOffsetAttribute.ALL, }) ); var numVertices = 24; expect(p.attributes.position.values.length).toEqual(numVertices * 3); var offset = p.attributes.applyOffset.values; expect(offset.length).toEqual(numVertices); var expected = new Array(offset.length); expected = arrayFill(expected, 1); expect(offset).toEqual(expected); }); it("removes duplicates extruded", function () { var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: Cartesian3.fromDegreesArray([ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, -1.0, -1.0, ]), extrudedHeight: 30000, }) ); expect(p.attributes.position.values.length).toEqual(50 * 3); expect(p.indices.length).toEqual(48 * 3); }); it("Ignores extrudedHeight if it equals height.", function () { var p = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: Cartesian3.fromDegreesArray([ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, ]), height: 0, extrudedHeight: CesiumMath.EPSILON7, }) ); expect(p.attributes.position.values.length).toEqual(13 * 3); expect(p.indices.length).toEqual(16 * 3); }); it("computes all attributes extruded", function () { var p = PolygonGeometry.createGeometry( new PolygonGeometry({ vertexFormat: VertexFormat.ALL, polygonHierarchy: { positions: Cartesian3.fromDegreesArray([ -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0, ]), }, extrudedHeight: 30000, }) ); var numVertices = 50; var numTriangles = 48; expect(p.attributes.position.values.length).toEqual(numVertices * 3); expect(p.attributes.st.values.length).toEqual(numVertices * 2); expect(p.attributes.normal.values.length).toEqual(numVertices * 3); expect(p.attributes.tangent.values.length).toEqual(numVertices * 3); expect(p.attributes.bitangent.values.length).toEqual(numVertices * 3); expect(p.indices.length).toEqual(numTriangles * 3); }); it("computes correct texture coordinates for polygon with height", function () { var p = PolygonGeometry.createGeometry( new PolygonGeometry({ vertexFormat: VertexFormat.POSITION_AND_ST, polygonHierarchy: { positions: Cartesian3.fromDegreesArray([ -100.5, 30.0, -100.0, 30.0, -100.0, 30.5, -100.5, 30.5, ]), }, height: 150000, granularity: CesiumMath.PI, }) ); var st = p.attributes.st.values; for (var i = 0; i < st.length; i++) { expect(st[i]).toBeGreaterThanOrEqualTo(0); expect(st[i]).toBeLessThanOrEqualTo(1); } }); it("computes correct texture coordinates for polygon with position heights", function () { var p = PolygonGeometry.createGeometry( new PolygonGeometry({ vertexFormat: VertexFormat.POSITION_AND_ST, polygonHierarchy: { positions: Cartesian3.fromDegreesArrayHeights([ -100.5, 30.0, 92, -100.0, 30.0, 92, -100.0, 30.5, 92, -100.5, 30.5, 92, ]), }, granularity: CesiumMath.PI, }) ); var st = p.attributes.st.values; for (var i = 0; i < st.length; i++) { expect(st[i]).toBeGreaterThanOrEqualTo(0); expect(st[i]).toBeLessThanOrEqualTo(1); } }); it("creates a polygon from hierarchy extruded", function () { var hierarchy = { positions: Cartesian3.fromDegreesArray([ -124.0, 35.0, -110.0, 35.0, -110.0, 40.0, -124.0, 40.0, ]), holes: [ { positions: Cartesian3.fromDegreesArray([ -122.0, 36.0, -122.0, 39.0, -112.0, 39.0, -112.0, 36.0, ]), holes: [ { positions: Cartesian3.fromDegreesArray([ -120.0, 36.5, -114.0, 36.5, -114.0, 38.5, -120.0, 38.5, ]), }, ], }, ], }; var p = PolygonGeometry.createGeometry( new PolygonGeometry({ vertexFormat: VertexFormat.POSITION_ONLY, polygonHierarchy: hierarchy, granularity: CesiumMath.PI_OVER_THREE, extrudedHeight: 30000, }) ); // (4 points * 3 rectangles * 3 to duplicate for normals) * 2 for top and bottom expect(p.attributes.position.values.length).toEqual(72 * 3); // 10 top + 10 bottom + 2 triangles * 12 walls expect(p.indices.length).toEqual(44 * 3); }); it("undefined is returned if there are less than 3 positions", function () { var polygon = PolygonGeometry.fromPositions({ positions: Cartesian3.fromDegreesArray([-72.0, 40.0, -68.0, 40.0]), }); var geometry = PolygonGeometry.createGeometry(polygon); expect(geometry).toBeUndefined(); }); it("computes normals for perPositionHeight", function () { var geometry = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ positions: [ new Cartesian3( 1333485.211963876, -4654510.505548239, 4138557.5850382405 ), new Cartesian3( 1333441.3994441305, -4654261.147368878, 4138322.784348336 ), new Cartesian3( 1333521.9333286814, -4654490.298890729, 4138567.564118971 ), ], extrudedHeight: 56, vertexFormat: VertexFormat.POSITION_AND_NORMAL, perPositionHeight: true, closeBottom: false, }) ); var normals = geometry.attributes.normal.values; geometry = GeometryPipeline.computeNormal(geometry); var expectedNormals = geometry.attributes.normal.values; var notEqualCount = 0; for (var i = 0; i < expectedNormals.length; i++) { if ( !CesiumMath.equalsEpsilon( normals[i], expectedNormals[i], CesiumMath.EPSILON6 ) ) { notEqualCount++; } } //Exactly 2 normals will be different due to weird triangles on the walls of the extrusion //PolygonGeometry needs major changes to how extruded walls are computed with perPositionHeight in order to improve this expect(notEqualCount).toEqual(6); }); it("computes geometry with position only vertex format with perPositionHeight and extrudedHeight", function () { var positions = Cartesian3.fromDegreesArrayHeights([ -1.0, -1.0, 100.0, 1.0, -1.0, 0.0, 1.0, 1.0, 100.0, -1.0, 1.0, 0.0, ]); var geometry = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ positions: positions, extrudedHeight: 0, vertexFormat: VertexFormat.POSITION_ONLY, perPositionHeight: true, }) ); expect(geometry).toBeDefined(); expect(geometry.attributes.position).toBeDefined(); expect(geometry.attributes.normal).toBeUndefined(); }); it("does not include indices for extruded walls that are too small", function () { var positions = Cartesian3.fromDegreesArray([ 7.757161063097392, 48.568676799636634, 7.753968290229146, 48.571796467099077, 7.755340073906587, 48.571948854067948, 7.756263393414589, 48.571947951609708, 7.756894446412183, 48.569396703043992, ]); var pRhumb = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: positions, extrudedHeight: 1000, closeTop: false, closeBottom: false, arcType: ArcType.RHUMB, }) ); var numVertices = 20; var numTriangles = 10; //5 wall segments, 2 triangles each wall expect(pRhumb.attributes.position.values.length).toEqual(numVertices * 3); expect(pRhumb.indices.length).toEqual(numTriangles * 3); var pGeodesic = PolygonGeometry.createGeometry( PolygonGeometry.fromPositions({ vertexFormat: VertexFormat.POSITION_ONLY, positions: positions, extrudedHeight: 1000, closeTop: false, closeBottom: false, arcType: ArcType.GEODESIC, }) ); numVertices = 20; numTriangles = 10; expect(pGeodesic.attributes.position.values.length).toEqual( numVertices * 3 ); expect(pGeodesic.indices.length).toEqual(numTriangles * 3); }); it("computing rectangle property", function () { var p = new PolygonGeometry({ vertexFormat: VertexFormat.POSITION_AND_ST, polygonHierarchy: { positions: Cartesian3.fromDegreesArrayHeights([ -100.5, 30.0, 92, -100.0, 30.0, 92, -100.0, 30.5, 92, -100.5, 30.5, 92, ]), }, granularity: CesiumMath.PI, }); var r = p.rectangle; expect(CesiumMath.toDegrees(r.north)).toEqualEpsilon( 30.5, CesiumMath.EPSILON13 ); expect(CesiumMath.toDegrees(r.south)).toEqualEpsilon( 30.0, CesiumMath.EPSILON13 ); expect(CesiumMath.toDegrees(r.east)).toEqualEpsilon( -100.0, CesiumMath.EPSILON13 ); expect(CesiumMath.toDegrees(r.west)).toEqualEpsilon( -100.5, CesiumMath.EPSILON13 ); }); it("computes rectangle according to arctype", function () { var pGeodesic = new PolygonGeometry({ vertexFormat: VertexFormat.POSITION_AND_ST, polygonHierarchy: { positions: Cartesian3.fromDegreesArrayHeights([ -90.0, 30.0, 0, -80.0, 30.0, 0, -80.0, 40.0, 0, -90.0, 40.0, 0, ]), }, granularity: CesiumMath.RADIANS_PER_DEGREE, arcType: ArcType.GEODESIC, }); var boundingGeodesic = pGeodesic.rectangle; expect(CesiumMath.toDegrees(boundingGeodesic.north)).toBeGreaterThan(40.0); expect(CesiumMath.toDegrees(boundingGeodesic.south)).toEqualEpsilon( 30.0, CesiumMath.EPSILON10 ); expect(CesiumMath.toDegrees(boundingGeodesic.east)).toEqualEpsilon( -80.0, CesiumMath.EPSILON10 ); expect(CesiumMath.toDegrees(boundingGeodesic.west)).toEqualEpsilon( -90.0, CesiumMath.EPSILON10 ); var pRhumb = new PolygonGeometry({ vertexFormat: VertexFormat.POSITION_AND_ST, polygonHierarchy: { positions: Cartesian3.fromDegreesArrayHeights([ -90.0, 30.0, 0, -80.0, 30.0, 0, -80.0, 40.0, 0, -90.0, 40.0, 0, ]), }, granularity: CesiumMath.RADIANS_PER_DEGREE, arcType: ArcType.RHUMB, }); var boundingRhumb = pRhumb.rectangle; expect(CesiumMath.toDegrees(boundingRhumb.north)).toEqualEpsilon( 40.0, CesiumMath.EPSILON10 ); expect(CesiumMath.toDegrees(boundingRhumb.south)).toEqualEpsilon( 30.0, CesiumMath.EPSILON10 ); expect(CesiumMath.toDegrees(boundingRhumb.east)).toEqualEpsilon( -80.0, CesiumMath.EPSILON10 ); expect(CesiumMath.toDegrees(boundingRhumb.west)).toEqualEpsilon( -90.0, CesiumMath.EPSILON10 ); }); it("computes rectangles for rhumbline polygons that cross the IDL", function () { var pRhumb = new PolygonGeometry({ vertexFormat: VertexFormat.POSITION_AND_ST, polygonHierarchy: { positions: Cartesian3.fromDegreesArray([ 175, 30, -170, 30, -170, 40, 175, 40, ]), }, granularity: CesiumMath.RADIANS_PER_DEGREE, arcType: ArcType.RHUMB, }); var boundingRhumb = pRhumb.rectangle; expect(CesiumMath.toDegrees(boundingRhumb.north)).toEqualEpsilon( 40.0, CesiumMath.EPSILON10 ); expect(CesiumMath.toDegrees(boundingRhumb.south)).toEqualEpsilon( 30.0, CesiumMath.EPSILON10 ); expect(CesiumMath.toDegrees(boundingRhumb.east)).toEqualEpsilon( -170.0, CesiumMath.EPSILON10 ); expect(CesiumMath.toDegrees(boundingRhumb.west)).toEqualEpsilon( 175.0, CesiumMath.EPSILON10 ); }); it("computes rectangles for geodesic polygons that cross the IDL", function () { var minLon = Cartographic.fromDegrees(-178, 3); var minLat = Cartographic.fromDegrees(-179, -4); var maxLon = Cartographic.fromDegrees(178, 3); var maxLat = Cartographic.fromDegrees(179, 4); var cartesianArray = Ellipsoid.WGS84.cartographicArrayToCartesianArray([ minLat, minLon, maxLat, maxLon, ]); var pGeodesic = new PolygonGeometry({ vertexFormat: VertexFormat.POSITION_AND_ST, polygonHierarchy: { positions: cartesianArray, }, granularity: CesiumMath.RADIANS_PER_DEGREE, arcType: ArcType.GEODESIC, }); var boundingGeodesic = pGeodesic.rectangle; expect(boundingGeodesic.east).toEqualEpsilon( minLon.longitude, CesiumMath.EPSILON10 ); expect(boundingGeodesic.south).toEqualEpsilon( minLat.latitude, CesiumMath.EPSILON10 ); expect(boundingGeodesic.west).toEqualEpsilon( maxLon.longitude, CesiumMath.EPSILON10 ); expect(boundingGeodesic.north).toEqualEpsilon( maxLat.latitude, CesiumMath.EPSILON10 ); }); it("computeRectangle", function () { var options = { vertexFormat: VertexFormat.POSITION_AND_ST, polygonHierarchy: { positions: Cartesian3.fromDegreesArrayHeights([ -100.5, 30.0, 92, -100.0, 30.0, 92, -100.0, 30.5, 92, -100.5, 30.5, 92, ]), }, ellipsoid: Ellipsoid.UNIT_SPHERE, }; var geometry = new PolygonGeometry(options); var expected = geometry.rectangle; var result = PolygonGeometry.computeRectangle(options); expect(result).toEqual(expected); }); it("computeRectangle with result parameter", function () { var options = { polygonHierarchy: { positions: Cartesian3.fromDegreesArray([ -10.5, 25.0, -10.0, 25.0, -10.0, 25.5, -10.5, 25.5, ]), }, }; var geometry = new PolygonGeometry(options); var result = new Rectangle(); var expected = geometry.rectangle; var returned = PolygonGeometry.computeRectangle(options, result); expect(returned).toEqual(expected); expect(returned).toBe(result); }); it("computing textureCoordinateRotationPoints property", function () { var p = new PolygonGeometry({ vertexFormat: VertexFormat.POSITION_AND_ST, polygonHierarchy: { positions: Cartesian3.fromDegreesArrayHeights([ -10.0, -10.0, 0, -10.0, 10.0, 0, 10.0, -10.0, 0, 10.0, 10.0, 0, ]), }, granularity: CesiumMath.PI, stRotation: CesiumMath.toRadians(90), }); // 90 degree rotation means (0, 1) should be the new min and (1, 1) (0, 0) are extents var textureCoordinateRotationPoints = p.textureCoordinateRotationPoints; expect(textureCoordinateRotationPoints.length).toEqual(6); expect(textureCoordinateRotationPoints[0]).toEqualEpsilon( 0, CesiumMath.EPSILON7 ); expect(textureCoordinateRotationPoints[1]).toEqualEpsilon( 1, CesiumMath.EPSILON7 ); expect(textureCoordinateRotationPoints[2]).toEqualEpsilon( 1, CesiumMath.EPSILON7 ); expect(textureCoordinateRotationPoints[3]).toEqualEpsilon( 1, CesiumMath.EPSILON7 ); expect(textureCoordinateRotationPoints[4]).toEqualEpsilon( 0, CesiumMath.EPSILON7 ); expect(textureCoordinateRotationPoints[5]).toEqualEpsilon( 0, CesiumMath.EPSILON7 ); p = new PolygonGeometry({ vertexFormat: VertexFormat.POSITION_AND_ST, polygonHierarchy: { positions: Cartesian3.fromDegreesArrayHeights([ -10.0, -10.0, 0, -10.0, 10.0, 0, 10.0, -10.0, 0, 10.0, 10.0, 0, ]), }, granularity: CesiumMath.PI, stRotation: CesiumMath.toRadians(0), }); textureCoordinateRotationPoints = p.textureCoordinateRotationPoints; expect(textureCoordinateRotationPoints.length).toEqual(6); expect(textureCoordinateRotationPoints[0]).toEqualEpsilon( 0, CesiumMath.EPSILON7 ); expect(textureCoordinateRotationPoints[1]).toEqualEpsilon( 0, CesiumMath.EPSILON7 ); expect(textureCoordinateRotationPoints[2]).toEqualEpsilon( 0, CesiumMath.EPSILON7 ); expect(textureCoordinateRotationPoints[3]).toEqualEpsilon( 1, CesiumMath.EPSILON7 ); expect(textureCoordinateRotationPoints[4]).toEqualEpsilon( 1, CesiumMath.EPSILON7 ); expect(textureCoordinateRotationPoints[5]).toEqualEpsilon( 0, CesiumMath.EPSILON7 ); }); var positions = Cartesian3.fromDegreesArray([ -12.4, 3.5, -12.0, 3.5, -12.0, 4.0, ]); var holePositions0 = Cartesian3.fromDegreesArray([ -12.2, 3.5, -12.2, 3.6, -12.3, 3.6, ]); var holePositions1 = Cartesian3.fromDegreesArray([ -12.2, 3.5, -12.25, 3.5, -12.25, 3.55, ]); var hierarchy = { positions: positions, holes: [ { positions: holePositions0, holes: [ { positions: holePositions1, holes: undefined, }, ], }, ], }; var polygon = new PolygonGeometry({ vertexFormat: VertexFormat.POSITION_ONLY, polygonHierarchy: hierarchy, granularity: CesiumMath.PI_OVER_THREE, perPositionHeight: true, closeTop: false, closeBottom: true, }); function addPositions(array, positions) { for (var i = 0; i < positions.length; ++i) { array.push(positions[i].x, positions[i].y, positions[i].z); } } var packedInstance = [3.0, 1.0]; addPositions(packedInstance, positions); packedInstance.push(3.0, 1.0); addPositions(packedInstance, holePositions0); packedInstance.push(3.0, 0.0); addPositions(packedInstance, holePositions1); packedInstance.push( Ellipsoid.WGS84.radii.x, Ellipsoid.WGS84.radii.y, Ellipsoid.WGS84.radii.z ); packedInstance.push(1.0, 0.0, 0.0, 0.0, 0.0, 0.0); packedInstance.push( 0.0, 0.0, CesiumMath.PI_OVER_THREE, 0.0, 0.0, 1.0, 0, 1, 0, -1, ArcType.GEODESIC, 54 ); createPackableSpecs(PolygonGeometry, polygon, packedInstance); });