c# – 用于查找重叠两个共线段的段的算法

前端之家收集整理的这篇文章主要介绍了c# – 用于查找重叠两个共线段的段的算法前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
更新

>我在C#中的原始实现
>我在C#中的最终实现,基于我得到的答案.

鉴于以下条件,我如何以编程方式找到两条线之间的重叠段?

另外,对于不同的斜率:

对于垂直线:

对于水平线:

注意:对于所有象限!

我从编码所有可能的条件开始,但它变得丑陋.

  1. public Line GetOverlap (Line line1,Line line2)
  2. {
  3. double line1X1 = line1.X1;
  4. double line1Y1 = line1.Y1;
  5. double line1X2 = line1.X2;
  6. double line1Y2 = line1.Y2;
  7. double line2X1 = line2.X1;
  8. double line2Y1 = line2.Y1;
  9. double line2X2 = line2.X2;
  10. double line2Y2 = line2.Y2;
  11.  
  12. if (line1X1 > line1X2)
  13. {
  14. double swap = line1X1;
  15. line1X1 = line1X2;
  16. line1X2 = swap;
  17.  
  18. swap = line1Y1;
  19. line1Y1 = line1Y2;
  20. line1Y2 = swap;
  21. }
  22. else if (line1X1.AlmostEqualTo (line1X2))
  23. {
  24. if (line1Y1 > line1Y2)
  25. {
  26. double swap = line1Y1;
  27. line1Y1 = line1Y2;
  28. line1Y2 = swap;
  29.  
  30. swap = line1X1;
  31. line1X1 = line1X2;
  32. line1X2 = swap;
  33. }
  34. }
  35.  
  36. if (line2X1 > line2X2)
  37. {
  38. double swap = line2X1;
  39. line2X1 = line2X2;
  40. line2X2 = swap;
  41.  
  42. swap = line2Y1;
  43. line2Y1 = line2Y2;
  44. line2Y2 = swap;
  45. }
  46. else if (line2X1.AlmostEqualTo (line2X2))
  47. {
  48. if (line2Y1 > line2Y2)
  49. {
  50. double swap = line2Y1;
  51. line2Y1 = line2Y2;
  52. line2Y2 = swap;
  53.  
  54. swap = line2X1;
  55. line2X1 = line2X2;
  56. line2X2 = swap;
  57. }
  58. }
  59.  
  60. double line1MinX = Math.Min (line1X1,line1X2);
  61. double line2MinX = Math.Min (line2X1,line2X2);
  62. double line1MinY = Math.Min (line1Y1,line1Y2);
  63. double line2MinY = Math.Min (line2Y1,line2Y2);
  64. double line1MaxX = Math.Max (line1X1,line1X2);
  65. double line2MaxX = Math.Max (line2X1,line2X2);
  66. double line1MaxY = Math.Max (line1Y1,line1Y2);
  67. double line2MaxY = Math.Max (line2Y1,line2Y2);
  68.  
  69. double overlap;
  70. if (line1MinX < line2MinX)
  71. overlap = Math.Max (line1X1,line1X2) - line2MinX;
  72. else
  73. overlap = Math.Max (line2X1,line2X2) - line1MinX;
  74.  
  75. if (overlap <= 0)
  76. return null;
  77.  
  78. double x1;
  79. double y1;
  80. double x2;
  81. double y2;
  82.  
  83. if (line1MinX.AlmostEqualTo (line2MinX))
  84. {
  85. x1 = line1X1;
  86. x2 = x1;
  87. y1 = line1MinY < line2MinY
  88. ? line2Y1
  89. : line1Y1;
  90. y2 = line1MaxY < line2MaxY
  91. ? line1Y2
  92. : line2Y2;
  93. }
  94. else
  95. {
  96. if (line1MinX < line2MinX)
  97. {
  98. x1 = line2X1;
  99. y1 = line2Y1;
  100. }
  101. else
  102. {
  103. x1 = line1X1;
  104. y1 = line1Y1;
  105. }
  106.  
  107. if (line1MaxX > line2MaxX)
  108. {
  109. x2 = line2X2;
  110. y2 = line2Y2;
  111. }
  112. else
  113. {
  114. x2 = line1X2;
  115. y2 = line1Y2;
  116. }
  117. }
  118.  
  119. return new Line (x1,y1,x2,y2);
  120. }

我确定存在一个算法,但我无法在网上找到一个.

根据我得到的答案更新解决方案:

这个解决方案解释了我能想到的所有情况(垂直,水平,正斜率,负斜率,不相交)

  1. public Line GetOverlap (Line line1,Line line2)
  2. {
  3. double slope = (line1.Y2 - line1.Y1)/(line1.X2 - line1.X1);
  4. bool isHorizontal = AlmostZero (slope);
  5. bool isDescending = slope < 0 && !isHorizontal;
  6. double invertY = isDescending || isHorizontal ? -1 : 1;
  7.  
  8. Point min1 = new Point (Math.Min (line1.X1,line1.X2),Math.Min (line1.Y1*invertY,line1.Y2*invertY));
  9. Point max1 = new Point (Math.Max (line1.X1,Math.Max (line1.Y1*invertY,line1.Y2*invertY));
  10.  
  11. Point min2 = new Point (Math.Min (line2.X1,line2.X2),Math.Min (line2.Y1*invertY,line2.Y2*invertY));
  12. Point max2 = new Point (Math.Max (line2.X1,Math.Max (line2.Y1*invertY,line2.Y2*invertY));
  13.  
  14. Point minIntersection;
  15. if (isDescending)
  16. minIntersection = new Point (Math.Max (min1.X,min2.X),Math.Min (min1.Y*invertY,min2.Y*invertY));
  17. else
  18. minIntersection = new Point (Math.Max (min1.X,Math.Max (min1.Y*invertY,min2.Y*invertY));
  19.  
  20. Point maxIntersection;
  21. if (isDescending)
  22. maxIntersection = new Point (Math.Min (max1.X,max2.X),Math.Max (max1.Y*invertY,max2.Y*invertY));
  23. else
  24. maxIntersection = new Point (Math.Min (max1.X,Math.Min (max1.Y*invertY,max2.Y*invertY));
  25.  
  26. bool intersect = minIntersection.X <= maxIntersection.X &&
  27. (!isDescending && minIntersection.Y <= maxIntersection.Y ||
  28. isDescending && minIntersection.Y >= maxIntersection.Y);
  29.  
  30. if (!intersect)
  31. return null;
  32.  
  33. return new Line (minIntersection,maxIntersection);
  34. }
  35.  
  36. public bool AlmostEqualTo (double value1,double value2)
  37. {
  38. return Math.Abs (value1 - value2) <= 0.00001;
  39. }
  40.  
  41. public bool AlmostZero (double value)
  42. {
  43. return Math.Abs (value) <= 0.00001;
  44. }

解决方法

这个问题大致相当于测试两个轴对齐的矩形是否相交:你可以威胁每个段作为轴对齐矩形的对角线,然后你需要找到这两个矩形的交点.以下是我用于矩形交叉的方法.

让我们假设段的斜率是上升的,垂直的或水平的;如果段正在下降,则否定每个y坐标以使它们上升.

为每个线段定义MinPoint和MaxPoint:

  1. Point min1 = new Point(Math.Min(line1.X1,Math.Min(line1.Y1,line1.Y2);
  2. Point max1 = new Point(Math.Max(line1.X1,Math.Max(line1.Y1,line1.Y2);
  3.  
  4. Point min2 = new Point(Math.Min(line2.X1,Math.Min(line2.Y1,line2.Y2);
  5. Point max2 = new Point(Math.Max(line2.X1,Math.Max(line2.Y1,line2.Y2);

现在交叉点由以下两点给出:两个最小值的最大值,以及两个最大值的最小值

  1. Point minIntersection = new Point(Math.Max(min1.X,Math.Max(min1.Y,min2.Y));
  2. Point maxIntersection = new Point(Math.Min(max1.X,Math.Min(max1.Y,max2.Y));

就是这样.要检查两个段是否相交,请检查

  1. bool intersect = (minIntersection.X< maxIntersection.X) && (minIntersection.Y< maxIntersection.Y);

如果它们相交,则交点由minIntersection和maxIntersection两个点给出.如果它们不相交,则段的长度(minIntersection,maxIntersection)是两个原始段之间的距离.

(如果在第一步中否定了每个y坐标,则现在否定结果的y坐标)

(您可以轻松扩展此方法以覆盖3个或更多维度的共线段)

猜你在找的C#相关文章