File indexing completed on 2024-12-29 03:29:28
0001 /* 0002 * Copyright (c) 2006-2011 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/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 m_frequencyHz = def->frequencyHz; 0053 m_dampingRatio = def->dampingRatio; 0054 0055 m_impulse.SetZero(); 0056 } 0057 0058 void b2WeldJoint::InitVelocityConstraints(const b2SolverData& data) 0059 { 0060 m_indexA = m_bodyA->m_islandIndex; 0061 m_indexB = m_bodyB->m_islandIndex; 0062 m_localCenterA = m_bodyA->m_sweep.localCenter; 0063 m_localCenterB = m_bodyB->m_sweep.localCenter; 0064 m_invMassA = m_bodyA->m_invMass; 0065 m_invMassB = m_bodyB->m_invMass; 0066 m_invIA = m_bodyA->m_invI; 0067 m_invIB = m_bodyB->m_invI; 0068 0069 float32 aA = data.positions[m_indexA].a; 0070 b2Vec2 vA = data.velocities[m_indexA].v; 0071 float32 wA = data.velocities[m_indexA].w; 0072 0073 float32 aB = data.positions[m_indexB].a; 0074 b2Vec2 vB = data.velocities[m_indexB].v; 0075 float32 wB = data.velocities[m_indexB].w; 0076 0077 b2Rot qA(aA), qB(aB); 0078 0079 m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA); 0080 m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB); 0081 0082 // J = [-I -r1_skew I r2_skew] 0083 // [ 0 -1 0 1] 0084 // r_skew = [-ry; rx] 0085 0086 // Matlab 0087 // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB] 0088 // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB] 0089 // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB] 0090 0091 float32 mA = m_invMassA, mB = m_invMassB; 0092 float32 iA = m_invIA, iB = m_invIB; 0093 0094 b2Mat33 K; 0095 K.ex.x = mA + mB + m_rA.y * m_rA.y * iA + m_rB.y * m_rB.y * iB; 0096 K.ey.x = -m_rA.y * m_rA.x * iA - m_rB.y * m_rB.x * iB; 0097 K.ez.x = -m_rA.y * iA - m_rB.y * iB; 0098 K.ex.y = K.ey.x; 0099 K.ey.y = mA + mB + m_rA.x * m_rA.x * iA + m_rB.x * m_rB.x * iB; 0100 K.ez.y = m_rA.x * iA + m_rB.x * iB; 0101 K.ex.z = K.ez.x; 0102 K.ey.z = K.ez.y; 0103 K.ez.z = iA + iB; 0104 0105 if (m_frequencyHz > 0.0f) 0106 { 0107 K.GetInverse22(&m_mass); 0108 0109 float32 invM = iA + iB; 0110 float32 m = invM > 0.0f ? 1.0f / invM : 0.0f; 0111 0112 float32 C = aB - aA - m_referenceAngle; 0113 0114 // Frequency 0115 float32 omega = 2.0f * b2_pi * m_frequencyHz; 0116 0117 // Damping coefficient 0118 float32 d = 2.0f * m * m_dampingRatio * omega; 0119 0120 // Spring stiffness 0121 float32 k = m * omega * omega; 0122 0123 // magic formulas 0124 float32 h = data.step.dt; 0125 m_gamma = h * (d + h * k); 0126 m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f; 0127 m_bias = C * h * k * m_gamma; 0128 0129 invM += m_gamma; 0130 m_mass.ez.z = invM != 0.0f ? 1.0f / invM : 0.0f; 0131 } 0132 else if (K.ez.z == 0.0f) 0133 { 0134 K.GetInverse22(&m_mass); 0135 m_gamma = 0.0f; 0136 m_bias = 0.0f; 0137 } 0138 else 0139 { 0140 K.GetSymInverse33(&m_mass); 0141 m_gamma = 0.0f; 0142 m_bias = 0.0f; 0143 } 0144 0145 if (data.step.warmStarting) 0146 { 0147 // Scale impulses to support a variable time step. 0148 m_impulse *= data.step.dtRatio; 0149 0150 b2Vec2 P(m_impulse.x, m_impulse.y); 0151 0152 vA -= mA * P; 0153 wA -= iA * (b2Cross(m_rA, P) + m_impulse.z); 0154 0155 vB += mB * P; 0156 wB += iB * (b2Cross(m_rB, P) + m_impulse.z); 0157 } 0158 else 0159 { 0160 m_impulse.SetZero(); 0161 } 0162 0163 data.velocities[m_indexA].v = vA; 0164 data.velocities[m_indexA].w = wA; 0165 data.velocities[m_indexB].v = vB; 0166 data.velocities[m_indexB].w = wB; 0167 } 0168 0169 void b2WeldJoint::SolveVelocityConstraints(const b2SolverData& data) 0170 { 0171 b2Vec2 vA = data.velocities[m_indexA].v; 0172 float32 wA = data.velocities[m_indexA].w; 0173 b2Vec2 vB = data.velocities[m_indexB].v; 0174 float32 wB = data.velocities[m_indexB].w; 0175 0176 float32 mA = m_invMassA, mB = m_invMassB; 0177 float32 iA = m_invIA, iB = m_invIB; 0178 0179 if (m_frequencyHz > 0.0f) 0180 { 0181 float32 Cdot2 = wB - wA; 0182 0183 float32 impulse2 = -m_mass.ez.z * (Cdot2 + m_bias + m_gamma * m_impulse.z); 0184 m_impulse.z += impulse2; 0185 0186 wA -= iA * impulse2; 0187 wB += iB * impulse2; 0188 0189 b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); 0190 0191 b2Vec2 impulse1 = -b2Mul22(m_mass, Cdot1); 0192 m_impulse.x += impulse1.x; 0193 m_impulse.y += impulse1.y; 0194 0195 b2Vec2 P = impulse1; 0196 0197 vA -= mA * P; 0198 wA -= iA * b2Cross(m_rA, P); 0199 0200 vB += mB * P; 0201 wB += iB * b2Cross(m_rB, P); 0202 } 0203 else 0204 { 0205 b2Vec2 Cdot1 = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA); 0206 float32 Cdot2 = wB - wA; 0207 b2Vec3 Cdot(Cdot1.x, Cdot1.y, Cdot2); 0208 0209 b2Vec3 impulse = -b2Mul(m_mass, Cdot); 0210 m_impulse += impulse; 0211 0212 b2Vec2 P(impulse.x, impulse.y); 0213 0214 vA -= mA * P; 0215 wA -= iA * (b2Cross(m_rA, P) + impulse.z); 0216 0217 vB += mB * P; 0218 wB += iB * (b2Cross(m_rB, P) + impulse.z); 0219 } 0220 0221 data.velocities[m_indexA].v = vA; 0222 data.velocities[m_indexA].w = wA; 0223 data.velocities[m_indexB].v = vB; 0224 data.velocities[m_indexB].w = wB; 0225 } 0226 0227 bool b2WeldJoint::SolvePositionConstraints(const b2SolverData& data) 0228 { 0229 b2Vec2 cA = data.positions[m_indexA].c; 0230 float32 aA = data.positions[m_indexA].a; 0231 b2Vec2 cB = data.positions[m_indexB].c; 0232 float32 aB = data.positions[m_indexB].a; 0233 0234 b2Rot qA(aA), qB(aB); 0235 0236 float32 mA = m_invMassA, mB = m_invMassB; 0237 float32 iA = m_invIA, iB = m_invIB; 0238 0239 b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA); 0240 b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB); 0241 0242 float32 positionError, angularError; 0243 0244 b2Mat33 K; 0245 K.ex.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB; 0246 K.ey.x = -rA.y * rA.x * iA - rB.y * rB.x * iB; 0247 K.ez.x = -rA.y * iA - rB.y * iB; 0248 K.ex.y = K.ey.x; 0249 K.ey.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB; 0250 K.ez.y = rA.x * iA + rB.x * iB; 0251 K.ex.z = K.ez.x; 0252 K.ey.z = K.ez.y; 0253 K.ez.z = iA + iB; 0254 0255 if (m_frequencyHz > 0.0f) 0256 { 0257 b2Vec2 C1 = cB + rB - cA - rA; 0258 0259 positionError = C1.Length(); 0260 angularError = 0.0f; 0261 0262 b2Vec2 P = -K.Solve22(C1); 0263 0264 cA -= mA * P; 0265 aA -= iA * b2Cross(rA, P); 0266 0267 cB += mB * P; 0268 aB += iB * b2Cross(rB, P); 0269 } 0270 else 0271 { 0272 b2Vec2 C1 = cB + rB - cA - rA; 0273 float32 C2 = aB - aA - m_referenceAngle; 0274 0275 positionError = C1.Length(); 0276 angularError = b2Abs(C2); 0277 0278 b2Vec3 C(C1.x, C1.y, C2); 0279 0280 b2Vec3 impulse; 0281 if (K.ez.z > 0.0f) 0282 { 0283 impulse = -K.Solve33(C); 0284 } 0285 else 0286 { 0287 b2Vec2 impulse2 = -K.Solve22(C1); 0288 impulse.Set(impulse2.x, impulse2.y, 0.0f); 0289 } 0290 0291 b2Vec2 P(impulse.x, impulse.y); 0292 0293 cA -= mA * P; 0294 aA -= iA * (b2Cross(rA, P) + impulse.z); 0295 0296 cB += mB * P; 0297 aB += iB * (b2Cross(rB, P) + impulse.z); 0298 } 0299 0300 data.positions[m_indexA].c = cA; 0301 data.positions[m_indexA].a = aA; 0302 data.positions[m_indexB].c = cB; 0303 data.positions[m_indexB].a = aB; 0304 0305 return positionError <= b2_linearSlop && angularError <= b2_angularSlop; 0306 } 0307 0308 b2Vec2 b2WeldJoint::GetAnchorA() const 0309 { 0310 return m_bodyA->GetWorldPoint(m_localAnchorA); 0311 } 0312 0313 b2Vec2 b2WeldJoint::GetAnchorB() const 0314 { 0315 return m_bodyB->GetWorldPoint(m_localAnchorB); 0316 } 0317 0318 b2Vec2 b2WeldJoint::GetReactionForce(float32 inv_dt) const 0319 { 0320 b2Vec2 P(m_impulse.x, m_impulse.y); 0321 return inv_dt * P; 0322 } 0323 0324 float32 b2WeldJoint::GetReactionTorque(float32 inv_dt) const 0325 { 0326 return inv_dt * m_impulse.z; 0327 } 0328 0329 void b2WeldJoint::Dump() 0330 { 0331 int32 indexA = m_bodyA->m_islandIndex; 0332 int32 indexB = m_bodyB->m_islandIndex; 0333 0334 b2Log(" b2WeldJointDef jd;\n"); 0335 b2Log(" jd.bodyA = bodies[%d];\n", indexA); 0336 b2Log(" jd.bodyB = bodies[%d];\n", indexB); 0337 b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected); 0338 b2Log(" jd.localAnchorA.Set(%.15lef, %.15lef);\n", m_localAnchorA.x, m_localAnchorA.y); 0339 b2Log(" jd.localAnchorB.Set(%.15lef, %.15lef);\n", m_localAnchorB.x, m_localAnchorB.y); 0340 b2Log(" jd.referenceAngle = %.15lef;\n", m_referenceAngle); 0341 b2Log(" jd.frequencyHz = %.15lef;\n", m_frequencyHz); 0342 b2Log(" jd.dampingRatio = %.15lef;\n", m_dampingRatio); 0343 b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index); 0344 }