File indexing completed on 2025-08-03 03:49:58
0001 /* 0002 * Copyright (c) 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/b2GearJoint.h> 0020 #include <Box2D/Dynamics/Joints/b2RevoluteJoint.h> 0021 #include <Box2D/Dynamics/Joints/b2PrismaticJoint.h> 0022 #include <Box2D/Dynamics/b2Body.h> 0023 #include <Box2D/Dynamics/b2TimeStep.h> 0024 0025 // Gear Joint: 0026 // C0 = (coordinate1 + ratio * coordinate2)_initial 0027 // C = C0 - (cordinate1 + ratio * coordinate2) = 0 0028 // Cdot = -(Cdot1 + ratio * Cdot2) 0029 // J = -[J1 ratio * J2] 0030 // K = J * invM * JT 0031 // = J1 * invM1 * J1T + ratio * ratio * J2 * invM2 * J2T 0032 // 0033 // Revolute: 0034 // coordinate = rotation 0035 // Cdot = angularVelocity 0036 // J = [0 0 1] 0037 // K = J * invM * JT = invI 0038 // 0039 // Prismatic: 0040 // coordinate = dot(p - pg, ug) 0041 // Cdot = dot(v + cross(w, r), ug) 0042 // J = [ug cross(r, ug)] 0043 // K = J * invM * JT = invMass + invI * cross(r, ug)^2 0044 0045 b2GearJoint::b2GearJoint(const b2GearJointDef* def) 0046 : b2Joint(def) 0047 { 0048 b2JointType type1 = def->joint1->GetType(); 0049 b2JointType type2 = def->joint2->GetType(); 0050 0051 b2Assert(type1 == e_revoluteJoint || type1 == e_prismaticJoint); 0052 b2Assert(type2 == e_revoluteJoint || type2 == e_prismaticJoint); 0053 b2Assert(def->joint1->GetBodyA()->GetType() == b2_staticBody); 0054 b2Assert(def->joint2->GetBodyA()->GetType() == b2_staticBody); 0055 0056 m_revolute1 = NULL; 0057 m_prismatic1 = NULL; 0058 m_revolute2 = NULL; 0059 m_prismatic2 = NULL; 0060 0061 qreal coordinate1, coordinate2; 0062 0063 m_ground1 = def->joint1->GetBodyA(); 0064 m_bodyA = def->joint1->GetBodyB(); 0065 if (type1 == e_revoluteJoint) 0066 { 0067 m_revolute1 = (b2RevoluteJoint*)def->joint1; 0068 m_groundAnchor1 = m_revolute1->m_localAnchor1; 0069 m_localAnchor1 = m_revolute1->m_localAnchor2; 0070 coordinate1 = m_revolute1->GetJointAngle(); 0071 } 0072 else 0073 { 0074 m_prismatic1 = (b2PrismaticJoint*)def->joint1; 0075 m_groundAnchor1 = m_prismatic1->m_localAnchor1; 0076 m_localAnchor1 = m_prismatic1->m_localAnchor2; 0077 coordinate1 = m_prismatic1->GetJointTranslation(); 0078 } 0079 0080 m_ground2 = def->joint2->GetBodyA(); 0081 m_bodyB = def->joint2->GetBodyB(); 0082 if (type2 == e_revoluteJoint) 0083 { 0084 m_revolute2 = (b2RevoluteJoint*)def->joint2; 0085 m_groundAnchor2 = m_revolute2->m_localAnchor1; 0086 m_localAnchor2 = m_revolute2->m_localAnchor2; 0087 coordinate2 = m_revolute2->GetJointAngle(); 0088 } 0089 else 0090 { 0091 m_prismatic2 = (b2PrismaticJoint*)def->joint2; 0092 m_groundAnchor2 = m_prismatic2->m_localAnchor1; 0093 m_localAnchor2 = m_prismatic2->m_localAnchor2; 0094 coordinate2 = m_prismatic2->GetJointTranslation(); 0095 } 0096 0097 m_ratio = def->ratio; 0098 0099 m_constant = coordinate1 + m_ratio * coordinate2; 0100 0101 m_impulse = 0.0f; 0102 } 0103 0104 void b2GearJoint::InitVelocityConstraints(const b2TimeStep& step) 0105 { 0106 b2Body* g1 = m_ground1; 0107 b2Body* g2 = m_ground2; 0108 b2Body* b1 = m_bodyA; 0109 b2Body* b2 = m_bodyB; 0110 0111 qreal K = 0.0f; 0112 m_J.SetZero(); 0113 0114 if (m_revolute1) 0115 { 0116 m_J.angularA = -1.0f; 0117 K += b1->m_invI; 0118 } 0119 else 0120 { 0121 b2Vec2 ug = b2Mul(g1->GetTransform().R, m_prismatic1->m_localXAxis1); 0122 b2Vec2 r = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter()); 0123 qreal crug = b2Cross(r, ug); 0124 m_J.linearA = -ug; 0125 m_J.angularA = -crug; 0126 K += b1->m_invMass + b1->m_invI * crug * crug; 0127 } 0128 0129 if (m_revolute2) 0130 { 0131 m_J.angularB = -m_ratio; 0132 K += m_ratio * m_ratio * b2->m_invI; 0133 } 0134 else 0135 { 0136 b2Vec2 ug = b2Mul(g2->GetTransform().R, m_prismatic2->m_localXAxis1); 0137 b2Vec2 r = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter()); 0138 qreal crug = b2Cross(r, ug); 0139 m_J.linearB = -m_ratio * ug; 0140 m_J.angularB = -m_ratio * crug; 0141 K += m_ratio * m_ratio * (b2->m_invMass + b2->m_invI * crug * crug); 0142 } 0143 0144 // Compute effective mass. 0145 m_mass = K > 0.0f ? 1.0f / K : 0.0f; 0146 0147 if (step.warmStarting) 0148 { 0149 // Warm starting. 0150 b1->m_linearVelocity += b1->m_invMass * m_impulse * m_J.linearA; 0151 b1->m_angularVelocity += b1->m_invI * m_impulse * m_J.angularA; 0152 b2->m_linearVelocity += b2->m_invMass * m_impulse * m_J.linearB; 0153 b2->m_angularVelocity += b2->m_invI * m_impulse * m_J.angularB; 0154 } 0155 else 0156 { 0157 m_impulse = 0.0f; 0158 } 0159 } 0160 0161 void b2GearJoint::SolveVelocityConstraints(const b2TimeStep& step) 0162 { 0163 B2_NOT_USED(step); 0164 0165 b2Body* b1 = m_bodyA; 0166 b2Body* b2 = m_bodyB; 0167 0168 qreal Cdot = m_J.Compute( b1->m_linearVelocity, b1->m_angularVelocity, 0169 b2->m_linearVelocity, b2->m_angularVelocity); 0170 0171 qreal impulse = m_mass * (-Cdot); 0172 m_impulse += impulse; 0173 0174 b1->m_linearVelocity += b1->m_invMass * impulse * m_J.linearA; 0175 b1->m_angularVelocity += b1->m_invI * impulse * m_J.angularA; 0176 b2->m_linearVelocity += b2->m_invMass * impulse * m_J.linearB; 0177 b2->m_angularVelocity += b2->m_invI * impulse * m_J.angularB; 0178 } 0179 0180 bool b2GearJoint::SolvePositionConstraints(qreal baumgarte) 0181 { 0182 B2_NOT_USED(baumgarte); 0183 0184 qreal linearError = 0.0f; 0185 0186 b2Body* b1 = m_bodyA; 0187 b2Body* b2 = m_bodyB; 0188 0189 qreal coordinate1, coordinate2; 0190 if (m_revolute1) 0191 { 0192 coordinate1 = m_revolute1->GetJointAngle(); 0193 } 0194 else 0195 { 0196 coordinate1 = m_prismatic1->GetJointTranslation(); 0197 } 0198 0199 if (m_revolute2) 0200 { 0201 coordinate2 = m_revolute2->GetJointAngle(); 0202 } 0203 else 0204 { 0205 coordinate2 = m_prismatic2->GetJointTranslation(); 0206 } 0207 0208 qreal C = m_constant - (coordinate1 + m_ratio * coordinate2); 0209 0210 qreal impulse = m_mass * (-C); 0211 0212 b1->m_sweep.c += b1->m_invMass * impulse * m_J.linearA; 0213 b1->m_sweep.a += b1->m_invI * impulse * m_J.angularA; 0214 b2->m_sweep.c += b2->m_invMass * impulse * m_J.linearB; 0215 b2->m_sweep.a += b2->m_invI * impulse * m_J.angularB; 0216 0217 b1->SynchronizeTransform(); 0218 b2->SynchronizeTransform(); 0219 0220 // TODO_ERIN not implemented 0221 return linearError < b2_linearSlop; 0222 } 0223 0224 b2Vec2 b2GearJoint::GetAnchorA() const 0225 { 0226 return m_bodyA->GetWorldPoint(m_localAnchor1); 0227 } 0228 0229 b2Vec2 b2GearJoint::GetAnchorB() const 0230 { 0231 return m_bodyB->GetWorldPoint(m_localAnchor2); 0232 } 0233 0234 b2Vec2 b2GearJoint::GetReactionForce(qreal inv_dt) const 0235 { 0236 // TODO_ERIN not tested 0237 b2Vec2 P = m_impulse * m_J.linearB; 0238 return inv_dt * P; 0239 } 0240 0241 qreal b2GearJoint::GetReactionTorque(qreal inv_dt) const 0242 { 0243 // TODO_ERIN not tested 0244 b2Vec2 r = b2Mul(m_bodyB->GetTransform().R, m_localAnchor2 - m_bodyB->GetLocalCenter()); 0245 b2Vec2 P = m_impulse * m_J.linearB; 0246 qreal L = m_impulse * m_J.angularB - b2Cross(r, P); 0247 return inv_dt * L; 0248 } 0249 0250 void b2GearJoint::SetRatio(qreal ratio) 0251 { 0252 b2Assert(b2IsValid(ratio)); 0253 m_ratio = ratio; 0254 } 0255 0256 qreal b2GearJoint::GetRatio() const 0257 { 0258 return m_ratio; 0259 }