@perplexdotgg/bounce 1.0.0

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 (140) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +30 -0
  3. package/package.json +32 -0
  4. package/src/builders/ConvexHullBuilder.ts +437 -0
  5. package/src/builders/ConvexHullBuilder2d.ts +344 -0
  6. package/src/builders/ConvexHullBuilder3d.ts +1689 -0
  7. package/src/builders/HeightMapBuilder.ts +414 -0
  8. package/src/builders/TriangleMeshBuilder.ts +92 -0
  9. package/src/collision/CastShapesModule.ts +184 -0
  10. package/src/collision/CollideShapesModule.ts +152 -0
  11. package/src/collision/HeightMapCaster.ts +38 -0
  12. package/src/collision/HeightMapCollider.ts +33 -0
  13. package/src/collision/TriangleCaster.ts +249 -0
  14. package/src/collision/TriangleCollider.ts +308 -0
  15. package/src/collision/TriangleCollider2.ts +379 -0
  16. package/src/collision/activeEdge.ts +146 -0
  17. package/src/collision/cast/cast.ts +139 -0
  18. package/src/collision/cast/castCompoundVsCompound.ts +59 -0
  19. package/src/collision/cast/castCompoundVsConvex.ts +116 -0
  20. package/src/collision/cast/castConvexVsCompound.ts +123 -0
  21. package/src/collision/cast/castConvexVsConvex.ts +213 -0
  22. package/src/collision/cast/castConvexVsHeightMap.ts +73 -0
  23. package/src/collision/cast/castConvexVsTriangleMesh.ts +56 -0
  24. package/src/collision/cast/castRayVsCompound.ts +44 -0
  25. package/src/collision/cast/castRayVsConvex.ts +45 -0
  26. package/src/collision/cast/castRayVsHeightMap.ts +58 -0
  27. package/src/collision/cast/castRayVsTriangleMesh.ts +58 -0
  28. package/src/collision/closestPoints/closestPoints.ts +23 -0
  29. package/src/collision/closestPoints/computeBarycentricCoordinates2d.ts +32 -0
  30. package/src/collision/closestPoints/computeBarycentricCoordinates3d.ts +81 -0
  31. package/src/collision/closestPoints/computeClosestPointOnLine.ts +30 -0
  32. package/src/collision/closestPoints/computeClosestPointOnTetrahedron.ts +96 -0
  33. package/src/collision/closestPoints/computeClosestPointOnTriangle.ts +195 -0
  34. package/src/collision/closestPoints/isOriginOutsideOfPlane.ts +25 -0
  35. package/src/collision/closestPoints/isOriginOutsideOfTrianglePlanes.ts +72 -0
  36. package/src/collision/collide/collide.ts +146 -0
  37. package/src/collision/collide/collideCompoundVsCompound.ts +60 -0
  38. package/src/collision/collide/collideCompoundVsConvex.ts +59 -0
  39. package/src/collision/collide/collideCompoundVsHeightMap.ts +73 -0
  40. package/src/collision/collide/collideCompoundVsTriangleMesh.ts +56 -0
  41. package/src/collision/collide/collideConvexVsCompound.ts +57 -0
  42. package/src/collision/collide/collideConvexVsConvex.ts +225 -0
  43. package/src/collision/collide/collideConvexVsConvexImp.ts +236 -0
  44. package/src/collision/collide/collideConvexVsHeightMap.ts +53 -0
  45. package/src/collision/collide/collideConvexVsTriangleMesh.ts +58 -0
  46. package/src/collision/collide/collideHeightMapVsCompound.ts +69 -0
  47. package/src/collision/collide/collideHeightMapVsConvex.ts +53 -0
  48. package/src/collision/collide/collideSphereVsSphere.ts +81 -0
  49. package/src/collision/collide/collideTriangleMeshVsCompound.ts +58 -0
  50. package/src/collision/collide/collideTriangleMeshVsConvex.ts +58 -0
  51. package/src/collision/epa/EpaConvexHullBuilder.ts +397 -0
  52. package/src/collision/epa/StaticArray.ts +154 -0
  53. package/src/collision/epa/TriangleFactory.ts +32 -0
  54. package/src/collision/epa/arrays.ts +99 -0
  55. package/src/collision/epa/binaryHeap.ts +82 -0
  56. package/src/collision/epa/structs.ts +227 -0
  57. package/src/collision/gjk/GjkModule.ts +864 -0
  58. package/src/collision/gjk/PenetrationDepthModule.ts +493 -0
  59. package/src/collision/gjk/SupportPoints.ts +50 -0
  60. package/src/collision/imp/MinkowskiDifference.ts +36 -0
  61. package/src/collision/imp/computeExploredDistanceLowerUpperBound.ts +40 -0
  62. package/src/collision/imp/finalizeImpResult.ts +69 -0
  63. package/src/collision/imp/findContactImp.ts +196 -0
  64. package/src/collision/imp/imp.ts +28 -0
  65. package/src/collision/imp/incrementalMinimumDistanceExploreDirection.ts +207 -0
  66. package/src/collision/mpr/findPortal.ts +152 -0
  67. package/src/collision/mpr/mpr.ts +29 -0
  68. package/src/collision/mpr/updatePortal.ts +52 -0
  69. package/src/constraints/BaseConstraint.ts +50 -0
  70. package/src/constraints/ConstraintOptions.ts +22 -0
  71. package/src/constraints/ConstraintSolver.ts +119 -0
  72. package/src/constraints/DistanceConstraint.ts +229 -0
  73. package/src/constraints/FixedConstraint.ts +203 -0
  74. package/src/constraints/HingeConstraint.ts +460 -0
  75. package/src/constraints/PointConstraint.ts +108 -0
  76. package/src/constraints/components/AngleComponent.ts +226 -0
  77. package/src/constraints/components/AxisComponent.ts +263 -0
  78. package/src/constraints/components/HingeComponent.ts +215 -0
  79. package/src/constraints/components/Motor.ts +36 -0
  80. package/src/constraints/components/PointConstraintComponent.ts +179 -0
  81. package/src/constraints/components/RotationEulerComponent.ts +139 -0
  82. package/src/constraints/components/Spring.ts +30 -0
  83. package/src/constraints/components/SpringComponent.ts +71 -0
  84. package/src/constraints/types.ts +6 -0
  85. package/src/helpers.ts +147 -0
  86. package/src/index.ts +50 -0
  87. package/src/math/BasicTransform.ts +19 -0
  88. package/src/math/NumberValue.ts +13 -0
  89. package/src/math/isometry.ts +64 -0
  90. package/src/math/mat3.ts +529 -0
  91. package/src/math/mat4.ts +588 -0
  92. package/src/math/quat.ts +193 -0
  93. package/src/math/scalar.ts +81 -0
  94. package/src/math/tensor.ts +17 -0
  95. package/src/math/vec3.ts +589 -0
  96. package/src/math/vec4.ts +10 -0
  97. package/src/physics/Body.ts +581 -0
  98. package/src/physics/CollisionFilter.ts +52 -0
  99. package/src/physics/SleepModule.ts +163 -0
  100. package/src/physics/broadphase/BodyPairsModule.ts +363 -0
  101. package/src/physics/broadphase/BvhModule.ts +237 -0
  102. package/src/physics/broadphase/BvhTree.ts +803 -0
  103. package/src/physics/broadphase/ConstraintPairsModule.ts +385 -0
  104. package/src/physics/broadphase/TriangleMeshBvhTree.ts +379 -0
  105. package/src/physics/manifold/ContactManifold.ts +227 -0
  106. package/src/physics/manifold/ContactManifoldModule.ts +623 -0
  107. package/src/physics/manifold/Face.ts +119 -0
  108. package/src/physics/manifold/ManifoldCache.ts +116 -0
  109. package/src/physics/manifold/clipping/clipPolyVsEdge.ts +131 -0
  110. package/src/physics/manifold/clipping/clipPolyVsPlane.ts +73 -0
  111. package/src/physics/manifold/clipping/clipPolyVsPoly.ts +72 -0
  112. package/src/physics/narrowphase/CollideBodiesModule.ts +755 -0
  113. package/src/physics/solver/ContactConstraintModule.ts +659 -0
  114. package/src/physics/solver/ManifoldConstraint.ts +420 -0
  115. package/src/physics/solver/estimateCollisionResponse.ts +146 -0
  116. package/src/shape/Aabb.ts +400 -0
  117. package/src/shape/Box.ts +231 -0
  118. package/src/shape/Capsule.ts +332 -0
  119. package/src/shape/CompoundShape.ts +288 -0
  120. package/src/shape/Convex.ts +130 -0
  121. package/src/shape/ConvexHull.ts +423 -0
  122. package/src/shape/Cylinder.ts +313 -0
  123. package/src/shape/HeightMap.ts +511 -0
  124. package/src/shape/Line.ts +14 -0
  125. package/src/shape/Plane.ts +116 -0
  126. package/src/shape/Ray.ts +81 -0
  127. package/src/shape/Segment.ts +25 -0
  128. package/src/shape/Shape.ts +77 -0
  129. package/src/shape/Sphere.ts +181 -0
  130. package/src/shape/TransformedShape.ts +51 -0
  131. package/src/shape/Triangle.ts +122 -0
  132. package/src/shape/TriangleMesh.ts +186 -0
  133. package/src/types.ts +1 -0
  134. package/src/world.ts +1335 -0
  135. package/tests/BodyPairsModule.test.ts +71 -0
  136. package/tests/BvhTree.test.ts +406 -0
  137. package/tests/test.md +642 -0
  138. package/tests/vec3.test.ts +12 -0
  139. package/tsconfig.json +20 -0
  140. package/vite.config.js +40 -0
@@ -0,0 +1,460 @@
1
+ import { BooleanType, createClass, MonomorphType, NumberType, PropertyDefinitionMap } from "monomorph";
2
+ import { baseConstraintProps, ConstraintInterface, ConstraintType, ReferenceFrame } from "./BaseConstraint";
3
+ import { Vec3 } from "../math/vec3";
4
+ import { Spring, SpringMode } from "./components/Spring";
5
+ import { Motor, MotorMode } from "./components/Motor";
6
+ import { Quat } from "../math/quat";
7
+ import { PointConstraintComponent } from "./components/PointConstraintComponent";
8
+ import { HingeComponent } from "./components/HingeComponent";
9
+ import { AngleComponent } from "./components/AngleComponent";
10
+ import type { World } from "../world";
11
+ import { Mat3 } from "../math/mat3";
12
+ import { Mat4 } from "../math/mat4";
13
+ import { clamp, normalizeBetweenMinusPiAndPi } from "../math/scalar";
14
+ import { Line } from "../shape/Line";
15
+
16
+ const constraintRotationA = /*@__PURE__*/ Mat3.create();
17
+ const constraintRotationB = /*@__PURE__*/ Mat3.create();
18
+ const constraintQuaternionA = /*@__PURE__*/ Quat.create();
19
+ const constraintQuaternionB = /*@__PURE__*/ Quat.create();
20
+ const localAxisZA = /*@__PURE__*/ Vec3.create();
21
+ const localAxisZB = /*@__PURE__*/ Vec3.create();
22
+ const axis = /*@__PURE__*/ Vec3.create();
23
+ const rotateWorldToLocalA = /*@__PURE__*/ Quat.create();
24
+ const rotation = /*@__PURE__*/ Quat.create();
25
+ const transformWorldToLocalA = /*@__PURE__*/ Mat4.create();
26
+ const transformWorldToLocalB = /*@__PURE__*/ Mat4.create();
27
+ const rotateWorldToLocalB = /*@__PURE__*/ Quat.create();
28
+ const rotateLocalToWorldAQuat = /*@__PURE__*/ Quat.create();
29
+ const rotateLocalToWorldAMat3 = /*@__PURE__*/ Mat3.create();
30
+ const rotateLocalToWorldB = /*@__PURE__*/ Mat3.create();
31
+ const worldHingeA = /*@__PURE__*/ Vec3.create();
32
+ const worldHingeB = /*@__PURE__*/ Vec3.create();
33
+ const transformLocalToWorld = /*@__PURE__*/ Mat4.create();
34
+
35
+ const hingeConstraintProps = {
36
+ ...baseConstraintProps,
37
+
38
+ // init data
39
+ pointA: MonomorphType(Vec3, { x: 0, y: 0, z: 0 }),
40
+ pointB: MonomorphType(Vec3, { x: 0, y: 0, z: 0 }),
41
+ hingeA: MonomorphType(Vec3, { x: 1, y: 0, z: 0 }),
42
+ hingeB: MonomorphType(Vec3, { x: 1, y: 0, z: 0 }),
43
+ normalA: MonomorphType(Vec3, { x: 0, y: 1, z: 0 }),
44
+ normalB: MonomorphType(Vec3, { x: 0, y: 1, z: 0 }),
45
+ spring: MonomorphType(Spring),
46
+ motor: MonomorphType(Motor),
47
+ minHingeAngle: NumberType(-Math.PI),
48
+ maxHingeAngle: NumberType(+Math.PI),
49
+ maxFrictionTorque: NumberType(0),
50
+
51
+ // constraint data
52
+ localPointA: MonomorphType(Vec3, undefined, true),
53
+ localPointB: MonomorphType(Vec3, undefined, true),
54
+ localHingeA: MonomorphType(Vec3, undefined, true),
55
+ localHingeB: MonomorphType(Vec3, undefined, true),
56
+ localNormalA: MonomorphType(Vec3, undefined, true),
57
+ localNormalB: MonomorphType(Vec3, undefined, true),
58
+ inverseInitialRotationAB: MonomorphType(Quat, undefined, true),
59
+ areLimitsEnabled: BooleanType(false, true),
60
+ targetAngularSpeed: NumberType(0),
61
+ targetAngle: NumberType(0),
62
+ hingeAngle: NumberType(0, true),
63
+ axis1: MonomorphType(Vec3, undefined, true),
64
+
65
+ // constraint parts
66
+ pointConstraintPart: MonomorphType(PointConstraintComponent),
67
+ rotationConstraintPart: MonomorphType(HingeComponent),
68
+ rotationLimitsConstraintPart: MonomorphType(AngleComponent),
69
+ motorConstraintPart: MonomorphType(AngleComponent),
70
+ } as const satisfies PropertyDefinitionMap;
71
+
72
+ export class HingeConstraint
73
+ extends createClass<HingeConstraint, typeof hingeConstraintProps>(hingeConstraintProps)
74
+ implements ConstraintInterface
75
+ {
76
+ type: ConstraintType.hingeConstraint = ConstraintType.hingeConstraint;
77
+ declare world: World;
78
+
79
+ deactivate(): void {
80
+ this.pointConstraintPart.deactivate();
81
+ this.rotationConstraintPart.deactivate();
82
+ this.rotationLimitsConstraintPart.deactivate();
83
+ this.motorConstraintPart.deactivate();
84
+ }
85
+
86
+ // TODO: generalize this into a quat or euler function, same or similar one exists on FixedConstraint right now
87
+ computeInverseInitialRotationAToB(out: Quat, inAxisX1: Vec3, inAxisZ1: Vec3, inAxisX2: Vec3, inAxisZ2: Vec3): void {
88
+ if (inAxisX1.exactEquals(inAxisX2) && inAxisZ1.exactEquals(inAxisZ2)) {
89
+ out.identity();
90
+ } else {
91
+ // normalize the local axes
92
+ inAxisX1.normalize();
93
+ inAxisZ1.normalize();
94
+ inAxisX2.normalize();
95
+ inAxisZ2.normalize();
96
+
97
+ localAxisZA.crossVectors(inAxisX1, inAxisX2);
98
+ localAxisZA.normalize();
99
+ constraintRotationA.setColumns(inAxisX1, inAxisX2, localAxisZA);
100
+ constraintQuaternionA.fromMat3(constraintRotationA);
101
+
102
+ localAxisZB.crossVectors(inAxisZ1, inAxisZ2);
103
+ localAxisZB.normalize();
104
+ constraintRotationB.setColumns(inAxisZ1, inAxisZ2, localAxisZB);
105
+ constraintQuaternionB.fromMat3(constraintRotationB);
106
+
107
+ constraintQuaternionA.conjugateQuat(constraintQuaternionA);
108
+ out.multiplyQuats(constraintQuaternionB, constraintQuaternionA);
109
+ }
110
+ }
111
+
112
+ getCurrentAngle(): number {
113
+ rotateWorldToLocalA.conjugateQuat(this.bodyA!.orientation);
114
+
115
+ rotation.multiplyQuats(this.bodyB!.orientation, this.inverseInitialRotationAB);
116
+ rotation.multiplyQuats(rotation, rotateWorldToLocalA);
117
+
118
+ axis.transformVectorByQuat(this.localHingeA, this.bodyA!.orientation);
119
+
120
+ return rotation.computeRotationAngle(axis);
121
+ }
122
+
123
+ isMinHingeAngleClosest(): boolean {
124
+ const angleToMin = normalizeBetweenMinusPiAndPi(this.hingeAngle - this.minHingeAngle);
125
+ const angleToMax = normalizeBetweenMinusPiAndPi(this.hingeAngle - this.maxHingeAngle);
126
+ return Math.abs(angleToMin) < Math.abs(angleToMax);
127
+ }
128
+
129
+ getSmallestDeltaAngle(): number {
130
+ const angleToMin = normalizeBetweenMinusPiAndPi(this.hingeAngle - this.minHingeAngle);
131
+ const angleToMax = normalizeBetweenMinusPiAndPi(this.hingeAngle - this.maxHingeAngle);
132
+ return Math.abs(angleToMin) < Math.abs(angleToMax) ? angleToMin : angleToMax;
133
+ }
134
+
135
+ isCurrentAngleWithinLimits(): boolean {
136
+ return this.hingeAngle >= this.minHingeAngle && this.hingeAngle <= this.maxHingeAngle;
137
+ }
138
+
139
+ setupLimits(minAngle: number, maxAngle: number): void {
140
+ // TODO: this is failing without the tolerance, possibly due to floating point errors?
141
+ const tolerance = 1e-6;
142
+ if (minAngle < -Math.PI - tolerance || minAngle > 0 + tolerance) {
143
+ throw new Error(`expected minAngle to be in the interval [-pi, 0], got ${minAngle} instead`);
144
+ }
145
+
146
+ if (maxAngle < 0 - tolerance || maxAngle > +Math.PI + tolerance) {
147
+ throw new Error(`expected maxAngle to be in the interval [0, +pi], got ${maxAngle} instead`);
148
+ }
149
+
150
+ this.minHingeAngle = minAngle;
151
+ this.maxHingeAngle = maxAngle;
152
+ this.areLimitsEnabled = minAngle > -Math.PI && maxAngle < Math.PI;
153
+ }
154
+
155
+ setupAxis1AndHingeAngle(): void {
156
+ if (this.areLimitsEnabled === false && this.motor.mode === MotorMode.Off && this.maxFrictionTorque <= 0) {
157
+ return;
158
+ }
159
+
160
+ rotateWorldToLocalA.conjugateQuat(this.bodyA!.orientation);
161
+
162
+ rotation.multiplyQuats(this.bodyB!.orientation, this.inverseInitialRotationAB);
163
+ rotation.multiplyQuats(rotation, rotateWorldToLocalA);
164
+
165
+ this.axis1.transformVectorByQuat(this.localHingeA, this.bodyA!.orientation);
166
+ this.hingeAngle = rotation.computeRotationAngle(this.axis1);
167
+ }
168
+
169
+ setupRotationLimitsConstraintPart(deltaTime: number): void {
170
+ if (this.areLimitsEnabled === false || this.isCurrentAngleWithinLimits()) {
171
+ this.rotationLimitsConstraintPart.deactivate();
172
+ return;
173
+ }
174
+
175
+ const deltaAngle = this.getSmallestDeltaAngle();
176
+
177
+ this.rotationLimitsConstraintPart.setupWithSpring(
178
+ this.bodyA!,
179
+ this.bodyB!,
180
+ this.axis1,
181
+ 0.0,
182
+ deltaAngle,
183
+ this.spring,
184
+ deltaTime
185
+ );
186
+ }
187
+
188
+ setupMotorConstraintPart(deltaTime: number): void {
189
+ switch (this.motor.mode) {
190
+ case MotorMode.Off: {
191
+ if (this.maxFrictionTorque <= 0) {
192
+ this.motorConstraintPart.deactivate();
193
+ return;
194
+ }
195
+
196
+ this.motorConstraintPart.setup(this.bodyA!, this.bodyB!, this.axis1, 0.0);
197
+ break;
198
+ }
199
+
200
+ case MotorMode.Velocity: {
201
+ this.motorConstraintPart.setup(this.bodyA!, this.bodyB!, this.axis1, -this.targetAngularSpeed);
202
+ break;
203
+ }
204
+
205
+ case MotorMode.Position: {
206
+ if (this.motor.spring.hasStiffness() === false) {
207
+ this.motorConstraintPart.deactivate();
208
+ return;
209
+ }
210
+
211
+ const deltaAngle = normalizeBetweenMinusPiAndPi(this.hingeAngle - this.targetAngle);
212
+
213
+ this.motorConstraintPart.setupWithSpring(
214
+ this.bodyA!,
215
+ this.bodyB!,
216
+ this.axis1,
217
+ 0.0,
218
+ deltaAngle,
219
+ this.motor.spring,
220
+ deltaTime
221
+ );
222
+ break;
223
+ }
224
+
225
+ default: {
226
+ throw new Error("Invalid motor mode");
227
+ }
228
+ }
229
+ }
230
+
231
+ onCreate() {
232
+ this.setupLimits(this.minHingeAngle, this.maxHingeAngle);
233
+ this.computeInverseInitialRotationAToB(
234
+ this.inverseInitialRotationAB,
235
+ this.normalA,
236
+ this.hingeA,
237
+ this.normalB,
238
+ this.hingeB
239
+ );
240
+ this.inverseInitialRotationAB.normalizeQuat(this.inverseInitialRotationAB);
241
+
242
+ if (this.referenceFrame === ReferenceFrame.local) {
243
+ this.localPointA.copy(this.pointA);
244
+ this.localPointB.copy(this.pointB);
245
+ this.localHingeA.copy(this.hingeA);
246
+ this.localNormalA.copy(this.normalA);
247
+ this.localHingeB.copy(this.hingeB);
248
+ this.localNormalB.copy(this.normalB);
249
+ } else {
250
+ transformWorldToLocalA.fromInverseRotationAndTranslation(
251
+ this.bodyA!.orientation,
252
+ this.bodyA!.computedCenterOfMassPosition
253
+ );
254
+ transformWorldToLocalB.fromInverseRotationAndTranslation(
255
+ this.bodyB!.orientation,
256
+ this.bodyB!.computedCenterOfMassPosition
257
+ );
258
+
259
+ this.localPointA.transformVectorFromMat4(this.pointA, transformWorldToLocalA);
260
+ this.localPointB.transformVectorFromMat4(this.pointB, transformWorldToLocalB);
261
+
262
+ transformWorldToLocalA.multiply3x3(this.localHingeA, this.hingeA);
263
+ transformWorldToLocalA.multiply3x3(this.localNormalA, this.normalA);
264
+ transformWorldToLocalB.multiply3x3(this.localHingeB, this.hingeB);
265
+ transformWorldToLocalB.multiply3x3(this.localNormalB, this.normalB);
266
+
267
+ rotateWorldToLocalB.conjugateQuat(this.bodyB!.orientation);
268
+ rotateLocalToWorldAQuat.copy(this.bodyA!.orientation);
269
+
270
+ this.inverseInitialRotationAB.multiplyQuats(rotateWorldToLocalB, this.inverseInitialRotationAB);
271
+ this.inverseInitialRotationAB.multiplyQuats(this.inverseInitialRotationAB, rotateLocalToWorldAQuat);
272
+ }
273
+
274
+ this.localHingeA.normalize();
275
+ this.localNormalA.normalize();
276
+ this.localHingeB.normalize();
277
+ this.localNormalB.normalize();
278
+
279
+ this.deactivate();
280
+ }
281
+
282
+ warmStart(warmStartImpulseRatio: number): void {
283
+ this.setComponentData();
284
+ this.motorConstraintPart.warmStart(this.bodyA!, this.bodyB!, warmStartImpulseRatio);
285
+ this.pointConstraintPart.warmStart(warmStartImpulseRatio);
286
+ this.rotationConstraintPart.warmStart(warmStartImpulseRatio);
287
+ this.rotationLimitsConstraintPart.warmStart(this.bodyA!, this.bodyB!, warmStartImpulseRatio);
288
+ }
289
+
290
+ initVelocityConstraint(deltaTimeSeconds: number): void {
291
+ this.setComponentData();
292
+ this.pointConstraintPart.setup(this.localPointA, this.localPointB);
293
+
294
+ rotateLocalToWorldAMat3.fromQuat(this.bodyA!.orientation);
295
+ rotateLocalToWorldB.fromQuat(this.bodyB!.orientation);
296
+
297
+ worldHingeA.transformVectorFromMat3(this.localHingeA, rotateLocalToWorldAMat3);
298
+ worldHingeB.transformVectorFromMat3(this.localHingeB, rotateLocalToWorldB);
299
+
300
+ this.rotationConstraintPart.setup(worldHingeA, worldHingeB);
301
+
302
+ this.setupAxis1AndHingeAngle();
303
+ this.setupRotationLimitsConstraintPart(deltaTimeSeconds);
304
+ this.setupMotorConstraintPart(deltaTimeSeconds);
305
+ }
306
+
307
+ solveVelocityConstraint(deltaTimeSeconds: number): void {
308
+ this.setComponentData();
309
+ if (this.motorConstraintPart.isActive()) {
310
+ switch (this.motor.mode) {
311
+ case MotorMode.Off: {
312
+ const maxLambda = this.maxFrictionTorque * deltaTimeSeconds;
313
+ this.motorConstraintPart.solveVelocity(this.bodyA!, this.bodyB!, this.axis1, -maxLambda, +maxLambda);
314
+ break;
315
+ }
316
+
317
+ case MotorMode.Velocity:
318
+ case MotorMode.Position: {
319
+ const minLambda = this.motor.minTorque * deltaTimeSeconds;
320
+ const maxLambda = this.motor.maxTorque * deltaTimeSeconds;
321
+ this.motorConstraintPart.solveVelocity(this.bodyA!, this.bodyB!, this.axis1, minLambda, maxLambda);
322
+ break;
323
+ }
324
+
325
+ default: {
326
+ throw new Error("Invalid motor mode");
327
+ }
328
+ }
329
+ }
330
+
331
+ this.pointConstraintPart.solveVelocity();
332
+ this.rotationConstraintPart.solveVelocity();
333
+
334
+ if (this.rotationLimitsConstraintPart.isActive()) {
335
+ let minLambda: number;
336
+ let maxLambda: number;
337
+
338
+ // case: limits are equal
339
+ if (this.minHingeAngle === this.maxHingeAngle) {
340
+ minLambda = -Infinity;
341
+ maxLambda = +Infinity;
342
+ }
343
+
344
+ // case: min angle is closest
345
+ else if (this.isMinHingeAngleClosest()) {
346
+ minLambda = 0.0;
347
+ maxLambda = +Infinity;
348
+ }
349
+
350
+ // case: max angle is closest
351
+ else {
352
+ minLambda = -Infinity;
353
+ maxLambda = 0.0;
354
+ }
355
+
356
+ this.rotationLimitsConstraintPart.solveVelocity(this.bodyA!, this.bodyB!, this.axis1, minLambda, maxLambda);
357
+ }
358
+ }
359
+
360
+ solvePositionConstraint(deltaTimeSeconds: number): void {
361
+ this.setComponentData();
362
+
363
+ this.pointConstraintPart.setup(this.localPointA, this.localPointB);
364
+ this.pointConstraintPart.solvePosition();
365
+
366
+ // have to update the rotations again because the point constraint might have changed them
367
+
368
+ rotateLocalToWorldAMat3.fromQuat(this.bodyA!.orientation);
369
+ rotateLocalToWorldB.fromQuat(this.bodyB!.orientation);
370
+ worldHingeA.transformVectorFromMat3(this.localHingeA, rotateLocalToWorldAMat3);
371
+ worldHingeB.transformVectorFromMat3(this.localHingeB, rotateLocalToWorldB);
372
+ this.rotationConstraintPart.setup(worldHingeA, worldHingeB);
373
+ this.rotationConstraintPart.solvePosition();
374
+
375
+ if (this.areLimitsEnabled && this.spring.frequency <= 0) {
376
+ this.setupAxis1AndHingeAngle();
377
+ this.setupRotationLimitsConstraintPart(deltaTimeSeconds);
378
+ if (this.rotationLimitsConstraintPart.isActive()) {
379
+ const deltaAngle = this.getSmallestDeltaAngle();
380
+ this.rotationLimitsConstraintPart.solvePosition(this.bodyA!, this.bodyB!, deltaAngle);
381
+ }
382
+ }
383
+ }
384
+
385
+ setTargetAngle(targetAngle: number): void {
386
+ if (this.areLimitsEnabled) {
387
+ clamp(targetAngle, this.minHingeAngle, this.maxHingeAngle);
388
+ }
389
+ }
390
+
391
+ getTotalLambdaPosition(out: Vec3): void {
392
+ out.copy(this.pointConstraintPart.totalLambda);
393
+ }
394
+
395
+ getTotalLambdaRotation(): [number, number] {
396
+ return [this.rotationConstraintPart.totalLambdaA, this.rotationConstraintPart.totalLambdaB];
397
+ }
398
+
399
+ getTotalLambdaRotationLimits(): number {
400
+ return this.rotationLimitsConstraintPart.totalLambda;
401
+ }
402
+
403
+ getTotalLambdaMotor(): number {
404
+ return this.motorConstraintPart.totalLambda;
405
+ }
406
+
407
+ getWorldData(
408
+ outPointA: Vec3,
409
+ outPointB: Vec3,
410
+ outHingeLineA: Line,
411
+ outHingeLineB: Line,
412
+ outNormalLineA: Line,
413
+ outNormalLineB: Line
414
+ ): void {
415
+ transformLocalToWorld.fromRotationTranslation(this.bodyA!.orientation, this.bodyA!.computedCenterOfMassPosition);
416
+ outHingeLineA.setFromPointAndDirection(this.localPointA, this.localHingeA, 1);
417
+ outNormalLineA.setFromPointAndDirection(this.localPointA, this.localNormalA, 1);
418
+ outPointA.transformVectorFromMat4(this.localPointA, transformLocalToWorld);
419
+ outHingeLineA.a.transformVectorFromMat4(outHingeLineA.a, transformLocalToWorld);
420
+ outHingeLineA.b.transformVectorFromMat4(outHingeLineA.b, transformLocalToWorld);
421
+ outNormalLineA.a.transformVectorFromMat4(outNormalLineA.a, transformLocalToWorld);
422
+ outNormalLineA.b.transformVectorFromMat4(outNormalLineA.b, transformLocalToWorld);
423
+
424
+ transformLocalToWorld.fromRotationTranslation(this.bodyB!.orientation, this.bodyB!.computedCenterOfMassPosition);
425
+ outHingeLineB.setFromPointAndDirection(this.localPointB, this.localHingeB, 1);
426
+ outNormalLineB.setFromPointAndDirection(this.localPointB, this.localNormalB, 1);
427
+ outPointB.transformVectorFromMat4(this.localPointB, transformLocalToWorld);
428
+ outHingeLineB.a.transformVectorFromMat4(outHingeLineB.a, transformLocalToWorld);
429
+ outHingeLineB.b.transformVectorFromMat4(outHingeLineB.b, transformLocalToWorld);
430
+ outNormalLineB.a.transformVectorFromMat4(outNormalLineB.a, transformLocalToWorld);
431
+ outNormalLineB.b.transformVectorFromMat4(outNormalLineB.b, transformLocalToWorld);
432
+ }
433
+
434
+ setComponentData(): void {
435
+ // @ts-ignore
436
+ this.world = this.bodyA!.world;
437
+ this.pointConstraintPart.world = this.world;
438
+ this.rotationConstraintPart.world = this.world;
439
+ this.rotationLimitsConstraintPart.world = this.world;
440
+ this.motorConstraintPart.world = this.world;
441
+ this.pointConstraintPart.bodyA = this.bodyA!;
442
+ this.pointConstraintPart.bodyB = this.bodyB!;
443
+ this.rotationConstraintPart.bodyA = this.bodyA!;
444
+ this.rotationConstraintPart.bodyB = this.bodyB!;
445
+ this.rotationLimitsConstraintPart.bodyA = this.bodyA!;
446
+ this.rotationLimitsConstraintPart.bodyB = this.bodyB!;
447
+ this.motorConstraintPart.bodyA = this.bodyA!;
448
+ this.motorConstraintPart.bodyB = this.bodyB!;
449
+ }
450
+ }
451
+
452
+ const oldCreate = HingeConstraint.create;
453
+ HingeConstraint.create = function () {
454
+ const constraint = oldCreate.apply(this, arguments as any);
455
+ constraint.setComponentData();
456
+ constraint.onCreate();
457
+ constraint.world.sleepModule.wakeBodyUp(constraint.bodyA!);
458
+ constraint.world.sleepModule.wakeBodyUp(constraint.bodyB!);
459
+ return constraint;
460
+ };
@@ -0,0 +1,108 @@
1
+ import { createClass, MonomorphType, PropertyDefinitionMap } from "monomorph";
2
+ import { baseConstraintProps, ConstraintInterface, ConstraintType, ReferenceFrame } from "./BaseConstraint";
3
+ import { Vec3 } from "../math/vec3";
4
+ import { PointConstraintComponent } from "./components/PointConstraintComponent";
5
+ import type { World } from "../world";
6
+ import { Isometry } from "../math/isometry";
7
+ import { Mat4 } from "../math/mat4";
8
+
9
+ const transformWorldToLocalA = /*@__PURE__*/ Isometry.create();
10
+ const transformWorldToLocalB = /*@__PURE__*/ Isometry.create();
11
+ const transformLocalToWorld = /*@__PURE__*/ Mat4.create();
12
+
13
+ baseConstraintProps;
14
+
15
+ const pointConstraintProps = {
16
+ ...baseConstraintProps,
17
+ positionA: MonomorphType(Vec3),
18
+ positionB: MonomorphType(Vec3),
19
+ localPositionA: MonomorphType(Vec3, undefined, true),
20
+ localPositionB: MonomorphType(Vec3, undefined, true),
21
+ translationComponent: MonomorphType(PointConstraintComponent),
22
+ } as const satisfies PropertyDefinitionMap;
23
+
24
+ export class PointConstraint
25
+ extends createClass<PointConstraint, typeof pointConstraintProps>(pointConstraintProps)
26
+ implements ConstraintInterface
27
+ {
28
+ type: ConstraintType.pointConstraint = ConstraintType.pointConstraint;
29
+ declare world: World;
30
+
31
+ deactivate(): void {
32
+ this.translationComponent.deactivate();
33
+ }
34
+
35
+ computeLocalPositions(): void {
36
+ if (this.referenceFrame === ReferenceFrame.local) {
37
+ this.localPositionA.copy(this.positionA);
38
+ this.localPositionB.copy(this.positionB);
39
+ } else {
40
+ transformWorldToLocalA.fromInverseRotationAndTranslation(
41
+ this.bodyA!.orientation,
42
+ this.bodyA!.computedCenterOfMassPosition
43
+ );
44
+ transformWorldToLocalB.fromInverseRotationAndTranslation(
45
+ this.bodyB!.orientation,
46
+ this.bodyB!.computedCenterOfMassPosition
47
+ );
48
+
49
+ this.localPositionA.transformVectorFromMat4(this.positionA, transformWorldToLocalA.matrix);
50
+ this.localPositionB.transformVectorFromMat4(this.positionB, transformWorldToLocalB.matrix);
51
+ }
52
+ }
53
+
54
+ getLocalPoints(outA: Vec3, outB: Vec3): void {
55
+ outA.copy(this.localPositionA);
56
+ outB.copy(this.localPositionB);
57
+ }
58
+
59
+ getWorldPoints(outA: Vec3, outB: Vec3): void {
60
+ transformLocalToWorld.fromRotationTranslation(this.bodyA!.orientation, this.bodyA!.computedCenterOfMassPosition);
61
+ outA.transformVectorFromMat4(this.localPositionA, transformLocalToWorld);
62
+
63
+ transformLocalToWorld.fromRotationTranslation(this.bodyB!.orientation, this.bodyB!.computedCenterOfMassPosition);
64
+ outB.transformVectorFromMat4(this.localPositionB, transformLocalToWorld);
65
+ }
66
+
67
+ initVelocityConstraint(deltaTimeSeconds: number): void {
68
+ this.setComponentData();
69
+ this.translationComponent.setup(this.localPositionA, this.localPositionB);
70
+ }
71
+
72
+ warmStart(deltaTimeSeconds: number, warmStartImpulseRatio: number): void {
73
+ this.setComponentData();
74
+ this.translationComponent.warmStart(warmStartImpulseRatio);
75
+ }
76
+
77
+ solveVelocityConstraint(deltaTimeSeconds: number): void {
78
+ this.setComponentData();
79
+ this.translationComponent.solveVelocity();
80
+ }
81
+
82
+ solvePositionConstraint(deltaTimeSeconds: number): void {
83
+ this.setComponentData();
84
+ this.translationComponent.setup(this.localPositionA, this.localPositionB);
85
+ this.translationComponent.solvePosition();
86
+ }
87
+
88
+ setComponentData(): void {
89
+ // @ts-ignore
90
+ this.world = this.bodyA!.world;
91
+ // @ts-ignore
92
+ this.translationComponent.world = this.bodyA!.world;
93
+ this.translationComponent.bodyA = this.bodyA!;
94
+ this.translationComponent.bodyB = this.bodyB!;
95
+ }
96
+ }
97
+
98
+ const oldCreate = PointConstraint.create;
99
+ PointConstraint.create = function () {
100
+ const constraint = oldCreate.apply(this, arguments as any);
101
+ constraint.setComponentData();
102
+ constraint.computeLocalPositions();
103
+ constraint.deactivate();
104
+ constraint.world.sleepModule.wakeBodyUp(constraint.bodyA!);
105
+ constraint.world.sleepModule.wakeBodyUp(constraint.bodyB!);
106
+
107
+ return constraint;
108
+ };