b2PulleyJoint.cpp
上传用户:gb3593
上传日期:2022-01-07
资源大小:3028k
文件大小:11k
源码类别:

游戏引擎

开发平台:

Visual C++

  1. /*
  2. * Copyright (c) 2007 Erin Catto http://www.gphysics.com
  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/b2PulleyJoint.h>
  19. #include <Box2D/Dynamics/b2Body.h>
  20. #include <Box2D/Dynamics/b2TimeStep.h>
  21. // Pulley:
  22. // length1 = norm(p1 - s1)
  23. // length2 = norm(p2 - s2)
  24. // C0 = (length1 + ratio * length2)_initial
  25. // C = C0 - (length1 + ratio * length2) >= 0
  26. // u1 = (p1 - s1) / norm(p1 - s1)
  27. // u2 = (p2 - s2) / norm(p2 - s2)
  28. // Cdot = -dot(u1, v1 + cross(w1, r1)) - ratio * dot(u2, v2 + cross(w2, r2))
  29. // J = -[u1 cross(r1, u1) ratio * u2  ratio * cross(r2, u2)]
  30. // K = J * invM * JT
  31. //   = invMass1 + invI1 * cross(r1, u1)^2 + ratio^2 * (invMass2 + invI2 * cross(r2, u2)^2)
  32. //
  33. // Limit:
  34. // C = maxLength - length
  35. // u = (p - s) / norm(p - s)
  36. // Cdot = -dot(u, v + cross(w, r))
  37. // K = invMass + invI * cross(r, u)^2
  38. // 0 <= impulse
  39. void b2PulleyJointDef::Initialize(b2Body* b1, b2Body* b2,
  40. const b2Vec2& ga1, const b2Vec2& ga2,
  41. const b2Vec2& anchor1, const b2Vec2& anchor2,
  42. float32 r)
  43. {
  44. bodyA = b1;
  45. bodyB = b2;
  46. groundAnchorA = ga1;
  47. groundAnchorB = ga2;
  48. localAnchorA = bodyA->GetLocalPoint(anchor1);
  49. localAnchorB = bodyB->GetLocalPoint(anchor2);
  50. b2Vec2 d1 = anchor1 - ga1;
  51. lengthA = d1.Length();
  52. b2Vec2 d2 = anchor2 - ga2;
  53. lengthB = d2.Length();
  54. ratio = r;
  55. b2Assert(ratio > b2_epsilon);
  56. float32 C = lengthA + ratio * lengthB;
  57. maxLengthA = C - ratio * b2_minPulleyLength;
  58. maxLengthB = (C - b2_minPulleyLength) / ratio;
  59. }
  60. b2PulleyJoint::b2PulleyJoint(const b2PulleyJointDef* def)
  61. : b2Joint(def)
  62. {
  63. m_groundAnchor1 = def->groundAnchorA;
  64. m_groundAnchor2 = def->groundAnchorB;
  65. m_localAnchor1 = def->localAnchorA;
  66. m_localAnchor2 = def->localAnchorB;
  67. b2Assert(def->ratio != 0.0f);
  68. m_ratio = def->ratio;
  69. m_constant = def->lengthA + m_ratio * def->lengthB;
  70. m_maxLength1 = b2Min(def->maxLengthA, m_constant - m_ratio * b2_minPulleyLength);
  71. m_maxLength2 = b2Min(def->maxLengthB, (m_constant - b2_minPulleyLength) / m_ratio);
  72. m_impulse = 0.0f;
  73. m_limitImpulse1 = 0.0f;
  74. m_limitImpulse2 = 0.0f;
  75. }
  76. void b2PulleyJoint::InitVelocityConstraints(const b2TimeStep& step)
  77. {
  78. b2Body* b1 = m_bodyA;
  79. b2Body* b2 = m_bodyB;
  80. b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());
  81. b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());
  82. b2Vec2 p1 = b1->m_sweep.c + r1;
  83. b2Vec2 p2 = b2->m_sweep.c + r2;
  84. b2Vec2 s1 = m_groundAnchor1;
  85. b2Vec2 s2 = m_groundAnchor2;
  86. // Get the pulley axes.
  87. m_u1 = p1 - s1;
  88. m_u2 = p2 - s2;
  89. float32 length1 = m_u1.Length();
  90. float32 length2 = m_u2.Length();
  91. if (length1 > b2_linearSlop)
  92. {
  93. m_u1 *= 1.0f / length1;
  94. }
  95. else
  96. {
  97. m_u1.SetZero();
  98. }
  99. if (length2 > b2_linearSlop)
  100. {
  101. m_u2 *= 1.0f / length2;
  102. }
  103. else
  104. {
  105. m_u2.SetZero();
  106. }
  107. float32 C = m_constant - length1 - m_ratio * length2;
  108. if (C > 0.0f)
  109. {
  110. m_state = e_inactiveLimit;
  111. m_impulse = 0.0f;
  112. }
  113. else
  114. {
  115. m_state = e_atUpperLimit;
  116. }
  117. if (length1 < m_maxLength1)
  118. {
  119. m_limitState1 = e_inactiveLimit;
  120. m_limitImpulse1 = 0.0f;
  121. }
  122. else
  123. {
  124. m_limitState1 = e_atUpperLimit;
  125. }
  126. if (length2 < m_maxLength2)
  127. {
  128. m_limitState2 = e_inactiveLimit;
  129. m_limitImpulse2 = 0.0f;
  130. }
  131. else
  132. {
  133. m_limitState2 = e_atUpperLimit;
  134. }
  135. // Compute effective mass.
  136. float32 cr1u1 = b2Cross(r1, m_u1);
  137. float32 cr2u2 = b2Cross(r2, m_u2);
  138. m_limitMass1 = b1->m_invMass + b1->m_invI * cr1u1 * cr1u1;
  139. m_limitMass2 = b2->m_invMass + b2->m_invI * cr2u2 * cr2u2;
  140. m_pulleyMass = m_limitMass1 + m_ratio * m_ratio * m_limitMass2;
  141. b2Assert(m_limitMass1 > b2_epsilon);
  142. b2Assert(m_limitMass2 > b2_epsilon);
  143. b2Assert(m_pulleyMass > b2_epsilon);
  144. m_limitMass1 = 1.0f / m_limitMass1;
  145. m_limitMass2 = 1.0f / m_limitMass2;
  146. m_pulleyMass = 1.0f / m_pulleyMass;
  147. if (step.warmStarting)
  148. {
  149. // Scale impulses to support variable time steps.
  150. m_impulse *= step.dtRatio;
  151. m_limitImpulse1 *= step.dtRatio;
  152. m_limitImpulse2 *= step.dtRatio;
  153. // Warm starting.
  154. b2Vec2 P1 = -(m_impulse + m_limitImpulse1) * m_u1;
  155. b2Vec2 P2 = (-m_ratio * m_impulse - m_limitImpulse2) * m_u2;
  156. b1->m_linearVelocity += b1->m_invMass * P1;
  157. b1->m_angularVelocity += b1->m_invI * b2Cross(r1, P1);
  158. b2->m_linearVelocity += b2->m_invMass * P2;
  159. b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P2);
  160. }
  161. else
  162. {
  163. m_impulse = 0.0f;
  164. m_limitImpulse1 = 0.0f;
  165. m_limitImpulse2 = 0.0f;
  166. }
  167. }
  168. void b2PulleyJoint::SolveVelocityConstraints(const b2TimeStep& step)
  169. {
  170. B2_NOT_USED(step);
  171. b2Body* b1 = m_bodyA;
  172. b2Body* b2 = m_bodyB;
  173. b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());
  174. b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());
  175. if (m_state == e_atUpperLimit)
  176. {
  177. b2Vec2 v1 = b1->m_linearVelocity + b2Cross(b1->m_angularVelocity, r1);
  178. b2Vec2 v2 = b2->m_linearVelocity + b2Cross(b2->m_angularVelocity, r2);
  179. float32 Cdot = -b2Dot(m_u1, v1) - m_ratio * b2Dot(m_u2, v2);
  180. float32 impulse = m_pulleyMass * (-Cdot);
  181. float32 oldImpulse = m_impulse;
  182. m_impulse = b2Max(0.0f, m_impulse + impulse);
  183. impulse = m_impulse - oldImpulse;
  184. b2Vec2 P1 = -impulse * m_u1;
  185. b2Vec2 P2 = -m_ratio * impulse * m_u2;
  186. b1->m_linearVelocity += b1->m_invMass * P1;
  187. b1->m_angularVelocity += b1->m_invI * b2Cross(r1, P1);
  188. b2->m_linearVelocity += b2->m_invMass * P2;
  189. b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P2);
  190. }
  191. if (m_limitState1 == e_atUpperLimit)
  192. {
  193. b2Vec2 v1 = b1->m_linearVelocity + b2Cross(b1->m_angularVelocity, r1);
  194. float32 Cdot = -b2Dot(m_u1, v1);
  195. float32 impulse = -m_limitMass1 * Cdot;
  196. float32 oldImpulse = m_limitImpulse1;
  197. m_limitImpulse1 = b2Max(0.0f, m_limitImpulse1 + impulse);
  198. impulse = m_limitImpulse1 - oldImpulse;
  199. b2Vec2 P1 = -impulse * m_u1;
  200. b1->m_linearVelocity += b1->m_invMass * P1;
  201. b1->m_angularVelocity += b1->m_invI * b2Cross(r1, P1);
  202. }
  203. if (m_limitState2 == e_atUpperLimit)
  204. {
  205. b2Vec2 v2 = b2->m_linearVelocity + b2Cross(b2->m_angularVelocity, r2);
  206. float32 Cdot = -b2Dot(m_u2, v2);
  207. float32 impulse = -m_limitMass2 * Cdot;
  208. float32 oldImpulse = m_limitImpulse2;
  209. m_limitImpulse2 = b2Max(0.0f, m_limitImpulse2 + impulse);
  210. impulse = m_limitImpulse2 - oldImpulse;
  211. b2Vec2 P2 = -impulse * m_u2;
  212. b2->m_linearVelocity += b2->m_invMass * P2;
  213. b2->m_angularVelocity += b2->m_invI * b2Cross(r2, P2);
  214. }
  215. }
  216. bool b2PulleyJoint::SolvePositionConstraints(float32 baumgarte)
  217. {
  218. B2_NOT_USED(baumgarte);
  219. b2Body* b1 = m_bodyA;
  220. b2Body* b2 = m_bodyB;
  221. b2Vec2 s1 = m_groundAnchor1;
  222. b2Vec2 s2 = m_groundAnchor2;
  223. float32 linearError = 0.0f;
  224. if (m_state == e_atUpperLimit)
  225. {
  226. b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());
  227. b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());
  228. b2Vec2 p1 = b1->m_sweep.c + r1;
  229. b2Vec2 p2 = b2->m_sweep.c + r2;
  230. // Get the pulley axes.
  231. m_u1 = p1 - s1;
  232. m_u2 = p2 - s2;
  233. float32 length1 = m_u1.Length();
  234. float32 length2 = m_u2.Length();
  235. if (length1 > b2_linearSlop)
  236. {
  237. m_u1 *= 1.0f / length1;
  238. }
  239. else
  240. {
  241. m_u1.SetZero();
  242. }
  243. if (length2 > b2_linearSlop)
  244. {
  245. m_u2 *= 1.0f / length2;
  246. }
  247. else
  248. {
  249. m_u2.SetZero();
  250. }
  251. float32 C = m_constant - length1 - m_ratio * length2;
  252. linearError = b2Max(linearError, -C);
  253. C = b2Clamp(C + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);
  254. float32 impulse = -m_pulleyMass * C;
  255. b2Vec2 P1 = -impulse * m_u1;
  256. b2Vec2 P2 = -m_ratio * impulse * m_u2;
  257. b1->m_sweep.c += b1->m_invMass * P1;
  258. b1->m_sweep.a += b1->m_invI * b2Cross(r1, P1);
  259. b2->m_sweep.c += b2->m_invMass * P2;
  260. b2->m_sweep.a += b2->m_invI * b2Cross(r2, P2);
  261. b1->SynchronizeTransform();
  262. b2->SynchronizeTransform();
  263. }
  264. if (m_limitState1 == e_atUpperLimit)
  265. {
  266. b2Vec2 r1 = b2Mul(b1->GetTransform().R, m_localAnchor1 - b1->GetLocalCenter());
  267. b2Vec2 p1 = b1->m_sweep.c + r1;
  268. m_u1 = p1 - s1;
  269. float32 length1 = m_u1.Length();
  270. if (length1 > b2_linearSlop)
  271. {
  272. m_u1 *= 1.0f / length1;
  273. }
  274. else
  275. {
  276. m_u1.SetZero();
  277. }
  278. float32 C = m_maxLength1 - length1;
  279. linearError = b2Max(linearError, -C);
  280. C = b2Clamp(C + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);
  281. float32 impulse = -m_limitMass1 * C;
  282. b2Vec2 P1 = -impulse * m_u1;
  283. b1->m_sweep.c += b1->m_invMass * P1;
  284. b1->m_sweep.a += b1->m_invI * b2Cross(r1, P1);
  285. b1->SynchronizeTransform();
  286. }
  287. if (m_limitState2 == e_atUpperLimit)
  288. {
  289. b2Vec2 r2 = b2Mul(b2->GetTransform().R, m_localAnchor2 - b2->GetLocalCenter());
  290. b2Vec2 p2 = b2->m_sweep.c + r2;
  291. m_u2 = p2 - s2;
  292. float32 length2 = m_u2.Length();
  293. if (length2 > b2_linearSlop)
  294. {
  295. m_u2 *= 1.0f / length2;
  296. }
  297. else
  298. {
  299. m_u2.SetZero();
  300. }
  301. float32 C = m_maxLength2 - length2;
  302. linearError = b2Max(linearError, -C);
  303. C = b2Clamp(C + b2_linearSlop, -b2_maxLinearCorrection, 0.0f);
  304. float32 impulse = -m_limitMass2 * C;
  305. b2Vec2 P2 = -impulse * m_u2;
  306. b2->m_sweep.c += b2->m_invMass * P2;
  307. b2->m_sweep.a += b2->m_invI * b2Cross(r2, P2);
  308. b2->SynchronizeTransform();
  309. }
  310. return linearError < b2_linearSlop;
  311. }
  312. b2Vec2 b2PulleyJoint::GetAnchorA() const
  313. {
  314. return m_bodyA->GetWorldPoint(m_localAnchor1);
  315. }
  316. b2Vec2 b2PulleyJoint::GetAnchorB() const
  317. {
  318. return m_bodyB->GetWorldPoint(m_localAnchor2);
  319. }
  320. b2Vec2 b2PulleyJoint::GetReactionForce(float32 inv_dt) const
  321. {
  322. b2Vec2 P = m_impulse * m_u2;
  323. return inv_dt * P;
  324. }
  325. float32 b2PulleyJoint::GetReactionTorque(float32 inv_dt) const
  326. {
  327. B2_NOT_USED(inv_dt);
  328. return 0.0f;
  329. }
  330. b2Vec2 b2PulleyJoint::GetGroundAnchorA() const
  331. {
  332. return m_groundAnchor1;
  333. }
  334. b2Vec2 b2PulleyJoint::GetGroundAnchorB() const
  335. {
  336. return m_groundAnchor2;
  337. }
  338. float32 b2PulleyJoint::GetLength1() const
  339. {
  340. b2Vec2 p = m_bodyA->GetWorldPoint(m_localAnchor1);
  341. b2Vec2 s = m_groundAnchor1;
  342. b2Vec2 d = p - s;
  343. return d.Length();
  344. }
  345. float32 b2PulleyJoint::GetLength2() const
  346. {
  347. b2Vec2 p = m_bodyB->GetWorldPoint(m_localAnchor2);
  348. b2Vec2 s = m_groundAnchor2;
  349. b2Vec2 d = p - s;
  350. return d.Length();
  351. }
  352. float32 b2PulleyJoint::GetRatio() const
  353. {
  354. return m_ratio;
  355. }