File indexing completed on 2025-08-03 03:50:00

0001 /*
0002 * Copyright (c) 2006-2009 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/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 
0053     m_impulse.SetZero();
0054 }
0055 
0056 void b2WeldJoint::InitVelocityConstraints(const b2TimeStep& step)
0057 {
0058     b2Body* bA = m_bodyA;
0059     b2Body* bB = m_bodyB;
0060 
0061     // Compute the effective mass matrix.
0062     b2Vec2 rA = b2Mul(bA->GetTransform().R, m_localAnchorA - bA->GetLocalCenter());
0063     b2Vec2 rB = b2Mul(bB->GetTransform().R, m_localAnchorB - bB->GetLocalCenter());
0064 
0065     // J = [-I -r1_skew I r2_skew]
0066     //     [ 0       -1 0       1]
0067     // r_skew = [-ry; rx]
0068 
0069     // Matlab
0070     // K = [ mA+r1y^2*iA+mB+r2y^2*iB,  -r1y*iA*r1x-r2y*iB*r2x,          -r1y*iA-r2y*iB]
0071     //     [  -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB,           r1x*iA+r2x*iB]
0072     //     [          -r1y*iA-r2y*iB,           r1x*iA+r2x*iB,                   iA+iB]
0073 
0074     qreal mA = bA->m_invMass, mB = bB->m_invMass;
0075     qreal iA = bA->m_invI, iB = bB->m_invI;
0076 
0077     m_mass.col1.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB;
0078     m_mass.col2.x = -rA.y * rA.x * iA - rB.y * rB.x * iB;
0079     m_mass.col3.x = -rA.y * iA - rB.y * iB;
0080     m_mass.col1.y = m_mass.col2.x;
0081     m_mass.col2.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB;
0082     m_mass.col3.y = rA.x * iA + rB.x * iB;
0083     m_mass.col1.z = m_mass.col3.x;
0084     m_mass.col2.z = m_mass.col3.y;
0085     m_mass.col3.z = iA + iB;
0086 
0087     if (step.warmStarting)
0088     {
0089         // Scale impulses to support a variable time step.
0090         m_impulse *= step.dtRatio;
0091 
0092         b2Vec2 P(m_impulse.x, m_impulse.y);
0093 
0094         bA->m_linearVelocity -= mA * P;
0095         bA->m_angularVelocity -= iA * (b2Cross(rA, P) + m_impulse.z);
0096 
0097         bB->m_linearVelocity += mB * P;
0098         bB->m_angularVelocity += iB * (b2Cross(rB, P) + m_impulse.z);
0099     }
0100     else
0101     {
0102         m_impulse.SetZero();
0103     }
0104 }
0105 
0106 void b2WeldJoint::SolveVelocityConstraints(const b2TimeStep& step)
0107 {
0108     B2_NOT_USED(step);
0109 
0110     b2Body* bA = m_bodyA;
0111     b2Body* bB = m_bodyB;
0112 
0113     b2Vec2 vA = bA->m_linearVelocity;
0114     qreal wA = bA->m_angularVelocity;
0115     b2Vec2 vB = bB->m_linearVelocity;
0116     qreal wB = bB->m_angularVelocity;
0117 
0118     qreal mA = bA->m_invMass, mB = bB->m_invMass;
0119     qreal iA = bA->m_invI, iB = bB->m_invI;
0120 
0121     b2Vec2 rA = b2Mul(bA->GetTransform().R, m_localAnchorA - bA->GetLocalCenter());
0122     b2Vec2 rB = b2Mul(bB->GetTransform().R, m_localAnchorB - bB->GetLocalCenter());
0123 
0124     // Solve point-to-point constraint
0125     b2Vec2 Cdot1 = vB + b2Cross(wB, rB) - vA - b2Cross(wA, rA);
0126     qreal Cdot2 = wB - wA;
0127     b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2);
0128 
0129     b2Vec3 impulse = m_mass.Solve33(-Cdot);
0130     m_impulse += impulse;
0131 
0132     b2Vec2 P(impulse.x, impulse.y);
0133 
0134     vA -= mA * P;
0135     wA -= iA * (b2Cross(rA, P) + impulse.z);
0136 
0137     vB += mB * P;
0138     wB += iB * (b2Cross(rB, P) + impulse.z);
0139 
0140     bA->m_linearVelocity = vA;
0141     bA->m_angularVelocity = wA;
0142     bB->m_linearVelocity = vB;
0143     bB->m_angularVelocity = wB;
0144 }
0145 
0146 bool b2WeldJoint::SolvePositionConstraints(qreal baumgarte)
0147 {
0148     B2_NOT_USED(baumgarte);
0149 
0150     b2Body* bA = m_bodyA;
0151     b2Body* bB = m_bodyB;
0152 
0153     qreal mA = bA->m_invMass, mB = bB->m_invMass;
0154     qreal iA = bA->m_invI, iB = bB->m_invI;
0155 
0156     b2Vec2 rA = b2Mul(bA->GetTransform().R, m_localAnchorA - bA->GetLocalCenter());
0157     b2Vec2 rB = b2Mul(bB->GetTransform().R, m_localAnchorB - bB->GetLocalCenter());
0158 
0159     b2Vec2 C1 =  bB->m_sweep.c + rB - bA->m_sweep.c - rA;
0160     qreal C2 = bB->m_sweep.a - bA->m_sweep.a - m_referenceAngle;
0161 
0162     // Handle large detachment.
0163     const qreal k_allowedStretch = 10.0f * b2_linearSlop;
0164     qreal positionError = C1.Length();
0165     qreal angularError = b2Abs(C2);
0166     if (positionError > k_allowedStretch)
0167     {
0168         iA *= 1.0f;
0169         iB *= 1.0f;
0170     }
0171 
0172     m_mass.col1.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB;
0173     m_mass.col2.x = -rA.y * rA.x * iA - rB.y * rB.x * iB;
0174     m_mass.col3.x = -rA.y * iA - rB.y * iB;
0175     m_mass.col1.y = m_mass.col2.x;
0176     m_mass.col2.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB;
0177     m_mass.col3.y = rA.x * iA + rB.x * iB;
0178     m_mass.col1.z = m_mass.col3.x;
0179     m_mass.col2.z = m_mass.col3.y;
0180     m_mass.col3.z = iA + iB;
0181 
0182     b2Vec3 C(C1.x, C1.y, C2);
0183 
0184     b2Vec3 impulse = m_mass.Solve33(-C);
0185 
0186     b2Vec2 P(impulse.x, impulse.y);
0187 
0188     bA->m_sweep.c -= mA * P;
0189     bA->m_sweep.a -= iA * (b2Cross(rA, P) + impulse.z);
0190 
0191     bB->m_sweep.c += mB * P;
0192     bB->m_sweep.a += iB * (b2Cross(rB, P) + impulse.z);
0193 
0194     bA->SynchronizeTransform();
0195     bB->SynchronizeTransform();
0196 
0197     return positionError <= b2_linearSlop && angularError <= b2_angularSlop;
0198 }
0199 
0200 b2Vec2 b2WeldJoint::GetAnchorA() const
0201 {
0202     return m_bodyA->GetWorldPoint(m_localAnchorA);
0203 }
0204 
0205 b2Vec2 b2WeldJoint::GetAnchorB() const
0206 {
0207     return m_bodyB->GetWorldPoint(m_localAnchorB);
0208 }
0209 
0210 b2Vec2 b2WeldJoint::GetReactionForce(qreal inv_dt) const
0211 {
0212     b2Vec2 P(m_impulse.x, m_impulse.y);
0213     return inv_dt * P;
0214 }
0215 
0216 qreal b2WeldJoint::GetReactionTorque(qreal inv_dt) const
0217 {
0218     return inv_dt * m_impulse.z;
0219 }