b2_distance_joint.cpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421
  1. // MIT License
  2. // Copyright (c) 2019 Erin Catto
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. // in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. // copies of the Software, and to permit persons to whom the Software is
  8. // furnished to do so, subject to the following conditions:
  9. // The above copyright notice and this permission notice shall be included in all
  10. // copies or substantial portions of the Software.
  11. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  12. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  13. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  14. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  15. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  16. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  17. // SOFTWARE.
  18. #include "box2d/b2_body.h"
  19. #include "box2d/b2_draw.h"
  20. #include "box2d/b2_distance_joint.h"
  21. #include "box2d/b2_time_step.h"
  22. // 1-D constrained system
  23. // m (v2 - v1) = lambda
  24. // v2 + (beta/h) * x1 + gamma * lambda = 0, gamma has units of inverse mass.
  25. // x2 = x1 + h * v2
  26. // 1-D mass-damper-spring system
  27. // m (v2 - v1) + h * d * v2 + h * k *
  28. // C = norm(p2 - p1) - L
  29. // u = (p2 - p1) / norm(p2 - p1)
  30. // Cdot = dot(u, v2 + cross(w2, r2) - v1 - cross(w1, r1))
  31. // J = [-u -cross(r1, u) u cross(r2, u)]
  32. // K = J * invM * JT
  33. // = invMass1 + invI1 * cross(r1, u)^2 + invMass2 + invI2 * cross(r2, u)^2
  34. void b2DistanceJointDef::Initialize(b2Body* b1, b2Body* b2,
  35. const b2Vec2& anchor1, const b2Vec2& anchor2)
  36. {
  37. bodyA = b1;
  38. bodyB = b2;
  39. localAnchorA = bodyA->GetLocalPoint(anchor1);
  40. localAnchorB = bodyB->GetLocalPoint(anchor2);
  41. b2Vec2 d = anchor2 - anchor1;
  42. length = b2Max(d.Length(), b2_linearSlop);
  43. minLength = length;
  44. maxLength = length;
  45. }
  46. b2DistanceJoint::b2DistanceJoint(const b2DistanceJointDef* def)
  47. : b2Joint(def)
  48. {
  49. m_localAnchorA = def->localAnchorA;
  50. m_localAnchorB = def->localAnchorB;
  51. m_length = b2Max(def->length, b2_linearSlop);
  52. m_minLength = b2Max(def->minLength, b2_linearSlop);
  53. m_maxLength = b2Max(def->maxLength, m_minLength);
  54. m_stiffness = def->stiffness;
  55. m_damping = def->damping;
  56. m_gamma = 0.0f;
  57. m_bias = 0.0f;
  58. m_impulse = 0.0f;
  59. m_lowerImpulse = 0.0f;
  60. m_upperImpulse = 0.0f;
  61. m_currentLength = 0.0f;
  62. }
  63. void b2DistanceJoint::InitVelocityConstraints(const b2SolverData& data)
  64. {
  65. m_indexA = m_bodyA->m_islandIndex;
  66. m_indexB = m_bodyB->m_islandIndex;
  67. m_localCenterA = m_bodyA->m_sweep.localCenter;
  68. m_localCenterB = m_bodyB->m_sweep.localCenter;
  69. m_invMassA = m_bodyA->m_invMass;
  70. m_invMassB = m_bodyB->m_invMass;
  71. m_invIA = m_bodyA->m_invI;
  72. m_invIB = m_bodyB->m_invI;
  73. b2Vec2 cA = data.positions[m_indexA].c;
  74. float aA = data.positions[m_indexA].a;
  75. b2Vec2 vA = data.velocities[m_indexA].v;
  76. float wA = data.velocities[m_indexA].w;
  77. b2Vec2 cB = data.positions[m_indexB].c;
  78. float aB = data.positions[m_indexB].a;
  79. b2Vec2 vB = data.velocities[m_indexB].v;
  80. float wB = data.velocities[m_indexB].w;
  81. b2Rot qA(aA), qB(aB);
  82. m_rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
  83. m_rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
  84. m_u = cB + m_rB - cA - m_rA;
  85. // Handle singularity.
  86. m_currentLength = m_u.Length();
  87. if (m_currentLength > b2_linearSlop)
  88. {
  89. m_u *= 1.0f / m_currentLength;
  90. }
  91. else
  92. {
  93. m_u.Set(0.0f, 0.0f);
  94. m_mass = 0.0f;
  95. m_impulse = 0.0f;
  96. m_lowerImpulse = 0.0f;
  97. m_upperImpulse = 0.0f;
  98. }
  99. float crAu = b2Cross(m_rA, m_u);
  100. float crBu = b2Cross(m_rB, m_u);
  101. float invMass = m_invMassA + m_invIA * crAu * crAu + m_invMassB + m_invIB * crBu * crBu;
  102. m_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;
  103. if (m_stiffness > 0.0f && m_minLength < m_maxLength)
  104. {
  105. // soft
  106. float C = m_currentLength - m_length;
  107. float d = m_damping;
  108. float k = m_stiffness;
  109. // magic formulas
  110. float h = data.step.dt;
  111. // gamma = 1 / (h * (d + h * k))
  112. // the extra factor of h in the denominator is since the lambda is an impulse, not a force
  113. m_gamma = h * (d + h * k);
  114. m_gamma = m_gamma != 0.0f ? 1.0f / m_gamma : 0.0f;
  115. m_bias = C * h * k * m_gamma;
  116. invMass += m_gamma;
  117. m_softMass = invMass != 0.0f ? 1.0f / invMass : 0.0f;
  118. }
  119. else
  120. {
  121. // rigid
  122. m_gamma = 0.0f;
  123. m_bias = 0.0f;
  124. m_softMass = m_mass;
  125. }
  126. if (data.step.warmStarting)
  127. {
  128. // Scale the impulse to support a variable time step.
  129. m_impulse *= data.step.dtRatio;
  130. m_lowerImpulse *= data.step.dtRatio;
  131. m_upperImpulse *= data.step.dtRatio;
  132. b2Vec2 P = (m_impulse + m_lowerImpulse - m_upperImpulse) * m_u;
  133. vA -= m_invMassA * P;
  134. wA -= m_invIA * b2Cross(m_rA, P);
  135. vB += m_invMassB * P;
  136. wB += m_invIB * b2Cross(m_rB, P);
  137. }
  138. else
  139. {
  140. m_impulse = 0.0f;
  141. }
  142. data.velocities[m_indexA].v = vA;
  143. data.velocities[m_indexA].w = wA;
  144. data.velocities[m_indexB].v = vB;
  145. data.velocities[m_indexB].w = wB;
  146. }
  147. void b2DistanceJoint::SolveVelocityConstraints(const b2SolverData& data)
  148. {
  149. b2Vec2 vA = data.velocities[m_indexA].v;
  150. float wA = data.velocities[m_indexA].w;
  151. b2Vec2 vB = data.velocities[m_indexB].v;
  152. float wB = data.velocities[m_indexB].w;
  153. if (m_minLength < m_maxLength)
  154. {
  155. if (m_stiffness > 0.0f)
  156. {
  157. // Cdot = dot(u, v + cross(w, r))
  158. b2Vec2 vpA = vA + b2Cross(wA, m_rA);
  159. b2Vec2 vpB = vB + b2Cross(wB, m_rB);
  160. float Cdot = b2Dot(m_u, vpB - vpA);
  161. float impulse = -m_softMass * (Cdot + m_bias + m_gamma * m_impulse);
  162. m_impulse += impulse;
  163. b2Vec2 P = impulse * m_u;
  164. vA -= m_invMassA * P;
  165. wA -= m_invIA * b2Cross(m_rA, P);
  166. vB += m_invMassB * P;
  167. wB += m_invIB * b2Cross(m_rB, P);
  168. }
  169. // lower
  170. {
  171. float C = m_currentLength - m_minLength;
  172. float bias = b2Max(0.0f, C) * data.step.inv_dt;
  173. b2Vec2 vpA = vA + b2Cross(wA, m_rA);
  174. b2Vec2 vpB = vB + b2Cross(wB, m_rB);
  175. float Cdot = b2Dot(m_u, vpB - vpA);
  176. float impulse = -m_mass * (Cdot + bias);
  177. float oldImpulse = m_lowerImpulse;
  178. m_lowerImpulse = b2Max(0.0f, m_lowerImpulse + impulse);
  179. impulse = m_lowerImpulse - oldImpulse;
  180. b2Vec2 P = impulse * m_u;
  181. vA -= m_invMassA * P;
  182. wA -= m_invIA * b2Cross(m_rA, P);
  183. vB += m_invMassB * P;
  184. wB += m_invIB * b2Cross(m_rB, P);
  185. }
  186. // upper
  187. {
  188. float C = m_maxLength - m_currentLength;
  189. float bias = b2Max(0.0f, C) * data.step.inv_dt;
  190. b2Vec2 vpA = vA + b2Cross(wA, m_rA);
  191. b2Vec2 vpB = vB + b2Cross(wB, m_rB);
  192. float Cdot = b2Dot(m_u, vpA - vpB);
  193. float impulse = -m_mass * (Cdot + bias);
  194. float oldImpulse = m_upperImpulse;
  195. m_upperImpulse = b2Max(0.0f, m_upperImpulse + impulse);
  196. impulse = m_upperImpulse - oldImpulse;
  197. b2Vec2 P = -impulse * m_u;
  198. vA -= m_invMassA * P;
  199. wA -= m_invIA * b2Cross(m_rA, P);
  200. vB += m_invMassB * P;
  201. wB += m_invIB * b2Cross(m_rB, P);
  202. }
  203. }
  204. else
  205. {
  206. // Equal limits
  207. // Cdot = dot(u, v + cross(w, r))
  208. b2Vec2 vpA = vA + b2Cross(wA, m_rA);
  209. b2Vec2 vpB = vB + b2Cross(wB, m_rB);
  210. float Cdot = b2Dot(m_u, vpB - vpA);
  211. float impulse = -m_mass * Cdot;
  212. m_impulse += impulse;
  213. b2Vec2 P = impulse * m_u;
  214. vA -= m_invMassA * P;
  215. wA -= m_invIA * b2Cross(m_rA, P);
  216. vB += m_invMassB * P;
  217. wB += m_invIB * b2Cross(m_rB, P);
  218. }
  219. data.velocities[m_indexA].v = vA;
  220. data.velocities[m_indexA].w = wA;
  221. data.velocities[m_indexB].v = vB;
  222. data.velocities[m_indexB].w = wB;
  223. }
  224. bool b2DistanceJoint::SolvePositionConstraints(const b2SolverData& data)
  225. {
  226. b2Vec2 cA = data.positions[m_indexA].c;
  227. float aA = data.positions[m_indexA].a;
  228. b2Vec2 cB = data.positions[m_indexB].c;
  229. float aB = data.positions[m_indexB].a;
  230. b2Rot qA(aA), qB(aB);
  231. b2Vec2 rA = b2Mul(qA, m_localAnchorA - m_localCenterA);
  232. b2Vec2 rB = b2Mul(qB, m_localAnchorB - m_localCenterB);
  233. b2Vec2 u = cB + rB - cA - rA;
  234. float length = u.Normalize();
  235. float C;
  236. if (m_minLength == m_maxLength)
  237. {
  238. C = length - m_minLength;
  239. }
  240. else if (length < m_minLength)
  241. {
  242. C = length - m_minLength;
  243. }
  244. else if (m_maxLength < length)
  245. {
  246. C = length - m_maxLength;
  247. }
  248. else
  249. {
  250. return true;
  251. }
  252. float impulse = -m_mass * C;
  253. b2Vec2 P = impulse * u;
  254. cA -= m_invMassA * P;
  255. aA -= m_invIA * b2Cross(rA, P);
  256. cB += m_invMassB * P;
  257. aB += m_invIB * b2Cross(rB, P);
  258. data.positions[m_indexA].c = cA;
  259. data.positions[m_indexA].a = aA;
  260. data.positions[m_indexB].c = cB;
  261. data.positions[m_indexB].a = aB;
  262. return b2Abs(C) < b2_linearSlop;
  263. }
  264. b2Vec2 b2DistanceJoint::GetAnchorA() const
  265. {
  266. return m_bodyA->GetWorldPoint(m_localAnchorA);
  267. }
  268. b2Vec2 b2DistanceJoint::GetAnchorB() const
  269. {
  270. return m_bodyB->GetWorldPoint(m_localAnchorB);
  271. }
  272. b2Vec2 b2DistanceJoint::GetReactionForce(float inv_dt) const
  273. {
  274. b2Vec2 F = inv_dt * (m_impulse + m_lowerImpulse - m_upperImpulse) * m_u;
  275. return F;
  276. }
  277. float b2DistanceJoint::GetReactionTorque(float inv_dt) const
  278. {
  279. B2_NOT_USED(inv_dt);
  280. return 0.0f;
  281. }
  282. float b2DistanceJoint::SetLength(float length)
  283. {
  284. m_impulse = 0.0f;
  285. m_length = b2Max(b2_linearSlop, length);
  286. return m_length;
  287. }
  288. float b2DistanceJoint::SetMinLength(float minLength)
  289. {
  290. m_lowerImpulse = 0.0f;
  291. m_minLength = b2Clamp(minLength, b2_linearSlop, m_maxLength);
  292. return m_minLength;
  293. }
  294. float b2DistanceJoint::SetMaxLength(float maxLength)
  295. {
  296. m_upperImpulse = 0.0f;
  297. m_maxLength = b2Max(maxLength, m_minLength);
  298. return m_maxLength;
  299. }
  300. float b2DistanceJoint::GetCurrentLength() const
  301. {
  302. b2Vec2 pA = m_bodyA->GetWorldPoint(m_localAnchorA);
  303. b2Vec2 pB = m_bodyB->GetWorldPoint(m_localAnchorB);
  304. b2Vec2 d = pB - pA;
  305. float length = d.Length();
  306. return length;
  307. }
  308. void b2DistanceJoint::Dump()
  309. {
  310. int32 indexA = m_bodyA->m_islandIndex;
  311. int32 indexB = m_bodyB->m_islandIndex;
  312. b2Dump(" b2DistanceJointDef jd;\n");
  313. b2Dump(" jd.bodyA = bodies[%d];\n", indexA);
  314. b2Dump(" jd.bodyB = bodies[%d];\n", indexB);
  315. b2Dump(" jd.collideConnected = bool(%d);\n", m_collideConnected);
  316. b2Dump(" jd.localAnchorA.Set(%.9g, %.9g);\n", m_localAnchorA.x, m_localAnchorA.y);
  317. b2Dump(" jd.localAnchorB.Set(%.9g, %.9g);\n", m_localAnchorB.x, m_localAnchorB.y);
  318. b2Dump(" jd.length = %.9g;\n", m_length);
  319. b2Dump(" jd.minLength = %.9g;\n", m_minLength);
  320. b2Dump(" jd.maxLength = %.9g;\n", m_maxLength);
  321. b2Dump(" jd.stiffness = %.9g;\n", m_stiffness);
  322. b2Dump(" jd.damping = %.9g;\n", m_damping);
  323. b2Dump(" joints[%d] = m_world->CreateJoint(&jd);\n", m_index);
  324. }
  325. void b2DistanceJoint::Draw(b2Draw* draw) const
  326. {
  327. const b2Transform& xfA = m_bodyA->GetTransform();
  328. const b2Transform& xfB = m_bodyB->GetTransform();
  329. b2Vec2 pA = b2Mul(xfA, m_localAnchorA);
  330. b2Vec2 pB = b2Mul(xfB, m_localAnchorB);
  331. b2Vec2 axis = pB - pA;
  332. axis.Normalize();
  333. b2Color c1(0.7f, 0.7f, 0.7f);
  334. b2Color c2(0.3f, 0.9f, 0.3f);
  335. b2Color c3(0.9f, 0.3f, 0.3f);
  336. b2Color c4(0.4f, 0.4f, 0.4f);
  337. draw->DrawSegment(pA, pB, c4);
  338. b2Vec2 pRest = pA + m_length * axis;
  339. draw->DrawPoint(pRest, 8.0f, c1);
  340. if (m_minLength != m_maxLength)
  341. {
  342. if (m_minLength > b2_linearSlop)
  343. {
  344. b2Vec2 pMin = pA + m_minLength * axis;
  345. draw->DrawPoint(pMin, 4.0f, c2);
  346. }
  347. if (m_maxLength < FLT_MAX)
  348. {
  349. b2Vec2 pMax = pA + m_maxLength * axis;
  350. draw->DrawPoint(pMax, 4.0f, c3);
  351. }
  352. }
  353. }