File indexing completed on 2025-08-03 03:49:58
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/b2FrictionJoint.h> 0020 #include <Box2D/Dynamics/b2Body.h> 0021 #include <Box2D/Dynamics/b2TimeStep.h> 0022 0023 // Point-to-point constraint 0024 // Cdot = v2 - v1 0025 // = v2 + cross(w2, r2) - v1 - cross(w1, r1) 0026 // J = [-I -r1_skew I r2_skew ] 0027 // Identity used: 0028 // w k % (rx i + ry j) = w * (-ry i + rx j) 0029 0030 // Angle constraint 0031 // Cdot = w2 - w1 0032 // J = [0 0 -1 0 0 1] 0033 // K = invI1 + invI2 0034 0035 void b2FrictionJointDef::Initialize(b2Body* bA, b2Body* bB, const b2Vec2& anchor) 0036 { 0037 bodyA = bA; 0038 bodyB = bB; 0039 localAnchorA = bodyA->GetLocalPoint(anchor); 0040 localAnchorB = bodyB->GetLocalPoint(anchor); 0041 } 0042 0043 b2FrictionJoint::b2FrictionJoint(const b2FrictionJointDef* def) 0044 : b2Joint(def) 0045 { 0046 m_localAnchorA = def->localAnchorA; 0047 m_localAnchorB = def->localAnchorB; 0048 0049 m_linearImpulse.SetZero(); 0050 m_angularImpulse = 0.0f; 0051 0052 m_maxForce = def->maxForce; 0053 m_maxTorque = def->maxTorque; 0054 } 0055 0056 void b2FrictionJoint::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 b2Mat22 K1; 0078 K1.col1.x = mA + mB; K1.col2.x = 0.0f; 0079 K1.col1.y = 0.0f; K1.col2.y = mA + mB; 0080 0081 b2Mat22 K2; 0082 K2.col1.x = iA * rA.y * rA.y; K2.col2.x = -iA * rA.x * rA.y; 0083 K2.col1.y = -iA * rA.x * rA.y; K2.col2.y = iA * rA.x * rA.x; 0084 0085 b2Mat22 K3; 0086 K3.col1.x = iB * rB.y * rB.y; K3.col2.x = -iB * rB.x * rB.y; 0087 K3.col1.y = -iB * rB.x * rB.y; K3.col2.y = iB * rB.x * rB.x; 0088 0089 b2Mat22 K = K1 + K2 + K3; 0090 m_linearMass = K.GetInverse(); 0091 0092 m_angularMass = iA + iB; 0093 if (m_angularMass > 0.0f) 0094 { 0095 m_angularMass = 1.0f / m_angularMass; 0096 } 0097 0098 if (step.warmStarting) 0099 { 0100 // Scale impulses to support a variable time step. 0101 m_linearImpulse *= step.dtRatio; 0102 m_angularImpulse *= step.dtRatio; 0103 0104 b2Vec2 P(m_linearImpulse.x, m_linearImpulse.y); 0105 0106 bA->m_linearVelocity -= mA * P; 0107 bA->m_angularVelocity -= iA * (b2Cross(rA, P) + m_angularImpulse); 0108 0109 bB->m_linearVelocity += mB * P; 0110 bB->m_angularVelocity += iB * (b2Cross(rB, P) + m_angularImpulse); 0111 } 0112 else 0113 { 0114 m_linearImpulse.SetZero(); 0115 m_angularImpulse = 0.0f; 0116 } 0117 } 0118 0119 void b2FrictionJoint::SolveVelocityConstraints(const b2TimeStep& step) 0120 { 0121 B2_NOT_USED(step); 0122 0123 b2Body* bA = m_bodyA; 0124 b2Body* bB = m_bodyB; 0125 0126 b2Vec2 vA = bA->m_linearVelocity; 0127 qreal wA = bA->m_angularVelocity; 0128 b2Vec2 vB = bB->m_linearVelocity; 0129 qreal wB = bB->m_angularVelocity; 0130 0131 qreal mA = bA->m_invMass, mB = bB->m_invMass; 0132 qreal iA = bA->m_invI, iB = bB->m_invI; 0133 0134 b2Vec2 rA = b2Mul(bA->GetTransform().R, m_localAnchorA - bA->GetLocalCenter()); 0135 b2Vec2 rB = b2Mul(bB->GetTransform().R, m_localAnchorB - bB->GetLocalCenter()); 0136 0137 // Solve angular friction 0138 { 0139 qreal Cdot = wB - wA; 0140 qreal impulse = -m_angularMass * Cdot; 0141 0142 qreal oldImpulse = m_angularImpulse; 0143 qreal maxImpulse = step.dt * m_maxTorque; 0144 m_angularImpulse = b2Clamp(m_angularImpulse + impulse, -maxImpulse, maxImpulse); 0145 impulse = m_angularImpulse - oldImpulse; 0146 0147 wA -= iA * impulse; 0148 wB += iB * impulse; 0149 } 0150 0151 // Solve linear friction 0152 { 0153 b2Vec2 Cdot = vB + b2Cross(wB, rB) - vA - b2Cross(wA, rA); 0154 0155 b2Vec2 impulse = -b2Mul(m_linearMass, Cdot); 0156 b2Vec2 oldImpulse = m_linearImpulse; 0157 m_linearImpulse += impulse; 0158 0159 qreal maxImpulse = step.dt * m_maxForce; 0160 0161 if (m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse) 0162 { 0163 m_linearImpulse.Normalize(); 0164 m_linearImpulse *= maxImpulse; 0165 } 0166 0167 impulse = m_linearImpulse - oldImpulse; 0168 0169 vA -= mA * impulse; 0170 wA -= iA * b2Cross(rA, impulse); 0171 0172 vB += mB * impulse; 0173 wB += iB * b2Cross(rB, impulse); 0174 } 0175 0176 bA->m_linearVelocity = vA; 0177 bA->m_angularVelocity = wA; 0178 bB->m_linearVelocity = vB; 0179 bB->m_angularVelocity = wB; 0180 } 0181 0182 bool b2FrictionJoint::SolvePositionConstraints(qreal baumgarte) 0183 { 0184 B2_NOT_USED(baumgarte); 0185 0186 return true; 0187 } 0188 0189 b2Vec2 b2FrictionJoint::GetAnchorA() const 0190 { 0191 return m_bodyA->GetWorldPoint(m_localAnchorA); 0192 } 0193 0194 b2Vec2 b2FrictionJoint::GetAnchorB() const 0195 { 0196 return m_bodyB->GetWorldPoint(m_localAnchorB); 0197 } 0198 0199 b2Vec2 b2FrictionJoint::GetReactionForce(qreal inv_dt) const 0200 { 0201 return inv_dt * m_linearImpulse; 0202 } 0203 0204 qreal b2FrictionJoint::GetReactionTorque(qreal inv_dt) const 0205 { 0206 return inv_dt * m_angularImpulse; 0207 } 0208 0209 void b2FrictionJoint::SetMaxForce(qreal force) 0210 { 0211 b2Assert(b2IsValid(force) && force >= 0.0f); 0212 m_maxForce = force; 0213 } 0214 0215 qreal b2FrictionJoint::GetMaxForce() const 0216 { 0217 return m_maxForce; 0218 } 0219 0220 void b2FrictionJoint::SetMaxTorque(qreal torque) 0221 { 0222 b2Assert(b2IsValid(torque) && torque >= 0.0f); 0223 m_maxTorque = torque; 0224 } 0225 0226 qreal b2FrictionJoint::GetMaxTorque() const 0227 { 0228 return m_maxTorque; 0229 }