@perplexdotgg/bounce 1.0.0 → 1.0.1

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.
Files changed (134) hide show
  1. package/build/bounce.d.ts +39501 -0
  2. package/build/bounce.js +17166 -0
  3. package/package.json +1 -1
  4. package/src/builders/ConvexHullBuilder.ts +0 -437
  5. package/src/builders/ConvexHullBuilder2d.ts +0 -344
  6. package/src/builders/ConvexHullBuilder3d.ts +0 -1689
  7. package/src/builders/HeightMapBuilder.ts +0 -414
  8. package/src/builders/TriangleMeshBuilder.ts +0 -92
  9. package/src/collision/CastShapesModule.ts +0 -184
  10. package/src/collision/CollideShapesModule.ts +0 -152
  11. package/src/collision/HeightMapCaster.ts +0 -38
  12. package/src/collision/HeightMapCollider.ts +0 -33
  13. package/src/collision/TriangleCaster.ts +0 -249
  14. package/src/collision/TriangleCollider.ts +0 -308
  15. package/src/collision/TriangleCollider2.ts +0 -379
  16. package/src/collision/activeEdge.ts +0 -146
  17. package/src/collision/cast/cast.ts +0 -139
  18. package/src/collision/cast/castCompoundVsCompound.ts +0 -59
  19. package/src/collision/cast/castCompoundVsConvex.ts +0 -116
  20. package/src/collision/cast/castConvexVsCompound.ts +0 -123
  21. package/src/collision/cast/castConvexVsConvex.ts +0 -213
  22. package/src/collision/cast/castConvexVsHeightMap.ts +0 -73
  23. package/src/collision/cast/castConvexVsTriangleMesh.ts +0 -56
  24. package/src/collision/cast/castRayVsCompound.ts +0 -44
  25. package/src/collision/cast/castRayVsConvex.ts +0 -45
  26. package/src/collision/cast/castRayVsHeightMap.ts +0 -58
  27. package/src/collision/cast/castRayVsTriangleMesh.ts +0 -58
  28. package/src/collision/closestPoints/closestPoints.ts +0 -23
  29. package/src/collision/closestPoints/computeBarycentricCoordinates2d.ts +0 -32
  30. package/src/collision/closestPoints/computeBarycentricCoordinates3d.ts +0 -81
  31. package/src/collision/closestPoints/computeClosestPointOnLine.ts +0 -30
  32. package/src/collision/closestPoints/computeClosestPointOnTetrahedron.ts +0 -96
  33. package/src/collision/closestPoints/computeClosestPointOnTriangle.ts +0 -195
  34. package/src/collision/closestPoints/isOriginOutsideOfPlane.ts +0 -25
  35. package/src/collision/closestPoints/isOriginOutsideOfTrianglePlanes.ts +0 -72
  36. package/src/collision/collide/collide.ts +0 -146
  37. package/src/collision/collide/collideCompoundVsCompound.ts +0 -60
  38. package/src/collision/collide/collideCompoundVsConvex.ts +0 -59
  39. package/src/collision/collide/collideCompoundVsHeightMap.ts +0 -73
  40. package/src/collision/collide/collideCompoundVsTriangleMesh.ts +0 -56
  41. package/src/collision/collide/collideConvexVsCompound.ts +0 -57
  42. package/src/collision/collide/collideConvexVsConvex.ts +0 -225
  43. package/src/collision/collide/collideConvexVsConvexImp.ts +0 -236
  44. package/src/collision/collide/collideConvexVsHeightMap.ts +0 -53
  45. package/src/collision/collide/collideConvexVsTriangleMesh.ts +0 -58
  46. package/src/collision/collide/collideHeightMapVsCompound.ts +0 -69
  47. package/src/collision/collide/collideHeightMapVsConvex.ts +0 -53
  48. package/src/collision/collide/collideSphereVsSphere.ts +0 -81
  49. package/src/collision/collide/collideTriangleMeshVsCompound.ts +0 -58
  50. package/src/collision/collide/collideTriangleMeshVsConvex.ts +0 -58
  51. package/src/collision/epa/EpaConvexHullBuilder.ts +0 -397
  52. package/src/collision/epa/StaticArray.ts +0 -154
  53. package/src/collision/epa/TriangleFactory.ts +0 -32
  54. package/src/collision/epa/arrays.ts +0 -99
  55. package/src/collision/epa/binaryHeap.ts +0 -82
  56. package/src/collision/epa/structs.ts +0 -227
  57. package/src/collision/gjk/GjkModule.ts +0 -864
  58. package/src/collision/gjk/PenetrationDepthModule.ts +0 -493
  59. package/src/collision/gjk/SupportPoints.ts +0 -50
  60. package/src/collision/imp/MinkowskiDifference.ts +0 -36
  61. package/src/collision/imp/computeExploredDistanceLowerUpperBound.ts +0 -40
  62. package/src/collision/imp/finalizeImpResult.ts +0 -69
  63. package/src/collision/imp/findContactImp.ts +0 -196
  64. package/src/collision/imp/imp.ts +0 -28
  65. package/src/collision/imp/incrementalMinimumDistanceExploreDirection.ts +0 -207
  66. package/src/collision/mpr/findPortal.ts +0 -152
  67. package/src/collision/mpr/mpr.ts +0 -29
  68. package/src/collision/mpr/updatePortal.ts +0 -52
  69. package/src/constraints/BaseConstraint.ts +0 -50
  70. package/src/constraints/ConstraintOptions.ts +0 -22
  71. package/src/constraints/ConstraintSolver.ts +0 -119
  72. package/src/constraints/DistanceConstraint.ts +0 -229
  73. package/src/constraints/FixedConstraint.ts +0 -203
  74. package/src/constraints/HingeConstraint.ts +0 -460
  75. package/src/constraints/PointConstraint.ts +0 -108
  76. package/src/constraints/components/AngleComponent.ts +0 -226
  77. package/src/constraints/components/AxisComponent.ts +0 -263
  78. package/src/constraints/components/HingeComponent.ts +0 -215
  79. package/src/constraints/components/Motor.ts +0 -36
  80. package/src/constraints/components/PointConstraintComponent.ts +0 -179
  81. package/src/constraints/components/RotationEulerComponent.ts +0 -139
  82. package/src/constraints/components/Spring.ts +0 -30
  83. package/src/constraints/components/SpringComponent.ts +0 -71
  84. package/src/constraints/types.ts +0 -6
  85. package/src/helpers.ts +0 -147
  86. package/src/index.ts +0 -50
  87. package/src/math/BasicTransform.ts +0 -19
  88. package/src/math/NumberValue.ts +0 -13
  89. package/src/math/isometry.ts +0 -64
  90. package/src/math/mat3.ts +0 -529
  91. package/src/math/mat4.ts +0 -588
  92. package/src/math/quat.ts +0 -193
  93. package/src/math/scalar.ts +0 -81
  94. package/src/math/tensor.ts +0 -17
  95. package/src/math/vec3.ts +0 -589
  96. package/src/math/vec4.ts +0 -10
  97. package/src/physics/Body.ts +0 -581
  98. package/src/physics/CollisionFilter.ts +0 -52
  99. package/src/physics/SleepModule.ts +0 -163
  100. package/src/physics/broadphase/BodyPairsModule.ts +0 -363
  101. package/src/physics/broadphase/BvhModule.ts +0 -237
  102. package/src/physics/broadphase/BvhTree.ts +0 -803
  103. package/src/physics/broadphase/ConstraintPairsModule.ts +0 -385
  104. package/src/physics/broadphase/TriangleMeshBvhTree.ts +0 -379
  105. package/src/physics/manifold/ContactManifold.ts +0 -227
  106. package/src/physics/manifold/ContactManifoldModule.ts +0 -623
  107. package/src/physics/manifold/Face.ts +0 -119
  108. package/src/physics/manifold/ManifoldCache.ts +0 -116
  109. package/src/physics/manifold/clipping/clipPolyVsEdge.ts +0 -131
  110. package/src/physics/manifold/clipping/clipPolyVsPlane.ts +0 -73
  111. package/src/physics/manifold/clipping/clipPolyVsPoly.ts +0 -72
  112. package/src/physics/narrowphase/CollideBodiesModule.ts +0 -755
  113. package/src/physics/solver/ContactConstraintModule.ts +0 -659
  114. package/src/physics/solver/ManifoldConstraint.ts +0 -420
  115. package/src/physics/solver/estimateCollisionResponse.ts +0 -146
  116. package/src/shape/Aabb.ts +0 -400
  117. package/src/shape/Box.ts +0 -231
  118. package/src/shape/Capsule.ts +0 -332
  119. package/src/shape/CompoundShape.ts +0 -288
  120. package/src/shape/Convex.ts +0 -130
  121. package/src/shape/ConvexHull.ts +0 -423
  122. package/src/shape/Cylinder.ts +0 -313
  123. package/src/shape/HeightMap.ts +0 -511
  124. package/src/shape/Line.ts +0 -14
  125. package/src/shape/Plane.ts +0 -116
  126. package/src/shape/Ray.ts +0 -81
  127. package/src/shape/Segment.ts +0 -25
  128. package/src/shape/Shape.ts +0 -77
  129. package/src/shape/Sphere.ts +0 -181
  130. package/src/shape/TransformedShape.ts +0 -51
  131. package/src/shape/Triangle.ts +0 -122
  132. package/src/shape/TriangleMesh.ts +0 -186
  133. package/src/types.ts +0 -1
  134. package/src/world.ts +0 -1335
@@ -1,864 +0,0 @@
1
- import { BooleanType, createClass, MonomorphType, NumberType, PropertyDefinitionMap } from "monomorph";
2
- import { Vec3 } from "../../math/vec3";
3
- import { computeBarycentricCoordinates2d } from "../closestPoints/computeBarycentricCoordinates2d";
4
- import { computeBarycentricCoordinates3d } from "../closestPoints/computeBarycentricCoordinates3d";
5
- import { BarycentricCoordinatesResult, ClosestPointResult } from "../closestPoints/closestPoints";
6
- import { isClose, squared } from "../../math/scalar";
7
- import { computeClosestPointOnLine } from "../closestPoints/computeClosestPointOnLine";
8
- import { computeClosestPointOnTriangle } from "../closestPoints/computeClosestPointOnTriangle";
9
- import { computeClosestPointOnTetrahedron } from "../closestPoints/computeClosestPointOnTetrahedron";
10
- import { Isometry } from "../../math/isometry";
11
- import { SupportShape, TransformedConvexObject } from "../../shape/Convex";
12
- import { SupportPoints } from "./SupportPoints";
13
- import { Ray } from "../../shape/Ray";
14
-
15
- const closestPointToSimplexProps = {
16
- point: MonomorphType(Vec3),
17
- squaredDistance: NumberType(0),
18
- pointSet: NumberType(0),
19
- closestPointFound: BooleanType(false),
20
- } as const satisfies PropertyDefinitionMap;
21
-
22
- export class ClosestPointToSimplex extends createClass<ClosestPointToSimplex, typeof closestPointToSimplexProps>(
23
- closestPointToSimplexProps
24
- ) {}
25
-
26
- const gjkClosestPointsProps = {
27
- squaredDistance: NumberType(0),
28
- penetrationAxis: MonomorphType(Vec3),
29
- pointA: MonomorphType(Vec3),
30
- pointB: MonomorphType(Vec3),
31
- } as const satisfies PropertyDefinitionMap;
32
-
33
- export class GjkClosestPoints extends createClass<GjkClosestPoints, typeof gjkClosestPointsProps>(
34
- gjkClosestPointsProps
35
- ) {
36
- reset(): void {
37
- this.pointA.zero();
38
- this.pointB.zero();
39
- this.penetrationAxis.zero();
40
- this.squaredDistance = 0;
41
- }
42
- }
43
-
44
- const gjkCastShapeResultProps = {
45
- isHitFound: BooleanType(false),
46
- lambda: NumberType(0),
47
- separatingAxis: MonomorphType(Vec3),
48
- pointA: MonomorphType(Vec3),
49
- pointB: MonomorphType(Vec3),
50
- } as const satisfies PropertyDefinitionMap;
51
-
52
- export class GjkCastShapeResult extends createClass<GjkCastShapeResult, typeof gjkCastShapeResultProps>(
53
- gjkCastShapeResultProps
54
- ) {
55
- reset(): void {
56
- this.isHitFound = false;
57
- this.pointA.zero();
58
- this.pointB.zero();
59
- this.separatingAxis.zero();
60
- this.lambda = 1;
61
- }
62
- }
63
-
64
- type Simplex = [Vec3, Vec3, Vec3, Vec3];
65
-
66
- const transformedConvexObject = /*@__PURE__*/ new TransformedConvexObject();
67
-
68
- const y0 = /*@__PURE__*/ Vec3.create();
69
- const y1 = /*@__PURE__*/ Vec3.create();
70
- const y2 = /*@__PURE__*/ Vec3.create();
71
- const y3 = /*@__PURE__*/ Vec3.create();
72
- const ys: Simplex = [y0, y1, y2, y3];
73
-
74
- const p0 = /*@__PURE__*/ Vec3.create();
75
- const p1 = /*@__PURE__*/ Vec3.create();
76
- const p2 = /*@__PURE__*/ Vec3.create();
77
- const p3 = /*@__PURE__*/ Vec3.create();
78
- const ps: Simplex = [p0, p1, p2, p3];
79
-
80
- const q0 = /*@__PURE__*/ Vec3.create();
81
- const q1 = /*@__PURE__*/ Vec3.create();
82
- const q2 = /*@__PURE__*/ Vec3.create();
83
- const q3 = /*@__PURE__*/ Vec3.create();
84
- const qs: Simplex = [q0, q1, q2, q3];
85
-
86
- const bary = /*@__PURE__*/ BarycentricCoordinatesResult.create();
87
-
88
- const closest = /*@__PURE__*/ ClosestPointResult.create();
89
-
90
- const p = /*@__PURE__*/ Vec3.create();
91
- const q = /*@__PURE__*/ Vec3.create();
92
- const w = /*@__PURE__*/ Vec3.create();
93
- const directionA = /*@__PURE__*/ Vec3.create();
94
- const directionB = /*@__PURE__*/ Vec3.create();
95
- const closestPointToSimplex = /*@__PURE__*/ ClosestPointToSimplex.create();
96
-
97
- const directionA_2 = /*@__PURE__*/ Vec3.create();
98
- const directionB_2 = /*@__PURE__*/ Vec3.create();
99
- const x = /*@__PURE__*/ Vec3.create();
100
- const prev_v = /*@__PURE__*/ Vec3.create();
101
- const pq = /*@__PURE__*/ Vec3.create();
102
- const normalized_v = /*@__PURE__*/ Vec3.create();
103
- const convex_radius_a = /*@__PURE__*/ Vec3.create();
104
- const convex_radius_b = /*@__PURE__*/ Vec3.create();
105
- const zero = /*@__PURE__*/ Vec3.create();
106
-
107
- // Calculate closest points on A and B
108
- function computePointsAAndB(outPointA: Vec3, outPointB: Vec3, numPoints: number): void {
109
- outPointA.zero();
110
- outPointB.zero();
111
-
112
- switch (numPoints) {
113
- case 1: {
114
- outPointA.copy(ps[0]);
115
- outPointB.copy(qs[0]);
116
- break;
117
- }
118
-
119
- case 2: {
120
- computeBarycentricCoordinates2d(bary, ys[0], ys[1]);
121
-
122
- outPointA.addScaled(ps[0], bary.u);
123
- outPointA.addScaled(ps[1], bary.v);
124
-
125
- outPointB.addScaled(qs[0], bary.u);
126
- outPointB.addScaled(qs[1], bary.v);
127
- break;
128
- }
129
-
130
- case 3: {
131
- computeBarycentricCoordinates3d(bary, ys[0], ys[1], ys[2]);
132
-
133
- outPointA.addScaled(ps[0], bary.u);
134
- outPointA.addScaled(ps[1], bary.v);
135
- outPointA.addScaled(ps[2], bary.w);
136
-
137
- outPointB.addScaled(qs[0], bary.u);
138
- outPointB.addScaled(qs[1], bary.v);
139
- outPointB.addScaled(qs[2], bary.w);
140
- break;
141
- }
142
-
143
- default: {
144
- break;
145
- }
146
- }
147
- }
148
-
149
- function getMaxYLengthSquared(numPoints: number): number {
150
- let yLengthSquared = ys[0].squaredLength();
151
- for (let i = 1; i < numPoints; ++i) {
152
- yLengthSquared = Math.max(yLengthSquared, ys[i].squaredLength());
153
- }
154
- return yLengthSquared;
155
- }
156
-
157
- // Remove points that are not in the set, only updates mP
158
- function updatePointSetP(inSet: number, numPoints: number): number {
159
- let newNumPoints = 0;
160
- for (let i = 0; i < numPoints; ++i) {
161
- if ((inSet & (1 << i)) !== 0) {
162
- ps[newNumPoints].copy(ps[i]);
163
- ++newNumPoints;
164
- }
165
- }
166
- return newNumPoints;
167
- }
168
-
169
- // Remove points that are not in the set, only updates mP and mQ
170
- function updatePointSetPQ(inSet: number, numPoints: number): number {
171
- let newNumPoints = 0;
172
- for (let i = 0; i < numPoints; ++i) {
173
- if ((inSet & (1 << i)) !== 0) {
174
- ps[newNumPoints].copy(ps[i]);
175
- qs[newNumPoints].copy(qs[i]);
176
- ++newNumPoints;
177
- }
178
- }
179
- return newNumPoints;
180
- }
181
-
182
- // Remove points that are not in the set, updates y, p, q
183
- function updatePointSetYPQ(inSet: number, numPoints: number): number {
184
- let newNumPoints = 0;
185
- for (let i = 0; i < numPoints; ++i) {
186
- if ((inSet & (1 << i)) !== 0) {
187
- ys[newNumPoints].copy(ys[i]);
188
- ps[newNumPoints].copy(ps[i]);
189
- qs[newNumPoints].copy(qs[i]);
190
- ++newNumPoints;
191
- }
192
- }
193
- return newNumPoints;
194
- }
195
-
196
- const vvv = /*@__PURE__*/ Vec3.create();
197
-
198
- function getClosest(
199
- inPrevVLenSq: number,
200
- outV: Vec3,
201
- outVLenSq: { value: number },
202
- outSet: { value: number },
203
- lastPointPartOfClosestFeature: boolean,
204
- numPoints: number,
205
- simplex: Simplex
206
- ): boolean {
207
- let set = 0;
208
- vvv.zero();
209
-
210
- switch (numPoints) {
211
- // Single point
212
- case 1: {
213
- set = 0b0001;
214
- vvv.copy(ys[0]);
215
- break;
216
- }
217
-
218
- // Line segment
219
- case 2: {
220
- computeClosestPointOnLine(closest, simplex[0], simplex[1]);
221
- set = closest.pointSet;
222
- vvv.copy(closest.point);
223
- break;
224
- }
225
- // Triangle
226
- case 3: {
227
- computeClosestPointOnTriangle(closest, simplex[0], simplex[1], simplex[2], lastPointPartOfClosestFeature);
228
- set = closest.pointSet;
229
- vvv.copy(closest.point);
230
- break;
231
- }
232
-
233
- // Tetrahedron
234
- case 4: {
235
- computeClosestPointOnTetrahedron(
236
- closest,
237
- simplex[0],
238
- simplex[1],
239
- simplex[2],
240
- simplex[3],
241
- lastPointPartOfClosestFeature
242
- );
243
- set = closest.pointSet;
244
- vvv.copy(closest.point);
245
- break;
246
- }
247
- default: {
248
- throw new Error("Invalid number of points in simplex");
249
- }
250
- }
251
-
252
- let v_len_sq = vvv.squaredLength();
253
- // Note, comparison order important: If v_len_sq is NaN then this expression will be false so we will return false
254
- if (v_len_sq < inPrevVLenSq) {
255
- // Return closest point
256
- outV.copy(vvv);
257
- outVLenSq.value = v_len_sq;
258
- outSet.value = set;
259
- return true;
260
- }
261
-
262
- // No better match found
263
- return false;
264
- }
265
-
266
- function computeClosestPointToSimplex(
267
- result: ClosestPointToSimplex,
268
- inPreviousSquaredDistance: number,
269
- lastPointPartOfClosestFeature: boolean,
270
- simplex: Simplex,
271
- numPoints: number
272
- ): void {
273
- switch (numPoints) {
274
- case 1: {
275
- // Single point
276
- closest.pointSet = 0b0001;
277
- closest.point.copy(simplex[0]);
278
- break;
279
- }
280
-
281
- case 2: {
282
- // Line segment
283
- computeClosestPointOnLine(closest, simplex[0], simplex[1]);
284
- break;
285
- }
286
-
287
- case 3: {
288
- // Triangle
289
- computeClosestPointOnTriangle(closest, simplex[0], simplex[1], simplex[2], lastPointPartOfClosestFeature);
290
- break;
291
- }
292
-
293
- case 4: {
294
- // Tetrahedron
295
- computeClosestPointOnTetrahedron(
296
- closest,
297
- simplex[0],
298
- simplex[1],
299
- simplex[2],
300
- simplex[3],
301
- lastPointPartOfClosestFeature
302
- );
303
- break;
304
- }
305
-
306
- default: {
307
- throw new Error("Invalid number of points");
308
- }
309
- }
310
-
311
- const squaredDistance = closest.point.squaredLength();
312
- if (squaredDistance < inPreviousSquaredDistance) {
313
- // Note, comparison order important: If v_len_sq is NaN then this expression will be false so we will return false
314
-
315
- // Return closest point
316
- result.point.copy(closest.point);
317
- result.squaredDistance = squaredDistance;
318
- result.pointSet = closest.pointSet;
319
- result.closestPointFound = true;
320
- return;
321
- }
322
-
323
- // No better match found
324
- // logDebug("New closer point is further away, failed to converge");
325
- result.closestPointFound = false;
326
- }
327
-
328
- export interface GjkModuleSettings {
329
- maxIterations: number;
330
- tolerance: number;
331
- }
332
-
333
- export class GjkModule {
334
- numPoints: number;
335
- settings: GjkModuleSettings;
336
- maxIterations: number;
337
- tolerance: number;
338
-
339
- constructor(settings: Partial<GjkModuleSettings> = {}) {
340
- this.numPoints = 0;
341
- this.settings = {
342
- ...GjkModule.createDefaultSettings(),
343
- ...settings,
344
- };
345
- this.maxIterations = this.settings.maxIterations;
346
- this.tolerance = this.settings.tolerance;
347
- }
348
-
349
- static createDefaultSettings(): GjkModuleSettings {
350
- return {
351
- maxIterations: 100,
352
- tolerance: 1e-5,
353
- };
354
- }
355
-
356
- getClosestPointsSimplex(supportPoints: SupportPoints) {
357
- for (let i = 0; i < this.numPoints; i++) {
358
- supportPoints.mY.pushBackCopy(ys[i]);
359
- supportPoints.mP.pushBackCopy(ps[i]);
360
- supportPoints.mQ.pushBackCopy(qs[i]);
361
- }
362
- }
363
-
364
- getClosestPoints(
365
- result: GjkClosestPoints,
366
- inA: SupportShape,
367
- inB: SupportShape,
368
- inTolerance: number,
369
- inMaxDistanceSquared: number,
370
- inDirection: Vec3
371
- ): void {
372
- const squaredTolerance = squared(inTolerance);
373
-
374
- // Reset state
375
- this.numPoints = 0;
376
-
377
- // Length^2 of v
378
- closestPointToSimplex.squaredDistance = inDirection.squaredLength();
379
- closestPointToSimplex.point.copy(inDirection);
380
-
381
- // Previous length^2 of v
382
- // TODO: there was a bug here caused by using Infinity instead of Number.MAX_VALUE due to the value being used in a comparison, is this or similar happening anywhere else?
383
- // let previousSquaredDistance = Infinity;
384
- let previousSquaredDistance = Number.MAX_VALUE;
385
-
386
- let iterations = 0;
387
- while (iterations++ < this.maxIterations) {
388
- // #v-ifdef DEV
389
- if (this.numPoints >= 4) {
390
- throw new Error("numPoints >= 4");
391
- }
392
- // #v-endif
393
-
394
- // Get support points for shape A and B in the direction of v
395
- directionA.copy(closestPointToSimplex.point);
396
- directionB.negateVector(closestPointToSimplex.point);
397
- inA.computeSupport(p, directionA);
398
- inB.computeSupport(q, directionB);
399
-
400
- // Get support point of the minkowski sum A - B of v
401
- w.subtractVectors(p, q);
402
-
403
- const dot = closestPointToSimplex.point.dot(w);
404
-
405
- // Test if we have a separation of more than inMaxDistSq, in which case we terminate early
406
- if (dot < 0.0 && dot * dot > closestPointToSimplex.squaredDistance * inMaxDistanceSquared) {
407
- result.squaredDistance = Infinity;
408
- return;
409
- }
410
-
411
- // Store the point for later use
412
- ys[this.numPoints].copy(w);
413
- ps[this.numPoints].copy(p);
414
- qs[this.numPoints].copy(q);
415
- ++this.numPoints;
416
-
417
- closestPointToSimplex.pointSet = 0;
418
- computeClosestPointToSimplex(closestPointToSimplex, previousSquaredDistance, true, ys, this.numPoints);
419
- if (!closestPointToSimplex.closestPointFound) {
420
- // Undo add last point
421
- --this.numPoints;
422
- break;
423
- }
424
-
425
- // If there are 4 points, the origin is inside the tetrahedron and we're done
426
- if (closestPointToSimplex.pointSet === 0xf) {
427
- // logDebug("Full simplex");
428
- closestPointToSimplex.point.zero();
429
- closestPointToSimplex.squaredDistance = 0.0;
430
- break;
431
- }
432
-
433
- // Update the points of the simplex
434
- this.numPoints = updatePointSetYPQ(closestPointToSimplex.pointSet, this.numPoints);
435
-
436
- // If v is very close to zero, we consider this a collision
437
- if (closestPointToSimplex.squaredDistance <= squaredTolerance) {
438
- // logDebug("Distance zero");
439
- closestPointToSimplex.point.zero();
440
- closestPointToSimplex.squaredDistance = 0.0;
441
- break;
442
- }
443
-
444
- // If v is very small compared to the length of y, we also consider this a collision
445
- if (closestPointToSimplex.squaredDistance <= this.tolerance * getMaxYLengthSquared(this.numPoints)) {
446
- // logDebug("Machine precision reached");
447
- closestPointToSimplex.point.zero();
448
- closestPointToSimplex.squaredDistance = 0.0;
449
- break;
450
- }
451
-
452
- // The next seperation axis to test is the negative of the closest point of the Minkowski sum to the origin
453
- // Note: This must be done before terminating as converged since the separating axis is -v
454
- closestPointToSimplex.point.negate();
455
-
456
- // #v-ifdef DEV
457
- // If the squared length of v is not changing enough, we've converged and there is no collision
458
- if (previousSquaredDistance < closestPointToSimplex.squaredDistance) {
459
- throw new Error("squared distance not decreasing");
460
- }
461
- // #v-endif
462
-
463
- if (previousSquaredDistance - closestPointToSimplex.squaredDistance <= this.tolerance * previousSquaredDistance) {
464
- // v is a separating axis
465
- // logDebug("Converged");
466
- break;
467
- }
468
-
469
- previousSquaredDistance = closestPointToSimplex.squaredDistance;
470
- }
471
-
472
- // Get the closest points
473
- computePointsAAndB(result.pointA, result.pointB, this.numPoints);
474
-
475
- // #v-ifdef DEV
476
- // assert ioV.LengthSq() == v_len_sq;
477
- if (!isClose(closestPointToSimplex.point.squaredLength(), closestPointToSimplex.squaredDistance, 1e-3)) {
478
- throw new Error("closest point squared length is not equal to closest squared distance");
479
- }
480
- // #v-endif
481
-
482
- result.squaredDistance = closestPointToSimplex.squaredDistance;
483
- result.penetrationAxis.copy(closestPointToSimplex.point); //ioV
484
- }
485
-
486
- castShape(
487
- result: GjkCastShapeResult, // contains return_value, ioLambda (lambda), outPointA (pointA), outPointB (pointB), outSeparatingAxis (separatingAxis)
488
- inStart: Isometry,
489
- inDirection: Vec3,
490
- inTolerance: number,
491
- inA: SupportShape,
492
- inB: SupportShape,
493
- inConvexRadiusA: number,
494
- inConvexRadiusB: number
495
- ): void {
496
- zero.zero();
497
-
498
- let squaredTolerance = squared(inTolerance);
499
-
500
- // Calculate how close A and B (without their convex radius) need to be to each other in order for us to consider this a collision
501
- const sum_convex_radius = inConvexRadiusA + inConvexRadiusB;
502
-
503
- // Transform the shape to be cast to the starting position
504
- const transformed_a = transformedConvexObject;
505
- transformed_a.setData(inStart, inA);
506
-
507
- // Reset state
508
- this.numPoints = 0;
509
-
510
- let lambda = 0.0;
511
-
512
- // Since A is already transformed we can start the cast from zero
513
- x.zero();
514
-
515
- directionB_2.zero();
516
- inB.computeSupport(q, directionB_2);
517
- q.negate();
518
-
519
- directionA_2.zero();
520
- transformed_a.computeSupport(p, directionA_2);
521
-
522
- // SOURCE
523
- // vec3.add(closest.point, q, p);
524
- // CHANGE
525
- closestPointToSimplex.point.subtractVectors(q, p);
526
-
527
- // let v_len_sq = Number.MAX_VALUE;
528
- closestPointToSimplex.squaredDistance = Number.MAX_VALUE;
529
- let allow_restart = false;
530
-
531
- // Keeps track of separating axis of the previous iteration.
532
- // Initialized at zero as we don't know if our first v is actually a separating axis.
533
- prev_v.zero();
534
-
535
- let iterations = 0;
536
- while (iterations++ < this.maxIterations) {
537
- // Calculate the minkowski difference inB - inA
538
- // inA is moving, so we need to add the back side of inB to the front side of inA
539
- // Keep the support points on A and B separate so that in the end we can calculate a contact point
540
- directionA_2.negateVector(closestPointToSimplex.point);
541
- transformed_a.computeSupport(p, directionA_2);
542
-
543
- directionB_2.copy(closestPointToSimplex.point);
544
- inB.computeSupport(q, directionB_2);
545
-
546
- pq.subtractVectors(q, p);
547
- w.subtractVectors(x, pq);
548
-
549
- // Difference from article to this code:
550
- // We did not include the convex radius in p and q in order to be able to calculate a good separating axis at the end of the algorithm.
551
- // However when moving forward along inDirection we do need to take this into account so that we keep A and B separated by the sum of their convex radii.
552
- // From p we have to subtract: inConvexRadiusA * v / |v|
553
- // To q we have to add: inConvexRadiusB * v / |v|
554
- // This means that to w we have to add: -(inConvexRadiusA + inConvexRadiusB) * v / |v|
555
- // So to v . w we have to add: v . (-(inConvexRadiusA + inConvexRadiusB) * v / |v|) = -(inConvexRadiusA + inConvexRadiusB) * |v|
556
- const v_dot_w = closestPointToSimplex.point.dot(w) - sum_convex_radius * closestPointToSimplex.point.length();
557
- if (v_dot_w > 0.0) {
558
- // If ray and normal are in the same direction, we've passed A and there's no collision
559
- const v_dot_r = closestPointToSimplex.point.dot(inDirection);
560
- if (v_dot_r >= 0.0) {
561
- result.isHitFound = false;
562
- return;
563
- }
564
-
565
- // Update the lower bound for lambda
566
- const delta = v_dot_w / v_dot_r;
567
- const old_lambda = lambda;
568
- lambda -= delta;
569
-
570
- // If lambda didn't change, we cannot converge any further and we assume a hit
571
- if (old_lambda === lambda) {
572
- break;
573
- }
574
-
575
- // If lambda is bigger or equal than max, we don't have a hit
576
- if (lambda >= result.lambda) {
577
- result.isHitFound = false;
578
- return;
579
- }
580
-
581
- // Update x to new closest point on the ray
582
- x.scaleVector(inDirection, lambda);
583
-
584
- // We've shifted x, so reset v_len_sq so that it is not used as early out when GetClosest returns false
585
- closestPointToSimplex.squaredDistance = Number.MAX_VALUE;
586
-
587
- // Now that we've moved, we know that A and B are not intersecting at lambda = 0, so we can update our tolerance to stop iterating
588
- // as soon as A and B are inConvexRadiusA + inConvexRadiusB apart
589
- squaredTolerance = squared(inTolerance + sum_convex_radius);
590
-
591
- // We allow rebuilding the simplex once after x changes because the simplex was built
592
- // for another x and numerical round off builds up as you keep adding points to an
593
- // existing simplex
594
- allow_restart = true;
595
- }
596
-
597
- // Add p to set P, q to set Q: P = P U {p}, Q = Q U {q}
598
- ps[this.numPoints].copy(p);
599
- qs[this.numPoints].copy(q);
600
- ++this.numPoints;
601
-
602
- // Calculate Y = {x} - (Q - P)
603
- for (let i = 0; i < this.numPoints; ++i) {
604
- pq.subtractVectors(qs[i], ps[i]);
605
- ys[i].subtractVectors(x, pq);
606
- }
607
-
608
- // Determine the new closest point from Y to origin
609
- closestPointToSimplex.pointSet = 0;
610
- computeClosestPointToSimplex(
611
- closestPointToSimplex,
612
- closestPointToSimplex.squaredDistance,
613
- false,
614
- ys,
615
- this.numPoints
616
- );
617
- if (!closestPointToSimplex.closestPointFound) {
618
- // Only allow 1 restart, if we still can't get a closest point
619
- // we're so close that we return this as a hit
620
- if (!allow_restart) {
621
- // logDebug("Failed to converge");
622
- break;
623
- }
624
-
625
- // If we fail to converge, we start again with the last point as simplex
626
- // logDebug("Restarting");
627
-
628
- allow_restart = false;
629
- ps[0].copy(p);
630
- this.numPoints = 1;
631
- closestPointToSimplex.point.subtractVectors(x, p);
632
- closestPointToSimplex.squaredDistance = Number.MAX_VALUE;
633
- continue;
634
- } else if (closestPointToSimplex.pointSet === 0xf) {
635
- // logDebug("Full simplex");
636
-
637
- // #v-ifdef DEV
638
- // We're inside the tetrahedron, we have a hit (verify that length of v is 0)
639
- if (closestPointToSimplex.squaredDistance !== 0.0) {
640
- throw new Error("v length must be 0");
641
- }
642
- // #v-endif
643
- }
644
-
645
- // Update the points P and Q to form the new simplex
646
- // Note: We're not updating Y as Y will shift with x so we have to calculate it every iteration
647
- this.numPoints = updatePointSetPQ(closestPointToSimplex.pointSet, this.numPoints);
648
-
649
- // Check if A and B are touching according to our tolerance
650
- if (closestPointToSimplex.squaredDistance <= squaredTolerance) {
651
- // logDebug("Converged");
652
- break;
653
- }
654
-
655
- // Store our v to return as separating axis
656
- prev_v.copy(closestPointToSimplex.point);
657
- }
658
-
659
- // Calculate Y = {x} - (Q - P) again so we can calculate the contact points
660
- for (let i = 0; i < this.numPoints; ++i) {
661
- pq.subtractVectors(qs[i], ps[i]);
662
- ys[i].subtractVectors(x, pq);
663
- }
664
-
665
- // Calculate the offset we need to apply to A and B to correct for the convex radius
666
- closestPointToSimplex.point.normalizedOr(normalized_v, zero);
667
- convex_radius_a.scaleVector(normalized_v, inConvexRadiusA);
668
- convex_radius_b.scaleVector(normalized_v, inConvexRadiusB);
669
-
670
- const bary = /*@__PURE__*/ BarycentricCoordinatesResult.create();
671
- result.pointA.zero();
672
- result.pointB.zero();
673
-
674
- // Get the contact point
675
- // Note that A and B will coincide when lambda > 0. In this case we calculate only B as it is more accurate as it contains less terms.
676
- switch (this.numPoints) {
677
- case 1: {
678
- result.pointB.addVectors(qs[0], convex_radius_b);
679
- if (lambda > 0.0) {
680
- result.pointA.copy(result.pointB);
681
- } else {
682
- result.pointA.subtractVectors(ps[0], convex_radius_a);
683
- }
684
- break;
685
- }
686
- case 2: {
687
- computeBarycentricCoordinates2d(bary, ys[0], ys[1]);
688
-
689
- result.pointB.addScaled(qs[0], bary.u);
690
- result.pointB.addScaled(qs[1], bary.v);
691
- result.pointB.addVectors(result.pointB, convex_radius_b);
692
-
693
- if (lambda > 0.0) {
694
- result.pointA.copy(result.pointB);
695
- } else {
696
- result.pointA.addScaled(ps[0], bary.u);
697
- result.pointA.addScaled(ps[1], bary.v);
698
- result.pointA.subtractVectors(result.pointA, convex_radius_a);
699
- }
700
- break;
701
- }
702
- case 3:
703
- case 4: {
704
- // A full simplex, we can't properly determine a contact point! As contact point we take the closest point of the previous iteration.
705
- computeBarycentricCoordinates3d(bary, ys[0], ys[1], ys[2]);
706
-
707
- result.pointB.addScaled(qs[0], bary.u);
708
- result.pointB.addScaled(qs[1], bary.v);
709
- result.pointB.addScaled(qs[2], bary.w);
710
- result.pointB.addVectors(result.pointB, convex_radius_b);
711
-
712
- if (lambda > 0.0) {
713
- result.pointA.copy(result.pointB);
714
- } else {
715
- result.pointA.addScaled(ps[0], bary.u);
716
- result.pointA.addScaled(ps[1], bary.v);
717
- result.pointA.addScaled(ps[2], bary.w);
718
- result.pointA.subtractVectors(result.pointA, convex_radius_a);
719
- }
720
- break;
721
- }
722
- default: {
723
- throw new Error("Invalid number of points");
724
- }
725
- }
726
-
727
- // Store separating axis, in case we have a convex radius we can just return v,
728
- // otherwise v will be very small and we resort to returning previous v as an approximation.
729
- if (sum_convex_radius > 0.0) {
730
- result.separatingAxis.negateVector(closestPointToSimplex.point);
731
- } else {
732
- result.separatingAxis.negateVector(prev_v);
733
- }
734
-
735
- // Store hit fraction
736
- result.lambda = lambda;
737
- result.isHitFound = true;
738
- }
739
-
740
- castRay(
741
- inRayOrigin: Vec3,
742
- inRayDirection: Vec3,
743
- inTolerance: number,
744
- inA: SupportShape,
745
- ioLambda: { fraction: number }
746
- ): boolean {
747
- const squaredTolerance = squared(inTolerance);
748
-
749
- // Reset state
750
- this.numPoints = 0;
751
-
752
- let lambda = 0.0;
753
- x.copy(inRayOrigin);
754
- directionB_2.zero();
755
- inA.computeSupport(p, directionB_2);
756
- v.subtractVectors(x, p);
757
- let v_len_sq = { value: Number.MAX_VALUE };
758
- let allowRestart = false;
759
-
760
- let iterations = 0;
761
- while (true) {
762
- if (iterations >= this.maxIterations) {
763
- return false;
764
- }
765
-
766
- // Get new support point
767
- inA.computeSupport(p, v);
768
- w.subtractVectors(x, p);
769
-
770
- const vDotW = v.dot(w);
771
-
772
- if (vDotW > 0.0) {
773
- // If ray and normal are in the same direction, we've passed A and there's no collision
774
- const vDotR = v.dot(inRayDirection);
775
-
776
- // Instead of checking >= 0, check with epsilon as we don't want the division below to overflow to infinity as it can cause a float exception
777
- if (vDotR >= -1.0e-18) {
778
- return false;
779
- }
780
-
781
- // Update the lower bound for lambda
782
- const delta = vDotW / vDotR;
783
- const oldLambda = lambda;
784
- lambda -= delta;
785
-
786
- // If lambda didn't change, we cannot converge any further and we assume a hit
787
- if (oldLambda === lambda) {
788
- break;
789
- }
790
-
791
- // If lambda is bigger or equal than max, we don't have a hit
792
- if (lambda >= ioLambda.fraction) {
793
- return false;
794
- }
795
-
796
- // Update x to new closest point on the ray
797
- x.addScaledToVector(inRayOrigin, inRayDirection, lambda);
798
-
799
- // We've shifted x, so reset vLengthSquared so that it is not used as early out for GetClosest
800
- v_len_sq.value = Number.MAX_VALUE;
801
-
802
- // We allow rebuilding the simplex once after x changes because the simplex was built
803
- // for another x and numerical round off builds up as you keep adding points to an
804
- // existing simplex
805
- allowRestart = true;
806
- }
807
-
808
- // Add p to set P: P = P U {p}
809
- ps[this.numPoints].copy(p);
810
- ++this.numPoints;
811
-
812
- // Calculate Y = {x} - P
813
- for (let i = 0; i < this.numPoints; ++i) {
814
- ys[i].subtractVectors(x, ps[i]);
815
- }
816
-
817
- // Determine the new closest point from Y to origin
818
- const set = { value: 0 };
819
- const found = getClosest(v_len_sq.value, v, v_len_sq, set, false, this.numPoints, ys);
820
-
821
- if (!found) {
822
- // Only allow 1 restart, if we still can't get a closest point
823
- // we're so close that we return this as a hit
824
- if (!allowRestart) {
825
- break;
826
- }
827
-
828
- // If we fail to converge, we start again with the last point as simplex
829
- allowRestart = false;
830
- ps[0].copy(p);
831
- this.numPoints = 1;
832
- v.subtractVectors(x, p);
833
- v_len_sq.value = Number.MAX_VALUE;
834
- continue;
835
- } else if (set.value === 0xf) {
836
- // #v-ifdef DEV
837
- // We're inside the tetrahedron, we have a hit (verify that length of v is 0)
838
- if (v_len_sq.value !== 0.0) {
839
- throw new Error("v length must be 0");
840
- }
841
- // #v-endif
842
- break;
843
- }
844
-
845
- // Update the points P to form the new simplex
846
- // Note: We're not updating Y as Y will shift with x so we have to calculate it every iteration
847
- this.numPoints = updatePointSetP(set.value, this.numPoints);
848
-
849
- // Check if A and B are touching according to our tolerance
850
- if (v_len_sq.value <= squaredTolerance) {
851
- // logDebug("Converged");
852
- break;
853
- }
854
-
855
- iterations++;
856
- }
857
-
858
- // Store hit fraction
859
- ioLambda.fraction = lambda;
860
- return true;
861
- }
862
- }
863
-
864
- const v = /*@__PURE__*/ Vec3.create();