【问题标题】:How can I tell if two polygons intersect?如何判断两个多边形是否相交?
【发布时间】:2011-04-06 15:09:30
【问题描述】:

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

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

任何建议将不胜感激。

莫什

【问题讨论】:

    标签: c# polygon intersection system.drawing


    【解决方案1】:

    如果你的多边形是凸的,那么你应该可以使用separating axis theorem。 here 有一个演示可用(它在 actionscript 中,但代码应该很容易移植到 c#)

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

    【讨论】:

      【解决方案2】:

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

      我还回答了这个问题here,它处理 C# 中的 2D 碰撞。​​

      【讨论】:

        【解决方案3】:

        严格来说,建议算法的其他答案可能是您最好的选择。但抛开性能不谈,您提到您找不到类似 IntersectsWith 用于 GraphicsPath 或 Region 的东西。但是,有一种 Intersect 方法可以将区域更新为自身与另一个区域或路径的交集。您可以创建两个区域,Intersect() 一个与另一个区域,然后测试 Region.IsEmpty()。

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

        【讨论】:

        • 令人惊讶的是,如果两者不相交,我并没有注意到减速。只有当区域相交时,才会出现明显的放缓。 (不过,我正在测试的区域并不是特别复杂。)
        【解决方案4】:

        这是一个老问题,但我想我也会分享我的解决方案。 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<List<IntPoint>> ConvertToClipperPolygons(GraphicsPath path)
            {
                var Polygon = new List<IntPoint>();
                var Polygons = new List<List<IntPoint>>();
        
                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<IntPoint>(Points.Select(x => new IntPoint(Convert.ToInt64(x.X * scale), Convert.ToInt64(x.Y * scale)))));
        
                }
                it.Dispose();
                return Polygons;
            }
        

        并执行交集

                public static GraphicsPath intersect(ref GraphicsPath p1, ref GraphicsPath p2)
            {
                List<List<IntPoint>> polygonB = ConvertToClipperPolygons(p1);
                List<List<IntPoint>> polygons = new List<List<IntPoint>>();
                List<List<IntPoint>> 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<List<IntPoint>> path)
            {
                GraphicsPath returnPath = new GraphicsPath();
        
                for (int i = 0; i < path.Count; i++)
                {
                    returnPath.AddPolygon(ToPointList(path[i]).ToArray());
                }
                return returnPath;
            }
                private static List<PointF> ToPointList(List<IntPoint> pointList)
            {
        
                List<PointF> newList = new List<PointF>();
                foreach (IntPoint pt in pointList)
                {
                    newList.Add(new PointF(((float)pt.X / (float)scale), ((float)pt.Y / (float)scale)));
                }
        
                return newList;
            }
        

        【讨论】:

          猜你喜欢
          • 2011-10-30
          • 1970-01-01
          • 2010-10-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-02-01
          • 2011-02-25
          • 1970-01-01
          相关资源
          最近更新 更多