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 }