File indexing completed on 2025-08-03 03:49:58
0001 /* 0002 * Copyright (c) 2006-2007 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/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 0050 b2DistanceJoint::b2DistanceJoint(const b2DistanceJointDef* def) 0051 : b2Joint(def) 0052 { 0053 m_localAnchor1 = def->localAnchorA; 0054 m_localAnchor2 = def->localAnchorB; 0055 m_length = def->length; 0056 m_frequencyHz = def->frequencyHz; 0057 m_dampingRatio = def->dampingRatio; 0058 m_impulse = 0.0f; 0059 m_gamma = 0.0f; 0060 m_bias = 0.0f; 0061 } 0062 0063 void b2DistanceJoint::InitVelocityConstraints(const b2TimeStep& step) 0064 { 0065 b2Body* b1 = m_bodyA; 0066 b2Body* b2 = m_bodyB; 0067 0068 // Compute the effective mass matrix. 0069 b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter()); 0070 b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter()); 0071 m_u = b2->m_sweep.c + r2 - b1->m_sweep.c - r1; 0072 0073 // Handle singularity. 0074 qreal length = m_u.Length(); 0075 if (length > b2_linearSlop) 0076 { 0077 m_u *= 1.0f / length; 0078 } 0079 else 0080 { 0081 m_u.Set(0.0f, 0.0f); 0082 } 0083 0084 qreal cr1u = b2Cross(r1, m_u); 0085 qreal cr2u = b2Cross(r2, m_u); 0086 qreal invMass = b1->m_invMass + b1->m_invI * cr1u * cr1u + b2->m_invMass + b2->m_invI * cr2u * cr2u; 0087 0088 m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; 0089 0090 if (m_frequencyHz > 0.0f) 0091 { 0092 qreal C = length - m_length; 0093 0094 // Frequency 0095 qreal omega = 2.0f * b2_pi * m_frequencyHz; 0096 0097 // Damping coefficient 0098 qreal d = 2.0f * m_mass * m_dampingRatio * omega; 0099 0100 // Spring stiffness 0101 qreal k = m_mass * omega * omega; 0102 0103 // magic formulas 0104 m_gamma = step.dt * (d + step.dt * k); 0105 m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f; 0106 m_bias = C * step.dt * k * m_gamma; 0107 0108 m_mass = invMass + m_gamma; 0109 m_mass = m_mass != 0.0f ? 1.0f / m_mass : 0.0f; 0110 } 0111 0112 if (step.warmStarting) 0113 { 0114 // Scale the impulse to support a variable time step. 0115 m_impulse *= step.dtRatio; 0116 0117 b2Vec2 P = m_impulse * m_u; 0118 b1->m_linearVelocity -= b1->m_invMass * P; 0119 b1->m_angularVelocity -= b1->m_invI * b2Cross(r1, P); 0120 b2->m_linearVelocity += b2->m_invMass * P; 0121 b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P); 0122 } 0123 else 0124 { 0125 m_impulse = 0.0f; 0126 } 0127 } 0128 0129 void b2DistanceJoint::SolveVelocityConstraints(const b2TimeStep& step) 0130 { 0131 B2_NOT_USED(step); 0132 0133 b2Body* b1 = m_bodyA; 0134 b2Body* b2 = m_bodyB; 0135 0136 b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter()); 0137 b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter()); 0138 0139 // Cdot = dot(u, v + cross(w, r)) 0140 b2Vec2 v1 = b1->m_linearVelocity + b2Cross(b1->m_angularVelocity, r1); 0141 b2Vec2 v2 = b2->m_linearVelocity + b2Cross(b2->m_angularVelocity, r2); 0142 qreal Cdot = b2Dot(m_u, v2 - v1); 0143 0144 qreal impulse = -m_mass * (Cdot + m_bias + m_gamma * m_impulse); 0145 m_impulse += impulse; 0146 0147 b2Vec2 P = impulse * m_u; 0148 b1->m_linearVelocity -= b1->m_invMass * P; 0149 b1->m_angularVelocity -= b1->m_invI * b2Cross(r1, P); 0150 b2->m_linearVelocity += b2->m_invMass * P; 0151 b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P); 0152 } 0153 0154 bool b2DistanceJoint::SolvePositionConstraints(qreal baumgarte) 0155 { 0156 B2_NOT_USED(baumgarte); 0157 0158 if (m_frequencyHz > 0.0f) 0159 { 0160 // There is no position correction for soft distance constraints. 0161 return true; 0162 } 0163 0164 b2Body* b1 = m_bodyA; 0165 b2Body* b2 = m_bodyB; 0166 0167 b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter()); 0168 b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter()); 0169 0170 b2Vec2 d = b2->m_sweep.c + r2 - b1->m_sweep.c - r1; 0171 0172 qreal length = d.Normalize(); 0173 qreal C = length - m_length; 0174 C = b2Clamp(C, -b2_maxLinearCorrection, b2_maxLinearCorrection); 0175 0176 qreal impulse = -m_mass * C; 0177 m_u = d; 0178 b2Vec2 P = impulse * m_u; 0179 0180 b1->m_sweep.c -= b1->m_invMass * P; 0181 b1->m_sweep.a -= b1->m_invI * b2Cross(r1, P); 0182 b2->m_sweep.c += b2->m_invMass * P; 0183 b2->m_sweep.a += b2->m_invI * b2Cross(r2, P); 0184 0185 b1->SynchronizeTransform(); 0186 b2->SynchronizeTransform(); 0187 0188 return b2Abs(C) < b2_linearSlop; 0189 } 0190 0191 b2Vec2 b2DistanceJoint::GetAnchorA() const 0192 { 0193 return m_bodyA->GetWorldPoint(m_localAnchor1); 0194 } 0195 0196 b2Vec2 b2DistanceJoint::GetAnchorB() const 0197 { 0198 return m_bodyB->GetWorldPoint(m_localAnchor2); 0199 } 0200 0201 b2Vec2 b2DistanceJoint::GetReactionForce(qreal inv_dt) const 0202 { 0203 b2Vec2 F = (inv_dt * m_impulse) * m_u; 0204 return F; 0205 } 0206 0207 qreal b2DistanceJoint::GetReactionTorque(qreal inv_dt) const 0208 { 0209 B2_NOT_USED(inv_dt); 0210 return 0.0f; 0211 }