FixedMouseJoint.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  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.Diagnostics;
  26. using FarseerPhysics.Common;
  27. using Microsoft.Xna.Framework;
  28. namespace FarseerPhysics.Dynamics.Joints
  29. {
  30. /// <summary>
  31. /// A mouse joint is used to make a point on a body track a
  32. /// specified world point. This a soft constraint with a maximum
  33. /// force. This allows the constraint to stretch and without
  34. /// applying huge forces.
  35. /// NOTE: this joint is not documented in the manual because it was
  36. /// developed to be used in the testbed. If you want to learn how to
  37. /// use the mouse joint, look at the testbed.
  38. /// </summary>
  39. public class FixedMouseJoint : Joint
  40. {
  41. public Vector2 LocalAnchorA;
  42. private Vector2 _C; // position error
  43. private float _beta;
  44. private float _gamma;
  45. private Vector2 _impulse;
  46. private Mat22 _mass; // effective mass for point-to-point constraint.
  47. private Vector2 _worldAnchor;
  48. /// <summary>
  49. /// This requires a world target point,
  50. /// tuning parameters, and the time step.
  51. /// </summary>
  52. /// <param name="body">The body.</param>
  53. /// <param name="worldAnchor">The target.</param>
  54. public FixedMouseJoint(Body body, Vector2 worldAnchor)
  55. : base(body)
  56. {
  57. JointType = JointType.FixedMouse;
  58. Frequency = 5.0f;
  59. DampingRatio = 0.7f;
  60. Debug.Assert(worldAnchor.IsValid());
  61. Transform xf1;
  62. BodyA.GetTransform(out xf1);
  63. _worldAnchor = worldAnchor;
  64. LocalAnchorA = BodyA.GetLocalPoint(worldAnchor);
  65. }
  66. public override Vector2 WorldAnchorA
  67. {
  68. get { return BodyA.GetWorldPoint(LocalAnchorA); }
  69. }
  70. public override Vector2 WorldAnchorB
  71. {
  72. get { return _worldAnchor; }
  73. set
  74. {
  75. BodyA.Awake = true;
  76. _worldAnchor = value;
  77. }
  78. }
  79. /// <summary>
  80. /// The maximum constraint force that can be exerted
  81. /// to move the candidate body. Usually you will express
  82. /// as some multiple of the weight (multiplier * mass * gravity).
  83. /// </summary>
  84. public float MaxForce { get; set; }
  85. /// <summary>
  86. /// The response speed.
  87. /// </summary>
  88. public float Frequency { get; set; }
  89. /// <summary>
  90. /// The damping ratio. 0 = no damping, 1 = critical damping.
  91. /// </summary>
  92. public float DampingRatio { get; set; }
  93. public override Vector2 GetReactionForce(float inv_dt)
  94. {
  95. return inv_dt * _impulse;
  96. }
  97. public override float GetReactionTorque(float inv_dt)
  98. {
  99. return inv_dt * 0.0f;
  100. }
  101. internal override void InitVelocityConstraints(ref TimeStep step)
  102. {
  103. Body b = BodyA;
  104. float mass = b.Mass;
  105. // Frequency
  106. float omega = 2.0f * Settings.Pi * Frequency;
  107. // Damping coefficient
  108. float d = 2.0f * mass * DampingRatio * omega;
  109. // Spring stiffness
  110. float k = mass * (omega * omega);
  111. // magic formulas
  112. // gamma has units of inverse mass.
  113. // beta has units of inverse time.
  114. Debug.Assert(d + step.dt * k > Settings.Epsilon);
  115. _gamma = step.dt * (d + step.dt * k);
  116. if (_gamma != 0.0f)
  117. {
  118. _gamma = 1.0f / _gamma;
  119. }
  120. _beta = step.dt * k * _gamma;
  121. // Compute the effective mass matrix.
  122. Transform xf1;
  123. b.GetTransform(out xf1);
  124. Vector2 r = MathUtils.Multiply(ref xf1.R, LocalAnchorA - b.LocalCenter);
  125. // K = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)]
  126. // = [1/m1+1/m2 0 ] + invI1 * [r1.Y*r1.Y -r1.X*r1.Y] + invI2 * [r1.Y*r1.Y -r1.X*r1.Y]
  127. // [ 0 1/m1+1/m2] [-r1.X*r1.Y r1.X*r1.X] [-r1.X*r1.Y r1.X*r1.X]
  128. float invMass = b.InvMass;
  129. float invI = b.InvI;
  130. Mat22 K1 = new Mat22(new Vector2(invMass, 0.0f), new Vector2(0.0f, invMass));
  131. Mat22 K2 = new Mat22(new Vector2(invI * r.Y * r.Y, -invI * r.X * r.Y),
  132. new Vector2(-invI * r.X * r.Y, invI * r.X * r.X));
  133. Mat22 K;
  134. Mat22.Add(ref K1, ref K2, out K);
  135. K.Col1.X += _gamma;
  136. K.Col2.Y += _gamma;
  137. _mass = K.Inverse;
  138. _C = b.Sweep.C + r - _worldAnchor;
  139. // Cheat with some damping
  140. b.AngularVelocityInternal *= 0.98f;
  141. // Warm starting.
  142. _impulse *= step.dtRatio;
  143. b.LinearVelocityInternal += invMass * _impulse;
  144. b.AngularVelocityInternal += invI * MathUtils.Cross(r, _impulse);
  145. }
  146. internal override void SolveVelocityConstraints(ref TimeStep step)
  147. {
  148. Body b = BodyA;
  149. Transform xf1;
  150. b.GetTransform(out xf1);
  151. Vector2 r = MathUtils.Multiply(ref xf1.R, LocalAnchorA - b.LocalCenter);
  152. // Cdot = v + cross(w, r)
  153. Vector2 Cdot = b.LinearVelocityInternal + MathUtils.Cross(b.AngularVelocityInternal, r);
  154. Vector2 impulse = MathUtils.Multiply(ref _mass, -(Cdot + _beta * _C + _gamma * _impulse));
  155. Vector2 oldImpulse = _impulse;
  156. _impulse += impulse;
  157. float maxImpulse = step.dt * MaxForce;
  158. if (_impulse.LengthSquared() > maxImpulse * maxImpulse)
  159. {
  160. _impulse *= maxImpulse / _impulse.Length();
  161. }
  162. impulse = _impulse - oldImpulse;
  163. b.LinearVelocityInternal += b.InvMass * impulse;
  164. b.AngularVelocityInternal += b.InvI * MathUtils.Cross(r, impulse);
  165. }
  166. internal override bool SolvePositionConstraints()
  167. {
  168. return true;
  169. }
  170. }
  171. }