Line2D.cs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6. namespace bbiwarg.Utility
  7. {
  8. public enum LineSide {
  9. onLine = 0,
  10. above = 1,
  11. below = 2
  12. }
  13. class Line2D
  14. {
  15. private Vector2D p1;
  16. private Vector2D p2;
  17. private Vector2D direction;
  18. private float length;
  19. private int numCombinedLines;
  20. public Vector2D P1 { get { return p1; } private set { p1 = value; } }
  21. public Vector2D P2 { get { return p2; } private set { p2 = value; } }
  22. public Vector2D Direction { get { return direction; } private set { direction = value; } }
  23. public float Length { get { return length; } private set { length = value; } }
  24. public int NumCombinedLines { get { return numCombinedLines; } private set { numCombinedLines = value; } }
  25. public Line2D(Vector2D p1, Vector2D p2) {
  26. setPoints(p1, p2);
  27. NumCombinedLines = 1;
  28. }
  29. public Line2D(List<Line2D> lines) {
  30. //list all points
  31. List<Vector2D> points = new List<Vector2D>();
  32. List<Vector2D> directions = new List<Vector2D>();
  33. NumCombinedLines = 0;
  34. foreach (Line2D line in lines) {
  35. points.Add(line.P1);
  36. points.Add(line.P2);
  37. directions.Add(line.Direction);
  38. NumCombinedLines += line.NumCombinedLines;
  39. }
  40. //find two points with max-distance
  41. Vector2D a = points[0];
  42. Vector2D b = points[0];
  43. float length = 0;
  44. foreach (Vector2D p in points) {
  45. float distanceToA = p.getDistanceTo(a);
  46. float distanceToB = p.getDistanceTo(b);
  47. if (distanceToA > length && distanceToA >= distanceToB) {
  48. b = p;
  49. length = distanceToA;
  50. }
  51. else if (distanceToB > length && distanceToB > distanceToA) {
  52. a = p;
  53. length = distanceToA;
  54. }
  55. }
  56. //project a and b on mean-line
  57. Vector2D meanPoint = Vector2D.mean(points);
  58. Vector2D meanDirection = Vector2D.mean(directions);
  59. Line2D meanLine = new Line2D(meanPoint, meanPoint + meanDirection);
  60. Vector2D meanA = meanLine.projectToLine(a);
  61. Vector2D meanB = meanLine.projectToLine(b);
  62. setPoints(meanA, meanB);
  63. }
  64. private void setPoints(Vector2D p1, Vector2D p2) {
  65. //endpoints
  66. P1 = p1;
  67. P2 = p2;
  68. //direction
  69. direction = (P1-P2).normalize();
  70. //length
  71. Length = P1.getDistanceTo(P2);
  72. }
  73. public float getAngleBetween(Line2D line) {
  74. float angle = direction.getAngleBetween(line.Direction);
  75. return Math.Min(angle, 180-angle);
  76. }
  77. public float getParallelDistanceTo(Line2D line) {
  78. if (onSide(line.P1) != onSide(line.P2)) return 0;
  79. Vector2D a1 = projectToLine(line.P1);
  80. Vector2D a2 = projectToLine(line.P2);
  81. float distanceA1 = a1.getDistanceTo(line.P1);
  82. float distanceA2 = a2.getDistanceTo(line.P2);
  83. return Math.Min(distanceA1, distanceA2);
  84. }
  85. public float getVerticalDistanceTo(Line2D line) {
  86. Vector2D a1 = projectToLine(line.P1);
  87. Vector2D a2 = projectToLine(line.P2);
  88. if (P1.isInBox(a1, a2) || P2.isInBox(a1, a2)) return 0;
  89. float distanceP1A1 = P1.getDistanceTo(a1);
  90. float distanceP1A2 = P1.getDistanceTo(a2);
  91. float distanceP2A1 = p2.getDistanceTo(a1);
  92. float distanceP2A2 = p2.getDistanceTo(a2);
  93. return Math.Min(Math.Min(distanceP1A1, distanceP1A2), Math.Min(distanceP2A1, distanceP2A2));
  94. }
  95. public LineSide onSide(Vector2D point) {
  96. float yPerX = direction.Y / direction.X;
  97. float xDiff = point.X - P1.X;
  98. float newY = P1.Y + yPerX * xDiff;
  99. if (newY < point.Y) return LineSide.above;
  100. else if (newY > point.Y) return LineSide.below;
  101. else return LineSide.onLine;
  102. }
  103. public Vector2D projectToLine(Vector2D point) {
  104. float px = point.X, py = point.Y, dx = Direction.X, dy = Direction.Y, ox = P1.X, oy = P1.Y;
  105. float diffx = px - ox;
  106. float diffy = py - oy;
  107. float diff_d = (diffx * dx + diffy * dy);
  108. float d_d = (dx * dx + dy * dy);
  109. float q = diff_d / d_d;
  110. float newX = ox + q * dx;
  111. float newY = oy + q * dy;
  112. return new Vector2D(newX, newY);
  113. }
  114. public override string ToString()
  115. {
  116. return (int)P1.X + "|" + (int)P1.Y + " --- " + (int)P2.X + "|" + (int)P2.Y;
  117. }
  118. }
  119. }