如何判断两个多边形是否相交?

想象一下,我有4个点的坐标,形成一个多边形。 这些点在C#中使用PointF表示。 如果我有2个多边形(使用8个点),我怎么知道它们是否相交?

Rectangle类有一个名为IntersectsWith的方法,但我找不到类似于GraphicsPath或Region的东西。

任何建议将不胜感激。

MOSH

正如查理已经指出的那样你可以使用分离轴定理。 查看本文了解C#实现和多边形碰撞检测示例。

我在这里也回答了这个问题,它涉及C#中的2D碰撞。

严格地说,提出算法的其他答案可能是你最好的选择。 但是除了性能之外,你提到你找不到像GraphicsPath或Region这样的IntersectsWith。 但是,有一种Intersect方法可以将区域更新为自身与另一个区域或路径的交集。 你可以创建两个区域, Intersect ()一个与另一个区域,然后测试Region.IsEmpty ()。

但我想这可能是一种非常缓慢的方法,如果在循环中完成,可能会导致很多分配。

如果您的多边形是凸的,那么您应该能够使用分离轴定理 。 这里有一个演示(它在actionscript中,但代码应该很容易移植到c#)

这真的不是我的领域,但我希望它无论如何都有帮助。

这是一个老问题,但我想我也会分享我的解决方案。 Region.IsEmpty()需要一个Graphics上下文,据我所知,它仅用于执行像素精度命中测试。 这对许多情况来说并不理想。 更好的解决方案是使用Angus Johnson的Clipper库。 根据我的经验,这是一个快速测试的库。 您可以提供自己的精度,它可以处理极其复杂的多边形。

http://www.angusj.com/delphi/clipper.php

有一个C#实现。 您需要做的是执行交叉操作,就像System.Drawing.Region方法一样。 然后检查操作的结果。 如果它是空的,则没有交叉点。 如果它包含数据,则数据是交叉点。

http://www.angusj.com/delphi/clipper/documentation/Docs/Units/ClipperLib/Types/ClipType.htm

您会发现一些对此有用的方法。

private static int scale = 1000; //your desired precision public static List> ConvertToClipperPolygons(GraphicsPath path) { var Polygon = new List(); var Polygons = new List>(); var it = new GraphicsPathIterator(path); it.Rewind(); bool isClosed; int startIndex; int endIndex; for (int i = 0; i < it.SubpathCount; i++) { var PointCount = it.NextSubpath(out startIndex, out endIndex, out isClosed); var Points = new PointF[PointCount]; var Types = new byte[PointCount]; it.CopyData(ref Points, ref Types, startIndex, endIndex); Polygons.Add(new List(Points.Select(x => new IntPoint(Convert.ToInt64(xX * scale), Convert.ToInt64(xY * scale))))); } it.Dispose(); return Polygons; } 

并执行一个交集

  public static GraphicsPath intersect(ref GraphicsPath p1, ref GraphicsPath p2) { List> polygonB = ConvertToClipperPolygons(p1); List> polygons = new List>(); List> polygonA = ConvertToClipperPolygons(p2); Clipper c = new Clipper(); c.AddPolygons(polygonB, PolyType.ptSubject); c.AddPolygons(polygonA, PolyType.ptClip); c.Execute(ClipType.ctIntersection, polygons, PolyFillType.pftEvenOdd, PolyFillType.pftEvenOdd); return ConvertClipperToGraphicsPath(polygons); } public static GraphicsPath ConvertClipperToGraphicsPath(List> path) { GraphicsPath returnPath = new GraphicsPath(); for (int i = 0; i < path.Count; i++) { returnPath.AddPolygon(ToPointList(path[i]).ToArray()); } return returnPath; } private static List ToPointList(List pointList) { List newList = new List(); foreach (IntPoint pt in pointList) { newList.Add(new PointF(((float)pt.X / (float)scale), ((float)pt.Y / (float)scale))); } return newList; }