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 
Initialize(b2Body * bA,b2Body * bB,const b2Vec2 & anchor,const b2Vec2 & axis)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 
b2PrismaticJoint(const b2PrismaticJointDef * def)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 
InitVelocityConstraints(const b2SolverData & data)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 
SolveVelocityConstraints(const b2SolverData & data)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 
SolvePositionConstraints(const b2SolverData & data)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 
GetAnchorA() const487 b2Vec2 b2PrismaticJoint::GetAnchorA() const
488 {
489 	return m_bodyA->GetWorldPoint(m_localAnchorA);
490 }
491 
GetAnchorB() const492 b2Vec2 b2PrismaticJoint::GetAnchorB() const
493 {
494 	return m_bodyB->GetWorldPoint(m_localAnchorB);
495 }
496 
GetReactionForce(float32 inv_dt) const497 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 
GetReactionTorque(float32 inv_dt) const502 float32 b2PrismaticJoint::GetReactionTorque(float32 inv_dt) const
503 {
504 	return inv_dt * m_impulse.y;
505 }
506 
GetJointTranslation() const507 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 
GetJointSpeed() const518 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 
IsLimitEnabled() const539 bool b2PrismaticJoint::IsLimitEnabled() const
540 {
541 	return m_enableLimit;
542 }
543 
EnableLimit(bool flag)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 
GetLowerLimit() const555 float32 b2PrismaticJoint::GetLowerLimit() const
556 {
557 	return m_lowerTranslation;
558 }
559 
GetUpperLimit() const560 float32 b2PrismaticJoint::GetUpperLimit() const
561 {
562 	return m_upperTranslation;
563 }
564 
SetLimits(float32 lower,float32 upper)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 
IsMotorEnabled() const578 bool b2PrismaticJoint::IsMotorEnabled() const
579 {
580 	return m_enableMotor;
581 }
582 
EnableMotor(bool flag)583 void b2PrismaticJoint::EnableMotor(bool flag)
584 {
585 	m_bodyA->SetAwake(true);
586 	m_bodyB->SetAwake(true);
587 	m_enableMotor = flag;
588 }
589 
SetMotorSpeed(float32 speed)590 void b2PrismaticJoint::SetMotorSpeed(float32 speed)
591 {
592 	m_bodyA->SetAwake(true);
593 	m_bodyB->SetAwake(true);
594 	m_motorSpeed = speed;
595 }
596 
SetMaxMotorForce(float32 force)597 void b2PrismaticJoint::SetMaxMotorForce(float32 force)
598 {
599 	m_bodyA->SetAwake(true);
600 	m_bodyB->SetAwake(true);
601 	m_maxMotorForce = force;
602 }
603 
GetMotorForce(float32 inv_dt) const604 float32 b2PrismaticJoint::GetMotorForce(float32 inv_dt) const
605 {
606 	return inv_dt * m_motorImpulse;
607 }
608 
Dump()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