cesium/packages/engine/Specs/Core/PolygonGeometrySpec.js

1874 lines
56 KiB
JavaScript

import {
ArcType,
BoundingSphere,
Cartesian2,
Cartesian3,
Cartographic,
Ellipsoid,
GeometryOffsetAttribute,
GeometryPipeline,
Math as CesiumMath,
PolygonGeometry,
Rectangle,
VertexFormat,
} from "../../index.js";
import createPackableSpecs from "../../../../Specs/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 () {
const 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 () {
const 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 () {
const 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,
]),
},
],
};
const geometry = PolygonGeometry.createGeometry(
new PolygonGeometry({ polygonHierarchy: hierarchy }),
);
expect(geometry).toBeUndefined();
});
it("createGeometry returns undefined due to duplicate hierarchy positions with different heights", function () {
const 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,
]),
},
],
};
const 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 () {
const 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,
]),
},
],
};
const geometry = PolygonGeometry.createGeometry(
new PolygonGeometry({
polygonHierarchy: hierarchy,
perPositionHeight: true,
}),
);
expect(geometry).toBeDefined();
});
it("computes positions", function () {
const 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 () {
const ellipsoid = Ellipsoid.WGS84;
const height = 100.0;
const 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,
]);
const 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 () {
const 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 () {
const positions = Cartesian3.fromDegreesArray([
-30.0, -30.0, 30.0, -30.0, 30.0, 30.0, -30.0, 30.0,
]);
const geodesic = PolygonGeometry.createGeometry(
PolygonGeometry.fromPositions({
vertexFormat: VertexFormat.POSITION_ONLY,
positions: positions,
granularity: CesiumMath.RADIANS_PER_DEGREE,
arcType: ArcType.GEODESIC,
}),
);
const 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 () {
const ellipsoid = Ellipsoid.WGS84;
const height = 100.0;
const 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,
]);
const 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 () {
const 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,
]),
}),
);
const numVertices = 13;
const 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 () {
const 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,
]),
},
],
},
],
};
const 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 () {
const 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,
]),
},
],
},
],
};
const 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 () {
const 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,
]),
},
],
},
],
};
const 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 () {
const 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,
]),
},
],
},
],
};
const 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 () {
const p = Cartesian3.fromDegreesArray([
-124.0, 35.0, -124.0, 40.0, -110.0, 40.0, -110.0, 35.0,
]);
const h1 = Cartesian3.fromDegreesArray([
-122.0, 36.0, -112.0, 36.0, -112.0, 39.0, -122.0, 39.0,
]);
const h2 = Cartesian3.fromDegreesArray([
-120.0, 36.5, -120.0, 38.5, -114.0, 38.5, -114.0, 36.5,
]);
const hierarchy = {
positions: p,
holes: [
{
positions: h1,
holes: [
{
positions: h2,
},
],
},
],
};
PolygonGeometry.createGeometry(
new PolygonGeometry({
vertexFormat: VertexFormat.POSITION_ONLY,
polygonHierarchy: hierarchy,
granularity: CesiumMath.PI_OVER_THREE,
}),
);
let i;
const 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);
}
const 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);
}
const 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 () {
const 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,
}),
);
const 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 () {
const height = 40000000.0;
const positions = Cartesian3.fromDegreesArray([
-108.0, 1.0, -108.0, -1.0, -106.0, -1.0, -106.0, 1.0,
]);
const p = PolygonGeometry.createGeometry(
PolygonGeometry.fromPositions({
vertexFormat: VertexFormat.POSITIONS_ONLY,
positions: positions,
height: height,
}),
);
const 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 () {
const 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,
}),
);
const numVertices = 50; // 13 top + 13 bottom + 8 top edge + 8 bottom edge + 4 top corner + 4 bottom corner
const 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 () {
const 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,
}),
);
const numVertices = 37; // 13 bottom + 8 top edge + 8 bottom edge + 4 top corner + 4 bottom corner
const 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 () {
const 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,
}),
);
const numVertices = 37; // 13 top + 8 top edge + 8 bottom edge + 4 top corner + 4 bottom corner
const 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 () {
const 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,
}),
);
const numVertices = 24; // 8 top edge + 8 bottom edge + 4 top corner + 4 bottom corner
const 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 () {
const 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,
}),
);
const numVertices = 13;
expect(p.attributes.position.values.length).toEqual(numVertices * 3);
const offset = p.attributes.applyOffset.values;
expect(offset.length).toEqual(numVertices);
const expected = new Array(offset.length).fill(1);
expect(offset).toEqual(expected);
});
it("computes offset attribute extruded for top vertices", function () {
const 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,
}),
);
const numVertices = 50;
expect(p.attributes.position.values.length).toEqual(numVertices * 3);
const offset = p.attributes.applyOffset.values;
expect(offset.length).toEqual(numVertices);
const expected = new Array(offset.length)
.fill(0)
.fill(1, 0, 13)
.fill(1, 26, 38);
expect(offset).toEqual(expected);
});
it("computes offset attribute extruded and not closeTop for top vertices", function () {
const 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,
}),
);
const 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);
const offset = p.attributes.applyOffset.values;
expect(offset.length).toEqual(numVertices);
const expected = new Array(offset.length).fill(0).fill(1, 13, 25);
expect(offset).toEqual(expected);
});
it("computes offset attribute extruded and not closeBottom for top vertcies", function () {
const 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,
}),
);
const numVertices = 37;
expect(p.attributes.position.values.length).toEqual(numVertices * 3);
const offset = p.attributes.applyOffset.values;
expect(offset.length).toEqual(numVertices);
const expected = new Array(offset.length).fill(0).fill(1, 0, 25);
expect(offset).toEqual(expected);
});
it("computes offset attribute extruded and not closeBottom or closeTop for top vertices", function () {
const 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,
}),
);
const numVertices = 24;
expect(p.attributes.position.values.length).toEqual(numVertices * 3);
const offset = p.attributes.applyOffset.values;
expect(offset.length).toEqual(numVertices);
const expected = new Array(offset.length).fill(0).fill(1, 0, 12);
expect(offset).toEqual(expected);
});
it("computes offset attribute extruded for all vertices", function () {
const 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,
}),
);
const numVertices = 50;
expect(p.attributes.position.values.length).toEqual(numVertices * 3);
const offset = p.attributes.applyOffset.values;
expect(offset.length).toEqual(numVertices);
const expected = new Array(offset.length).fill(1);
expect(offset).toEqual(expected);
});
it("computes offset attribute extruded and not closeTop for all vertices", function () {
const 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,
}),
);
const 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);
const offset = p.attributes.applyOffset.values;
expect(offset.length).toEqual(numVertices);
const expected = new Array(offset.length).fill(1);
expect(offset).toEqual(expected);
});
it("computes offset attribute extruded and not closeBottom for all vertcies", function () {
const 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,
}),
);
const numVertices = 37;
expect(p.attributes.position.values.length).toEqual(numVertices * 3);
const offset = p.attributes.applyOffset.values;
expect(offset.length).toEqual(numVertices);
const expected = new Array(offset.length).fill(1);
expect(offset).toEqual(expected);
});
it("computes offset attribute extruded and not closeBottom or closeTop for all vertices", function () {
const 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,
}),
);
const numVertices = 24;
expect(p.attributes.position.values.length).toEqual(numVertices * 3);
const offset = p.attributes.applyOffset.values;
expect(offset.length).toEqual(numVertices);
const expected = new Array(offset.length).fill(1);
expect(offset).toEqual(expected);
});
it("removes duplicates extruded", function () {
const 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 () {
const 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 () {
const 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,
}),
);
const numVertices = 50;
const 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 () {
const 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,
}),
);
const st = p.attributes.st.values;
for (let i = 0; i < st.length; i++) {
expect(st[i]).toBeGreaterThanOrEqual(0);
expect(st[i]).toBeLessThanOrEqual(1);
}
});
it("computes correct texture coordinates for polygon with position heights", function () {
const 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,
}),
);
const st = p.attributes.st.values;
for (let i = 0; i < st.length; i++) {
expect(st[i]).toBeGreaterThanOrEqual(0);
expect(st[i]).toBeLessThanOrEqual(1);
}
});
it("uses explicit texture coordinates if defined in options", function () {
const textureCoordinates = {
positions: [
new Cartesian2(0, 0),
new Cartesian2(1, 0),
new Cartesian2(1, 1),
new Cartesian2(0, 1),
],
};
const 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,
]),
},
textureCoordinates: textureCoordinates,
height: 150000,
granularity: CesiumMath.PI,
}),
);
const st = p.attributes.st.values;
for (let i = 0; i < textureCoordinates.positions.length; i++) {
expect(st[i * 2 + 0]).toEqual(textureCoordinates.positions[i].x);
expect(st[i * 2 + 1]).toEqual(textureCoordinates.positions[i].y);
}
});
it("creates a polygon from hierarchy extruded", function () {
const 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,
]),
},
],
},
],
};
const 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 () {
const polygon = PolygonGeometry.fromPositions({
positions: Cartesian3.fromDegreesArray([-72.0, 40.0, -68.0, 40.0]),
});
const geometry = PolygonGeometry.createGeometry(polygon);
expect(geometry).toBeUndefined();
});
it("computes normals for perPositionHeight", function () {
let 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,
}),
);
const normals = geometry.attributes.normal.values;
geometry = GeometryPipeline.computeNormal(geometry);
const expectedNormals = geometry.attributes.normal.values;
let notEqualCount = 0;
for (let 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 () {
const 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,
]);
const 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 () {
const positions = Cartesian3.fromDegreesArray([
7.757161063097392, 48.568676799636634, 7.753968290229146,
48.571796467099077, 7.755340073906587, 48.571948854067948,
7.756263393414589, 48.571947951609708, 7.756894446412183,
48.569396703043992,
]);
const pRhumb = PolygonGeometry.createGeometry(
PolygonGeometry.fromPositions({
vertexFormat: VertexFormat.POSITION_ONLY,
positions: positions,
extrudedHeight: 1000,
closeTop: false,
closeBottom: false,
arcType: ArcType.RHUMB,
}),
);
let numVertices = 20;
let 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);
const 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 () {
const 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,
});
const r = p.rectangle;
expect(CesiumMath.toDegrees(r.north)).toBeGreaterThan(30.5);
expect(CesiumMath.toDegrees(r.north)).toBeLessThan(30.5999);
expect(CesiumMath.toDegrees(r.south)).toEqualEpsilon(
30.0,
CesiumMath.EPSILON5,
);
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 () {
const 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,
});
const 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,
);
const 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,
});
const 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 () {
const 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,
});
const 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 () {
const minLon = Cartographic.fromDegrees(-178, 3);
const minLat = Cartographic.fromDegrees(-179, -4);
const maxLon = Cartographic.fromDegrees(178, 3);
const maxLat = Cartographic.fromDegrees(179, 4);
const cartesianArray = Ellipsoid.WGS84.cartographicArrayToCartesianArray([
minLat,
minLon,
maxLat,
maxLon,
]);
const pGeodesic = new PolygonGeometry({
vertexFormat: VertexFormat.POSITION_AND_ST,
polygonHierarchy: {
positions: cartesianArray,
},
granularity: CesiumMath.RADIANS_PER_DEGREE,
arcType: ArcType.GEODESIC,
});
const 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,
);
});
describe("computeRectangleFromPositions", function () {
it("computeRectangle with result parameter", function () {
const positions = Cartesian3.fromDegreesArray([30, 30, 60, 60, 30, 60]);
const result = new Rectangle();
const returned = PolygonGeometry.computeRectangleFromPositions(
positions,
Ellipsoid.WGS84,
ArcType.GEODESIC,
result,
);
expect(returned).toBe(result);
});
it("computes a rectangle enclosing a simple geodesic polygon in the northern hemisphere", function () {
const positions = Cartesian3.fromDegreesArray([30, 30, 60, 60, 30, 60]);
const result = PolygonGeometry.computeRectangleFromPositions(
positions,
Ellipsoid.WGS84,
);
expect(result).toBeInstanceOf(Rectangle);
expect(result.west).toEqualEpsilon(
CesiumMath.toRadians(30),
CesiumMath.EPSILON7,
);
expect(result.south).toEqualEpsilon(
CesiumMath.toRadians(30),
CesiumMath.EPSILON7,
);
expect(result.east).toEqualEpsilon(
CesiumMath.toRadians(60),
CesiumMath.EPSILON7,
);
expect(result.north).toBeGreaterThan(CesiumMath.toRadians(60));
expect(result.north).toBeLessThan(CesiumMath.toRadians(70));
});
it("computes a rectangle enclosing a simple rhumb polygon in the northern hemisphere", function () {
const positions = Cartesian3.fromDegreesArray([30, 30, 60, 60, 30, 60]);
const result = PolygonGeometry.computeRectangleFromPositions(
positions,
Ellipsoid.WGS84,
ArcType.RHUMB,
);
expect(result).toBeInstanceOf(Rectangle);
expect(result.west).toEqualEpsilon(
CesiumMath.toRadians(30),
CesiumMath.EPSILON7,
);
expect(result.south).toEqualEpsilon(
CesiumMath.toRadians(30),
CesiumMath.EPSILON7,
);
expect(result.east).toEqualEpsilon(
CesiumMath.toRadians(60),
CesiumMath.EPSILON7,
);
expect(result.north).toEqualEpsilon(
CesiumMath.toRadians(60),
CesiumMath.EPSILON7,
);
});
it("computes a rectangle enclosing a simple geodesic polygon in the southern hemisphere", function () {
const positions = Cartesian3.fromDegreesArray([
-30, -30, -60, -60, -30, -60,
]);
const result = PolygonGeometry.computeRectangleFromPositions(
positions,
Ellipsoid.WGS84,
);
expect(result).toBeInstanceOf(Rectangle);
expect(result.west).toEqualEpsilon(
CesiumMath.toRadians(-60),
CesiumMath.EPSILON7,
);
expect(result.south).toBeLessThan(CesiumMath.toRadians(-60));
expect(result.south).toBeGreaterThan(CesiumMath.toRadians(-70));
expect(result.east).toEqualEpsilon(
CesiumMath.toRadians(-30),
CesiumMath.EPSILON7,
);
expect(result.north).toEqualEpsilon(
CesiumMath.toRadians(-30),
CesiumMath.EPSILON7,
);
});
it("computes a rectangle enclosing a simple rhumb polygon in the southern hemisphere", function () {
const positions = Cartesian3.fromDegreesArray([
-30, -30, -60, -60, -30, -60,
]);
const result = PolygonGeometry.computeRectangleFromPositions(
positions,
Ellipsoid.WGS84,
ArcType.RHUMB,
);
expect(result).toBeInstanceOf(Rectangle);
expect(result.west).toEqualEpsilon(
CesiumMath.toRadians(-60),
CesiumMath.EPSILON7,
);
expect(result.south).toEqualEpsilon(
CesiumMath.toRadians(-60),
CesiumMath.EPSILON7,
);
expect(result.east).toEqualEpsilon(
CesiumMath.toRadians(-30),
CesiumMath.EPSILON7,
);
expect(result.north).toEqualEpsilon(
CesiumMath.toRadians(-30),
CesiumMath.EPSILON7,
);
});
it("computes a rectangle enclosing a simple polygon across the IDL", function () {
const positions = Cartesian3.fromDegreesArray([
170, 60, 170, 30, -170, 30,
]);
const result = PolygonGeometry.computeRectangleFromPositions(
positions,
Ellipsoid.WGS84,
);
expect(result).toBeInstanceOf(Rectangle);
expect(result.west).toEqualEpsilon(
CesiumMath.toRadians(170),
CesiumMath.EPSILON7,
);
expect(result.south).toEqualEpsilon(
CesiumMath.toRadians(30),
CesiumMath.EPSILON7,
);
expect(result.east).toEqualEpsilon(
CesiumMath.toRadians(-170),
CesiumMath.EPSILON7,
);
expect(result.north).toEqualEpsilon(
CesiumMath.toRadians(60),
CesiumMath.EPSILON7,
);
});
it("computes a rectangle enclosing a simple polygon across the equator", function () {
const positions = Cartesian3.fromDegreesArray([
30, 30, -30, 30, -30, -30, 30, -30,
]);
const result = PolygonGeometry.computeRectangleFromPositions(
positions,
Ellipsoid.WGS84,
ArcType.RHUMB,
);
expect(result).toBeInstanceOf(Rectangle);
expect(result.west).toEqualEpsilon(
CesiumMath.toRadians(-30),
CesiumMath.EPSILON7,
);
expect(result.south).toEqualEpsilon(
CesiumMath.toRadians(-30),
CesiumMath.EPSILON7,
);
expect(result.east).toEqualEpsilon(
CesiumMath.toRadians(30),
CesiumMath.EPSILON7,
);
expect(result.north).toEqualEpsilon(
CesiumMath.toRadians(30),
CesiumMath.EPSILON7,
);
});
it("computes a rectangle enclosing a simple convex polygon around the north pole", function () {
const positions = Cartesian3.fromDegreesArray([
45, 60, -45, 60, -135, 60, 140, 60,
]);
const result = PolygonGeometry.computeRectangleFromPositions(
positions,
Ellipsoid.WGS84,
);
expect(result).toBeInstanceOf(Rectangle);
expect(result.west).toEqualEpsilon(
CesiumMath.toRadians(-180),
CesiumMath.EPSILON7,
);
expect(result.south).toEqualEpsilon(
CesiumMath.toRadians(60),
CesiumMath.EPSILON7,
);
expect(result.east).toEqualEpsilon(
CesiumMath.toRadians(180),
CesiumMath.EPSILON7,
);
expect(result.north).toEqualEpsilon(
CesiumMath.toRadians(90),
CesiumMath.EPSILON7,
);
});
it("computes a rectangle enclosing a simple concave polygon around the north pole", function () {
const positions = Cartesian3.fromDegreesArray([
45, 60, -45, 60, -135, 60, -45, 80,
]);
const result = PolygonGeometry.computeRectangleFromPositions(
positions,
Ellipsoid.WGS84,
);
expect(result).toBeInstanceOf(Rectangle);
expect(result.west).toEqualEpsilon(
CesiumMath.toRadians(-135),
CesiumMath.EPSILON7,
);
expect(result.south).toEqualEpsilon(
CesiumMath.toRadians(60),
CesiumMath.EPSILON7,
);
expect(result.east).toEqualEpsilon(
CesiumMath.toRadians(45),
CesiumMath.EPSILON7,
);
expect(result.north).toEqualEpsilon(1.40485733, CesiumMath.EPSILON7);
});
it("computes a rectangle enclosing a simple clockwise convex polygon around the north pole", function () {
const positions = Cartesian3.fromDegreesArray([
140, 60, -135, 60, -45, 60, 45, 60,
]);
const result = PolygonGeometry.computeRectangleFromPositions(
positions,
Ellipsoid.WGS84,
);
expect(result).toBeInstanceOf(Rectangle);
expect(result.west).toEqualEpsilon(
CesiumMath.toRadians(-180),
CesiumMath.EPSILON7,
);
expect(result.south).toEqualEpsilon(
CesiumMath.toRadians(60),
CesiumMath.EPSILON7,
);
expect(result.east).toEqualEpsilon(
CesiumMath.toRadians(180),
CesiumMath.EPSILON7,
);
expect(result.north).toEqualEpsilon(
CesiumMath.toRadians(90),
CesiumMath.EPSILON7,
);
});
it("computes a rectangle enclosing a simple convex polygon around the south pole", function () {
const positions = Cartesian3.fromDegreesArray([
140, -60, -135, -60, -45, -60, 45, -60,
]);
const result = PolygonGeometry.computeRectangleFromPositions(
positions,
Ellipsoid.WGS84,
);
expect(result).toBeInstanceOf(Rectangle);
expect(result.west).toEqualEpsilon(
CesiumMath.toRadians(-180),
CesiumMath.EPSILON7,
);
expect(result.south).toEqualEpsilon(
CesiumMath.toRadians(-90),
CesiumMath.EPSILON7,
);
expect(result.east).toEqualEpsilon(
CesiumMath.toRadians(180),
CesiumMath.EPSILON7,
);
expect(result.north).toEqualEpsilon(
CesiumMath.toRadians(-60),
CesiumMath.EPSILON7,
);
});
it("computes a rectangle enclosing a simple concave rhumb polygon around the south pole", function () {
const positions = Cartesian3.fromDegreesArray([
45, -60, -45, -60, -135, -60, -45, -80,
]);
const result = PolygonGeometry.computeRectangleFromPositions(
positions,
Ellipsoid.WGS84,
ArcType.RHUMB,
);
expect(result).toBeInstanceOf(Rectangle);
expect(result.west).toEqualEpsilon(
CesiumMath.toRadians(-135),
CesiumMath.EPSILON7,
);
expect(result.south).toEqualEpsilon(
CesiumMath.toRadians(-80),
CesiumMath.EPSILON7,
);
expect(result.east).toEqualEpsilon(
CesiumMath.toRadians(45),
CesiumMath.EPSILON7,
);
expect(result.north).toEqualEpsilon(
CesiumMath.toRadians(-60),
CesiumMath.EPSILON7,
);
});
it("computes a rectangle enclosing a simple concave geodesic polygon around the south pole", function () {
const positions = Cartesian3.fromDegreesArray([
45, -60, -45, -60, -135, -60, -45, -80,
]);
const result = PolygonGeometry.computeRectangleFromPositions(
positions,
Ellipsoid.WGS84,
);
expect(result).toBeInstanceOf(Rectangle);
expect(result.west).toEqualEpsilon(
CesiumMath.toRadians(-135),
CesiumMath.EPSILON7,
);
expect(result.south).toBeLessThan(CesiumMath.toRadians(-80));
expect(result.south).toBeGreaterThan(CesiumMath.toRadians(-90));
expect(result.east).toEqualEpsilon(
CesiumMath.toRadians(45),
CesiumMath.EPSILON7,
);
expect(result.north).toEqualEpsilon(
CesiumMath.toRadians(-60),
CesiumMath.EPSILON7,
);
});
it("computes a rectangle enclosing a simple clockwise convex polygon around the south pole", function () {
const positions = Cartesian3.fromDegreesArray([
45, -60, -45, -60, -135, -60, 140, -60,
]);
const result = PolygonGeometry.computeRectangleFromPositions(
positions,
Ellipsoid.WGS84,
);
expect(result).toBeInstanceOf(Rectangle);
expect(result.west).toEqualEpsilon(
CesiumMath.toRadians(-180),
CesiumMath.EPSILON7,
);
expect(result.south).toEqualEpsilon(
CesiumMath.toRadians(-90),
CesiumMath.EPSILON7,
);
expect(result.east).toEqualEpsilon(
CesiumMath.toRadians(180),
CesiumMath.EPSILON7,
);
expect(result.north).toEqualEpsilon(
CesiumMath.toRadians(-60),
CesiumMath.EPSILON7,
);
});
});
it("computing textureCoordinateRotationPoints property", function () {
let 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),
arcType: ArcType.RHUMB,
});
// 90 degree rotation means (0, 1) should be the new min and (1, 1) (0, 0) are extents
let 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,
);
});
// pack without explicit texture coordinates
const positions = Cartesian3.fromDegreesArray([
-12.4, 3.5, -12.0, 3.5, -12.0, 4.0,
]);
const holePositions0 = Cartesian3.fromDegreesArray([
-12.2, 3.5, -12.2, 3.6, -12.3, 3.6,
]);
const holePositions1 = Cartesian3.fromDegreesArray([
-12.2, 3.5, -12.25, 3.5, -12.25, 3.55,
]);
const hierarchy = {
positions: positions,
holes: [
{
positions: holePositions0,
holes: [
{
positions: holePositions1,
holes: undefined,
},
],
},
],
};
const 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 (let i = 0; i < positions.length; ++i) {
array.push(positions[i].x, positions[i].y, positions[i].z);
}
}
function addPositions2D(array, positions) {
for (let i = 0; i < positions.length; ++i) {
array.push(positions[i].x, positions[i].y);
}
}
const 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,
-1,
55,
);
createPackableSpecs(PolygonGeometry, polygon, packedInstance);
// pack with explicit texture coordinates
const textureCoordinates = {
positions: [
new Cartesian2(0, 0),
new Cartesian2(1, 0),
new Cartesian2(0, 1),
new Cartesian2(0.1, 0.1),
new Cartesian2(0.5, 0.1),
new Cartesian2(0.1, 0.5),
new Cartesian2(0.2, 0.2),
new Cartesian2(0.3, 0.2),
new Cartesian2(0.2, 0.3),
],
holes: undefined,
};
const polygonTextured = new PolygonGeometry({
vertexFormat: VertexFormat.POSITION_ONLY,
polygonHierarchy: hierarchy,
textureCoordinates: textureCoordinates,
granularity: CesiumMath.PI_OVER_THREE,
perPositionHeight: true,
closeTop: false,
closeBottom: true,
});
const packedInstanceTextured = [3.0, 1.0];
addPositions(packedInstanceTextured, positions);
packedInstanceTextured.push(3.0, 1.0);
addPositions(packedInstanceTextured, holePositions0);
packedInstanceTextured.push(3.0, 0.0);
addPositions(packedInstanceTextured, holePositions1);
packedInstanceTextured.push(
Ellipsoid.WGS84.radii.x,
Ellipsoid.WGS84.radii.y,
Ellipsoid.WGS84.radii.z,
);
packedInstanceTextured.push(1.0, 0.0, 0.0, 0.0, 0.0, 0.0);
packedInstanceTextured.push(
0.0,
0.0,
CesiumMath.PI_OVER_THREE,
0.0,
0.0,
1.0,
0,
1,
0,
-1,
ArcType.GEODESIC,
);
packedInstanceTextured.push(9.0, 0.0);
addPositions2D(packedInstanceTextured, textureCoordinates.positions);
packedInstanceTextured.push(74);
createPackableSpecs(PolygonGeometry, polygonTextured, packedInstanceTextured);
});