box2d-ruby 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 (109) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +21 -0
  3. data/README.md +336 -0
  4. data/examples/contact_events.rb +22 -0
  5. data/examples/debug_draw.rb +15 -0
  6. data/examples/falling_ball.rb +19 -0
  7. data/examples/rugl_debug_draw.rb +68 -0
  8. data/examples/stagecraft_debug_draw.rb +64 -0
  9. data/examples/support/box2d_debug_lines.rb +125 -0
  10. data/ext/box2d/CMakeLists.txt +35 -0
  11. data/ext/box2d/extconf.rb +42 -0
  12. data/ext/box2d/native.c +9 -0
  13. data/ext/box2d/vendor/box2d/LICENSE +21 -0
  14. data/ext/box2d/vendor/box2d/VERSION +1 -0
  15. data/ext/box2d/vendor/box2d/include/box2d/base.h +131 -0
  16. data/ext/box2d/vendor/box2d/include/box2d/box2d.h +1222 -0
  17. data/ext/box2d/vendor/box2d/include/box2d/collision.h +830 -0
  18. data/ext/box2d/vendor/box2d/include/box2d/id.h +144 -0
  19. data/ext/box2d/vendor/box2d/include/box2d/math_functions.h +761 -0
  20. data/ext/box2d/vendor/box2d/include/box2d/types.h +1457 -0
  21. data/ext/box2d/vendor/box2d/src/CMakeLists.txt +223 -0
  22. data/ext/box2d/vendor/box2d/src/aabb.c +132 -0
  23. data/ext/box2d/vendor/box2d/src/aabb.h +56 -0
  24. data/ext/box2d/vendor/box2d/src/arena_allocator.c +112 -0
  25. data/ext/box2d/vendor/box2d/src/arena_allocator.h +48 -0
  26. data/ext/box2d/vendor/box2d/src/array.c +8 -0
  27. data/ext/box2d/vendor/box2d/src/array.h +179 -0
  28. data/ext/box2d/vendor/box2d/src/atomic.h +79 -0
  29. data/ext/box2d/vendor/box2d/src/bitset.c +67 -0
  30. data/ext/box2d/vendor/box2d/src/bitset.h +65 -0
  31. data/ext/box2d/vendor/box2d/src/body.c +1884 -0
  32. data/ext/box2d/vendor/box2d/src/body.h +194 -0
  33. data/ext/box2d/vendor/box2d/src/box2d.natvis +41 -0
  34. data/ext/box2d/vendor/box2d/src/broad_phase.c +524 -0
  35. data/ext/box2d/vendor/box2d/src/broad_phase.h +83 -0
  36. data/ext/box2d/vendor/box2d/src/constants.h +54 -0
  37. data/ext/box2d/vendor/box2d/src/constraint_graph.c +322 -0
  38. data/ext/box2d/vendor/box2d/src/constraint_graph.h +58 -0
  39. data/ext/box2d/vendor/box2d/src/contact.c +650 -0
  40. data/ext/box2d/vendor/box2d/src/contact.h +148 -0
  41. data/ext/box2d/vendor/box2d/src/contact_solver.c +2120 -0
  42. data/ext/box2d/vendor/box2d/src/contact_solver.h +54 -0
  43. data/ext/box2d/vendor/box2d/src/core.c +178 -0
  44. data/ext/box2d/vendor/box2d/src/core.h +149 -0
  45. data/ext/box2d/vendor/box2d/src/ctz.h +112 -0
  46. data/ext/box2d/vendor/box2d/src/distance.c +1415 -0
  47. data/ext/box2d/vendor/box2d/src/distance_joint.c +556 -0
  48. data/ext/box2d/vendor/box2d/src/dynamic_tree.c +1989 -0
  49. data/ext/box2d/vendor/box2d/src/geometry.c +1028 -0
  50. data/ext/box2d/vendor/box2d/src/hull.c +328 -0
  51. data/ext/box2d/vendor/box2d/src/id_pool.c +79 -0
  52. data/ext/box2d/vendor/box2d/src/id_pool.h +35 -0
  53. data/ext/box2d/vendor/box2d/src/island.c +977 -0
  54. data/ext/box2d/vendor/box2d/src/island.h +89 -0
  55. data/ext/box2d/vendor/box2d/src/joint.c +1272 -0
  56. data/ext/box2d/vendor/box2d/src/joint.h +335 -0
  57. data/ext/box2d/vendor/box2d/src/manifold.c +1726 -0
  58. data/ext/box2d/vendor/box2d/src/math_functions.c +159 -0
  59. data/ext/box2d/vendor/box2d/src/motor_joint.c +283 -0
  60. data/ext/box2d/vendor/box2d/src/mouse_joint.c +214 -0
  61. data/ext/box2d/vendor/box2d/src/mover.c +73 -0
  62. data/ext/box2d/vendor/box2d/src/prismatic_joint.c +656 -0
  63. data/ext/box2d/vendor/box2d/src/revolute_joint.c +534 -0
  64. data/ext/box2d/vendor/box2d/src/sensor.c +389 -0
  65. data/ext/box2d/vendor/box2d/src/sensor.h +36 -0
  66. data/ext/box2d/vendor/box2d/src/shape.c +1714 -0
  67. data/ext/box2d/vendor/box2d/src/shape.h +123 -0
  68. data/ext/box2d/vendor/box2d/src/solver.c +2038 -0
  69. data/ext/box2d/vendor/box2d/src/solver.h +155 -0
  70. data/ext/box2d/vendor/box2d/src/solver_set.c +613 -0
  71. data/ext/box2d/vendor/box2d/src/solver_set.h +57 -0
  72. data/ext/box2d/vendor/box2d/src/table.c +238 -0
  73. data/ext/box2d/vendor/box2d/src/table.h +37 -0
  74. data/ext/box2d/vendor/box2d/src/timer.c +185 -0
  75. data/ext/box2d/vendor/box2d/src/types.c +151 -0
  76. data/ext/box2d/vendor/box2d/src/weld_joint.c +310 -0
  77. data/ext/box2d/vendor/box2d/src/wheel_joint.c +551 -0
  78. data/ext/box2d/vendor/box2d/src/world.c +3301 -0
  79. data/ext/box2d/vendor/box2d/src/world.h +192 -0
  80. data/generator/generate.rb +316 -0
  81. data/generator/layout_probe.c +507 -0
  82. data/generator/verify_layouts.rb +32 -0
  83. data/lib/box2d/body.rb +172 -0
  84. data/lib/box2d/body_definition.rb +38 -0
  85. data/lib/box2d/body_shapes.rb +135 -0
  86. data/lib/box2d/chain.rb +61 -0
  87. data/lib/box2d/debug_draw.rb +118 -0
  88. data/lib/box2d/events.rb +103 -0
  89. data/lib/box2d/fixed_stepper.rb +39 -0
  90. data/lib/box2d/handle.rb +46 -0
  91. data/lib/box2d/hit.rb +5 -0
  92. data/lib/box2d/joint.rb +197 -0
  93. data/lib/box2d/native.rb +1462 -0
  94. data/lib/box2d/native_loader.rb +45 -0
  95. data/lib/box2d/pixel_scale.rb +29 -0
  96. data/lib/box2d/shape.rb +109 -0
  97. data/lib/box2d/shape_definition.rb +44 -0
  98. data/lib/box2d/value_conversion.rb +80 -0
  99. data/lib/box2d/version.rb +7 -0
  100. data/lib/box2d/world.rb +135 -0
  101. data/lib/box2d/world_joints.rb +156 -0
  102. data/lib/box2d/world_queries.rb +122 -0
  103. data/lib/box2d/world_registry.rb +95 -0
  104. data/lib/box2d.rb +31 -0
  105. data/script/build_platform_gem.rb +24 -0
  106. data/script/deterministic_scene.rb +56 -0
  107. data/script/update_deterministic_snapshot.rb +11 -0
  108. data/script/verify_platform_gem.rb +24 -0
  109. metadata +164 -0
@@ -0,0 +1,656 @@
1
+ // SPDX-FileCopyrightText: 2023 Erin Catto
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ #include "body.h"
5
+ #include "core.h"
6
+ #include "joint.h"
7
+ #include "solver.h"
8
+ #include "solver_set.h"
9
+ #include "world.h"
10
+
11
+ // needed for dll export
12
+ #include "box2d/box2d.h"
13
+
14
+ #include <stdio.h>
15
+
16
+ void b2PrismaticJoint_EnableSpring( b2JointId jointId, bool enableSpring )
17
+ {
18
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_prismaticJoint );
19
+ if ( enableSpring != joint->prismaticJoint.enableSpring )
20
+ {
21
+ joint->prismaticJoint.enableSpring = enableSpring;
22
+ joint->prismaticJoint.springImpulse = 0.0f;
23
+ }
24
+ }
25
+
26
+ bool b2PrismaticJoint_IsSpringEnabled( b2JointId jointId )
27
+ {
28
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_prismaticJoint );
29
+ return joint->prismaticJoint.enableSpring;
30
+ }
31
+
32
+ void b2PrismaticJoint_SetSpringHertz( b2JointId jointId, float hertz )
33
+ {
34
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_prismaticJoint );
35
+ joint->prismaticJoint.hertz = hertz;
36
+ }
37
+
38
+ float b2PrismaticJoint_GetSpringHertz( b2JointId jointId )
39
+ {
40
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_prismaticJoint );
41
+ return joint->prismaticJoint.hertz;
42
+ }
43
+
44
+ void b2PrismaticJoint_SetSpringDampingRatio( b2JointId jointId, float dampingRatio )
45
+ {
46
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_prismaticJoint );
47
+ joint->prismaticJoint.dampingRatio = dampingRatio;
48
+ }
49
+
50
+ float b2PrismaticJoint_GetSpringDampingRatio( b2JointId jointId )
51
+ {
52
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_prismaticJoint );
53
+ return joint->prismaticJoint.dampingRatio;
54
+ }
55
+
56
+ void b2PrismaticJoint_EnableLimit( b2JointId jointId, bool enableLimit )
57
+ {
58
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_prismaticJoint );
59
+ if ( enableLimit != joint->prismaticJoint.enableLimit )
60
+ {
61
+ joint->prismaticJoint.enableLimit = enableLimit;
62
+ joint->prismaticJoint.lowerImpulse = 0.0f;
63
+ joint->prismaticJoint.upperImpulse = 0.0f;
64
+ }
65
+ }
66
+
67
+ bool b2PrismaticJoint_IsLimitEnabled( b2JointId jointId )
68
+ {
69
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_prismaticJoint );
70
+ return joint->prismaticJoint.enableLimit;
71
+ }
72
+
73
+ float b2PrismaticJoint_GetLowerLimit( b2JointId jointId )
74
+ {
75
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_prismaticJoint );
76
+ return joint->prismaticJoint.lowerTranslation;
77
+ }
78
+
79
+ float b2PrismaticJoint_GetUpperLimit( b2JointId jointId )
80
+ {
81
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_prismaticJoint );
82
+ return joint->prismaticJoint.upperTranslation;
83
+ }
84
+
85
+ void b2PrismaticJoint_SetLimits( b2JointId jointId, float lower, float upper )
86
+ {
87
+ B2_ASSERT( lower <= upper );
88
+
89
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_prismaticJoint );
90
+ if ( lower != joint->prismaticJoint.lowerTranslation || upper != joint->prismaticJoint.upperTranslation )
91
+ {
92
+ joint->prismaticJoint.lowerTranslation = b2MinFloat( lower, upper );
93
+ joint->prismaticJoint.upperTranslation = b2MaxFloat( lower, upper );
94
+ joint->prismaticJoint.lowerImpulse = 0.0f;
95
+ joint->prismaticJoint.upperImpulse = 0.0f;
96
+ }
97
+ }
98
+
99
+ void b2PrismaticJoint_EnableMotor( b2JointId jointId, bool enableMotor )
100
+ {
101
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_prismaticJoint );
102
+ if ( enableMotor != joint->prismaticJoint.enableMotor )
103
+ {
104
+ joint->prismaticJoint.enableMotor = enableMotor;
105
+ joint->prismaticJoint.motorImpulse = 0.0f;
106
+ }
107
+ }
108
+
109
+ bool b2PrismaticJoint_IsMotorEnabled( b2JointId jointId )
110
+ {
111
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_prismaticJoint );
112
+ return joint->prismaticJoint.enableMotor;
113
+ }
114
+
115
+ void b2PrismaticJoint_SetMotorSpeed( b2JointId jointId, float motorSpeed )
116
+ {
117
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_prismaticJoint );
118
+ joint->prismaticJoint.motorSpeed = motorSpeed;
119
+ }
120
+
121
+ float b2PrismaticJoint_GetMotorSpeed( b2JointId jointId )
122
+ {
123
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_prismaticJoint );
124
+ return joint->prismaticJoint.motorSpeed;
125
+ }
126
+
127
+ float b2PrismaticJoint_GetMotorForce( b2JointId jointId )
128
+ {
129
+ b2World* world = b2GetWorld( jointId.world0 );
130
+ b2JointSim* base = b2GetJointSimCheckType( jointId, b2_prismaticJoint );
131
+ return world->inv_h * base->prismaticJoint.motorImpulse;
132
+ }
133
+
134
+ void b2PrismaticJoint_SetMaxMotorForce( b2JointId jointId, float force )
135
+ {
136
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_prismaticJoint );
137
+ joint->prismaticJoint.maxMotorForce = force;
138
+ }
139
+
140
+ float b2PrismaticJoint_GetMaxMotorForce( b2JointId jointId )
141
+ {
142
+ b2JointSim* joint = b2GetJointSimCheckType( jointId, b2_prismaticJoint );
143
+ return joint->prismaticJoint.maxMotorForce;
144
+ }
145
+
146
+ float b2PrismaticJoint_GetTranslation(b2JointId jointId)
147
+ {
148
+ b2World* world = b2GetWorld( jointId.world0 );
149
+ b2JointSim* jointSim = b2GetJointSimCheckType( jointId, b2_prismaticJoint );
150
+ b2Transform transformA = b2GetBodyTransform( world, jointSim->bodyIdA );
151
+ b2Transform transformB = b2GetBodyTransform( world, jointSim->bodyIdB );
152
+
153
+ b2PrismaticJoint* joint = &jointSim->prismaticJoint;
154
+ b2Vec2 axisA = b2RotateVector( transformA.q, joint->localAxisA );
155
+ b2Vec2 pA = b2TransformPoint( transformA, jointSim->localOriginAnchorA );
156
+ b2Vec2 pB = b2TransformPoint( transformB, jointSim->localOriginAnchorB );
157
+ b2Vec2 d = b2Sub( pB, pA );
158
+ float translation = b2Dot( d, axisA );
159
+ return translation;
160
+ }
161
+
162
+ float b2PrismaticJoint_GetSpeed(b2JointId jointId)
163
+ {
164
+ b2World* world = b2GetWorld( jointId.world0 );
165
+ b2Joint* joint = b2GetJointFullId( world, jointId );
166
+ B2_ASSERT( joint->type == b2_prismaticJoint );
167
+ b2JointSim* jointSim = b2GetJointSim( world, joint );
168
+ B2_ASSERT( jointSim->type == b2_prismaticJoint );
169
+
170
+ b2Body* bodyA = b2BodyArray_Get( &world->bodies, jointSim->bodyIdA );
171
+ b2Body* bodyB = b2BodyArray_Get( &world->bodies, jointSim->bodyIdB );
172
+ b2BodySim* bodySimA = b2GetBodySim( world, bodyA );
173
+ b2BodySim* bodySimB = b2GetBodySim( world, bodyB );
174
+ b2BodyState* bodyStateA = b2GetBodyState( world, bodyA );
175
+ b2BodyState* bodyStateB = b2GetBodyState( world, bodyB );
176
+
177
+ b2Transform transformA = bodySimA->transform;
178
+ b2Transform transformB = bodySimB->transform;
179
+
180
+ b2PrismaticJoint* prismatic = &jointSim->prismaticJoint;
181
+ b2Vec2 axisA = b2RotateVector( transformA.q, prismatic->localAxisA );
182
+ b2Vec2 cA = bodySimA->center;
183
+ b2Vec2 cB = bodySimB->center;
184
+ b2Vec2 rA = b2RotateVector( transformA.q, b2Sub( jointSim->localOriginAnchorA, bodySimA->localCenter ) );
185
+ b2Vec2 rB = b2RotateVector( transformB.q, b2Sub( jointSim->localOriginAnchorB, bodySimB->localCenter ) );
186
+
187
+ b2Vec2 d = b2Add(b2Sub(cB, cA), b2Sub( rB, rA ));
188
+
189
+ b2Vec2 vA = bodyStateA ? bodyStateA->linearVelocity : b2Vec2_zero;
190
+ b2Vec2 vB = bodyStateB ? bodyStateB->linearVelocity : b2Vec2_zero;
191
+ float wA = bodyStateA ? bodyStateA->angularVelocity : 0.0f;
192
+ float wB = bodyStateB ? bodyStateB->angularVelocity : 0.0f;
193
+
194
+ b2Vec2 vRel = b2Sub( b2Add( vB, b2CrossSV( wB, rB ) ), b2Add( vA, b2CrossSV( wA, rA ) ) );
195
+ float speed = b2Dot( d, b2CrossSV( wA, axisA ) ) + b2Dot( axisA, vRel );
196
+ return speed;
197
+ }
198
+
199
+ b2Vec2 b2GetPrismaticJointForce( b2World* world, b2JointSim* base )
200
+ {
201
+ int idA = base->bodyIdA;
202
+ b2Transform transformA = b2GetBodyTransform( world, idA );
203
+
204
+ b2PrismaticJoint* joint = &base->prismaticJoint;
205
+
206
+ b2Vec2 axisA = b2RotateVector( transformA.q, joint->localAxisA );
207
+ b2Vec2 perpA = b2LeftPerp( axisA );
208
+
209
+ float inv_h = world->inv_h;
210
+ float perpForce = inv_h * joint->impulse.x;
211
+ float axialForce = inv_h * ( joint->motorImpulse + joint->lowerImpulse - joint->upperImpulse );
212
+
213
+ b2Vec2 force = b2Add( b2MulSV( perpForce, perpA ), b2MulSV( axialForce, axisA ) );
214
+ return force;
215
+ }
216
+
217
+ float b2GetPrismaticJointTorque( b2World* world, b2JointSim* base )
218
+ {
219
+ return world->inv_h * base->prismaticJoint.impulse.y;
220
+ }
221
+
222
+ // Linear constraint (point-to-line)
223
+ // d = p2 - p1 = x2 + r2 - x1 - r1
224
+ // C = dot(perp, d)
225
+ // Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1))
226
+ // = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2)
227
+ // J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)]
228
+ //
229
+ // Angular constraint
230
+ // C = a2 - a1 + a_initial
231
+ // Cdot = w2 - w1
232
+ // J = [0 0 -1 0 0 1]
233
+ //
234
+ // K = J * invM * JT
235
+ //
236
+ // J = [-a -s1 a s2]
237
+ // [0 -1 0 1]
238
+ // a = perp
239
+ // s1 = cross(d + r1, a) = cross(p2 - x1, a)
240
+ // s2 = cross(r2, a) = cross(p2 - x2, a)
241
+
242
+ // Motor/Limit linear constraint
243
+ // C = dot(ax1, d)
244
+ // Cdot = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2)
245
+ // J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)]
246
+
247
+ // Predictive limit is applied even when the limit is not active.
248
+ // Prevents a constraint speed that can lead to a constraint error in one time step.
249
+ // Want C2 = C1 + h * Cdot >= 0
250
+ // Or:
251
+ // Cdot + C1/h >= 0
252
+ // I do not apply a negative constraint error because that is handled in position correction.
253
+ // So:
254
+ // Cdot + max(C1, 0)/h >= 0
255
+
256
+ // Block Solver
257
+ // We develop a block solver that includes the angular and linear constraints. This makes the limit stiffer.
258
+ //
259
+ // The Jacobian has 2 rows:
260
+ // J = [-uT -s1 uT s2] // linear
261
+ // [0 -1 0 1] // angular
262
+ //
263
+ // u = perp
264
+ // s1 = cross(d + r1, u), s2 = cross(r2, u)
265
+ // a1 = cross(d + r1, v), a2 = cross(r2, v)
266
+
267
+ void b2PreparePrismaticJoint( b2JointSim* base, b2StepContext* context )
268
+ {
269
+ B2_ASSERT( base->type == b2_prismaticJoint );
270
+
271
+ // chase body id to the solver set where the body lives
272
+ int idA = base->bodyIdA;
273
+ int idB = base->bodyIdB;
274
+
275
+ b2World* world = context->world;
276
+
277
+ b2Body* bodyA = b2BodyArray_Get( &world->bodies, idA );
278
+ b2Body* bodyB = b2BodyArray_Get( &world->bodies, idB );
279
+
280
+ B2_ASSERT( bodyA->setIndex == b2_awakeSet || bodyB->setIndex == b2_awakeSet );
281
+ b2SolverSet* setA = b2SolverSetArray_Get( &world->solverSets, bodyA->setIndex );
282
+ b2SolverSet* setB = b2SolverSetArray_Get( &world->solverSets, bodyB->setIndex );
283
+
284
+ int localIndexA = bodyA->localIndex;
285
+ int localIndexB = bodyB->localIndex;
286
+
287
+ b2BodySim* bodySimA = b2BodySimArray_Get( &setA->bodySims, localIndexA );
288
+ b2BodySim* bodySimB = b2BodySimArray_Get( &setB->bodySims, localIndexB );
289
+
290
+ float mA = bodySimA->invMass;
291
+ float iA = bodySimA->invInertia;
292
+ float mB = bodySimB->invMass;
293
+ float iB = bodySimB->invInertia;
294
+
295
+ base->invMassA = mA;
296
+ base->invMassB = mB;
297
+ base->invIA = iA;
298
+ base->invIB = iB;
299
+
300
+ b2PrismaticJoint* joint = &base->prismaticJoint;
301
+ joint->indexA = bodyA->setIndex == b2_awakeSet ? localIndexA : B2_NULL_INDEX;
302
+ joint->indexB = bodyB->setIndex == b2_awakeSet ? localIndexB : B2_NULL_INDEX;
303
+
304
+ b2Rot qA = bodySimA->transform.q;
305
+ b2Rot qB = bodySimB->transform.q;
306
+
307
+ joint->anchorA = b2RotateVector( qA, b2Sub( base->localOriginAnchorA, bodySimA->localCenter ) );
308
+ joint->anchorB = b2RotateVector( qB, b2Sub( base->localOriginAnchorB, bodySimB->localCenter ) );
309
+ joint->axisA = b2RotateVector( qA, joint->localAxisA );
310
+ joint->deltaCenter = b2Sub( bodySimB->center, bodySimA->center );
311
+ joint->deltaAngle = b2RelativeAngle( qB, qA ) - joint->referenceAngle;
312
+ joint->deltaAngle = b2UnwindAngle( joint->deltaAngle );
313
+
314
+ b2Vec2 rA = joint->anchorA;
315
+ b2Vec2 rB = joint->anchorB;
316
+
317
+ b2Vec2 d = b2Add( joint->deltaCenter, b2Sub( rB, rA ) );
318
+ float a1 = b2Cross( b2Add( d, rA ), joint->axisA );
319
+ float a2 = b2Cross( rB, joint->axisA );
320
+
321
+ // effective masses
322
+ float k = mA + mB + iA * a1 * a1 + iB * a2 * a2;
323
+ joint->axialMass = k > 0.0f ? 1.0f / k : 0.0f;
324
+
325
+ joint->springSoftness = b2MakeSoft( joint->hertz, joint->dampingRatio, context->h );
326
+
327
+ if ( context->enableWarmStarting == false )
328
+ {
329
+ joint->impulse = b2Vec2_zero;
330
+ joint->springImpulse = 0.0f;
331
+ joint->motorImpulse = 0.0f;
332
+ joint->lowerImpulse = 0.0f;
333
+ joint->upperImpulse = 0.0f;
334
+ }
335
+ }
336
+
337
+ void b2WarmStartPrismaticJoint( b2JointSim* base, b2StepContext* context )
338
+ {
339
+ B2_ASSERT( base->type == b2_prismaticJoint );
340
+
341
+ float mA = base->invMassA;
342
+ float mB = base->invMassB;
343
+ float iA = base->invIA;
344
+ float iB = base->invIB;
345
+
346
+ // dummy state for static bodies
347
+ b2BodyState dummyState = b2_identityBodyState;
348
+
349
+ b2PrismaticJoint* joint = &base->prismaticJoint;
350
+
351
+ b2BodyState* stateA = joint->indexA == B2_NULL_INDEX ? &dummyState : context->states + joint->indexA;
352
+ b2BodyState* stateB = joint->indexB == B2_NULL_INDEX ? &dummyState : context->states + joint->indexB;
353
+
354
+ b2Vec2 rA = b2RotateVector( stateA->deltaRotation, joint->anchorA );
355
+ b2Vec2 rB = b2RotateVector( stateB->deltaRotation, joint->anchorB );
356
+
357
+ b2Vec2 d = b2Add( b2Add( b2Sub( stateB->deltaPosition, stateA->deltaPosition ), joint->deltaCenter ), b2Sub( rB, rA ) );
358
+ b2Vec2 axisA = b2RotateVector( stateA->deltaRotation, joint->axisA );
359
+
360
+ // impulse is applied at anchor point on body B
361
+ float a1 = b2Cross( b2Add( d, rA ), axisA );
362
+ float a2 = b2Cross( rB, axisA );
363
+ float axialImpulse = joint->springImpulse + joint->motorImpulse + joint->lowerImpulse - joint->upperImpulse;
364
+
365
+ // perpendicular constraint
366
+ b2Vec2 perpA = b2LeftPerp( axisA );
367
+ float s1 = b2Cross( b2Add( d, rA ), perpA );
368
+ float s2 = b2Cross( rB, perpA );
369
+ float perpImpulse = joint->impulse.x;
370
+ float angleImpulse = joint->impulse.y;
371
+
372
+ b2Vec2 P = b2Add( b2MulSV( axialImpulse, axisA ), b2MulSV( perpImpulse, perpA ) );
373
+ float LA = axialImpulse * a1 + perpImpulse * s1 + angleImpulse;
374
+ float LB = axialImpulse * a2 + perpImpulse * s2 + angleImpulse;
375
+
376
+ stateA->linearVelocity = b2MulSub( stateA->linearVelocity, mA, P );
377
+ stateA->angularVelocity -= iA * LA;
378
+ stateB->linearVelocity = b2MulAdd( stateB->linearVelocity, mB, P );
379
+ stateB->angularVelocity += iB * LB;
380
+ }
381
+
382
+ void b2SolvePrismaticJoint( b2JointSim* base, b2StepContext* context, bool useBias )
383
+ {
384
+ B2_ASSERT( base->type == b2_prismaticJoint );
385
+
386
+ float mA = base->invMassA;
387
+ float mB = base->invMassB;
388
+ float iA = base->invIA;
389
+ float iB = base->invIB;
390
+
391
+ // dummy state for static bodies
392
+ b2BodyState dummyState = b2_identityBodyState;
393
+
394
+ b2PrismaticJoint* joint = &base->prismaticJoint;
395
+
396
+ b2BodyState* stateA = joint->indexA == B2_NULL_INDEX ? &dummyState : context->states + joint->indexA;
397
+ b2BodyState* stateB = joint->indexB == B2_NULL_INDEX ? &dummyState : context->states + joint->indexB;
398
+
399
+ b2Vec2 vA = stateA->linearVelocity;
400
+ float wA = stateA->angularVelocity;
401
+ b2Vec2 vB = stateB->linearVelocity;
402
+ float wB = stateB->angularVelocity;
403
+
404
+ // current anchors
405
+ b2Vec2 rA = b2RotateVector( stateA->deltaRotation, joint->anchorA );
406
+ b2Vec2 rB = b2RotateVector( stateB->deltaRotation, joint->anchorB );
407
+
408
+ b2Vec2 d = b2Add( b2Add( b2Sub( stateB->deltaPosition, stateA->deltaPosition ), joint->deltaCenter ), b2Sub( rB, rA ) );
409
+ b2Vec2 axisA = b2RotateVector( stateA->deltaRotation, joint->axisA );
410
+ float translation = b2Dot( axisA, d );
411
+
412
+ // These scalars are for torques generated by axial forces
413
+ float a1 = b2Cross( b2Add( d, rA ), axisA );
414
+ float a2 = b2Cross( rB, axisA );
415
+
416
+ // spring constraint
417
+ if ( joint->enableSpring )
418
+ {
419
+ // This is a real spring and should be applied even during relax
420
+ float C = translation;
421
+ float bias = joint->springSoftness.biasRate * C;
422
+ float massScale = joint->springSoftness.massScale;
423
+ float impulseScale = joint->springSoftness.impulseScale;
424
+
425
+ float Cdot = b2Dot( axisA, b2Sub( vB, vA ) ) + a2 * wB - a1 * wA;
426
+ float deltaImpulse = -massScale * joint->axialMass * ( Cdot + bias ) - impulseScale * joint->springImpulse;
427
+ joint->springImpulse += deltaImpulse;
428
+
429
+ b2Vec2 P = b2MulSV( deltaImpulse, axisA );
430
+ float LA = deltaImpulse * a1;
431
+ float LB = deltaImpulse * a2;
432
+
433
+ vA = b2MulSub( vA, mA, P );
434
+ wA -= iA * LA;
435
+ vB = b2MulAdd( vB, mB, P );
436
+ wB += iB * LB;
437
+ }
438
+
439
+ // Solve motor constraint
440
+ if ( joint->enableMotor )
441
+ {
442
+ float Cdot = b2Dot( axisA, b2Sub( vB, vA ) ) + a2 * wB - a1 * wA;
443
+ float impulse = joint->axialMass * ( joint->motorSpeed - Cdot );
444
+ float oldImpulse = joint->motorImpulse;
445
+ float maxImpulse = context->h * joint->maxMotorForce;
446
+ joint->motorImpulse = b2ClampFloat( joint->motorImpulse + impulse, -maxImpulse, maxImpulse );
447
+ impulse = joint->motorImpulse - oldImpulse;
448
+
449
+ b2Vec2 P = b2MulSV( impulse, axisA );
450
+ float LA = impulse * a1;
451
+ float LB = impulse * a2;
452
+
453
+ vA = b2MulSub( vA, mA, P );
454
+ wA -= iA * LA;
455
+ vB = b2MulAdd( vB, mB, P );
456
+ wB += iB * LB;
457
+ }
458
+
459
+ if ( joint->enableLimit )
460
+ {
461
+ // Lower limit
462
+ {
463
+ float C = translation - joint->lowerTranslation;
464
+ float bias = 0.0f;
465
+ float massScale = 1.0f;
466
+ float impulseScale = 0.0f;
467
+
468
+ if ( C > 0.0f )
469
+ {
470
+ // speculation
471
+ bias = C * context->inv_h;
472
+ }
473
+ else if ( useBias )
474
+ {
475
+ bias = context->jointSoftness.biasRate * C;
476
+ massScale = context->jointSoftness.massScale;
477
+ impulseScale = context->jointSoftness.impulseScale;
478
+ }
479
+
480
+ float oldImpulse = joint->lowerImpulse;
481
+ float Cdot = b2Dot( axisA, b2Sub( vB, vA ) ) + a2 * wB - a1 * wA;
482
+ float impulse = -joint->axialMass * massScale * ( Cdot + bias ) - impulseScale * oldImpulse;
483
+ joint->lowerImpulse = b2MaxFloat( oldImpulse + impulse, 0.0f );
484
+ impulse = joint->lowerImpulse - oldImpulse;
485
+
486
+ b2Vec2 P = b2MulSV( impulse, axisA );
487
+ float LA = impulse * a1;
488
+ float LB = impulse * a2;
489
+
490
+ vA = b2MulSub( vA, mA, P );
491
+ wA -= iA * LA;
492
+ vB = b2MulAdd( vB, mB, P );
493
+ wB += iB * LB;
494
+ }
495
+
496
+ // Upper limit
497
+ // Note: signs are flipped to keep C positive when the constraint is satisfied.
498
+ // This also keeps the impulse positive when the limit is active.
499
+ {
500
+ // sign flipped
501
+ float C = joint->upperTranslation - translation;
502
+ float bias = 0.0f;
503
+ float massScale = 1.0f;
504
+ float impulseScale = 0.0f;
505
+
506
+ if ( C > 0.0f )
507
+ {
508
+ // speculation
509
+ bias = C * context->inv_h;
510
+ }
511
+ else if ( useBias )
512
+ {
513
+ bias = context->jointSoftness.biasRate * C;
514
+ massScale = context->jointSoftness.massScale;
515
+ impulseScale = context->jointSoftness.impulseScale;
516
+ }
517
+
518
+ float oldImpulse = joint->upperImpulse;
519
+ // sign flipped
520
+ float Cdot = b2Dot( axisA, b2Sub( vA, vB ) ) + a1 * wA - a2 * wB;
521
+ float impulse = -joint->axialMass * massScale * ( Cdot + bias ) - impulseScale * oldImpulse;
522
+ joint->upperImpulse = b2MaxFloat( oldImpulse + impulse, 0.0f );
523
+ impulse = joint->upperImpulse - oldImpulse;
524
+
525
+ b2Vec2 P = b2MulSV( impulse, axisA );
526
+ float LA = impulse * a1;
527
+ float LB = impulse * a2;
528
+
529
+ // sign flipped
530
+ vA = b2MulAdd( vA, mA, P );
531
+ wA += iA * LA;
532
+ vB = b2MulSub( vB, mB, P );
533
+ wB -= iB * LB;
534
+ }
535
+ }
536
+
537
+ // Solve the prismatic constraint in block form
538
+ {
539
+ b2Vec2 perpA = b2LeftPerp( axisA );
540
+
541
+ // These scalars are for torques generated by the perpendicular constraint force
542
+ float s1 = b2Cross( b2Add( d, rA ), perpA );
543
+ float s2 = b2Cross( rB, perpA );
544
+
545
+ b2Vec2 Cdot;
546
+ Cdot.x = b2Dot( perpA, b2Sub( vB, vA ) ) + s2 * wB - s1 * wA;
547
+ Cdot.y = wB - wA;
548
+
549
+ b2Vec2 bias = b2Vec2_zero;
550
+ float massScale = 1.0f;
551
+ float impulseScale = 0.0f;
552
+ if ( useBias )
553
+ {
554
+ b2Vec2 C;
555
+ C.x = b2Dot( perpA, d );
556
+ C.y = b2RelativeAngle( stateB->deltaRotation, stateA->deltaRotation ) + joint->deltaAngle;
557
+
558
+ bias = b2MulSV( context->jointSoftness.biasRate, C );
559
+ massScale = context->jointSoftness.massScale;
560
+ impulseScale = context->jointSoftness.impulseScale;
561
+ }
562
+
563
+ float k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2;
564
+ float k12 = iA * s1 + iB * s2;
565
+ float k22 = iA + iB;
566
+ if ( k22 == 0.0f )
567
+ {
568
+ // For bodies with fixed rotation.
569
+ k22 = 1.0f;
570
+ }
571
+
572
+ b2Mat22 K = { { k11, k12 }, { k12, k22 } };
573
+
574
+ b2Vec2 b = b2Solve22( K, b2Add( Cdot, bias ) );
575
+ b2Vec2 impulse;
576
+ impulse.x = -massScale * b.x - impulseScale * joint->impulse.x;
577
+ impulse.y = -massScale * b.y - impulseScale * joint->impulse.y;
578
+
579
+ joint->impulse.x += impulse.x;
580
+ joint->impulse.y += impulse.y;
581
+
582
+ b2Vec2 P = b2MulSV( impulse.x, perpA );
583
+ float LA = impulse.x * s1 + impulse.y;
584
+ float LB = impulse.x * s2 + impulse.y;
585
+
586
+ vA = b2MulSub( vA, mA, P );
587
+ wA -= iA * LA;
588
+ vB = b2MulAdd( vB, mB, P );
589
+ wB += iB * LB;
590
+ }
591
+
592
+ stateA->linearVelocity = vA;
593
+ stateA->angularVelocity = wA;
594
+ stateB->linearVelocity = vB;
595
+ stateB->angularVelocity = wB;
596
+ }
597
+
598
+ #if 0
599
+ void b2PrismaticJoint::Dump()
600
+ {
601
+ int32 indexA = joint->bodyA->joint->islandIndex;
602
+ int32 indexB = joint->bodyB->joint->islandIndex;
603
+
604
+ b2Dump(" b2PrismaticJointDef jd;\n");
605
+ b2Dump(" jd.bodyA = sims[%d];\n", indexA);
606
+ b2Dump(" jd.bodyB = sims[%d];\n", indexB);
607
+ b2Dump(" jd.collideConnected = bool(%d);\n", joint->collideConnected);
608
+ b2Dump(" jd.localAnchorA.Set(%.9g, %.9g);\n", joint->localAnchorA.x, joint->localAnchorA.y);
609
+ b2Dump(" jd.localAnchorB.Set(%.9g, %.9g);\n", joint->localAnchorB.x, joint->localAnchorB.y);
610
+ b2Dump(" jd.referenceAngle = %.9g;\n", joint->referenceAngle);
611
+ b2Dump(" jd.enableLimit = bool(%d);\n", joint->enableLimit);
612
+ b2Dump(" jd.lowerAngle = %.9g;\n", joint->lowerAngle);
613
+ b2Dump(" jd.upperAngle = %.9g;\n", joint->upperAngle);
614
+ b2Dump(" jd.enableMotor = bool(%d);\n", joint->enableMotor);
615
+ b2Dump(" jd.motorSpeed = %.9g;\n", joint->motorSpeed);
616
+ b2Dump(" jd.maxMotorTorque = %.9g;\n", joint->maxMotorTorque);
617
+ b2Dump(" joints[%d] = joint->world->CreateJoint(&jd);\n", joint->index);
618
+ }
619
+ #endif
620
+
621
+ void b2DrawPrismaticJoint( b2DebugDraw* draw, b2JointSim* base, b2Transform transformA, b2Transform transformB )
622
+ {
623
+ B2_ASSERT( base->type == b2_prismaticJoint );
624
+
625
+ b2PrismaticJoint* joint = &base->prismaticJoint;
626
+
627
+ b2Vec2 pA = b2TransformPoint( transformA, base->localOriginAnchorA );
628
+ b2Vec2 pB = b2TransformPoint( transformB, base->localOriginAnchorB );
629
+
630
+ b2Vec2 axis = b2RotateVector( transformA.q, joint->localAxisA );
631
+
632
+ b2HexColor c1 = b2_colorGray;
633
+ b2HexColor c2 = b2_colorGreen;
634
+ b2HexColor c3 = b2_colorRed;
635
+ b2HexColor c4 = b2_colorBlue;
636
+ b2HexColor c5 = b2_colorDimGray;
637
+
638
+ draw->DrawSegmentFcn( pA, pB, c5, draw->context );
639
+
640
+ if ( joint->enableLimit )
641
+ {
642
+ b2Vec2 lower = b2MulAdd( pA, joint->lowerTranslation, axis );
643
+ b2Vec2 upper = b2MulAdd( pA, joint->upperTranslation, axis );
644
+ b2Vec2 perp = b2LeftPerp( axis );
645
+ draw->DrawSegmentFcn( lower, upper, c1, draw->context );
646
+ draw->DrawSegmentFcn( b2MulSub( lower, 0.1f, perp ), b2MulAdd( lower, 0.1f, perp ), c2, draw->context );
647
+ draw->DrawSegmentFcn( b2MulSub( upper, 0.1f, perp ), b2MulAdd( upper, 0.1f, perp ), c3, draw->context );
648
+ }
649
+ else
650
+ {
651
+ draw->DrawSegmentFcn( b2MulSub( pA, 1.0f, axis ), b2MulAdd( pA, 1.0f, axis ), c1, draw->context );
652
+ }
653
+
654
+ draw->DrawPointFcn( pA, 5.0f, c1, draw->context );
655
+ draw->DrawPointFcn( pB, 5.0f, c4, draw->context );
656
+ }