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

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/b2WeldJoint.h>
0020 #include <Box2D/Dynamics/b2Body.h>
0021 #include <Box2D/Dynamics/b2TimeStep.h>
0022 
0023 // Point-to-point constraint
0024 // C = p2 - p1
0025 // Cdot = v2 - v1
0026 //      = v2 + cross(w2, r2) - v1 - cross(w1, r1)
0027 // J = [-I -r1_skew I r2_skew ]
0028 // Identity used:
0029 // w k % (rx i + ry j) = w * (-ry i + rx j)
0030 
0031 // Angle constraint
0032 // C = angle2 - angle1 - referenceAngle
0033 // Cdot = w2 - w1
0034 // J = [0 0 -1 0 0 1]
0035 // K = invI1 + invI2
0036 
0037 void b2WeldJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor)
0038 {
0039     bodyA = bA;
0040     bodyB = bB;
0041     localAnchorA = bodyA->GetLocalPoint(anchor);
0042     localAnchorB = bodyB->GetLocalPoint(anchor);
0043     referenceAngle = bodyB->GetAngle() - bodyA->GetAngle();
0044 }
0045 
0046 b2WeldJoint::b2WeldJoint(const b2WeldJointDef* def)
0047 : b2Joint(def)
0048 {
0049     m_localAnchorA = def->localAnchorA;
0050     m_localAnchorB = def->localAnchorB;
0051     m_referenceAngle = def->referenceAngle;
0052     m_frequencyHz = def->frequencyHz;
0053     m_dampingRatio = def->dampingRatio;
0054 
0055     m_impulse.SetZero();
0056 }
0057 
0058 void b2WeldJoint::InitVelocityConstraints(const b2SolverData& data)
0059 {
0060     m_indexA = m_bodyA->m_islandIndex;
0061     m_indexB = m_bodyB->m_islandIndex;
0062     m_localCenterA = m_bodyA->m_sweep.localCenter;
0063     m_localCenterB = m_bodyB->m_sweep.localCenter;
0064     m_invMassA = m_bodyA->m_invMass;
0065     m_invMassB = m_bodyB->m_invMass;
0066     m_invIA = m_bodyA->m_invI;
0067     m_invIB = m_bodyB->m_invI;
0068 
0069     float32 aA = data.positions[m_indexA].a;
0070     b2Vec2 vA = data.velocities[m_indexA].v;
0071     float32 wA = data.velocities[m_indexA].w;
0072 
0073     float32 aB = data.positions[m_indexB].a;
0074     b2Vec2 vB = data.velocities[m_indexB].v;
0075     float32 wB = data.velocities[m_indexB].w;
0076 
0077     b2Rot qA(aA), qB(aB);
0078 
0079     m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
0080     m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
0081 
0082     // J = [-I -r1_skew I r2_skew]
0083     //     [ 0       -1 0       1]
0084     // r_skew = [-ry; rx]
0085 
0086     // Matlab
0087     // K = [ mA+r1y^2*iA+mB+r2y^2*iB,  -r1y*iA*r1x-r2y*iB*r2x,          -r1y*iA-r2y*iB]
0088     //     [  -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB,           r1x*iA+r2x*iB]
0089     //     [          -r1y*iA-r2y*iB,           r1x*iA+r2x*iB,                   iA+iB]
0090 
0091     float32 mA = m_invMassA, mB = m_invMassB;
0092     float32 iA = m_invIA, iB = m_invIB;
0093 
0094     b2Mat33 K;
0095     K.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB;
0096     K.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB;
0097     K.ez.x = -m_rA.y * iA - m_rB.y * iB;
0098     K.ex.y = K.ey.x;
0099     K.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB;
0100     K.ez.y = m_rA.x * iA + m_rB.x * iB;
0101     K.ex.z = K.ez.x;
0102     K.ey.z = K.ez.y;
0103     K.ez.z = iA + iB;
0104 
0105     if (m_frequencyHz > 0.0f)
0106     {
0107         K.GetInverse22(&m_mass);
0108 
0109         float32 invM = iA + iB;
0110         float32 m = invM > 0.0f ? 1.0f / invM : 0.0f;
0111 
0112         float32 C = aB - aA - m_referenceAngle;
0113 
0114         // Frequency
0115         float32 omega = 2.0f * b2_pi * m_frequencyHz;
0116 
0117         // Damping coefficient
0118         float32 d = 2.0f * m * m_dampingRatio * omega;
0119 
0120         // Spring stiffness
0121         float32 k = m * omega * omega;
0122 
0123         // magic formulas
0124         float32 h = data.step.dt;
0125         m_gamma = h * (d + h * k);
0126         m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f;
0127         m_bias = C * h * k * m_gamma;
0128 
0129         invM += m_gamma;
0130         m_mass.ez.z = invM != 0.0f ? 1.0f / invM : 0.0f;
0131     }
0132     else if (K.ez.z == 0.0f)
0133     {
0134         K.GetInverse22(&m_mass);
0135         m_gamma = 0.0f;
0136         m_bias = 0.0f;
0137     }
0138     else
0139     {
0140         K.GetSymInverse33(&m_mass);
0141         m_gamma = 0.0f;
0142         m_bias = 0.0f;
0143     }
0144 
0145     if (data.step.warmStarting)
0146     {
0147         // Scale impulses to support a variable time step.
0148         m_impulse *= data.step.dtRatio;
0149 
0150         b2Vec2 P(m_impulse.x, m_impulse.y);
0151 
0152         vA -= mA * P;
0153         wA -= iA * (b2Cross(m_rA, P) + m_impulse.z);
0154 
0155         vB += mB * P;
0156         wB += iB * (b2Cross(m_rB, P) + m_impulse.z);
0157     }
0158     else
0159     {
0160         m_impulse.SetZero();
0161     }
0162 
0163     data.velocities[m_indexA].v = vA;
0164     data.velocities[m_indexA].w = wA;
0165     data.velocities[m_indexB].v = vB;
0166     data.velocities[m_indexB].w = wB;
0167 }
0168 
0169 void b2WeldJoint::SolveVelocityConstraints(const b2SolverData& data)
0170 {
0171     b2Vec2 vA = data.velocities[m_indexA].v;
0172     float32 wA = data.velocities[m_indexA].w;
0173     b2Vec2 vB = data.velocities[m_indexB].v;
0174     float32 wB = data.velocities[m_indexB].w;
0175 
0176     float32 mA = m_invMassA, mB = m_invMassB;
0177     float32 iA = m_invIA, iB = m_invIB;
0178 
0179     if (m_frequencyHz > 0.0f)
0180     {
0181         float32 Cdot2 = wB - wA;
0182 
0183         float32 impulse2 = -m_mass.ez.z * (Cdot2 + m_bias + m_gamma * m_impulse.z);
0184         m_impulse.z += impulse2;
0185 
0186         wA -= iA * impulse2;
0187         wB += iB * impulse2;
0188 
0189         b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
0190 
0191         b2Vec2 impulse1 = -b2Mul22(m_mass, Cdot1);
0192         m_impulse.x += impulse1.x;
0193         m_impulse.y += impulse1.y;
0194 
0195         b2Vec2 P = impulse1;
0196 
0197         vA -= mA * P;
0198         wA -= iA * b2Cross(m_rA, P);
0199 
0200         vB += mB * P;
0201         wB += iB * b2Cross(m_rB, P);
0202     }
0203     else
0204     {
0205         b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA);
0206         float32 Cdot2 = wB - wA;
0207         b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);
0208 
0209         b2Vec3 impulse = -b2Mul(m_mass, Cdot);
0210         m_impulse += impulse;
0211 
0212         b2Vec2 P(impulse.x, impulse.y);
0213 
0214         vA -= mA * P;
0215         wA -= iA * (b2Cross(m_rA, P) + impulse.z);
0216 
0217         vB += mB * P;
0218         wB += iB * (b2Cross(m_rB, P) + impulse.z);
0219     }
0220 
0221     data.velocities[m_indexA].v = vA;
0222     data.velocities[m_indexA].w = wA;
0223     data.velocities[m_indexB].v = vB;
0224     data.velocities[m_indexB].w = wB;
0225 }
0226 
0227 bool b2WeldJoint::SolvePositionConstraints(const b2SolverData& data)
0228 {
0229     b2Vec2 cA = data.positions[m_indexA].c;
0230     float32 aA = data.positions[m_indexA].a;
0231     b2Vec2 cB = data.positions[m_indexB].c;
0232     float32 aB = data.positions[m_indexB].a;
0233 
0234     b2Rot qA(aA), qB(aB);
0235 
0236     float32 mA = m_invMassA, mB = m_invMassB;
0237     float32 iA = m_invIA, iB = m_invIB;
0238 
0239     b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
0240     b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
0241 
0242     float32 positionError, angularError;
0243 
0244     b2Mat33 K;
0245     K.ex.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB;
0246     K.ey.x = -rA.y * rA.x * iA - rB.y * rB.x * iB;
0247     K.ez.x = -rA.y * iA - rB.y * iB;
0248     K.ex.y = K.ey.x;
0249     K.ey.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB;
0250     K.ez.y = rA.x * iA + rB.x * iB;
0251     K.ex.z = K.ez.x;
0252     K.ey.z = K.ez.y;
0253     K.ez.z = iA + iB;
0254 
0255     if (m_frequencyHz > 0.0f)
0256     {
0257         b2Vec2 C1 =  cB + rB - cA - rA;
0258 
0259         positionError = C1.Length();
0260         angularError = 0.0f;
0261 
0262         b2Vec2 P = -K.Solve22(C1);
0263 
0264         cA -= mA * P;
0265         aA -= iA * b2Cross(rA, P);
0266 
0267         cB += mB * P;
0268         aB += iB * b2Cross(rB, P);
0269     }
0270     else
0271     {
0272         b2Vec2 C1 =  cB + rB - cA - rA;
0273         float32 C2 = aB - aA - m_referenceAngle;
0274 
0275         positionError = C1.Length();
0276         angularError = b2Abs(C2);
0277 
0278         b2Vec3 C(C1.x, C1.y, C2);
0279     
0280         b2Vec3 impulse;
0281         if (K.ez.z > 0.0f)
0282         {
0283             impulse = -K.Solve33(C);
0284         }
0285         else
0286         {
0287             b2Vec2 impulse2 = -K.Solve22(C1);
0288             impulse.Set(impulse2.x, impulse2.y, 0.0f);
0289         }
0290 
0291         b2Vec2 P(impulse.x, impulse.y);
0292 
0293         cA -= mA * P;
0294         aA -= iA * (b2Cross(rA, P) + impulse.z);
0295 
0296         cB += mB * P;
0297         aB += iB * (b2Cross(rB, P) + impulse.z);
0298     }
0299 
0300     data.positions[m_indexA].c = cA;
0301     data.positions[m_indexA].a = aA;
0302     data.positions[m_indexB].c = cB;
0303     data.positions[m_indexB].a = aB;
0304 
0305     return positionError <= b2_linearSlop && angularError <= b2_angularSlop;
0306 }
0307 
0308 b2Vec2 b2WeldJoint::GetAnchorA() const
0309 {
0310     return m_bodyA->GetWorldPoint(m_localAnchorA);
0311 }
0312 
0313 b2Vec2 b2WeldJoint::GetAnchorB() const
0314 {
0315     return m_bodyB->GetWorldPoint(m_localAnchorB);
0316 }
0317 
0318 b2Vec2 b2WeldJoint::GetReactionForce(float32 inv_dt) const
0319 {
0320     b2Vec2 P(m_impulse.x, m_impulse.y);
0321     return inv_dt * P;
0322 }
0323 
0324 float32 b2WeldJoint::GetReactionTorque(float32 inv_dt) const
0325 {
0326     return inv_dt * m_impulse.z;
0327 }
0328 
0329 void b2WeldJoint::Dump()
0330 {
0331     int32 indexA = m_bodyA->m_islandIndex;
0332     int32 indexB = m_bodyB->m_islandIndex;
0333 
0334     b2Log("  b2WeldJointDef jd;\n");
0335     b2Log("  jd.bodyA = bodies[%d];\n", indexA);
0336     b2Log("  jd.bodyB = bodies[%d];\n", indexB);
0337     b2Log("  jd.collideConnected = bool(%d);\n", m_collideConnected);
0338     b2Log("  jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y);
0339     b2Log("  jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y);
0340     b2Log("  jd.referenceAngle = %.15lef;\n", m_referenceAngle);
0341     b2Log("  jd.frequencyHz = %.15lef;\n", m_frequencyHz);
0342     b2Log("  jd.dampingRatio = %.15lef;\n", m_dampingRatio);
0343     b2Log("  joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
0344 }