Math 多边形求交的一种简单算法
我正在寻找一个非常简单的算法来计算多边形相交/剪裁。 也就是说,给定多边形Math 多边形求交的一种简单算法,math,geometry,2d,polygon,Math,Geometry,2d,Polygon,我正在寻找一个非常简单的算法来计算多边形相交/剪裁。 也就是说,给定多边形P,Q,我希望找到包含在P和Q中的多边形T,我希望T在所有可能的多边形中是最大的 我不介意运行时间(我有一些非常小的多边形),我还可以获得多边形交点的近似值(即,点较少的多边形,但仍包含在多边形交点中) 但对我来说,算法简单(测试成本较低),最好短(代码较少),这一点非常重要 编辑:请注意,我希望获得表示交点的多边形。对于两个多边形是否相交的问题,我不需要一个布尔答案。这可能是一个很大的近似值,取决于您的多边形,但这里有一
P
,Q
,我希望找到包含在P
和Q
中的多边形T
,我希望T
在所有可能的多边形中是最大的
我不介意运行时间(我有一些非常小的多边形),我还可以获得多边形交点的近似值(即,点较少的多边形,但仍包含在多边形交点中)
但对我来说,算法简单(测试成本较低),最好短(代码较少),这一点非常重要
编辑:请注意,我希望获得表示交点的多边形。对于两个多边形是否相交的问题,我不需要一个布尔答案。这可能是一个很大的近似值,取决于您的多边形,但这里有一个:
- 计算每个轴的质心 多边形
- 计算最小值、最大值或平均值 距离每一点的距离 多边形到质心
- 如果C1C2(其中C1/2是第一个/第二个多边形的中心)>=D1+D2(其中D1/2是您为第一个/第二个多边形计算的距离),则两个多边形“相交”
不过,这应该是非常有效的,因为对多边形的任何变换都以非常相同的方式应用于质心,并且中心节点距离只能计算一次。您可以使用多边形剪裁算法来查找两个多边形之间的交点。然而,当考虑到所有的边缘情况时,这些算法往往是复杂的 您可以使用喜爱的搜索引擎查找的多边形剪裁的一个实现是Weiler Atherton Alan Murta拥有多边形裁剪器的完整实现 编辑:
另一种方法是首先将每个多边形划分为一组三角形,这样更容易处理。Gary H.Meisters的双耳定理就做到了这一点。这很好地解释了三角形细分。您没有给我们您的多边形表示。所以我选择了(更像是建议)一个给你:) 将每个多边形表示为一个大凸多边形,以及需要从该大凸多边形中“减去”的较小凸多边形列表 现在,给定该表示中的两个多边形,可以将交点计算为: 计算大型凸多边形的交点以形成交点的大型多边形。然后“减去”两者中所有较小多边形的交点,以得到一个细分多边形列表 您将获得一个遵循相同表示的新多边形 由于凸多边形相交很容易,因此该相交查找也应该很容易
这似乎应该行得通,但我没有对正确性/时间/空间复杂性进行更深入的思考。这里有一个简单而愚蠢的方法:输入时,将多边形离散化为位图。要相交,请将位图合并在一起。要生成输出多边形,请勾画出位图的锯齿状边界,并使用平滑工具平滑锯齿状边界。(我不记得这个链接是否给出了最合适的算法,这只是谷歌的第一次成功。你可以查看其中一个将位图图像转换为矢量表示的工具。也许你可以在不重新实现算法的情况下调用它们?) 我认为最复杂的部分是
顺便说一句,在90年代初,我在工作中遇到了类似的问题。我把它弄糊涂了:我想出了一个(完全不同的)算法,可以处理实数坐标,但面对浮点(和噪声输入)的现实,似乎遇到了完全不可修复的过多退化情况。也许有了互联网的帮助,我会做得更好 > P>如果你使用C++,不想自己创建算法,你可以使用。它使用了上面提到的Weiler-Atherton算法的改编版本。我知道原始海报在寻找一个简单的解决方案,但不幸的是,实际上没有简单的解决方案
不过,我最近创建了一个开源的免费剪辑库(用Delphi、C++和C语言编写),它可以剪辑各种多边形(包括自交)。这个库使用起来非常简单:。
我没有非常简单的解决方案,但下面是实际算法的主要步骤:std::list
不行,因为您必须交换下一个和
上一个指针/偏移量用于在
节点。这是获得简单代码的唯一方法,这将
表现不错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);
}