00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <Box2D/Dynamics/Joints/b2PrismaticJoint.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
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090 void b2PrismaticJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor, const b2Vec2& axis)
00091 {
00092 bodyA = bA;
00093 bodyB = bB;
00094 localAnchorA = bodyA->GetLocalPoint(anchor);
00095 localAnchorB = bodyB->GetLocalPoint(anchor);
00096 localAxisA = bodyA->GetLocalVector(axis);
00097 referenceAngle = bodyB->GetAngle() - bodyA->GetAngle();
00098 }
00099
00100 b2PrismaticJoint::b2PrismaticJoint(const b2PrismaticJointDef* def)
00101 : b2Joint(def)
00102 {
00103 m_localAnchorA = def->localAnchorA;
00104 m_localAnchorB = def->localAnchorB;
00105 m_localXAxisA = def->localAxisA;
00106 m_localXAxisA.Normalize();
00107 m_localYAxisA = b2Cross(1.0f, m_localXAxisA);
00108 m_referenceAngle = def->referenceAngle;
00109
00110 m_impulse.SetZero();
00111 m_motorMass = 0.0f;
00112 m_motorImpulse = 0.0f;
00113
00114 m_lowerTranslation = def->lowerTranslation;
00115 m_upperTranslation = def->upperTranslation;
00116 m_maxMotorForce = def->maxMotorForce;
00117 m_motorSpeed = def->motorSpeed;
00118 m_enableLimit = def->enableLimit;
00119 m_enableMotor = def->enableMotor;
00120 m_limitState = e_inactiveLimit;
00121
00122 m_axis.SetZero();
00123 m_perp.SetZero();
00124 }
00125
00126 void b2PrismaticJoint::InitVelocityConstraints(const b2SolverData& data)
00127 {
00128 m_indexA = m_bodyA->m_islandIndex;
00129 m_indexB = m_bodyB->m_islandIndex;
00130 m_localCenterA = m_bodyA->m_sweep.localCenter;
00131 m_localCenterB = m_bodyB->m_sweep.localCenter;
00132 m_invMassA = m_bodyA->m_invMass;
00133 m_invMassB = m_bodyB->m_invMass;
00134 m_invIA = m_bodyA->m_invI;
00135 m_invIB = m_bodyB->m_invI;
00136
00137 b2Vec2 cA = data.positions[m_indexA].c;
00138 float32 aA = data.positions[m_indexA].a;
00139 b2Vec2 vA = data.velocities[m_indexA].v;
00140 float32 wA = data.velocities[m_indexA].w;
00141
00142 b2Vec2 cB = data.positions[m_indexB].c;
00143 float32 aB = data.positions[m_indexB].a;
00144 b2Vec2 vB = data.velocities[m_indexB].v;
00145 float32 wB = data.velocities[m_indexB].w;
00146
00147 b2Rot qA(aA), qB(aB);
00148
00149
00150 b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
00151 b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
00152 b2Vec2 d = (cB - cA) + rB - rA;
00153
00154 float32 mA = m_invMassA, mB = m_invMassB;
00155 float32 iA = m_invIA, iB = m_invIB;
00156
00157
00158 {
00159 m_axis = b2Mul(qA, m_localXAxisA);
00160 m_a1 = b2Cross(d + rA, m_axis);
00161 m_a2 = b2Cross(rB, m_axis);
00162
00163 m_motorMass = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2;
00164 if (m_motorMass > 0.0f)
00165 {
00166 m_motorMass = 1.0f / m_motorMass;
00167 }
00168 }
00169
00170
00171 {
00172 m_perp = b2Mul(qA, m_localYAxisA);
00173
00174 m_s1 = b2Cross(d + rA, m_perp);
00175 m_s2 = b2Cross(rB, m_perp);
00176
00177 float32 s1test;
00178 s1test = b2Cross(rA, m_perp);
00179
00180 float32 k11 = mA + mB + iA * m_s1 * m_s1 + iB * m_s2 * m_s2;
00181 float32 k12 = iA * m_s1 + iB * m_s2;
00182 float32 k13 = iA * m_s1 * m_a1 + iB * m_s2 * m_a2;
00183 float32 k22 = iA + iB;
00184 if (k22 == 0.0f)
00185 {
00186
00187 k22 = 1.0f;
00188 }
00189 float32 k23 = iA * m_a1 + iB * m_a2;
00190 float32 k33 = mA + mB + iA * m_a1 * m_a1 + iB * m_a2 * m_a2;
00191
00192 m_K.ex.Set(k11, k12, k13);
00193 m_K.ey.Set(k12, k22, k23);
00194 m_K.ez.Set(k13, k23, k33);
00195 }
00196
00197
00198 if (m_enableLimit)
00199 {
00200 float32 jointTranslation = b2Dot(m_axis, d);
00201 if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop)
00202 {
00203 m_limitState = e_equalLimits;
00204 }
00205 else if (jointTranslation <= m_lowerTranslation)
00206 {
00207 if (m_limitState != e_atLowerLimit)
00208 {
00209 m_limitState = e_atLowerLimit;
00210 m_impulse.z = 0.0f;
00211 }
00212 }
00213 else if (jointTranslation >= m_upperTranslation)
00214 {
00215 if (m_limitState != e_atUpperLimit)
00216 {
00217 m_limitState = e_atUpperLimit;
00218 m_impulse.z = 0.0f;
00219 }
00220 }
00221 else
00222 {
00223 m_limitState = e_inactiveLimit;
00224 m_impulse.z = 0.0f;
00225 }
00226 }
00227 else
00228 {
00229 m_limitState = e_inactiveLimit;
00230 m_impulse.z = 0.0f;
00231 }
00232
00233 if (m_enableMotor == false)
00234 {
00235 m_motorImpulse = 0.0f;
00236 }
00237
00238 if (data.step.warmStarting)
00239 {
00240
00241 m_impulse *= data.step.dtRatio;
00242 m_motorImpulse *= data.step.dtRatio;
00243
00244 b2Vec2 P = m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis;
00245 float32 LA = m_impulse.x * m_s1 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a1;
00246 float32 LB = m_impulse.x * m_s2 + m_impulse.y + (m_motorImpulse + m_impulse.z) * m_a2;
00247
00248 vA -= mA * P;
00249 wA -= iA * LA;
00250
00251 vB += mB * P;
00252 wB += iB * LB;
00253 }
00254 else
00255 {
00256 m_impulse.SetZero();
00257 m_motorImpulse = 0.0f;
00258 }
00259
00260 data.velocities[m_indexA].v = vA;
00261 data.velocities[m_indexA].w = wA;
00262 data.velocities[m_indexB].v = vB;
00263 data.velocities[m_indexB].w = wB;
00264 }
00265
00266 void b2PrismaticJoint::SolveVelocityConstraints(const b2SolverData& data)
00267 {
00268 b2Vec2 vA = data.velocities[m_indexA].v;
00269 float32 wA = data.velocities[m_indexA].w;
00270 b2Vec2 vB = data.velocities[m_indexB].v;
00271 float32 wB = data.velocities[m_indexB].w;
00272
00273 float32 mA = m_invMassA, mB = m_invMassB;
00274 float32 iA = m_invIA, iB = m_invIB;
00275
00276
00277 if (m_enableMotor && m_limitState != e_equalLimits)
00278 {
00279 float32 Cdot = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA;
00280 float32 impulse = m_motorMass * (m_motorSpeed - Cdot);
00281 float32 oldImpulse = m_motorImpulse;
00282 float32 maxImpulse = data.step.dt * m_maxMotorForce;
00283 m_motorImpulse = b2Clamp(m_motorImpulse + impulse, -maxImpulse, maxImpulse);
00284 impulse = m_motorImpulse - oldImpulse;
00285
00286 b2Vec2 P = impulse * m_axis;
00287 float32 LA = impulse * m_a1;
00288 float32 LB = impulse * m_a2;
00289
00290 vA -= mA * P;
00291 wA -= iA * LA;
00292
00293 vB += mB * P;
00294 wB += iB * LB;
00295 }
00296
00297 b2Vec2 Cdot1;
00298 Cdot1.x = b2Dot(m_perp, vB - vA) + m_s2 * wB - m_s1 * wA;
00299 Cdot1.y = wB - wA;
00300
00301 if (m_enableLimit && m_limitState != e_inactiveLimit)
00302 {
00303
00304 float32 Cdot2;
00305 Cdot2 = b2Dot(m_axis, vB - vA) + m_a2 * wB - m_a1 * wA;
00306 b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);
00307
00308 b2Vec3 f1 = m_impulse;
00309 b2Vec3 df = m_K.Solve33(-Cdot);
00310 m_impulse += df;
00311
00312 if (m_limitState == e_atLowerLimit)
00313 {
00314 m_impulse.z = b2Max(m_impulse.z, 0.0f);
00315 }
00316 else if (m_limitState == e_atUpperLimit)
00317 {
00318 m_impulse.z = b2Min(m_impulse.z, 0.0f);
00319 }
00320
00321
00322 b2Vec2 b = -Cdot1 - (m_impulse.z - f1.z) * b2Vec2(m_K.ez.x, m_K.ez.y);
00323 b2Vec2 f2r = m_K.Solve22(b) + b2Vec2(f1.x, f1.y);
00324 m_impulse.x = f2r.x;
00325 m_impulse.y = f2r.y;
00326
00327 df = m_impulse - f1;
00328
00329 b2Vec2 P = df.x * m_perp + df.z * m_axis;
00330 float32 LA = df.x * m_s1 + df.y + df.z * m_a1;
00331 float32 LB = df.x * m_s2 + df.y + df.z * m_a2;
00332
00333 vA -= mA * P;
00334 wA -= iA * LA;
00335
00336 vB += mB * P;
00337 wB += iB * LB;
00338 }
00339 else
00340 {
00341
00342 b2Vec2 df = m_K.Solve22(-Cdot1);
00343 m_impulse.x += df.x;
00344 m_impulse.y += df.y;
00345
00346 b2Vec2 P = df.x * m_perp;
00347 float32 LA = df.x * m_s1 + df.y;
00348 float32 LB = df.x * m_s2 + df.y;
00349
00350 vA -= mA * P;
00351 wA -= iA * LA;
00352
00353 vB += mB * P;
00354 wB += iB * LB;
00355 }
00356
00357 data.velocities[m_indexA].v = vA;
00358 data.velocities[m_indexA].w = wA;
00359 data.velocities[m_indexB].v = vB;
00360 data.velocities[m_indexB].w = wB;
00361 }
00362
00363 bool b2PrismaticJoint::SolvePositionConstraints(const b2SolverData& data)
00364 {
00365 b2Vec2 cA = data.positions[m_indexA].c;
00366 float32 aA = data.positions[m_indexA].a;
00367 b2Vec2 cB = data.positions[m_indexB].c;
00368 float32 aB = data.positions[m_indexB].a;
00369
00370 b2Rot qA(aA), qB(aB);
00371
00372 float32 mA = m_invMassA, mB = m_invMassB;
00373 float32 iA = m_invIA, iB = m_invIB;
00374
00375
00376 b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
00377 b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
00378 b2Vec2 d = cB + rB - cA - rA;
00379
00380 b2Vec2 axis = b2Mul(qA, m_localXAxisA);
00381 float32 a1 = b2Cross(d + rA, axis);
00382 float32 a2 = b2Cross(rB, axis);
00383 b2Vec2 perp = b2Mul(qA, m_localYAxisA);
00384
00385 float32 s1 = b2Cross(d + rA, perp);
00386 float32 s2 = b2Cross(rB, perp);
00387
00388 b2Vec3 impulse;
00389 b2Vec2 C1;
00390 C1.x = b2Dot(perp, d);
00391 C1.y = aB - aA - m_referenceAngle;
00392
00393 float32 linearError = b2Abs(C1.x);
00394 float32 angularError = b2Abs(C1.y);
00395
00396 bool active = false;
00397 float32 C2 = 0.0f;
00398 if (m_enableLimit)
00399 {
00400 float32 translation = b2Dot(axis, d);
00401 if (b2Abs(m_upperTranslation - m_lowerTranslation) < 2.0f * b2_linearSlop)
00402 {
00403
00404 C2 = b2Clamp(translation, -b2_maxLinearCorrection, b2_maxLinearCorrection);
00405 linearError = b2Max(linearError, b2Abs(translation));
00406 active = true;
00407 }
00408 else if (translation <= m_lowerTranslation)
00409 {
00410
00411 C2 = b2Clamp(translation - m_lowerTranslation + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);
00412 linearError = b2Max(linearError, m_lowerTranslation - translation);
00413 active = true;
00414 }
00415 else if (translation >= m_upperTranslation)
00416 {
00417
00418 C2 = b2Clamp(translation - m_upperTranslation - b2_linearSlop, 0.0f, b2_maxLinearCorrection);
00419 linearError = b2Max(linearError, translation - m_upperTranslation);
00420 active = true;
00421 }
00422 }
00423
00424 if (active)
00425 {
00426 float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2;
00427 float32 k12 = iA * s1 + iB * s2;
00428 float32 k13 = iA * s1 * a1 + iB * s2 * a2;
00429 float32 k22 = iA + iB;
00430 if (k22 == 0.0f)
00431 {
00432
00433 k22 = 1.0f;
00434 }
00435 float32 k23 = iA * a1 + iB * a2;
00436 float32 k33 = mA + mB + iA * a1 * a1 + iB * a2 * a2;
00437
00438 b2Mat33 K;
00439 K.ex.Set(k11, k12, k13);
00440 K.ey.Set(k12, k22, k23);
00441 K.ez.Set(k13, k23, k33);
00442
00443 b2Vec3 C;
00444 C.x = C1.x;
00445 C.y = C1.y;
00446 C.z = C2;
00447
00448 impulse = K.Solve33(-C);
00449 }
00450 else
00451 {
00452 float32 k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2;
00453 float32 k12 = iA * s1 + iB * s2;
00454 float32 k22 = iA + iB;
00455 if (k22 == 0.0f)
00456 {
00457 k22 = 1.0f;
00458 }
00459
00460 b2Mat22 K;
00461 K.ex.Set(k11, k12);
00462 K.ey.Set(k12, k22);
00463
00464 b2Vec2 impulse1 = K.Solve(-C1);
00465 impulse.x = impulse1.x;
00466 impulse.y = impulse1.y;
00467 impulse.z = 0.0f;
00468 }
00469
00470 b2Vec2 P = impulse.x * perp + impulse.z * axis;
00471 float32 LA = impulse.x * s1 + impulse.y + impulse.z * a1;
00472 float32 LB = impulse.x * s2 + impulse.y + impulse.z * a2;
00473
00474 cA -= mA * P;
00475 aA -= iA * LA;
00476 cB += mB * P;
00477 aB += iB * LB;
00478
00479 data.positions[m_indexA].c = cA;
00480 data.positions[m_indexA].a = aA;
00481 data.positions[m_indexB].c = cB;
00482 data.positions[m_indexB].a = aB;
00483
00484 return linearError <= b2_linearSlop && angularError <= b2_angularSlop;
00485 }
00486
00487 b2Vec2 b2PrismaticJoint::GetAnchorA() const
00488 {
00489 return m_bodyA->GetWorldPoint(m_localAnchorA);
00490 }
00491
00492 b2Vec2 b2PrismaticJoint::GetAnchorB() const
00493 {
00494 return m_bodyB->GetWorldPoint(m_localAnchorB);
00495 }
00496
00497 b2Vec2 b2PrismaticJoint::GetReactionForce(float32 inv_dt) const
00498 {
00499 return inv_dt * (m_impulse.x * m_perp + (m_motorImpulse + m_impulse.z) * m_axis);
00500 }
00501
00502 float32 b2PrismaticJoint::GetReactionTorque(float32 inv_dt) const
00503 {
00504 return inv_dt * m_impulse.y;
00505 }
00506
00507 float32 b2PrismaticJoint::GetJointTranslation() const
00508 {
00509 b2Vec2 pA = m_bodyA->GetWorldPoint(m_localAnchorA);
00510 b2Vec2 pB = m_bodyB->GetWorldPoint(m_localAnchorB);
00511 b2Vec2 d = pB - pA;
00512 b2Vec2 axis = m_bodyA->GetWorldVector(m_localXAxisA);
00513
00514 float32 translation = b2Dot(d, axis);
00515 return translation;
00516 }
00517
00518 float32 b2PrismaticJoint::GetJointSpeed() const
00519 {
00520 b2Body* bA = m_bodyA;
00521 b2Body* bB = m_bodyB;
00522
00523 b2Vec2 rA = b2Mul(bA->m_xf.q, m_localAnchorA - bA->m_sweep.localCenter);
00524 b2Vec2 rB = b2Mul(bB->m_xf.q, m_localAnchorB - bB->m_sweep.localCenter);
00525 b2Vec2 p1 = bA->m_sweep.c + rA;
00526 b2Vec2 p2 = bB->m_sweep.c + rB;
00527 b2Vec2 d = p2 - p1;
00528 b2Vec2 axis = b2Mul(bA->m_xf.q, m_localXAxisA);
00529
00530 b2Vec2 vA = bA->m_linearVelocity;
00531 b2Vec2 vB = bB->m_linearVelocity;
00532 float32 wA = bA->m_angularVelocity;
00533 float32 wB = bB->m_angularVelocity;
00534
00535 float32 speed = b2Dot(d, b2Cross(wA, axis)) + b2Dot(axis, vB + b2Cross(wB, rB) - vA - b2Cross(wA, rA));
00536 return speed;
00537 }
00538
00539 bool b2PrismaticJoint::IsLimitEnabled() const
00540 {
00541 return m_enableLimit;
00542 }
00543
00544 void b2PrismaticJoint::EnableLimit(bool flag)
00545 {
00546 if (flag != m_enableLimit)
00547 {
00548 m_bodyA->SetAwake(true);
00549 m_bodyB->SetAwake(true);
00550 m_enableLimit = flag;
00551 m_impulse.z = 0.0f;
00552 }
00553 }
00554
00555 float32 b2PrismaticJoint::GetLowerLimit() const
00556 {
00557 return m_lowerTranslation;
00558 }
00559
00560 float32 b2PrismaticJoint::GetUpperLimit() const
00561 {
00562 return m_upperTranslation;
00563 }
00564
00565 void b2PrismaticJoint::SetLimits(float32 lower, float32 upper)
00566 {
00567 b2Assert(lower <= upper);
00568 if (lower != m_lowerTranslation || upper != m_upperTranslation)
00569 {
00570 m_bodyA->SetAwake(true);
00571 m_bodyB->SetAwake(true);
00572 m_lowerTranslation = lower;
00573 m_upperTranslation = upper;
00574 m_impulse.z = 0.0f;
00575 }
00576 }
00577
00578 bool b2PrismaticJoint::IsMotorEnabled() const
00579 {
00580 return m_enableMotor;
00581 }
00582
00583 void b2PrismaticJoint::EnableMotor(bool flag)
00584 {
00585 m_bodyA->SetAwake(true);
00586 m_bodyB->SetAwake(true);
00587 m_enableMotor = flag;
00588 }
00589
00590 void b2PrismaticJoint::SetMotorSpeed(float32 speed)
00591 {
00592 m_bodyA->SetAwake(true);
00593 m_bodyB->SetAwake(true);
00594 m_motorSpeed = speed;
00595 }
00596
00597 void b2PrismaticJoint::SetMaxMotorForce(float32 force)
00598 {
00599 m_bodyA->SetAwake(true);
00600 m_bodyB->SetAwake(true);
00601 m_maxMotorForce = force;
00602 }
00603
00604 float32 b2PrismaticJoint::GetMotorForce(float32 inv_dt) const
00605 {
00606 return inv_dt * m_motorImpulse;
00607 }
00608
00609 void b2PrismaticJoint::Dump()
00610 {
00611 int32 indexA = m_bodyA->m_islandIndex;
00612 int32 indexB = m_bodyB->m_islandIndex;
00613
00614 b2Log(" b2PrismaticJointDef jd;\n");
00615 b2Log(" jd.bodyA = bodies[%d];\n", indexA);
00616 b2Log(" jd.bodyB = bodies[%d];\n", indexB);
00617 b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
00618 b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
00619 b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
00620 b2Log(" jd.localAxisA.Set(%.15lef, %.15lef);\n", m_localXAxisA.x, m_localXAxisA.y);
00621 b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle);
00622 b2Log(" jd.enableLimit = bool(%d);\n", m_enableLimit);
00623 b2Log(" jd.lowerTranslation = %.15lef;\n", m_lowerTranslation);
00624 b2Log(" jd.upperTranslation = %.15lef;\n", m_upperTranslation);
00625 b2Log(" jd.enableMotor = bool(%d);\n", m_enableMotor);
00626 b2Log(" jd.motorSpeed = %.15lef;\n", m_motorSpeed);
00627 b2Log(" jd.maxMotorForce = %.15lef;\n", m_maxMotorForce);
00628 b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
00629 }