FixedPrismaticJoint.cs 22 KB

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