File indexing completed on 2024-12-29 03:29:26

0001 /*
0002 * Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
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/b2DistanceJoint.h>
0020 #include <Box2D/Dynamics/b2Body.h>
0021 #include <Box2D/Dynamics/b2TimeStep.h>
0022 
0023 // 1-D constrained system
0024 // m (v2 - v1) = lambda
0025 // v2 + (beta/h) * x1 + gamma * lambda = 0, gamma has units of inverse mass.
0026 // x2 = x1 + h * v2
0027 
0028 // 1-D mass-damper-spring system
0029 // m (v2 - v1) + h * d * v2 + h * k * 
0030 
0031 // C = norm(p2 - p1) - L
0032 // u = (p2 - p1) / norm(p2 - p1)
0033 // Cdot = dot(u, v2 + cross(w2, r2) - v1 - cross(w1, r1))
0034 // J = [-u -cross(r1, u) u cross(r2, u)]
0035 // K = J * invM * JT
0036 //   = invMass1 + invI1 * cross(r1, u)^2 + invMass2 + invI2 * cross(r2, u)^2
0037 
0038 void b2DistanceJointDef::Initialize(b2Body* b1, b2Body* b2,
0039                                     const b2Vec2& anchor1, const b2Vec2& anchor2)
0040 {
0041     bodyA = b1;
0042     bodyB = b2;
0043     localAnchorA = bodyA->GetLocalPoint(anchor1);
0044     localAnchorB = bodyB->GetLocalPoint(anchor2);
0045     b2Vec2 d = anchor2 - anchor1;
0046     length = d.Length();
0047 }
0048 
0049 b2DistanceJoint::b2DistanceJoint(const b2DistanceJointDef* def)
0050 : b2Joint(def)
0051 {
0052     m_localAnchorA = def->localAnchorA;
0053     m_localAnchorB = def->localAnchorB;
0054     m_length = def->length;
0055     m_frequencyHz = def->frequencyHz;
0056     m_dampingRatio = def->dampingRatio;
0057     m_impulse = 0.0f;
0058     m_gamma = 0.0f;
0059     m_bias = 0.0f;
0060 }
0061 
0062 void b2DistanceJoint::InitVelocityConstraints(const b2SolverData& data)
0063 {
0064     m_indexA = m_bodyA->m_islandIndex;
0065     m_indexB = m_bodyB->m_islandIndex;
0066     m_localCenterA = m_bodyA->m_sweep.localCenter;
0067     m_localCenterB = m_bodyB->m_sweep.localCenter;
0068     m_invMassA = m_bodyA->m_invMass;
0069     m_invMassB = m_bodyB->m_invMass;
0070     m_invIA = m_bodyA->m_invI;
0071     m_invIB = m_bodyB->m_invI;
0072 
0073     b2Vec2 cA = data.positions[m_indexA].c;
0074     float32 aA = data.positions[m_indexA].a;
0075     b2Vec2 vA = data.velocities[m_indexA].v;
0076     float32 wA = data.velocities[m_indexA].w;
0077 
0078     b2Vec2 cB = data.positions[m_indexB].c;
0079     float32 aB = data.positions[m_indexB].a;
0080     b2Vec2 vB = data.velocities[m_indexB].v;
0081     float32 wB = data.velocities[m_indexB].w;
0082 
0083     b2Rot qA(aA), qB(aB);
0084 
0085     m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
0086     m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
0087     m_u = cB + m_rB - cA - m_rA;
0088 
0089     // Handle singularity.
0090     float32 length = m_u.Length();
0091     if (length > b2_linearSlop)
0092     {
0093         m_u *= 1.0f / length;
0094     }
0095     else
0096     {
0097         m_u.Set(0.0f, 0.0f);
0098     }
0099 
0100     float32 crAu = b2Cross(m_rA, m_u);
0101     float32 crBu = b2Cross(m_rB, m_u);
0102     float32 invMass = m_invMassA + m_invIA * crAu * crAu + m_invMassB + m_invIB * crBu * crBu;
0103 
0104     // Compute the effective mass matrix.
0105     m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;
0106 
0107     if (m_frequencyHz > 0.0f)
0108     {
0109         float32 C = length - m_length;
0110 
0111         // Frequency
0112         float32 omega = 2.0f * b2_pi * m_frequencyHz;
0113 
0114         // Damping coefficient
0115         float32 d = 2.0f * m_mass * m_dampingRatio * omega;
0116 
0117         // Spring stiffness
0118         float32 k = m_mass * omega * omega;
0119 
0120         // magic formulas
0121         float32 h = data.step.dt;
0122         m_gamma = h * (d + h * k);
0123         m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f;
0124         m_bias = C * h * k * m_gamma;
0125 
0126         invMass += m_gamma;
0127         m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;
0128     }
0129     else
0130     {
0131         m_gamma = 0.0f;
0132         m_bias = 0.0f;
0133     }
0134 
0135     if (data.step.warmStarting)
0136     {
0137         // Scale the impulse to support a variable time step.
0138         m_impulse *= data.step.dtRatio;
0139 
0140         b2Vec2 P = m_impulse * m_u;
0141         vA -= m_invMassA * P;
0142         wA -= m_invIA * b2Cross(m_rA, P);
0143         vB += m_invMassB * P;
0144         wB += m_invIB * b2Cross(m_rB, P);
0145     }
0146     else
0147     {
0148         m_impulse = 0.0f;
0149     }
0150 
0151     data.velocities[m_indexA].v = vA;
0152     data.velocities[m_indexA].w = wA;
0153     data.velocities[m_indexB].v = vB;
0154     data.velocities[m_indexB].w = wB;
0155 }
0156 
0157 void b2DistanceJoint::SolveVelocityConstraints(const b2SolverData& data)
0158 {
0159     b2Vec2 vA = data.velocities[m_indexA].v;
0160     float32 wA = data.velocities[m_indexA].w;
0161     b2Vec2 vB = data.velocities[m_indexB].v;
0162     float32 wB = data.velocities[m_indexB].w;
0163 
0164     // Cdot = dot(u, v + cross(w, r))
0165     b2Vec2 vpA = vA + b2Cross(wA, m_rA);
0166     b2Vec2 vpB = vB + b2Cross(wB, m_rB);
0167     float32 Cdot = b2Dot(m_u, vpB - vpA);
0168 
0169     float32 impulse = -m_mass * (Cdot + m_bias + m_gamma * m_impulse);
0170     m_impulse += impulse;
0171 
0172     b2Vec2 P = impulse * m_u;
0173     vA -= m_invMassA * P;
0174     wA -= m_invIA * b2Cross(m_rA, P);
0175     vB += m_invMassB * P;
0176     wB += m_invIB * b2Cross(m_rB, P);
0177 
0178     data.velocities[m_indexA].v = vA;
0179     data.velocities[m_indexA].w = wA;
0180     data.velocities[m_indexB].v = vB;
0181     data.velocities[m_indexB].w = wB;
0182 }
0183 
0184 bool b2DistanceJoint::SolvePositionConstraints(const b2SolverData& data)
0185 {
0186     if (m_frequencyHz > 0.0f)
0187     {
0188         // There is no position correction for soft distance constraints.
0189         return true;
0190     }
0191 
0192     b2Vec2 cA = data.positions[m_indexA].c;
0193     float32 aA = data.positions[m_indexA].a;
0194     b2Vec2 cB = data.positions[m_indexB].c;
0195     float32 aB = data.positions[m_indexB].a;
0196 
0197     b2Rot qA(aA), qB(aB);
0198 
0199     b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
0200     b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
0201     b2Vec2 u = cB + rB - cA - rA;
0202 
0203     float32 length = u.Normalize();
0204     float32 C = length - m_length;
0205     C = b2Clamp(C, -b2_maxLinearCorrection, b2_maxLinearCorrection);
0206 
0207     float32 impulse = -m_mass * C;
0208     b2Vec2 P = impulse * u;
0209 
0210     cA -= m_invMassA * P;
0211     aA -= m_invIA * b2Cross(rA, P);
0212     cB += m_invMassB * P;
0213     aB += m_invIB * b2Cross(rB, P);
0214 
0215     data.positions[m_indexA].c = cA;
0216     data.positions[m_indexA].a = aA;
0217     data.positions[m_indexB].c = cB;
0218     data.positions[m_indexB].a = aB;
0219 
0220     return b2Abs(C) < b2_linearSlop;
0221 }
0222 
0223 b2Vec2 b2DistanceJoint::GetAnchorA() const
0224 {
0225     return m_bodyA->GetWorldPoint(m_localAnchorA);
0226 }
0227 
0228 b2Vec2 b2DistanceJoint::GetAnchorB() const
0229 {
0230     return m_bodyB->GetWorldPoint(m_localAnchorB);
0231 }
0232 
0233 b2Vec2 b2DistanceJoint::GetReactionForce(float32 inv_dt) const
0234 {
0235     b2Vec2 F = (inv_dt * m_impulse) * m_u;
0236     return F;
0237 }
0238 
0239 float32 b2DistanceJoint::GetReactionTorque(float32 inv_dt) const
0240 {
0241     B2_NOT_USED(inv_dt);
0242     return 0.0f;
0243 }
0244 
0245 void b2DistanceJoint::Dump()
0246 {
0247     int32 indexA = m_bodyA->m_islandIndex;
0248     int32 indexB = m_bodyB->m_islandIndex;
0249 
0250     b2Log("  b2DistanceJointDef jd;\n");
0251     b2Log("  jd.bodyA = bodies[%d];\n", indexA);
0252     b2Log("  jd.bodyB = bodies[%d];\n", indexB);
0253     b2Log("  jd.collideConnected = bool(%d);\n", m_collideConnected);
0254     b2Log("  jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
0255     b2Log("  jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
0256     b2Log("  jd.length = %.15lef;\n", m_length);
0257     b2Log("  jd.frequencyHz = %.15lef;\n", m_frequencyHz);
0258     b2Log("  jd.dampingRatio = %.15lef;\n", m_dampingRatio);
0259     b2Log("  joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
0260 }