b2MotorJoint.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /*
  2. * Copyright (c) 2006-2012 Erin Catto http://www.box2d.org
  3. *
  4. * This software is provided 'as-is', without any express or implied
  5. * warranty. In no event will the authors be held liable for any damages
  6. * arising from the use of this software.
  7. * Permission is granted to anyone to use this software for any purpose,
  8. * including commercial applications, and to alter it and redistribute it
  9. * freely, subject to the following restrictions:
  10. * 1. The origin of this software must not be misrepresented; you must not
  11. * claim that you wrote the original software. If you use this software
  12. * in a product, an acknowledgment in the product documentation would be
  13. * appreciated but is not required.
  14. * 2. Altered source versions must be plainly marked as such, and must not be
  15. * misrepresented as being the original software.
  16. * 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include <Box2D/Dynamics/Joints/b2MotorJoint.h>
  19. #include <Box2D/Dynamics/b2Body.h>
  20. #include <Box2D/Dynamics/b2TimeStep.h>
  21. // Point-to-point constraint
  22. // Cdot = v2 - v1
  23. // = v2 + cross(w2, r2) - v1 - cross(w1, r1)
  24. // J = [-I -r1_skew I r2_skew ]
  25. // Identity used:
  26. // w k % (rx i + ry j) = w * (-ry i + rx j)
  27. // Angle constraint
  28. // Cdot = w2 - w1
  29. // J = [0 0 -1 0 0 1]
  30. // K = invI1 + invI2
  31. void b2MotorJointDef::Initialize(b2Body* bA, b2Body* bB)
  32. {
  33. bodyA = bA;
  34. bodyB = bB;
  35. b2Vec2 xB = bodyB->GetPosition();
  36. linearOffset = bodyA->GetLocalPoint(xB);
  37. float32 angleA = bodyA->GetAngle();
  38. float32 angleB = bodyB->GetAngle();
  39. angularOffset = angleB - angleA;
  40. }
  41. b2MotorJoint::b2MotorJoint(const b2MotorJointDef* def)
  42. : b2Joint(def)
  43. {
  44. m_linearOffset = def->linearOffset;
  45. m_angularOffset = def->angularOffset;
  46. m_linearImpulse.SetZero();
  47. m_angularImpulse = 0.0f;
  48. m_maxForce = def->maxForce;
  49. m_maxTorque = def->maxTorque;
  50. m_correctionFactor = def->correctionFactor;
  51. }
  52. void b2MotorJoint::InitVelocityConstraints(const b2SolverData& data)
  53. {
  54. m_indexA = m_bodyA->m_islandIndex;
  55. m_indexB = m_bodyB->m_islandIndex;
  56. m_localCenterA = m_bodyA->m_sweep.localCenter;
  57. m_localCenterB = m_bodyB->m_sweep.localCenter;
  58. m_invMassA = m_bodyA->m_invMass;
  59. m_invMassB = m_bodyB->m_invMass;
  60. m_invIA = m_bodyA->m_invI;
  61. m_invIB = m_bodyB->m_invI;
  62. b2Vec2 cA = data.positions[m_indexA].c;
  63. float32 aA = data.positions[m_indexA].a;
  64. b2Vec2 vA = data.velocities[m_indexA].v;
  65. float32 wA = data.velocities[m_indexA].w;
  66. b2Vec2 cB = data.positions[m_indexB].c;
  67. float32 aB = data.positions[m_indexB].a;
  68. b2Vec2 vB = data.velocities[m_indexB].v;
  69. float32 wB = data.velocities[m_indexB].w;
  70. b2Rot qA(aA), qB(aB);
  71. // Compute the effective mass matrix.
  72. m_rA = b2Mul(qA, -m_localCenterA);
  73. m_rB = b2Mul(qB, -m_localCenterB);
  74. // J = [-I -r1_skew I r2_skew]
  75. // [ 0 -1 0 1]
  76. // r_skew = [-ry; rx]
  77. // Matlab
  78. // K = [ mA+r1y^2*iA+mB+r2y^2*iB, -r1y*iA*r1x-r2y*iB*r2x, -r1y*iA-r2y*iB]
  79. // [ -r1y*iA*r1x-r2y*iB*r2x, mA+r1x^2*iA+mB+r2x^2*iB, r1x*iA+r2x*iB]
  80. // [ -r1y*iA-r2y*iB, r1x*iA+r2x*iB, iA+iB]
  81. float32 mA = m_invMassA, mB = m_invMassB;
  82. float32 iA = m_invIA, iB = m_invIB;
  83. b2Mat22 K;
  84. K.ex.x = mA + mB + iA * m_rA.y * m_rA.y + iB * m_rB.y * m_rB.y;
  85. K.ex.y = -iA * m_rA.x * m_rA.y - iB * m_rB.x * m_rB.y;
  86. K.ey.x = K.ex.y;
  87. K.ey.y = mA + mB + iA * m_rA.x * m_rA.x + iB * m_rB.x * m_rB.x;
  88. m_linearMass = K.GetInverse();
  89. m_angularMass = iA + iB;
  90. if (m_angularMass > 0.0f)
  91. {
  92. m_angularMass = 1.0f / m_angularMass;
  93. }
  94. m_linearError = cB + m_rB - cA - m_rA - b2Mul(qA, m_linearOffset);
  95. m_angularError = aB - aA - m_angularOffset;
  96. if (data.step.warmStarting)
  97. {
  98. // Scale impulses to support a variable time step.
  99. m_linearImpulse *= data.step.dtRatio;
  100. m_angularImpulse *= data.step.dtRatio;
  101. b2Vec2 P(m_linearImpulse.x, m_linearImpulse.y);
  102. vA -= mA * P;
  103. wA -= iA * (b2Cross(m_rA, P) + m_angularImpulse);
  104. vB += mB * P;
  105. wB += iB * (b2Cross(m_rB, P) + m_angularImpulse);
  106. }
  107. else
  108. {
  109. m_linearImpulse.SetZero();
  110. m_angularImpulse = 0.0f;
  111. }
  112. data.velocities[m_indexA].v = vA;
  113. data.velocities[m_indexA].w = wA;
  114. data.velocities[m_indexB].v = vB;
  115. data.velocities[m_indexB].w = wB;
  116. }
  117. void b2MotorJoint::SolveVelocityConstraints(const b2SolverData& data)
  118. {
  119. b2Vec2 vA = data.velocities[m_indexA].v;
  120. float32 wA = data.velocities[m_indexA].w;
  121. b2Vec2 vB = data.velocities[m_indexB].v;
  122. float32 wB = data.velocities[m_indexB].w;
  123. float32 mA = m_invMassA, mB = m_invMassB;
  124. float32 iA = m_invIA, iB = m_invIB;
  125. float32 h = data.step.dt;
  126. float32 inv_h = data.step.inv_dt;
  127. // Solve angular friction
  128. {
  129. float32 Cdot = wB - wA + inv_h * m_correctionFactor * m_angularError;
  130. float32 impulse = -m_angularMass * Cdot;
  131. float32 oldImpulse = m_angularImpulse;
  132. float32 maxImpulse = h * m_maxTorque;
  133. m_angularImpulse = b2Clamp(m_angularImpulse + impulse, -maxImpulse, maxImpulse);
  134. impulse = m_angularImpulse - oldImpulse;
  135. wA -= iA * impulse;
  136. wB += iB * impulse;
  137. }
  138. // Solve linear friction
  139. {
  140. b2Vec2 Cdot = vB + b2Cross(wB, m_rB) - vA - b2Cross(wA, m_rA) + inv_h * m_correctionFactor * m_linearError;
  141. b2Vec2 impulse = -b2Mul(m_linearMass, Cdot);
  142. b2Vec2 oldImpulse = m_linearImpulse;
  143. m_linearImpulse += impulse;
  144. float32 maxImpulse = h * m_maxForce;
  145. if (m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse)
  146. {
  147. m_linearImpulse.Normalize();
  148. m_linearImpulse *= maxImpulse;
  149. }
  150. impulse = m_linearImpulse - oldImpulse;
  151. vA -= mA * impulse;
  152. wA -= iA * b2Cross(m_rA, impulse);
  153. vB += mB * impulse;
  154. wB += iB * b2Cross(m_rB, impulse);
  155. }
  156. data.velocities[m_indexA].v = vA;
  157. data.velocities[m_indexA].w = wA;
  158. data.velocities[m_indexB].v = vB;
  159. data.velocities[m_indexB].w = wB;
  160. }
  161. bool b2MotorJoint::SolvePositionConstraints(const b2SolverData& data)
  162. {
  163. B2_NOT_USED(data);
  164. return true;
  165. }
  166. b2Vec2 b2MotorJoint::GetAnchorA() const
  167. {
  168. return m_bodyA->GetPosition();
  169. }
  170. b2Vec2 b2MotorJoint::GetAnchorB() const
  171. {
  172. return m_bodyB->GetPosition();
  173. }
  174. b2Vec2 b2MotorJoint::GetReactionForce(float32 inv_dt) const
  175. {
  176. return inv_dt * m_linearImpulse;
  177. }
  178. float32 b2MotorJoint::GetReactionTorque(float32 inv_dt) const
  179. {
  180. return inv_dt * m_angularImpulse;
  181. }
  182. void b2MotorJoint::SetMaxForce(float32 force)
  183. {
  184. b2Assert(b2IsValid(force) && force >= 0.0f);
  185. m_maxForce = force;
  186. }
  187. float32 b2MotorJoint::GetMaxForce() const
  188. {
  189. return m_maxForce;
  190. }
  191. void b2MotorJoint::SetMaxTorque(float32 torque)
  192. {
  193. b2Assert(b2IsValid(torque) && torque >= 0.0f);
  194. m_maxTorque = torque;
  195. }
  196. float32 b2MotorJoint::GetMaxTorque() const
  197. {
  198. return m_maxTorque;
  199. }
  200. void b2MotorJoint::SetCorrectionFactor(float32 factor)
  201. {
  202. b2Assert(b2IsValid(factor) && 0.0f <= factor && factor <= 1.0f);
  203. m_correctionFactor = factor;
  204. }
  205. float32 b2MotorJoint::GetCorrectionFactor() const
  206. {
  207. return m_correctionFactor;
  208. }
  209. void b2MotorJoint::SetLinearOffset(const b2Vec2& linearOffset)
  210. {
  211. if (linearOffset.x != m_linearOffset.x || linearOffset.y != m_linearOffset.y)
  212. {
  213. m_bodyA->SetAwake(true);
  214. m_bodyB->SetAwake(true);
  215. m_linearOffset = linearOffset;
  216. }
  217. }
  218. const b2Vec2& b2MotorJoint::GetLinearOffset() const
  219. {
  220. return m_linearOffset;
  221. }
  222. void b2MotorJoint::SetAngularOffset(float32 angularOffset)
  223. {
  224. if (angularOffset != m_angularOffset)
  225. {
  226. m_bodyA->SetAwake(true);
  227. m_bodyB->SetAwake(true);
  228. m_angularOffset = angularOffset;
  229. }
  230. }
  231. float32 b2MotorJoint::GetAngularOffset() const
  232. {
  233. return m_angularOffset;
  234. }
  235. void b2MotorJoint::Dump()
  236. {
  237. int32 indexA = m_bodyA->m_islandIndex;
  238. int32 indexB = m_bodyB->m_islandIndex;
  239. b2Log(" b2MotorJointDef jd;\n");
  240. b2Log(" jd.bodyA = bodies[%d];\n", indexA);
  241. b2Log(" jd.bodyB = bodies[%d];\n", indexB);
  242. b2Log(" jd.collideConnected = bool(%d);\n", m_collideConnected);
  243. b2Log(" jd.linearOffset.Set(%.15lef, %.15lef);\n", m_linearOffset.x, m_linearOffset.y);
  244. b2Log(" jd.angularOffset = %.15lef;\n", m_angularOffset);
  245. b2Log(" jd.maxForce = %.15lef;\n", m_maxForce);
  246. b2Log(" jd.maxTorque = %.15lef;\n", m_maxTorque);
  247. b2Log(" jd.correctionFactor = %.15lef;\n", m_correctionFactor);
  248. b2Log(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
  249. }