IntersectionHelper.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. // -----------------------------------------------------------------------
  2. // <copyright file="IntersectionHelper.cs" company="">
  3. // Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
  4. // </copyright>
  5. // -----------------------------------------------------------------------
  6. namespace UnityEngine.U2D.Animation.TriangleNet
  7. .Tools
  8. {
  9. using Animation.TriangleNet.Geometry;
  10. internal static class IntersectionHelper
  11. {
  12. /// <summary>
  13. /// Compute intersection of two segments.
  14. /// </summary>
  15. /// <param name="p0">Segment 1 start point.</param>
  16. /// <param name="p1">Segment 1 end point.</param>
  17. /// <param name="q0">Segment 2 start point.</param>
  18. /// <param name="q1">Segment 2 end point.</param>
  19. /// <param name="c0">The intersection point.</param>
  20. /// <remarks>
  21. /// This is a special case of segment intersection. Since the calling algorithm assures
  22. /// that a valid intersection exists, there's no need to check for any special cases.
  23. /// </remarks>
  24. internal static void IntersectSegments(Point p0, Point p1, Point q0, Point q1, ref Point c0)
  25. {
  26. double ux = p1.x - p0.x;
  27. double uy = p1.y - p0.y;
  28. double vx = q1.x - q0.x;
  29. double vy = q1.y - q0.y;
  30. double wx = p0.x - q0.x;
  31. double wy = p0.y - q0.y;
  32. double d = (ux * vy - uy * vx);
  33. double s = (vx * wy - vy * wx) / d;
  34. // Intersection point
  35. c0.x = p0.X + s * ux;
  36. c0.y = p0.Y + s * uy;
  37. }
  38. /// <summary>
  39. /// Intersect segment with a bounding box.
  40. /// </summary>
  41. /// <param name="rect">The clip rectangle.</param>
  42. /// <param name="p0">Segment endpoint.</param>
  43. /// <param name="p1">Segment endpoint.</param>
  44. /// <param name="c0">The new location of p0.</param>
  45. /// <param name="c1">The new location of p1.</param>
  46. /// <returns>Returns true, if segment is clipped.</returns>
  47. /// <remarks>
  48. /// Based on Liang-Barsky function by Daniel White:
  49. /// http://www.skytopia.com/project/articles/compsci/clipping.html
  50. /// </remarks>
  51. internal static bool LiangBarsky(Rectangle rect, Point p0, Point p1, ref Point c0, ref Point c1)
  52. {
  53. // Define the x/y clipping values for the border.
  54. double xmin = rect.Left;
  55. double xmax = rect.Right;
  56. double ymin = rect.Bottom;
  57. double ymax = rect.Top;
  58. // Define the start and end points of the line.
  59. double x0 = p0.X;
  60. double y0 = p0.Y;
  61. double x1 = p1.X;
  62. double y1 = p1.Y;
  63. double t0 = 0.0;
  64. double t1 = 1.0;
  65. double dx = x1 - x0;
  66. double dy = y1 - y0;
  67. double p = 0.0, q = 0.0, r;
  68. for (int edge = 0; edge < 4; edge++)
  69. {
  70. // Traverse through left, right, bottom, top edges.
  71. if (edge == 0) { p = -dx; q = -(xmin - x0); }
  72. if (edge == 1) { p = dx; q = (xmax - x0); }
  73. if (edge == 2) { p = -dy; q = -(ymin - y0); }
  74. if (edge == 3) { p = dy; q = (ymax - y0); }
  75. r = q / p;
  76. if (p == 0 && q < 0) return false; // Don't draw line at all. (parallel line outside)
  77. if (p < 0)
  78. {
  79. if (r > t1) return false; // Don't draw line at all.
  80. else if (r > t0) t0 = r; // Line is clipped!
  81. }
  82. else if (p > 0)
  83. {
  84. if (r < t0) return false; // Don't draw line at all.
  85. else if (r < t1) t1 = r; // Line is clipped!
  86. }
  87. }
  88. c0.X = x0 + t0 * dx;
  89. c0.Y = y0 + t0 * dy;
  90. c1.X = x0 + t1 * dx;
  91. c1.Y = y0 + t1 * dy;
  92. return true; // (clipped) line is drawn
  93. }
  94. /// <summary>
  95. /// Intersect a ray with a bounding box.
  96. /// </summary>
  97. /// <param name="rect">The clip rectangle.</param>
  98. /// <param name="p0">The ray startpoint (inside the box).</param>
  99. /// <param name="p1">Any point in ray direction (NOT the direction vector).</param>
  100. /// <param name="c1">The intersection point.</param>
  101. /// <returns>Returns false, if startpoint is outside the box.</returns>
  102. internal static bool BoxRayIntersection(Rectangle rect, Point p0, Point p1, ref Point c1)
  103. {
  104. return BoxRayIntersection(rect, p0, p1.x - p0.x, p1.y - p0.y, ref c1);
  105. }
  106. /// <summary>
  107. /// Intersect a ray with a bounding box.
  108. /// </summary>
  109. /// <param name="rect">The clip rectangle.</param>
  110. /// <param name="p">The ray startpoint (inside the box).</param>
  111. /// <param name="dx">X direction.</param>
  112. /// <param name="dy">Y direction.</param>
  113. /// <returns>Returns false, if startpoint is outside the box.</returns>
  114. internal static Point BoxRayIntersection(Rectangle rect, Point p, double dx, double dy)
  115. {
  116. var intersection = new Point();
  117. if (BoxRayIntersection(rect, p, dx, dy, ref intersection))
  118. {
  119. return intersection;
  120. }
  121. return null;
  122. }
  123. /// <summary>
  124. /// Intersect a ray with a bounding box.
  125. /// </summary>
  126. /// <param name="rect">The clip rectangle.</param>
  127. /// <param name="p">The ray startpoint (inside the box).</param>
  128. /// <param name="dx">X direction.</param>
  129. /// <param name="dy">Y direction.</param>
  130. /// <param name="c">The intersection point.</param>
  131. /// <returns>Returns false, if startpoint is outside the box.</returns>
  132. internal static bool BoxRayIntersection(Rectangle rect, Point p, double dx, double dy, ref Point c)
  133. {
  134. double x = p.X;
  135. double y = p.Y;
  136. double t1, x1, y1, t2, x2, y2;
  137. // Bounding box
  138. double xmin = rect.Left;
  139. double xmax = rect.Right;
  140. double ymin = rect.Bottom;
  141. double ymax = rect.Top;
  142. // Check if point is inside the bounds
  143. if (x < xmin || x > xmax || y < ymin || y > ymax)
  144. {
  145. return false;
  146. }
  147. // Calculate the cut through the vertical boundaries
  148. if (dx < 0)
  149. {
  150. // Line going to the left: intersect with x = minX
  151. t1 = (xmin - x) / dx;
  152. x1 = xmin;
  153. y1 = y + t1 * dy;
  154. }
  155. else if (dx > 0)
  156. {
  157. // Line going to the right: intersect with x = maxX
  158. t1 = (xmax - x) / dx;
  159. x1 = xmax;
  160. y1 = y + t1 * dy;
  161. }
  162. else
  163. {
  164. // Line going straight up or down: no intersection possible
  165. t1 = double.MaxValue;
  166. x1 = y1 = 0;
  167. }
  168. // Calculate the cut through upper and lower boundaries
  169. if (dy < 0)
  170. {
  171. // Line going downwards: intersect with y = minY
  172. t2 = (ymin - y) / dy;
  173. x2 = x + t2 * dx;
  174. y2 = ymin;
  175. }
  176. else if (dy > 0)
  177. {
  178. // Line going upwards: intersect with y = maxY
  179. t2 = (ymax - y) / dy;
  180. x2 = x + t2 * dx;
  181. y2 = ymax;
  182. }
  183. else
  184. {
  185. // Horizontal line: no intersection possible
  186. t2 = double.MaxValue;
  187. x2 = y2 = 0;
  188. }
  189. if (t1 < t2)
  190. {
  191. c.x = x1;
  192. c.y = y1;
  193. }
  194. else
  195. {
  196. c.x = x2;
  197. c.y = y2;
  198. }
  199. return true;
  200. }
  201. }
  202. }