File indexing completed on 2025-08-03 03:49:59
0001 /* 0002 * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 0003 * 0004 * This software is provided 'as-is', without any express or implied 0005 * warranty. In no event will the authors be held liable for any damages 0006 * arising from the use of this software. 0007 * Permission is granted to anyone to use this software for any purpose, 0008 * including commercial applications, and to alter it and redistribute it 0009 * freely, subject to the following restrictions: 0010 * 1. The origin of this software must not be misrepresented; you must not 0011 * claim that you wrote the original software. If you use this software 0012 * in a product, an acknowledgment in the product documentation would be 0013 * appreciated but is not required. 0014 * 2. Altered source versions must be plainly marked as such, and must not be 0015 * misrepresented as being the original software. 0016 * 3. This notice may not be removed or altered from any source distribution. 0017 */ 0018 0019 #include <Box2D/Dynamics/Joints/b2PrismaticJoint.h> 0020 #include <Box2D/Dynamics/b2Body.h> 0021 #include <Box2D/Dynamics/b2TimeStep.h> 0022 0023 // Linear constraint (point-to-line) 0024 // d = p2 - p1 = x2 + r2 - x1 - r1 0025 // C = dot(perp, d) 0026 // Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1)) 0027 // = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2) 0028 // J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)] 0029 // 0030 // Angular constraint 0031 // C = a2 - a1 + a_initial 0032 // Cdot = w2 - w1 0033 // J = [0 0 -1 0 0 1] 0034 // 0035 // K = J * invM * JT 0036 // 0037 // J = [-a -s1 a s2] 0038 // [0 -1 0 1] 0039 // a = perp 0040 // s1 = cross(d + r1, a) = cross(p2 - x1, a) 0041 // s2 = cross(r2, a) = cross(p2 - x2, a) 0042 0043 0044 // Motor/Limit linear constraint 0045 // C = dot(ax1, d) 0046 // Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2) 0047 // J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)] 0048 0049 // Block Solver 0050 // We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even 0051 // when the mass has poor distribution (leading to large torques about the joint anchor points). 0052 // 0053 // The Jacobian has 3 rows: 0054 // J = [-uT -s1 uT s2] // linear 0055 // [0 -1 0 1] // angular 0056 // [-vT -a1 vT a2] // limit 0057 // 0058 // u = perp 0059 // v = axis 0060 // s1 = cross(d + r1, u), s2 = cross(r2, u) 0061 // a1 = cross(d + r1, v), a2 = cross(r2, v) 0062 0063 // M * (v2 - v1) = JT * df 0064 // J * v2 = bias 0065 // 0066 // v2 = v1 + invM * JT * df 0067 // J * (v1 + invM * JT * df) = bias 0068 // K * df = bias - J * v1 = -Cdot 0069 // K = J * invM * JT 0070 // Cdot = J * v1 - bias 0071 // 0072 // Now solve for f2. 0073 // df = f2 - f1 0074 // K * (f2 - f1) = -Cdot 0075 // f2 = invK * (-Cdot) + f1 0076 // 0077 // Clamp accumulated limit impulse. 0078 // lower: f2(3) = max(f2(3), 0) 0079 // upper: f2(3) = min(f2(3), 0) 0080 // 0081 // Solve for correct f2(1:2) 0082 // K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:3) * f1 0083 // = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:2) * f1(1:2) + K(1:2,3) * f1(3) 0084 // 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) 0085 // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2) 0086 // 0087 // Now compute impulse to be applied: 0088 // df = f2 - f1 0089 0090 void b2PrismaticJointDef::Initialize(b2Body* b1, b2Body* b2, const b2Vec2& anchor, const b2Vec2& axis) 0091 { 0092 bodyA = b1; 0093 bodyB = b2; 0094 localAnchorA = bodyA->GetLocalPoint(anchor); 0095 localAnchorB = bodyB->GetLocalPoint(anchor); 0096 localAxis1 = bodyA->GetLocalVector(axis); 0097 referenceAngle = bodyB->GetAngle() - bodyA->GetAngle(); 0098 } 0099 0100 b2PrismaticJoint::b2PrismaticJoint(const b2PrismaticJointDef* def) 0101 : b2Joint(def) 0102 { 0103 m_localAnchor1 = def->localAnchorA; 0104 m_localAnchor2 = def->localAnchorB; 0105 m_localXAxis1 = def->localAxis1; 0106 m_localYAxis1 = b2Cross(1.0f, m_localXAxis1); 0107 m_refAngle = def->referenceAngle; 0108 0109 m_impulse.SetZero(); 0110 m_motorMass = 0.0; 0111 m_motorImpulse = 0.0f; 0112 0113 m_lowerTranslation = def->lowerTranslation; 0114 m_upperTranslation = def->upperTranslation; 0115 m_maxMotorForce = def->maxMotorForce; 0116 m_motorSpeed = def->motorSpeed; 0117 m_enableLimit = def->enableLimit; 0118 m_enableMotor = def->enableMotor; 0119 m_limitState = e_inactiveLimit; 0120 0121 m_axis.SetZero(); 0122 m_perp.SetZero(); 0123 } 0124 0125 void b2PrismaticJoint::InitVelocityConstraints(const b2TimeStep& step) 0126 { 0127 b2Body* b1 = m_bodyA; 0128 b2Body* b2 = m_bodyB; 0129 0130 m_localCenterA = b1->GetLocalCenter(); 0131 m_localCenterB = b2->GetLocalCenter(); 0132 0133 b2Transform xf1 = b1->GetTransform(); 0134 b2Transform xf2 = b2->GetTransform(); 0135 0136 // Compute the effective masses. 0137 b2Vec2 r1 = b2Mul(xf1.R, m_localAnchor1 - m_localCenterA); 0138 b2Vec2 r2 = b2Mul(xf2.R, m_localAnchor2 - m_localCenterB); 0139 b2Vec2 d = b2->m_sweep.c + r2 - b1->m_sweep.c - r1; 0140 0141 m_invMassA = b1->m_invMass; 0142 m_invIA = b1->m_invI; 0143 m_invMassB = b2->m_invMass; 0144 m_invIB = b2->m_invI; 0145 0146 // Compute motor Jacobian and effective mass. 0147 { 0148 m_axis = b2Mul(xf1.R, m_localXAxis1); 0149 m_a1 = b2Cross(d + r1, m_axis); 0150 m_a2 = b2Cross(r2, m_axis); 0151 0152 m_motorMass = m_invMassA + m_invMassB + m_invIA * m_a1 * m_a1 + m_invIB * m_a2 * m_a2; 0153 if (m_motorMass > b2_epsilon) 0154 { 0155 m_motorMass = 1.0f / m_motorMass; 0156 } 0157 } 0158 0159 // Prismatic constraint. 0160 { 0161 m_perp = b2Mul(xf1.R, m_localYAxis1); 0162 0163 m_s1 = b2Cross(d + r1, m_perp); 0164 m_s2 = b2Cross(r2, m_perp); 0165 0166 qreal m1 = m_invMassA, m2 = m_invMassB; 0167 qreal i1 = m_invIA, i2 = m_invIB; 0168 0169 qreal k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2; 0170 qreal k12 = i1 * m_s1 + i2 * m_s2; 0171 qreal k13 = i1 * m_s1 * m_a1 + i2 * m_s2 * m_a2; 0172 qreal k22 = i1 + i2; 0173 if (k22 == 0.0f) 0174 { 0175 k22 = 1.0f; 0176 } 0177 qreal k23 = i1 * m_a1 + i2 * m_a2; 0178 qreal k33 = m1 + m2 + i1 * m_a1 * m_a1 + i2 * m_a2 * m_a2; 0179 0180 m_K.col1.Set(k11, k12, k13); 0181 m_K.col2.Set(k12, k22, k23); 0182 m_K.col3.Set(k13, k23, k33); 0183 } 0184 0185 // Compute motor and limit terms. 0186 if (m_enableLimit) 0187 { 0188 qreal jointTranslation = b2Dot(m_axis, d); 0189 if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop) 0190 { 0191 m_limitState = e_equalLimits; 0192 } 0193 else if (jointTranslation <= m_lowerTranslation) 0194 { 0195 if (m_limitState != e_atLowerLimit) 0196 { 0197 m_limitState = e_atLowerLimit; 0198 m_impulse.z = 0.0f; 0199 } 0200 } 0201 else if (jointTranslation >= m_upperTranslation) 0202 { 0203 if (m_limitState != e_atUpperLimit) 0204 { 0205 m_limitState = e_atUpperLimit; 0206 m_impulse.z = 0.0f; 0207 } 0208 } 0209 else 0210 { 0211 m_limitState = e_inactiveLimit; 0212 m_impulse.z = 0.0f; 0213 } 0214 } 0215 else 0216 { 0217 m_limitState = e_inactiveLimit; 0218 m_impulse.z = 0.0f; 0219 } 0220 0221 if (m_enableMotor == false) 0222 { 0223 m_motorImpulse = 0.0f; 0224 } 0225 0226 if (step.warmStarting) 0227 { 0228 // Account for variable time step. 0229 m_impulse *= step.dtRatio; 0230 m_motorImpulse *= step.dtRatio; 0231 0232 b2Vec2 P = m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis; 0233 qreal L1 = m_impulse.x * m_s1 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a1; 0234 qreal L2 = m_impulse.x * m_s2 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a2; 0235 0236 b1->m_linearVelocity -= m_invMassA * P; 0237 b1->m_angularVelocity -= m_invIA * L1; 0238 0239 b2->m_linearVelocity += m_invMassB * P; 0240 b2->m_angularVelocity += m_invIB * L2; 0241 } 0242 else 0243 { 0244 m_impulse.SetZero(); 0245 m_motorImpulse = 0.0f; 0246 } 0247 } 0248 0249 void b2PrismaticJoint::SolveVelocityConstraints(const b2TimeStep& step) 0250 { 0251 b2Body* b1 = m_bodyA; 0252 b2Body* b2 = m_bodyB; 0253 0254 b2Vec2 v1 = b1->m_linearVelocity; 0255 qreal w1 = b1->m_angularVelocity; 0256 b2Vec2 v2 = b2->m_linearVelocity; 0257 qreal w2 = b2->m_angularVelocity; 0258 0259 // Solve linear motor constraint. 0260 if (m_enableMotor && m_limitState != e_equalLimits) 0261 { 0262 qreal Cdot = b2Dot(m_axis, v2 - v1) + m_a2 * w2 - m_a1 * w1; 0263 qreal impulse = m_motorMass * (m_motorSpeed - Cdot); 0264 qreal oldImpulse = m_motorImpulse; 0265 qreal maxImpulse = step.dt * m_maxMotorForce; 0266 m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse); 0267 impulse = m_motorImpulse - oldImpulse; 0268 0269 b2Vec2 P = impulse * m_axis; 0270 qreal L1 = impulse * m_a1; 0271 qreal L2 = impulse * m_a2; 0272 0273 v1 -= m_invMassA * P; 0274 w1 -= m_invIA * L1; 0275 0276 v2 += m_invMassB * P; 0277 w2 += m_invIB * L2; 0278 } 0279 0280 b2Vec2 Cdot1; 0281 Cdot1.x = b2Dot(m_perp, v2 - v1) + m_s2 * w2 - m_s1 * w1; 0282 Cdot1.y = w2 - w1; 0283 0284 if (m_enableLimit && m_limitState != e_inactiveLimit) 0285 { 0286 // Solve prismatic and limit constraint in block form. 0287 qreal Cdot2; 0288 Cdot2 = b2Dot(m_axis, v2 - v1) + m_a2 * w2 - m_a1 * w1; 0289 b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); 0290 0291 b2Vec3 f1 = m_impulse; 0292 b2Vec3 df = m_K.Solve33(-Cdot); 0293 m_impulse += df; 0294 0295 if (m_limitState == e_atLowerLimit) 0296 { 0297 m_impulse.z = b2Max(m_impulse.z, 0.0f); 0298 } 0299 else if (m_limitState == e_atUpperLimit) 0300 { 0301 m_impulse.z = b2Min(m_impulse.z, 0.0f); 0302 } 0303 0304 // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2) 0305 b2Vec2 b = -Cdot1 - (m_impulse.z - f1.z) * b2Vec2(m_K.col3.x, m_K.col3.y); 0306 b2Vec2 f2r = m_K.Solve22(b) + b2Vec2(f1.x, f1.y); 0307 m_impulse.x = f2r.x; 0308 m_impulse.y = f2r.y; 0309 0310 df = m_impulse - f1; 0311 0312 b2Vec2 P = df.x * m_perp + df.z * m_axis; 0313 qreal L1 = df.x * m_s1 + df.y + df.z * m_a1; 0314 qreal L2 = df.x * m_s2 + df.y + df.z * m_a2; 0315 0316 v1 -= m_invMassA * P; 0317 w1 -= m_invIA * L1; 0318 0319 v2 += m_invMassB * P; 0320 w2 += m_invIB * L2; 0321 } 0322 else 0323 { 0324 // Limit is inactive, just solve the prismatic constraint in block form. 0325 b2Vec2 df = m_K.Solve22(-Cdot1); 0326 m_impulse.x += df.x; 0327 m_impulse.y += df.y; 0328 0329 b2Vec2 P = df.x * m_perp; 0330 qreal L1 = df.x * m_s1 + df.y; 0331 qreal L2 = df.x * m_s2 + df.y; 0332 0333 v1 -= m_invMassA * P; 0334 w1 -= m_invIA * L1; 0335 0336 v2 += m_invMassB * P; 0337 w2 += m_invIB * L2; 0338 } 0339 0340 b1->m_linearVelocity = v1; 0341 b1->m_angularVelocity = w1; 0342 b2->m_linearVelocity = v2; 0343 b2->m_angularVelocity = w2; 0344 } 0345 0346 bool b2PrismaticJoint::SolvePositionConstraints(qreal baumgarte) 0347 { 0348 B2_NOT_USED(baumgarte); 0349 0350 b2Body* b1 = m_bodyA; 0351 b2Body* b2 = m_bodyB; 0352 0353 b2Vec2 c1 = b1->m_sweep.c; 0354 qreal a1 = b1->m_sweep.a; 0355 0356 b2Vec2 c2 = b2->m_sweep.c; 0357 qreal a2 = b2->m_sweep.a; 0358 0359 // Solve linear limit constraint. 0360 qreal linearError = 0.0f, angularError = 0.0f; 0361 bool active = false; 0362 qreal C2 = 0.0f; 0363 0364 b2Mat22 R1(a1), R2(a2); 0365 0366 b2Vec2 r1 = b2Mul(R1, m_localAnchor1 - m_localCenterA); 0367 b2Vec2 r2 = b2Mul(R2, m_localAnchor2 - m_localCenterB); 0368 b2Vec2 d = c2 + r2 - c1 - r1; 0369 0370 if (m_enableLimit) 0371 { 0372 m_axis = b2Mul(R1, m_localXAxis1); 0373 0374 m_a1 = b2Cross(d + r1, m_axis); 0375 m_a2 = b2Cross(r2, m_axis); 0376 0377 qreal translation = b2Dot(m_axis, d); 0378 if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop) 0379 { 0380 // Prevent large angular corrections 0381 C2 = b2Clamp(translation, -b2_maxLinearCorrection, b2_maxLinearCorrection); 0382 linearError = b2Abs(translation); 0383 active = true; 0384 } 0385 else if (translation <= m_lowerTranslation) 0386 { 0387 // Prevent large linear corrections and allow some slop. 0388 C2 = b2Clamp(translation - m_lowerTranslation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f); 0389 linearError = m_lowerTranslation - translation; 0390 active = true; 0391 } 0392 else if (translation >= m_upperTranslation) 0393 { 0394 // Prevent large linear corrections and allow some slop. 0395 C2 = b2Clamp(translation - m_upperTranslation - b2_linearSlop, 0.0f, b2_maxLinearCorrection); 0396 linearError = translation - m_upperTranslation; 0397 active = true; 0398 } 0399 } 0400 0401 m_perp = b2Mul(R1, m_localYAxis1); 0402 0403 m_s1 = b2Cross(d + r1, m_perp); 0404 m_s2 = b2Cross(r2, m_perp); 0405 0406 b2Vec3 impulse; 0407 b2Vec2 C1; 0408 C1.x = b2Dot(m_perp, d); 0409 C1.y = a2 - a1 - m_refAngle; 0410 0411 linearError = b2Max(linearError, b2Abs(C1.x)); 0412 angularError = b2Abs(C1.y); 0413 0414 if (active) 0415 { 0416 qreal m1 = m_invMassA, m2 = m_invMassB; 0417 qreal i1 = m_invIA, i2 = m_invIB; 0418 0419 qreal k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2; 0420 qreal k12 = i1 * m_s1 + i2 * m_s2; 0421 qreal k13 = i1 * m_s1 * m_a1 + i2 * m_s2 * m_a2; 0422 qreal k22 = i1 + i2; 0423 if (k22 == 0.0f) 0424 { 0425 k22 = 1.0f; 0426 } 0427 qreal k23 = i1 * m_a1 + i2 * m_a2; 0428 qreal k33 = m1 + m2 + i1 * m_a1 * m_a1 + i2 * m_a2 * m_a2; 0429 0430 m_K.col1.Set(k11, k12, k13); 0431 m_K.col2.Set(k12, k22, k23); 0432 m_K.col3.Set(k13, k23, k33); 0433 0434 b2Vec3 C; 0435 C.x = C1.x; 0436 C.y = C1.y; 0437 C.z = C2; 0438 0439 impulse = m_K.Solve33(-C); 0440 } 0441 else 0442 { 0443 qreal m1 = m_invMassA, m2 = m_invMassB; 0444 qreal i1 = m_invIA, i2 = m_invIB; 0445 0446 qreal k11 = m1 + m2 + i1 * m_s1 * m_s1 + i2 * m_s2 * m_s2; 0447 qreal k12 = i1 * m_s1 + i2 * m_s2; 0448 qreal k22 = i1 + i2; 0449 if (k22 == 0.0f) 0450 { 0451 k22 = 1.0f; 0452 } 0453 0454 m_K.col1.Set(k11, k12, 0.0f); 0455 m_K.col2.Set(k12, k22, 0.0f); 0456 0457 b2Vec2 impulse1 = m_K.Solve22(-C1); 0458 impulse.x = impulse1.x; 0459 impulse.y = impulse1.y; 0460 impulse.z = 0.0f; 0461 } 0462 0463 b2Vec2 P = impulse.x * m_perp + impulse.z * m_axis; 0464 qreal L1 = impulse.x * m_s1 + impulse.y + impulse.z * m_a1; 0465 qreal L2 = impulse.x * m_s2 + impulse.y + impulse.z * m_a2; 0466 0467 c1 -= m_invMassA * P; 0468 a1 -= m_invIA * L1; 0469 c2 += m_invMassB * P; 0470 a2 += m_invIB * L2; 0471 0472 // TODO_ERIN remove need for this. 0473 b1->m_sweep.c = c1; 0474 b1->m_sweep.a = a1; 0475 b2->m_sweep.c = c2; 0476 b2->m_sweep.a = a2; 0477 b1->SynchronizeTransform(); 0478 b2->SynchronizeTransform(); 0479 0480 return linearError <= b2_linearSlop && angularError <= b2_angularSlop; 0481 } 0482 0483 b2Vec2 b2PrismaticJoint::GetAnchorA() const 0484 { 0485 return m_bodyA->GetWorldPoint(m_localAnchor1); 0486 } 0487 0488 b2Vec2 b2PrismaticJoint::GetAnchorB() const 0489 { 0490 return m_bodyB->GetWorldPoint(m_localAnchor2); 0491 } 0492 0493 b2Vec2 b2PrismaticJoint::GetReactionForce(qreal inv_dt) const 0494 { 0495 return inv_dt * (m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis); 0496 } 0497 0498 qreal b2PrismaticJoint::GetReactionTorque(qreal inv_dt) const 0499 { 0500 return inv_dt * m_impulse.y; 0501 } 0502 0503 qreal b2PrismaticJoint::GetJointTranslation() const 0504 { 0505 b2Body* b1 = m_bodyA; 0506 b2Body* b2 = m_bodyB; 0507 0508 b2Vec2 p1 = b1->GetWorldPoint(m_localAnchor1); 0509 b2Vec2 p2 = b2->GetWorldPoint(m_localAnchor2); 0510 b2Vec2 d = p2 - p1; 0511 b2Vec2 axis = b1->GetWorldVector(m_localXAxis1); 0512 0513 qreal translation = b2Dot(d, axis); 0514 return translation; 0515 } 0516 0517 qreal b2PrismaticJoint::GetJointSpeed() const 0518 { 0519 b2Body* b1 = m_bodyA; 0520 b2Body* b2 = m_bodyB; 0521 0522 b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter()); 0523 b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter()); 0524 b2Vec2 p1 = b1->m_sweep.c + r1; 0525 b2Vec2 p2 = b2->m_sweep.c + r2; 0526 b2Vec2 d = p2 - p1; 0527 b2Vec2 axis = b1->GetWorldVector(m_localXAxis1); 0528 0529 b2Vec2 v1 = b1->m_linearVelocity; 0530 b2Vec2 v2 = b2->m_linearVelocity; 0531 qreal w1 = b1->m_angularVelocity; 0532 qreal w2 = b2->m_angularVelocity; 0533 0534 qreal speed = b2Dot(d, b2Cross(w1, axis)) + b2Dot(axis, v2 + b2Cross(w2, r2) - v1 - b2Cross(w1, r1)); 0535 return speed; 0536 } 0537 0538 bool b2PrismaticJoint::IsLimitEnabled() const 0539 { 0540 return m_enableLimit; 0541 } 0542 0543 void b2PrismaticJoint::EnableLimit(bool flag) 0544 { 0545 m_bodyA->SetAwake(true); 0546 m_bodyB->SetAwake(true); 0547 m_enableLimit = flag; 0548 } 0549 0550 qreal b2PrismaticJoint::GetLowerLimit() const 0551 { 0552 return m_lowerTranslation; 0553 } 0554 0555 qreal b2PrismaticJoint::GetUpperLimit() const 0556 { 0557 return m_upperTranslation; 0558 } 0559 0560 void b2PrismaticJoint::SetLimits(qreal lower, qreal upper) 0561 { 0562 b2Assert(lower <= upper); 0563 m_bodyA->SetAwake(true); 0564 m_bodyB->SetAwake(true); 0565 m_lowerTranslation = lower; 0566 m_upperTranslation = upper; 0567 } 0568 0569 bool b2PrismaticJoint::IsMotorEnabled() const 0570 { 0571 return m_enableMotor; 0572 } 0573 0574 void b2PrismaticJoint::EnableMotor(bool flag) 0575 { 0576 m_bodyA->SetAwake(true); 0577 m_bodyB->SetAwake(true); 0578 m_enableMotor = flag; 0579 } 0580 0581 void b2PrismaticJoint::SetMotorSpeed(qreal speed) 0582 { 0583 m_bodyA->SetAwake(true); 0584 m_bodyB->SetAwake(true); 0585 m_motorSpeed = speed; 0586 } 0587 0588 void b2PrismaticJoint::SetMaxMotorForce(qreal force) 0589 { 0590 m_bodyA->SetAwake(true); 0591 m_bodyB->SetAwake(true); 0592 m_maxMotorForce = force; 0593 } 0594 0595 qreal b2PrismaticJoint::GetMotorForce(qreal inv_dt) const 0596 { 0597 return inv_dt * m_motorImpulse; 0598 }