MouseJoint.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  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.Diagnostics;
  23. using Microsoft.Xna.Framework;
  24. namespace Box2D.XNA
  25. {
  26. /// Mouse joint definition. This requires a world target point,
  27. /// tuning parameters, and the time step.
  28. public class MouseJointDef : JointDef
  29. {
  30. public MouseJointDef()
  31. {
  32. type = JointType.Mouse;
  33. target = new Vector2(0.0f, 0.0f);
  34. maxForce = 0.0f;
  35. frequencyHz = 5.0f;
  36. dampingRatio = 0.7f;
  37. }
  38. /// The initial world target point. This is assumed
  39. /// to coincide with the body anchor initially.
  40. public Vector2 target;
  41. /// The maximum constraint force that can be exerted
  42. /// to move the candidate body. Usually you will express
  43. /// as some multiple of the weight (multiplier * mass * gravity).
  44. public float maxForce;
  45. /// The response speed.
  46. public float frequencyHz;
  47. /// The damping ratio. 0 = no damping, 1 = critical damping.
  48. public float dampingRatio;
  49. };
  50. /// A mouse joint is used to make a point on a body track a
  51. /// specified world point. This a soft constraint with a maximum
  52. /// force. This allows the constraint to stretch and without
  53. /// applying huge forces.
  54. /// NOTE: this joint is not documented in the manual because it was
  55. /// developed to be used in the testbed. If you want to learn how to
  56. /// use the mouse joint, look at the testbed.
  57. public class MouseJoint : Joint
  58. {
  59. /// Implements Joint.
  60. public override Vector2 GetAnchorA()
  61. {
  62. return _target;
  63. }
  64. /// Implements Joint.
  65. public override Vector2 GetAnchorB()
  66. {
  67. return _bodyB.GetWorldPoint(_localAnchor);
  68. }
  69. /// Implements Joint.
  70. public override Vector2 GetReactionForce(float inv_dt)
  71. {
  72. return inv_dt * _impulse;
  73. }
  74. /// Implements Joint.
  75. public override float GetReactionTorque(float inv_dt)
  76. {
  77. return inv_dt * 0.0f;
  78. }
  79. /// Use this to update the target point.
  80. public void SetTarget(Vector2 target)
  81. {
  82. if (_bodyB.IsAwake() == false)
  83. {
  84. _bodyB.SetAwake(true);
  85. }
  86. _target = target;
  87. }
  88. public Vector2 GetTarget()
  89. {
  90. return _target;
  91. }
  92. /// Set/get the maximum force in Newtons.
  93. public void SetMaxForce(float force)
  94. {
  95. _maxForce = force;
  96. }
  97. public float GetMaxForce()
  98. {
  99. return _maxForce;
  100. }
  101. /// Set/get the frequency in Hertz.
  102. public void SetFrequency(float hz)
  103. {
  104. _frequencyHz = hz;
  105. }
  106. public float GetFrequency()
  107. {
  108. return _frequencyHz;
  109. }
  110. /// Set/get the damping ratio (dimensionless).
  111. public void SetDampingRatio(float ratio)
  112. {
  113. _dampingRatio = ratio;
  114. }
  115. public float GetDampingRatio()
  116. {
  117. return _dampingRatio;
  118. }
  119. internal MouseJoint(MouseJointDef def)
  120. : base(def)
  121. {
  122. Debug.Assert(def.target.IsValid());
  123. Debug.Assert(MathUtils.IsValid(def.maxForce) && def.maxForce >= 0.0f);
  124. Debug.Assert(MathUtils.IsValid(def.frequencyHz) && def.frequencyHz >= 0.0f);
  125. Debug.Assert(MathUtils.IsValid(def.dampingRatio) && def.dampingRatio >= 0.0f);
  126. Transform xf1;
  127. _bodyB.GetTransform(out xf1);
  128. _target = def.target;
  129. _localAnchor = MathUtils.MultiplyT(ref xf1, _target);
  130. _maxForce = def.maxForce;
  131. _impulse = Vector2.Zero;
  132. _frequencyHz = def.frequencyHz;
  133. _dampingRatio = def.dampingRatio;
  134. _beta = 0.0f;
  135. _gamma = 0.0f;
  136. }
  137. internal override void InitVelocityConstraints(ref TimeStep step)
  138. {
  139. Body b = _bodyB;
  140. float mass = b.GetMass();
  141. // Frequency
  142. float omega = 2.0f * Settings.b2_pi * _frequencyHz;
  143. // Damping coefficient
  144. float d = 2.0f * mass * _dampingRatio * omega;
  145. // Spring stiffness
  146. float k = mass * (omega * omega);
  147. // magic formulas
  148. // gamma has units of inverse mass.
  149. // beta has units of inverse time.
  150. Debug.Assert(d + step.dt * k > Settings.b2_epsilon);
  151. _gamma = step.dt * (d + step.dt * k);
  152. if (_gamma != 0.0f)
  153. {
  154. _gamma = 1.0f / _gamma;
  155. }
  156. _beta = step.dt * k * _gamma;
  157. // Compute the effective mass matrix.
  158. Transform xf1;
  159. b.GetTransform(out xf1);
  160. Vector2 r = MathUtils.Multiply(ref xf1.R, _localAnchor - b.GetLocalCenter());
  161. // K = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)]
  162. // = [1/m1+1/m2 0 ] + invI1 * [r1.Y*r1.Y -r1.X*r1.Y] + invI2 * [r1.Y*r1.Y -r1.X*r1.Y]
  163. // [ 0 1/m1+1/m2] [-r1.X*r1.Y r1.X*r1.X] [-r1.X*r1.Y r1.X*r1.X]
  164. float invMass = b._invMass;
  165. float invI = b._invI;
  166. Mat22 K1 = new Mat22(new Vector2(invMass, 0.0f), new Vector2(0.0f, invMass));
  167. Mat22 K2 = new Mat22(new Vector2(invI * r.Y * r.Y, -invI * r.X * r.Y), new Vector2(-invI * r.X * r.Y, invI * r.X * r.X));
  168. Mat22 K;
  169. Mat22.Add(ref K1, ref K2, out K);
  170. K.col1.X += _gamma;
  171. K.col2.Y += _gamma;
  172. _mass = K.GetInverse();
  173. _C = b._sweep.c + r - _target;
  174. // Cheat with some damping
  175. b._angularVelocity *= 0.98f;
  176. // Warm starting.
  177. _impulse *= step.dtRatio;
  178. b._linearVelocity += invMass * _impulse;
  179. b._angularVelocity += invI * MathUtils.Cross(r, _impulse);
  180. }
  181. internal override void SolveVelocityConstraints(ref TimeStep step)
  182. {
  183. Body b = _bodyB;
  184. Transform xf1;
  185. b.GetTransform(out xf1);
  186. Vector2 r = MathUtils.Multiply(ref xf1.R, _localAnchor - b.GetLocalCenter());
  187. // Cdot = v + cross(w, r)
  188. Vector2 Cdot = b._linearVelocity + MathUtils.Cross(b._angularVelocity, r);
  189. Vector2 impulse = MathUtils.Multiply(ref _mass, -(Cdot + _beta * _C + _gamma * _impulse));
  190. Vector2 oldImpulse = _impulse;
  191. _impulse += impulse;
  192. float maxImpulse = step.dt * _maxForce;
  193. if (_impulse.LengthSquared() > maxImpulse * maxImpulse)
  194. {
  195. _impulse *= maxImpulse / _impulse.Length();
  196. }
  197. impulse = _impulse - oldImpulse;
  198. b._linearVelocity += b._invMass * impulse;
  199. b._angularVelocity += b._invI * MathUtils.Cross(r, impulse);
  200. }
  201. internal override bool SolvePositionConstraints(float baumgarte)
  202. {
  203. return true;
  204. }
  205. public Vector2 _localAnchor;
  206. public Vector2 _target;
  207. public Vector2 _impulse;
  208. public Mat22 _mass; // effective mass for point-to-point constraint.
  209. public Vector2 _C; // position error
  210. public float _maxForce;
  211. public float _frequencyHz;
  212. public float _dampingRatio;
  213. public float _beta;
  214. public float _gamma;
  215. };
  216. }