File indexing completed on 2025-08-03 03:50:00
0001 /* 0002 * Copyright (c) 2007-2010 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/b2RopeJoint.h> 0020 #include <Box2D/Dynamics/b2Body.h> 0021 #include <Box2D/Dynamics/b2TimeStep.h> 0022 0023 0024 // Limit: 0025 // C = norm(pB - pA) - L 0026 // u = (pB - pA) / norm(pB - pA) 0027 // Cdot = dot(u, vB + cross(wB, rB) - vA - cross(wA, rA)) 0028 // J = [-u -cross(rA, u) u cross(rB, u)] 0029 // K = J * invM * JT 0030 // = invMassA + invIA * cross(rA, u)^2 + invMassB + invIB * cross(rB, u)^2 0031 0032 b2RopeJoint::b2RopeJoint(const b2RopeJointDef* def) 0033 : b2Joint(def) 0034 { 0035 m_localAnchorA = def->localAnchorA; 0036 m_localAnchorB = def->localAnchorB; 0037 0038 m_maxLength = def->maxLength; 0039 0040 m_mass = 0.0f; 0041 m_impulse = 0.0f; 0042 m_state = e_inactiveLimit; 0043 m_length = 0.0f; 0044 } 0045 0046 void b2RopeJoint::InitVelocityConstraints(const b2TimeStep& step) 0047 { 0048 b2Body* bA = m_bodyA; 0049 b2Body* bB = m_bodyB; 0050 0051 m_rA = b2Mul(bA->GetTransform().R, m_localAnchorA - bA->GetLocalCenter()); 0052 m_rB = b2Mul(bB->GetTransform().R, m_localAnchorB - bB->GetLocalCenter()); 0053 0054 // Rope axis 0055 m_u = bB->m_sweep.c + m_rB - bA->m_sweep.c - m_rA; 0056 0057 m_length = m_u.Length(); 0058 0059 qreal C = m_length - m_maxLength; 0060 if (C > 0.0f) 0061 { 0062 m_state = e_atUpperLimit; 0063 } 0064 else 0065 { 0066 m_state = e_inactiveLimit; 0067 } 0068 0069 if (m_length > b2_linearSlop) 0070 { 0071 m_u *= 1.0f / m_length; 0072 } 0073 else 0074 { 0075 m_u.SetZero(); 0076 m_mass = 0.0f; 0077 m_impulse = 0.0f; 0078 return; 0079 } 0080 0081 // Compute effective mass. 0082 qreal crA = b2Cross(m_rA, m_u); 0083 qreal crB = b2Cross(m_rB, m_u); 0084 qreal invMass = bA->m_invMass + bA->m_invI * crA * crA + bB->m_invMass + bB->m_invI * crB * crB; 0085 0086 m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f; 0087 0088 if (step.warmStarting) 0089 { 0090 // Scale the impulse to support a variable time step. 0091 m_impulse *= step.dtRatio; 0092 0093 b2Vec2 P = m_impulse * m_u; 0094 bA->m_linearVelocity -= bA->m_invMass * P; 0095 bA->m_angularVelocity -= bA->m_invI * b2Cross(m_rA, P); 0096 bB->m_linearVelocity += bB->m_invMass * P; 0097 bB->m_angularVelocity += bB->m_invI * b2Cross(m_rB, P); 0098 } 0099 else 0100 { 0101 m_impulse = 0.0f; 0102 } 0103 } 0104 0105 void b2RopeJoint::SolveVelocityConstraints(const b2TimeStep& step) 0106 { 0107 B2_NOT_USED(step); 0108 0109 b2Body* bA = m_bodyA; 0110 b2Body* bB = m_bodyB; 0111 0112 // Cdot = dot(u, v + cross(w, r)) 0113 b2Vec2 vA = bA->m_linearVelocity + b2Cross(bA->m_angularVelocity, m_rA); 0114 b2Vec2 vB = bB->m_linearVelocity + b2Cross(bB->m_angularVelocity, m_rB); 0115 qreal C = m_length - m_maxLength; 0116 qreal Cdot = b2Dot(m_u, vB - vA); 0117 0118 // Predictive constraint. 0119 if (C < 0.0f) 0120 { 0121 Cdot += step.inv_dt * C; 0122 } 0123 0124 qreal impulse = -m_mass * Cdot; 0125 qreal oldImpulse = m_impulse; 0126 m_impulse = b2Min(0.0f, m_impulse + impulse); 0127 impulse = m_impulse - oldImpulse; 0128 0129 b2Vec2 P = impulse * m_u; 0130 bA->m_linearVelocity -= bA->m_invMass * P; 0131 bA->m_angularVelocity -= bA->m_invI * b2Cross(m_rA, P); 0132 bB->m_linearVelocity += bB->m_invMass * P; 0133 bB->m_angularVelocity += bB->m_invI * b2Cross(m_rB, P); 0134 } 0135 0136 bool b2RopeJoint::SolvePositionConstraints(qreal baumgarte) 0137 { 0138 B2_NOT_USED(baumgarte); 0139 0140 b2Body* bA = m_bodyA; 0141 b2Body* bB = m_bodyB; 0142 0143 b2Vec2 rA = b2Mul(bA->GetTransform().R, m_localAnchorA - bA->GetLocalCenter()); 0144 b2Vec2 rB = b2Mul(bB->GetTransform().R, m_localAnchorB - bB->GetLocalCenter()); 0145 0146 b2Vec2 u = bB->m_sweep.c + rB - bA->m_sweep.c - rA; 0147 0148 qreal length = u.Normalize(); 0149 qreal C = length - m_maxLength; 0150 0151 C = b2Clamp(C, 0.0f, b2_maxLinearCorrection); 0152 0153 qreal impulse = -m_mass * C; 0154 b2Vec2 P = impulse * u; 0155 0156 bA->m_sweep.c -= bA->m_invMass * P; 0157 bA->m_sweep.a -= bA->m_invI * b2Cross(rA, P); 0158 bB->m_sweep.c += bB->m_invMass * P; 0159 bB->m_sweep.a += bB->m_invI * b2Cross(rB, P); 0160 0161 bA->SynchronizeTransform(); 0162 bB->SynchronizeTransform(); 0163 0164 return length - m_maxLength < b2_linearSlop; 0165 } 0166 0167 b2Vec2 b2RopeJoint::GetAnchorA() const 0168 { 0169 return m_bodyA->GetWorldPoint(m_localAnchorA); 0170 } 0171 0172 b2Vec2 b2RopeJoint::GetAnchorB() const 0173 { 0174 return m_bodyB->GetWorldPoint(m_localAnchorB); 0175 } 0176 0177 b2Vec2 b2RopeJoint::GetReactionForce(qreal inv_dt) const 0178 { 0179 b2Vec2 F = (inv_dt * m_impulse) * m_u; 0180 return F; 0181 } 0182 0183 qreal b2RopeJoint::GetReactionTorque(qreal inv_dt) const 0184 { 0185 B2_NOT_USED(inv_dt); 0186 return 0.0f; 0187 } 0188 0189 qreal b2RopeJoint::GetMaxLength() const 0190 { 0191 return m_maxLength; 0192 } 0193 0194 b2LimitState b2RopeJoint::GetLimitState() const 0195 { 0196 return m_state; 0197 }