CircleShape.cs 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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 FarseerPhysics.Common;
  27. using Microsoft.Xna.Framework;
  28. namespace FarseerPhysics.Collision.Shapes
  29. {
  30. public class CircleShape : Shape
  31. {
  32. internal Vector2 _position;
  33. public CircleShape(float radius, float density)
  34. : base(density)
  35. {
  36. ShapeType = ShapeType.Circle;
  37. _radius = radius;
  38. _position = Vector2.Zero;
  39. ComputeProperties();
  40. }
  41. internal CircleShape()
  42. : base(0)
  43. {
  44. ShapeType = ShapeType.Circle;
  45. _radius = 0.0f;
  46. _position = Vector2.Zero;
  47. }
  48. public override int ChildCount
  49. {
  50. get { return 1; }
  51. }
  52. public Vector2 Position
  53. {
  54. get { return _position; }
  55. set
  56. {
  57. _position = value;
  58. ComputeProperties();
  59. }
  60. }
  61. public override Shape Clone()
  62. {
  63. CircleShape shape = new CircleShape();
  64. shape._radius = Radius;
  65. shape._density = _density;
  66. shape._position = _position;
  67. shape.ShapeType = ShapeType;
  68. shape.MassData = MassData;
  69. return shape;
  70. }
  71. /// <summary>
  72. /// Test a point for containment in this shape. This only works for convex shapes.
  73. /// </summary>
  74. /// <param name="transform">The shape world transform.</param>
  75. /// <param name="point">a point in world coordinates.</param>
  76. /// <returns>True if the point is inside the shape</returns>
  77. public override bool TestPoint(ref Transform transform, ref Vector2 point)
  78. {
  79. Vector2 center = transform.Position + MathUtils.Multiply(ref transform.R, Position);
  80. Vector2 d = point - center;
  81. return Vector2.Dot(d, d) <= Radius * Radius;
  82. }
  83. /// <summary>
  84. /// Cast a ray against a child shape.
  85. /// </summary>
  86. /// <param name="output">The ray-cast results.</param>
  87. /// <param name="input">The ray-cast input parameters.</param>
  88. /// <param name="transform">The transform to be applied to the shape.</param>
  89. /// <param name="childIndex">The child shape index.</param>
  90. /// <returns>True if the ray-cast hits the shape</returns>
  91. public override bool RayCast(out RayCastOutput output, ref RayCastInput input, ref Transform transform,
  92. int childIndex)
  93. {
  94. // Collision Detection in Interactive 3D Environments by Gino van den Bergen
  95. // From Section 3.1.2
  96. // x = s + a * r
  97. // norm(x) = radius
  98. output = new RayCastOutput();
  99. Vector2 position = transform.Position + MathUtils.Multiply(ref transform.R, Position);
  100. Vector2 s = input.Point1 - position;
  101. float b = Vector2.Dot(s, s) - Radius * Radius;
  102. // Solve quadratic equation.
  103. Vector2 r = input.Point2 - input.Point1;
  104. float c = Vector2.Dot(s, r);
  105. float rr = Vector2.Dot(r, r);
  106. float sigma = c * c - rr * b;
  107. // Check for negative discriminant and short segment.
  108. if (sigma < 0.0f || rr < Settings.Epsilon)
  109. {
  110. return false;
  111. }
  112. // Find the point of intersection of the line with the circle.
  113. float a = -(c + (float)Math.Sqrt(sigma));
  114. // Is the intersection point on the segment?
  115. if (0.0f <= a && a <= input.MaxFraction * rr)
  116. {
  117. a /= rr;
  118. output.Fraction = a;
  119. Vector2 norm = (s + a * r);
  120. norm.Normalize();
  121. output.Normal = norm;
  122. return true;
  123. }
  124. return false;
  125. }
  126. /// <summary>
  127. /// Given a transform, compute the associated axis aligned bounding box for a child shape.
  128. /// </summary>
  129. /// <param name="aabb">The aabb results.</param>
  130. /// <param name="transform">The world transform of the shape.</param>
  131. /// <param name="childIndex">The child shape index.</param>
  132. public override void ComputeAABB(out AABB aabb, ref Transform transform, int childIndex)
  133. {
  134. Vector2 p = transform.Position + MathUtils.Multiply(ref transform.R, Position);
  135. aabb.LowerBound = new Vector2(p.X - Radius, p.Y - Radius);
  136. aabb.UpperBound = new Vector2(p.X + Radius, p.Y + Radius);
  137. }
  138. /// <summary>
  139. /// Compute the mass properties of this shape using its dimensions and density.
  140. /// The inertia tensor is computed about the local origin, not the centroid.
  141. /// </summary>
  142. public override sealed void ComputeProperties()
  143. {
  144. float area = Settings.Pi * Radius * Radius;
  145. MassData.Area = area;
  146. MassData.Mass = Density * area;
  147. MassData.Centroid = Position;
  148. // inertia about the local origin
  149. MassData.Inertia = MassData.Mass * (0.5f * Radius * Radius + Vector2.Dot(Position, Position));
  150. }
  151. public bool CompareTo(CircleShape shape)
  152. {
  153. return (Radius == shape.Radius &&
  154. Position == shape.Position);
  155. }
  156. public override float ComputeSubmergedArea(Vector2 normal, float offset, Transform xf, out Vector2 sc)
  157. {
  158. sc = Vector2.Zero;
  159. Vector2 p = MathUtils.Multiply(ref xf, Position);
  160. float l = -(Vector2.Dot(normal, p) - offset);
  161. if (l < -Radius + Settings.Epsilon)
  162. {
  163. //Completely dry
  164. return 0;
  165. }
  166. if (l > Radius)
  167. {
  168. //Completely wet
  169. sc = p;
  170. return Settings.Pi * Radius * Radius;
  171. }
  172. //Magic
  173. float r2 = Radius * Radius;
  174. float l2 = l * l;
  175. float area = r2 * (float)((Math.Asin(l / Radius) + Settings.Pi / 2) + l * Math.Sqrt(r2 - l2));
  176. float com = -2.0f / 3.0f * (float)Math.Pow(r2 - l2, 1.5f) / area;
  177. sc.X = p.X + normal.X * com;
  178. sc.Y = p.Y + normal.Y * com;
  179. return area;
  180. }
  181. }
  182. }