@math.gl/culling 4.1.0 → 4.2.0-alpha.5
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/LICENSE +51 -0
- package/README.md +8 -1
- package/dist/index.cjs +660 -83
- package/dist/index.cjs.map +3 -4
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/bounding-volumes/oriented-bounding-box.d.ts +1 -1
- package/dist/lib/bounding-volumes/oriented-bounding-box.d.ts.map +1 -1
- package/dist/lib/bounding-volumes/oriented-bounding-box.js.map +1 -1
- package/dist/lib/plane.d.ts +9 -0
- package/dist/lib/plane.d.ts.map +1 -1
- package/dist/lib/plane.js +22 -1
- package/dist/lib/plane.js.map +1 -1
- package/dist/lib/ray.d.ts +13 -0
- package/dist/lib/ray.d.ts.map +1 -0
- package/dist/lib/ray.js +28 -0
- package/dist/lib/ray.js.map +1 -0
- package/dist/lib/shapes/box-shape.d.ts +19 -0
- package/dist/lib/shapes/box-shape.d.ts.map +1 -0
- package/dist/lib/shapes/box-shape.js +69 -0
- package/dist/lib/shapes/box-shape.js.map +1 -0
- package/dist/lib/shapes/capsule-shape.d.ts +23 -0
- package/dist/lib/shapes/capsule-shape.d.ts.map +1 -0
- package/dist/lib/shapes/capsule-shape.js +151 -0
- package/dist/lib/shapes/capsule-shape.js.map +1 -0
- package/dist/lib/shapes/cylinder-shape.d.ts +22 -0
- package/dist/lib/shapes/cylinder-shape.d.ts.map +1 -0
- package/dist/lib/shapes/cylinder-shape.js +99 -0
- package/dist/lib/shapes/cylinder-shape.js.map +1 -0
- package/dist/lib/shapes/implicit-shape.d.ts +55 -0
- package/dist/lib/shapes/implicit-shape.d.ts.map +1 -0
- package/dist/lib/shapes/implicit-shape.js +143 -0
- package/dist/lib/shapes/implicit-shape.js.map +1 -0
- package/dist/lib/shapes/plane-shape.d.ts +26 -0
- package/dist/lib/shapes/plane-shape.d.ts.map +1 -0
- package/dist/lib/shapes/plane-shape.js +72 -0
- package/dist/lib/shapes/plane-shape.js.map +1 -0
- package/dist/lib/shapes/sphere-shape.d.ts +18 -0
- package/dist/lib/shapes/sphere-shape.d.ts.map +1 -0
- package/dist/lib/shapes/sphere-shape.js +43 -0
- package/dist/lib/shapes/sphere-shape.js.map +1 -0
- package/package.json +4 -4
- package/src/index.ts +13 -0
- package/src/lib/bounding-volumes/oriented-bounding-box.ts +2 -1
- package/src/lib/plane.ts +28 -1
- package/src/lib/ray.ts +31 -0
- package/src/lib/shapes/box-shape.ts +78 -0
- package/src/lib/shapes/capsule-shape.ts +232 -0
- package/src/lib/shapes/cylinder-shape.ts +133 -0
- package/src/lib/shapes/implicit-shape.ts +209 -0
- package/src/lib/shapes/plane-shape.ts +78 -0
- package/src/lib/shapes/sphere-shape.ts +60 -0
package/dist/index.cjs
CHANGED
|
@@ -17,14 +17,20 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
17
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
18
18
|
|
|
19
19
|
// dist/index.js
|
|
20
|
-
var
|
|
21
|
-
__export(
|
|
20
|
+
var index_exports = {};
|
|
21
|
+
__export(index_exports, {
|
|
22
22
|
AxisAlignedBoundingBox: () => AxisAlignedBoundingBox,
|
|
23
23
|
BoundingSphere: () => BoundingSphere,
|
|
24
|
+
BoxShape: () => BoxShape,
|
|
25
|
+
CapsuleShape: () => CapsuleShape,
|
|
24
26
|
CullingVolume: () => CullingVolume,
|
|
27
|
+
CylinderShape: () => CylinderShape,
|
|
25
28
|
INTERSECTION: () => INTERSECTION,
|
|
26
29
|
OrientedBoundingBox: () => OrientedBoundingBox,
|
|
27
30
|
Plane: () => Plane,
|
|
31
|
+
PlaneShape: () => PlaneShape,
|
|
32
|
+
Ray: () => Ray,
|
|
33
|
+
SphereShape: () => SphereShape,
|
|
28
34
|
_PerspectiveFrustum: () => PerspectiveFrustum,
|
|
29
35
|
_PerspectiveOffCenterFrustum: () => PerspectiveOffCenterFrustum,
|
|
30
36
|
computeEigenDecomposition: () => computeEigenDecomposition,
|
|
@@ -32,7 +38,7 @@ __export(dist_exports, {
|
|
|
32
38
|
makeBoundingSphereFromPoints: () => makeBoundingSphereFromPoints,
|
|
33
39
|
makeOrientedBoundingBoxFromPoints: () => makeOrientedBoundingBoxFromPoints
|
|
34
40
|
});
|
|
35
|
-
module.exports = __toCommonJS(
|
|
41
|
+
module.exports = __toCommonJS(index_exports);
|
|
36
42
|
|
|
37
43
|
// dist/constants.js
|
|
38
44
|
var INTERSECTION = {
|
|
@@ -48,7 +54,7 @@ var INTERSECTION = {
|
|
|
48
54
|
var import_core = require("@math.gl/core");
|
|
49
55
|
var scratchVector = new import_core.Vector3();
|
|
50
56
|
var scratchNormal = new import_core.Vector3();
|
|
51
|
-
var AxisAlignedBoundingBox = class {
|
|
57
|
+
var AxisAlignedBoundingBox = class _AxisAlignedBoundingBox {
|
|
52
58
|
/**
|
|
53
59
|
* Creates an instance of an AxisAlignedBoundingBox from the minimum and maximum points along the x, y, and z axes.
|
|
54
60
|
* @param minimum=[0, 0, 0] The minimum point along the x, y, and z axes.
|
|
@@ -68,7 +74,7 @@ var AxisAlignedBoundingBox = class {
|
|
|
68
74
|
* @returns {AxisAlignedBoundingBox} A new AxisAlignedBoundingBox instance.
|
|
69
75
|
*/
|
|
70
76
|
clone() {
|
|
71
|
-
return new
|
|
77
|
+
return new _AxisAlignedBoundingBox(this.minimum, this.maximum, this.center);
|
|
72
78
|
}
|
|
73
79
|
/**
|
|
74
80
|
* Compares the provided AxisAlignedBoundingBox componentwise and returns
|
|
@@ -138,7 +144,7 @@ var AxisAlignedBoundingBox = class {
|
|
|
138
144
|
var import_core2 = require("@math.gl/core");
|
|
139
145
|
var scratchVector2 = new import_core2.Vector3();
|
|
140
146
|
var scratchVector22 = new import_core2.Vector3();
|
|
141
|
-
var BoundingSphere = class {
|
|
147
|
+
var BoundingSphere = class _BoundingSphere {
|
|
142
148
|
/** Creates a bounding sphere */
|
|
143
149
|
constructor(center = [0, 0, 0], radius = 0) {
|
|
144
150
|
this.radius = -0;
|
|
@@ -167,7 +173,7 @@ var BoundingSphere = class {
|
|
|
167
173
|
}
|
|
168
174
|
/** Duplicates a BoundingSphere instance. */
|
|
169
175
|
clone() {
|
|
170
|
-
return new
|
|
176
|
+
return new _BoundingSphere(this.center, this.radius);
|
|
171
177
|
}
|
|
172
178
|
/** Computes a bounding sphere that contains both the left and right bounding spheres. */
|
|
173
179
|
union(boundingSphere) {
|
|
@@ -258,7 +264,7 @@ var MATRIX3 = {
|
|
|
258
264
|
COLUMN2ROW1: 7,
|
|
259
265
|
COLUMN2ROW2: 8
|
|
260
266
|
};
|
|
261
|
-
var OrientedBoundingBox = class {
|
|
267
|
+
var OrientedBoundingBox = class _OrientedBoundingBox {
|
|
262
268
|
constructor(center = [0, 0, 0], halfAxes = [0, 0, 0, 0, 0, 0, 0, 0, 0]) {
|
|
263
269
|
this.center = new import_core3.Vector3().from(center);
|
|
264
270
|
this.halfAxes = new import_core3.Matrix3(halfAxes);
|
|
@@ -301,7 +307,7 @@ var OrientedBoundingBox = class {
|
|
|
301
307
|
}
|
|
302
308
|
/** Duplicates a OrientedBoundingBox instance. */
|
|
303
309
|
clone() {
|
|
304
|
-
return new
|
|
310
|
+
return new _OrientedBoundingBox(this.center, this.halfAxes);
|
|
305
311
|
}
|
|
306
312
|
/** Compares the provided OrientedBoundingBox component wise and returns */
|
|
307
313
|
equals(right) {
|
|
@@ -467,7 +473,7 @@ var import_core5 = require("@math.gl/core");
|
|
|
467
473
|
var import_core4 = require("@math.gl/core");
|
|
468
474
|
var scratchPosition = new import_core4.Vector3();
|
|
469
475
|
var scratchNormal2 = new import_core4.Vector3();
|
|
470
|
-
var Plane = class {
|
|
476
|
+
var Plane = class _Plane {
|
|
471
477
|
constructor(normal = [0, 0, 1], distance = 0) {
|
|
472
478
|
this.normal = new import_core4.Vector3();
|
|
473
479
|
this.distance = -0;
|
|
@@ -497,7 +503,7 @@ var Plane = class {
|
|
|
497
503
|
}
|
|
498
504
|
/** Duplicates a Plane instance. */
|
|
499
505
|
clone() {
|
|
500
|
-
return new
|
|
506
|
+
return new _Plane(this.normal, this.distance);
|
|
501
507
|
}
|
|
502
508
|
/** Compares the provided Planes by normal and distance */
|
|
503
509
|
equals(right) {
|
|
@@ -521,13 +527,34 @@ var Plane = class {
|
|
|
521
527
|
const scaledNormal = scratchNormal2.copy(this.normal).scale(pointDistance);
|
|
522
528
|
return scratchPoint.subtract(scaledNormal).to(result);
|
|
523
529
|
}
|
|
530
|
+
/**
|
|
531
|
+
* Computes the intersection of a ray and this plane.
|
|
532
|
+
*
|
|
533
|
+
* @param {Ray} ray The ray.
|
|
534
|
+
* @param {Vector3} [result] The object onto which to store the result.
|
|
535
|
+
* @returns {Vector3} The intersection point or undefined if there is no intersection.
|
|
536
|
+
*/
|
|
537
|
+
intersectWithRay(ray, result = new import_core4.Vector3()) {
|
|
538
|
+
const origin = ray.origin;
|
|
539
|
+
const direction = ray.direction;
|
|
540
|
+
const normal = this.normal;
|
|
541
|
+
const denominator = normal.dot(direction);
|
|
542
|
+
if (Math.abs(denominator) < import_core4._MathUtils.EPSILON15) {
|
|
543
|
+
return void 0;
|
|
544
|
+
}
|
|
545
|
+
const t = (-this.distance - normal.dot(origin)) / denominator;
|
|
546
|
+
if (t < 0) {
|
|
547
|
+
return void 0;
|
|
548
|
+
}
|
|
549
|
+
return result.copy(direction).multiplyByScalar(t).add(origin);
|
|
550
|
+
}
|
|
524
551
|
};
|
|
525
552
|
|
|
526
553
|
// dist/lib/culling-volume.js
|
|
527
554
|
var faces = [new import_core5.Vector3([1, 0, 0]), new import_core5.Vector3([0, 1, 0]), new import_core5.Vector3([0, 0, 1])];
|
|
528
555
|
var scratchPlaneCenter = new import_core5.Vector3();
|
|
529
556
|
var scratchPlaneNormal = new import_core5.Vector3();
|
|
530
|
-
var CullingVolume = class {
|
|
557
|
+
var CullingVolume = class _CullingVolume {
|
|
531
558
|
/**
|
|
532
559
|
* Create a new `CullingVolume` bounded by an array of clipping planed
|
|
533
560
|
* @param planes Array of clipping planes.
|
|
@@ -588,10 +615,10 @@ var CullingVolume = class {
|
|
|
588
615
|
*/
|
|
589
616
|
computeVisibilityWithPlaneMask(boundingVolume, parentPlaneMask) {
|
|
590
617
|
(0, import_core5.assert)(Number.isFinite(parentPlaneMask), "parentPlaneMask is required.");
|
|
591
|
-
if (parentPlaneMask ===
|
|
618
|
+
if (parentPlaneMask === _CullingVolume.MASK_OUTSIDE || parentPlaneMask === _CullingVolume.MASK_INSIDE) {
|
|
592
619
|
return parentPlaneMask;
|
|
593
620
|
}
|
|
594
|
-
let mask =
|
|
621
|
+
let mask = _CullingVolume.MASK_INSIDE;
|
|
595
622
|
const planes = this.planes;
|
|
596
623
|
for (let k = 0; k < this.planes.length; ++k) {
|
|
597
624
|
const flag = k < 31 ? 1 << k : 0;
|
|
@@ -601,7 +628,7 @@ var CullingVolume = class {
|
|
|
601
628
|
const plane = planes[k];
|
|
602
629
|
const result = boundingVolume.intersectPlane(plane);
|
|
603
630
|
if (result === INTERSECTION.OUTSIDE) {
|
|
604
|
-
return
|
|
631
|
+
return _CullingVolume.MASK_OUTSIDE;
|
|
605
632
|
} else if (result === INTERSECTION.INTERSECTING) {
|
|
606
633
|
mask |= flag;
|
|
607
634
|
}
|
|
@@ -613,14 +640,564 @@ CullingVolume.MASK_OUTSIDE = 4294967295;
|
|
|
613
640
|
CullingVolume.MASK_INSIDE = 0;
|
|
614
641
|
CullingVolume.MASK_INDETERMINATE = 2147483647;
|
|
615
642
|
|
|
616
|
-
// dist/lib/
|
|
643
|
+
// dist/lib/ray.js
|
|
617
644
|
var import_core6 = require("@math.gl/core");
|
|
618
|
-
var
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
645
|
+
var Ray = class {
|
|
646
|
+
/**
|
|
647
|
+
* Creates a new ray that extends infinitely from the provided origin in the provided direction.
|
|
648
|
+
*
|
|
649
|
+
* @param [origin=Vector3] The origin of the ray.
|
|
650
|
+
* @param [direction=Vector3] The direction of the ray.
|
|
651
|
+
*/
|
|
652
|
+
constructor(origin, direction) {
|
|
653
|
+
if (origin)
|
|
654
|
+
origin = origin.clone();
|
|
655
|
+
else
|
|
656
|
+
origin = new import_core6.Vector3();
|
|
657
|
+
if (direction)
|
|
658
|
+
direction = direction.clone().normalize();
|
|
659
|
+
else
|
|
660
|
+
direction = new import_core6.Vector3();
|
|
661
|
+
this.origin = origin;
|
|
662
|
+
this.direction = direction;
|
|
663
|
+
}
|
|
664
|
+
};
|
|
665
|
+
|
|
666
|
+
// dist/lib/shapes/implicit-shape.js
|
|
667
|
+
var import_core7 = require("@math.gl/core");
|
|
668
|
+
var ImplicitShapeBase = class {
|
|
669
|
+
constructor(matrix) {
|
|
670
|
+
this.matrix = new import_core7.Matrix4();
|
|
671
|
+
if (matrix)
|
|
672
|
+
this.matrix.copy(matrix);
|
|
673
|
+
validateAffineMatrix(this.matrix);
|
|
674
|
+
this.inverseMatrix = this.matrix.clone().invert();
|
|
675
|
+
}
|
|
676
|
+
equals(shape) {
|
|
677
|
+
if (this.type !== shape.type)
|
|
678
|
+
return false;
|
|
679
|
+
for (let i = 0; i < 16; i++)
|
|
680
|
+
if (this.matrix[i] !== shape.matrix[i])
|
|
681
|
+
return false;
|
|
682
|
+
return true;
|
|
683
|
+
}
|
|
684
|
+
transform(transform) {
|
|
685
|
+
const next = new import_core7.Matrix4().copy(transform);
|
|
686
|
+
validateAffineMatrix(next);
|
|
687
|
+
this.matrix.multiplyLeft(next);
|
|
688
|
+
validateAffineMatrix(this.matrix);
|
|
689
|
+
this.inverseMatrix.copy(this.matrix).invert();
|
|
690
|
+
return this;
|
|
691
|
+
}
|
|
692
|
+
containsPoint(point) {
|
|
693
|
+
return this.containsLocalPoint(this.inverseMatrix.transformAsPoint(point));
|
|
694
|
+
}
|
|
695
|
+
distanceSquaredTo(point) {
|
|
696
|
+
const distance = this.distanceTo(point);
|
|
697
|
+
return distance * distance;
|
|
698
|
+
}
|
|
699
|
+
/** Exact for rigid/uniform transforms; conservative estimate for non-uniform scale or shear. */
|
|
700
|
+
distanceTo(point) {
|
|
701
|
+
const localPoint = this.inverseMatrix.transformAsPoint(point);
|
|
702
|
+
const localDistance = this.distanceToLocalPoint(localPoint);
|
|
703
|
+
const scales = this.matrix.getScale();
|
|
704
|
+
return localDistance * Math.min(scales[0], scales[1], scales[2]);
|
|
705
|
+
}
|
|
706
|
+
intersectPlane(plane) {
|
|
707
|
+
const maximum = this.getSupportPoint(plane.normal);
|
|
708
|
+
const minimum = this.getSupportPoint([-plane.normal[0], -plane.normal[1], -plane.normal[2]]);
|
|
709
|
+
const maxDistance = plane.getPointDistance(maximum);
|
|
710
|
+
const minDistance = plane.getPointDistance(minimum);
|
|
711
|
+
if (minDistance > 0)
|
|
712
|
+
return INTERSECTION.INSIDE;
|
|
713
|
+
if (maxDistance < 0)
|
|
714
|
+
return INTERSECTION.OUTSIDE;
|
|
715
|
+
return INTERSECTION.INTERSECTING;
|
|
716
|
+
}
|
|
717
|
+
intersectRay(ray) {
|
|
718
|
+
const localOrigin = this.inverseMatrix.transformAsPoint(ray.origin);
|
|
719
|
+
const localDirection = this.inverseMatrix.transformAsVector(ray.direction);
|
|
720
|
+
const hit = this.intersectLocalRay(localOrigin, localDirection);
|
|
721
|
+
if (!hit || hit.distance < 0)
|
|
722
|
+
return void 0;
|
|
723
|
+
const point = new import_core7.Vector3(ray.direction).scale(hit.distance).add(ray.origin);
|
|
724
|
+
const inverse = this.inverseMatrix;
|
|
725
|
+
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();
|
|
726
|
+
return { distance: hit.distance, point, normal, entering: ray.direction.dot(normal) < 0 };
|
|
727
|
+
}
|
|
728
|
+
getAxisAlignedBoundingBox() {
|
|
729
|
+
const minimum = new import_core7.Vector3();
|
|
730
|
+
const maximum = new import_core7.Vector3();
|
|
731
|
+
for (let axis = 0; axis < 3; axis++) {
|
|
732
|
+
const direction = [0, 0, 0];
|
|
733
|
+
direction[axis] = 1;
|
|
734
|
+
maximum[axis] = this.getSupportPoint(direction)[axis];
|
|
735
|
+
direction[axis] = -1;
|
|
736
|
+
minimum[axis] = this.getSupportPoint(direction)[axis];
|
|
737
|
+
}
|
|
738
|
+
return new AxisAlignedBoundingBox(minimum, maximum);
|
|
739
|
+
}
|
|
740
|
+
getBoundingSphere() {
|
|
741
|
+
const box = this.getAxisAlignedBoundingBox();
|
|
742
|
+
if (!box)
|
|
743
|
+
return void 0;
|
|
744
|
+
return new BoundingSphere().fromCornerPoints(box.minimum, box.maximum);
|
|
745
|
+
}
|
|
746
|
+
getSupportPoint(worldDirection) {
|
|
747
|
+
const matrix = this.matrix;
|
|
748
|
+
const localDirection = [
|
|
749
|
+
matrix[0] * worldDirection[0] + matrix[1] * worldDirection[1] + matrix[2] * worldDirection[2],
|
|
750
|
+
matrix[4] * worldDirection[0] + matrix[5] * worldDirection[1] + matrix[6] * worldDirection[2],
|
|
751
|
+
matrix[8] * worldDirection[0] + matrix[9] * worldDirection[1] + matrix[10] * worldDirection[2]
|
|
752
|
+
];
|
|
753
|
+
return new import_core7.Vector3(this.supportLocal(localDirection)).transform(this.matrix);
|
|
754
|
+
}
|
|
755
|
+
};
|
|
756
|
+
function validateAffineMatrix(matrix) {
|
|
757
|
+
if (matrix.length !== 16 || matrix.some((value) => !Number.isFinite(value))) {
|
|
758
|
+
throw new Error("Shape matrix must contain 16 finite values");
|
|
759
|
+
}
|
|
760
|
+
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) {
|
|
761
|
+
throw new Error("Shape matrix must be affine");
|
|
762
|
+
}
|
|
763
|
+
if (Math.abs(new import_core7.Matrix4().copy(matrix).determinant()) < 1e-15)
|
|
764
|
+
throw new Error("Shape matrix must be invertible");
|
|
765
|
+
}
|
|
766
|
+
function solveQuadratic(a, b, c) {
|
|
767
|
+
if (Math.abs(a) < 1e-15)
|
|
768
|
+
return Math.abs(b) < 1e-15 ? [] : [-c / b];
|
|
769
|
+
const discriminant = b * b - 4 * a * c;
|
|
770
|
+
if (discriminant < 0)
|
|
771
|
+
return [];
|
|
772
|
+
const root = Math.sqrt(Math.max(0, discriminant));
|
|
773
|
+
return [(-b - root) / (2 * a), (-b + root) / (2 * a)].sort((left, right) => left - right);
|
|
774
|
+
}
|
|
775
|
+
function closestDistanceToSegment2D(px, py, ax, ay, bx, by) {
|
|
776
|
+
const dx = bx - ax;
|
|
777
|
+
const dy = by - ay;
|
|
778
|
+
const denominator = dx * dx + dy * dy;
|
|
779
|
+
const t = denominator ? Math.max(0, Math.min(1, ((px - ax) * dx + (py - ay) * dy) / denominator)) : 0;
|
|
780
|
+
return Math.hypot(px - (ax + t * dx), py - (ay + t * dy));
|
|
781
|
+
}
|
|
782
|
+
function closestDistanceToCircleArc2D(px, py, centerY, radius, minimumNormalY, maximumNormalY) {
|
|
783
|
+
if (radius === 0)
|
|
784
|
+
return Math.hypot(px, py - centerY);
|
|
785
|
+
const dx = px;
|
|
786
|
+
const dy = py - centerY;
|
|
787
|
+
const length = Math.hypot(dx, dy);
|
|
788
|
+
const normalY = length ? dy / length : 0;
|
|
789
|
+
if (normalY >= minimumNormalY && normalY <= maximumNormalY) {
|
|
790
|
+
return Math.abs(length - radius);
|
|
791
|
+
}
|
|
792
|
+
const minimumRadius = radius * Math.sqrt(Math.max(0, 1 - minimumNormalY ** 2));
|
|
793
|
+
const maximumRadius = radius * Math.sqrt(Math.max(0, 1 - maximumNormalY ** 2));
|
|
794
|
+
return Math.min(Math.hypot(px - minimumRadius, py - (centerY + radius * minimumNormalY)), Math.hypot(px - maximumRadius, py - (centerY + radius * maximumNormalY)));
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
// dist/lib/shapes/box-shape.js
|
|
798
|
+
var EPSILON = 1e-6;
|
|
799
|
+
var BoxShape = class _BoxShape extends ImplicitShapeBase {
|
|
800
|
+
constructor(props = {}) {
|
|
801
|
+
super(props.matrix);
|
|
802
|
+
this.type = "box";
|
|
803
|
+
this.size = props.size ? [...props.size] : [1, 1, 1];
|
|
804
|
+
if (this.size.some((value) => !Number.isFinite(value) || value <= 0))
|
|
805
|
+
throw new Error("Box size values must be greater than zero");
|
|
806
|
+
this.halfSize = [this.size[0] / 2, this.size[1] / 2, this.size[2] / 2];
|
|
807
|
+
}
|
|
808
|
+
clone() {
|
|
809
|
+
return new _BoxShape({ size: this.size, matrix: this.matrix });
|
|
810
|
+
}
|
|
811
|
+
equals(shape) {
|
|
812
|
+
return shape instanceof _BoxShape && super.equals(shape) && this.size.every((value, i) => value === shape.size[i]);
|
|
813
|
+
}
|
|
814
|
+
containsLocalPoint(point) {
|
|
815
|
+
return point.every((value, i) => Math.abs(value) <= this.halfSize[i] + EPSILON);
|
|
816
|
+
}
|
|
817
|
+
distanceToLocalPoint(point) {
|
|
818
|
+
return Math.hypot(...point.map((value, i) => Math.max(0, Math.abs(value) - this.halfSize[i])));
|
|
819
|
+
}
|
|
820
|
+
supportLocal(direction) {
|
|
821
|
+
return direction.map((value, i) => value < 0 ? -this.halfSize[i] : this.halfSize[i]);
|
|
822
|
+
}
|
|
823
|
+
intersectLocalRay(origin, direction) {
|
|
824
|
+
let near = -Infinity;
|
|
825
|
+
let far = Infinity;
|
|
826
|
+
let nearAxis = 0;
|
|
827
|
+
let farAxis = 0;
|
|
828
|
+
for (let axis2 = 0; axis2 < 3; axis2++) {
|
|
829
|
+
if (Math.abs(direction[axis2]) < 1e-15) {
|
|
830
|
+
if (Math.abs(origin[axis2]) > this.halfSize[axis2])
|
|
831
|
+
return void 0;
|
|
832
|
+
continue;
|
|
833
|
+
}
|
|
834
|
+
let t1 = (-this.halfSize[axis2] - origin[axis2]) / direction[axis2];
|
|
835
|
+
let t2 = (this.halfSize[axis2] - origin[axis2]) / direction[axis2];
|
|
836
|
+
if (t1 > t2)
|
|
837
|
+
[t1, t2] = [t2, t1];
|
|
838
|
+
if (t1 > near) {
|
|
839
|
+
near = t1;
|
|
840
|
+
nearAxis = axis2;
|
|
841
|
+
}
|
|
842
|
+
if (t2 < far) {
|
|
843
|
+
far = t2;
|
|
844
|
+
farAxis = axis2;
|
|
845
|
+
}
|
|
846
|
+
if (near > far)
|
|
847
|
+
return void 0;
|
|
848
|
+
}
|
|
849
|
+
const distance = near >= 0 ? near : far;
|
|
850
|
+
if (distance < 0 || !Number.isFinite(distance))
|
|
851
|
+
return void 0;
|
|
852
|
+
const axis = near >= 0 ? nearAxis : farAxis;
|
|
853
|
+
const pointCoordinate = origin[axis] + distance * direction[axis];
|
|
854
|
+
const normal = [0, 0, 0];
|
|
855
|
+
normal[axis] = pointCoordinate < 0 ? -1 : 1;
|
|
856
|
+
return { distance, normal };
|
|
857
|
+
}
|
|
858
|
+
};
|
|
859
|
+
|
|
860
|
+
// dist/lib/shapes/capsule-shape.js
|
|
861
|
+
var EPSILON2 = 1e-6;
|
|
862
|
+
var CapsuleShape = class _CapsuleShape extends ImplicitShapeBase {
|
|
863
|
+
constructor(props = {}) {
|
|
864
|
+
super(props.matrix);
|
|
865
|
+
this.type = "capsule";
|
|
866
|
+
this.height = props.height ?? 1;
|
|
867
|
+
this.radiusBottom = props.radiusBottom ?? 0.5;
|
|
868
|
+
this.radiusTop = props.radiusTop ?? 0.5;
|
|
869
|
+
if (!Number.isFinite(this.height) || this.height <= 0)
|
|
870
|
+
throw new Error("Capsule height must be greater than zero");
|
|
871
|
+
if (![this.radiusBottom, this.radiusTop].every((value) => Number.isFinite(value) && value >= 0))
|
|
872
|
+
throw new Error("Capsule radii must be non-negative");
|
|
873
|
+
if (this.radiusBottom === 0 && this.radiusTop === 0)
|
|
874
|
+
throw new Error("At least one capsule radius must be greater than zero");
|
|
875
|
+
}
|
|
876
|
+
clone() {
|
|
877
|
+
return new _CapsuleShape({
|
|
878
|
+
height: this.height,
|
|
879
|
+
radiusBottom: this.radiusBottom,
|
|
880
|
+
radiusTop: this.radiusTop,
|
|
881
|
+
matrix: this.matrix
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
equals(shape) {
|
|
885
|
+
return shape instanceof _CapsuleShape && super.equals(shape) && this.height === shape.height && this.radiusBottom === shape.radiusBottom && this.radiusTop === shape.radiusTop;
|
|
886
|
+
}
|
|
887
|
+
containsLocalPoint(point) {
|
|
888
|
+
const profile = this.getProfile();
|
|
889
|
+
const radial = Math.hypot(point[0], point[2]);
|
|
890
|
+
if (profile.sphere)
|
|
891
|
+
return Math.hypot(radial, point[1] - profile.sphere.center) <= profile.sphere.radius + EPSILON2;
|
|
892
|
+
if (point[1] < profile.bottom.y)
|
|
893
|
+
return Math.hypot(radial, point[1] + this.height / 2) <= this.radiusBottom + EPSILON2;
|
|
894
|
+
if (point[1] > profile.top.y)
|
|
895
|
+
return Math.hypot(radial, point[1] - this.height / 2) <= this.radiusTop + EPSILON2;
|
|
896
|
+
const t = (point[1] - profile.bottom.y) / (profile.top.y - profile.bottom.y);
|
|
897
|
+
return radial <= profile.bottom.radius + (profile.top.radius - profile.bottom.radius) * t + EPSILON2;
|
|
898
|
+
}
|
|
899
|
+
distanceToLocalPoint(point) {
|
|
900
|
+
if (this.containsLocalPoint(point))
|
|
901
|
+
return 0;
|
|
902
|
+
const profile = this.getProfile();
|
|
903
|
+
const radial = Math.hypot(point[0], point[2]);
|
|
904
|
+
if (profile.sphere)
|
|
905
|
+
return Math.max(0, Math.hypot(radial, point[1] - profile.sphere.center) - profile.sphere.radius);
|
|
906
|
+
const delta = this.radiusTop - this.radiusBottom;
|
|
907
|
+
const sideNormalY = -delta / this.height;
|
|
908
|
+
const bottomArc = closestDistanceToCircleArc2D(radial, point[1], -this.height / 2, this.radiusBottom, -1, sideNormalY);
|
|
909
|
+
const topArc = closestDistanceToCircleArc2D(radial, point[1], this.height / 2, this.radiusTop, sideNormalY, 1);
|
|
910
|
+
const side = closestDistanceToSegment2D(radial, point[1], profile.bottom.radius, profile.bottom.y, profile.top.radius, profile.top.y);
|
|
911
|
+
return Math.min(bottomArc, topArc, side);
|
|
912
|
+
}
|
|
913
|
+
supportLocal(direction) {
|
|
914
|
+
const length = Math.hypot(...direction);
|
|
915
|
+
const unit = length ? direction.map((value) => value / length) : [1, 0, 0];
|
|
916
|
+
const bottom = [
|
|
917
|
+
unit[0] * this.radiusBottom,
|
|
918
|
+
-this.height / 2 + unit[1] * this.radiusBottom,
|
|
919
|
+
unit[2] * this.radiusBottom
|
|
920
|
+
];
|
|
921
|
+
const top = [
|
|
922
|
+
unit[0] * this.radiusTop,
|
|
923
|
+
this.height / 2 + unit[1] * this.radiusTop,
|
|
924
|
+
unit[2] * this.radiusTop
|
|
925
|
+
];
|
|
926
|
+
return dot(top, direction) >= dot(bottom, direction) ? top : bottom;
|
|
927
|
+
}
|
|
928
|
+
intersectLocalRay(origin, direction) {
|
|
929
|
+
const profile = this.getProfile();
|
|
930
|
+
if (profile.sphere)
|
|
931
|
+
return intersectSphere(origin, direction, profile.sphere.center, profile.sphere.radius);
|
|
932
|
+
const candidates = [];
|
|
933
|
+
const slope = (profile.top.radius - profile.bottom.radius) / (profile.top.y - profile.bottom.y);
|
|
934
|
+
const intercept = profile.bottom.radius - slope * profile.bottom.y;
|
|
935
|
+
const radialAtOrigin = intercept + slope * origin[1];
|
|
936
|
+
const radialAlongRay = slope * direction[1];
|
|
937
|
+
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)) {
|
|
938
|
+
const y = origin[1] + distance * direction[1];
|
|
939
|
+
if (distance >= 0 && y >= profile.bottom.y - EPSILON2 && y <= profile.top.y + EPSILON2) {
|
|
940
|
+
const x = origin[0] + distance * direction[0];
|
|
941
|
+
const z = origin[2] + distance * direction[2];
|
|
942
|
+
const radial = Math.hypot(x, z) || 1;
|
|
943
|
+
const normal = [x / radial, -slope, z / radial];
|
|
944
|
+
const length = Math.hypot(...normal);
|
|
945
|
+
candidates.push({ distance, normal: normal.map((value) => value / length) });
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
for (const bottomHit of intersectSphereRoots(origin, direction, -this.height / 2, this.radiusBottom)) {
|
|
949
|
+
const y = origin[1] + bottomHit.distance * direction[1];
|
|
950
|
+
if (y <= profile.bottom.y + EPSILON2)
|
|
951
|
+
candidates.push(bottomHit);
|
|
952
|
+
}
|
|
953
|
+
for (const topHit of intersectSphereRoots(origin, direction, this.height / 2, this.radiusTop)) {
|
|
954
|
+
const y = origin[1] + topHit.distance * direction[1];
|
|
955
|
+
if (y >= profile.top.y - EPSILON2)
|
|
956
|
+
candidates.push(topHit);
|
|
957
|
+
}
|
|
958
|
+
return candidates.sort((a, b) => a.distance - b.distance)[0];
|
|
959
|
+
}
|
|
960
|
+
getProfile() {
|
|
961
|
+
const delta = this.radiusTop - this.radiusBottom;
|
|
962
|
+
if (Math.abs(delta) >= this.height) {
|
|
963
|
+
const topWins = this.radiusTop >= this.radiusBottom;
|
|
964
|
+
return {
|
|
965
|
+
sphere: {
|
|
966
|
+
center: topWins ? this.height / 2 : -this.height / 2,
|
|
967
|
+
radius: topWins ? this.radiusTop : this.radiusBottom
|
|
968
|
+
},
|
|
969
|
+
bottom: { radius: 0, y: 0 },
|
|
970
|
+
top: { radius: 0, y: 0 }
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
const sinSlope = delta / this.height;
|
|
974
|
+
const radialNormal = Math.sqrt(1 - sinSlope * sinSlope);
|
|
975
|
+
const normalY = -sinSlope;
|
|
976
|
+
return {
|
|
977
|
+
bottom: {
|
|
978
|
+
radius: this.radiusBottom * radialNormal,
|
|
979
|
+
y: -this.height / 2 + this.radiusBottom * normalY
|
|
980
|
+
},
|
|
981
|
+
top: { radius: this.radiusTop * radialNormal, y: this.height / 2 + this.radiusTop * normalY }
|
|
982
|
+
};
|
|
983
|
+
}
|
|
984
|
+
};
|
|
985
|
+
function intersectSphere(origin, direction, centerY, radius) {
|
|
986
|
+
return intersectSphereRoots(origin, direction, centerY, radius)[0];
|
|
987
|
+
}
|
|
988
|
+
function intersectSphereRoots(origin, direction, centerY, radius) {
|
|
989
|
+
if (radius === 0)
|
|
990
|
+
return [];
|
|
991
|
+
const relative = [origin[0], origin[1] - centerY, origin[2]];
|
|
992
|
+
return solveQuadratic(dot(direction, direction), 2 * dot(relative, direction), dot(relative, relative) - radius * radius).filter((distance) => distance >= 0).map((distance) => ({
|
|
993
|
+
distance,
|
|
994
|
+
normal: relative.map((value, i) => (value + distance * direction[i]) / radius)
|
|
995
|
+
}));
|
|
996
|
+
}
|
|
997
|
+
function dot(a, b) {
|
|
998
|
+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
// dist/lib/shapes/cylinder-shape.js
|
|
1002
|
+
var EPSILON3 = 1e-6;
|
|
1003
|
+
var CylinderShape = class _CylinderShape extends ImplicitShapeBase {
|
|
1004
|
+
constructor(props = {}) {
|
|
1005
|
+
super(props.matrix);
|
|
1006
|
+
this.type = "cylinder";
|
|
1007
|
+
this.height = props.height ?? 2;
|
|
1008
|
+
this.radiusBottom = props.radiusBottom ?? 0.5;
|
|
1009
|
+
this.radiusTop = props.radiusTop ?? 0.5;
|
|
1010
|
+
if (!Number.isFinite(this.height) || this.height <= 0)
|
|
1011
|
+
throw new Error("Cylinder height must be greater than zero");
|
|
1012
|
+
if (![this.radiusBottom, this.radiusTop].every((value) => Number.isFinite(value) && value >= 0))
|
|
1013
|
+
throw new Error("Cylinder radii must be non-negative");
|
|
1014
|
+
if (this.radiusBottom === 0 && this.radiusTop === 0)
|
|
1015
|
+
throw new Error("At least one cylinder radius must be greater than zero");
|
|
1016
|
+
}
|
|
1017
|
+
clone() {
|
|
1018
|
+
return new _CylinderShape({
|
|
1019
|
+
height: this.height,
|
|
1020
|
+
radiusBottom: this.radiusBottom,
|
|
1021
|
+
radiusTop: this.radiusTop,
|
|
1022
|
+
matrix: this.matrix
|
|
1023
|
+
});
|
|
1024
|
+
}
|
|
1025
|
+
equals(shape) {
|
|
1026
|
+
return shape instanceof _CylinderShape && super.equals(shape) && this.height === shape.height && this.radiusBottom === shape.radiusBottom && this.radiusTop === shape.radiusTop;
|
|
1027
|
+
}
|
|
1028
|
+
containsLocalPoint(point) {
|
|
1029
|
+
const half = this.height / 2;
|
|
1030
|
+
if (point[1] < -half - EPSILON3 || point[1] > half + EPSILON3)
|
|
1031
|
+
return false;
|
|
1032
|
+
const t = (point[1] + half) / this.height;
|
|
1033
|
+
const radius = this.radiusBottom + (this.radiusTop - this.radiusBottom) * t;
|
|
1034
|
+
return Math.hypot(point[0], point[2]) <= radius + EPSILON3;
|
|
1035
|
+
}
|
|
1036
|
+
distanceToLocalPoint(point) {
|
|
1037
|
+
if (this.containsLocalPoint(point))
|
|
1038
|
+
return 0;
|
|
1039
|
+
const radial = Math.hypot(point[0], point[2]);
|
|
1040
|
+
const half = this.height / 2;
|
|
1041
|
+
const side = closestDistanceToSegment2D(radial, point[1], this.radiusBottom, -half, this.radiusTop, half);
|
|
1042
|
+
const bottom = closestDistanceToSegment2D(radial, point[1], 0, -half, this.radiusBottom, -half);
|
|
1043
|
+
const top = closestDistanceToSegment2D(radial, point[1], 0, half, this.radiusTop, half);
|
|
1044
|
+
return Math.min(side, bottom, top);
|
|
1045
|
+
}
|
|
1046
|
+
supportLocal(direction) {
|
|
1047
|
+
const radialLength = Math.hypot(direction[0], direction[2]);
|
|
1048
|
+
const x = radialLength ? direction[0] / radialLength : 1;
|
|
1049
|
+
const z = radialLength ? direction[2] / radialLength : 0;
|
|
1050
|
+
const half = this.height / 2;
|
|
1051
|
+
const bottomValue = radialLength * this.radiusBottom - direction[1] * half;
|
|
1052
|
+
const topValue = radialLength * this.radiusTop + direction[1] * half;
|
|
1053
|
+
return topValue >= bottomValue ? [x * this.radiusTop, half, z * this.radiusTop] : [x * this.radiusBottom, -half, z * this.radiusBottom];
|
|
1054
|
+
}
|
|
1055
|
+
intersectLocalRay(origin, direction) {
|
|
1056
|
+
const half = this.height / 2;
|
|
1057
|
+
const slope = (this.radiusTop - this.radiusBottom) / this.height;
|
|
1058
|
+
const intercept = (this.radiusTop + this.radiusBottom) / 2;
|
|
1059
|
+
const radialAtOrigin = intercept + slope * origin[1];
|
|
1060
|
+
const radialAlongRay = slope * direction[1];
|
|
1061
|
+
const candidates = [];
|
|
1062
|
+
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);
|
|
1063
|
+
for (const distance of roots) {
|
|
1064
|
+
const y = origin[1] + distance * direction[1];
|
|
1065
|
+
if (distance >= 0 && y >= -half - EPSILON3 && y <= half + EPSILON3) {
|
|
1066
|
+
const x = origin[0] + distance * direction[0];
|
|
1067
|
+
const z = origin[2] + distance * direction[2];
|
|
1068
|
+
const radial = Math.hypot(x, z) || 1;
|
|
1069
|
+
const normal = [x / radial, -slope, z / radial];
|
|
1070
|
+
const length = Math.hypot(...normal);
|
|
1071
|
+
candidates.push({ distance, normal: normal.map((value) => value / length) });
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1074
|
+
if (Math.abs(direction[1]) > 1e-15) {
|
|
1075
|
+
for (const [y, radius, normalY] of [
|
|
1076
|
+
[-half, this.radiusBottom, -1],
|
|
1077
|
+
[half, this.radiusTop, 1]
|
|
1078
|
+
]) {
|
|
1079
|
+
const distance = (y - origin[1]) / direction[1];
|
|
1080
|
+
const x = origin[0] + distance * direction[0];
|
|
1081
|
+
const z = origin[2] + distance * direction[2];
|
|
1082
|
+
if (distance >= 0 && Math.hypot(x, z) <= radius + EPSILON3)
|
|
1083
|
+
candidates.push({ distance, normal: [0, normalY, 0] });
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
return candidates.sort((a, b) => a.distance - b.distance)[0];
|
|
1087
|
+
}
|
|
1088
|
+
};
|
|
1089
|
+
|
|
1090
|
+
// dist/lib/shapes/plane-shape.js
|
|
1091
|
+
var import_core8 = require("@math.gl/core");
|
|
1092
|
+
var PlaneShape = class _PlaneShape extends ImplicitShapeBase {
|
|
1093
|
+
constructor(props = {}) {
|
|
1094
|
+
super(props.matrix);
|
|
1095
|
+
this.type = "plane";
|
|
1096
|
+
this.sizeX = props.sizeX;
|
|
1097
|
+
this.sizeZ = props.sizeZ;
|
|
1098
|
+
if (this.sizeX !== void 0 && (!Number.isFinite(this.sizeX) || this.sizeX <= 0))
|
|
1099
|
+
throw new Error("Plane sizeX must be greater than zero");
|
|
1100
|
+
if (this.sizeZ !== void 0 && (!Number.isFinite(this.sizeZ) || this.sizeZ <= 0))
|
|
1101
|
+
throw new Error("Plane sizeZ must be greater than zero");
|
|
1102
|
+
}
|
|
1103
|
+
clone() {
|
|
1104
|
+
return new _PlaneShape({ sizeX: this.sizeX, sizeZ: this.sizeZ, matrix: this.matrix });
|
|
1105
|
+
}
|
|
1106
|
+
equals(shape) {
|
|
1107
|
+
return shape instanceof _PlaneShape && super.equals(shape) && this.sizeX === shape.sizeX && this.sizeZ === shape.sizeZ;
|
|
1108
|
+
}
|
|
1109
|
+
containsLocalPoint(point) {
|
|
1110
|
+
return point[1] <= 1e-12;
|
|
1111
|
+
}
|
|
1112
|
+
distanceToLocalPoint(point) {
|
|
1113
|
+
return Math.max(0, point[1]);
|
|
1114
|
+
}
|
|
1115
|
+
supportLocal() {
|
|
1116
|
+
throw new Error("An unbounded plane half-space has no finite support point");
|
|
1117
|
+
}
|
|
1118
|
+
intersectLocalRay(origin, direction) {
|
|
1119
|
+
if (Math.abs(direction[1]) < 1e-15)
|
|
1120
|
+
return void 0;
|
|
1121
|
+
const distance = -origin[1] / direction[1];
|
|
1122
|
+
if (distance < 0)
|
|
1123
|
+
return void 0;
|
|
1124
|
+
const x = origin[0] + distance * direction[0];
|
|
1125
|
+
const z = origin[2] + distance * direction[2];
|
|
1126
|
+
if (this.sizeX !== void 0 && Math.abs(x) > this.sizeX / 2 + 1e-12)
|
|
1127
|
+
return void 0;
|
|
1128
|
+
if (this.sizeZ !== void 0 && Math.abs(z) > this.sizeZ / 2 + 1e-12)
|
|
1129
|
+
return void 0;
|
|
1130
|
+
return { distance, normal: [0, 1, 0] };
|
|
1131
|
+
}
|
|
1132
|
+
intersectPlane(plane) {
|
|
1133
|
+
const boundaryPoint = new import_core8.Vector3(0, 0, 0).transform(this.matrix);
|
|
1134
|
+
const inverse = this.inverseMatrix;
|
|
1135
|
+
const boundaryNormal = new import_core8.Vector3(inverse[1], inverse[5], inverse[9]).normalize();
|
|
1136
|
+
const alignment = boundaryNormal.dot(plane.normal);
|
|
1137
|
+
if (Math.abs(Math.abs(alignment) - 1) > 1e-10)
|
|
1138
|
+
return INTERSECTION.INTERSECTING;
|
|
1139
|
+
const boundaryDistance = plane.getPointDistance(boundaryPoint);
|
|
1140
|
+
if (alignment < 0 && boundaryDistance > 0)
|
|
1141
|
+
return INTERSECTION.INSIDE;
|
|
1142
|
+
if (alignment > 0 && boundaryDistance < 0)
|
|
1143
|
+
return INTERSECTION.OUTSIDE;
|
|
1144
|
+
return INTERSECTION.INTERSECTING;
|
|
1145
|
+
}
|
|
1146
|
+
getAxisAlignedBoundingBox() {
|
|
1147
|
+
return void 0;
|
|
1148
|
+
}
|
|
1149
|
+
getBoundingSphere() {
|
|
1150
|
+
return void 0;
|
|
1151
|
+
}
|
|
1152
|
+
};
|
|
1153
|
+
|
|
1154
|
+
// dist/lib/shapes/sphere-shape.js
|
|
1155
|
+
var EPSILON4 = 1e-6;
|
|
1156
|
+
var SphereShape = class _SphereShape extends ImplicitShapeBase {
|
|
1157
|
+
constructor(props = {}) {
|
|
1158
|
+
super(props.matrix);
|
|
1159
|
+
this.type = "sphere";
|
|
1160
|
+
this.radius = props.radius ?? 0.5;
|
|
1161
|
+
if (!Number.isFinite(this.radius) || this.radius <= 0)
|
|
1162
|
+
throw new Error("Sphere radius must be greater than zero");
|
|
1163
|
+
}
|
|
1164
|
+
clone() {
|
|
1165
|
+
return new _SphereShape({ radius: this.radius, matrix: this.matrix });
|
|
1166
|
+
}
|
|
1167
|
+
equals(shape) {
|
|
1168
|
+
return shape instanceof _SphereShape && super.equals(shape) && this.radius === shape.radius;
|
|
1169
|
+
}
|
|
1170
|
+
containsLocalPoint(point) {
|
|
1171
|
+
return Math.hypot(...point) <= this.radius + EPSILON4;
|
|
1172
|
+
}
|
|
1173
|
+
distanceToLocalPoint(point) {
|
|
1174
|
+
return Math.max(0, Math.hypot(...point) - this.radius);
|
|
1175
|
+
}
|
|
1176
|
+
supportLocal(direction) {
|
|
1177
|
+
const length = Math.hypot(...direction);
|
|
1178
|
+
return length ? direction.map((value) => value / length * this.radius) : [this.radius, 0, 0];
|
|
1179
|
+
}
|
|
1180
|
+
intersectLocalRay(origin, direction) {
|
|
1181
|
+
const roots = solveQuadratic(dot2(direction, direction), 2 * dot2(origin, direction), dot2(origin, origin) - this.radius * this.radius);
|
|
1182
|
+
const distance = roots.find((value) => value >= 0);
|
|
1183
|
+
if (distance === void 0)
|
|
1184
|
+
return void 0;
|
|
1185
|
+
const point = origin.map((value, i) => value + distance * direction[i]);
|
|
1186
|
+
return { distance, normal: point.map((value) => value / this.radius) };
|
|
1187
|
+
}
|
|
1188
|
+
};
|
|
1189
|
+
function dot2(a, b) {
|
|
1190
|
+
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
// dist/lib/perspective-off-center-frustum.js
|
|
1194
|
+
var import_core9 = require("@math.gl/core");
|
|
1195
|
+
var scratchPlaneUpVector = new import_core9.Vector3();
|
|
1196
|
+
var scratchPlaneRightVector = new import_core9.Vector3();
|
|
1197
|
+
var scratchPlaneNearCenter = new import_core9.Vector3();
|
|
1198
|
+
var scratchPlaneFarCenter = new import_core9.Vector3();
|
|
1199
|
+
var scratchPlaneNormal2 = new import_core9.Vector3();
|
|
1200
|
+
var PerspectiveOffCenterFrustum = class _PerspectiveOffCenterFrustum {
|
|
624
1201
|
/**
|
|
625
1202
|
* The viewing frustum is defined by 6 planes.
|
|
626
1203
|
* Each plane is represented by a {@link Vector4} object, where the x, y, and z components
|
|
@@ -650,8 +1227,8 @@ var PerspectiveOffCenterFrustum = class {
|
|
|
650
1227
|
new Plane(),
|
|
651
1228
|
new Plane()
|
|
652
1229
|
]);
|
|
653
|
-
this._perspectiveMatrix = new
|
|
654
|
-
this._infinitePerspective = new
|
|
1230
|
+
this._perspectiveMatrix = new import_core9.Matrix4();
|
|
1231
|
+
this._infinitePerspective = new import_core9.Matrix4();
|
|
655
1232
|
const { near = 1, far = 5e8 } = options;
|
|
656
1233
|
this.left = options.left;
|
|
657
1234
|
this._left = void 0;
|
|
@@ -671,7 +1248,7 @@ var PerspectiveOffCenterFrustum = class {
|
|
|
671
1248
|
* @returns {PerspectiveOffCenterFrustum} A new PerspectiveFrustum instance.
|
|
672
1249
|
* */
|
|
673
1250
|
clone() {
|
|
674
|
-
return new
|
|
1251
|
+
return new _PerspectiveOffCenterFrustum({
|
|
675
1252
|
right: this.right,
|
|
676
1253
|
left: this.left,
|
|
677
1254
|
top: this.top,
|
|
@@ -687,7 +1264,7 @@ var PerspectiveOffCenterFrustum = class {
|
|
|
687
1264
|
* @returns {Boolean} <code>true</code> if they are equal, <code>false</code> otherwise.
|
|
688
1265
|
*/
|
|
689
1266
|
equals(other) {
|
|
690
|
-
return other && other instanceof
|
|
1267
|
+
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;
|
|
691
1268
|
}
|
|
692
1269
|
/**
|
|
693
1270
|
* Gets the perspective projection matrix computed from the view frustum.
|
|
@@ -722,9 +1299,9 @@ var PerspectiveOffCenterFrustum = class {
|
|
|
722
1299
|
*/
|
|
723
1300
|
// eslint-disable-next-line complexity, max-statements
|
|
724
1301
|
computeCullingVolume(position, direction, up) {
|
|
725
|
-
(0,
|
|
726
|
-
(0,
|
|
727
|
-
(0,
|
|
1302
|
+
(0, import_core9.assert)(position, "position is required.");
|
|
1303
|
+
(0, import_core9.assert)(direction, "direction is required.");
|
|
1304
|
+
(0, import_core9.assert)(up, "up is required.");
|
|
728
1305
|
const planes = this._cullingVolume.planes;
|
|
729
1306
|
up = scratchPlaneUpVector.copy(up).normalize();
|
|
730
1307
|
const right = scratchPlaneRightVector.copy(direction).cross(up).normalize();
|
|
@@ -739,7 +1316,7 @@ var PerspectiveOffCenterFrustum = class {
|
|
|
739
1316
|
planes[2].fromPointNormal(position, normal);
|
|
740
1317
|
normal.copy(up).multiplyByScalar(this.top).add(nearCenter).subtract(position).cross(right);
|
|
741
1318
|
planes[3].fromPointNormal(position, normal);
|
|
742
|
-
normal = new
|
|
1319
|
+
normal = new import_core9.Vector3().copy(direction);
|
|
743
1320
|
planes[4].fromPointNormal(nearCenter, normal);
|
|
744
1321
|
normal.negate();
|
|
745
1322
|
planes[5].fromPointNormal(farCenter, normal);
|
|
@@ -771,11 +1348,11 @@ var PerspectiveOffCenterFrustum = class {
|
|
|
771
1348
|
*/
|
|
772
1349
|
getPixelDimensions(drawingBufferWidth, drawingBufferHeight, distance, result) {
|
|
773
1350
|
this._update();
|
|
774
|
-
(0,
|
|
775
|
-
(0,
|
|
776
|
-
(0,
|
|
777
|
-
(0,
|
|
778
|
-
(0,
|
|
1351
|
+
(0, import_core9.assert)(Number.isFinite(drawingBufferWidth) && Number.isFinite(drawingBufferHeight));
|
|
1352
|
+
(0, import_core9.assert)(drawingBufferWidth > 0);
|
|
1353
|
+
(0, import_core9.assert)(drawingBufferHeight > 0);
|
|
1354
|
+
(0, import_core9.assert)(distance > 0);
|
|
1355
|
+
(0, import_core9.assert)(result);
|
|
779
1356
|
const inverseNear = 1 / this.near;
|
|
780
1357
|
let tanTheta = this.top * inverseNear;
|
|
781
1358
|
const pixelHeight = 2 * distance * tanTheta / drawingBufferHeight;
|
|
@@ -787,17 +1364,17 @@ var PerspectiveOffCenterFrustum = class {
|
|
|
787
1364
|
}
|
|
788
1365
|
// eslint-disable-next-line complexity, max-statements
|
|
789
1366
|
_update() {
|
|
790
|
-
(0,
|
|
1367
|
+
(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));
|
|
791
1368
|
const { top, bottom, right, left, near, far } = this;
|
|
792
1369
|
if (top !== this._top || bottom !== this._bottom || left !== this._left || right !== this._right || near !== this._near || far !== this._far) {
|
|
793
|
-
(0,
|
|
1370
|
+
(0, import_core9.assert)(this.near > 0 && this.near < this.far, "near must be greater than zero and less than far.");
|
|
794
1371
|
this._left = left;
|
|
795
1372
|
this._right = right;
|
|
796
1373
|
this._top = top;
|
|
797
1374
|
this._bottom = bottom;
|
|
798
1375
|
this._near = near;
|
|
799
1376
|
this._far = far;
|
|
800
|
-
this._perspectiveMatrix = new
|
|
1377
|
+
this._perspectiveMatrix = new import_core9.Matrix4().frustum({
|
|
801
1378
|
left,
|
|
802
1379
|
right,
|
|
803
1380
|
bottom,
|
|
@@ -805,7 +1382,7 @@ var PerspectiveOffCenterFrustum = class {
|
|
|
805
1382
|
near,
|
|
806
1383
|
far
|
|
807
1384
|
});
|
|
808
|
-
this._infinitePerspective = new
|
|
1385
|
+
this._infinitePerspective = new import_core9.Matrix4().frustum({
|
|
809
1386
|
left,
|
|
810
1387
|
right,
|
|
811
1388
|
bottom,
|
|
@@ -818,9 +1395,9 @@ var PerspectiveOffCenterFrustum = class {
|
|
|
818
1395
|
};
|
|
819
1396
|
|
|
820
1397
|
// dist/lib/perspective-frustum.js
|
|
821
|
-
var
|
|
1398
|
+
var import_core10 = require("@math.gl/core");
|
|
822
1399
|
var defined = (val) => val !== null && typeof val !== "undefined";
|
|
823
|
-
var PerspectiveFrustum = class {
|
|
1400
|
+
var PerspectiveFrustum = class _PerspectiveFrustum {
|
|
824
1401
|
constructor(options = {}) {
|
|
825
1402
|
this._offCenterFrustum = new PerspectiveOffCenterFrustum();
|
|
826
1403
|
const { fov, aspectRatio, near = 1, far = 5e8, xOffset = 0, yOffset = 0 } = options;
|
|
@@ -835,7 +1412,7 @@ var PerspectiveFrustum = class {
|
|
|
835
1412
|
* Returns a duplicate of a PerspectiveFrustum instance.
|
|
836
1413
|
*/
|
|
837
1414
|
clone() {
|
|
838
|
-
return new
|
|
1415
|
+
return new _PerspectiveFrustum({
|
|
839
1416
|
aspectRatio: this.aspectRatio,
|
|
840
1417
|
fov: this.fov,
|
|
841
1418
|
near: this.near,
|
|
@@ -847,7 +1424,7 @@ var PerspectiveFrustum = class {
|
|
|
847
1424
|
* <code>true</code> if they are equal, <code>false</code> otherwise.
|
|
848
1425
|
*/
|
|
849
1426
|
equals(other) {
|
|
850
|
-
if (!defined(other) || !(other instanceof
|
|
1427
|
+
if (!defined(other) || !(other instanceof _PerspectiveFrustum)) {
|
|
851
1428
|
return false;
|
|
852
1429
|
}
|
|
853
1430
|
this._update();
|
|
@@ -920,16 +1497,16 @@ var PerspectiveFrustum = class {
|
|
|
920
1497
|
*/
|
|
921
1498
|
getPixelDimensions(drawingBufferWidth, drawingBufferHeight, distance, result) {
|
|
922
1499
|
this._update();
|
|
923
|
-
return this._offCenterFrustum.getPixelDimensions(drawingBufferWidth, drawingBufferHeight, distance, result || new
|
|
1500
|
+
return this._offCenterFrustum.getPixelDimensions(drawingBufferWidth, drawingBufferHeight, distance, result || new import_core10.Vector2());
|
|
924
1501
|
}
|
|
925
1502
|
// eslint-disable-next-line complexity, max-statements
|
|
926
1503
|
_update() {
|
|
927
|
-
(0,
|
|
1504
|
+
(0, import_core10.assert)(Number.isFinite(this.fov) && Number.isFinite(this.aspectRatio) && Number.isFinite(this.near) && Number.isFinite(this.far));
|
|
928
1505
|
const f = this._offCenterFrustum;
|
|
929
1506
|
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) {
|
|
930
|
-
(0,
|
|
931
|
-
(0,
|
|
932
|
-
(0,
|
|
1507
|
+
(0, import_core10.assert)(this.fov >= 0 && this.fov < Math.PI);
|
|
1508
|
+
(0, import_core10.assert)(this.aspectRatio > 0);
|
|
1509
|
+
(0, import_core10.assert)(this.near >= 0 && this.near < this.far);
|
|
933
1510
|
this._aspectRatio = this.aspectRatio;
|
|
934
1511
|
this._fov = this.fov;
|
|
935
1512
|
this._fovy = this.aspectRatio <= 1 ? this.fov : Math.atan(Math.tan(this.fov * 0.5) / this.aspectRatio) * 2;
|
|
@@ -953,19 +1530,19 @@ var PerspectiveFrustum = class {
|
|
|
953
1530
|
};
|
|
954
1531
|
|
|
955
1532
|
// dist/lib/algorithms/bounding-sphere-from-points.js
|
|
956
|
-
var
|
|
957
|
-
var fromPointsXMin = new
|
|
958
|
-
var fromPointsYMin = new
|
|
959
|
-
var fromPointsZMin = new
|
|
960
|
-
var fromPointsXMax = new
|
|
961
|
-
var fromPointsYMax = new
|
|
962
|
-
var fromPointsZMax = new
|
|
963
|
-
var fromPointsCurrentPos = new
|
|
964
|
-
var fromPointsScratch = new
|
|
965
|
-
var fromPointsRitterCenter = new
|
|
966
|
-
var fromPointsMinBoxPt = new
|
|
967
|
-
var fromPointsMaxBoxPt = new
|
|
968
|
-
var fromPointsNaiveCenterScratch = new
|
|
1533
|
+
var import_core11 = require("@math.gl/core");
|
|
1534
|
+
var fromPointsXMin = new import_core11.Vector3();
|
|
1535
|
+
var fromPointsYMin = new import_core11.Vector3();
|
|
1536
|
+
var fromPointsZMin = new import_core11.Vector3();
|
|
1537
|
+
var fromPointsXMax = new import_core11.Vector3();
|
|
1538
|
+
var fromPointsYMax = new import_core11.Vector3();
|
|
1539
|
+
var fromPointsZMax = new import_core11.Vector3();
|
|
1540
|
+
var fromPointsCurrentPos = new import_core11.Vector3();
|
|
1541
|
+
var fromPointsScratch = new import_core11.Vector3();
|
|
1542
|
+
var fromPointsRitterCenter = new import_core11.Vector3();
|
|
1543
|
+
var fromPointsMinBoxPt = new import_core11.Vector3();
|
|
1544
|
+
var fromPointsMaxBoxPt = new import_core11.Vector3();
|
|
1545
|
+
var fromPointsNaiveCenterScratch = new import_core11.Vector3();
|
|
969
1546
|
function makeBoundingSphereFromPoints(positions, result = new BoundingSphere()) {
|
|
970
1547
|
if (!positions || positions.length === 0) {
|
|
971
1548
|
return result.fromCenterRadius([0, 0, 0], 0);
|
|
@@ -1061,17 +1638,17 @@ function makeBoundingSphereFromPoints(positions, result = new BoundingSphere())
|
|
|
1061
1638
|
}
|
|
1062
1639
|
|
|
1063
1640
|
// dist/lib/algorithms/bounding-box-from-points.js
|
|
1064
|
-
var
|
|
1641
|
+
var import_core13 = require("@math.gl/core");
|
|
1065
1642
|
|
|
1066
1643
|
// dist/lib/algorithms/compute-eigen-decomposition.js
|
|
1067
|
-
var
|
|
1068
|
-
var scratchMatrix = new
|
|
1069
|
-
var scratchUnitary = new
|
|
1070
|
-
var scratchDiagonal = new
|
|
1071
|
-
var jMatrix = new
|
|
1072
|
-
var jMatrixTranspose = new
|
|
1644
|
+
var import_core12 = require("@math.gl/core");
|
|
1645
|
+
var scratchMatrix = new import_core12.Matrix3();
|
|
1646
|
+
var scratchUnitary = new import_core12.Matrix3();
|
|
1647
|
+
var scratchDiagonal = new import_core12.Matrix3();
|
|
1648
|
+
var jMatrix = new import_core12.Matrix3();
|
|
1649
|
+
var jMatrixTranspose = new import_core12.Matrix3();
|
|
1073
1650
|
function computeEigenDecomposition(matrix, result = {}) {
|
|
1074
|
-
const EIGEN_TOLERANCE =
|
|
1651
|
+
const EIGEN_TOLERANCE = import_core12._MathUtils.EPSILON20;
|
|
1075
1652
|
const EIGEN_MAX_SWEEPS = 10;
|
|
1076
1653
|
let count = 0;
|
|
1077
1654
|
let sweep = 0;
|
|
@@ -1114,7 +1691,7 @@ function offDiagonalFrobeniusNorm(matrix) {
|
|
|
1114
1691
|
return Math.sqrt(norm);
|
|
1115
1692
|
}
|
|
1116
1693
|
function shurDecomposition(matrix, result) {
|
|
1117
|
-
const tolerance =
|
|
1694
|
+
const tolerance = import_core12._MathUtils.EPSILON15;
|
|
1118
1695
|
let maxDiagonal = 0;
|
|
1119
1696
|
let rotAxis = 1;
|
|
1120
1697
|
for (let i = 0; i < 3; ++i) {
|
|
@@ -1142,7 +1719,7 @@ function shurDecomposition(matrix, result) {
|
|
|
1142
1719
|
c = 1 / Math.sqrt(1 + t * t);
|
|
1143
1720
|
s = t * c;
|
|
1144
1721
|
}
|
|
1145
|
-
|
|
1722
|
+
import_core12.Matrix3.IDENTITY.to(result);
|
|
1146
1723
|
result[scratchMatrix.getElementIndex(p, p)] = result[scratchMatrix.getElementIndex(q, q)] = c;
|
|
1147
1724
|
result[scratchMatrix.getElementIndex(q, p)] = s;
|
|
1148
1725
|
result[scratchMatrix.getElementIndex(p, q)] = -s;
|
|
@@ -1150,24 +1727,24 @@ function shurDecomposition(matrix, result) {
|
|
|
1150
1727
|
}
|
|
1151
1728
|
|
|
1152
1729
|
// dist/lib/algorithms/bounding-box-from-points.js
|
|
1153
|
-
var scratchVector23 = new
|
|
1154
|
-
var scratchVector32 = new
|
|
1155
|
-
var scratchVector4 = new
|
|
1156
|
-
var scratchVector5 = new
|
|
1157
|
-
var scratchVector6 = new
|
|
1158
|
-
var scratchCovarianceResult = new
|
|
1730
|
+
var scratchVector23 = new import_core13.Vector3();
|
|
1731
|
+
var scratchVector32 = new import_core13.Vector3();
|
|
1732
|
+
var scratchVector4 = new import_core13.Vector3();
|
|
1733
|
+
var scratchVector5 = new import_core13.Vector3();
|
|
1734
|
+
var scratchVector6 = new import_core13.Vector3();
|
|
1735
|
+
var scratchCovarianceResult = new import_core13.Matrix3();
|
|
1159
1736
|
var scratchEigenResult = {
|
|
1160
|
-
diagonal: new
|
|
1161
|
-
unitary: new
|
|
1737
|
+
diagonal: new import_core13.Matrix3(),
|
|
1738
|
+
unitary: new import_core13.Matrix3()
|
|
1162
1739
|
};
|
|
1163
1740
|
function makeOrientedBoundingBoxFromPoints(positions, result = new OrientedBoundingBox()) {
|
|
1164
1741
|
if (!positions || positions.length === 0) {
|
|
1165
|
-
result.halfAxes = new
|
|
1166
|
-
result.center = new
|
|
1742
|
+
result.halfAxes = new import_core13.Matrix3([0, 0, 0, 0, 0, 0, 0, 0, 0]);
|
|
1743
|
+
result.center = new import_core13.Vector3();
|
|
1167
1744
|
return result;
|
|
1168
1745
|
}
|
|
1169
1746
|
const length = positions.length;
|
|
1170
|
-
const meanPoint = new
|
|
1747
|
+
const meanPoint = new import_core13.Vector3(0, 0, 0);
|
|
1171
1748
|
for (const position of positions) {
|
|
1172
1749
|
meanPoint.add(position);
|
|
1173
1750
|
}
|
|
@@ -1229,7 +1806,7 @@ function makeOrientedBoundingBoxFromPoints(positions, result = new OrientedBound
|
|
|
1229
1806
|
v3 = v3.multiplyByScalar(0.5 * (l3 + u3));
|
|
1230
1807
|
result.center.copy(v1).add(v2).add(v3);
|
|
1231
1808
|
const scale = scratchVector32.set(u1 - l1, u2 - l2, u3 - l3).multiplyByScalar(0.5);
|
|
1232
|
-
const scaleMatrix = new
|
|
1809
|
+
const scaleMatrix = new import_core13.Matrix3([scale[0], 0, 0, 0, scale[1], 0, 0, 0, scale[2]]);
|
|
1233
1810
|
result.halfAxes.multiplyRight(scaleMatrix);
|
|
1234
1811
|
return result;
|
|
1235
1812
|
}
|