00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <Box2D/Dynamics/Joints/b2RevoluteJoint.h>
00020 #include <Box2D/Dynamics/b2Body.h>
00021 #include <Box2D/Dynamics/b2TimeStep.h>
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 void b2RevoluteJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor)
00037 {
00038 bodyA = bA;
00039 bodyB = bB;
00040 localAnchorA = bodyA->GetLocalPoint(anchor);
00041 localAnchorB = bodyB->GetLocalPoint(anchor);
00042 referenceAngle = bodyB->GetAngle() - bodyA->GetAngle();
00043 }
00044
00045 b2RevoluteJoint::b2RevoluteJoint(const b2RevoluteJointDef* def)
00046 : b2Joint(def)
00047 {
00048 m_localAnchorA = def->localAnchorA;
00049 m_localAnchorB = def->localAnchorB;
00050 m_referenceAngle = def->referenceAngle;
00051
00052 m_impulse.SetZero();
00053 m_motorImpulse = 0.0f;
00054
00055 m_lowerAngle = def->lowerAngle;
00056 m_upperAngle = def->upperAngle;
00057 m_maxMotorTorque = def->maxMotorTorque;
00058 m_motorSpeed = def->motorSpeed;
00059 m_enableLimit = def->enableLimit;
00060 m_enableMotor = def->enableMotor;
00061 m_limitState = e_inactiveLimit;
00062 }
00063
00064 void b2RevoluteJoint::InitVelocityConstraints(const b2SolverData& data)
00065 {
00066 m_indexA = m_bodyA->m_islandIndex;
00067 m_indexB = m_bodyB->m_islandIndex;
00068 m_localCenterA = m_bodyA->m_sweep.localCenter;
00069 m_localCenterB = m_bodyB->m_sweep.localCenter;
00070 m_invMassA = m_bodyA->m_invMass;
00071 m_invMassB = m_bodyB->m_invMass;
00072 m_invIA = m_bodyA->m_invI;
00073 m_invIB = m_bodyB->m_invI;
00074
00075 float32 aA = data.positions[m_indexA].a;
00076 b2Vec2 vA = data.velocities[m_indexA].v;
00077 float32 wA = data.velocities[m_indexA].w;
00078
00079 float32 aB = data.positions[m_indexB].a;
00080 b2Vec2 vB = data.velocities[m_indexB].v;
00081 float32 wB = data.velocities[m_indexB].w;
00082
00083 b2Rot qA(aA), qB(aB);
00084
00085 m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
00086 m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097 float32 mA = m_invMassA, mB = m_invMassB;
00098 float32 iA = m_invIA, iB = m_invIB;
00099
00100 bool fixedRotation = (iA + iB == 0.0f);
00101
00102 m_mass.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB;
00103 m_mass.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB;
00104 m_mass.ez.x = -m_rA.y * iA - m_rB.y * iB;
00105 m_mass.ex.y = m_mass.ey.x;
00106 m_mass.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB;
00107 m_mass.ez.y = m_rA.x * iA + m_rB.x * iB;
00108 m_mass.ex.z = m_mass.ez.x;
00109 m_mass.ey.z = m_mass.ez.y;
00110 m_mass.ez.z = iA + iB;
00111
00112 m_motorMass = iA + iB;
00113 if (m_motorMass > 0.0f)
00114 {
00115 m_motorMass = 1.0f / m_motorMass;
00116 }
00117
00118 if (m_enableMotor == false || fixedRotation)
00119 {
00120 m_motorImpulse = 0.0f;
00121 }
00122
00123 if (m_enableLimit && fixedRotation == false)
00124 {
00125 float32 jointAngle = aB - aA - m_referenceAngle;
00126 if (b2Abs(m_upperAngle - m_lowerAngle) < 2.0f * b2_angularSlop)
00127 {
00128 m_limitState = e_equalLimits;
00129 }
00130 else if (jointAngle <= m_lowerAngle)
00131 {
00132 if (m_limitState != e_atLowerLimit)
00133 {
00134 m_impulse.z = 0.0f;
00135 }
00136 m_limitState = e_atLowerLimit;
00137 }
00138 else if (jointAngle >= m_upperAngle)
00139 {
00140 if (m_limitState != e_atUpperLimit)
00141 {
00142 m_impulse.z = 0.0f;
00143 }
00144 m_limitState = e_atUpperLimit;
00145 }
00146 else
00147 {
00148 m_limitState = e_inactiveLimit;
00149 m_impulse.z = 0.0f;
00150 }
00151 }
00152 else
00153 {
00154 m_limitState = e_inactiveLimit;
00155 }
00156
00157 if (data.step.warmStarting)
00158 {
00159
00160 m_impulse *= data.step.dtRatio;
00161 m_motorImpulse *= data.step.dtRatio;
00162
00163 b2Vec2 P(m_impulse.x, m_impulse.y);
00164
00165 vA -= mA * P;
00166 wA -= iA * (b2Cross(m_rA, P) + m_motorImpulse + m_impulse.z);
00167
00168 vB += mB * P;
00169 wB += iB * (b2Cross(m_rB, P) + m_motorImpulse + m_impulse.z);
00170 }
00171 else
00172 {
00173 m_impulse.SetZero();
00174 m_motorImpulse = 0.0f;
00175 }
00176
00177 data.velocities[m_indexA].v = vA;
00178 data.velocities[m_indexA].w = wA;
00179 data.velocities[m_indexB].v = vB;
00180 data.velocities[m_indexB].w = wB;
00181 }
00182
00183 void b2RevoluteJoint::SolveVelocityConstraints(const b2SolverData& data)
00184 {
00185 b2Vec2 vA = data.velocities[m_indexA].v;
00186 float32 wA = data.velocities[m_indexA].w;
00187 b2Vec2 vB = data.velocities[m_indexB].v;
00188 float32 wB = data.velocities[m_indexB].w;
00189
00190 float32 mA = m_invMassA, mB = m_invMassB;
00191 float32 iA = m_invIA, iB = m_invIB;
00192
00193 bool fixedRotation = (iA + iB == 0.0f);
00194
00195
00196 if (m_enableMotor && m_limitState != e_equalLimits && fixedRotation == false)
00197 {
00198 float32 Cdot = wB - wA - m_motorSpeed;
00199 float32 impulse = -m_motorMass * Cdot;
00200 float32 oldImpulse = m_motorImpulse;
00201 float32 maxImpulse = data.step.dt * m_maxMotorTorque;
00202 m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse);
00203 impulse = m_motorImpulse - oldImpulse;
00204
00205 wA -= iA * impulse;
00206 wB += iB * impulse;
00207 }
00208
00209
00210 if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false)
00211 {
00212 b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
00213 float32 Cdot2 = wB - wA;
00214 b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);
00215
00216 b2Vec3 impulse = -m_mass.Solve33(Cdot);
00217
00218 if (m_limitState == e_equalLimits)
00219 {
00220 m_impulse += impulse;
00221 }
00222 else if (m_limitState == e_atLowerLimit)
00223 {
00224 float32 newImpulse = m_impulse.z + impulse.z;
00225 if (newImpulse < 0.0f)
00226 {
00227 b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y);
00228 b2Vec2 reduced = m_mass.Solve22(rhs);
00229 impulse.x = reduced.x;
00230 impulse.y = reduced.y;
00231 impulse.z = -m_impulse.z;
00232 m_impulse.x += reduced.x;
00233 m_impulse.y += reduced.y;
00234 m_impulse.z = 0.0f;
00235 }
00236 else
00237 {
00238 m_impulse += impulse;
00239 }
00240 }
00241 else if (m_limitState == e_atUpperLimit)
00242 {
00243 float32 newImpulse = m_impulse.z + impulse.z;
00244 if (newImpulse > 0.0f)
00245 {
00246 b2Vec2 rhs = -Cdot1 + m_impulse.z * b2Vec2(m_mass.ez.x, m_mass.ez.y);
00247 b2Vec2 reduced = m_mass.Solve22(rhs);
00248 impulse.x = reduced.x;
00249 impulse.y = reduced.y;
00250 impulse.z = -m_impulse.z;
00251 m_impulse.x += reduced.x;
00252 m_impulse.y += reduced.y;
00253 m_impulse.z = 0.0f;
00254 }
00255 else
00256 {
00257 m_impulse += impulse;
00258 }
00259 }
00260
00261 b2Vec2 P(impulse.x, impulse.y);
00262
00263 vA -= mA * P;
00264 wA -= iA * (b2Cross(m_rA, P) + impulse.z);
00265
00266 vB += mB * P;
00267 wB += iB * (b2Cross(m_rB, P) + impulse.z);
00268 }
00269 else
00270 {
00271
00272 b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
00273 b2Vec2 impulse = m_mass.Solve22(-Cdot);
00274
00275 m_impulse.x += impulse.x;
00276 m_impulse.y += impulse.y;
00277
00278 vA -= mA * impulse;
00279 wA -= iA * b2Cross(m_rA, impulse);
00280
00281 vB += mB * impulse;
00282 wB += iB * b2Cross(m_rB, impulse);
00283 }
00284
00285 data.velocities[m_indexA].v = vA;
00286 data.velocities[m_indexA].w = wA;
00287 data.velocities[m_indexB].v = vB;
00288 data.velocities[m_indexB].w = wB;
00289 }
00290
00291 bool b2RevoluteJoint::SolvePositionConstraints(const b2SolverData& data)
00292 {
00293 b2Vec2 cA = data.positions[m_indexA].c;
00294 float32 aA = data.positions[m_indexA].a;
00295 b2Vec2 cB = data.positions[m_indexB].c;
00296 float32 aB = data.positions[m_indexB].a;
00297
00298 b2Rot qA(aA), qB(aB);
00299
00300 float32 angularError = 0.0f;
00301 float32 positionError = 0.0f;
00302
00303 bool fixedRotation = (m_invIA + m_invIB == 0.0f);
00304
00305
00306 if (m_enableLimit && m_limitState != e_inactiveLimit && fixedRotation == false)
00307 {
00308 float32 angle = aB - aA - m_referenceAngle;
00309 float32 limitImpulse = 0.0f;
00310
00311 if (m_limitState == e_equalLimits)
00312 {
00313
00314 float32 C = b2Clamp(angle - m_lowerAngle, -b2_maxAngularCorrection, b2_maxAngularCorrection);
00315 limitImpulse = -m_motorMass * C;
00316 angularError = b2Abs(C);
00317 }
00318 else if (m_limitState == e_atLowerLimit)
00319 {
00320 float32 C = angle - m_lowerAngle;
00321 angularError = -C;
00322
00323
00324 C = b2Clamp(C + b2_angularSlop, -b2_maxAngularCorrection, 0.0f);
00325 limitImpulse = -m_motorMass * C;
00326 }
00327 else if (m_limitState == e_atUpperLimit)
00328 {
00329 float32 C = angle - m_upperAngle;
00330 angularError = C;
00331
00332
00333 C = b2Clamp(C - b2_angularSlop, 0.0f, b2_maxAngularCorrection);
00334 limitImpulse = -m_motorMass * C;
00335 }
00336
00337 aA -= m_invIA * limitImpulse;
00338 aB += m_invIB * limitImpulse;
00339 }
00340
00341
00342 {
00343 qA.Set(aA);
00344 qB.Set(aB);
00345 b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
00346 b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
00347
00348 b2Vec2 C = cB + rB - cA - rA;
00349 positionError = C.Length();
00350
00351 float32 mA = m_invMassA, mB = m_invMassB;
00352 float32 iA = m_invIA, iB = m_invIB;
00353
00354 b2Mat22 K;
00355 K.ex.x = mA + mB + iA * rA.y * rA.y + iB * rB.y * rB.y;
00356 K.ex.y = -iA * rA.x * rA.y - iB * rB.x * rB.y;
00357 K.ey.x = K.ex.y;
00358 K.ey.y = mA + mB + iA * rA.x * rA.x + iB * rB.x * rB.x;
00359
00360 b2Vec2 impulse = -K.Solve(C);
00361
00362 cA -= mA * impulse;
00363 aA -= iA * b2Cross(rA, impulse);
00364
00365 cB += mB * impulse;
00366 aB += iB * b2Cross(rB, impulse);
00367 }
00368
00369 data.positions[m_indexA].c = cA;
00370 data.positions[m_indexA].a = aA;
00371 data.positions[m_indexB].c = cB;
00372 data.positions[m_indexB].a = aB;
00373
00374 return positionError <= b2_linearSlop && angularError <= b2_angularSlop;
00375 }
00376
00377 b2Vec2 b2RevoluteJoint::GetAnchorA() const
00378 {
00379 return m_bodyA->GetWorldPoint(m_localAnchorA);
00380 }
00381
00382 b2Vec2 b2RevoluteJoint::GetAnchorB() const
00383 {
00384 return m_bodyB->GetWorldPoint(m_localAnchorB);
00385 }
00386
00387 b2Vec2 b2RevoluteJoint::GetReactionForce(float32 inv_dt) const
00388 {
00389 b2Vec2 P(m_impulse.x, m_impulse.y);
00390 return inv_dt * P;
00391 }
00392
00393 float32 b2RevoluteJoint::GetReactionTorque(float32 inv_dt) const
00394 {
00395 return inv_dt * m_impulse.z;
00396 }
00397
00398 float32 b2RevoluteJoint::GetJointAngle() const
00399 {
00400 b2Body* bA = m_bodyA;
00401 b2Body* bB = m_bodyB;
00402 return bB->m_sweep.a - bA->m_sweep.a - m_referenceAngle;
00403 }
00404
00405 float32 b2RevoluteJoint::GetJointSpeed() const
00406 {
00407 b2Body* bA = m_bodyA;
00408 b2Body* bB = m_bodyB;
00409 return bB->m_angularVelocity - bA->m_angularVelocity;
00410 }
00411
00412 bool b2RevoluteJoint::IsMotorEnabled() const
00413 {
00414 return m_enableMotor;
00415 }
00416
00417 void b2RevoluteJoint::EnableMotor(bool flag)
00418 {
00419 m_bodyA->SetAwake(true);
00420 m_bodyB->SetAwake(true);
00421 m_enableMotor = flag;
00422 }
00423
00424 float32 b2RevoluteJoint::GetMotorTorque(float32 inv_dt) const
00425 {
00426 return inv_dt * m_motorImpulse;
00427 }
00428
00429 void b2RevoluteJoint::SetMotorSpeed(float32 speed)
00430 {
00431 m_bodyA->SetAwake(true);
00432 m_bodyB->SetAwake(true);
00433 m_motorSpeed = speed;
00434 }
00435
00436 void b2RevoluteJoint::SetMaxMotorTorque(float32 torque)
00437 {
00438 m_bodyA->SetAwake(true);
00439 m_bodyB->SetAwake(true);
00440 m_maxMotorTorque = torque;
00441 }
00442
00443 bool b2RevoluteJoint::IsLimitEnabled() const
00444 {
00445 return m_enableLimit;
00446 }
00447
00448 void b2RevoluteJoint::EnableLimit(bool flag)
00449 {
00450 if (flag != m_enableLimit)
00451 {
00452 m_bodyA->SetAwake(true);
00453 m_bodyB->SetAwake(true);
00454 m_enableLimit = flag;
00455 m_impulse.z = 0.0f;
00456 }
00457 }
00458
00459 float32 b2RevoluteJoint::GetLowerLimit() const
00460 {
00461 return m_lowerAngle;
00462 }
00463
00464 float32 b2RevoluteJoint::GetUpperLimit() const
00465 {
00466 return m_upperAngle;
00467 }
00468
00469 void b2RevoluteJoint::SetLimits(float32 lower, float32 upper)
00470 {
00471 b2Assert(lower <= upper);
00472
00473 if (lower != m_lowerAngle || upper != m_upperAngle)
00474 {
00475 m_bodyA->SetAwake(true);
00476 m_bodyB->SetAwake(true);
00477 m_impulse.z = 0.0f;
00478 m_lowerAngle = lower;
00479 m_upperAngle = upper;
00480 }
00481 }
00482
00483 void b2RevoluteJoint::Dump()
00484 {
00485 int32 indexA = m_bodyA->m_islandIndex;
00486 int32 indexB = m_bodyB->m_islandIndex;
00487
00488 b2Log(" b2RevoluteJointDef jd;\n");
00489 b2Log(" jd.bodyA = bodies[%d];\n", indexA);
00490 b2Log(" jd.bodyB = bodies[%d];\n", indexB);
00491 b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
00492 b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
00493 b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
00494 b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle);
00495 b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit);
00496 b2Log(" jd.lowerAngle = %.15lef;\n", m_lowerAngle);
00497 b2Log(" jd.upperAngle = %.15lef;\n", m_upperAngle);
00498 b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor);
00499 b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed);
00500 b2Log(" jd.maxMotorTorque = %.15lef;\n", m_maxMotorTorque);
00501 b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
00502 }