PrismaticJoint.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694
  1. /*
  2. * Box2D.XNA port of Box2D:
  3. * Copyright (c) 2009 Brandon Furtwangler, Nathan Furtwangler
  4. *
  5. * Original source Box2D:
  6. * Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
  7. *
  8. * This software is provided 'as-is', without any express or implied
  9. * warranty. In no event will the authors be held liable for any damages
  10. * arising from the use of this software.
  11. * Permission is granted to anyone to use this software for any purpose,
  12. * including commercial applications, and to alter it and redistribute it
  13. * freely, subject to the following restrictions:
  14. * 1. The origin of this software must not be misrepresented; you must not
  15. * claim that you wrote the original software. If you use this software
  16. * in a product, an acknowledgment in the product documentation would be
  17. * appreciated but is not required.
  18. * 2. Altered source versions must be plainly marked as such, and must not be
  19. * misrepresented as being the original software.
  20. * 3. This notice may not be removed or altered from any source distribution.
  21. */
  22. using System;
  23. using System.Diagnostics;
  24. using Microsoft.Xna.Framework;
  25. namespace Box2D.XNA
  26. {
  27. /// Prismatic joint definition. This requires defining a line of
  28. /// motion using an axis and an anchor point. The definition uses local
  29. /// anchor points and a local axis so that the initial configuration
  30. /// can violate the constraint slightly. The joint translation is zero
  31. /// when the local anchor points coincide in world space. Using local
  32. /// anchors and a local axis helps when saving and loading a game.
  33. public class PrismaticJointDef : JointDef
  34. {
  35. public PrismaticJointDef()
  36. {
  37. type = JointType.Prismatic;
  38. localAnchorA = Vector2.Zero;
  39. localAnchorB = Vector2.Zero;
  40. localAxis1 = new Vector2(1.0f, 0.0f);
  41. referenceAngle = 0.0f;
  42. enableLimit = false;
  43. lowerTranslation = 0.0f;
  44. upperTranslation = 0.0f;
  45. enableMotor = false;
  46. maxMotorForce = 0.0f;
  47. motorSpeed = 0.0f;
  48. }
  49. /// Initialize the bodies, anchors, axis, and reference angle using the world
  50. /// anchor and world axis.
  51. // Linear constraint (point-to-line)
  52. // d = p2 - p1 = x2 + r2 - x1 - r1
  53. // C = dot(perp, d)
  54. // Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1))
  55. // = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2)
  56. // J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)]
  57. //
  58. // Angular constraint
  59. // C = a2 - a1 + a_initial
  60. // Cdot = w2 - w1
  61. // J = [0 0 -1 0 0 1]
  62. //
  63. // K = J * invM * JT
  64. //
  65. // J = [-a -s1 a s2]
  66. // [0 -1 0 1]
  67. // a = perp
  68. // s1 = cross(d + r1, a) = cross(p2 - x1, a)
  69. // s2 = cross(r2, a) = cross(p2 - x2, a)
  70. // Motor/Limit linear constraint
  71. // C = dot(ax1, d)
  72. // Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2)
  73. // J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)]
  74. // Block Solver
  75. // We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even
  76. // when the mass has poor distribution (leading to large torques about the joint anchor points).
  77. //
  78. // The Jacobian has 3 rows:
  79. // J = [-uT -s1 uT s2] // linear
  80. // [0 -1 0 1] // angular
  81. // [-vT -a1 vT a2] // limit
  82. //
  83. // u = perp
  84. // v = axis
  85. // s1 = cross(d + r1, u), s2 = cross(r2, u)
  86. // a1 = cross(d + r1, v), a2 = cross(r2, v)
  87. // M * (v2 - v1) = JT * df
  88. // J * v2 = bias
  89. //
  90. // v2 = v1 + invM * JT * df
  91. // J * (v1 + invM * JT * df) = bias
  92. // K * df = bias - J * v1 = -Cdot
  93. // K = J * invM * JT
  94. // Cdot = J * v1 - bias
  95. //
  96. // Now solve for f2.
  97. // df = f2 - f1
  98. // K * (f2 - f1) = -Cdot
  99. // f2 = invK * (-Cdot) + f1
  100. //
  101. // Clamp accumulated limit impulse.
  102. // lower: f2(3) = max(f2(3), 0)
  103. // upper: f2(3) = min(f2(3), 0)
  104. //
  105. // Solve for correct f2(1:2)
  106. // K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:3) * f1
  107. // = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:2) * f1(1:2) + K(1:2,3) * f1(3)
  108. // K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3)) + K(1:2,1:2) * f1(1:2)
  109. // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2)
  110. //
  111. // Now compute impulse to be applied:
  112. // df = f2 - f1
  113. public void Initialize(Body b1, Body b2, Vector2 anchor, Vector2 axis)
  114. {
  115. bodyA = b1;
  116. bodyB = b2;
  117. localAnchorA = bodyA.GetLocalPoint(anchor);
  118. localAnchorB = bodyB.GetLocalPoint(anchor);
  119. localAxis1 = bodyA.GetLocalVector(axis);
  120. referenceAngle = bodyB.GetAngle() - bodyA.GetAngle();
  121. }
  122. /// The local anchor point relative to body1's origin.
  123. public Vector2 localAnchorA;
  124. /// The local anchor point relative to body2's origin.
  125. public Vector2 localAnchorB;
  126. /// The local translation axis in body1.
  127. public Vector2 localAxis1;
  128. /// The rained angle between the bodies: body2_angle - body1_angle.
  129. public float referenceAngle;
  130. /// Enable/disable the joint limit.
  131. public bool enableLimit;
  132. /// The lower translation limit, usually in meters.
  133. public float lowerTranslation;
  134. /// The upper translation limit, usually in meters.
  135. public float upperTranslation;
  136. /// Enable/disable the joint motor.
  137. public bool enableMotor;
  138. /// The maximum motor torque, usually in N-m.
  139. public float maxMotorForce;
  140. /// The desired motor speed in radians per second.
  141. public float motorSpeed;
  142. };
  143. /// A prismatic joint. This joint provides one degree of freedom: translation
  144. /// along an axis fixed in body1. Relative rotation is prevented. You can
  145. /// use a joint limit to restrict the range of motion and a joint motor to
  146. /// drive the motion or to model joint friction.
  147. public class PrismaticJoint : Joint
  148. {
  149. public override Vector2 GetAnchorA()
  150. {
  151. return _bodyA.GetWorldPoint(_localAnchor1);
  152. }
  153. public override Vector2 GetAnchorB()
  154. {
  155. return _bodyB.GetWorldPoint(_localAnchor2);
  156. }
  157. public override Vector2 GetReactionForce(float inv_dt)
  158. {
  159. return inv_dt * (_impulse.X * _perp + (_motorImpulse + _impulse.Z) * _axis);
  160. }
  161. public override float GetReactionTorque(float inv_dt)
  162. {
  163. return inv_dt * _impulse.Y;
  164. }
  165. /// Get the current joint translation, usually in meters.
  166. public float GetJointTranslation()
  167. {
  168. Body b1 = _bodyA;
  169. Body b2 = _bodyB;
  170. Vector2 p1 = b1.GetWorldPoint(_localAnchor1);
  171. Vector2 p2 = b2.GetWorldPoint(_localAnchor2);
  172. Vector2 d = p2 - p1;
  173. Vector2 axis = b1.GetWorldVector(_localXAxis1);
  174. float translation = Vector2.Dot(d, axis);
  175. return translation;
  176. }
  177. /// Get the current joint translation speed, usually in meters per second.
  178. public float GetJointSpeed()
  179. {
  180. Body b1 = _bodyA;
  181. Body b2 = _bodyB;
  182. Transform xf1, xf2;
  183. b1.GetTransform(out xf1);
  184. b2.GetTransform(out xf2);
  185. Vector2 r1 = MathUtils.Multiply(ref xf1.R, _localAnchor1 - b1.GetLocalCenter());
  186. Vector2 r2 = MathUtils.Multiply(ref xf2.R, _localAnchor2 - b2.GetLocalCenter());
  187. Vector2 p1 = b1._sweep.c + r1;
  188. Vector2 p2 = b2._sweep.c + r2;
  189. Vector2 d = p2 - p1;
  190. Vector2 axis = b1.GetWorldVector(_localXAxis1);
  191. Vector2 v1 = b1._linearVelocity;
  192. Vector2 v2 = b2._linearVelocity;
  193. float w1 = b1._angularVelocity;
  194. float w2 = b2._angularVelocity;
  195. float speed = Vector2.Dot(d, MathUtils.Cross(w1, axis)) + Vector2.Dot(axis, v2 + MathUtils.Cross(w2, r2) - v1 - MathUtils.Cross(w1, r1));
  196. return speed;
  197. }
  198. /// Is the joint limit enabled?
  199. public bool IsLimitEnabled()
  200. {
  201. return _enableLimit;
  202. }
  203. /// Enable/disable the joint limit.
  204. public void EnableLimit(bool flag)
  205. {
  206. _bodyA.SetAwake(true);
  207. _bodyB.SetAwake(true);
  208. _enableLimit = flag;
  209. }
  210. /// Get the lower joint limit, usually in meters.
  211. public float GetLowerLimit()
  212. {
  213. return _lowerTranslation;
  214. }
  215. /// Get the upper joint limit, usually in meters.
  216. public float GetUpperLimit()
  217. {
  218. return _upperTranslation;
  219. }
  220. /// Set the joint limits, usually in meters.
  221. public void SetLimits(float lower, float upper)
  222. {
  223. Debug.Assert(lower <= upper);
  224. _bodyA.SetAwake(true);
  225. _bodyB.SetAwake(true);
  226. _lowerTranslation = lower;
  227. _upperTranslation = upper;
  228. }
  229. /// Is the joint motor enabled?
  230. public bool IsMotorEnabled()
  231. {
  232. return _enableMotor;
  233. }
  234. /// Enable/disable the joint motor.
  235. public void EnableMotor(bool flag)
  236. {
  237. _bodyA.SetAwake(true);
  238. _bodyB.SetAwake(true);
  239. _enableMotor = flag;
  240. }
  241. /// Set the motor speed, usually in meters per second.
  242. public void SetMotorSpeed(float speed)
  243. {
  244. _bodyA.SetAwake(true);
  245. _bodyB.SetAwake(true);
  246. _motorSpeed = speed;
  247. }
  248. /// Get the motor speed, usually in meters per second.
  249. public float GetMotorSpeed()
  250. {
  251. return _motorSpeed;
  252. }
  253. /// Set the maximum motor force, usually in N.
  254. public void SetMaxMotorForce(float force)
  255. {
  256. _bodyA.SetAwake(true);
  257. _bodyB.SetAwake(true);
  258. _maxMotorForce = force;
  259. }
  260. /// Get the current motor force, usually in N.
  261. public float GetMotorForce()
  262. {
  263. return _motorImpulse;
  264. }
  265. internal PrismaticJoint(PrismaticJointDef def)
  266. : base(def)
  267. {
  268. _localAnchor1 = def.localAnchorA;
  269. _localAnchor2 = def.localAnchorB;
  270. _localXAxis1 = def.localAxis1;
  271. _localYAxis1 = MathUtils.Cross(1.0f, _localXAxis1);
  272. _refAngle = def.referenceAngle;
  273. _impulse = Vector3.Zero;
  274. _motorMass = 0.0f;
  275. _motorImpulse = 0.0f;
  276. _lowerTranslation = def.lowerTranslation;
  277. _upperTranslation = def.upperTranslation;
  278. _maxMotorForce = def.maxMotorForce;
  279. _motorSpeed = def.motorSpeed;
  280. _enableLimit = def.enableLimit;
  281. _enableMotor = def.enableMotor;
  282. _limitState = LimitState.Inactive;
  283. _axis = Vector2.Zero;
  284. _perp = Vector2.Zero;
  285. }
  286. internal override void InitVelocityConstraints(ref TimeStep step)
  287. {
  288. Body b1 = _bodyA;
  289. Body b2 = _bodyB;
  290. _localCenterA = b1.GetLocalCenter();
  291. _localCenterB = b2.GetLocalCenter();
  292. Transform xf1, xf2;
  293. b1.GetTransform(out xf1);
  294. b2.GetTransform(out xf2);
  295. // Compute the effective masses.
  296. Vector2 r1 = MathUtils.Multiply(ref xf1.R, _localAnchor1 - _localCenterA);
  297. Vector2 r2 = MathUtils.Multiply(ref xf2.R, _localAnchor2 - _localCenterB);
  298. Vector2 d = b2._sweep.c + r2 - b1._sweep.c - r1;
  299. _invMassA = b1._invMass;
  300. _invIA = b1._invI;
  301. _invMassB = b2._invMass;
  302. _invIB = b2._invI;
  303. // Compute motor Jacobian and effective mass.
  304. {
  305. _axis = MathUtils.Multiply(ref xf1.R, _localXAxis1);
  306. _a1 = MathUtils.Cross(d + r1, _axis);
  307. _a2 = MathUtils.Cross(r2, _axis);
  308. _motorMass = _invMassA + _invMassB + _invIA * _a1 * _a1 + _invIB * _a2 * _a2;
  309. if (_motorMass > Settings.b2_epsilon)
  310. {
  311. _motorMass = 1.0f / _motorMass;
  312. }
  313. }
  314. // Prismatic constraint.
  315. {
  316. _perp = MathUtils.Multiply(ref xf1.R, _localYAxis1);
  317. _s1 = MathUtils.Cross(d + r1, _perp);
  318. _s2 = MathUtils.Cross(r2, _perp);
  319. float m1 = _invMassA, m2 = _invMassB;
  320. float i1 = _invIA, i2 = _invIB;
  321. float k11 = m1 + m2 + i1 * _s1 * _s1 + i2 * _s2 * _s2;
  322. float k12 = i1 * _s1 + i2 * _s2;
  323. float k13 = i1 * _s1 * _a1 + i2 * _s2 * _a2;
  324. float k22 = i1 + i2;
  325. float k23 = i1 * _a1 + i2 * _a2;
  326. float k33 = m1 + m2 + i1 * _a1 * _a1 + i2 * _a2 * _a2;
  327. _K.col1 = new Vector3(k11, k12, k13);
  328. _K.col2 = new Vector3(k12, k22, k23);
  329. _K.col3 = new Vector3(k13, k23, k33);
  330. }
  331. // Compute motor and limit terms.
  332. if (_enableLimit)
  333. {
  334. float jointTranslation = Vector2.Dot(_axis, d);
  335. if (Math.Abs(_upperTranslation - _lowerTranslation) < 2.0f * Settings.b2_linearSlop)
  336. {
  337. _limitState = LimitState.Equal;
  338. }
  339. else if (jointTranslation <= _lowerTranslation)
  340. {
  341. if (_limitState != LimitState.AtLower)
  342. {
  343. _limitState = LimitState.AtLower;
  344. _impulse.Z = 0.0f;
  345. }
  346. }
  347. else if (jointTranslation >= _upperTranslation)
  348. {
  349. if (_limitState != LimitState.AtUpper)
  350. {
  351. _limitState = LimitState.AtUpper;
  352. _impulse.Z = 0.0f;
  353. }
  354. }
  355. else
  356. {
  357. _limitState = LimitState.Inactive;
  358. _impulse.Z = 0.0f;
  359. }
  360. }
  361. else
  362. {
  363. _limitState = LimitState.Inactive;
  364. }
  365. if (_enableMotor == false)
  366. {
  367. _motorImpulse = 0.0f;
  368. }
  369. if (step.warmStarting)
  370. {
  371. // Account for variable time step.
  372. _impulse *= step.dtRatio;
  373. _motorImpulse *= step.dtRatio;
  374. Vector2 P = _impulse.X * _perp + (_motorImpulse + _impulse.Z) * _axis;
  375. float L1 = _impulse.X * _s1 + _impulse.Y + (_motorImpulse + _impulse.Z) * _a1;
  376. float L2 = _impulse.X * _s2 + _impulse.Y + (_motorImpulse + _impulse.Z) * _a2;
  377. b1._linearVelocity -= _invMassA * P;
  378. b1._angularVelocity -= _invIA * L1;
  379. b2._linearVelocity += _invMassB * P;
  380. b2._angularVelocity += _invIB * L2;
  381. }
  382. else
  383. {
  384. _impulse = Vector3.Zero;
  385. _motorImpulse = 0.0f;
  386. }
  387. }
  388. internal override void SolveVelocityConstraints(ref TimeStep step)
  389. {
  390. Body b1 = _bodyA;
  391. Body b2 = _bodyB;
  392. Vector2 v1 = b1._linearVelocity;
  393. float w1 = b1._angularVelocity;
  394. Vector2 v2 = b2._linearVelocity;
  395. float w2 = b2._angularVelocity;
  396. // Solve linear motor constraint.
  397. if (_enableMotor && _limitState != LimitState.Equal)
  398. {
  399. float Cdot = Vector2.Dot(_axis, v2 - v1) + _a2 * w2 - _a1 * w1;
  400. float impulse = _motorMass * (_motorSpeed - Cdot);
  401. float oldImpulse = _motorImpulse;
  402. float maxImpulse = step.dt * _maxMotorForce;
  403. _motorImpulse = MathUtils.Clamp(_motorImpulse + impulse, -maxImpulse, maxImpulse);
  404. impulse = _motorImpulse - oldImpulse;
  405. Vector2 P = impulse * _axis;
  406. float L1 = impulse * _a1;
  407. float L2 = impulse * _a2;
  408. v1 -= _invMassA * P;
  409. w1 -= _invIA * L1;
  410. v2 += _invMassB * P;
  411. w2 += _invIB * L2;
  412. }
  413. Vector2 Cdot1 = new Vector2(Vector2.Dot(_perp, v2 - v1) + _s2 * w2 - _s1 * w1, w2 - w1);
  414. if (_enableLimit && _limitState != LimitState.Inactive)
  415. {
  416. // Solve prismatic and limit constraint in block form.
  417. float Cdot2 = Vector2.Dot(_axis, v2 - v1) + _a2 * w2 - _a1 * w1;
  418. Vector3 Cdot = new Vector3(Cdot1.X, Cdot1.Y, Cdot2);
  419. Vector3 f1 = _impulse;
  420. Vector3 df = _K.Solve33(-Cdot);
  421. _impulse += df;
  422. if (_limitState == LimitState.AtLower)
  423. {
  424. _impulse.Z = Math.Max(_impulse.Z, 0.0f);
  425. }
  426. else if (_limitState == LimitState.AtUpper)
  427. {
  428. _impulse.Z = Math.Min(_impulse.Z, 0.0f);
  429. }
  430. // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2)
  431. Vector2 b = -Cdot1 - (_impulse.Z - f1.Z) * new Vector2(_K.col3.X, _K.col3.Y);
  432. Vector2 f2r = _K.Solve22(b) + new Vector2(f1.X, f1.Y);
  433. _impulse.X = f2r.X;
  434. _impulse.Y = f2r.Y;
  435. df = _impulse - f1;
  436. Vector2 P = df.X * _perp + df.Z * _axis;
  437. float L1 = df.X * _s1 + df.Y + df.Z * _a1;
  438. float L2 = df.X * _s2 + df.Y + df.Z * _a2;
  439. v1 -= _invMassA * P;
  440. w1 -= _invIA * L1;
  441. v2 += _invMassB * P;
  442. w2 += _invIB * L2;
  443. }
  444. else
  445. {
  446. // Limit is inactive, just solve the prismatic constraint in block form.
  447. Vector2 df = _K.Solve22(-Cdot1);
  448. _impulse.X += df.X;
  449. _impulse.Y += df.Y;
  450. Vector2 P = df.X * _perp;
  451. float L1 = df.X * _s1 + df.Y;
  452. float L2 = df.X * _s2 + df.Y;
  453. v1 -= _invMassA * P;
  454. w1 -= _invIA * L1;
  455. v2 += _invMassB * P;
  456. w2 += _invIB * L2;
  457. }
  458. b1._linearVelocity = v1;
  459. b1._angularVelocity = w1;
  460. b2._linearVelocity = v2;
  461. b2._angularVelocity = w2;
  462. }
  463. internal override bool SolvePositionConstraints(float baumgarte)
  464. {
  465. Body b1 = _bodyA;
  466. Body b2 = _bodyB;
  467. Vector2 c1 = b1._sweep.c;
  468. float a1 = b1._sweep.a;
  469. Vector2 c2 = b2._sweep.c;
  470. float a2 = b2._sweep.a;
  471. // Solve linear limit constraint.
  472. float linearError = 0.0f, angularError = 0.0f;
  473. bool active = false;
  474. float C2 = 0.0f;
  475. Mat22 R1 = new Mat22(a1);
  476. Mat22 R2 = new Mat22(a2);
  477. Vector2 r1 = MathUtils.Multiply(ref R1, _localAnchor1 - _localCenterA);
  478. Vector2 r2 = MathUtils.Multiply(ref R2, _localAnchor2 - _localCenterB);
  479. Vector2 d = c2 + r2 - c1 - r1;
  480. if (_enableLimit)
  481. {
  482. _axis = MathUtils.Multiply(ref R1, _localXAxis1);
  483. _a1 = MathUtils.Cross(d + r1, _axis);
  484. _a2 = MathUtils.Cross(r2, _axis);
  485. float translation = Vector2.Dot(_axis, d);
  486. if (Math.Abs(_upperTranslation - _lowerTranslation) < 2.0f * Settings.b2_linearSlop)
  487. {
  488. // Prevent large angular corrections
  489. C2 = MathUtils.Clamp(translation, -Settings.b2_maxLinearCorrection, Settings.b2_maxLinearCorrection);
  490. linearError = Math.Abs(translation);
  491. active = true;
  492. }
  493. else if (translation <= _lowerTranslation)
  494. {
  495. // Prevent large linear corrections and allow some slop.
  496. C2 = MathUtils.Clamp(translation - _lowerTranslation + Settings.b2_linearSlop, -Settings.b2_maxLinearCorrection, 0.0f);
  497. linearError = _lowerTranslation - translation;
  498. active = true;
  499. }
  500. else if (translation >= _upperTranslation)
  501. {
  502. // Prevent large linear corrections and allow some slop.
  503. C2 = MathUtils.Clamp(translation - _upperTranslation - Settings.b2_linearSlop, 0.0f, Settings.b2_maxLinearCorrection);
  504. linearError = translation - _upperTranslation;
  505. active = true;
  506. }
  507. }
  508. _perp = MathUtils.Multiply(ref R1, _localYAxis1);
  509. _s1 = MathUtils.Cross(d + r1, _perp);
  510. _s2 = MathUtils.Cross(r2, _perp);
  511. Vector3 impulse;
  512. Vector2 C1 = new Vector2(Vector2.Dot(_perp, d), a2 - a1 - _refAngle);
  513. linearError = Math.Max(linearError, Math.Abs(C1.X));
  514. angularError = Math.Abs(C1.Y);
  515. if (active)
  516. {
  517. float m1 = _invMassA, m2 = _invMassB;
  518. float i1 = _invIA, i2 = _invIB;
  519. float k11 = m1 + m2 + i1 * _s1 * _s1 + i2 * _s2 * _s2;
  520. float k12 = i1 * _s1 + i2 * _s2;
  521. float k13 = i1 * _s1 * _a1 + i2 * _s2 * _a2;
  522. float k22 = i1 + i2;
  523. float k23 = i1 * _a1 + i2 * _a2;
  524. float k33 = m1 + m2 + i1 * _a1 * _a1 + i2 * _a2 * _a2;
  525. _K.col1 = new Vector3(k11, k12, k13);
  526. _K.col2 = new Vector3(k12, k22, k23);
  527. _K.col3 = new Vector3(k13, k23, k33);
  528. Vector3 C = new Vector3(-C1.X, -C1.Y, -C2);
  529. impulse = _K.Solve33(C); // negated above
  530. }
  531. else
  532. {
  533. float m1 = _invMassA, m2 = _invMassB;
  534. float i1 = _invIA, i2 = _invIB;
  535. float k11 = m1 + m2 + i1 * _s1 * _s1 + i2 * _s2 * _s2;
  536. float k12 = i1 * _s1 + i2 * _s2;
  537. float k22 = i1 + i2;
  538. _K.col1 = new Vector3(k11, k12, 0.0f);
  539. _K.col2 = new Vector3(k12, k22, 0.0f);
  540. Vector2 impulse1 = _K.Solve22(-C1);
  541. impulse.X = impulse1.X;
  542. impulse.Y = impulse1.Y;
  543. impulse.Z = 0.0f;
  544. }
  545. Vector2 P = impulse.X * _perp + impulse.Z * _axis;
  546. float L1 = impulse.X * _s1 + impulse.Y + impulse.Z * _a1;
  547. float L2 = impulse.X * _s2 + impulse.Y + impulse.Z * _a2;
  548. c1 -= _invMassA * P;
  549. a1 -= _invIA * L1;
  550. c2 += _invMassB * P;
  551. a2 += _invIB * L2;
  552. // TODO_ERIN remove need for this.
  553. b1._sweep.c = c1;
  554. b1._sweep.a = a1;
  555. b2._sweep.c = c2;
  556. b2._sweep.a = a2;
  557. b1.SynchronizeTransform();
  558. b2.SynchronizeTransform();
  559. return linearError <= Settings.b2_linearSlop && angularError <= Settings.b2_angularSlop;
  560. }
  561. public Vector2 _localAnchor1;
  562. public Vector2 _localAnchor2;
  563. public Vector2 _localXAxis1;
  564. public Vector2 _localYAxis1;
  565. public float _refAngle;
  566. public Vector2 _axis, _perp;
  567. public float _s1, _s2;
  568. public float _a1, _a2;
  569. public Mat33 _K;
  570. public Vector3 _impulse;
  571. public float _motorMass; // effective mass for motor/limit translational constraint.
  572. public float _motorImpulse;
  573. public float _lowerTranslation;
  574. public float _upperTranslation;
  575. public float _maxMotorForce;
  576. public float _motorSpeed;
  577. public bool _enableLimit;
  578. public bool _enableMotor;
  579. public LimitState _limitState;
  580. };
  581. }