File indexing completed on 2024-12-29 03:29:28
0001 /* 0002 * Copyright (c) 2007 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/b2PulleyJoint.h> 0020 #include <Box2D/Dynamics/b2Body.h> 0021 #include <Box2D/Dynamics/b2TimeStep.h> 0022 0023 // Pulley: 0024 // length1 = norm(p1 - s1) 0025 // length2 = norm(p2 - s2) 0026 // C0 = (length1 + ratio * length2)_initial 0027 // C = C0 - (length1 + ratio * length2) 0028 // u1 = (p1 - s1) / norm(p1 - s1) 0029 // u2 = (p2 - s2) / norm(p2 - s2) 0030 // Cdot = -dot(u1, v1 + cross(w1, r1)) - ratio * dot(u2, v2 + cross(w2, r2)) 0031 // J = -[u1 cross(r1, u1) ratio * u2 ratio * cross(r2, u2)] 0032 // K = J * invM * JT 0033 // = invMass1 + invI1 * cross(r1, u1)^2 + ratio^2 * (invMass2 + invI2 * cross(r2, u2)^2) 0034 0035 void b2PulleyJointDef::Initialize(b2Body* bA, b2Body* bB, 0036 const b2Vec2& groundA, const b2Vec2& groundB, 0037 const b2Vec2& anchorA, const b2Vec2& anchorB, 0038 float32 r) 0039 { 0040 bodyA = bA; 0041 bodyB = bB; 0042 groundAnchorA = groundA; 0043 groundAnchorB = groundB; 0044 localAnchorA = bodyA->GetLocalPoint(anchorA); 0045 localAnchorB = bodyB->GetLocalPoint(anchorB); 0046 b2Vec2 dA = anchorA - groundA; 0047 lengthA = dA.Length(); 0048 b2Vec2 dB = anchorB - groundB; 0049 lengthB = dB.Length(); 0050 ratio = r; 0051 b2Assert(ratio > b2_epsilon); 0052 } 0053 0054 b2PulleyJoint::b2PulleyJoint(const b2PulleyJointDef* def) 0055 : b2Joint(def) 0056 { 0057 m_groundAnchorA = def->groundAnchorA; 0058 m_groundAnchorB = def->groundAnchorB; 0059 m_localAnchorA = def->localAnchorA; 0060 m_localAnchorB = def->localAnchorB; 0061 0062 m_lengthA = def->lengthA; 0063 m_lengthB = def->lengthB; 0064 0065 b2Assert(def->ratio != 0.0f); 0066 m_ratio = def->ratio; 0067 0068 m_constant = def->lengthA + m_ratio * def->lengthB; 0069 0070 m_impulse = 0.0f; 0071 } 0072 0073 void b2PulleyJoint::InitVelocityConstraints(const b2SolverData& data) 0074 { 0075 m_indexA = m_bodyA->m_islandIndex; 0076 m_indexB = m_bodyB->m_islandIndex; 0077 m_localCenterA = m_bodyA->m_sweep.localCenter; 0078 m_localCenterB = m_bodyB->m_sweep.localCenter; 0079 m_invMassA = m_bodyA->m_invMass; 0080 m_invMassB = m_bodyB->m_invMass; 0081 m_invIA = m_bodyA->m_invI; 0082 m_invIB = m_bodyB->m_invI; 0083 0084 b2Vec2 cA = data.positions[m_indexA].c; 0085 float32 aA = data.positions[m_indexA].a; 0086 b2Vec2 vA = data.velocities[m_indexA].v; 0087 float32 wA = data.velocities[m_indexA].w; 0088 0089 b2Vec2 cB = data.positions[m_indexB].c; 0090 float32 aB = data.positions[m_indexB].a; 0091 b2Vec2 vB = data.velocities[m_indexB].v; 0092 float32 wB = data.velocities[m_indexB].w; 0093 0094 b2Rot qA(aA), qB(aB); 0095 0096 m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); 0097 m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); 0098 0099 // Get the pulley axes. 0100 m_uA = cA + m_rA - m_groundAnchorA; 0101 m_uB = cB + m_rB - m_groundAnchorB; 0102 0103 float32 lengthA = m_uA.Length(); 0104 float32 lengthB = m_uB.Length(); 0105 0106 if (lengthA > 10.0f * b2_linearSlop) 0107 { 0108 m_uA *= 1.0f / lengthA; 0109 } 0110 else 0111 { 0112 m_uA.SetZero(); 0113 } 0114 0115 if (lengthB > 10.0f * b2_linearSlop) 0116 { 0117 m_uB *= 1.0f / lengthB; 0118 } 0119 else 0120 { 0121 m_uB.SetZero(); 0122 } 0123 0124 // Compute effective mass. 0125 float32 ruA = b2Cross(m_rA, m_uA); 0126 float32 ruB = b2Cross(m_rB, m_uB); 0127 0128 float32 mA = m_invMassA + m_invIA * ruA * ruA; 0129 float32 mB = m_invMassB + m_invIB * ruB * ruB; 0130 0131 m_mass = mA + m_ratio * m_ratio * mB; 0132 0133 if (m_mass > 0.0f) 0134 { 0135 m_mass = 1.0f / m_mass; 0136 } 0137 0138 if (data.step.warmStarting) 0139 { 0140 // Scale impulses to support variable time steps. 0141 m_impulse *= data.step.dtRatio; 0142 0143 // Warm starting. 0144 b2Vec2 PA = -(m_impulse) * m_uA; 0145 b2Vec2 PB = (-m_ratio * m_impulse) * m_uB; 0146 0147 vA += m_invMassA * PA; 0148 wA += m_invIA * b2Cross(m_rA, PA); 0149 vB += m_invMassB * PB; 0150 wB += m_invIB * b2Cross(m_rB, PB); 0151 } 0152 else 0153 { 0154 m_impulse = 0.0f; 0155 } 0156 0157 data.velocities[m_indexA].v = vA; 0158 data.velocities[m_indexA].w = wA; 0159 data.velocities[m_indexB].v = vB; 0160 data.velocities[m_indexB].w = wB; 0161 } 0162 0163 void b2PulleyJoint::SolveVelocityConstraints(const b2SolverData& data) 0164 { 0165 b2Vec2 vA = data.velocities[m_indexA].v; 0166 float32 wA = data.velocities[m_indexA].w; 0167 b2Vec2 vB = data.velocities[m_indexB].v; 0168 float32 wB = data.velocities[m_indexB].w; 0169 0170 b2Vec2 vpA = vA + b2Cross(wA, m_rA); 0171 b2Vec2 vpB = vB + b2Cross(wB, m_rB); 0172 0173 float32 Cdot = -b2Dot(m_uA, vpA) - m_ratio * b2Dot(m_uB, vpB); 0174 float32 impulse = -m_mass * Cdot; 0175 m_impulse += impulse; 0176 0177 b2Vec2 PA = -impulse * m_uA; 0178 b2Vec2 PB = -m_ratio * impulse * m_uB; 0179 vA += m_invMassA * PA; 0180 wA += m_invIA * b2Cross(m_rA, PA); 0181 vB += m_invMassB * PB; 0182 wB += m_invIB * b2Cross(m_rB, PB); 0183 0184 data.velocities[m_indexA].v = vA; 0185 data.velocities[m_indexA].w = wA; 0186 data.velocities[m_indexB].v = vB; 0187 data.velocities[m_indexB].w = wB; 0188 } 0189 0190 bool b2PulleyJoint::SolvePositionConstraints(const b2SolverData& data) 0191 { 0192 b2Vec2 cA = data.positions[m_indexA].c; 0193 float32 aA = data.positions[m_indexA].a; 0194 b2Vec2 cB = data.positions[m_indexB].c; 0195 float32 aB = data.positions[m_indexB].a; 0196 0197 b2Rot qA(aA), qB(aB); 0198 0199 b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); 0200 b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); 0201 0202 // Get the pulley axes. 0203 b2Vec2 uA = cA + rA - m_groundAnchorA; 0204 b2Vec2 uB = cB + rB - m_groundAnchorB; 0205 0206 float32 lengthA = uA.Length(); 0207 float32 lengthB = uB.Length(); 0208 0209 if (lengthA > 10.0f * b2_linearSlop) 0210 { 0211 uA *= 1.0f / lengthA; 0212 } 0213 else 0214 { 0215 uA.SetZero(); 0216 } 0217 0218 if (lengthB > 10.0f * b2_linearSlop) 0219 { 0220 uB *= 1.0f / lengthB; 0221 } 0222 else 0223 { 0224 uB.SetZero(); 0225 } 0226 0227 // Compute effective mass. 0228 float32 ruA = b2Cross(rA, uA); 0229 float32 ruB = b2Cross(rB, uB); 0230 0231 float32 mA = m_invMassA + m_invIA * ruA * ruA; 0232 float32 mB = m_invMassB + m_invIB * ruB * ruB; 0233 0234 float32 mass = mA + m_ratio * m_ratio * mB; 0235 0236 if (mass > 0.0f) 0237 { 0238 mass = 1.0f / mass; 0239 } 0240 0241 float32 C = m_constant - lengthA - m_ratio * lengthB; 0242 float32 linearError = b2Abs(C); 0243 0244 float32 impulse = -mass * C; 0245 0246 b2Vec2 PA = -impulse * uA; 0247 b2Vec2 PB = -m_ratio * impulse * uB; 0248 0249 cA += m_invMassA * PA; 0250 aA += m_invIA * b2Cross(rA, PA); 0251 cB += m_invMassB * PB; 0252 aB += m_invIB * b2Cross(rB, PB); 0253 0254 data.positions[m_indexA].c = cA; 0255 data.positions[m_indexA].a = aA; 0256 data.positions[m_indexB].c = cB; 0257 data.positions[m_indexB].a = aB; 0258 0259 return linearError < b2_linearSlop; 0260 } 0261 0262 b2Vec2 b2PulleyJoint::GetAnchorA() const 0263 { 0264 return m_bodyA->GetWorldPoint(m_localAnchorA); 0265 } 0266 0267 b2Vec2 b2PulleyJoint::GetAnchorB() const 0268 { 0269 return m_bodyB->GetWorldPoint(m_localAnchorB); 0270 } 0271 0272 b2Vec2 b2PulleyJoint::GetReactionForce(float32 inv_dt) const 0273 { 0274 b2Vec2 P = m_impulse * m_uB; 0275 return inv_dt * P; 0276 } 0277 0278 float32 b2PulleyJoint::GetReactionTorque(float32 inv_dt) const 0279 { 0280 B2_NOT_USED(inv_dt); 0281 return 0.0f; 0282 } 0283 0284 b2Vec2 b2PulleyJoint::GetGroundAnchorA() const 0285 { 0286 return m_groundAnchorA; 0287 } 0288 0289 b2Vec2 b2PulleyJoint::GetGroundAnchorB() const 0290 { 0291 return m_groundAnchorB; 0292 } 0293 0294 float32 b2PulleyJoint::GetLengthA() const 0295 { 0296 return m_lengthA; 0297 } 0298 0299 float32 b2PulleyJoint::GetLengthB() const 0300 { 0301 return m_lengthB; 0302 } 0303 0304 float32 b2PulleyJoint::GetRatio() const 0305 { 0306 return m_ratio; 0307 } 0308 0309 float32 b2PulleyJoint::GetCurrentLengthA() const 0310 { 0311 b2Vec2 p = m_bodyA->GetWorldPoint(m_localAnchorA); 0312 b2Vec2 s = m_groundAnchorA; 0313 b2Vec2 d = p - s; 0314 return d.Length(); 0315 } 0316 0317 float32 b2PulleyJoint::GetCurrentLengthB() const 0318 { 0319 b2Vec2 p = m_bodyB->GetWorldPoint(m_localAnchorB); 0320 b2Vec2 s = m_groundAnchorB; 0321 b2Vec2 d = p - s; 0322 return d.Length(); 0323 } 0324 0325 void b2PulleyJoint::Dump() 0326 { 0327 int32 indexA = m_bodyA->m_islandIndex; 0328 int32 indexB = m_bodyB->m_islandIndex; 0329 0330 b2Log(" b2PulleyJointDef jd;\n"); 0331 b2Log(" jd.bodyA = bodies[%d];\n", indexA); 0332 b2Log(" jd.bodyB = bodies[%d];\n", indexB); 0333 b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); 0334 b2Log(" jd.groundAnchorA.Set(%.15lef, %.15lef);\n", m_groundAnchorA.x, m_groundAnchorA.y); 0335 b2Log(" jd.groundAnchorB.Set(%.15lef, %.15lef);\n", m_groundAnchorB.x, m_groundAnchorB.y); 0336 b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); 0337 b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); 0338 b2Log(" jd.lengthA = %.15lef;\n", m_lengthA); 0339 b2Log(" jd.lengthB = %.15lef;\n", m_lengthB); 0340 b2Log(" jd.ratio = %.15lef;\n", m_ratio); 0341 b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); 0342 } 0343 0344 void b2PulleyJoint::ShiftOrigin(const b2Vec2& newOrigin) 0345 { 0346 m_groundAnchorA -= newOrigin; 0347 m_groundAnchorB -= newOrigin; 0348 }