Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 12 additions & 12 deletions specs/data/createTilesetJson/golden/batchedColors.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@
"root": {
"boundingVolume": {
"box": [
1215017.1239874638,
-4736316.080057698,
4081603.1264158455,
-1.2755385681689153,
4.9722508120558055,
-4.3138044394725314,
23.12108928345635,
-52.382444478338165,
-67.21456600138885,
-82.75933184818228,
-27.40170140970006,
-7.11330633281961
1215020.962196599,
-4736314.431739063,
4081600.5689328797,
83.39198781945653,
25.09669489341931,
3.497625570651054,
-1.4049290385910531,
5.351828760253799,
-4.904295184843724,
-19.867408658008266,
56.61289181944477,
67.47040900152847
]
},
"geometricError": 512,
Expand Down
24 changes: 12 additions & 12 deletions specs/data/createTilesetJson/golden/compositeOfComposite.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@
"root": {
"boundingVolume": {
"box": [
1215015.740633026,
-4736317.709331602,
4081606.5029129568,
91.34493746005317,
25.73468456069652,
2.891651051729513,
-3.4712154541846187,
13.441215114981711,
-9.969208596733905,
-17.541319642226654,
53.4750698059166,
78.20677126109172
1215014.7674845206,
-4736317.496050191,
4081607.1679102723,
90.85283629182183,
26.12990540945053,
3.22218827509456,
-3.4086480439178746,
13.055111922193284,
-9.758429440398935,
-18.098582106397203,
53.34766432454173,
77.69195131959206
]
},
"geometricError": 512,
Expand Down
287 changes: 287 additions & 0 deletions specs/tools/tilesetProcessing/BoundingVolumesContainmentSpec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
import {
Cartesian3,
Math as CesiumMath,
Matrix3,
Matrix4,
OrientedBoundingBox,
Quaternion,
} from "cesium";

import { BoundingVolumesContainment } from "../../../src/tools/tilesetProcessing/BoundingVolumesContainment";

/**
* Converts the given values from degrees to radians, and passes them
* to BoundingVolumesContainment.longitudeRangeContainsInclusive,
* returning whether the actual containment matches the expected one.
*
* @param westDeg - The west (leftmost) point, in degrees
* @param eastDeg - The east (rightmost) point, in degrees
* @param pointDeg - The point, in degrees
* @param expected - The expected containment
* @returns Whether the actual containment matches the expected one
*/
const check = (
westDeg: number,
eastDeg: number,
pointDeg: number,
expected: boolean
) => {
const epsilon = 1e-12;
const westRad = CesiumMath.toRadians(westDeg);
const eastRad = CesiumMath.toRadians(eastDeg);
const pointRad = CesiumMath.toRadians(pointDeg);
const actual = BoundingVolumesContainment.longitudeRangeContainsInclusive(
westRad,
eastRad,
pointRad,
epsilon
);
return expected == actual;
};

/**
* Calls 'check' with the given arguments, with all combinations of
* adding/subtracting 360 degrees, to check the wrapping behavior.
*
* @param westDeg - The west (leftmost) point, in degrees
* @param eastDeg - The east (rightmost) point, in degrees
* @param pointDeg - The point, in degrees
* @param expected - The expected containment
* @returns Whether the actual containment matches the expected one
*/
const checkAll = (
westDeg: number,
eastDeg: number,
pointDeg: number,
expected: boolean
) => {
let a = true;
a = a && check(westDeg, eastDeg, pointDeg, expected);

a = a && check(westDeg + 360, eastDeg, pointDeg, expected);
a = a && check(westDeg - 360, eastDeg, pointDeg, expected);
a = a && check(westDeg, eastDeg + 360, pointDeg, expected);
a = a && check(westDeg, eastDeg - 360, pointDeg, expected);
a = a && check(westDeg + 360, eastDeg + 360, pointDeg, expected);
a = a && check(westDeg - 360, eastDeg - 360, pointDeg, expected);

a = a && check(westDeg + 360, eastDeg, pointDeg + 360, expected);
a = a && check(westDeg - 360, eastDeg, pointDeg + 360, expected);
a = a && check(westDeg, eastDeg + 360, pointDeg + 360, expected);
a = a && check(westDeg, eastDeg - 360, pointDeg + 360, expected);
a = a && check(westDeg + 360, eastDeg + 360, pointDeg + 360, expected);
a = a && check(westDeg - 360, eastDeg - 360, pointDeg + 360, expected);

a = a && check(westDeg + 360, eastDeg, pointDeg - 360, expected);
a = a && check(westDeg - 360, eastDeg, pointDeg - 360, expected);
a = a && check(westDeg, eastDeg + 360, pointDeg - 360, expected);
a = a && check(westDeg, eastDeg - 360, pointDeg - 360, expected);
a = a && check(westDeg + 360, eastDeg + 360, pointDeg - 360, expected);
a = a && check(westDeg - 360, eastDeg - 360, pointDeg - 360, expected);

return a;
};

/**
* Transforms the given oriented bounding box with the given matrix
*
* @param orientedBoundingBox The oriented bounding box
* @param transform The transform matrix
* @returns The result
*/
const transformOrientedBoundingBox = (
orientedBoundingBox: OrientedBoundingBox,
transform: Matrix4
) => {
const result = new OrientedBoundingBox();
Matrix4.multiplyByPoint(transform, orientedBoundingBox.center, result.center);
const rotationScaleTransform = Matrix4.getMatrix3(transform, new Matrix3());
Matrix3.multiply(
rotationScaleTransform,
orientedBoundingBox.halfAxes,
result.halfAxes
);
return result;
};

/**
* Tests for the BoundingVolumesContainment class
*/
describe("BoundingVolumesContainment", function () {
it("boxContains works", function () {
const epsilon = 1e-12;

// Create an arbitrary matrix to be applied to the OBB and points,
// involving translation, rotation, and scale
const transform = Matrix4.fromTranslationQuaternionRotationScale(
new Cartesian3(1.0, 2.0, 3.0),
Quaternion.fromAxisAngle(
new Cartesian3(2.0, 4.0, 6.0),
CesiumMath.toRadians(45)
),
new Cartesian3(2.0, 4.0, 6.0)
);

// Create a "unit OBB", transform it, and convert the result into a "box" array
const unitObb = new OrientedBoundingBox(Cartesian3.ZERO, Matrix3.IDENTITY);
const obb = transformOrientedBoundingBox(unitObb, transform);
const box = OrientedBoundingBox.pack(obb, Array<number>(12), 0);

// Transform cartesians that are relative to the unit OBB
// with the matrix, convert them into point[] arrays,
// and perform the containment checks

const cartesianIn = new Cartesian3(0.9, 0.9, 0.9);
Matrix4.multiplyByPoint(transform, cartesianIn, cartesianIn);
const pointIn = Cartesian3.pack(cartesianIn, Array<number>(3), 0);
const actualIn = BoundingVolumesContainment.boxContains(
box,
pointIn,
epsilon
);
const expectedIn = true;
expect(actualIn).toBe(expectedIn);

const cartesianOn = new Cartesian3(1.0, 1.0, 1.0);
Matrix4.multiplyByPoint(transform, cartesianOn, cartesianOn);
const pointOn = Cartesian3.pack(cartesianOn, Array<number>(3), 0);
const actualOn = BoundingVolumesContainment.boxContains(
box,
pointOn,
epsilon
);
const expectedOn = true;
expect(actualOn).toBe(expectedOn);

const cartesianOut = new Cartesian3(1.0, 1.0, 1.01);
Matrix4.multiplyByPoint(transform, cartesianOut, cartesianOut);
const pointOut = Cartesian3.pack(cartesianOut, Array<number>(3), 0);
const actualOut = BoundingVolumesContainment.boxContains(
box,
pointOut,
epsilon
);
const expectedOut = false;
expect(actualOut).toBe(expectedOut);
});

it("sphereContains works", function () {
const epsilon = 1e-12;
const sphere = [1.0, 2.0, 3.0, 10.0];

const pointIn = [1.0 + 9.99, 2.0, 3.0];
const actualIn = BoundingVolumesContainment.sphereContains(
sphere,
pointIn,
epsilon
);
const expectedIn = true;
expect(actualIn).toBe(expectedIn);

const pointOn = [1.0, 2.0 + 10.0, 3.0];
const actualOn = BoundingVolumesContainment.sphereContains(
sphere,
pointOn,
epsilon
);
const expectedOn = true;
expect(actualOn).toBe(expectedOn);

const pointOut = [1.0, 2.0, 3.0 + 10.01];
const actualOut = BoundingVolumesContainment.sphereContains(
sphere,
pointOut,
epsilon
);
const expectedOut = false;
expect(actualOut).toBe(expectedOut);
});

it("regionContains works", function () {
const epsilon = 1e-6;

const westRad = CesiumMath.toRadians(20);
const southRad = CesiumMath.toRadians(10);
const eastRad = CesiumMath.toRadians(30);
const northRad = CesiumMath.toRadians(40);
const minHeightMeters = 50;
const maxHeightMeters = 60;
const region = [
westRad,
southRad,
eastRad,
northRad,
minHeightMeters,
maxHeightMeters,
];

const cartesianIn = Cartesian3.fromDegrees(25, 20, 55);
const pointIn = Cartesian3.pack(cartesianIn, Array<number>(3), 0);
const actualIn = BoundingVolumesContainment.regionContains(
region,
pointIn,
epsilon
);
const expectedIn = true;
expect(actualIn).toBe(expectedIn);

const cartesianOn = Cartesian3.fromDegrees(20, 30, 50);
const pointOn = Cartesian3.pack(cartesianOn, Array<number>(3), 0);
const actualOn = BoundingVolumesContainment.regionContains(
region,
pointOn,
epsilon
);
const expectedOn = true;
expect(actualOn).toBe(expectedOn);

const cartesianOut = Cartesian3.fromDegrees(19, 20, 55);
const pointOut = Cartesian3.pack(cartesianOut, Array<number>(3), 0);
const actualOut = BoundingVolumesContainment.regionContains(
region,
pointOut,
epsilon
);
const expectedOut = false;
expect(actualOut).toBe(expectedOut);
});

it("longitudeRangeContainsInclusive works", function () {
// Both positive, left, in, right
expect(checkAll(20, 40, 10, false)).toBeTrue();
expect(checkAll(20, 40, 20, true)).toBeTrue();
expect(checkAll(20, 40, 30, true)).toBeTrue();
expect(checkAll(20, 40, 40, true)).toBeTrue();
expect(checkAll(20, 40, 50, false)).toBeTrue();

// Both negative, left, in, right
expect(checkAll(-40, -20, -50, false)).toBeTrue();
expect(checkAll(-40, -20, -40, true)).toBeTrue();
expect(checkAll(-40, -20, -30, true)).toBeTrue();
expect(checkAll(-40, -20, -20, true)).toBeTrue();
expect(checkAll(-40, -20, -10, false)).toBeTrue();

// Crossing meridian, left, negative in, positive in, right
expect(checkAll(-20, 20, -30, false)).toBeTrue();
expect(checkAll(-20, 20, -20, true)).toBeTrue();
expect(checkAll(-20, 20, -10, true)).toBeTrue();
expect(checkAll(-20, 20, 10, true)).toBeTrue();
expect(checkAll(-20, 20, 20, true)).toBeTrue();
expect(checkAll(-20, 20, 30, false)).toBeTrue();

// Crossing antimeridian, left, positive in, negative in, right
expect(checkAll(160, -160, 150, false)).toBeTrue();
expect(checkAll(160, -160, 160, true)).toBeTrue();
expect(checkAll(160, -160, 170, true)).toBeTrue();
expect(checkAll(160, -160, -160, true)).toBeTrue();
expect(checkAll(160, -160, -150, false)).toBeTrue();

// Special cases
expect(checkAll(180, -180, 180, true)).toBeTrue();
expect(checkAll(180, -180, -180, true)).toBeTrue();
expect(checkAll(0, 0, 0, true)).toBeTrue();
expect(checkAll(0, 0, 360, true)).toBeTrue();
expect(checkAll(0, 360, 0, true)).toBeTrue();
expect(checkAll(0, 360, 360, true)).toBeTrue();
});
});
Loading