LineTools.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308
  1. using System;
  2. using System.Collections.Generic;
  3. using FarseerPhysics.Collision;
  4. using Microsoft.Xna.Framework;
  5. namespace FarseerPhysics.Common
  6. {
  7. /// <summary>
  8. /// Collection of helper methods for misc collisions.
  9. /// Does float tolerance and line collisions with lines and AABBs.
  10. /// </summary>
  11. public static class LineTools
  12. {
  13. public static float DistanceBetweenPointAndPoint(ref Vector2 point1, ref Vector2 point2)
  14. {
  15. Vector2 v;
  16. Vector2.Subtract(ref point1, ref point2, out v);
  17. return v.Length();
  18. }
  19. public static float DistanceBetweenPointAndLineSegment(ref Vector2 point, ref Vector2 lineEndPoint1,
  20. ref Vector2 lineEndPoint2)
  21. {
  22. Vector2 v = Vector2.Subtract(lineEndPoint2, lineEndPoint1);
  23. Vector2 w = Vector2.Subtract(point, lineEndPoint1);
  24. float c1 = Vector2.Dot(w, v);
  25. if (c1 <= 0) return DistanceBetweenPointAndPoint(ref point, ref lineEndPoint1);
  26. float c2 = Vector2.Dot(v, v);
  27. if (c2 <= c1) return DistanceBetweenPointAndPoint(ref point, ref lineEndPoint2);
  28. float b = c1 / c2;
  29. Vector2 pointOnLine = Vector2.Add(lineEndPoint1, Vector2.Multiply(v, b));
  30. return DistanceBetweenPointAndPoint(ref point, ref pointOnLine);
  31. }
  32. // From Eric Jordan's convex decomposition library
  33. /// <summary>
  34. ///Check if the lines a0->a1 and b0->b1 cross.
  35. ///If they do, intersectionPoint will be filled
  36. ///with the point of crossing.
  37. ///
  38. ///Grazing lines should not return true.
  39. ///
  40. /// </summary>
  41. /// <param name="a0"></param>
  42. /// <param name="a1"></param>
  43. /// <param name="b0"></param>
  44. /// <param name="b1"></param>
  45. /// <param name="intersectionPoint"></param>
  46. /// <returns></returns>
  47. public static bool LineIntersect2(Vector2 a0, Vector2 a1, Vector2 b0, Vector2 b1, out Vector2 intersectionPoint)
  48. {
  49. intersectionPoint = Vector2.Zero;
  50. if (a0 == b0 || a0 == b1 || a1 == b0 || a1 == b1)
  51. return false;
  52. float x1 = a0.X;
  53. float y1 = a0.Y;
  54. float x2 = a1.X;
  55. float y2 = a1.Y;
  56. float x3 = b0.X;
  57. float y3 = b0.Y;
  58. float x4 = b1.X;
  59. float y4 = b1.Y;
  60. //AABB early exit
  61. if (Math.Max(x1, x2) < Math.Min(x3, x4) || Math.Max(x3, x4) < Math.Min(x1, x2))
  62. return false;
  63. if (Math.Max(y1, y2) < Math.Min(y3, y4) || Math.Max(y3, y4) < Math.Min(y1, y2))
  64. return false;
  65. float ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3));
  66. float ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3));
  67. float denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
  68. if (Math.Abs(denom) < Settings.Epsilon)
  69. {
  70. //Lines are too close to parallel to call
  71. return false;
  72. }
  73. ua /= denom;
  74. ub /= denom;
  75. if ((0 < ua) && (ua < 1) && (0 < ub) && (ub < 1))
  76. {
  77. intersectionPoint.X = (x1 + ua * (x2 - x1));
  78. intersectionPoint.Y = (y1 + ua * (y2 - y1));
  79. return true;
  80. }
  81. return false;
  82. }
  83. //From Mark Bayazit's convex decomposition algorithm
  84. public static Vector2 LineIntersect(Vector2 p1, Vector2 p2, Vector2 q1, Vector2 q2)
  85. {
  86. Vector2 i = Vector2.Zero;
  87. float a1 = p2.Y - p1.Y;
  88. float b1 = p1.X - p2.X;
  89. float c1 = a1 * p1.X + b1 * p1.Y;
  90. float a2 = q2.Y - q1.Y;
  91. float b2 = q1.X - q2.X;
  92. float c2 = a2 * q1.X + b2 * q1.Y;
  93. float det = a1 * b2 - a2 * b1;
  94. if (!MathUtils.FloatEquals(det, 0))
  95. {
  96. // lines are not parallel
  97. i.X = (b2 * c1 - b1 * c2) / det;
  98. i.Y = (a1 * c2 - a2 * c1) / det;
  99. }
  100. return i;
  101. }
  102. /// <summary>
  103. /// This method detects if two line segments (or lines) intersect,
  104. /// and, if so, the point of intersection. Use the <paramref name="firstIsSegment"/> and
  105. /// <paramref name="secondIsSegment"/> parameters to set whether the intersection point
  106. /// must be on the first and second line segments. Setting these
  107. /// both to true means you are doing a line-segment to line-segment
  108. /// intersection. Setting one of them to true means you are doing a
  109. /// line to line-segment intersection test, and so on.
  110. /// Note: If two line segments are coincident, then
  111. /// no intersection is detected (there are actually
  112. /// infinite intersection points).
  113. /// Author: Jeremy Bell
  114. /// </summary>
  115. /// <param name="point1">The first point of the first line segment.</param>
  116. /// <param name="point2">The second point of the first line segment.</param>
  117. /// <param name="point3">The first point of the second line segment.</param>
  118. /// <param name="point4">The second point of the second line segment.</param>
  119. /// <param name="point">This is set to the intersection
  120. /// point if an intersection is detected.</param>
  121. /// <param name="firstIsSegment">Set this to true to require that the
  122. /// intersection point be on the first line segment.</param>
  123. /// <param name="secondIsSegment">Set this to true to require that the
  124. /// intersection point be on the second line segment.</param>
  125. /// <returns>True if an intersection is detected, false otherwise.</returns>
  126. public static bool LineIntersect(ref Vector2 point1, ref Vector2 point2, ref Vector2 point3, ref Vector2 point4,
  127. bool firstIsSegment, bool secondIsSegment,
  128. out Vector2 point)
  129. {
  130. point = new Vector2();
  131. // these are reused later.
  132. // each lettered sub-calculation is used twice, except
  133. // for b and d, which are used 3 times
  134. float a = point4.Y - point3.Y;
  135. float b = point2.X - point1.X;
  136. float c = point4.X - point3.X;
  137. float d = point2.Y - point1.Y;
  138. // denominator to solution of linear system
  139. float denom = (a * b) - (c * d);
  140. // if denominator is 0, then lines are parallel
  141. if (!(denom >= -Settings.Epsilon && denom <= Settings.Epsilon))
  142. {
  143. float e = point1.Y - point3.Y;
  144. float f = point1.X - point3.X;
  145. float oneOverDenom = 1.0f / denom;
  146. // numerator of first equation
  147. float ua = (c * e) - (a * f);
  148. ua *= oneOverDenom;
  149. // check if intersection point of the two lines is on line segment 1
  150. if (!firstIsSegment || ua >= 0.0f && ua <= 1.0f)
  151. {
  152. // numerator of second equation
  153. float ub = (b * e) - (d * f);
  154. ub *= oneOverDenom;
  155. // check if intersection point of the two lines is on line segment 2
  156. // means the line segments intersect, since we know it is on
  157. // segment 1 as well.
  158. if (!secondIsSegment || ub >= 0.0f && ub <= 1.0f)
  159. {
  160. // check if they are coincident (no collision in this case)
  161. if (ua != 0f || ub != 0f)
  162. {
  163. //There is an intersection
  164. point.X = point1.X + ua * b;
  165. point.Y = point1.Y + ua * d;
  166. return true;
  167. }
  168. }
  169. }
  170. }
  171. return false;
  172. }
  173. /// <summary>
  174. /// This method detects if two line segments (or lines) intersect,
  175. /// and, if so, the point of intersection. Use the <paramref name="firstIsSegment"/> and
  176. /// <paramref name="secondIsSegment"/> parameters to set whether the intersection point
  177. /// must be on the first and second line segments. Setting these
  178. /// both to true means you are doing a line-segment to line-segment
  179. /// intersection. Setting one of them to true means you are doing a
  180. /// line to line-segment intersection test, and so on.
  181. /// Note: If two line segments are coincident, then
  182. /// no intersection is detected (there are actually
  183. /// infinite intersection points).
  184. /// Author: Jeremy Bell
  185. /// </summary>
  186. /// <param name="point1">The first point of the first line segment.</param>
  187. /// <param name="point2">The second point of the first line segment.</param>
  188. /// <param name="point3">The first point of the second line segment.</param>
  189. /// <param name="point4">The second point of the second line segment.</param>
  190. /// <param name="intersectionPoint">This is set to the intersection
  191. /// point if an intersection is detected.</param>
  192. /// <param name="firstIsSegment">Set this to true to require that the
  193. /// intersection point be on the first line segment.</param>
  194. /// <param name="secondIsSegment">Set this to true to require that the
  195. /// intersection point be on the second line segment.</param>
  196. /// <returns>True if an intersection is detected, false otherwise.</returns>
  197. public static bool LineIntersect(Vector2 point1, Vector2 point2, Vector2 point3, Vector2 point4,
  198. bool firstIsSegment,
  199. bool secondIsSegment, out Vector2 intersectionPoint)
  200. {
  201. return LineIntersect(ref point1, ref point2, ref point3, ref point4, firstIsSegment, secondIsSegment,
  202. out intersectionPoint);
  203. }
  204. /// <summary>
  205. /// This method detects if two line segments intersect,
  206. /// and, if so, the point of intersection.
  207. /// Note: If two line segments are coincident, then
  208. /// no intersection is detected (there are actually
  209. /// infinite intersection points).
  210. /// </summary>
  211. /// <param name="point1">The first point of the first line segment.</param>
  212. /// <param name="point2">The second point of the first line segment.</param>
  213. /// <param name="point3">The first point of the second line segment.</param>
  214. /// <param name="point4">The second point of the second line segment.</param>
  215. /// <param name="intersectionPoint">This is set to the intersection
  216. /// point if an intersection is detected.</param>
  217. /// <returns>True if an intersection is detected, false otherwise.</returns>
  218. public static bool LineIntersect(ref Vector2 point1, ref Vector2 point2, ref Vector2 point3, ref Vector2 point4,
  219. out Vector2 intersectionPoint)
  220. {
  221. return LineIntersect(ref point1, ref point2, ref point3, ref point4, true, true, out intersectionPoint);
  222. }
  223. /// <summary>
  224. /// This method detects if two line segments intersect,
  225. /// and, if so, the point of intersection.
  226. /// Note: If two line segments are coincident, then
  227. /// no intersection is detected (there are actually
  228. /// infinite intersection points).
  229. /// </summary>
  230. /// <param name="point1">The first point of the first line segment.</param>
  231. /// <param name="point2">The second point of the first line segment.</param>
  232. /// <param name="point3">The first point of the second line segment.</param>
  233. /// <param name="point4">The second point of the second line segment.</param>
  234. /// <param name="intersectionPoint">This is set to the intersection
  235. /// point if an intersection is detected.</param>
  236. /// <returns>True if an intersection is detected, false otherwise.</returns>
  237. public static bool LineIntersect(Vector2 point1, Vector2 point2, Vector2 point3, Vector2 point4,
  238. out Vector2 intersectionPoint)
  239. {
  240. return LineIntersect(ref point1, ref point2, ref point3, ref point4, true, true, out intersectionPoint);
  241. }
  242. /// <summary>
  243. /// Get all intersections between a line segment and a list of vertices
  244. /// representing a polygon. The vertices reuse adjacent points, so for example
  245. /// edges one and two are between the first and second vertices and between the
  246. /// second and third vertices. The last edge is between vertex vertices.Count - 1
  247. /// and verts0. (ie, vertices from a Geometry or AABB)
  248. /// </summary>
  249. /// <param name="point1">The first point of the line segment to test</param>
  250. /// <param name="point2">The second point of the line segment to test.</param>
  251. /// <param name="vertices">The vertices, as described above</param>
  252. /// <param name="intersectionPoints">An list of intersection points. Any intersection points
  253. /// found will be added to this list.</param>
  254. public static void LineSegmentVerticesIntersect(ref Vector2 point1, ref Vector2 point2, Vertices vertices,
  255. ref List<Vector2> intersectionPoints)
  256. {
  257. for (int i = 0; i < vertices.Count; i++)
  258. {
  259. Vector2 point;
  260. if (LineIntersect(vertices[i], vertices[vertices.NextIndex(i)],
  261. point1, point2, true, true, out point))
  262. {
  263. intersectionPoints.Add(point);
  264. }
  265. }
  266. }
  267. /// <summary>
  268. /// Get all intersections between a line segment and an AABB.
  269. /// </summary>
  270. /// <param name="point1">The first point of the line segment to test</param>
  271. /// <param name="point2">The second point of the line segment to test.</param>
  272. /// <param name="aabb">The AABB that is used for testing intersection.</param>
  273. /// <param name="intersectionPoints">An list of intersection points. Any intersection points found will be added to this list.</param>
  274. public static void LineSegmentAABBIntersect(ref Vector2 point1, ref Vector2 point2, AABB aabb,
  275. ref List<Vector2> intersectionPoints)
  276. {
  277. LineSegmentVerticesIntersect(ref point1, ref point2, aabb.Vertices, ref intersectionPoints);
  278. }
  279. }
  280. }