我正在寻找一种计算多边形交叉/剪裁的非常简单的算法。
也就是说,给定多边形P
,Q
,我希望找到包含在T
和P
中的多边形Q
,我希望{{1在所有可能的多边形中最大化。
我不介意运行时间(我有一些非常小的多边形),我也可以得到一个近似的多边形的交叉点(也就是说,一个点数较少的多边形,但它仍包含在多边形的交集。)
但对我来说,算法很简单(测试更便宜),最好是短(代码少)。
编辑请注意,我希望获得一个代表交叉点的多边形。对于两个多边形是否相交的问题,我不需要一个布尔答案。
答案 0 :(得分:50)
我理解原始海报正在寻找一个简单的解决方案,但不幸的是,确实没有简单的解决方案。
尽管如此,我最近创建了一个开源免费软件剪辑库(用Delphi,C ++和C#编写),它可以剪切各种多边形(包括自相交的多边形)。这个库非常易于使用:http://sourceforge.net/projects/polyclipping/。
答案 1 :(得分:17)
您可以使用多边形裁剪算法来查找两个多边形之间的交集。然而,当考虑所有边缘情况时,这些算法往往是复杂的算法。
您可以使用自己喜欢的搜索引擎查找的多边形裁剪的一个实现是 Weiler-Atherton 。 wikipedia article on Weiler-Atherton
Alan Murta完全实现了多边形裁剪器GPC。
编辑:
另一种方法是首先将每个多边形划分为一组三角形,这些三角形更容易处理。 Gary H. Meisters的 Two-Ears Theorem 可以解决问题。这个page at McGill在解释三角形细分方面做得很好。
答案 2 :(得分:12)
如果您使用C ++,并且不想自己创建算法,则可以使用Boost.Geometry。它使用了上面提到的Weiler-Atherton算法的改编版本。
答案 3 :(得分:6)
您尚未向我们提供多边形的表示。所以我选择(更像是建议)一个给你:)
将每个多边形表示为一个大的凸多边形,以及需要从该大凸多边形“减去”的较小凸多边形的列表。
现在给出了该表示中的两个多边形,您可以将交集计算为:
计算大凸多边形的交点以形成交点的大多边形。然后'减去'两者中所有较小的交点,得到一个减去的多边形列表。
您将获得一个遵循相同表示的新多边形。
由于凸多边形交叉很容易,这个交点发现也应该很容易。
这似乎应该有效,但我没有在正确性/时间/空间复杂性方面给予更深入的思考。
答案 4 :(得分:5)
这是一种基于三角测量的方法,该方法非常简单,可以在O(N 2 )中运行。
BTW,O(N 2 )对于这个问题是最佳的。想象一下两个形状像干草叉叶片的多边形,它们以直角相交。每个都有一些与尖齿数量成比例的部分;交叉点中多边形的数量与尖齿数的平方成正比。首先,对每个多边形进行三角测量。
将P中的所有三角形与Q中的所有三角形进行比较,以检测交叉点。可以将任何一对交叉三角形分成较小的三角形,每个三角形在P,Q或交叉点中。 (无论你在步骤1中使用什么,都可以重复使用来帮助解决这个问题。)只保留交叉点中的三角形。
通过成对比较每个三角形的邻居,并构建邻接图。该图将包含P和Q交叉点中每个多边形的一个连通子图。
对于每个这样的子图,选择一个三角形,走到边缘,然后在边缘处走动,产生限定相应输出多边形的线段。
答案 5 :(得分:4)
这是一种简单而愚蠢的方法:在输入时,将多边形离散化为位图。交叉,和位图一起。要生成输出多边形,请使用polygon-approximation algorithm跟踪位图的锯齿状边框并平滑锯齿。 (我不记得那个链接是否提供了最合适的算法,它只是第一个谷歌搜索。你可以查看其中一个工具将位图图像转换为矢量表示。也许你可以调用它们而不重新实现算法?)
我认为最复杂的部分是tracing out the borders。
早在90年代初,我在工作中遇到了类似这个问题的问题。我把它搞砸了:我提出了一个(完全不同的)算法,它可以处理实数坐标,但是面对浮点(和嘈杂的输入)的现实,似乎遇到了一个完全无法修复的过多退化情况。也许在互联网的帮助下我会做得更好!
答案 6 :(得分:0)
我没有非常简单的解决方案,但以下是真实算法的主要步骤:
std::list
不会,因为你必须交换下一个和
以前的指针/偏移你自己的特殊操作
节点。这是获得简单代码的唯一方法,这将给出
良好的表现。然后你得到了多边形交集解算算法的原始结果。通常,您需要根据每个区域的匝数选择一些区域。搜索多边形缠绕数以获得对此的解释。
如果你想用这个O(N²)算法制作O(N·logN)算法,你必须做同样的事情,除非你在行扫描算法中做。寻找 Bentley Ottman算法。内部算法将是相同的,唯一的区别是你将在循环内部减少要比较的边数。
答案 7 :(得分:0)
我处理同样问题的方式
IntervalTrees
或LineSweepAlgo
GrahamScanAlgo
查找封闭路径以查找具有相邻顶点的闭合路径DinicAlgo
解散它们注意:鉴于多边形有一个共同的顶点,我的场景是不同的。但希望这可以帮助
答案 8 :(得分:0)
如果您不关心可预测的运行时间,则可以尝试先将多边形分成凸多边形的并集,然后成对计算子多边形之间的交点。
这将为您提供凸多边形的集合,以使它们的并集恰好是起始多边形的交集。
答案 9 :(得分:0)
如果多边形未对齐,则它们必须对齐。我会通过找到多边形的中心(X 的平均值,Y 的平均值)然后通过矩阵变换增量旋转多边形,将点投影到轴之一并使用最小标准偏差的角度来对齐形状(你也可以使用主成分)。为了找到交点,一个简单的算法是定义一个点网格。对于每个点,维护一个多边形或另一个多边形或两者(联合)内的点数(有简单而快速的算法,例如http://wiki.unity3d.com/index.php?title=PolyContainsPoint)。计算点polygon1 和polygon2,除以polygon1 或Polygon2 中的点数,您就可以粗略(取决于网格采样)估计多边形重叠的比例。交集区域将由与操作对应的点给出。
例如
function get_polygon_intersection($arr, $user_array)
{
$maxx = -999; // choose sensible limits for your application
$maxy = -999;
$minx = 999;
$miny = 999;
$intersection_count = 0;
$not_intersected = 0;
$sampling = 20;
// find min, max values of polygon (min/max variables passed as reference)
get_array_extent($arr, $maxx, $maxy, $minx, $miny);
get_array_extent($user_array, $maxx, $maxy, $minx, $miny);
$inc_x = $maxx-$minx/$sampling;
$inc_y = $maxy-$miny/$sampling;
// see if x,y is within poly1 and poly2 and count
for($i=$minx; $i<=$maxx; $i+= $inc_x)
{
for($j=$miny; $j<=$maxy; $j+= $inc_y)
{
$in_arr = pt_in_poly_array($arr, $i, $j);
$in_user_arr = pt_in_poly_array($user_array, $i, $j);
if($in_arr && $in_user_arr)
{
$intersection_count++;
}
else
{
$not_intersected++;
}
}
}
// return score as percentage intersection
return 100.0 * $intersection_count/($not_intersected+$intersection_count);
}
答案 10 :(得分:-2)
这可能是一个巨大的近似值,取决于你的多边形,但这里是一个:
尽管如此,这应该非常有效,因为对多边形的任何变换都以与质心相同的方式应用,并且中心节点距离只能计算一次。