@math.gl/geometry 5.0.0-alpha.17 → 5.0.0-alpha.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -1
- package/dist/culling/constants.d.ts +3 -0
- package/dist/culling/constants.d.ts.map +1 -0
- package/dist/culling/constants.js +5 -0
- package/dist/culling/constants.js.map +1 -0
- package/dist/culling/index.cjs +2022 -0
- package/dist/culling/index.cjs.map +6 -0
- package/dist/culling/index.d.ts +28 -0
- package/dist/culling/index.d.ts.map +1 -0
- package/dist/culling/index.js +22 -0
- package/dist/culling/index.js.map +1 -0
- package/dist/culling/lib/algorithms/bounding-box-from-points.d.ts +15 -0
- package/dist/culling/lib/algorithms/bounding-box-from-points.d.ts.map +1 -0
- package/dist/culling/lib/algorithms/bounding-box-from-points.js +137 -0
- package/dist/culling/lib/algorithms/bounding-box-from-points.js.map +1 -0
- package/dist/culling/lib/algorithms/bounding-sphere-from-points.d.ts +14 -0
- package/dist/culling/lib/algorithms/bounding-sphere-from-points.d.ts.map +1 -0
- package/dist/culling/lib/algorithms/bounding-sphere-from-points.js +146 -0
- package/dist/culling/lib/algorithms/bounding-sphere-from-points.js.map +1 -0
- package/dist/culling/lib/algorithms/compute-eigen-decomposition.d.ts +37 -0
- package/dist/culling/lib/algorithms/compute-eigen-decomposition.d.ts.map +1 -0
- package/dist/culling/lib/algorithms/compute-eigen-decomposition.js +137 -0
- package/dist/culling/lib/algorithms/compute-eigen-decomposition.js.map +1 -0
- package/dist/culling/lib/bounding-volumes/axis-aligned-bounding-box.d.ts +56 -0
- package/dist/culling/lib/bounding-volumes/axis-aligned-bounding-box.d.ts.map +1 -0
- package/dist/culling/lib/bounding-volumes/axis-aligned-bounding-box.js +116 -0
- package/dist/culling/lib/bounding-volumes/axis-aligned-bounding-box.js.map +1 -0
- package/dist/culling/lib/bounding-volumes/bounding-sphere.d.ts +40 -0
- package/dist/culling/lib/bounding-volumes/bounding-sphere.d.ts.map +1 -0
- package/dist/culling/lib/bounding-volumes/bounding-sphere.js +123 -0
- package/dist/culling/lib/bounding-volumes/bounding-sphere.js.map +1 -0
- package/dist/culling/lib/bounding-volumes/bounding-volume.d.ts +30 -0
- package/dist/culling/lib/bounding-volumes/bounding-volume.d.ts.map +1 -0
- package/dist/culling/lib/bounding-volumes/bounding-volume.js +7 -0
- package/dist/culling/lib/bounding-volumes/bounding-volume.js.map +1 -0
- package/dist/culling/lib/bounding-volumes/oriented-bounding-box.d.ts +68 -0
- package/dist/culling/lib/bounding-volumes/oriented-bounding-box.d.ts.map +1 -0
- package/dist/culling/lib/bounding-volumes/oriented-bounding-box.js +259 -0
- package/dist/culling/lib/bounding-volumes/oriented-bounding-box.js.map +1 -0
- package/dist/culling/lib/culling-volume.d.ts +46 -0
- package/dist/culling/lib/culling-volume.d.ts.map +1 -0
- package/dist/culling/lib/culling-volume.js +126 -0
- package/dist/culling/lib/culling-volume.js.map +1 -0
- package/dist/culling/lib/perspective-frustum.d.ts +153 -0
- package/dist/culling/lib/perspective-frustum.d.ts.map +1 -0
- package/dist/culling/lib/perspective-frustum.js +191 -0
- package/dist/culling/lib/perspective-frustum.js.map +1 -0
- package/dist/culling/lib/perspective-off-center-frustum.d.ts +158 -0
- package/dist/culling/lib/perspective-off-center-frustum.d.ts.map +1 -0
- package/dist/culling/lib/perspective-off-center-frustum.js +276 -0
- package/dist/culling/lib/perspective-off-center-frustum.js.map +1 -0
- package/dist/culling/lib/plane.d.ts +35 -0
- package/dist/culling/lib/plane.d.ts.map +1 -0
- package/dist/culling/lib/plane.js +90 -0
- package/dist/culling/lib/plane.js.map +1 -0
- package/dist/culling/lib/ray.d.ts +13 -0
- package/dist/culling/lib/ray.d.ts.map +1 -0
- package/dist/culling/lib/ray.js +30 -0
- package/dist/culling/lib/ray.js.map +1 -0
- package/dist/culling/lib/shapes/box-shape.d.ts +19 -0
- package/dist/culling/lib/shapes/box-shape.d.ts.map +1 -0
- package/dist/culling/lib/shapes/box-shape.js +69 -0
- package/dist/culling/lib/shapes/box-shape.js.map +1 -0
- package/dist/culling/lib/shapes/capsule-shape.d.ts +23 -0
- package/dist/culling/lib/shapes/capsule-shape.d.ts.map +1 -0
- package/dist/culling/lib/shapes/capsule-shape.js +151 -0
- package/dist/culling/lib/shapes/capsule-shape.js.map +1 -0
- package/dist/culling/lib/shapes/cylinder-shape.d.ts +22 -0
- package/dist/culling/lib/shapes/cylinder-shape.d.ts.map +1 -0
- package/dist/culling/lib/shapes/cylinder-shape.js +99 -0
- package/dist/culling/lib/shapes/cylinder-shape.js.map +1 -0
- package/dist/culling/lib/shapes/implicit-shape.d.ts +56 -0
- package/dist/culling/lib/shapes/implicit-shape.d.ts.map +1 -0
- package/dist/culling/lib/shapes/implicit-shape.js +142 -0
- package/dist/culling/lib/shapes/implicit-shape.js.map +1 -0
- package/dist/culling/lib/shapes/plane-shape.d.ts +27 -0
- package/dist/culling/lib/shapes/plane-shape.d.ts.map +1 -0
- package/dist/culling/lib/shapes/plane-shape.js +71 -0
- package/dist/culling/lib/shapes/plane-shape.js.map +1 -0
- package/dist/culling/lib/shapes/sphere-shape.d.ts +18 -0
- package/dist/culling/lib/shapes/sphere-shape.d.ts.map +1 -0
- package/dist/culling/lib/shapes/sphere-shape.js +43 -0
- package/dist/culling/lib/shapes/sphere-shape.js.map +1 -0
- package/dist/culling/oriented-box-2d.cjs +73 -0
- package/dist/culling/oriented-box-2d.cjs.map +6 -0
- package/dist/culling/oriented-box-2d.d.ts +22 -0
- package/dist/culling/oriented-box-2d.d.ts.map +1 -0
- package/dist/culling/oriented-box-2d.js +86 -0
- package/dist/culling/oriented-box-2d.js.map +1 -0
- package/dist/culling/queries.cjs +161 -0
- package/dist/culling/queries.cjs.map +6 -0
- package/dist/culling/queries.d.ts +20 -0
- package/dist/culling/queries.d.ts.map +1 -0
- package/dist/culling/queries.js +139 -0
- package/dist/culling/queries.js.map +1 -0
- package/dist/curves/bezier-curves.d.ts +18 -0
- package/dist/curves/bezier-curves.d.ts.map +1 -0
- package/dist/curves/bezier-curves.js +54 -0
- package/dist/curves/bezier-curves.js.map +1 -0
- package/dist/curves/catmull-rom-curve.d.ts +15 -0
- package/dist/curves/catmull-rom-curve.d.ts.map +1 -0
- package/dist/curves/catmull-rom-curve.js +77 -0
- package/dist/curves/catmull-rom-curve.js.map +1 -0
- package/dist/curves/curve-arc-length.d.ts +17 -0
- package/dist/curves/curve-arc-length.d.ts.map +1 -0
- package/dist/curves/curve-arc-length.js +58 -0
- package/dist/curves/curve-arc-length.js.map +1 -0
- package/dist/curves/curve.d.ts +23 -0
- package/dist/curves/curve.d.ts.map +1 -0
- package/dist/curves/curve.js +77 -0
- package/dist/curves/curve.js.map +1 -0
- package/dist/curves/hermite-curve.d.ts +9 -0
- package/dist/curves/hermite-curve.d.ts.map +1 -0
- package/dist/curves/hermite-curve.js +24 -0
- package/dist/curves/hermite-curve.js.map +1 -0
- package/dist/curves/index.cjs +293 -0
- package/dist/curves/index.cjs.map +6 -0
- package/dist/curves/index.d.ts +8 -0
- package/dist/curves/index.d.ts.map +1 -0
- package/dist/curves/index.js +9 -0
- package/dist/curves/index.js.map +1 -0
- package/dist/lib/geometry.d.ts +1 -1
- package/dist/lib/geometry.d.ts.map +1 -1
- package/dist/polygon/cut-by-grid.d.ts +24 -0
- package/dist/polygon/cut-by-grid.d.ts.map +1 -0
- package/dist/polygon/cut-by-grid.js +221 -0
- package/dist/polygon/cut-by-grid.js.map +1 -0
- package/dist/polygon/cut-by-mercator-bounds.d.ts +17 -0
- package/dist/polygon/cut-by-mercator-bounds.d.ts.map +1 -0
- package/dist/polygon/cut-by-mercator-bounds.js +149 -0
- package/dist/polygon/cut-by-mercator-bounds.js.map +1 -0
- package/dist/polygon/earcut.d.ts +13 -0
- package/dist/polygon/earcut.d.ts.map +1 -0
- package/dist/polygon/earcut.js +627 -0
- package/dist/polygon/earcut.js.map +1 -0
- package/dist/polygon/index.cjs +1414 -0
- package/dist/polygon/index.cjs.map +6 -0
- package/dist/polygon/index.d.ts +12 -0
- package/dist/polygon/index.d.ts.map +1 -0
- package/dist/polygon/index.js +12 -0
- package/dist/polygon/index.js.map +1 -0
- package/dist/polygon/lineclip.d.ts +31 -0
- package/dist/polygon/lineclip.d.ts.map +1 -0
- package/dist/polygon/lineclip.js +184 -0
- package/dist/polygon/lineclip.js.map +1 -0
- package/dist/polygon/polygon-utils.d.ts +103 -0
- package/dist/polygon/polygon-utils.d.ts.map +1 -0
- package/dist/polygon/polygon-utils.js +155 -0
- package/dist/polygon/polygon-utils.js.map +1 -0
- package/dist/polygon/polygon.d.ts +41 -0
- package/dist/polygon/polygon.d.ts.map +1 -0
- package/dist/polygon/polygon.js +76 -0
- package/dist/polygon/polygon.js.map +1 -0
- package/dist/polygon/subdivide-polyline.d.ts +42 -0
- package/dist/polygon/subdivide-polyline.d.ts.map +1 -0
- package/dist/polygon/subdivide-polyline.js +109 -0
- package/dist/polygon/subdivide-polyline.js.map +1 -0
- package/dist/polygon/subdivide-triangle-mesh.d.ts +68 -0
- package/dist/polygon/subdivide-triangle-mesh.d.ts.map +1 -0
- package/dist/polygon/subdivide-triangle-mesh.js +228 -0
- package/dist/polygon/subdivide-triangle-mesh.js.map +1 -0
- package/dist/polygon/utils.d.ts +5 -0
- package/dist/polygon/utils.d.ts.map +1 -0
- package/dist/polygon/utils.js +38 -0
- package/dist/polygon/utils.js.map +1 -0
- package/dist/spatial-index/box-index.cjs +328 -0
- package/dist/spatial-index/box-index.cjs.map +6 -0
- package/dist/spatial-index/box-index.d.ts +65 -0
- package/dist/spatial-index/box-index.d.ts.map +1 -0
- package/dist/spatial-index/box-index.js +263 -0
- package/dist/spatial-index/box-index.js.map +1 -0
- package/dist/spatial-index/index.cjs +494 -0
- package/dist/spatial-index/index.cjs.map +6 -0
- package/dist/spatial-index/index.d.ts +5 -0
- package/dist/spatial-index/index.d.ts.map +1 -0
- package/dist/spatial-index/index.js +6 -0
- package/dist/spatial-index/index.js.map +1 -0
- package/dist/spatial-index/triangle-bvh.d.ts +53 -0
- package/dist/spatial-index/triangle-bvh.d.ts.map +1 -0
- package/dist/spatial-index/triangle-bvh.js +102 -0
- package/dist/spatial-index/triangle-bvh.js.map +1 -0
- package/dist/utils/attribute-compression.d.ts +50 -0
- package/dist/utils/attribute-compression.d.ts.map +1 -0
- package/dist/utils/attribute-compression.js +186 -0
- package/dist/utils/attribute-compression.js.map +1 -0
- package/dist/utils/attribute-iterator.d.ts +8 -0
- package/dist/utils/attribute-iterator.d.ts.map +1 -0
- package/dist/utils/attribute-iterator.js +25 -0
- package/dist/utils/attribute-iterator.js.map +1 -0
- package/dist/utils/compute-vertex-normals.d.ts +4 -0
- package/dist/utils/compute-vertex-normals.d.ts.map +1 -0
- package/dist/utils/compute-vertex-normals.js +54 -0
- package/dist/utils/compute-vertex-normals.js.map +1 -0
- package/dist/utils/constants.d.ts +52 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +39 -0
- package/dist/utils/constants.js.map +1 -0
- package/dist/utils/coordinates.d.ts +3 -0
- package/dist/utils/coordinates.d.ts.map +1 -0
- package/dist/utils/coordinates.js +8 -0
- package/dist/utils/coordinates.js.map +1 -0
- package/dist/utils/geometry.d.ts +20 -0
- package/dist/utils/geometry.d.ts.map +1 -0
- package/dist/utils/geometry.js +31 -0
- package/dist/utils/geometry.js.map +1 -0
- package/dist/utils/gl-type.d.ts +17 -0
- package/dist/utils/gl-type.d.ts.map +1 -0
- package/dist/utils/gl-type.js +69 -0
- package/dist/utils/gl-type.js.map +1 -0
- package/dist/utils/index.cjs +965 -0
- package/dist/utils/index.cjs.map +6 -0
- package/dist/utils/index.d.ts +18 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +16 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/interpolate-packed-attributes.cjs +176 -0
- package/dist/utils/interpolate-packed-attributes.cjs.map +6 -0
- package/dist/utils/interpolate-packed-attributes.d.ts +43 -0
- package/dist/utils/interpolate-packed-attributes.d.ts.map +1 -0
- package/dist/utils/interpolate-packed-attributes.js +192 -0
- package/dist/utils/interpolate-packed-attributes.js.map +1 -0
- package/dist/utils/mesh-processing.d.ts +18 -0
- package/dist/utils/mesh-processing.d.ts.map +1 -0
- package/dist/utils/mesh-processing.js +300 -0
- package/dist/utils/mesh-processing.js.map +1 -0
- package/dist/utils/primitive-iterator.d.ts +21 -0
- package/dist/utils/primitive-iterator.d.ts.map +1 -0
- package/dist/utils/primitive-iterator.js +117 -0
- package/dist/utils/primitive-iterator.js.map +1 -0
- package/dist/utils/rgb565.d.ts +5 -0
- package/dist/utils/rgb565.d.ts.map +1 -0
- package/dist/utils/rgb565.js +24 -0
- package/dist/utils/rgb565.js.map +1 -0
- package/dist/utils/typed-array-utils.d.ts +3 -0
- package/dist/utils/typed-array-utils.d.ts.map +1 -0
- package/dist/utils/typed-array-utils.js +16 -0
- package/dist/utils/typed-array-utils.js.map +1 -0
- package/package.json +49 -3
- package/src/culling/constants.ts +6 -0
- package/src/culling/index.ts +40 -0
- package/src/culling/lib/algorithms/bounding-box-from-points.ts +174 -0
- package/src/culling/lib/algorithms/bounding-sphere-from-points.ts +175 -0
- package/src/culling/lib/algorithms/compute-eigen-decomposition.ts +171 -0
- package/src/culling/lib/bounding-volumes/axis-aligned-bounding-box.ts +153 -0
- package/src/culling/lib/bounding-volumes/bounding-sphere.ts +154 -0
- package/src/culling/lib/bounding-volumes/bounding-volume.ts +38 -0
- package/src/culling/lib/bounding-volumes/oriented-bounding-box.ts +355 -0
- package/src/culling/lib/culling-volume.ts +163 -0
- package/src/culling/lib/perspective-frustum.ts +288 -0
- package/src/culling/lib/perspective-off-center-frustum.ts +381 -0
- package/src/culling/lib/plane.ts +118 -0
- package/src/culling/lib/ray.ts +33 -0
- package/src/culling/lib/shapes/box-shape.ts +78 -0
- package/src/culling/lib/shapes/capsule-shape.ts +232 -0
- package/src/culling/lib/shapes/cylinder-shape.ts +133 -0
- package/src/culling/lib/shapes/implicit-shape.ts +209 -0
- package/src/culling/lib/shapes/plane-shape.ts +78 -0
- package/src/culling/lib/shapes/sphere-shape.ts +60 -0
- package/src/culling/oriented-box-2d.ts +165 -0
- package/src/culling/queries.ts +155 -0
- package/src/curves/bezier-curves.ts +62 -0
- package/src/curves/catmull-rom-curve.ts +89 -0
- package/src/curves/curve-arc-length.ts +70 -0
- package/src/curves/curve.ts +96 -0
- package/src/curves/hermite-curve.ts +34 -0
- package/src/curves/index.ts +15 -0
- package/src/lib/geometry-utils.ts +1 -1
- package/src/lib/geometry.ts +1 -1
- package/src/polygon/cut-by-grid.ts +313 -0
- package/src/polygon/cut-by-mercator-bounds.ts +204 -0
- package/src/polygon/earcut.ts +798 -0
- package/src/polygon/index.ts +31 -0
- package/src/polygon/lineclip.ts +218 -0
- package/src/polygon/polygon-utils.ts +273 -0
- package/src/polygon/polygon.ts +105 -0
- package/src/polygon/subdivide-polyline.ts +160 -0
- package/src/polygon/subdivide-triangle-mesh.ts +322 -0
- package/src/polygon/utils.ts +50 -0
- package/src/spatial-index/box-index.ts +343 -0
- package/src/spatial-index/index.ts +18 -0
- package/src/spatial-index/triangle-bvh.ts +162 -0
- package/src/utils/attribute-compression.ts +234 -0
- package/src/utils/attribute-iterator.ts +28 -0
- package/src/utils/compute-vertex-normals.ts +63 -0
- package/src/utils/constants.ts +42 -0
- package/src/utils/coordinates.ts +8 -0
- package/src/utils/geometry.ts +49 -0
- package/src/utils/gl-type.ts +87 -0
- package/src/utils/index.ts +55 -0
- package/src/utils/interpolate-packed-attributes.ts +284 -0
- package/src/utils/mesh-processing.ts +377 -0
- package/src/utils/primitive-iterator.ts +145 -0
- package/src/utils/rgb565.ts +26 -0
- package/src/utils/typed-array-utils.ts +16 -0
|
@@ -0,0 +1,2022 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
|
|
29
|
+
// dist/culling/index.js
|
|
30
|
+
var index_exports = {};
|
|
31
|
+
__export(index_exports, {
|
|
32
|
+
AxisAlignedBoundingBox: () => AxisAlignedBoundingBox,
|
|
33
|
+
BoundingSphere: () => BoundingSphere,
|
|
34
|
+
BoxShape: () => BoxShape,
|
|
35
|
+
CapsuleShape: () => CapsuleShape,
|
|
36
|
+
CullingVolume: () => CullingVolume,
|
|
37
|
+
CylinderShape: () => CylinderShape,
|
|
38
|
+
OrientedBoundingBox: () => OrientedBoundingBox,
|
|
39
|
+
Plane: () => Plane,
|
|
40
|
+
PlaneShape: () => PlaneShape,
|
|
41
|
+
Ray: () => Ray,
|
|
42
|
+
SphereShape: () => SphereShape,
|
|
43
|
+
_PerspectiveFrustum: () => PerspectiveFrustum,
|
|
44
|
+
_PerspectiveOffCenterFrustum: () => PerspectiveOffCenterFrustum,
|
|
45
|
+
computeEigenDecomposition: () => computeEigenDecomposition,
|
|
46
|
+
getClosestPointOnTriangle: () => getClosestPointOnTriangle,
|
|
47
|
+
intersectOrientedBoxes2D: () => intersectOrientedBoxes2D,
|
|
48
|
+
intersectRayBounds: () => intersectRayBounds,
|
|
49
|
+
intersectRayTriangle: () => intersectRayTriangle,
|
|
50
|
+
makeAxisAlignedBoundingBoxFromPoints: () => makeAxisAlignedBoundingBoxFromPoints,
|
|
51
|
+
makeBoundingSphereFromPoints: () => makeBoundingSphereFromPoints,
|
|
52
|
+
makeOrientedBoundingBoxFromPoints: () => makeOrientedBoundingBoxFromPoints
|
|
53
|
+
});
|
|
54
|
+
module.exports = __toCommonJS(index_exports);
|
|
55
|
+
|
|
56
|
+
// dist/culling/lib/bounding-volumes/axis-aligned-bounding-box.js
|
|
57
|
+
var import_core = require("@math.gl/core");
|
|
58
|
+
var scratchVector = new import_core.Vector3();
|
|
59
|
+
var scratchNormal = new import_core.Vector3();
|
|
60
|
+
var AxisAlignedBoundingBox = class _AxisAlignedBoundingBox {
|
|
61
|
+
/**
|
|
62
|
+
* Creates an instance of an AxisAlignedBoundingBox from the minimum and maximum points along the x, y, and z axes.
|
|
63
|
+
* @param minimum=[0, 0, 0] The minimum point along the x, y, and z axes.
|
|
64
|
+
* @param maximum=[0, 0, 0] The maximum point along the x, y, and z axes.
|
|
65
|
+
* @param center The center of the box; automatically computed if not supplied.
|
|
66
|
+
*/
|
|
67
|
+
constructor(minimum = [0, 0, 0], maximum = [0, 0, 0], center) {
|
|
68
|
+
center = center || scratchVector.copy(minimum).add(maximum).scale(0.5);
|
|
69
|
+
this.center = new import_core.Vector3(center);
|
|
70
|
+
this.halfDiagonal = new import_core.Vector3(maximum).subtract(this.center);
|
|
71
|
+
this.minimum = new import_core.Vector3(minimum);
|
|
72
|
+
this.maximum = new import_core.Vector3(maximum);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Duplicates a AxisAlignedBoundingBox instance.
|
|
76
|
+
*
|
|
77
|
+
* @returns {AxisAlignedBoundingBox} A new AxisAlignedBoundingBox instance.
|
|
78
|
+
*/
|
|
79
|
+
clone() {
|
|
80
|
+
return new _AxisAlignedBoundingBox(this.minimum, this.maximum, this.center);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Compares the provided AxisAlignedBoundingBox componentwise and returns
|
|
84
|
+
* <code>true</code> if they are equal, <code>false</code> otherwise.
|
|
85
|
+
*
|
|
86
|
+
* @param {AxisAlignedBoundingBox} [right] The second AxisAlignedBoundingBox to compare with.
|
|
87
|
+
* @returns {Boolean} <code>true</code> if left and right are equal, <code>false</code> otherwise.
|
|
88
|
+
*/
|
|
89
|
+
equals(right) {
|
|
90
|
+
return this === right || Boolean(right) && this.minimum.equals(right.minimum) && this.maximum.equals(right.maximum);
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Applies a 4x4 affine transformation matrix to a bounding sphere.
|
|
94
|
+
* @param transform The transformation matrix to apply to the bounding sphere.
|
|
95
|
+
* @returns itself, i.e. the modified BoundingVolume.
|
|
96
|
+
*/
|
|
97
|
+
transform(transform) {
|
|
98
|
+
this.center.transformAsPoint(transform);
|
|
99
|
+
this.halfDiagonal.transform(transform);
|
|
100
|
+
this.minimum.transform(transform);
|
|
101
|
+
this.maximum.transform(transform);
|
|
102
|
+
return this;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Determines which side of a plane a box is located.
|
|
106
|
+
*/
|
|
107
|
+
intersectPlane(plane) {
|
|
108
|
+
const { halfDiagonal } = this;
|
|
109
|
+
const normal = scratchNormal.from(plane.normal);
|
|
110
|
+
const e = halfDiagonal.x * Math.abs(normal.x) + halfDiagonal.y * Math.abs(normal.y) + halfDiagonal.z * Math.abs(normal.z);
|
|
111
|
+
const s = this.center.dot(normal) + plane.distance;
|
|
112
|
+
if (s - e > 0) {
|
|
113
|
+
return "inside";
|
|
114
|
+
}
|
|
115
|
+
if (s + e < 0) {
|
|
116
|
+
return "outside";
|
|
117
|
+
}
|
|
118
|
+
return "intersecting";
|
|
119
|
+
}
|
|
120
|
+
/** Computes the estimated distance from the closest point on a bounding box to a point. */
|
|
121
|
+
distanceTo(point) {
|
|
122
|
+
return Math.sqrt(this.distanceSquaredTo(point));
|
|
123
|
+
}
|
|
124
|
+
/** Computes the estimated distance squared from the closest point on a bounding box to a point. */
|
|
125
|
+
distanceSquaredTo(point) {
|
|
126
|
+
const offset = scratchVector.from(point).subtract(this.center);
|
|
127
|
+
const { halfDiagonal } = this;
|
|
128
|
+
let distanceSquared = 0;
|
|
129
|
+
let d;
|
|
130
|
+
d = Math.abs(offset.x) - halfDiagonal.x;
|
|
131
|
+
if (d > 0) {
|
|
132
|
+
distanceSquared += d * d;
|
|
133
|
+
}
|
|
134
|
+
d = Math.abs(offset.y) - halfDiagonal.y;
|
|
135
|
+
if (d > 0) {
|
|
136
|
+
distanceSquared += d * d;
|
|
137
|
+
}
|
|
138
|
+
d = Math.abs(offset.z) - halfDiagonal.z;
|
|
139
|
+
if (d > 0) {
|
|
140
|
+
distanceSquared += d * d;
|
|
141
|
+
}
|
|
142
|
+
return distanceSquared;
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// dist/culling/lib/bounding-volumes/bounding-sphere.js
|
|
147
|
+
var import_core2 = require("@math.gl/core");
|
|
148
|
+
var mat4 = __toESM(require("@math.gl/core/mat4"), 1);
|
|
149
|
+
var scratchVector2 = new import_core2.Vector3();
|
|
150
|
+
var scratchVector22 = new import_core2.Vector3();
|
|
151
|
+
var BoundingSphere = class _BoundingSphere {
|
|
152
|
+
/** Creates a bounding sphere */
|
|
153
|
+
constructor(center = [0, 0, 0], radius = 0) {
|
|
154
|
+
this.radius = -0;
|
|
155
|
+
this.center = new import_core2.Vector3();
|
|
156
|
+
this.fromCenterRadius(center, radius);
|
|
157
|
+
}
|
|
158
|
+
/** Sets the bounding sphere from `center` and `radius`. */
|
|
159
|
+
fromCenterRadius(center, radius) {
|
|
160
|
+
this.center.from(center);
|
|
161
|
+
this.radius = radius;
|
|
162
|
+
return this;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Computes a bounding sphere from the corner points of an axis-aligned bounding box. The sphere
|
|
166
|
+
* tightly and fully encompasses the box.
|
|
167
|
+
*/
|
|
168
|
+
fromCornerPoints(corner, oppositeCorner) {
|
|
169
|
+
oppositeCorner = scratchVector2.from(oppositeCorner);
|
|
170
|
+
this.center = new import_core2.Vector3().from(corner).add(oppositeCorner).scale(0.5);
|
|
171
|
+
this.radius = this.center.distance(oppositeCorner);
|
|
172
|
+
return this;
|
|
173
|
+
}
|
|
174
|
+
/** Compares the provided BoundingSphere component wise */
|
|
175
|
+
equals(right) {
|
|
176
|
+
return this === right || Boolean(right) && this.center.equals(right.center) && this.radius === right.radius;
|
|
177
|
+
}
|
|
178
|
+
/** Duplicates a BoundingSphere instance. */
|
|
179
|
+
clone() {
|
|
180
|
+
return new _BoundingSphere(this.center, this.radius);
|
|
181
|
+
}
|
|
182
|
+
/** Computes a bounding sphere that contains both the left and right bounding spheres. */
|
|
183
|
+
union(boundingSphere) {
|
|
184
|
+
const leftCenter = this.center;
|
|
185
|
+
const leftRadius = this.radius;
|
|
186
|
+
const rightCenter = boundingSphere.center;
|
|
187
|
+
const rightRadius = boundingSphere.radius;
|
|
188
|
+
const toRightCenter = scratchVector2.copy(rightCenter).subtract(leftCenter);
|
|
189
|
+
const centerSeparation = toRightCenter.magnitude();
|
|
190
|
+
if (leftRadius >= centerSeparation + rightRadius) {
|
|
191
|
+
return this.clone();
|
|
192
|
+
}
|
|
193
|
+
if (rightRadius >= centerSeparation + leftRadius) {
|
|
194
|
+
return boundingSphere.clone();
|
|
195
|
+
}
|
|
196
|
+
const halfDistanceBetweenTangentPoints = (leftRadius + centerSeparation + rightRadius) * 0.5;
|
|
197
|
+
scratchVector22.copy(toRightCenter).scale((-leftRadius + halfDistanceBetweenTangentPoints) / centerSeparation).add(leftCenter);
|
|
198
|
+
this.center.copy(scratchVector22);
|
|
199
|
+
this.radius = halfDistanceBetweenTangentPoints;
|
|
200
|
+
return this;
|
|
201
|
+
}
|
|
202
|
+
/** Computes a bounding sphere by enlarging the provided sphere to contain the provided point. */
|
|
203
|
+
expand(point) {
|
|
204
|
+
const scratchPoint = scratchVector2.from(point);
|
|
205
|
+
const radius = scratchPoint.subtract(this.center).magnitude();
|
|
206
|
+
if (radius > this.radius) {
|
|
207
|
+
this.radius = radius;
|
|
208
|
+
}
|
|
209
|
+
return this;
|
|
210
|
+
}
|
|
211
|
+
// BoundingVolume interface
|
|
212
|
+
/**
|
|
213
|
+
* Applies a 4x4 affine transformation matrix to a bounding sphere.
|
|
214
|
+
* @param sphere The bounding sphere to apply the transformation to.
|
|
215
|
+
* @param transform The transformation matrix to apply to the bounding sphere.
|
|
216
|
+
* @returns self.
|
|
217
|
+
*/
|
|
218
|
+
transform(transform) {
|
|
219
|
+
this.center.transform(transform);
|
|
220
|
+
const scale = mat4.getScaling(scratchVector2, transform);
|
|
221
|
+
this.radius = Math.max(scale[0], Math.max(scale[1], scale[2])) * this.radius;
|
|
222
|
+
return this;
|
|
223
|
+
}
|
|
224
|
+
/** Computes the estimated distance squared from the closest point on a bounding sphere to a point. */
|
|
225
|
+
distanceSquaredTo(point) {
|
|
226
|
+
const d = this.distanceTo(point);
|
|
227
|
+
return d * d;
|
|
228
|
+
}
|
|
229
|
+
/** Computes the estimated distance from the closest point on a bounding sphere to a point. */
|
|
230
|
+
distanceTo(point) {
|
|
231
|
+
const scratchPoint = scratchVector2.from(point);
|
|
232
|
+
const delta = scratchPoint.subtract(this.center);
|
|
233
|
+
return Math.max(0, delta.len() - this.radius);
|
|
234
|
+
}
|
|
235
|
+
/** Determines which side of a plane a sphere is located. */
|
|
236
|
+
intersectPlane(plane) {
|
|
237
|
+
const center = this.center;
|
|
238
|
+
const radius = this.radius;
|
|
239
|
+
const normal = plane.normal;
|
|
240
|
+
const distanceToPlane = normal.dot(center) + plane.distance;
|
|
241
|
+
if (distanceToPlane < -radius) {
|
|
242
|
+
return "outside";
|
|
243
|
+
}
|
|
244
|
+
if (distanceToPlane < radius) {
|
|
245
|
+
return "intersecting";
|
|
246
|
+
}
|
|
247
|
+
return "inside";
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
// dist/culling/lib/bounding-volumes/oriented-bounding-box.js
|
|
252
|
+
var import_core3 = require("@math.gl/core");
|
|
253
|
+
var scratchVector3 = new import_core3.Vector3();
|
|
254
|
+
var scratchOffset = new import_core3.Vector3();
|
|
255
|
+
var scratchVectorU = new import_core3.Vector3();
|
|
256
|
+
var scratchVectorV = new import_core3.Vector3();
|
|
257
|
+
var scratchVectorW = new import_core3.Vector3();
|
|
258
|
+
var scratchCorner = new import_core3.Vector3();
|
|
259
|
+
var scratchToCenter = new import_core3.Vector3();
|
|
260
|
+
var MATRIX3 = {
|
|
261
|
+
COLUMN0ROW0: 0,
|
|
262
|
+
COLUMN0ROW1: 1,
|
|
263
|
+
COLUMN0ROW2: 2,
|
|
264
|
+
COLUMN1ROW0: 3,
|
|
265
|
+
COLUMN1ROW1: 4,
|
|
266
|
+
COLUMN1ROW2: 5,
|
|
267
|
+
COLUMN2ROW0: 6,
|
|
268
|
+
COLUMN2ROW1: 7,
|
|
269
|
+
COLUMN2ROW2: 8
|
|
270
|
+
};
|
|
271
|
+
var OrientedBoundingBox = class _OrientedBoundingBox {
|
|
272
|
+
constructor(center = [0, 0, 0], halfAxes = [0, 0, 0, 0, 0, 0, 0, 0, 0]) {
|
|
273
|
+
this.center = new import_core3.Vector3().from(center);
|
|
274
|
+
this.halfAxes = new import_core3.Matrix3(halfAxes);
|
|
275
|
+
}
|
|
276
|
+
/** Returns an array with three halfSizes for the bounding box */
|
|
277
|
+
get halfSize() {
|
|
278
|
+
const xAxis = this.halfAxes.getColumn(0);
|
|
279
|
+
const yAxis = this.halfAxes.getColumn(1);
|
|
280
|
+
const zAxis = this.halfAxes.getColumn(2);
|
|
281
|
+
return [new import_core3.Vector3(xAxis).len(), new import_core3.Vector3(yAxis).len(), new import_core3.Vector3(zAxis).len()];
|
|
282
|
+
}
|
|
283
|
+
/** Returns a quaternion describing the orientation of the bounding box */
|
|
284
|
+
get quaternion() {
|
|
285
|
+
const xAxis = this.halfAxes.getColumn(0);
|
|
286
|
+
const yAxis = this.halfAxes.getColumn(1);
|
|
287
|
+
const zAxis = this.halfAxes.getColumn(2);
|
|
288
|
+
const normXAxis = new import_core3.Vector3(xAxis).normalize();
|
|
289
|
+
const normYAxis = new import_core3.Vector3(yAxis).normalize();
|
|
290
|
+
const normZAxis = new import_core3.Vector3(zAxis).normalize();
|
|
291
|
+
return new import_core3.Quaternion().fromMatrix3(new import_core3.Matrix3([...normXAxis, ...normYAxis, ...normZAxis]));
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Create OrientedBoundingBox from quaternion based OBB,
|
|
295
|
+
*/
|
|
296
|
+
fromCenterHalfSizeQuaternion(center, halfSize, quaternion) {
|
|
297
|
+
const quaternionObject = new import_core3.Quaternion(quaternion);
|
|
298
|
+
const directionsMatrix = new import_core3.Matrix3().fromQuaternion(quaternionObject);
|
|
299
|
+
directionsMatrix[0] = directionsMatrix[0] * halfSize[0];
|
|
300
|
+
directionsMatrix[1] = directionsMatrix[1] * halfSize[0];
|
|
301
|
+
directionsMatrix[2] = directionsMatrix[2] * halfSize[0];
|
|
302
|
+
directionsMatrix[3] = directionsMatrix[3] * halfSize[1];
|
|
303
|
+
directionsMatrix[4] = directionsMatrix[4] * halfSize[1];
|
|
304
|
+
directionsMatrix[5] = directionsMatrix[5] * halfSize[1];
|
|
305
|
+
directionsMatrix[6] = directionsMatrix[6] * halfSize[2];
|
|
306
|
+
directionsMatrix[7] = directionsMatrix[7] * halfSize[2];
|
|
307
|
+
directionsMatrix[8] = directionsMatrix[8] * halfSize[2];
|
|
308
|
+
this.center = new import_core3.Vector3().from(center);
|
|
309
|
+
this.halfAxes = directionsMatrix;
|
|
310
|
+
return this;
|
|
311
|
+
}
|
|
312
|
+
/** Duplicates a OrientedBoundingBox instance. */
|
|
313
|
+
clone() {
|
|
314
|
+
return new _OrientedBoundingBox(this.center, this.halfAxes);
|
|
315
|
+
}
|
|
316
|
+
/** Compares the provided OrientedBoundingBox component wise and returns */
|
|
317
|
+
equals(right) {
|
|
318
|
+
return this === right || Boolean(right) && this.center.equals(right.center) && this.halfAxes.equals(right.halfAxes);
|
|
319
|
+
}
|
|
320
|
+
/** Computes a tight-fitting bounding sphere enclosing the provided oriented bounding box. */
|
|
321
|
+
getBoundingSphere(result = new BoundingSphere()) {
|
|
322
|
+
const halfAxes = this.halfAxes;
|
|
323
|
+
const u = halfAxes.getColumn(0, scratchVectorU);
|
|
324
|
+
const v = halfAxes.getColumn(1, scratchVectorV);
|
|
325
|
+
const w = halfAxes.getColumn(2, scratchVectorW);
|
|
326
|
+
const cornerVector = scratchVector3.copy(u).add(v).add(w);
|
|
327
|
+
result.center.copy(this.center);
|
|
328
|
+
result.radius = cornerVector.magnitude();
|
|
329
|
+
return result;
|
|
330
|
+
}
|
|
331
|
+
/** Determines which side of a plane the oriented bounding box is located. */
|
|
332
|
+
intersectPlane(plane) {
|
|
333
|
+
const center = this.center;
|
|
334
|
+
const normal = plane.normal;
|
|
335
|
+
const halfAxes = this.halfAxes;
|
|
336
|
+
const normalX = normal.x;
|
|
337
|
+
const normalY = normal.y;
|
|
338
|
+
const normalZ = normal.z;
|
|
339
|
+
const radEffective = Math.abs(normalX * halfAxes[MATRIX3.COLUMN0ROW0] + normalY * halfAxes[MATRIX3.COLUMN0ROW1] + normalZ * halfAxes[MATRIX3.COLUMN0ROW2]) + Math.abs(normalX * halfAxes[MATRIX3.COLUMN1ROW0] + normalY * halfAxes[MATRIX3.COLUMN1ROW1] + normalZ * halfAxes[MATRIX3.COLUMN1ROW2]) + Math.abs(normalX * halfAxes[MATRIX3.COLUMN2ROW0] + normalY * halfAxes[MATRIX3.COLUMN2ROW1] + normalZ * halfAxes[MATRIX3.COLUMN2ROW2]);
|
|
340
|
+
const distanceToPlane = normal.dot(center) + plane.distance;
|
|
341
|
+
if (distanceToPlane <= -radEffective) {
|
|
342
|
+
return "outside";
|
|
343
|
+
} else if (distanceToPlane >= radEffective) {
|
|
344
|
+
return "inside";
|
|
345
|
+
}
|
|
346
|
+
return "intersecting";
|
|
347
|
+
}
|
|
348
|
+
/** Computes the estimated distance from the closest point on a bounding box to a point. */
|
|
349
|
+
distanceTo(point) {
|
|
350
|
+
return Math.sqrt(this.distanceSquaredTo(point));
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Computes the estimated distance squared from the closest point
|
|
354
|
+
* on a bounding box to a point.
|
|
355
|
+
* See Geometric Tools for Computer Graphics 10.4.2
|
|
356
|
+
*/
|
|
357
|
+
distanceSquaredTo(point) {
|
|
358
|
+
const offset = scratchOffset.from(point).subtract(this.center);
|
|
359
|
+
const halfAxes = this.halfAxes;
|
|
360
|
+
const u = halfAxes.getColumn(0, scratchVectorU);
|
|
361
|
+
const v = halfAxes.getColumn(1, scratchVectorV);
|
|
362
|
+
const w = halfAxes.getColumn(2, scratchVectorW);
|
|
363
|
+
const uHalf = u.magnitude();
|
|
364
|
+
const vHalf = v.magnitude();
|
|
365
|
+
const wHalf = w.magnitude();
|
|
366
|
+
u.normalize();
|
|
367
|
+
v.normalize();
|
|
368
|
+
w.normalize();
|
|
369
|
+
let distanceSquared = 0;
|
|
370
|
+
let d;
|
|
371
|
+
d = Math.abs(offset.dot(u)) - uHalf;
|
|
372
|
+
if (d > 0) {
|
|
373
|
+
distanceSquared += d * d;
|
|
374
|
+
}
|
|
375
|
+
d = Math.abs(offset.dot(v)) - vHalf;
|
|
376
|
+
if (d > 0) {
|
|
377
|
+
distanceSquared += d * d;
|
|
378
|
+
}
|
|
379
|
+
d = Math.abs(offset.dot(w)) - wHalf;
|
|
380
|
+
if (d > 0) {
|
|
381
|
+
distanceSquared += d * d;
|
|
382
|
+
}
|
|
383
|
+
return distanceSquared;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* The distances calculated by the vector from the center of the bounding box
|
|
387
|
+
* to position projected onto direction.
|
|
388
|
+
*
|
|
389
|
+
* - If you imagine the infinite number of planes with normal direction,
|
|
390
|
+
* this computes the smallest distance to the closest and farthest planes
|
|
391
|
+
* from `position` that intersect the bounding box.
|
|
392
|
+
*
|
|
393
|
+
* @param position The position to calculate the distance from.
|
|
394
|
+
* @param direction The direction from position.
|
|
395
|
+
* @param result An Interval (array of length 2) to store the nearest and farthest distances.
|
|
396
|
+
* @returns Interval (array of length 2) with nearest and farthest distances
|
|
397
|
+
* on the bounding box from position in direction.
|
|
398
|
+
*/
|
|
399
|
+
// eslint-disable-next-line max-statements
|
|
400
|
+
computePlaneDistances(position, direction, result = [-0, -0]) {
|
|
401
|
+
let minDist = Number.POSITIVE_INFINITY;
|
|
402
|
+
let maxDist = Number.NEGATIVE_INFINITY;
|
|
403
|
+
const center = this.center;
|
|
404
|
+
const halfAxes = this.halfAxes;
|
|
405
|
+
const u = halfAxes.getColumn(0, scratchVectorU);
|
|
406
|
+
const v = halfAxes.getColumn(1, scratchVectorV);
|
|
407
|
+
const w = halfAxes.getColumn(2, scratchVectorW);
|
|
408
|
+
const corner = scratchCorner.copy(u).add(v).add(w).add(center);
|
|
409
|
+
const toCenter = scratchToCenter.copy(corner).subtract(position);
|
|
410
|
+
let mag = direction.dot(toCenter);
|
|
411
|
+
minDist = Math.min(mag, minDist);
|
|
412
|
+
maxDist = Math.max(mag, maxDist);
|
|
413
|
+
corner.copy(center).add(u).add(v).subtract(w);
|
|
414
|
+
toCenter.copy(corner).subtract(position);
|
|
415
|
+
mag = direction.dot(toCenter);
|
|
416
|
+
minDist = Math.min(mag, minDist);
|
|
417
|
+
maxDist = Math.max(mag, maxDist);
|
|
418
|
+
corner.copy(center).add(u).subtract(v).add(w);
|
|
419
|
+
toCenter.copy(corner).subtract(position);
|
|
420
|
+
mag = direction.dot(toCenter);
|
|
421
|
+
minDist = Math.min(mag, minDist);
|
|
422
|
+
maxDist = Math.max(mag, maxDist);
|
|
423
|
+
corner.copy(center).add(u).subtract(v).subtract(w);
|
|
424
|
+
toCenter.copy(corner).subtract(position);
|
|
425
|
+
mag = direction.dot(toCenter);
|
|
426
|
+
minDist = Math.min(mag, minDist);
|
|
427
|
+
maxDist = Math.max(mag, maxDist);
|
|
428
|
+
center.copy(corner).subtract(u).add(v).add(w);
|
|
429
|
+
toCenter.copy(corner).subtract(position);
|
|
430
|
+
mag = direction.dot(toCenter);
|
|
431
|
+
minDist = Math.min(mag, minDist);
|
|
432
|
+
maxDist = Math.max(mag, maxDist);
|
|
433
|
+
center.copy(corner).subtract(u).add(v).subtract(w);
|
|
434
|
+
toCenter.copy(corner).subtract(position);
|
|
435
|
+
mag = direction.dot(toCenter);
|
|
436
|
+
minDist = Math.min(mag, minDist);
|
|
437
|
+
maxDist = Math.max(mag, maxDist);
|
|
438
|
+
center.copy(corner).subtract(u).subtract(v).add(w);
|
|
439
|
+
toCenter.copy(corner).subtract(position);
|
|
440
|
+
mag = direction.dot(toCenter);
|
|
441
|
+
minDist = Math.min(mag, minDist);
|
|
442
|
+
maxDist = Math.max(mag, maxDist);
|
|
443
|
+
center.copy(corner).subtract(u).subtract(v).subtract(w);
|
|
444
|
+
toCenter.copy(corner).subtract(position);
|
|
445
|
+
mag = direction.dot(toCenter);
|
|
446
|
+
minDist = Math.min(mag, minDist);
|
|
447
|
+
maxDist = Math.max(mag, maxDist);
|
|
448
|
+
result[0] = minDist;
|
|
449
|
+
result[1] = maxDist;
|
|
450
|
+
return result;
|
|
451
|
+
}
|
|
452
|
+
/**
|
|
453
|
+
* Applies a 4x4 affine transformation matrix to a bounding sphere.
|
|
454
|
+
* @param transform The transformation matrix to apply to the bounding sphere.
|
|
455
|
+
* @returns itself, i.e. the modified BoundingVolume.
|
|
456
|
+
*/
|
|
457
|
+
transform(transformation) {
|
|
458
|
+
this.center.transformAsPoint(transformation);
|
|
459
|
+
const xAxis = this.halfAxes.getColumn(0, scratchVectorU);
|
|
460
|
+
xAxis.transformAsPoint(transformation);
|
|
461
|
+
const yAxis = this.halfAxes.getColumn(1, scratchVectorV);
|
|
462
|
+
yAxis.transformAsPoint(transformation);
|
|
463
|
+
const zAxis = this.halfAxes.getColumn(2, scratchVectorW);
|
|
464
|
+
zAxis.transformAsPoint(transformation);
|
|
465
|
+
this.halfAxes = new import_core3.Matrix3([...xAxis, ...yAxis, ...zAxis]);
|
|
466
|
+
return this;
|
|
467
|
+
}
|
|
468
|
+
getTransform() {
|
|
469
|
+
throw new Error("not implemented");
|
|
470
|
+
}
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
// dist/culling/lib/culling-volume.js
|
|
474
|
+
var import_core5 = require("@math.gl/core");
|
|
475
|
+
|
|
476
|
+
// dist/culling/lib/plane.js
|
|
477
|
+
var import_core4 = require("@math.gl/core");
|
|
478
|
+
var scratchPosition = new import_core4.Vector3();
|
|
479
|
+
var scratchNormal2 = new import_core4.Vector3();
|
|
480
|
+
var Plane = class _Plane {
|
|
481
|
+
constructor(normal = [0, 0, 1], distance = 0) {
|
|
482
|
+
this.normal = new import_core4.Vector3();
|
|
483
|
+
this.distance = -0;
|
|
484
|
+
this.fromNormalDistance(normal, distance);
|
|
485
|
+
}
|
|
486
|
+
/** Creates a plane from a normal and a distance from the origin. */
|
|
487
|
+
fromNormalDistance(normal, distance) {
|
|
488
|
+
(0, import_core4.assert)(Number.isFinite(distance));
|
|
489
|
+
this.normal.from(normal).normalize();
|
|
490
|
+
this.distance = distance;
|
|
491
|
+
return this;
|
|
492
|
+
}
|
|
493
|
+
/** Creates a plane from a normal and a point on the plane. */
|
|
494
|
+
fromPointNormal(point, normal) {
|
|
495
|
+
point = scratchPosition.from(point);
|
|
496
|
+
this.normal.from(normal).normalize();
|
|
497
|
+
const distance = -this.normal.dot(point);
|
|
498
|
+
this.distance = distance;
|
|
499
|
+
return this;
|
|
500
|
+
}
|
|
501
|
+
/** Creates a plane from the general equation */
|
|
502
|
+
fromCoefficients(a, b, c, d) {
|
|
503
|
+
this.normal.set(a, b, c);
|
|
504
|
+
(0, import_core4.assert)((0, import_core4.equals)(this.normal.len(), 1));
|
|
505
|
+
this.distance = d;
|
|
506
|
+
return this;
|
|
507
|
+
}
|
|
508
|
+
/** Duplicates a Plane instance. */
|
|
509
|
+
clone() {
|
|
510
|
+
return new _Plane(this.normal, this.distance);
|
|
511
|
+
}
|
|
512
|
+
/** Compares the provided Planes by normal and distance */
|
|
513
|
+
equals(right) {
|
|
514
|
+
return (0, import_core4.equals)(this.distance, right.distance) && (0, import_core4.equals)(this.normal, right.normal);
|
|
515
|
+
}
|
|
516
|
+
/** Computes the signed shortest distance of a point to a plane.
|
|
517
|
+
* The sign of the distance determines which side of the plane the point is on.
|
|
518
|
+
*/
|
|
519
|
+
getPointDistance(point) {
|
|
520
|
+
return this.normal.dot(point) + this.distance;
|
|
521
|
+
}
|
|
522
|
+
/** Transforms the plane by the given transformation matrix. */
|
|
523
|
+
transform(matrix4) {
|
|
524
|
+
const normal = scratchNormal2.copy(this.normal).transformAsVector(matrix4).normalize();
|
|
525
|
+
const point = this.normal.scale(-this.distance).transform(matrix4);
|
|
526
|
+
return this.fromPointNormal(point, normal);
|
|
527
|
+
}
|
|
528
|
+
projectPointOntoPlane(point, result = [0, 0, 0]) {
|
|
529
|
+
const scratchPoint = scratchPosition.from(point);
|
|
530
|
+
const pointDistance = this.getPointDistance(scratchPoint);
|
|
531
|
+
const scaledNormal = scratchNormal2.copy(this.normal).scale(pointDistance);
|
|
532
|
+
return scratchPoint.subtract(scaledNormal).to(result);
|
|
533
|
+
}
|
|
534
|
+
/**
|
|
535
|
+
* Computes the intersection of a ray and this plane.
|
|
536
|
+
*
|
|
537
|
+
* @param {Ray} ray The ray.
|
|
538
|
+
* @param {Vector3} [result] The object onto which to store the result.
|
|
539
|
+
* @returns {Vector3} The intersection point or undefined if there is no intersection.
|
|
540
|
+
*/
|
|
541
|
+
intersectWithRay(ray, result = new import_core4.Vector3()) {
|
|
542
|
+
const origin = ray.origin;
|
|
543
|
+
const direction = ray.direction;
|
|
544
|
+
const normal = this.normal;
|
|
545
|
+
const denominator = normal.dot(direction);
|
|
546
|
+
if (Math.abs(denominator) < import_core4._MathUtils.EPSILON15) {
|
|
547
|
+
return void 0;
|
|
548
|
+
}
|
|
549
|
+
const t = (-this.distance - normal.dot(origin)) / denominator;
|
|
550
|
+
if (t < 0) {
|
|
551
|
+
return void 0;
|
|
552
|
+
}
|
|
553
|
+
return result.copy(direction).multiplyByScalar(t).add(origin);
|
|
554
|
+
}
|
|
555
|
+
};
|
|
556
|
+
|
|
557
|
+
// dist/culling/lib/culling-volume.js
|
|
558
|
+
var faces = [new import_core5.Vector3([1, 0, 0]), new import_core5.Vector3([0, 1, 0]), new import_core5.Vector3([0, 0, 1])];
|
|
559
|
+
var scratchPlaneCenter = new import_core5.Vector3();
|
|
560
|
+
var scratchPlaneNormal = new import_core5.Vector3();
|
|
561
|
+
var CullingVolume = class _CullingVolume {
|
|
562
|
+
/**
|
|
563
|
+
* Create a new `CullingVolume` bounded by an array of clipping planed
|
|
564
|
+
* @param planes Array of clipping planes.
|
|
565
|
+
* */
|
|
566
|
+
constructor(planes = []) {
|
|
567
|
+
this.planes = planes;
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Constructs a culling volume from a bounding sphere. Creates six planes that create a box containing the sphere.
|
|
571
|
+
* The planes are aligned to the x, y, and z axes in world coordinates.
|
|
572
|
+
*/
|
|
573
|
+
fromBoundingSphere(boundingSphere) {
|
|
574
|
+
this.planes.length = 2 * faces.length;
|
|
575
|
+
const center = boundingSphere.center;
|
|
576
|
+
const radius = boundingSphere.radius;
|
|
577
|
+
let planeIndex = 0;
|
|
578
|
+
for (const faceNormal of faces) {
|
|
579
|
+
let plane0 = this.planes[planeIndex];
|
|
580
|
+
let plane1 = this.planes[planeIndex + 1];
|
|
581
|
+
if (!plane0) {
|
|
582
|
+
plane0 = this.planes[planeIndex] = new Plane();
|
|
583
|
+
}
|
|
584
|
+
if (!plane1) {
|
|
585
|
+
plane1 = this.planes[planeIndex + 1] = new Plane();
|
|
586
|
+
}
|
|
587
|
+
const plane0Center = scratchPlaneCenter.copy(faceNormal).scale(-radius).add(center);
|
|
588
|
+
plane0.fromPointNormal(plane0Center, faceNormal);
|
|
589
|
+
const plane1Center = scratchPlaneCenter.copy(faceNormal).scale(radius).add(center);
|
|
590
|
+
const negatedFaceNormal = scratchPlaneNormal.copy(faceNormal).negate();
|
|
591
|
+
plane1.fromPointNormal(plane1Center, negatedFaceNormal);
|
|
592
|
+
planeIndex += 2;
|
|
593
|
+
}
|
|
594
|
+
return this;
|
|
595
|
+
}
|
|
596
|
+
/** Determines whether a bounding volume intersects the culling volume. */
|
|
597
|
+
computeVisibility(boundingVolume) {
|
|
598
|
+
let intersect = "inside";
|
|
599
|
+
for (const plane of this.planes) {
|
|
600
|
+
const result = boundingVolume.intersectPlane(plane);
|
|
601
|
+
switch (result) {
|
|
602
|
+
case "outside":
|
|
603
|
+
return "outside";
|
|
604
|
+
case "intersecting":
|
|
605
|
+
intersect = "intersecting";
|
|
606
|
+
break;
|
|
607
|
+
default:
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
return intersect;
|
|
611
|
+
}
|
|
612
|
+
/**
|
|
613
|
+
* Determines whether a bounding volume intersects the culling volume.
|
|
614
|
+
*
|
|
615
|
+
* @param parentPlaneMask A bit mask from the boundingVolume's parent's check against the same culling
|
|
616
|
+
* volume, such that if (planeMask & (1 << planeIndex) === 0), for k < 31, then
|
|
617
|
+
* the parent (and therefore this) volume is completely inside plane[planeIndex]
|
|
618
|
+
* and that plane check can be skipped.
|
|
619
|
+
*/
|
|
620
|
+
computeVisibilityWithPlaneMask(boundingVolume, parentPlaneMask) {
|
|
621
|
+
(0, import_core5.assert)(Number.isFinite(parentPlaneMask), "parentPlaneMask is required.");
|
|
622
|
+
if (parentPlaneMask === _CullingVolume.MASK_OUTSIDE || parentPlaneMask === _CullingVolume.MASK_INSIDE) {
|
|
623
|
+
return parentPlaneMask;
|
|
624
|
+
}
|
|
625
|
+
let mask = _CullingVolume.MASK_INSIDE;
|
|
626
|
+
const planes = this.planes;
|
|
627
|
+
for (let k = 0; k < this.planes.length; ++k) {
|
|
628
|
+
const flag = k < 31 ? 1 << k : 0;
|
|
629
|
+
if (k < 31 && (parentPlaneMask & flag) === 0) {
|
|
630
|
+
continue;
|
|
631
|
+
}
|
|
632
|
+
const plane = planes[k];
|
|
633
|
+
const result = boundingVolume.intersectPlane(plane);
|
|
634
|
+
if (result === "outside") {
|
|
635
|
+
return _CullingVolume.MASK_OUTSIDE;
|
|
636
|
+
} else if (result === "intersecting") {
|
|
637
|
+
mask |= flag;
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
return mask;
|
|
641
|
+
}
|
|
642
|
+
};
|
|
643
|
+
CullingVolume.MASK_OUTSIDE = 4294967295;
|
|
644
|
+
CullingVolume.MASK_INSIDE = 0;
|
|
645
|
+
CullingVolume.MASK_INDETERMINATE = 2147483647;
|
|
646
|
+
|
|
647
|
+
// dist/culling/lib/ray.js
|
|
648
|
+
var import_core6 = require("@math.gl/core");
|
|
649
|
+
var Ray = class {
|
|
650
|
+
/**
|
|
651
|
+
* Creates a new ray that extends infinitely from the provided origin in the provided direction.
|
|
652
|
+
*
|
|
653
|
+
* @param [origin=Vector3] The origin of the ray.
|
|
654
|
+
* @param [direction=Vector3] The direction of the ray.
|
|
655
|
+
*/
|
|
656
|
+
constructor(origin, direction) {
|
|
657
|
+
if (origin)
|
|
658
|
+
origin = origin.clone();
|
|
659
|
+
else
|
|
660
|
+
origin = new import_core6.Vector3();
|
|
661
|
+
if (direction)
|
|
662
|
+
direction = direction.clone().normalize();
|
|
663
|
+
else
|
|
664
|
+
direction = new import_core6.Vector3();
|
|
665
|
+
this.origin = origin;
|
|
666
|
+
this.direction = direction;
|
|
667
|
+
}
|
|
668
|
+
};
|
|
669
|
+
|
|
670
|
+
// dist/culling/lib/shapes/implicit-shape.js
|
|
671
|
+
var import_core7 = require("@math.gl/core");
|
|
672
|
+
var ImplicitShapeBase = class {
|
|
673
|
+
constructor(matrix) {
|
|
674
|
+
this.matrix = new import_core7.Matrix4();
|
|
675
|
+
if (matrix)
|
|
676
|
+
this.matrix.copy(matrix);
|
|
677
|
+
validateAffineMatrix(this.matrix);
|
|
678
|
+
this.inverseMatrix = this.matrix.clone().invert();
|
|
679
|
+
}
|
|
680
|
+
equals(shape) {
|
|
681
|
+
if (this.type !== shape.type)
|
|
682
|
+
return false;
|
|
683
|
+
for (let i = 0; i < 16; i++)
|
|
684
|
+
if (this.matrix[i] !== shape.matrix[i])
|
|
685
|
+
return false;
|
|
686
|
+
return true;
|
|
687
|
+
}
|
|
688
|
+
transform(transform) {
|
|
689
|
+
const next = new import_core7.Matrix4().copy(transform);
|
|
690
|
+
validateAffineMatrix(next);
|
|
691
|
+
this.matrix.multiplyLeft(next);
|
|
692
|
+
validateAffineMatrix(this.matrix);
|
|
693
|
+
this.inverseMatrix.copy(this.matrix).invert();
|
|
694
|
+
return this;
|
|
695
|
+
}
|
|
696
|
+
containsPoint(point) {
|
|
697
|
+
return this.containsLocalPoint(this.inverseMatrix.transformAsPoint(point));
|
|
698
|
+
}
|
|
699
|
+
distanceSquaredTo(point) {
|
|
700
|
+
const distance = this.distanceTo(point);
|
|
701
|
+
return distance * distance;
|
|
702
|
+
}
|
|
703
|
+
/** Exact for rigid/uniform transforms; conservative estimate for non-uniform scale or shear. */
|
|
704
|
+
distanceTo(point) {
|
|
705
|
+
const localPoint = this.inverseMatrix.transformAsPoint(point);
|
|
706
|
+
const localDistance = this.distanceToLocalPoint(localPoint);
|
|
707
|
+
const scales = this.matrix.getScale();
|
|
708
|
+
return localDistance * Math.min(scales[0], scales[1], scales[2]);
|
|
709
|
+
}
|
|
710
|
+
intersectPlane(plane) {
|
|
711
|
+
const maximum = this.getSupportPoint(plane.normal);
|
|
712
|
+
const minimum = this.getSupportPoint([-plane.normal[0], -plane.normal[1], -plane.normal[2]]);
|
|
713
|
+
const maxDistance = plane.getPointDistance(maximum);
|
|
714
|
+
const minDistance = plane.getPointDistance(minimum);
|
|
715
|
+
if (minDistance > 0)
|
|
716
|
+
return "inside";
|
|
717
|
+
if (maxDistance < 0)
|
|
718
|
+
return "outside";
|
|
719
|
+
return "intersecting";
|
|
720
|
+
}
|
|
721
|
+
intersectRay(ray) {
|
|
722
|
+
const localOrigin = this.inverseMatrix.transformAsPoint(ray.origin);
|
|
723
|
+
const localDirection = this.inverseMatrix.transformAsVector(ray.direction);
|
|
724
|
+
const hit = this.intersectLocalRay(localOrigin, localDirection);
|
|
725
|
+
if (!hit || hit.distance < 0)
|
|
726
|
+
return void 0;
|
|
727
|
+
const point = new import_core7.Vector3(ray.direction).scale(hit.distance).add(ray.origin);
|
|
728
|
+
const inverse = this.inverseMatrix;
|
|
729
|
+
const normal = new import_core7.Vector3(inverse[0] * hit.normal[0] + inverse[1] * hit.normal[1] + inverse[2] * hit.normal[2], inverse[4] * hit.normal[0] + inverse[5] * hit.normal[1] + inverse[6] * hit.normal[2], inverse[8] * hit.normal[0] + inverse[9] * hit.normal[1] + inverse[10] * hit.normal[2]).normalize();
|
|
730
|
+
return { distance: hit.distance, point, normal, entering: ray.direction.dot(normal) < 0 };
|
|
731
|
+
}
|
|
732
|
+
getAxisAlignedBoundingBox() {
|
|
733
|
+
const minimum = new import_core7.Vector3();
|
|
734
|
+
const maximum = new import_core7.Vector3();
|
|
735
|
+
for (let axis = 0; axis < 3; axis++) {
|
|
736
|
+
const direction = [0, 0, 0];
|
|
737
|
+
direction[axis] = 1;
|
|
738
|
+
maximum[axis] = this.getSupportPoint(direction)[axis];
|
|
739
|
+
direction[axis] = -1;
|
|
740
|
+
minimum[axis] = this.getSupportPoint(direction)[axis];
|
|
741
|
+
}
|
|
742
|
+
return new AxisAlignedBoundingBox(minimum, maximum);
|
|
743
|
+
}
|
|
744
|
+
getBoundingSphere() {
|
|
745
|
+
const box = this.getAxisAlignedBoundingBox();
|
|
746
|
+
if (!box)
|
|
747
|
+
return void 0;
|
|
748
|
+
return new BoundingSphere().fromCornerPoints(box.minimum, box.maximum);
|
|
749
|
+
}
|
|
750
|
+
getSupportPoint(worldDirection) {
|
|
751
|
+
const matrix = this.matrix;
|
|
752
|
+
const localDirection = [
|
|
753
|
+
matrix[0] * worldDirection[0] + matrix[1] * worldDirection[1] + matrix[2] * worldDirection[2],
|
|
754
|
+
matrix[4] * worldDirection[0] + matrix[5] * worldDirection[1] + matrix[6] * worldDirection[2],
|
|
755
|
+
matrix[8] * worldDirection[0] + matrix[9] * worldDirection[1] + matrix[10] * worldDirection[2]
|
|
756
|
+
];
|
|
757
|
+
return new import_core7.Vector3(this.supportLocal(localDirection)).transform(this.matrix);
|
|
758
|
+
}
|
|
759
|
+
};
|
|
760
|
+
function validateAffineMatrix(matrix) {
|
|
761
|
+
if (matrix.length !== 16 || matrix.some((value) => !Number.isFinite(value))) {
|
|
762
|
+
throw new Error("Shape matrix must contain 16 finite values");
|
|
763
|
+
}
|
|
764
|
+
if (Math.abs(matrix[3]) > 1e-12 || Math.abs(matrix[7]) > 1e-12 || Math.abs(matrix[11]) > 1e-12 || Math.abs(matrix[15] - 1) > 1e-12) {
|
|
765
|
+
throw new Error("Shape matrix must be affine");
|
|
766
|
+
}
|
|
767
|
+
if (Math.abs(new import_core7.Matrix4().copy(matrix).determinant()) < 1e-15)
|
|
768
|
+
throw new Error("Shape matrix must be invertible");
|
|
769
|
+
}
|
|
770
|
+
function solveQuadratic(a, b, c) {
|
|
771
|
+
if (Math.abs(a) < 1e-15)
|
|
772
|
+
return Math.abs(b) < 1e-15 ? [] : [-c / b];
|
|
773
|
+
const discriminant = b * b - 4 * a * c;
|
|
774
|
+
if (discriminant < 0)
|
|
775
|
+
return [];
|
|
776
|
+
const root = Math.sqrt(Math.max(0, discriminant));
|
|
777
|
+
return [(-b - root) / (2 * a), (-b + root) / (2 * a)].sort((left, right) => left - right);
|
|
778
|
+
}
|
|
779
|
+
function closestDistanceToSegment2D(px, py, ax, ay, bx, by) {
|
|
780
|
+
const dx = bx - ax;
|
|
781
|
+
const dy = by - ay;
|
|
782
|
+
const denominator = dx * dx + dy * dy;
|
|
783
|
+
const t = denominator ? Math.max(0, Math.min(1, ((px - ax) * dx + (py - ay) * dy) / denominator)) : 0;
|
|
784
|
+
return Math.hypot(px - (ax + t * dx), py - (ay + t * dy));
|
|
785
|
+
}
|
|
786
|
+
function closestDistanceToCircleArc2D(px, py, centerY, radius, minimumNormalY, maximumNormalY) {
|
|
787
|
+
if (radius === 0)
|
|
788
|
+
return Math.hypot(px, py - centerY);
|
|
789
|
+
const dx = px;
|
|
790
|
+
const dy = py - centerY;
|
|
791
|
+
const length = Math.hypot(dx, dy);
|
|
792
|
+
const normalY = length ? dy / length : 0;
|
|
793
|
+
if (normalY >= minimumNormalY && normalY <= maximumNormalY) {
|
|
794
|
+
return Math.abs(length - radius);
|
|
795
|
+
}
|
|
796
|
+
const minimumRadius = radius * Math.sqrt(Math.max(0, 1 - minimumNormalY ** 2));
|
|
797
|
+
const maximumRadius = radius * Math.sqrt(Math.max(0, 1 - maximumNormalY ** 2));
|
|
798
|
+
return Math.min(Math.hypot(px - minimumRadius, py - (centerY + radius * minimumNormalY)), Math.hypot(px - maximumRadius, py - (centerY + radius * maximumNormalY)));
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
// dist/culling/lib/shapes/box-shape.js
|
|
802
|
+
var EPSILON = 1e-6;
|
|
803
|
+
var BoxShape = class _BoxShape extends ImplicitShapeBase {
|
|
804
|
+
constructor(props = {}) {
|
|
805
|
+
super(props.matrix);
|
|
806
|
+
this.type = "box";
|
|
807
|
+
this.size = props.size ? [...props.size] : [1, 1, 1];
|
|
808
|
+
if (this.size.some((value) => !Number.isFinite(value) || value <= 0))
|
|
809
|
+
throw new Error("Box size values must be greater than zero");
|
|
810
|
+
this.halfSize = [this.size[0] / 2, this.size[1] / 2, this.size[2] / 2];
|
|
811
|
+
}
|
|
812
|
+
clone() {
|
|
813
|
+
return new _BoxShape({ size: this.size, matrix: this.matrix });
|
|
814
|
+
}
|
|
815
|
+
equals(shape) {
|
|
816
|
+
return shape instanceof _BoxShape && super.equals(shape) && this.size.every((value, i) => value === shape.size[i]);
|
|
817
|
+
}
|
|
818
|
+
containsLocalPoint(point) {
|
|
819
|
+
return point.every((value, i) => Math.abs(value) <= this.halfSize[i] + EPSILON);
|
|
820
|
+
}
|
|
821
|
+
distanceToLocalPoint(point) {
|
|
822
|
+
return Math.hypot(...point.map((value, i) => Math.max(0, Math.abs(value) - this.halfSize[i])));
|
|
823
|
+
}
|
|
824
|
+
supportLocal(direction) {
|
|
825
|
+
return direction.map((value, i) => value < 0 ? -this.halfSize[i] : this.halfSize[i]);
|
|
826
|
+
}
|
|
827
|
+
intersectLocalRay(origin, direction) {
|
|
828
|
+
let near = -Infinity;
|
|
829
|
+
let far = Infinity;
|
|
830
|
+
let nearAxis = 0;
|
|
831
|
+
let farAxis = 0;
|
|
832
|
+
for (let axis2 = 0; axis2 < 3; axis2++) {
|
|
833
|
+
if (Math.abs(direction[axis2]) < 1e-15) {
|
|
834
|
+
if (Math.abs(origin[axis2]) > this.halfSize[axis2])
|
|
835
|
+
return void 0;
|
|
836
|
+
continue;
|
|
837
|
+
}
|
|
838
|
+
let t1 = (-this.halfSize[axis2] - origin[axis2]) / direction[axis2];
|
|
839
|
+
let t2 = (this.halfSize[axis2] - origin[axis2]) / direction[axis2];
|
|
840
|
+
if (t1 > t2)
|
|
841
|
+
[t1, t2] = [t2, t1];
|
|
842
|
+
if (t1 > near) {
|
|
843
|
+
near = t1;
|
|
844
|
+
nearAxis = axis2;
|
|
845
|
+
}
|
|
846
|
+
if (t2 < far) {
|
|
847
|
+
far = t2;
|
|
848
|
+
farAxis = axis2;
|
|
849
|
+
}
|
|
850
|
+
if (near > far)
|
|
851
|
+
return void 0;
|
|
852
|
+
}
|
|
853
|
+
const distance = near >= 0 ? near : far;
|
|
854
|
+
if (distance < 0 || !Number.isFinite(distance))
|
|
855
|
+
return void 0;
|
|
856
|
+
const axis = near >= 0 ? nearAxis : farAxis;
|
|
857
|
+
const pointCoordinate = origin[axis] + distance * direction[axis];
|
|
858
|
+
const normal = [0, 0, 0];
|
|
859
|
+
normal[axis] = pointCoordinate < 0 ? -1 : 1;
|
|
860
|
+
return { distance, normal };
|
|
861
|
+
}
|
|
862
|
+
};
|
|
863
|
+
|
|
864
|
+
// dist/culling/lib/shapes/capsule-shape.js
|
|
865
|
+
var EPSILON2 = 1e-6;
|
|
866
|
+
var CapsuleShape = class _CapsuleShape extends ImplicitShapeBase {
|
|
867
|
+
constructor(props = {}) {
|
|
868
|
+
super(props.matrix);
|
|
869
|
+
this.type = "capsule";
|
|
870
|
+
this.height = props.height ?? 1;
|
|
871
|
+
this.radiusBottom = props.radiusBottom ?? 0.5;
|
|
872
|
+
this.radiusTop = props.radiusTop ?? 0.5;
|
|
873
|
+
if (!Number.isFinite(this.height) || this.height <= 0)
|
|
874
|
+
throw new Error("Capsule height must be greater than zero");
|
|
875
|
+
if (![this.radiusBottom, this.radiusTop].every((value) => Number.isFinite(value) && value >= 0))
|
|
876
|
+
throw new Error("Capsule radii must be non-negative");
|
|
877
|
+
if (this.radiusBottom === 0 && this.radiusTop === 0)
|
|
878
|
+
throw new Error("At least one capsule radius must be greater than zero");
|
|
879
|
+
}
|
|
880
|
+
clone() {
|
|
881
|
+
return new _CapsuleShape({
|
|
882
|
+
height: this.height,
|
|
883
|
+
radiusBottom: this.radiusBottom,
|
|
884
|
+
radiusTop: this.radiusTop,
|
|
885
|
+
matrix: this.matrix
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
equals(shape) {
|
|
889
|
+
return shape instanceof _CapsuleShape && super.equals(shape) && this.height === shape.height && this.radiusBottom === shape.radiusBottom && this.radiusTop === shape.radiusTop;
|
|
890
|
+
}
|
|
891
|
+
containsLocalPoint(point) {
|
|
892
|
+
const profile = this.getProfile();
|
|
893
|
+
const radial = Math.hypot(point[0], point[2]);
|
|
894
|
+
if (profile.sphere)
|
|
895
|
+
return Math.hypot(radial, point[1] - profile.sphere.center) <= profile.sphere.radius + EPSILON2;
|
|
896
|
+
if (point[1] < profile.bottom.y)
|
|
897
|
+
return Math.hypot(radial, point[1] + this.height / 2) <= this.radiusBottom + EPSILON2;
|
|
898
|
+
if (point[1] > profile.top.y)
|
|
899
|
+
return Math.hypot(radial, point[1] - this.height / 2) <= this.radiusTop + EPSILON2;
|
|
900
|
+
const t = (point[1] - profile.bottom.y) / (profile.top.y - profile.bottom.y);
|
|
901
|
+
return radial <= profile.bottom.radius + (profile.top.radius - profile.bottom.radius) * t + EPSILON2;
|
|
902
|
+
}
|
|
903
|
+
distanceToLocalPoint(point) {
|
|
904
|
+
if (this.containsLocalPoint(point))
|
|
905
|
+
return 0;
|
|
906
|
+
const profile = this.getProfile();
|
|
907
|
+
const radial = Math.hypot(point[0], point[2]);
|
|
908
|
+
if (profile.sphere)
|
|
909
|
+
return Math.max(0, Math.hypot(radial, point[1] - profile.sphere.center) - profile.sphere.radius);
|
|
910
|
+
const delta = this.radiusTop - this.radiusBottom;
|
|
911
|
+
const sideNormalY = -delta / this.height;
|
|
912
|
+
const bottomArc = closestDistanceToCircleArc2D(radial, point[1], -this.height / 2, this.radiusBottom, -1, sideNormalY);
|
|
913
|
+
const topArc = closestDistanceToCircleArc2D(radial, point[1], this.height / 2, this.radiusTop, sideNormalY, 1);
|
|
914
|
+
const side = closestDistanceToSegment2D(radial, point[1], profile.bottom.radius, profile.bottom.y, profile.top.radius, profile.top.y);
|
|
915
|
+
return Math.min(bottomArc, topArc, side);
|
|
916
|
+
}
|
|
917
|
+
supportLocal(direction) {
|
|
918
|
+
const length = Math.hypot(...direction);
|
|
919
|
+
const unit = length ? direction.map((value) => value / length) : [1, 0, 0];
|
|
920
|
+
const bottom = [
|
|
921
|
+
unit[0] * this.radiusBottom,
|
|
922
|
+
-this.height / 2 + unit[1] * this.radiusBottom,
|
|
923
|
+
unit[2] * this.radiusBottom
|
|
924
|
+
];
|
|
925
|
+
const top = [
|
|
926
|
+
unit[0] * this.radiusTop,
|
|
927
|
+
this.height / 2 + unit[1] * this.radiusTop,
|
|
928
|
+
unit[2] * this.radiusTop
|
|
929
|
+
];
|
|
930
|
+
return dot(top, direction) >= dot(bottom, direction) ? top : bottom;
|
|
931
|
+
}
|
|
932
|
+
intersectLocalRay(origin, direction) {
|
|
933
|
+
const profile = this.getProfile();
|
|
934
|
+
if (profile.sphere)
|
|
935
|
+
return intersectSphere(origin, direction, profile.sphere.center, profile.sphere.radius);
|
|
936
|
+
const candidates = [];
|
|
937
|
+
const slope = (profile.top.radius - profile.bottom.radius) / (profile.top.y - profile.bottom.y);
|
|
938
|
+
const intercept = profile.bottom.radius - slope * profile.bottom.y;
|
|
939
|
+
const radialAtOrigin = intercept + slope * origin[1];
|
|
940
|
+
const radialAlongRay = slope * direction[1];
|
|
941
|
+
for (const distance of solveQuadratic(direction[0] ** 2 + direction[2] ** 2 - radialAlongRay ** 2, 2 * (origin[0] * direction[0] + origin[2] * direction[2] - radialAtOrigin * radialAlongRay), origin[0] ** 2 + origin[2] ** 2 - radialAtOrigin ** 2)) {
|
|
942
|
+
const y = origin[1] + distance * direction[1];
|
|
943
|
+
if (distance >= 0 && y >= profile.bottom.y - EPSILON2 && y <= profile.top.y + EPSILON2) {
|
|
944
|
+
const x = origin[0] + distance * direction[0];
|
|
945
|
+
const z = origin[2] + distance * direction[2];
|
|
946
|
+
const radial = Math.hypot(x, z) || 1;
|
|
947
|
+
const normal = [x / radial, -slope, z / radial];
|
|
948
|
+
const length = Math.hypot(...normal);
|
|
949
|
+
candidates.push({ distance, normal: normal.map((value) => value / length) });
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
for (const bottomHit of intersectSphereRoots(origin, direction, -this.height / 2, this.radiusBottom)) {
|
|
953
|
+
const y = origin[1] + bottomHit.distance * direction[1];
|
|
954
|
+
if (y <= profile.bottom.y + EPSILON2)
|
|
955
|
+
candidates.push(bottomHit);
|
|
956
|
+
}
|
|
957
|
+
for (const topHit of intersectSphereRoots(origin, direction, this.height / 2, this.radiusTop)) {
|
|
958
|
+
const y = origin[1] + topHit.distance * direction[1];
|
|
959
|
+
if (y >= profile.top.y - EPSILON2)
|
|
960
|
+
candidates.push(topHit);
|
|
961
|
+
}
|
|
962
|
+
return candidates.sort((a, b) => a.distance - b.distance)[0];
|
|
963
|
+
}
|
|
964
|
+
getProfile() {
|
|
965
|
+
const delta = this.radiusTop - this.radiusBottom;
|
|
966
|
+
if (Math.abs(delta) >= this.height) {
|
|
967
|
+
const topWins = this.radiusTop >= this.radiusBottom;
|
|
968
|
+
return {
|
|
969
|
+
sphere: {
|
|
970
|
+
center: topWins ? this.height / 2 : -this.height / 2,
|
|
971
|
+
radius: topWins ? this.radiusTop : this.radiusBottom
|
|
972
|
+
},
|
|
973
|
+
bottom: { radius: 0, y: 0 },
|
|
974
|
+
top: { radius: 0, y: 0 }
|
|
975
|
+
};
|
|
976
|
+
}
|
|
977
|
+
const sinSlope = delta / this.height;
|
|
978
|
+
const radialNormal = Math.sqrt(1 - sinSlope * sinSlope);
|
|
979
|
+
const normalY = -sinSlope;
|
|
980
|
+
return {
|
|
981
|
+
bottom: {
|
|
982
|
+
radius: this.radiusBottom * radialNormal,
|
|
983
|
+
y: -this.height / 2 + this.radiusBottom * normalY
|
|
984
|
+
},
|
|
985
|
+
top: { radius: this.radiusTop * radialNormal, y: this.height / 2 + this.radiusTop * normalY }
|
|
986
|
+
};
|
|
987
|
+
}
|
|
988
|
+
};
|
|
989
|
+
function intersectSphere(origin, direction, centerY, radius) {
|
|
990
|
+
return intersectSphereRoots(origin, direction, centerY, radius)[0];
|
|
991
|
+
}
|
|
992
|
+
function intersectSphereRoots(origin, direction, centerY, radius) {
|
|
993
|
+
if (radius === 0)
|
|
994
|
+
return [];
|
|
995
|
+
const relative = [origin[0], origin[1] - centerY, origin[2]];
|
|
996
|
+
return solveQuadratic(dot(direction, direction), 2 * dot(relative, direction), dot(relative, relative) - radius * radius).filter((distance) => distance >= 0).map((distance) => ({
|
|
997
|
+
distance,
|
|
998
|
+
normal: relative.map((value, i) => (value + distance * direction[i]) / radius)
|
|
999
|
+
}));
|
|
1000
|
+
}
|
|
1001
|
+
function dot(a, b) {
|
|
1002
|
+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
// dist/culling/lib/shapes/cylinder-shape.js
|
|
1006
|
+
var EPSILON3 = 1e-6;
|
|
1007
|
+
var CylinderShape = class _CylinderShape extends ImplicitShapeBase {
|
|
1008
|
+
constructor(props = {}) {
|
|
1009
|
+
super(props.matrix);
|
|
1010
|
+
this.type = "cylinder";
|
|
1011
|
+
this.height = props.height ?? 2;
|
|
1012
|
+
this.radiusBottom = props.radiusBottom ?? 0.5;
|
|
1013
|
+
this.radiusTop = props.radiusTop ?? 0.5;
|
|
1014
|
+
if (!Number.isFinite(this.height) || this.height <= 0)
|
|
1015
|
+
throw new Error("Cylinder height must be greater than zero");
|
|
1016
|
+
if (![this.radiusBottom, this.radiusTop].every((value) => Number.isFinite(value) && value >= 0))
|
|
1017
|
+
throw new Error("Cylinder radii must be non-negative");
|
|
1018
|
+
if (this.radiusBottom === 0 && this.radiusTop === 0)
|
|
1019
|
+
throw new Error("At least one cylinder radius must be greater than zero");
|
|
1020
|
+
}
|
|
1021
|
+
clone() {
|
|
1022
|
+
return new _CylinderShape({
|
|
1023
|
+
height: this.height,
|
|
1024
|
+
radiusBottom: this.radiusBottom,
|
|
1025
|
+
radiusTop: this.radiusTop,
|
|
1026
|
+
matrix: this.matrix
|
|
1027
|
+
});
|
|
1028
|
+
}
|
|
1029
|
+
equals(shape) {
|
|
1030
|
+
return shape instanceof _CylinderShape && super.equals(shape) && this.height === shape.height && this.radiusBottom === shape.radiusBottom && this.radiusTop === shape.radiusTop;
|
|
1031
|
+
}
|
|
1032
|
+
containsLocalPoint(point) {
|
|
1033
|
+
const half = this.height / 2;
|
|
1034
|
+
if (point[1] < -half - EPSILON3 || point[1] > half + EPSILON3)
|
|
1035
|
+
return false;
|
|
1036
|
+
const t = (point[1] + half) / this.height;
|
|
1037
|
+
const radius = this.radiusBottom + (this.radiusTop - this.radiusBottom) * t;
|
|
1038
|
+
return Math.hypot(point[0], point[2]) <= radius + EPSILON3;
|
|
1039
|
+
}
|
|
1040
|
+
distanceToLocalPoint(point) {
|
|
1041
|
+
if (this.containsLocalPoint(point))
|
|
1042
|
+
return 0;
|
|
1043
|
+
const radial = Math.hypot(point[0], point[2]);
|
|
1044
|
+
const half = this.height / 2;
|
|
1045
|
+
const side = closestDistanceToSegment2D(radial, point[1], this.radiusBottom, -half, this.radiusTop, half);
|
|
1046
|
+
const bottom = closestDistanceToSegment2D(radial, point[1], 0, -half, this.radiusBottom, -half);
|
|
1047
|
+
const top = closestDistanceToSegment2D(radial, point[1], 0, half, this.radiusTop, half);
|
|
1048
|
+
return Math.min(side, bottom, top);
|
|
1049
|
+
}
|
|
1050
|
+
supportLocal(direction) {
|
|
1051
|
+
const radialLength = Math.hypot(direction[0], direction[2]);
|
|
1052
|
+
const x = radialLength ? direction[0] / radialLength : 1;
|
|
1053
|
+
const z = radialLength ? direction[2] / radialLength : 0;
|
|
1054
|
+
const half = this.height / 2;
|
|
1055
|
+
const bottomValue = radialLength * this.radiusBottom - direction[1] * half;
|
|
1056
|
+
const topValue = radialLength * this.radiusTop + direction[1] * half;
|
|
1057
|
+
return topValue >= bottomValue ? [x * this.radiusTop, half, z * this.radiusTop] : [x * this.radiusBottom, -half, z * this.radiusBottom];
|
|
1058
|
+
}
|
|
1059
|
+
intersectLocalRay(origin, direction) {
|
|
1060
|
+
const half = this.height / 2;
|
|
1061
|
+
const slope = (this.radiusTop - this.radiusBottom) / this.height;
|
|
1062
|
+
const intercept = (this.radiusTop + this.radiusBottom) / 2;
|
|
1063
|
+
const radialAtOrigin = intercept + slope * origin[1];
|
|
1064
|
+
const radialAlongRay = slope * direction[1];
|
|
1065
|
+
const candidates = [];
|
|
1066
|
+
const roots = solveQuadratic(direction[0] ** 2 + direction[2] ** 2 - radialAlongRay ** 2, 2 * (origin[0] * direction[0] + origin[2] * direction[2] - radialAtOrigin * radialAlongRay), origin[0] ** 2 + origin[2] ** 2 - radialAtOrigin ** 2);
|
|
1067
|
+
for (const distance of roots) {
|
|
1068
|
+
const y = origin[1] + distance * direction[1];
|
|
1069
|
+
if (distance >= 0 && y >= -half - EPSILON3 && y <= half + EPSILON3) {
|
|
1070
|
+
const x = origin[0] + distance * direction[0];
|
|
1071
|
+
const z = origin[2] + distance * direction[2];
|
|
1072
|
+
const radial = Math.hypot(x, z) || 1;
|
|
1073
|
+
const normal = [x / radial, -slope, z / radial];
|
|
1074
|
+
const length = Math.hypot(...normal);
|
|
1075
|
+
candidates.push({ distance, normal: normal.map((value) => value / length) });
|
|
1076
|
+
}
|
|
1077
|
+
}
|
|
1078
|
+
if (Math.abs(direction[1]) > 1e-15) {
|
|
1079
|
+
for (const [y, radius, normalY] of [
|
|
1080
|
+
[-half, this.radiusBottom, -1],
|
|
1081
|
+
[half, this.radiusTop, 1]
|
|
1082
|
+
]) {
|
|
1083
|
+
const distance = (y - origin[1]) / direction[1];
|
|
1084
|
+
const x = origin[0] + distance * direction[0];
|
|
1085
|
+
const z = origin[2] + distance * direction[2];
|
|
1086
|
+
if (distance >= 0 && Math.hypot(x, z) <= radius + EPSILON3)
|
|
1087
|
+
candidates.push({ distance, normal: [0, normalY, 0] });
|
|
1088
|
+
}
|
|
1089
|
+
}
|
|
1090
|
+
return candidates.sort((a, b) => a.distance - b.distance)[0];
|
|
1091
|
+
}
|
|
1092
|
+
};
|
|
1093
|
+
|
|
1094
|
+
// dist/culling/lib/shapes/plane-shape.js
|
|
1095
|
+
var import_core8 = require("@math.gl/core");
|
|
1096
|
+
var PlaneShape = class _PlaneShape extends ImplicitShapeBase {
|
|
1097
|
+
constructor(props = {}) {
|
|
1098
|
+
super(props.matrix);
|
|
1099
|
+
this.type = "plane";
|
|
1100
|
+
this.sizeX = props.sizeX;
|
|
1101
|
+
this.sizeZ = props.sizeZ;
|
|
1102
|
+
if (this.sizeX !== void 0 && (!Number.isFinite(this.sizeX) || this.sizeX <= 0))
|
|
1103
|
+
throw new Error("Plane sizeX must be greater than zero");
|
|
1104
|
+
if (this.sizeZ !== void 0 && (!Number.isFinite(this.sizeZ) || this.sizeZ <= 0))
|
|
1105
|
+
throw new Error("Plane sizeZ must be greater than zero");
|
|
1106
|
+
}
|
|
1107
|
+
clone() {
|
|
1108
|
+
return new _PlaneShape({ sizeX: this.sizeX, sizeZ: this.sizeZ, matrix: this.matrix });
|
|
1109
|
+
}
|
|
1110
|
+
equals(shape) {
|
|
1111
|
+
return shape instanceof _PlaneShape && super.equals(shape) && this.sizeX === shape.sizeX && this.sizeZ === shape.sizeZ;
|
|
1112
|
+
}
|
|
1113
|
+
containsLocalPoint(point) {
|
|
1114
|
+
return point[1] <= 1e-12;
|
|
1115
|
+
}
|
|
1116
|
+
distanceToLocalPoint(point) {
|
|
1117
|
+
return Math.max(0, point[1]);
|
|
1118
|
+
}
|
|
1119
|
+
supportLocal() {
|
|
1120
|
+
throw new Error("An unbounded plane half-space has no finite support point");
|
|
1121
|
+
}
|
|
1122
|
+
intersectLocalRay(origin, direction) {
|
|
1123
|
+
if (Math.abs(direction[1]) < 1e-15)
|
|
1124
|
+
return void 0;
|
|
1125
|
+
const distance = -origin[1] / direction[1];
|
|
1126
|
+
if (distance < 0)
|
|
1127
|
+
return void 0;
|
|
1128
|
+
const x = origin[0] + distance * direction[0];
|
|
1129
|
+
const z = origin[2] + distance * direction[2];
|
|
1130
|
+
if (this.sizeX !== void 0 && Math.abs(x) > this.sizeX / 2 + 1e-12)
|
|
1131
|
+
return void 0;
|
|
1132
|
+
if (this.sizeZ !== void 0 && Math.abs(z) > this.sizeZ / 2 + 1e-12)
|
|
1133
|
+
return void 0;
|
|
1134
|
+
return { distance, normal: [0, 1, 0] };
|
|
1135
|
+
}
|
|
1136
|
+
intersectPlane(plane) {
|
|
1137
|
+
const boundaryPoint = new import_core8.Vector3(0, 0, 0).transform(this.matrix);
|
|
1138
|
+
const inverse = this.inverseMatrix;
|
|
1139
|
+
const boundaryNormal = new import_core8.Vector3(inverse[1], inverse[5], inverse[9]).normalize();
|
|
1140
|
+
const alignment = boundaryNormal.dot(plane.normal);
|
|
1141
|
+
if (Math.abs(Math.abs(alignment) - 1) > 1e-10)
|
|
1142
|
+
return "intersecting";
|
|
1143
|
+
const boundaryDistance = plane.getPointDistance(boundaryPoint);
|
|
1144
|
+
if (alignment < 0 && boundaryDistance > 0)
|
|
1145
|
+
return "inside";
|
|
1146
|
+
if (alignment > 0 && boundaryDistance < 0)
|
|
1147
|
+
return "outside";
|
|
1148
|
+
return "intersecting";
|
|
1149
|
+
}
|
|
1150
|
+
getAxisAlignedBoundingBox() {
|
|
1151
|
+
return void 0;
|
|
1152
|
+
}
|
|
1153
|
+
getBoundingSphere() {
|
|
1154
|
+
return void 0;
|
|
1155
|
+
}
|
|
1156
|
+
};
|
|
1157
|
+
|
|
1158
|
+
// dist/culling/lib/shapes/sphere-shape.js
|
|
1159
|
+
var EPSILON4 = 1e-6;
|
|
1160
|
+
var SphereShape = class _SphereShape extends ImplicitShapeBase {
|
|
1161
|
+
constructor(props = {}) {
|
|
1162
|
+
super(props.matrix);
|
|
1163
|
+
this.type = "sphere";
|
|
1164
|
+
this.radius = props.radius ?? 0.5;
|
|
1165
|
+
if (!Number.isFinite(this.radius) || this.radius <= 0)
|
|
1166
|
+
throw new Error("Sphere radius must be greater than zero");
|
|
1167
|
+
}
|
|
1168
|
+
clone() {
|
|
1169
|
+
return new _SphereShape({ radius: this.radius, matrix: this.matrix });
|
|
1170
|
+
}
|
|
1171
|
+
equals(shape) {
|
|
1172
|
+
return shape instanceof _SphereShape && super.equals(shape) && this.radius === shape.radius;
|
|
1173
|
+
}
|
|
1174
|
+
containsLocalPoint(point) {
|
|
1175
|
+
return Math.hypot(...point) <= this.radius + EPSILON4;
|
|
1176
|
+
}
|
|
1177
|
+
distanceToLocalPoint(point) {
|
|
1178
|
+
return Math.max(0, Math.hypot(...point) - this.radius);
|
|
1179
|
+
}
|
|
1180
|
+
supportLocal(direction) {
|
|
1181
|
+
const length = Math.hypot(...direction);
|
|
1182
|
+
return length ? direction.map((value) => value / length * this.radius) : [this.radius, 0, 0];
|
|
1183
|
+
}
|
|
1184
|
+
intersectLocalRay(origin, direction) {
|
|
1185
|
+
const roots = solveQuadratic(dot2(direction, direction), 2 * dot2(origin, direction), dot2(origin, origin) - this.radius * this.radius);
|
|
1186
|
+
const distance = roots.find((value) => value >= 0);
|
|
1187
|
+
if (distance === void 0)
|
|
1188
|
+
return void 0;
|
|
1189
|
+
const point = origin.map((value, i) => value + distance * direction[i]);
|
|
1190
|
+
return { distance, normal: point.map((value) => value / this.radius) };
|
|
1191
|
+
}
|
|
1192
|
+
};
|
|
1193
|
+
function dot2(a, b) {
|
|
1194
|
+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1197
|
+
// dist/culling/lib/perspective-off-center-frustum.js
|
|
1198
|
+
var import_core9 = require("@math.gl/core");
|
|
1199
|
+
var scratchPlaneUpVector = new import_core9.Vector3();
|
|
1200
|
+
var scratchPlaneRightVector = new import_core9.Vector3();
|
|
1201
|
+
var scratchPlaneNearCenter = new import_core9.Vector3();
|
|
1202
|
+
var scratchPlaneFarCenter = new import_core9.Vector3();
|
|
1203
|
+
var scratchPlaneNormal2 = new import_core9.Vector3();
|
|
1204
|
+
var PerspectiveOffCenterFrustum = class _PerspectiveOffCenterFrustum {
|
|
1205
|
+
/**
|
|
1206
|
+
* The viewing frustum is defined by 6 planes.
|
|
1207
|
+
* Each plane is represented by a {@link Vector4} object, where the x, y, and z components
|
|
1208
|
+
* define the unit vector normal to the plane, and the w component is the distance of the
|
|
1209
|
+
* plane from the origin/camera position.
|
|
1210
|
+
*
|
|
1211
|
+
* @alias PerspectiveOffCenterFrustum
|
|
1212
|
+
*
|
|
1213
|
+
* @example
|
|
1214
|
+
* const frustum = new PerspectiveOffCenterFrustum({
|
|
1215
|
+
* left : -1.0,
|
|
1216
|
+
* right : 1.0,
|
|
1217
|
+
* top : 1.0,
|
|
1218
|
+
* bottom : -1.0,
|
|
1219
|
+
* near : 1.0,
|
|
1220
|
+
* far : 100.0
|
|
1221
|
+
* });
|
|
1222
|
+
*
|
|
1223
|
+
* @see PerspectiveFrustum
|
|
1224
|
+
*/
|
|
1225
|
+
constructor(options = {}) {
|
|
1226
|
+
this._cullingVolume = new CullingVolume([
|
|
1227
|
+
new Plane(),
|
|
1228
|
+
new Plane(),
|
|
1229
|
+
new Plane(),
|
|
1230
|
+
new Plane(),
|
|
1231
|
+
new Plane(),
|
|
1232
|
+
new Plane()
|
|
1233
|
+
]);
|
|
1234
|
+
this._perspectiveMatrix = new import_core9.Matrix4();
|
|
1235
|
+
this._infinitePerspective = new import_core9.Matrix4();
|
|
1236
|
+
const { near = 1, far = 5e8 } = options;
|
|
1237
|
+
this.left = options.left;
|
|
1238
|
+
this._left = void 0;
|
|
1239
|
+
this.right = options.right;
|
|
1240
|
+
this._right = void 0;
|
|
1241
|
+
this.top = options.top;
|
|
1242
|
+
this._top = void 0;
|
|
1243
|
+
this.bottom = options.bottom;
|
|
1244
|
+
this._bottom = void 0;
|
|
1245
|
+
this.near = near;
|
|
1246
|
+
this._near = near;
|
|
1247
|
+
this.far = far;
|
|
1248
|
+
this._far = far;
|
|
1249
|
+
}
|
|
1250
|
+
/**
|
|
1251
|
+
* Returns a duplicate of a PerspectiveOffCenterFrustum instance.
|
|
1252
|
+
* @returns {PerspectiveOffCenterFrustum} A new PerspectiveFrustum instance.
|
|
1253
|
+
* */
|
|
1254
|
+
clone() {
|
|
1255
|
+
return new _PerspectiveOffCenterFrustum({
|
|
1256
|
+
right: this.right,
|
|
1257
|
+
left: this.left,
|
|
1258
|
+
top: this.top,
|
|
1259
|
+
bottom: this.bottom,
|
|
1260
|
+
near: this.near,
|
|
1261
|
+
far: this.far
|
|
1262
|
+
});
|
|
1263
|
+
}
|
|
1264
|
+
/**
|
|
1265
|
+
* Compares the provided PerspectiveOffCenterFrustum componentwise and returns
|
|
1266
|
+
* <code>true</code> if they are equal, <code>false</code> otherwise.
|
|
1267
|
+
*
|
|
1268
|
+
* @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
|
|
1269
|
+
*/
|
|
1270
|
+
equals(other) {
|
|
1271
|
+
return other && other instanceof _PerspectiveOffCenterFrustum && this.right === other.right && this.left === other.left && this.top === other.top && this.bottom === other.bottom && this.near === other.near && this.far === other.far;
|
|
1272
|
+
}
|
|
1273
|
+
/**
|
|
1274
|
+
* Gets the perspective projection matrix computed from the view frustum.
|
|
1275
|
+
* @memberof PerspectiveOffCenterFrustum.prototype
|
|
1276
|
+
* @type {Matrix4}
|
|
1277
|
+
*
|
|
1278
|
+
* @see PerspectiveOffCenterFrustum#infiniteProjectionMatrix
|
|
1279
|
+
*/
|
|
1280
|
+
get projectionMatrix() {
|
|
1281
|
+
this._update();
|
|
1282
|
+
return this._perspectiveMatrix;
|
|
1283
|
+
}
|
|
1284
|
+
/**
|
|
1285
|
+
* Gets the perspective projection matrix computed from the view frustum with an infinite far plane.
|
|
1286
|
+
* @memberof PerspectiveOffCenterFrustum.prototype
|
|
1287
|
+
* @type {Matrix4}
|
|
1288
|
+
*
|
|
1289
|
+
* @see PerspectiveOffCenterFrustum#projectionMatrix
|
|
1290
|
+
*/
|
|
1291
|
+
get infiniteProjectionMatrix() {
|
|
1292
|
+
this._update();
|
|
1293
|
+
return this._infinitePerspective;
|
|
1294
|
+
}
|
|
1295
|
+
/**
|
|
1296
|
+
* Creates a culling volume for this frustum.
|
|
1297
|
+
* @returns {CullingVolume} A culling volume at the given position and orientation.
|
|
1298
|
+
*
|
|
1299
|
+
* @example
|
|
1300
|
+
* // Check if a bounding volume intersects the frustum.
|
|
1301
|
+
* const cullingVolume = frustum.computeCullingVolume(cameraPosition, cameraDirection, cameraUp);
|
|
1302
|
+
* const intersect = cullingVolume.computeVisibility(boundingVolume);
|
|
1303
|
+
*/
|
|
1304
|
+
// eslint-disable-next-line complexity, max-statements
|
|
1305
|
+
computeCullingVolume(position, direction, up) {
|
|
1306
|
+
(0, import_core9.assert)(position, "position is required.");
|
|
1307
|
+
(0, import_core9.assert)(direction, "direction is required.");
|
|
1308
|
+
(0, import_core9.assert)(up, "up is required.");
|
|
1309
|
+
const planes = this._cullingVolume.planes;
|
|
1310
|
+
up = scratchPlaneUpVector.copy(up).normalize();
|
|
1311
|
+
const right = scratchPlaneRightVector.copy(direction).cross(up).normalize();
|
|
1312
|
+
const nearCenter = scratchPlaneNearCenter.copy(direction).multiplyByScalar(this.near).add(position);
|
|
1313
|
+
const farCenter = scratchPlaneFarCenter.copy(direction).multiplyByScalar(this.far).add(position);
|
|
1314
|
+
let normal = scratchPlaneNormal2;
|
|
1315
|
+
normal.copy(right).multiplyByScalar(this.left).add(nearCenter).subtract(position).cross(up);
|
|
1316
|
+
planes[0].fromPointNormal(position, normal);
|
|
1317
|
+
normal.copy(right).multiplyByScalar(this.right).add(nearCenter).subtract(position).cross(up).negate();
|
|
1318
|
+
planes[1].fromPointNormal(position, normal);
|
|
1319
|
+
normal.copy(up).multiplyByScalar(this.bottom).add(nearCenter).subtract(position).cross(right).negate();
|
|
1320
|
+
planes[2].fromPointNormal(position, normal);
|
|
1321
|
+
normal.copy(up).multiplyByScalar(this.top).add(nearCenter).subtract(position).cross(right);
|
|
1322
|
+
planes[3].fromPointNormal(position, normal);
|
|
1323
|
+
normal = new import_core9.Vector3().copy(direction);
|
|
1324
|
+
planes[4].fromPointNormal(nearCenter, normal);
|
|
1325
|
+
normal.negate();
|
|
1326
|
+
planes[5].fromPointNormal(farCenter, normal);
|
|
1327
|
+
return this._cullingVolume;
|
|
1328
|
+
}
|
|
1329
|
+
/**
|
|
1330
|
+
* Returns the pixel's width and height in meters.
|
|
1331
|
+
*
|
|
1332
|
+
* @returns {Vector2} The modified result parameter or a new instance of {@link Vector2} with the pixel's width and height in the x and y properties, respectively.
|
|
1333
|
+
*
|
|
1334
|
+
* @exception {DeveloperError} drawingBufferWidth must be greater than zero.
|
|
1335
|
+
* @exception {DeveloperError} drawingBufferHeight must be greater than zero.
|
|
1336
|
+
*
|
|
1337
|
+
* @example
|
|
1338
|
+
* // Example 1
|
|
1339
|
+
* // Get the width and height of a pixel.
|
|
1340
|
+
* const pixelSize = camera.frustum.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, 1.0, new Vector2());
|
|
1341
|
+
*
|
|
1342
|
+
* @example
|
|
1343
|
+
* // Example 2
|
|
1344
|
+
* // Get the width and height of a pixel if the near plane was set to 'distance'.
|
|
1345
|
+
* // For example, get the size of a pixel of an image on a billboard.
|
|
1346
|
+
* const position = camera.position;
|
|
1347
|
+
* const direction = camera.direction;
|
|
1348
|
+
* const toCenter = Vector3.subtract(primitive.boundingVolume.center, position, new Vector3()); // vector from camera to a primitive
|
|
1349
|
+
* const toCenterProj = Vector3.multiplyByScalar(direction, Vector3.dot(direction, toCenter), new Vector3()); // project vector onto camera direction vector
|
|
1350
|
+
* const distance = Vector3.magnitude(toCenterProj);
|
|
1351
|
+
* const pixelSize = camera.frustum.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, distance, new Vector2());
|
|
1352
|
+
*/
|
|
1353
|
+
getPixelDimensions(drawingBufferWidth, drawingBufferHeight, distance, result) {
|
|
1354
|
+
this._update();
|
|
1355
|
+
(0, import_core9.assert)(Number.isFinite(drawingBufferWidth) && Number.isFinite(drawingBufferHeight));
|
|
1356
|
+
(0, import_core9.assert)(drawingBufferWidth > 0);
|
|
1357
|
+
(0, import_core9.assert)(drawingBufferHeight > 0);
|
|
1358
|
+
(0, import_core9.assert)(distance > 0);
|
|
1359
|
+
(0, import_core9.assert)(result);
|
|
1360
|
+
const inverseNear = 1 / this.near;
|
|
1361
|
+
let tanTheta = this.top * inverseNear;
|
|
1362
|
+
const pixelHeight = 2 * distance * tanTheta / drawingBufferHeight;
|
|
1363
|
+
tanTheta = this.right * inverseNear;
|
|
1364
|
+
const pixelWidth = 2 * distance * tanTheta / drawingBufferWidth;
|
|
1365
|
+
result.x = pixelWidth;
|
|
1366
|
+
result.y = pixelHeight;
|
|
1367
|
+
return result;
|
|
1368
|
+
}
|
|
1369
|
+
// eslint-disable-next-line complexity, max-statements
|
|
1370
|
+
_update() {
|
|
1371
|
+
(0, import_core9.assert)(Number.isFinite(this.right) && Number.isFinite(this.left) && Number.isFinite(this.top) && Number.isFinite(this.bottom) && Number.isFinite(this.near) && Number.isFinite(this.far));
|
|
1372
|
+
const { top, bottom, right, left, near, far } = this;
|
|
1373
|
+
if (top !== this._top || bottom !== this._bottom || left !== this._left || right !== this._right || near !== this._near || far !== this._far) {
|
|
1374
|
+
(0, import_core9.assert)(this.near > 0 && this.near < this.far, "near must be greater than zero and less than far.");
|
|
1375
|
+
this._left = left;
|
|
1376
|
+
this._right = right;
|
|
1377
|
+
this._top = top;
|
|
1378
|
+
this._bottom = bottom;
|
|
1379
|
+
this._near = near;
|
|
1380
|
+
this._far = far;
|
|
1381
|
+
this._perspectiveMatrix = new import_core9.Matrix4().frustum({
|
|
1382
|
+
left,
|
|
1383
|
+
right,
|
|
1384
|
+
bottom,
|
|
1385
|
+
top,
|
|
1386
|
+
near,
|
|
1387
|
+
far
|
|
1388
|
+
});
|
|
1389
|
+
this._infinitePerspective = new import_core9.Matrix4().frustum({
|
|
1390
|
+
left,
|
|
1391
|
+
right,
|
|
1392
|
+
bottom,
|
|
1393
|
+
top,
|
|
1394
|
+
near,
|
|
1395
|
+
far: Infinity
|
|
1396
|
+
});
|
|
1397
|
+
}
|
|
1398
|
+
}
|
|
1399
|
+
};
|
|
1400
|
+
|
|
1401
|
+
// dist/culling/lib/perspective-frustum.js
|
|
1402
|
+
var import_core10 = require("@math.gl/core");
|
|
1403
|
+
var defined = (val) => val !== null && typeof val !== "undefined";
|
|
1404
|
+
var PerspectiveFrustum = class _PerspectiveFrustum {
|
|
1405
|
+
constructor(options = {}) {
|
|
1406
|
+
this._offCenterFrustum = new PerspectiveOffCenterFrustum();
|
|
1407
|
+
const { fov, aspectRatio, near = 1, far = 5e8, xOffset = 0, yOffset = 0 } = options;
|
|
1408
|
+
this.fov = fov;
|
|
1409
|
+
this.aspectRatio = aspectRatio;
|
|
1410
|
+
this.near = near;
|
|
1411
|
+
this.far = far;
|
|
1412
|
+
this.xOffset = xOffset;
|
|
1413
|
+
this.yOffset = yOffset;
|
|
1414
|
+
}
|
|
1415
|
+
/**
|
|
1416
|
+
* Returns a duplicate of a PerspectiveFrustum instance.
|
|
1417
|
+
*/
|
|
1418
|
+
clone() {
|
|
1419
|
+
return new _PerspectiveFrustum({
|
|
1420
|
+
aspectRatio: this.aspectRatio,
|
|
1421
|
+
fov: this.fov,
|
|
1422
|
+
near: this.near,
|
|
1423
|
+
far: this.far
|
|
1424
|
+
});
|
|
1425
|
+
}
|
|
1426
|
+
/**
|
|
1427
|
+
* Compares the provided PerspectiveFrustum componentwise and returns
|
|
1428
|
+
* <code>true</code> if they are equal, <code>false</code> otherwise.
|
|
1429
|
+
*/
|
|
1430
|
+
equals(other) {
|
|
1431
|
+
if (!defined(other) || !(other instanceof _PerspectiveFrustum)) {
|
|
1432
|
+
return false;
|
|
1433
|
+
}
|
|
1434
|
+
this._update();
|
|
1435
|
+
other._update();
|
|
1436
|
+
return this.fov === other.fov && this.aspectRatio === other.aspectRatio && this.near === other.near && this.far === other.far && this._offCenterFrustum.equals(other._offCenterFrustum);
|
|
1437
|
+
}
|
|
1438
|
+
/**
|
|
1439
|
+
* Gets the perspective projection matrix computed from the view this.
|
|
1440
|
+
*/
|
|
1441
|
+
get projectionMatrix() {
|
|
1442
|
+
this._update();
|
|
1443
|
+
return this._offCenterFrustum.projectionMatrix;
|
|
1444
|
+
}
|
|
1445
|
+
/**
|
|
1446
|
+
* The perspective projection matrix computed from the view frustum with an infinite far plane.
|
|
1447
|
+
*/
|
|
1448
|
+
get infiniteProjectionMatrix() {
|
|
1449
|
+
this._update();
|
|
1450
|
+
return this._offCenterFrustum.infiniteProjectionMatrix;
|
|
1451
|
+
}
|
|
1452
|
+
/**
|
|
1453
|
+
* Gets the angle of the vertical field of view, in radians.
|
|
1454
|
+
*/
|
|
1455
|
+
get fovy() {
|
|
1456
|
+
this._update();
|
|
1457
|
+
return this._fovy;
|
|
1458
|
+
}
|
|
1459
|
+
/**
|
|
1460
|
+
* @private
|
|
1461
|
+
*/
|
|
1462
|
+
get sseDenominator() {
|
|
1463
|
+
this._update();
|
|
1464
|
+
return this._sseDenominator;
|
|
1465
|
+
}
|
|
1466
|
+
/**
|
|
1467
|
+
* Creates a culling volume for this this.ion.
|
|
1468
|
+
* @returns {CullingVolume} A culling volume at the given position and orientation.
|
|
1469
|
+
*
|
|
1470
|
+
* @example
|
|
1471
|
+
* // Check if a bounding volume intersects the this.
|
|
1472
|
+
* var cullingVolume = this.computeCullingVolume(cameraPosition, cameraDirection, cameraUp);
|
|
1473
|
+
* var intersect = cullingVolume.computeVisibility(boundingVolume);
|
|
1474
|
+
*/
|
|
1475
|
+
computeCullingVolume(position, direction, up) {
|
|
1476
|
+
this._update();
|
|
1477
|
+
return this._offCenterFrustum.computeCullingVolume(position, direction, up);
|
|
1478
|
+
}
|
|
1479
|
+
/**
|
|
1480
|
+
* Returns the pixel's width and height in meters.
|
|
1481
|
+
* @returns {Vector2} The modified result parameter or a new instance of {@link Vector2} with the pixel's width and height in the x and y properties, respectively.
|
|
1482
|
+
*
|
|
1483
|
+
* @exception {DeveloperError} drawingBufferWidth must be greater than zero.
|
|
1484
|
+
* @exception {DeveloperError} drawingBufferHeight must be greater than zero.
|
|
1485
|
+
*
|
|
1486
|
+
* @example
|
|
1487
|
+
* // Example 1
|
|
1488
|
+
* // Get the width and height of a pixel.
|
|
1489
|
+
* var pixelSize = camera.this.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, 1.0, new Vector2());
|
|
1490
|
+
*
|
|
1491
|
+
* @example
|
|
1492
|
+
* // Example 2
|
|
1493
|
+
* // Get the width and height of a pixel if the near plane was set to 'distance'.
|
|
1494
|
+
* // For example, get the size of a pixel of an image on a billboard.
|
|
1495
|
+
* var position = camera.position;
|
|
1496
|
+
* var direction = camera.direction;
|
|
1497
|
+
* var toCenter = Vector3.subtract(primitive.boundingVolume.center, position, new Vector3()); // vector from camera to a primitive
|
|
1498
|
+
* var toCenterProj = Vector3.multiplyByScalar(direction, Vector3.dot(direction, toCenter), new Vector3()); // project vector onto camera direction vector
|
|
1499
|
+
* var distance = Vector3.magnitude(toCenterProj);
|
|
1500
|
+
* var pixelSize = camera.this.getPixelDimensions(scene.drawingBufferWidth, scene.drawingBufferHeight, distance, new Vector2());
|
|
1501
|
+
*/
|
|
1502
|
+
getPixelDimensions(drawingBufferWidth, drawingBufferHeight, distance, result) {
|
|
1503
|
+
this._update();
|
|
1504
|
+
return this._offCenterFrustum.getPixelDimensions(drawingBufferWidth, drawingBufferHeight, distance, result || new import_core10.Vector2());
|
|
1505
|
+
}
|
|
1506
|
+
// eslint-disable-next-line complexity, max-statements
|
|
1507
|
+
_update() {
|
|
1508
|
+
(0, import_core10.assert)(Number.isFinite(this.fov) && Number.isFinite(this.aspectRatio) && Number.isFinite(this.near) && Number.isFinite(this.far));
|
|
1509
|
+
const f = this._offCenterFrustum;
|
|
1510
|
+
if (this.fov !== this._fov || this.aspectRatio !== this._aspectRatio || this.near !== this._near || this.far !== this._far || this.xOffset !== this._xOffset || this.yOffset !== this._yOffset) {
|
|
1511
|
+
(0, import_core10.assert)(this.fov >= 0 && this.fov < Math.PI);
|
|
1512
|
+
(0, import_core10.assert)(this.aspectRatio > 0);
|
|
1513
|
+
(0, import_core10.assert)(this.near >= 0 && this.near < this.far);
|
|
1514
|
+
this._aspectRatio = this.aspectRatio;
|
|
1515
|
+
this._fov = this.fov;
|
|
1516
|
+
this._fovy = this.aspectRatio <= 1 ? this.fov : Math.atan(Math.tan(this.fov * 0.5) / this.aspectRatio) * 2;
|
|
1517
|
+
this._near = this.near;
|
|
1518
|
+
this._far = this.far;
|
|
1519
|
+
this._sseDenominator = 2 * Math.tan(0.5 * this._fovy);
|
|
1520
|
+
this._xOffset = this.xOffset;
|
|
1521
|
+
this._yOffset = this.yOffset;
|
|
1522
|
+
f.top = this.near * Math.tan(0.5 * this._fovy);
|
|
1523
|
+
f.bottom = -f.top;
|
|
1524
|
+
f.right = this.aspectRatio * f.top;
|
|
1525
|
+
f.left = -f.right;
|
|
1526
|
+
f.near = this.near;
|
|
1527
|
+
f.far = this.far;
|
|
1528
|
+
f.right += this.xOffset;
|
|
1529
|
+
f.left += this.xOffset;
|
|
1530
|
+
f.top += this.yOffset;
|
|
1531
|
+
f.bottom += this.yOffset;
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
};
|
|
1535
|
+
|
|
1536
|
+
// dist/culling/lib/algorithms/bounding-sphere-from-points.js
|
|
1537
|
+
var import_core11 = require("@math.gl/core");
|
|
1538
|
+
var fromPointsXMin = new import_core11.Vector3();
|
|
1539
|
+
var fromPointsYMin = new import_core11.Vector3();
|
|
1540
|
+
var fromPointsZMin = new import_core11.Vector3();
|
|
1541
|
+
var fromPointsXMax = new import_core11.Vector3();
|
|
1542
|
+
var fromPointsYMax = new import_core11.Vector3();
|
|
1543
|
+
var fromPointsZMax = new import_core11.Vector3();
|
|
1544
|
+
var fromPointsCurrentPos = new import_core11.Vector3();
|
|
1545
|
+
var fromPointsScratch = new import_core11.Vector3();
|
|
1546
|
+
var fromPointsRitterCenter = new import_core11.Vector3();
|
|
1547
|
+
var fromPointsMinBoxPt = new import_core11.Vector3();
|
|
1548
|
+
var fromPointsMaxBoxPt = new import_core11.Vector3();
|
|
1549
|
+
var fromPointsNaiveCenterScratch = new import_core11.Vector3();
|
|
1550
|
+
function makeBoundingSphereFromPoints(positions, result = new BoundingSphere()) {
|
|
1551
|
+
if (!positions || positions.length === 0) {
|
|
1552
|
+
return result.fromCenterRadius([0, 0, 0], 0);
|
|
1553
|
+
}
|
|
1554
|
+
const currentPos = fromPointsCurrentPos.copy(positions[0]);
|
|
1555
|
+
const xMin = fromPointsXMin.copy(currentPos);
|
|
1556
|
+
const yMin = fromPointsYMin.copy(currentPos);
|
|
1557
|
+
const zMin = fromPointsZMin.copy(currentPos);
|
|
1558
|
+
const xMax = fromPointsXMax.copy(currentPos);
|
|
1559
|
+
const yMax = fromPointsYMax.copy(currentPos);
|
|
1560
|
+
const zMax = fromPointsZMax.copy(currentPos);
|
|
1561
|
+
for (const position of positions) {
|
|
1562
|
+
currentPos.copy(position);
|
|
1563
|
+
const x = currentPos.x;
|
|
1564
|
+
const y = currentPos.y;
|
|
1565
|
+
const z = currentPos.z;
|
|
1566
|
+
if (x < xMin.x) {
|
|
1567
|
+
xMin.copy(currentPos);
|
|
1568
|
+
}
|
|
1569
|
+
if (x > xMax.x) {
|
|
1570
|
+
xMax.copy(currentPos);
|
|
1571
|
+
}
|
|
1572
|
+
if (y < yMin.y) {
|
|
1573
|
+
yMin.copy(currentPos);
|
|
1574
|
+
}
|
|
1575
|
+
if (y > yMax.y) {
|
|
1576
|
+
yMax.copy(currentPos);
|
|
1577
|
+
}
|
|
1578
|
+
if (z < zMin.z) {
|
|
1579
|
+
zMin.copy(currentPos);
|
|
1580
|
+
}
|
|
1581
|
+
if (z > zMax.z) {
|
|
1582
|
+
zMax.copy(currentPos);
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
const xSpan = fromPointsScratch.copy(xMax).subtract(xMin).magnitudeSquared();
|
|
1586
|
+
const ySpan = fromPointsScratch.copy(yMax).subtract(yMin).magnitudeSquared();
|
|
1587
|
+
const zSpan = fromPointsScratch.copy(zMax).subtract(zMin).magnitudeSquared();
|
|
1588
|
+
let diameter1 = xMin;
|
|
1589
|
+
let diameter2 = xMax;
|
|
1590
|
+
let maxSpan = xSpan;
|
|
1591
|
+
if (ySpan > maxSpan) {
|
|
1592
|
+
maxSpan = ySpan;
|
|
1593
|
+
diameter1 = yMin;
|
|
1594
|
+
diameter2 = yMax;
|
|
1595
|
+
}
|
|
1596
|
+
if (zSpan > maxSpan) {
|
|
1597
|
+
maxSpan = zSpan;
|
|
1598
|
+
diameter1 = zMin;
|
|
1599
|
+
diameter2 = zMax;
|
|
1600
|
+
}
|
|
1601
|
+
const ritterCenter = fromPointsRitterCenter;
|
|
1602
|
+
ritterCenter.x = (diameter1.x + diameter2.x) * 0.5;
|
|
1603
|
+
ritterCenter.y = (diameter1.y + diameter2.y) * 0.5;
|
|
1604
|
+
ritterCenter.z = (diameter1.z + diameter2.z) * 0.5;
|
|
1605
|
+
let radiusSquared = fromPointsScratch.copy(diameter2).subtract(ritterCenter).magnitudeSquared();
|
|
1606
|
+
let ritterRadius = Math.sqrt(radiusSquared);
|
|
1607
|
+
const minBoxPt = fromPointsMinBoxPt;
|
|
1608
|
+
minBoxPt.x = xMin.x;
|
|
1609
|
+
minBoxPt.y = yMin.y;
|
|
1610
|
+
minBoxPt.z = zMin.z;
|
|
1611
|
+
const maxBoxPt = fromPointsMaxBoxPt;
|
|
1612
|
+
maxBoxPt.x = xMax.x;
|
|
1613
|
+
maxBoxPt.y = yMax.y;
|
|
1614
|
+
maxBoxPt.z = zMax.z;
|
|
1615
|
+
const naiveCenter = fromPointsNaiveCenterScratch.copy(minBoxPt).add(maxBoxPt).multiplyByScalar(0.5);
|
|
1616
|
+
let naiveRadius = 0;
|
|
1617
|
+
for (const position of positions) {
|
|
1618
|
+
currentPos.copy(position);
|
|
1619
|
+
const r = fromPointsScratch.copy(currentPos).subtract(naiveCenter).magnitude();
|
|
1620
|
+
if (r > naiveRadius) {
|
|
1621
|
+
naiveRadius = r;
|
|
1622
|
+
}
|
|
1623
|
+
const oldCenterToPointSquared = fromPointsScratch.copy(currentPos).subtract(ritterCenter).magnitudeSquared();
|
|
1624
|
+
if (oldCenterToPointSquared > radiusSquared) {
|
|
1625
|
+
const oldCenterToPoint = Math.sqrt(oldCenterToPointSquared);
|
|
1626
|
+
ritterRadius = (ritterRadius + oldCenterToPoint) * 0.5;
|
|
1627
|
+
radiusSquared = ritterRadius * ritterRadius;
|
|
1628
|
+
const oldToNew = oldCenterToPoint - ritterRadius;
|
|
1629
|
+
ritterCenter.x = (ritterRadius * ritterCenter.x + oldToNew * currentPos.x) / oldCenterToPoint;
|
|
1630
|
+
ritterCenter.y = (ritterRadius * ritterCenter.y + oldToNew * currentPos.y) / oldCenterToPoint;
|
|
1631
|
+
ritterCenter.z = (ritterRadius * ritterCenter.z + oldToNew * currentPos.z) / oldCenterToPoint;
|
|
1632
|
+
}
|
|
1633
|
+
}
|
|
1634
|
+
if (ritterRadius < naiveRadius) {
|
|
1635
|
+
ritterCenter.to(result.center);
|
|
1636
|
+
result.radius = ritterRadius;
|
|
1637
|
+
} else {
|
|
1638
|
+
naiveCenter.to(result.center);
|
|
1639
|
+
result.radius = naiveRadius;
|
|
1640
|
+
}
|
|
1641
|
+
return result;
|
|
1642
|
+
}
|
|
1643
|
+
|
|
1644
|
+
// dist/culling/lib/algorithms/bounding-box-from-points.js
|
|
1645
|
+
var import_core13 = require("@math.gl/core");
|
|
1646
|
+
|
|
1647
|
+
// dist/culling/lib/algorithms/compute-eigen-decomposition.js
|
|
1648
|
+
var import_core12 = require("@math.gl/core");
|
|
1649
|
+
var scratchMatrix = new import_core12.Matrix3();
|
|
1650
|
+
var scratchUnitary = new import_core12.Matrix3();
|
|
1651
|
+
var scratchDiagonal = new import_core12.Matrix3();
|
|
1652
|
+
var jMatrix = new import_core12.Matrix3();
|
|
1653
|
+
var jMatrixTranspose = new import_core12.Matrix3();
|
|
1654
|
+
function computeEigenDecomposition(matrix, result = {}) {
|
|
1655
|
+
const EIGEN_TOLERANCE = import_core12._MathUtils.EPSILON20;
|
|
1656
|
+
const EIGEN_MAX_SWEEPS = 10;
|
|
1657
|
+
let count = 0;
|
|
1658
|
+
let sweep = 0;
|
|
1659
|
+
const unitaryMatrix = scratchUnitary;
|
|
1660
|
+
const diagonalMatrix = scratchDiagonal;
|
|
1661
|
+
unitaryMatrix.identity();
|
|
1662
|
+
diagonalMatrix.copy(matrix);
|
|
1663
|
+
const epsilon = EIGEN_TOLERANCE * computeFrobeniusNorm(diagonalMatrix);
|
|
1664
|
+
while (sweep < EIGEN_MAX_SWEEPS && offDiagonalFrobeniusNorm(diagonalMatrix) > epsilon) {
|
|
1665
|
+
shurDecomposition(diagonalMatrix, jMatrix);
|
|
1666
|
+
jMatrixTranspose.copy(jMatrix).transpose();
|
|
1667
|
+
diagonalMatrix.multiplyRight(jMatrix);
|
|
1668
|
+
diagonalMatrix.multiplyLeft(jMatrixTranspose);
|
|
1669
|
+
unitaryMatrix.multiplyRight(jMatrix);
|
|
1670
|
+
if (++count > 2) {
|
|
1671
|
+
++sweep;
|
|
1672
|
+
count = 0;
|
|
1673
|
+
}
|
|
1674
|
+
}
|
|
1675
|
+
result.unitary = unitaryMatrix.toTarget(result.unitary);
|
|
1676
|
+
result.diagonal = diagonalMatrix.toTarget(result.diagonal);
|
|
1677
|
+
return result;
|
|
1678
|
+
}
|
|
1679
|
+
function computeFrobeniusNorm(matrix) {
|
|
1680
|
+
let norm = 0;
|
|
1681
|
+
for (let i = 0; i < 9; ++i) {
|
|
1682
|
+
const temp = matrix[i];
|
|
1683
|
+
norm += temp * temp;
|
|
1684
|
+
}
|
|
1685
|
+
return Math.sqrt(norm);
|
|
1686
|
+
}
|
|
1687
|
+
var rowVal = [1, 0, 0];
|
|
1688
|
+
var colVal = [2, 2, 1];
|
|
1689
|
+
function offDiagonalFrobeniusNorm(matrix) {
|
|
1690
|
+
let norm = 0;
|
|
1691
|
+
for (let i = 0; i < 3; ++i) {
|
|
1692
|
+
const temp = matrix[scratchMatrix.getElementIndex(colVal[i], rowVal[i])];
|
|
1693
|
+
norm += 2 * temp * temp;
|
|
1694
|
+
}
|
|
1695
|
+
return Math.sqrt(norm);
|
|
1696
|
+
}
|
|
1697
|
+
function shurDecomposition(matrix, result) {
|
|
1698
|
+
const tolerance = import_core12._MathUtils.EPSILON15;
|
|
1699
|
+
let maxDiagonal = 0;
|
|
1700
|
+
let rotAxis = 1;
|
|
1701
|
+
for (let i = 0; i < 3; ++i) {
|
|
1702
|
+
const temp = Math.abs(matrix[scratchMatrix.getElementIndex(colVal[i], rowVal[i])]);
|
|
1703
|
+
if (temp > maxDiagonal) {
|
|
1704
|
+
rotAxis = i;
|
|
1705
|
+
maxDiagonal = temp;
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
const p = rowVal[rotAxis];
|
|
1709
|
+
const q = colVal[rotAxis];
|
|
1710
|
+
let c = 1;
|
|
1711
|
+
let s = 0;
|
|
1712
|
+
if (Math.abs(matrix[scratchMatrix.getElementIndex(q, p)]) > tolerance) {
|
|
1713
|
+
const qq = matrix[scratchMatrix.getElementIndex(q, q)];
|
|
1714
|
+
const pp = matrix[scratchMatrix.getElementIndex(p, p)];
|
|
1715
|
+
const qp = matrix[scratchMatrix.getElementIndex(q, p)];
|
|
1716
|
+
const tau = (qq - pp) / 2 / qp;
|
|
1717
|
+
let t;
|
|
1718
|
+
if (tau < 0) {
|
|
1719
|
+
t = -1 / (-tau + Math.sqrt(1 + tau * tau));
|
|
1720
|
+
} else {
|
|
1721
|
+
t = 1 / (tau + Math.sqrt(1 + tau * tau));
|
|
1722
|
+
}
|
|
1723
|
+
c = 1 / Math.sqrt(1 + t * t);
|
|
1724
|
+
s = t * c;
|
|
1725
|
+
}
|
|
1726
|
+
import_core12.Matrix3.IDENTITY.to(result);
|
|
1727
|
+
result[scratchMatrix.getElementIndex(p, p)] = result[scratchMatrix.getElementIndex(q, q)] = c;
|
|
1728
|
+
result[scratchMatrix.getElementIndex(q, p)] = s;
|
|
1729
|
+
result[scratchMatrix.getElementIndex(p, q)] = -s;
|
|
1730
|
+
return result;
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
// dist/culling/lib/algorithms/bounding-box-from-points.js
|
|
1734
|
+
var scratchVector23 = new import_core13.Vector3();
|
|
1735
|
+
var scratchVector32 = new import_core13.Vector3();
|
|
1736
|
+
var scratchVector4 = new import_core13.Vector3();
|
|
1737
|
+
var scratchVector5 = new import_core13.Vector3();
|
|
1738
|
+
var scratchVector6 = new import_core13.Vector3();
|
|
1739
|
+
var scratchCovarianceResult = new import_core13.Matrix3();
|
|
1740
|
+
var scratchEigenResult = {
|
|
1741
|
+
diagonal: new import_core13.Matrix3(),
|
|
1742
|
+
unitary: new import_core13.Matrix3()
|
|
1743
|
+
};
|
|
1744
|
+
function makeOrientedBoundingBoxFromPoints(positions, result = new OrientedBoundingBox()) {
|
|
1745
|
+
if (!positions || positions.length === 0) {
|
|
1746
|
+
result.halfAxes = new import_core13.Matrix3([0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
|
1747
|
+
result.center = new import_core13.Vector3();
|
|
1748
|
+
return result;
|
|
1749
|
+
}
|
|
1750
|
+
const length = positions.length;
|
|
1751
|
+
const meanPoint = new import_core13.Vector3(0, 0, 0);
|
|
1752
|
+
for (const position of positions) {
|
|
1753
|
+
meanPoint.add(position);
|
|
1754
|
+
}
|
|
1755
|
+
const invLength = 1 / length;
|
|
1756
|
+
meanPoint.multiplyByScalar(invLength);
|
|
1757
|
+
let exx = 0;
|
|
1758
|
+
let exy = 0;
|
|
1759
|
+
let exz = 0;
|
|
1760
|
+
let eyy = 0;
|
|
1761
|
+
let eyz = 0;
|
|
1762
|
+
let ezz = 0;
|
|
1763
|
+
for (const position of positions) {
|
|
1764
|
+
const p = scratchVector23.copy(position).subtract(meanPoint);
|
|
1765
|
+
exx += p.x * p.x;
|
|
1766
|
+
exy += p.x * p.y;
|
|
1767
|
+
exz += p.x * p.z;
|
|
1768
|
+
eyy += p.y * p.y;
|
|
1769
|
+
eyz += p.y * p.z;
|
|
1770
|
+
ezz += p.z * p.z;
|
|
1771
|
+
}
|
|
1772
|
+
exx *= invLength;
|
|
1773
|
+
exy *= invLength;
|
|
1774
|
+
exz *= invLength;
|
|
1775
|
+
eyy *= invLength;
|
|
1776
|
+
eyz *= invLength;
|
|
1777
|
+
ezz *= invLength;
|
|
1778
|
+
const covarianceMatrix = scratchCovarianceResult;
|
|
1779
|
+
covarianceMatrix[0] = exx;
|
|
1780
|
+
covarianceMatrix[1] = exy;
|
|
1781
|
+
covarianceMatrix[2] = exz;
|
|
1782
|
+
covarianceMatrix[3] = exy;
|
|
1783
|
+
covarianceMatrix[4] = eyy;
|
|
1784
|
+
covarianceMatrix[5] = eyz;
|
|
1785
|
+
covarianceMatrix[6] = exz;
|
|
1786
|
+
covarianceMatrix[7] = eyz;
|
|
1787
|
+
covarianceMatrix[8] = ezz;
|
|
1788
|
+
const { unitary } = computeEigenDecomposition(covarianceMatrix, scratchEigenResult);
|
|
1789
|
+
const rotation = result.halfAxes.copy(unitary);
|
|
1790
|
+
let v1 = rotation.getColumn(0, scratchVector4);
|
|
1791
|
+
let v2 = rotation.getColumn(1, scratchVector5);
|
|
1792
|
+
let v3 = rotation.getColumn(2, scratchVector6);
|
|
1793
|
+
let u1 = -Number.MAX_VALUE;
|
|
1794
|
+
let u2 = -Number.MAX_VALUE;
|
|
1795
|
+
let u3 = -Number.MAX_VALUE;
|
|
1796
|
+
let l1 = Number.MAX_VALUE;
|
|
1797
|
+
let l2 = Number.MAX_VALUE;
|
|
1798
|
+
let l3 = Number.MAX_VALUE;
|
|
1799
|
+
for (const position of positions) {
|
|
1800
|
+
scratchVector23.copy(position);
|
|
1801
|
+
u1 = Math.max(scratchVector23.dot(v1), u1);
|
|
1802
|
+
u2 = Math.max(scratchVector23.dot(v2), u2);
|
|
1803
|
+
u3 = Math.max(scratchVector23.dot(v3), u3);
|
|
1804
|
+
l1 = Math.min(scratchVector23.dot(v1), l1);
|
|
1805
|
+
l2 = Math.min(scratchVector23.dot(v2), l2);
|
|
1806
|
+
l3 = Math.min(scratchVector23.dot(v3), l3);
|
|
1807
|
+
}
|
|
1808
|
+
v1 = v1.multiplyByScalar(0.5 * (l1 + u1));
|
|
1809
|
+
v2 = v2.multiplyByScalar(0.5 * (l2 + u2));
|
|
1810
|
+
v3 = v3.multiplyByScalar(0.5 * (l3 + u3));
|
|
1811
|
+
result.center.copy(v1).add(v2).add(v3);
|
|
1812
|
+
const scale = scratchVector32.set(u1 - l1, u2 - l2, u3 - l3).multiplyByScalar(0.5);
|
|
1813
|
+
const scaleMatrix = new import_core13.Matrix3([scale[0], 0, 0, 0, scale[1], 0, 0, 0, scale[2]]);
|
|
1814
|
+
result.halfAxes.multiplyRight(scaleMatrix);
|
|
1815
|
+
return result;
|
|
1816
|
+
}
|
|
1817
|
+
function makeAxisAlignedBoundingBoxFromPoints(positions, result = new AxisAlignedBoundingBox()) {
|
|
1818
|
+
if (!positions || positions.length === 0) {
|
|
1819
|
+
result.minimum.set(0, 0, 0);
|
|
1820
|
+
result.maximum.set(0, 0, 0);
|
|
1821
|
+
result.center.set(0, 0, 0);
|
|
1822
|
+
result.halfDiagonal.set(0, 0, 0);
|
|
1823
|
+
return result;
|
|
1824
|
+
}
|
|
1825
|
+
let minimumX = positions[0][0];
|
|
1826
|
+
let minimumY = positions[0][1];
|
|
1827
|
+
let minimumZ = positions[0][2];
|
|
1828
|
+
let maximumX = positions[0][0];
|
|
1829
|
+
let maximumY = positions[0][1];
|
|
1830
|
+
let maximumZ = positions[0][2];
|
|
1831
|
+
for (const p of positions) {
|
|
1832
|
+
const x = p[0];
|
|
1833
|
+
const y = p[1];
|
|
1834
|
+
const z = p[2];
|
|
1835
|
+
minimumX = Math.min(x, minimumX);
|
|
1836
|
+
maximumX = Math.max(x, maximumX);
|
|
1837
|
+
minimumY = Math.min(y, minimumY);
|
|
1838
|
+
maximumY = Math.max(y, maximumY);
|
|
1839
|
+
minimumZ = Math.min(z, minimumZ);
|
|
1840
|
+
maximumZ = Math.max(z, maximumZ);
|
|
1841
|
+
}
|
|
1842
|
+
result.minimum.set(minimumX, minimumY, minimumZ);
|
|
1843
|
+
result.maximum.set(maximumX, maximumY, maximumZ);
|
|
1844
|
+
result.center.copy(result.minimum).add(result.maximum).scale(0.5);
|
|
1845
|
+
result.halfDiagonal.copy(result.maximum).subtract(result.center);
|
|
1846
|
+
return result;
|
|
1847
|
+
}
|
|
1848
|
+
|
|
1849
|
+
// dist/culling/queries.js
|
|
1850
|
+
function validateQueryPoint(point, dimension) {
|
|
1851
|
+
if (point.length !== dimension)
|
|
1852
|
+
throw new RangeError("Query dimension must match the index");
|
|
1853
|
+
for (let i = 0; i < dimension; i++) {
|
|
1854
|
+
if (!Number.isFinite(point[i]))
|
|
1855
|
+
throw new RangeError("Coordinates must be finite");
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
function validateQueryDistance(distance) {
|
|
1859
|
+
if (Number.isNaN(distance) || distance < 0)
|
|
1860
|
+
throw new RangeError("Distance must be nonnegative");
|
|
1861
|
+
}
|
|
1862
|
+
function intersectRayBounds(origin, direction, minimum, maximum, maxT = Infinity) {
|
|
1863
|
+
const dimension = origin.length;
|
|
1864
|
+
if (dimension !== 2 && dimension !== 3)
|
|
1865
|
+
throw new RangeError("Bounds must be 2D or 3D");
|
|
1866
|
+
validateQueryPoint(origin, dimension);
|
|
1867
|
+
validateQueryPoint(direction, dimension);
|
|
1868
|
+
validateQueryPoint(minimum, dimension);
|
|
1869
|
+
validateQueryPoint(maximum, dimension);
|
|
1870
|
+
validateQueryDistance(maxT);
|
|
1871
|
+
let near = 0, far = maxT, nonzero = false;
|
|
1872
|
+
for (let i = 0; i < dimension; i++) {
|
|
1873
|
+
if (minimum[i] > maximum[i])
|
|
1874
|
+
throw new RangeError("Bounds must be ordered");
|
|
1875
|
+
nonzero || (nonzero = direction[i] !== 0);
|
|
1876
|
+
}
|
|
1877
|
+
if (!nonzero)
|
|
1878
|
+
throw new RangeError("Ray direction must be nonzero");
|
|
1879
|
+
for (let i = 0; i < dimension; i++) {
|
|
1880
|
+
if (direction[i] === 0) {
|
|
1881
|
+
if (origin[i] < minimum[i] || origin[i] > maximum[i])
|
|
1882
|
+
return null;
|
|
1883
|
+
continue;
|
|
1884
|
+
}
|
|
1885
|
+
let a = (minimum[i] - origin[i]) / direction[i];
|
|
1886
|
+
let b = (maximum[i] - origin[i]) / direction[i];
|
|
1887
|
+
if (a > b)
|
|
1888
|
+
[a, b] = [b, a];
|
|
1889
|
+
near = Math.max(near, a);
|
|
1890
|
+
far = Math.min(far, b);
|
|
1891
|
+
if (near > far)
|
|
1892
|
+
return null;
|
|
1893
|
+
}
|
|
1894
|
+
return Number.isFinite(near) ? near : null;
|
|
1895
|
+
}
|
|
1896
|
+
function intersectRayTriangle(origin, direction, a, b, c, options = {}) {
|
|
1897
|
+
for (const point of [origin, direction, a, b, c])
|
|
1898
|
+
validateQueryPoint(point, 3);
|
|
1899
|
+
if (direction[0] === 0 && direction[1] === 0 && direction[2] === 0) {
|
|
1900
|
+
throw new RangeError("Ray direction must be nonzero");
|
|
1901
|
+
}
|
|
1902
|
+
const maxT = options.maxT ?? Infinity;
|
|
1903
|
+
validateQueryDistance(maxT);
|
|
1904
|
+
const e1 = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
|
|
1905
|
+
const e2 = [c[0] - a[0], c[1] - a[1], c[2] - a[2]];
|
|
1906
|
+
const p = cross(direction, e2);
|
|
1907
|
+
const determinant = dot3(e1, p);
|
|
1908
|
+
if (determinant === 0 || options.backfaceCulling && determinant < 0)
|
|
1909
|
+
return null;
|
|
1910
|
+
const offset = [origin[0] - a[0], origin[1] - a[1], origin[2] - a[2]];
|
|
1911
|
+
const u = dot3(offset, p) / determinant;
|
|
1912
|
+
if (u < 0 || u > 1)
|
|
1913
|
+
return null;
|
|
1914
|
+
const q = cross(offset, e1);
|
|
1915
|
+
const v = dot3(direction, q) / determinant;
|
|
1916
|
+
if (v < 0 || u + v > 1)
|
|
1917
|
+
return null;
|
|
1918
|
+
const t = dot3(e2, q) / determinant;
|
|
1919
|
+
if (!Number.isFinite(t) || t < 0 || t > maxT)
|
|
1920
|
+
return null;
|
|
1921
|
+
return { t: Math.max(0, t), barycentric: [1 - u - v, u, v] };
|
|
1922
|
+
}
|
|
1923
|
+
function getClosestPointOnTriangle(point, a, b, c) {
|
|
1924
|
+
for (const value of [point, a, b, c])
|
|
1925
|
+
validateQueryPoint(value, 3);
|
|
1926
|
+
const ab = [b[0] - a[0], b[1] - a[1], b[2] - a[2]];
|
|
1927
|
+
const ac = [c[0] - a[0], c[1] - a[1], c[2] - a[2]];
|
|
1928
|
+
const ap = [point[0] - a[0], point[1] - a[1], point[2] - a[2]];
|
|
1929
|
+
const aa = dot3(ab, ab), bb = dot3(ac, ac), cc = dot3(ab, ac);
|
|
1930
|
+
const denominator = aa * bb - cc * cc;
|
|
1931
|
+
if (denominator > 0 && Number.isFinite(denominator)) {
|
|
1932
|
+
const u = (bb * dot3(ap, ab) - cc * dot3(ap, ac)) / denominator;
|
|
1933
|
+
const v = (aa * dot3(ap, ac) - cc * dot3(ap, ab)) / denominator;
|
|
1934
|
+
if (u >= 0 && v >= 0 && u + v <= 1) {
|
|
1935
|
+
return [
|
|
1936
|
+
a[0] + u * ab[0] + v * ac[0],
|
|
1937
|
+
a[1] + u * ab[1] + v * ac[1],
|
|
1938
|
+
a[2] + u * ab[2] + v * ac[2]
|
|
1939
|
+
];
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
let best = [a[0], a[1], a[2]];
|
|
1943
|
+
let distance = Infinity;
|
|
1944
|
+
for (const [start, end] of [
|
|
1945
|
+
[a, b],
|
|
1946
|
+
[b, c],
|
|
1947
|
+
[c, a]
|
|
1948
|
+
]) {
|
|
1949
|
+
const edge = [end[0] - start[0], end[1] - start[1], end[2] - start[2]];
|
|
1950
|
+
const offset = [point[0] - start[0], point[1] - start[1], point[2] - start[2]];
|
|
1951
|
+
const squared = dot3(edge, edge);
|
|
1952
|
+
const t = squared > 0 ? Math.max(0, Math.min(1, dot3(offset, edge) / squared)) : 0;
|
|
1953
|
+
const candidate = [
|
|
1954
|
+
start[0] + t * edge[0],
|
|
1955
|
+
start[1] + t * edge[1],
|
|
1956
|
+
start[2] + t * edge[2]
|
|
1957
|
+
];
|
|
1958
|
+
const d = Math.hypot(point[0] - candidate[0], point[1] - candidate[1], point[2] - candidate[2]);
|
|
1959
|
+
if (d < distance) {
|
|
1960
|
+
distance = d;
|
|
1961
|
+
best = candidate;
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
return best;
|
|
1965
|
+
}
|
|
1966
|
+
function dot3(a, b) {
|
|
1967
|
+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
1968
|
+
}
|
|
1969
|
+
function cross(a, b) {
|
|
1970
|
+
return [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]];
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
// dist/culling/oriented-box-2d.js
|
|
1974
|
+
function intersectOrientedBoxes2D(first, second, epsilon = 0) {
|
|
1975
|
+
validateBox(first);
|
|
1976
|
+
validateBox(second);
|
|
1977
|
+
if (!Number.isFinite(epsilon) || epsilon < 0) {
|
|
1978
|
+
throw new RangeError("Box separation allowance must be finite and nonnegative");
|
|
1979
|
+
}
|
|
1980
|
+
const firstDirectionScale = Math.max(Math.abs(first.direction[0]), Math.abs(first.direction[1]));
|
|
1981
|
+
const secondDirectionScale = Math.max(Math.abs(second.direction[0]), Math.abs(second.direction[1]));
|
|
1982
|
+
const firstWidthX = first.direction[0] / firstDirectionScale;
|
|
1983
|
+
const firstWidthY = first.direction[1] / firstDirectionScale;
|
|
1984
|
+
const secondWidthX = second.direction[0] / secondDirectionScale;
|
|
1985
|
+
const secondWidthY = second.direction[1] / secondDirectionScale;
|
|
1986
|
+
const firstLength = Math.hypot(firstWidthX, firstWidthY);
|
|
1987
|
+
const secondLength = Math.hypot(secondWidthX, secondWidthY);
|
|
1988
|
+
const firstX = firstWidthX / firstLength;
|
|
1989
|
+
const firstY = firstWidthY / firstLength;
|
|
1990
|
+
const secondX = secondWidthX / secondLength;
|
|
1991
|
+
const secondY = secondWidthY / secondLength;
|
|
1992
|
+
const cosine = Math.min(1, Math.abs(firstX * secondX + firstY * secondY));
|
|
1993
|
+
const sine = Math.min(1, Math.abs(firstX * secondY - firstY * secondX));
|
|
1994
|
+
return overlapsOnAxis(first, second, firstX, firstY, first.halfSize[0], second.halfSize[0] * cosine, second.halfSize[1] * sine, epsilon) && overlapsOnAxis(first, second, -firstY, firstX, first.halfSize[1], second.halfSize[0] * sine, second.halfSize[1] * cosine, epsilon) && overlapsOnAxis(first, second, secondX, secondY, second.halfSize[0], first.halfSize[0] * cosine, first.halfSize[1] * sine, epsilon) && overlapsOnAxis(first, second, -secondY, secondX, second.halfSize[1], first.halfSize[0] * sine, first.halfSize[1] * cosine, epsilon);
|
|
1995
|
+
}
|
|
1996
|
+
function overlapsOnAxis(first, second, axisX, axisY, ownRadius, otherWidthRadius, otherHeightRadius, epsilon) {
|
|
1997
|
+
const displacementX = second.center[0] - first.center[0];
|
|
1998
|
+
const displacementY = second.center[1] - first.center[1];
|
|
1999
|
+
const projectionX = Number.isFinite(displacementX) ? displacementX * axisX : second.center[0] * axisX - first.center[0] * axisX;
|
|
2000
|
+
const projectionY = Number.isFinite(displacementY) ? displacementY * axisY : second.center[1] * axisY - first.center[1] * axisY;
|
|
2001
|
+
const scale = Math.max(ownRadius, otherWidthRadius, otherHeightRadius, epsilon, Number.isFinite(projectionX) ? Math.abs(projectionX) : Math.max(Math.abs(first.center[0] * axisX), Math.abs(second.center[0] * axisX)), Number.isFinite(projectionY) ? Math.abs(projectionY) : Math.max(Math.abs(first.center[1] * axisY), Math.abs(second.center[1] * axisY))) || 1;
|
|
2002
|
+
const normalizedX = Number.isFinite(projectionX) ? projectionX / scale : second.center[0] * axisX / scale - first.center[0] * axisX / scale;
|
|
2003
|
+
const normalizedY = Number.isFinite(projectionY) ? projectionY / scale : second.center[1] * axisY / scale - first.center[1] * axisY / scale;
|
|
2004
|
+
return Math.abs(normalizedX + normalizedY) <= ownRadius / scale + otherWidthRadius / scale + otherHeightRadius / scale + epsilon / scale;
|
|
2005
|
+
}
|
|
2006
|
+
function validateBox(box) {
|
|
2007
|
+
validateVector(box.center);
|
|
2008
|
+
validateVector(box.halfSize);
|
|
2009
|
+
validateVector(box.direction);
|
|
2010
|
+
if (box.halfSize[0] < 0 || box.halfSize[1] < 0) {
|
|
2011
|
+
throw new RangeError("Box half-sizes must be nonnegative");
|
|
2012
|
+
}
|
|
2013
|
+
if (box.direction[0] === 0 && box.direction[1] === 0) {
|
|
2014
|
+
throw new RangeError("Box direction must be nonzero");
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
function validateVector(vector) {
|
|
2018
|
+
if (vector.length !== 2 || !Number.isFinite(vector[0]) || !Number.isFinite(vector[1])) {
|
|
2019
|
+
throw new RangeError("Box vectors must have exactly two finite components");
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
//# sourceMappingURL=index.cjs.map
|