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
    不行,因为您必须交换下一个和 上一个指针/偏移量用于在 节点。这是获得简单代码的唯一方法,这将 表现不错
  • 通过比较每对边找到交点。注 比较每一对边缘会给O(N²)时间,但会有所改善 之后,O(N·logN)的算法将变得简单。为了一双 边缘(比如a)→b和c→d) ,通过使用 边a上的参数(从0到1)→b、 这是由 Tₐ=D₀/(d)₀-D₁), d在哪里₀ is(c-a)×(b-a)和d₁ is(d-a)×b-a.×is 二维叉积,如p×q=pₓ·Qᵧ-Pᵧ·Qₓ. 找到t之后ₐ, 求交点是将其用作线性插值 a段上的参数→b:P=a+tₐ(b-a)
  • 拆分每条边添加顶点(以及链接列表中的节点) 线段相交的位置
  • 然后必须在交点处穿过节点。这是 需要对其执行自定义双链接的操作 您必须交换下一对指针(并更新 相应地,前面的指针)
  • 然后就有了多边形相交解析算法的原始结果
    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);
    }