LineSegment2D.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. using System;
  2. namespace BBIWARG.Utility
  3. {
  4. /// <summary>
  5. /// Class to represent a segment of a line, a line between two points.
  6. /// </summary>
  7. public class LineSegment2D
  8. {
  9. /// <summary>
  10. /// direction vector of the line which contains the lineSegment
  11. /// </summary>
  12. public Vector2D Direction { get { return Line.Direction; } }
  13. /// <summary>
  14. /// length of the LineSegment
  15. /// </summary>
  16. public float Length { get; private set; }
  17. /// <summary>
  18. /// line which contains the lineSegment
  19. /// </summary>
  20. public Line2D Line { get; private set; }
  21. /// <summary>
  22. /// first point of the lineSegment
  23. /// </summary>
  24. public Vector2D P1 { get; private set; }
  25. /// <summary>
  26. /// second point of the lineSegment
  27. /// </summary>
  28. public Vector2D P2 { get; private set; }
  29. /// <summary>
  30. /// Standard constructor which sets the essential attributes.
  31. /// </summary>
  32. /// <param name="p1">first point of LineSegment<see cref="P1"/></param>
  33. /// <param name="p2">second point of LineSegment<see cref="P2"/></param>
  34. public LineSegment2D(Vector2D p1, Vector2D p2)
  35. {
  36. // endpoints
  37. P1 = p1;
  38. P2 = p2;
  39. Line = new Line2D(P1, P2 - P1);
  40. Length = P1.getDistanceTo(P2);
  41. }
  42. /// <summary>
  43. /// Computes the shortest distance of a point to the LineSegment.
  44. /// </summary>
  45. /// <param name="point">the point for distance calculation</param>
  46. /// <returns>the distance</returns>
  47. public float getDistanceTo(Vector2D point)
  48. {
  49. // http://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment
  50. float l2 = (P1 - P2).dotProduct(P1 - P2); // i.e. |w-v|^2 - avoid a sqrt
  51. if (l2 == 0.0)
  52. return point.getDistanceTo(P1); // v == w case
  53. // Consider the line extending the segment, parameterized as v + t (w - v).
  54. // We find projection of point p onto the line.
  55. // It falls where t = [(p-v) . (w-v)] / |w-v|^2
  56. float t = (point - P1).dotProduct(P2 - P1) / l2;
  57. if (t < 0.0)
  58. return point.getDistanceTo(P1); // Beyond the 'v' end of the segment
  59. else if (t > 1.0)
  60. return point.getDistanceTo(P2); // Beyond the 'w' end of the segment
  61. Vector2D projection = P1 + t * (P2 - P1); // Projection falls on the segment
  62. return point.getDistanceTo(projection);
  63. }
  64. /// <summary>
  65. /// Computes the Distance of two parallel LineSegments, iff they are not parallel it returns 0.
  66. /// </summary>
  67. /// <param name="line">second LineSegment</param>
  68. /// <returns>Distance between the LineSegment</returns>
  69. public float getParallelDistanceTo(LineSegment2D line)
  70. {
  71. if (Line.onSide(line.P1) != Line.onSide(line.P2)) return 0;
  72. Vector2D a1 = Line.projectToLine(line.P1);
  73. Vector2D a2 = Line.projectToLine(line.P2);
  74. float distanceA1 = a1.getDistanceTo(line.P1);
  75. float distanceA2 = a2.getDistanceTo(line.P2);
  76. return Math.Min(distanceA1, distanceA2);
  77. }
  78. /// <summary>
  79. /// Computes the vertical distance between two lineSegments. the vertical distance is the minimal distance between the LineSegments after they are projected on a horizontal line.
  80. /// </summary>
  81. /// <param name="line">second LineSegment</param>
  82. /// <returns>the vertical distance</returns>
  83. public float getVerticalDistanceTo(LineSegment2D line)
  84. {
  85. Vector2D a1 = Line.projectToLine(line.P1);
  86. Vector2D a2 = Line.projectToLine(line.P2);
  87. if (P1.isInBox(a1, a2) || P2.isInBox(a1, a2)) return 0;
  88. float distanceP1A1 = P1.getDistanceTo(a1);
  89. float distanceP1A2 = P1.getDistanceTo(a2);
  90. float distanceP2A1 = P2.getDistanceTo(a1);
  91. float distanceP2A2 = P2.getDistanceTo(a2);
  92. return Math.Min(Math.Min(distanceP1A1, distanceP1A2), Math.Min(distanceP2A1, distanceP2A2));
  93. }
  94. /// <summary>
  95. /// Computes the intersection of two LineSegments, iff they do not intersect returns null.
  96. /// </summary>
  97. /// <param name="ls">second LineSegment</param>
  98. /// <returns>Intersection iff its defined, else null</returns>
  99. public bool intersectsWith(LineSegment2D ls)
  100. {
  101. Vector2D intersection = Line.getIntersection(ls.Line);
  102. return intersection != null && intersection.isInBox(P1, P2) && intersection.isInBox(ls.P1, ls.P2);
  103. }
  104. /// <summary>
  105. /// Returns a <see cref="System.String" /> that represents this instance.
  106. /// </summary>
  107. /// <returns>
  108. /// A <see cref="System.String" /> that represents this instance.
  109. /// </returns>
  110. public override string ToString()
  111. {
  112. return (int)P1.X + "|" + (int)P1.Y + " --- " + (int)P2.X + "|" + (int)P2.Y;
  113. }
  114. }
  115. }