FixedLineJoint.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  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. public class FixedLineJoint : Joint
  32. {
  33. private Vector2 _ax, _ay;
  34. private float _bias;
  35. private bool _enableMotor;
  36. private float _gamma;
  37. private float _impulse;
  38. private Vector2 _localXAxis;
  39. private Vector2 _localYAxisA;
  40. private float _mass;
  41. private float _maxMotorTorque;
  42. private float _motorImpulse;
  43. private float _motorMass;
  44. private float _motorSpeed;
  45. private float _sAx;
  46. private float _sAy;
  47. private float _sBx;
  48. private float _sBy;
  49. private float _springImpulse;
  50. private float _springMass;
  51. // Linear constraint (point-to-line)
  52. // d = pB - pA = xB + rB - xA - rA
  53. // C = dot(ay, d)
  54. // Cdot = dot(d, cross(wA, ay)) + dot(ay, vB + cross(wB, rB) - vA - cross(wA, rA))
  55. // = -dot(ay, vA) - dot(cross(d + rA, ay), wA) + dot(ay, vB) + dot(cross(rB, ay), vB)
  56. // J = [-ay, -cross(d + rA, ay), ay, cross(rB, ay)]
  57. // Spring linear constraint
  58. // C = dot(ax, d)
  59. // Cdot = = -dot(ax, vA) - dot(cross(d + rA, ax), wA) + dot(ax, vB) + dot(cross(rB, ax), vB)
  60. // J = [-ax -cross(d+rA, ax) ax cross(rB, ax)]
  61. // Motor rotational constraint
  62. // Cdot = wB - wA
  63. // J = [0 0 -1 0 0 1]
  64. internal FixedLineJoint() { JointType = JointType.FixedLine; }
  65. public FixedLineJoint(Body body, Vector2 worldAnchor, Vector2 axis)
  66. : base(body)
  67. {
  68. JointType = JointType.FixedLine;
  69. BodyB = BodyA;
  70. LocalAnchorA = worldAnchor;
  71. LocalAnchorB = BodyB.GetLocalPoint(worldAnchor);
  72. LocalXAxis = axis;
  73. }
  74. public Vector2 LocalAnchorA { get; set; }
  75. public Vector2 LocalAnchorB { get; set; }
  76. public override Vector2 WorldAnchorA
  77. {
  78. get { return LocalAnchorA; }
  79. }
  80. public override Vector2 WorldAnchorB
  81. {
  82. get { return BodyA.GetWorldPoint(LocalAnchorB); }
  83. set { Debug.Assert(false, "You can't set the world anchor on this joint type."); }
  84. }
  85. public float JointTranslation
  86. {
  87. get
  88. {
  89. Body bA = BodyA;
  90. Body bB = BodyB;
  91. Vector2 pA = bA.GetWorldPoint(LocalAnchorA);
  92. Vector2 pB = bB.GetWorldPoint(LocalAnchorB);
  93. Vector2 d = pB - pA;
  94. Vector2 axis = bA.GetWorldVector(LocalXAxis);
  95. float translation = Vector2.Dot(d, axis);
  96. return translation;
  97. }
  98. }
  99. public float JointSpeed
  100. {
  101. get
  102. {
  103. float wA = BodyA.AngularVelocityInternal;
  104. float wB = BodyB.AngularVelocityInternal;
  105. return wB - wA;
  106. }
  107. }
  108. public bool MotorEnabled
  109. {
  110. get { return _enableMotor; }
  111. set
  112. {
  113. BodyA.Awake = true;
  114. BodyB.Awake = true;
  115. _enableMotor = value;
  116. }
  117. }
  118. public float MotorSpeed
  119. {
  120. set
  121. {
  122. BodyA.Awake = true;
  123. BodyB.Awake = true;
  124. _motorSpeed = value;
  125. }
  126. get { return _motorSpeed; }
  127. }
  128. public float MaxMotorTorque
  129. {
  130. set
  131. {
  132. BodyA.Awake = true;
  133. BodyB.Awake = true;
  134. _maxMotorTorque = value;
  135. }
  136. get { return _maxMotorTorque; }
  137. }
  138. public float Frequency { get; set; }
  139. public float DampingRatio { get; set; }
  140. public Vector2 LocalXAxis
  141. {
  142. get { return _localXAxis; }
  143. set
  144. {
  145. _localXAxis = value;
  146. _localYAxisA = MathUtils.Cross(1.0f, _localXAxis);
  147. }
  148. }
  149. public override Vector2 GetReactionForce(float invDt)
  150. {
  151. return invDt * (_impulse * _ay + _springImpulse * _ax);
  152. }
  153. public override float GetReactionTorque(float invDt)
  154. {
  155. return invDt * _motorImpulse;
  156. }
  157. internal override void InitVelocityConstraints(ref TimeStep step)
  158. {
  159. Body bB = BodyB;
  160. LocalCenterA = Vector2.Zero;
  161. LocalCenterB = bB.LocalCenter;
  162. Transform xfB;
  163. bB.GetTransform(out xfB);
  164. // Compute the effective masses.
  165. Vector2 rA = LocalAnchorA;
  166. Vector2 rB = MathUtils.Multiply(ref xfB.R, LocalAnchorB - LocalCenterB);
  167. Vector2 d = bB.Sweep.C + rB - rA;
  168. InvMassA = 0.0f;
  169. InvIA = 0.0f;
  170. InvMassB = bB.InvMass;
  171. InvIB = bB.InvI;
  172. // Point to line constraint
  173. {
  174. _ay = _localYAxisA;
  175. _sAy = MathUtils.Cross(d + rA, _ay);
  176. _sBy = MathUtils.Cross(rB, _ay);
  177. _mass = InvMassA + InvMassB + InvIA * _sAy * _sAy + InvIB * _sBy * _sBy;
  178. if (_mass > 0.0f)
  179. {
  180. _mass = 1.0f / _mass;
  181. }
  182. }
  183. // Spring constraint
  184. _springMass = 0.0f;
  185. if (Frequency > 0.0f)
  186. {
  187. _ax = LocalXAxis;
  188. _sAx = MathUtils.Cross(d + rA, _ax);
  189. _sBx = MathUtils.Cross(rB, _ax);
  190. float invMass = InvMassA + InvMassB + InvIA * _sAx * _sAx + InvIB * _sBx * _sBx;
  191. if (invMass > 0.0f)
  192. {
  193. _springMass = 1.0f / invMass;
  194. float C = Vector2.Dot(d, _ax);
  195. // Frequency
  196. float omega = 2.0f * Settings.Pi * Frequency;
  197. // Damping coefficient
  198. float da = 2.0f * _springMass * DampingRatio * omega;
  199. // Spring stiffness
  200. float k = _springMass * omega * omega;
  201. // magic formulas
  202. _gamma = step.dt * (da + step.dt * k);
  203. if (_gamma > 0.0f)
  204. {
  205. _gamma = 1.0f / _gamma;
  206. }
  207. _bias = C * step.dt * k * _gamma;
  208. _springMass = invMass + _gamma;
  209. if (_springMass > 0.0f)
  210. {
  211. _springMass = 1.0f / _springMass;
  212. }
  213. }
  214. }
  215. else
  216. {
  217. _springImpulse = 0.0f;
  218. _springMass = 0.0f;
  219. }
  220. // Rotational motor
  221. if (_enableMotor)
  222. {
  223. _motorMass = InvIA + InvIB;
  224. if (_motorMass > 0.0f)
  225. {
  226. _motorMass = 1.0f / _motorMass;
  227. }
  228. }
  229. else
  230. {
  231. _motorMass = 0.0f;
  232. _motorImpulse = 0.0f;
  233. }
  234. if (Settings.EnableWarmstarting)
  235. {
  236. // Account for variable time step.
  237. _impulse *= step.dtRatio;
  238. _springImpulse *= step.dtRatio;
  239. _motorImpulse *= step.dtRatio;
  240. Vector2 P = _impulse * _ay + _springImpulse * _ax;
  241. float LB = _impulse * _sBy + _springImpulse * _sBx + _motorImpulse;
  242. bB.LinearVelocityInternal += InvMassB * P;
  243. bB.AngularVelocityInternal += InvIB * LB;
  244. }
  245. else
  246. {
  247. _impulse = 0.0f;
  248. _springImpulse = 0.0f;
  249. _motorImpulse = 0.0f;
  250. }
  251. }
  252. internal override void SolveVelocityConstraints(ref TimeStep step)
  253. {
  254. Body bB = BodyB;
  255. Vector2 vA = Vector2.Zero;
  256. float wA = 0.0f;
  257. Vector2 vB = bB.LinearVelocityInternal;
  258. float wB = bB.AngularVelocityInternal;
  259. // Solve spring constraint
  260. {
  261. float Cdot = Vector2.Dot(_ax, vB - vA) + _sBx * wB - _sAx * wA;
  262. float impulse = -_springMass * (Cdot + _bias + _gamma * _springImpulse);
  263. _springImpulse += impulse;
  264. Vector2 P = impulse * _ax;
  265. float LA = impulse * _sAx;
  266. float LB = impulse * _sBx;
  267. vA -= InvMassA * P;
  268. wA -= InvIA * LA;
  269. vB += InvMassB * P;
  270. wB += InvIB * LB;
  271. }
  272. // Solve rotational motor constraint
  273. {
  274. float Cdot = wB - wA - _motorSpeed;
  275. float impulse = -_motorMass * Cdot;
  276. float oldImpulse = _motorImpulse;
  277. float maxImpulse = step.dt * _maxMotorTorque;
  278. _motorImpulse = MathUtils.Clamp(_motorImpulse + impulse, -maxImpulse, maxImpulse);
  279. impulse = _motorImpulse - oldImpulse;
  280. wA -= InvIA * impulse;
  281. wB += InvIB * impulse;
  282. }
  283. // Solve point to line constraint
  284. {
  285. float Cdot = Vector2.Dot(_ay, vB - vA) + _sBy * wB - _sAy * wA;
  286. float impulse = _mass * (-Cdot);
  287. _impulse += impulse;
  288. Vector2 P = impulse * _ay;
  289. float LB = impulse * _sBy;
  290. vB += InvMassB * P;
  291. wB += InvIB * LB;
  292. }
  293. bB.LinearVelocityInternal = vB;
  294. bB.AngularVelocityInternal = wB;
  295. }
  296. internal override bool SolvePositionConstraints()
  297. {
  298. Body bB = BodyB;
  299. Vector2 xA = Vector2.Zero;
  300. const float angleA = 0.0f;
  301. Vector2 xB = bB.Sweep.C;
  302. float angleB = bB.Sweep.A;
  303. Mat22 RA = new Mat22(angleA);
  304. Mat22 RB = new Mat22(angleB);
  305. Vector2 rA = MathUtils.Multiply(ref RA, LocalAnchorA - LocalCenterA);
  306. Vector2 rB = MathUtils.Multiply(ref RB, LocalAnchorB - LocalCenterB);
  307. Vector2 d = xB + rB - xA - rA;
  308. Vector2 ay = MathUtils.Multiply(ref RA, _localYAxisA);
  309. float sBy = MathUtils.Cross(rB, ay);
  310. float C = Vector2.Dot(d, ay);
  311. float k = InvMassA + InvMassB + InvIA * _sAy * _sAy + InvIB * _sBy * _sBy;
  312. float impulse;
  313. if (k != 0.0f)
  314. {
  315. impulse = -C / k;
  316. }
  317. else
  318. {
  319. impulse = 0.0f;
  320. }
  321. Vector2 P = impulse * ay;
  322. float LB = impulse * sBy;
  323. xB += InvMassB * P;
  324. angleB += InvIB * LB;
  325. // TODO_ERIN remove need for this.
  326. bB.Sweep.C = xB;
  327. bB.Sweep.A = angleB;
  328. bB.SynchronizeTransform();
  329. return Math.Abs(C) <= Settings.LinearSlop;
  330. }
  331. public float GetMotorTorque(float invDt)
  332. {
  333. return invDt * _motorImpulse;
  334. }
  335. }
  336. }