1 | /* |
2 | * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org |
3 | * |
4 | * This software is provided 'as-is', without any express or implied |
5 | * warranty. In no event will the authors be held liable for any damages |
6 | * arising from the use of this software. |
7 | * Permission is granted to anyone to use this software for any purpose, |
8 | * including commercial applications, and to alter it and redistribute it |
9 | * freely, subject to the following restrictions: |
10 | * 1. The origin of this software must not be misrepresented; you must not |
11 | * claim that you wrote the original software. If you use this software |
12 | * in a product, an acknowledgment in the product documentation would be |
13 | * appreciated but is not required. |
14 | * 2. Altered source versions must be plainly marked as such, and must not be |
15 | * misrepresented as being the original software. |
16 | * 3. This notice may not be removed or altered from any source distribution. |
17 | */ |
18 | |
19 | #include <Box2D/Dynamics/Joints/b2PrismaticJoint.h> |
20 | #include <Box2D/Dynamics/b2Body.h> |
21 | #include <Box2D/Dynamics/b2TimeStep.h> |
22 | |
23 | // Linear constraint (point-to-line) |
24 | // d = p2 - p1 = x2 + r2 - x1 - r1 |
25 | // C = dot(perp, d) |
26 | // Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1)) |
27 | // = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2) |
28 | // J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)] |
29 | // |
30 | // Angular constraint |
31 | // C = a2 - a1 + a_initial |
32 | // Cdot = w2 - w1 |
33 | // J = [0 0 -1 0 0 1] |
34 | // |
35 | // K = J * invM * JT |
36 | // |
37 | // J = [-a -s1 a s2] |
38 | // [0 -1 0 1] |
39 | // a = perp |
40 | // s1 = cross(d + r1, a) = cross(p2 - x1, a) |
41 | // s2 = cross(r2, a) = cross(p2 - x2, a) |
42 | |
43 | |
44 | // Motor/Limit linear constraint |
45 | // C = dot(ax1, d) |
46 | // Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2) |
47 | // J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)] |
48 | |
49 | // Block Solver |
50 | // We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even |
51 | // when the mass has poor distribution (leading to large torques about the joint anchor points). |
52 | // |
53 | // The Jacobian has 3 rows: |
54 | // J = [-uT -s1 uT s2] // linear |
55 | // [0 -1 0 1] // angular |
56 | // [-vT -a1 vT a2] // limit |
57 | // |
58 | // u = perp |
59 | // v = axis |
60 | // s1 = cross(d + r1, u), s2 = cross(r2, u) |
61 | // a1 = cross(d + r1, v), a2 = cross(r2, v) |
62 | |
63 | // M * (v2 - v1) = JT * df |
64 | // J * v2 = bias |
65 | // |
66 | // v2 = v1 + invM * JT * df |
67 | // J * (v1 + invM * JT * df) = bias |
68 | // K * df = bias - J * v1 = -Cdot |
69 | // K = J * invM * JT |
70 | // Cdot = J * v1 - bias |
71 | // |
72 | // Now solve for f2. |
73 | // df = f2 - f1 |
74 | // K * (f2 - f1) = -Cdot |
75 | // f2 = invK * (-Cdot) + f1 |
76 | // |
77 | // Clamp accumulated limit impulse. |
78 | // lower: f2(3) = max(f2(3), 0) |
79 | // upper: f2(3) = min(f2(3), 0) |
80 | // |
81 | // Solve for correct f2(1:2) |
82 | // K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:3) * f1 |
83 | // = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:2) * f1(1:2) + K(1:2,3) * f1(3) |
84 | // K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3)) + K(1:2,1:2) * f1(1:2) |
85 | // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2) |
86 | // |
87 | // Now compute impulse to be applied: |
88 | // df = f2 - f1 |
89 | |
90 | void b2PrismaticJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis) |
91 | { |
92 | bodyA = bA; |
93 | bodyB = bB; |
94 | localAnchorA = bodyA->GetLocalPoint(anchor); |
95 | localAnchorB = bodyB->GetLocalPoint(anchor); |
96 | localAxisA = bodyA->GetLocalVector(axis); |
97 | referenceAngle = bodyB->GetAngle() - bodyA->GetAngle(); |
98 | } |
99 | |
100 | b2PrismaticJoint::b2PrismaticJoint(const b2PrismaticJointDef* def) |
101 | : b2Joint(def) |
102 | { |
103 | m_localAnchorA = def->localAnchorA; |
104 | m_localAnchorB = def->localAnchorB; |
105 | m_localXAxisA = def->localAxisA; |
106 | m_localXAxisA.Normalize(); |
107 | m_localYAxisA = b2Cross(1.0f, m_localXAxisA); |
108 | m_referenceAngle = def->referenceAngle; |
109 | |
110 | m_impulse.SetZero(); |
111 | m_motorMass = 0.0f; |
112 | m_motorImpulse = 0.0f; |
113 | |
114 | m_lowerTranslation = def->lowerTranslation; |
115 | m_upperTranslation = def->upperTranslation; |
116 | m_maxMotorForce = def->maxMotorForce; |
117 | m_motorSpeed = def->motorSpeed; |
118 | m_enableLimit = def->enableLimit; |
119 | m_enableMotor = def->enableMotor; |
120 | m_limitState = e_inactiveLimit; |
121 | |
122 | m_axis.SetZero(); |
123 | m_perp.SetZero(); |
124 | } |
125 | |
126 | void b2PrismaticJoint::InitVelocityConstraints(const b2SolverData& data) |
127 | { |
128 | m_indexA = m_bodyA->m_islandIndex; |
129 | m_indexB = m_bodyB->m_islandIndex; |
130 | m_localCenterA = m_bodyA->m_sweep.localCenter; |
131 | m_localCenterB = m_bodyB->m_sweep.localCenter; |
132 | m_invMassA = m_bodyA->m_invMass; |
133 | m_invMassB = m_bodyB->m_invMass; |
134 | m_invIA = m_bodyA->m_invI; |
135 | m_invIB = m_bodyB->m_invI; |
136 | |
137 | b2Vec2 cA = data.positions[m_indexA].c; |
138 | float32 aA = data.positions[m_indexA].a; |
139 | b2Vec2 vA = data.velocities[m_indexA].v; |
140 | float32 wA = data.velocities[m_indexA].w; |
141 | |
142 | b2Vec2 cB = data.positions[m_indexB].c; |
143 | float32 aB = data.positions[m_indexB].a; |
144 | b2Vec2 vB = data.velocities[m_indexB].v; |
145 | float32 wB = data.velocities[m_indexB].w; |
146 | |
147 | b2Rot qA(aA), qB(aB); |
148 | |
149 | // Compute the effective masses. |
150 | b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); |
151 | b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); |
152 | b2Vec2 d = (cB - cA) + rB - rA; |
153 | |
154 | float32 mA = m_invMassA, mB = m_invMassB; |
155 | float32 iA = m_invIA, iB = m_invIB; |
156 | |
157 | // Compute motor Jacobian and effective mass. |
158 | { |
159 | m_axis = b2Mul(qA, m_localXAxisA); |
160 | m_a1 = b2Cross(d + rA, m_axis); |
161 | m_a2 = b2Cross(rB, m_axis); |
162 | |
163 | m_motorMass = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2; |
164 | if (m_motorMass > 0.0f) |
165 | { |
166 | m_motorMass = 1.0f / m_motorMass; |
167 | } |
168 | } |
169 | |
170 | // Prismatic constraint. |
171 | { |
172 | m_perp = b2Mul(qA, m_localYAxisA); |
173 | |
174 | m_s1 = b2Cross(d + rA, m_perp); |
175 | m_s2 = b2Cross(rB, m_perp); |
176 | |
177 | float32 s1test; |
178 | s1test = b2Cross(rA, m_perp); |
179 | |
180 | float32 k11 = mA + mB + iA * m_s1 * m_s1 + iB * m_s2 * m_s2; |
181 | float32 k12 = iA * m_s1 + iB * m_s2; |
182 | float32 k13 = iA * m_s1 * m_a1 + iB * m_s2 * m_a2; |
183 | float32 k22 = iA + iB; |
184 | if (k22 == 0.0f) |
185 | { |
186 | // For bodies with fixed rotation. |
187 | k22 = 1.0f; |
188 | } |
189 | float32 k23 = iA * m_a1 + iB * m_a2; |
190 | float32 k33 = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2; |
191 | |
192 | m_K.ex.Set(k11, k12, k13); |
193 | m_K.ey.Set(k12, k22, k23); |
194 | m_K.ez.Set(k13, k23, k33); |
195 | } |
196 | |
197 | // Compute motor and limit terms. |
198 | if (m_enableLimit) |
199 | { |
200 | float32 jointTranslation = b2Dot(m_axis, d); |
201 | if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop) |
202 | { |
203 | m_limitState = e_equalLimits; |
204 | } |
205 | else if (jointTranslation <= m_lowerTranslation) |
206 | { |
207 | if (m_limitState != e_atLowerLimit) |
208 | { |
209 | m_limitState = e_atLowerLimit; |
210 | m_impulse.z = 0.0f; |
211 | } |
212 | } |
213 | else if (jointTranslation >= m_upperTranslation) |
214 | { |
215 | if (m_limitState != e_atUpperLimit) |
216 | { |
217 | m_limitState = e_atUpperLimit; |
218 | m_impulse.z = 0.0f; |
219 | } |
220 | } |
221 | else |
222 | { |
223 | m_limitState = e_inactiveLimit; |
224 | m_impulse.z = 0.0f; |
225 | } |
226 | } |
227 | else |
228 | { |
229 | m_limitState = e_inactiveLimit; |
230 | m_impulse.z = 0.0f; |
231 | } |
232 | |
233 | if (m_enableMotor == false) |
234 | { |
235 | m_motorImpulse = 0.0f; |
236 | } |
237 | |
238 | if (data.step.warmStarting) |
239 | { |
240 | // Account for variable time step. |
241 | m_impulse *= data.step.dtRatio; |
242 | m_motorImpulse *= data.step.dtRatio; |
243 | |
244 | b2Vec2 P = m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis; |
245 | float32 LA = m_impulse.x * m_s1 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a1; |
246 | float32 LB = m_impulse.x * m_s2 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a2; |
247 | |
248 | vA -= mA * P; |
249 | wA -= iA * LA; |
250 | |
251 | vB += mB * P; |
252 | wB += iB * LB; |
253 | } |
254 | else |
255 | { |
256 | m_impulse.SetZero(); |
257 | m_motorImpulse = 0.0f; |
258 | } |
259 | |
260 | data.velocities[m_indexA].v = vA; |
261 | data.velocities[m_indexA].w = wA; |
262 | data.velocities[m_indexB].v = vB; |
263 | data.velocities[m_indexB].w = wB; |
264 | } |
265 | |
266 | void b2PrismaticJoint::SolveVelocityConstraints(const b2SolverData& data) |
267 | { |
268 | b2Vec2 vA = data.velocities[m_indexA].v; |
269 | float32 wA = data.velocities[m_indexA].w; |
270 | b2Vec2 vB = data.velocities[m_indexB].v; |
271 | float32 wB = data.velocities[m_indexB].w; |
272 | |
273 | float32 mA = m_invMassA, mB = m_invMassB; |
274 | float32 iA = m_invIA, iB = m_invIB; |
275 | |
276 | // Solve linear motor constraint. |
277 | if (m_enableMotor && m_limitState != e_equalLimits) |
278 | { |
279 | float32 Cdot = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA; |
280 | float32 impulse = m_motorMass * (m_motorSpeed - Cdot); |
281 | float32 oldImpulse = m_motorImpulse; |
282 | float32 maxImpulse = data.step.dt * m_maxMotorForce; |
283 | m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); |
284 | impulse = m_motorImpulse - oldImpulse; |
285 | |
286 | b2Vec2 P = impulse * m_axis; |
287 | float32 LA = impulse * m_a1; |
288 | float32 LB = impulse * m_a2; |
289 | |
290 | vA -= mA * P; |
291 | wA -= iA * LA; |
292 | |
293 | vB += mB * P; |
294 | wB += iB * LB; |
295 | } |
296 | |
297 | b2Vec2 Cdot1; |
298 | Cdot1.x = b2Dot(m_perp, vB - vA) + m_s2 * wB - m_s1 * wA; |
299 | Cdot1.y = wB - wA; |
300 | |
301 | if (m_enableLimit && m_limitState != e_inactiveLimit) |
302 | { |
303 | // Solve prismatic and limit constraint in block form. |
304 | float32 Cdot2; |
305 | Cdot2 = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA; |
306 | b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); |
307 | |
308 | b2Vec3 f1 = m_impulse; |
309 | b2Vec3 df = m_K.Solve33(-Cdot); |
310 | m_impulse += df; |
311 | |
312 | if (m_limitState == e_atLowerLimit) |
313 | { |
314 | m_impulse.z = b2Max(m_impulse.z, 0.0f); |
315 | } |
316 | else if (m_limitState == e_atUpperLimit) |
317 | { |
318 | m_impulse.z = b2Min(m_impulse.z, 0.0f); |
319 | } |
320 | |
321 | // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2) |
322 | b2Vec2 b = -Cdot1 - (m_impulse.z - f1.z) * b2Vec2(m_K.ez.x, m_K.ez.y); |
323 | b2Vec2 f2r = m_K.Solve22(b) + b2Vec2(f1.x, f1.y); |
324 | m_impulse.x = f2r.x; |
325 | m_impulse.y = f2r.y; |
326 | |
327 | df = m_impulse - f1; |
328 | |
329 | b2Vec2 P = df.x * m_perp + df.z * m_axis; |
330 | float32 LA = df.x * m_s1 + df.y + df.z * m_a1; |
331 | float32 LB = df.x * m_s2 + df.y + df.z * m_a2; |
332 | |
333 | vA -= mA * P; |
334 | wA -= iA * LA; |
335 | |
336 | vB += mB * P; |
337 | wB += iB * LB; |
338 | } |
339 | else |
340 | { |
341 | // Limit is inactive, just solve the prismatic constraint in block form. |
342 | b2Vec2 df = m_K.Solve22(-Cdot1); |
343 | m_impulse.x += df.x; |
344 | m_impulse.y += df.y; |
345 | |
346 | b2Vec2 P = df.x * m_perp; |
347 | float32 LA = df.x * m_s1 + df.y; |
348 | float32 LB = df.x * m_s2 + df.y; |
349 | |
350 | vA -= mA * P; |
351 | wA -= iA * LA; |
352 | |
353 | vB += mB * P; |
354 | wB += iB * LB; |
355 | } |
356 | |
357 | data.velocities[m_indexA].v = vA; |
358 | data.velocities[m_indexA].w = wA; |
359 | data.velocities[m_indexB].v = vB; |
360 | data.velocities[m_indexB].w = wB; |
361 | } |
362 | |
363 | bool b2PrismaticJoint::SolvePositionConstraints(const b2SolverData& data) |
364 | { |
365 | b2Vec2 cA = data.positions[m_indexA].c; |
366 | float32 aA = data.positions[m_indexA].a; |
367 | b2Vec2 cB = data.positions[m_indexB].c; |
368 | float32 aB = data.positions[m_indexB].a; |
369 | |
370 | b2Rot qA(aA), qB(aB); |
371 | |
372 | float32 mA = m_invMassA, mB = m_invMassB; |
373 | float32 iA = m_invIA, iB = m_invIB; |
374 | |
375 | // Compute fresh Jacobians |
376 | b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); |
377 | b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); |
378 | b2Vec2 d = cB + rB - cA - rA; |
379 | |
380 | b2Vec2 axis = b2Mul(qA, m_localXAxisA); |
381 | float32 a1 = b2Cross(d + rA, axis); |
382 | float32 a2 = b2Cross(rB, axis); |
383 | b2Vec2 perp = b2Mul(qA, m_localYAxisA); |
384 | |
385 | float32 s1 = b2Cross(d + rA, perp); |
386 | float32 s2 = b2Cross(rB, perp); |
387 | |
388 | b2Vec3 impulse; |
389 | b2Vec2 C1; |
390 | C1.x = b2Dot(perp, d); |
391 | C1.y = aB - aA - m_referenceAngle; |
392 | |
393 | float32 linearError = b2Abs(C1.x); |
394 | float32 angularError = b2Abs(C1.y); |
395 | |
396 | bool active = false; |
397 | float32 C2 = 0.0f; |
398 | if (m_enableLimit) |
399 | { |
400 | float32 translation = b2Dot(axis, d); |
401 | if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop) |
402 | { |
403 | // Prevent large angular corrections |
404 | C2 = b2Clamp(translation, -b2_maxLinearCorrection, b2_maxLinearCorrection); |
405 | linearError = b2Max(linearError, b2Abs(translation)); |
406 | active = true; |
407 | } |
408 | else if (translation <= m_lowerTranslation) |
409 | { |
410 | // Prevent large linear corrections and allow some slop. |
411 | C2 = b2Clamp(translation - m_lowerTranslation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f); |
412 | linearError = b2Max(linearError, m_lowerTranslation - translation); |
413 | active = true; |
414 | } |
415 | else if (translation >= m_upperTranslation) |
416 | { |
417 | // Prevent large linear corrections and allow some slop. |
418 | C2 = b2Clamp(translation - m_upperTranslation - b2_linearSlop, 0.0f, b2_maxLinearCorrection); |
419 | linearError = b2Max(linearError, translation - m_upperTranslation); |
420 | active = true; |
421 | } |
422 | } |
423 | |
424 | if (active) |
425 | { |
426 | float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2; |
427 | float32 k12 = iA * s1 + iB * s2; |
428 | float32 k13 = iA * s1 * a1 + iB * s2 * a2; |
429 | float32 k22 = iA + iB; |
430 | if (k22 == 0.0f) |
431 | { |
432 | // For fixed rotation |
433 | k22 = 1.0f; |
434 | } |
435 | float32 k23 = iA * a1 + iB * a2; |
436 | float32 k33 = mA + mB + iA * a1 * a1 + iB * a2 * a2; |
437 | |
438 | b2Mat33 K; |
439 | K.ex.Set(k11, k12, k13); |
440 | K.ey.Set(k12, k22, k23); |
441 | K.ez.Set(k13, k23, k33); |
442 | |
443 | b2Vec3 C; |
444 | C.x = C1.x; |
445 | C.y = C1.y; |
446 | C.z = C2; |
447 | |
448 | impulse = K.Solve33(-C); |
449 | } |
450 | else |
451 | { |
452 | float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2; |
453 | float32 k12 = iA * s1 + iB * s2; |
454 | float32 k22 = iA + iB; |
455 | if (k22 == 0.0f) |
456 | { |
457 | k22 = 1.0f; |
458 | } |
459 | |
460 | b2Mat22 K; |
461 | K.ex.Set(k11, k12); |
462 | K.ey.Set(k12, k22); |
463 | |
464 | b2Vec2 impulse1 = K.Solve(-C1); |
465 | impulse.x = impulse1.x; |
466 | impulse.y = impulse1.y; |
467 | impulse.z = 0.0f; |
468 | } |
469 | |
470 | b2Vec2 P = impulse.x * perp + impulse.z * axis; |
471 | float32 LA = impulse.x * s1 + impulse.y + impulse.z * a1; |
472 | float32 LB = impulse.x * s2 + impulse.y + impulse.z * a2; |
473 | |
474 | cA -= mA * P; |
475 | aA -= iA * LA; |
476 | cB += mB * P; |
477 | aB += iB * LB; |
478 | |
479 | data.positions[m_indexA].c = cA; |
480 | data.positions[m_indexA].a = aA; |
481 | data.positions[m_indexB].c = cB; |
482 | data.positions[m_indexB].a = aB; |
483 | |
484 | return linearError <= b2_linearSlop && angularError <= b2_angularSlop; |
485 | } |
486 | |
487 | b2Vec2 b2PrismaticJoint::GetAnchorA() const |
488 | { |
489 | return m_bodyA->GetWorldPoint(m_localAnchorA); |
490 | } |
491 | |
492 | b2Vec2 b2PrismaticJoint::GetAnchorB() const |
493 | { |
494 | return m_bodyB->GetWorldPoint(m_localAnchorB); |
495 | } |
496 | |
497 | b2Vec2 b2PrismaticJoint::GetReactionForce(float32 inv_dt) const |
498 | { |
499 | return inv_dt * (m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis); |
500 | } |
501 | |
502 | float32 b2PrismaticJoint::GetReactionTorque(float32 inv_dt) const |
503 | { |
504 | return inv_dt * m_impulse.y; |
505 | } |
506 | |
507 | float32 b2PrismaticJoint::GetJointTranslation() const |
508 | { |
509 | b2Vec2 pA = m_bodyA->GetWorldPoint(m_localAnchorA); |
510 | b2Vec2 pB = m_bodyB->GetWorldPoint(m_localAnchorB); |
511 | b2Vec2 d = pB - pA; |
512 | b2Vec2 axis = m_bodyA->GetWorldVector(m_localXAxisA); |
513 | |
514 | float32 translation = b2Dot(d, axis); |
515 | return translation; |
516 | } |
517 | |
518 | float32 b2PrismaticJoint::GetJointSpeed() const |
519 | { |
520 | b2Body* bA = m_bodyA; |
521 | b2Body* bB = m_bodyB; |
522 | |
523 | b2Vec2 rA = b2Mul(bA->m_xf.q, m_localAnchorA - bA->m_sweep.localCenter); |
524 | b2Vec2 rB = b2Mul(bB->m_xf.q, m_localAnchorB - bB->m_sweep.localCenter); |
525 | b2Vec2 p1 = bA->m_sweep.c + rA; |
526 | b2Vec2 p2 = bB->m_sweep.c + rB; |
527 | b2Vec2 d = p2 - p1; |
528 | b2Vec2 axis = b2Mul(bA->m_xf.q, m_localXAxisA); |
529 | |
530 | b2Vec2 vA = bA->m_linearVelocity; |
531 | b2Vec2 vB = bB->m_linearVelocity; |
532 | float32 wA = bA->m_angularVelocity; |
533 | float32 wB = bB->m_angularVelocity; |
534 | |
535 | float32 speed = b2Dot(d, b2Cross(wA, axis)) + b2Dot(axis, vB + b2Cross(wB, rB) - vA - b2Cross(wA, rA)); |
536 | return speed; |
537 | } |
538 | |
539 | bool b2PrismaticJoint::IsLimitEnabled() const |
540 | { |
541 | return m_enableLimit; |
542 | } |
543 | |
544 | void b2PrismaticJoint::EnableLimit(bool flag) |
545 | { |
546 | if (flag != m_enableLimit) |
547 | { |
548 | m_bodyA->SetAwake(true); |
549 | m_bodyB->SetAwake(true); |
550 | m_enableLimit = flag; |
551 | m_impulse.z = 0.0f; |
552 | } |
553 | } |
554 | |
555 | float32 b2PrismaticJoint::GetLowerLimit() const |
556 | { |
557 | return m_lowerTranslation; |
558 | } |
559 | |
560 | float32 b2PrismaticJoint::GetUpperLimit() const |
561 | { |
562 | return m_upperTranslation; |
563 | } |
564 | |
565 | void b2PrismaticJoint::SetLimits(float32 lower, float32 upper) |
566 | { |
567 | b2Assert(lower <= upper); |
568 | if (lower != m_lowerTranslation || upper != m_upperTranslation) |
569 | { |
570 | m_bodyA->SetAwake(true); |
571 | m_bodyB->SetAwake(true); |
572 | m_lowerTranslation = lower; |
573 | m_upperTranslation = upper; |
574 | m_impulse.z = 0.0f; |
575 | } |
576 | } |
577 | |
578 | bool b2PrismaticJoint::IsMotorEnabled() const |
579 | { |
580 | return m_enableMotor; |
581 | } |
582 | |
583 | void b2PrismaticJoint::EnableMotor(bool flag) |
584 | { |
585 | m_bodyA->SetAwake(true); |
586 | m_bodyB->SetAwake(true); |
587 | m_enableMotor = flag; |
588 | } |
589 | |
590 | void b2PrismaticJoint::SetMotorSpeed(float32 speed) |
591 | { |
592 | m_bodyA->SetAwake(true); |
593 | m_bodyB->SetAwake(true); |
594 | m_motorSpeed = speed; |
595 | } |
596 | |
597 | void b2PrismaticJoint::SetMaxMotorForce(float32 force) |
598 | { |
599 | m_bodyA->SetAwake(true); |
600 | m_bodyB->SetAwake(true); |
601 | m_maxMotorForce = force; |
602 | } |
603 | |
604 | float32 b2PrismaticJoint::GetMotorForce(float32 inv_dt) const |
605 | { |
606 | return inv_dt * m_motorImpulse; |
607 | } |
608 | |
609 | void b2PrismaticJoint::Dump() |
610 | { |
611 | int32 indexA = m_bodyA->m_islandIndex; |
612 | int32 indexB = m_bodyB->m_islandIndex; |
613 | |
614 | b2Log(" b2PrismaticJointDef jd;\n" ); |
615 | b2Log(" jd.bodyA = bodies[%d];\n" , indexA); |
616 | b2Log(" jd.bodyB = bodies[%d];\n" , indexB); |
617 | b2Log(" jd.collideConnected = bool(%d);\n" , m_collideConnected); |
618 | b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n" , m_localAnchorA.x, m_localAnchorA.y); |
619 | b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n" , m_localAnchorB.x, m_localAnchorB.y); |
620 | b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n" , m_localXAxisA.x, m_localXAxisA.y); |
621 | b2Log(" jd.referenceAngle = %.15lef;\n" , m_referenceAngle); |
622 | b2Log(" jd.enableLimit = bool(%d);\n" , m_enableLimit); |
623 | b2Log(" jd.lowerTranslation = %.15lef;\n" , m_lowerTranslation); |
624 | b2Log(" jd.upperTranslation = %.15lef;\n" , m_upperTranslation); |
625 | b2Log(" jd.enableMotor = bool(%d);\n" , m_enableMotor); |
626 | b2Log(" jd.motorSpeed = %.15lef;\n" , m_motorSpeed); |
627 | b2Log(" jd.maxMotorForce = %.15lef;\n" , m_maxMotorForce); |
628 | b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n" , m_index); |
629 | } |
630 | |