如何交叉两个多边形?

时间:2009-10-06 15:29:49

标签: c# polygon intersection

这似乎并不重要(在各种论坛上都会有很多问题),但我绝对需要将它作为更复杂算法的构建块。

输入:2D中的2个多边形(A和B),每个边框列出[(x0, y0, x1, y2), ...]。这些点由成对的double s表示。我不知道它们是顺时针,逆时针还是任何方向。我知道它们不一定是凸的。

输出:表示A,B和交叉多边形AB的3个多边形。其中任何一个都可以是空的(?)多边形,例如null

提示优化:这些多边形代表房间和楼层边界。所以房间边界通常与地面边界完全相交,除非它属于同一平面上的另一层(argh!)。

我有点希望有人已经在c#中完成了这项工作并让我使用他们的策略/代码,因为到目前为止我在这个问题上找到的内容相当令人生畏。

编辑:所以看起来我并不完全是鸡,因为这样做的前景微弱。我想在这里重述所需的输出,因为这是一个特殊情况,可能会使计算更简单:

输出:第一个多边形减去所有相交的位,交叉多边形(复数是正常的)。我对第二个多边形并不感兴趣,只是它与第一个多边形的交集。

EDIT2 :我目前正在使用GPC (General Polygon Clipper)库,这非常容易!

9 个答案:

答案 0 :(得分:17)

Arash Partow的FastGEO库包含计算几何中许多有趣算法的实现。多边形交叉点就是其中之一。它是用Pascal编写的,但它只是实现数学所以它非常易读。请注意,您肯定需要稍微预处理边缘,以使它们顺时针或逆时针顺序。

ETA:但实际上,最好的方法就是不要这样做。找到另一种方法来解决不涉及任意多边形交叉的问题。

答案 1 :(得分:12)

如果您使用.NET Framework进行编程,您可能需要查看.NET程序集中提供的SqlGeometry类Microsoft SQL Server System CLR Types

SqlGeometry类提供STIntersection方法

SqlGeometry g1 = SqlGeometry.Parse("POLYGON ((...))");
SqlGeometry g2 = SqlGeometry.Parse("POLYGON ((...))");
SqlGeometry intersection = g1.STIntersection(g2);

答案 2 :(得分:10)

我认为你应该做什么

如果您可以提供帮助,请不要尝试自己动手。相反,请使用已存在的许多可用多边形交集算法之一。

我强烈考虑以下代码库,因为他们的演示代码以及他们提到他们处理大多数/所有奇怪案例的事实。如果您在商业上使用它,您需要捐赠一定数量(由您/您公司选择),但是获得此类代码的强大版本是值得的。

http://www.cs.man.ac.uk/~toby/gpc/

我实际上做的是使用作为Java2D库一部分的多边形交集算法。您可以在MS自己的C#库中找到类似的东西。

还有其他选择;寻找“多边形裁剪器”或“多边形裁剪”,因为处理多边形交叉的相同基本算法也可用于一般裁剪情况。

一旦你真的有了一个多边形裁剪库,你只需要从多边形A中减去多边形B来获得你的第一个输出,并交叉多边形A和B来得到你的第二个输出。

如何滚动自己,为无望的自虐

当我考虑自己动手时,我发现Weiler-Atherton算法最有可能进行一般多边形切割。我使用以下作为参考:

http://cs1.bradley.edu/public/jcm/weileratherton.html

http://en.wikipedia.org/wiki/Weiler-Atherton

正如他们所说,细节过于密集而无法包括在内,但毫无疑问,您将能够在未来几年内找到Weiler-Atherton的参考资料。基本上,您将所有点分成那些进入最终多边形或退出最终多边形的点,然后从所有点中形成一个图形,然后沿适当的方向走图形以提取所有多边形块想。通过更改定义和处理“输入”和“退出”多边形的方式,可以实现多个可能的多边形交叉(AND,OR,XOR等)。

它实际上是相当可行的,但与任何计算几何代码一样,魔鬼也在退化。

答案 3 :(得分:2)

您可能还想查看NetTopologySuite,或者甚至尝试将其导入Sql server 2008&这是空间工具。

答案 4 :(得分:2)

如果您敢于查看其他人的GPL C ++代码,您可以在Inkscape中看到他们是如何做到的:

http://bazaar.launchpad.net/~inkscape.dev/inkscape/trunk/view/head:/src/2geom/shape.cpp(第126行)

答案 5 :(得分:2)

多边形由点的有序列表(P1,P2,...,Pn)完整描述。边缘是(P1-P2),(P2-P3),......,(Pn-P1)。如果有两个重叠的多边形A和B,则会有一个点An(来自描述多边形A的点上的列表)位于由多边形B包围的区域内,反之亦然(B的一个点位于A中)。如果没有找到这样的点,则多边形不重叠。如果找到这样的点(即Ai),则检查多边形A(i-1)和A(i + 1)的相邻点。重复直到在区域外找到一个点或检查所有点(然后第一个多边形完全位于第二个多边形内)。如果您在外面找到了一个点,那么您可以计算交叉点。找到多边形B的相应边缘并使用resersed roles跟随它=现在检查多边形B的点是否位于多边形A内。这样,您可以构建描述重叠多边形的点列表。如果需要,你应该检查多边形是否相同,(P1,P2,P3)===(P2,P3,P1)。

这只是一个想法,可能有更好的方法。如果您找到了经过测试的工作解决方案,我建议您使用它......

narozed

答案 6 :(得分:2)

尝试使用GIS工具,例如ArcObjects,TopologySuite,GEOS,OGR等。我不确定所有这些发行版是否都可用于.net,但它们都是一样的。

答案 7 :(得分:2)

Clipper是一个开源免费软件多边形剪辑库(用Delphi和C ++编写),完全符合您的要求 - http://sourceforge.net/projects/polyclipping/

在我的测试中,Clipper比GPC明显更快且更不容易出错(请参阅此处更详细的比较 - http://www.angusj.com/delphi/clipper.php#features)。此外,虽然有Delphi和C ++的源代码,但Clipper库还包含一个已编译的DLL,以便在其他(Windows)语言中使用剪辑功能也非常容易。

答案 8 :(得分:2)

academic paper解释了如何执行此操作。