如何组合复杂的多边形?

时间:2010-04-19 13:31:43

标签: math geometry union

给出两个多边形:

POLYGON((1 0, 1 8, 6 4, 1 0))
POLYGON((4 1, 3 5, 4 9, 9 5, 4 1),(4 5, 5 7, 6 7, 4 4, 4 5))

如何计算并集(组合多边形)?

enter image description here

Dave's example使用SQL服务器生成联合,但我需要在代码中完成相同的操作。我正在寻找任何暴露实际数学的语言的数学公式或代码示例。我正在尝试制作将国家动态组合到地区的地图。我在这里问了一个相关的问题:Grouping geographical shapes

10 个答案:

答案 0 :(得分:54)

这是一个非常好的问题。我前段时间在c#上实现了相同的算法。算法构造两个多边形的公共轮廓(即构造一个没有孔的联合)。在这里。


Goal

步骤1.创建描述多边形的图形。

输入:第一个多边形(n个点),第二个多边形(m个点)。输出:图表。顶点 - 多边形交点。

我们应该找到交叉点。遍历两个多边形[O(n * m)]中的所有多边形边并找到任何交点。

  • 如果找不到交叉点,只需添加顶点并连接它们即可 到了边缘。

  • 如果找到任何交叉点,请按长度对它们的起点进行排序,然后添加全部 顶点(开始,结束和交叉点)并连接它们(已经在 排序顺序)到边缘。 Graph

步骤2.检查构造的图形

如果我们在构建图形时没有找到任何交叉点,则我们有以下条件之一:

  1. Polygon1包含polygon2 - return polygon1
  2. Polygon2包含polygon1 - return polygon2
  3. Polygon1和polygon2不相交。返回polygon1和polygon2。
  4. 步骤3.找到左下角的顶点。

    找到最小x和y坐标(minx,miny)。然后找到(minx,miny)和多边形点之间的最小距离。这一点将是左下角。

    Left-bottom point

    步骤4.构建共同轮廓。

    我们开始从左下角遍历图表并继续直到我们回到它。在开始时,我们将所有边标记为未访问。在每次迭代中,您应该选择下一个点并将其标记为已访问。

    要选择下一个点,请选择逆时针方向内角最大的边。

    我计算了两个向量:当前边缘的vector1和下一个未访问边缘的vector2(如图所示)。

    对于我计算的向量:

    1. 标量积(点积)。它返回与矢量之间的角度相关的值。
    2. 矢量产品(交叉产品)。它返回一个新的向量。如果是z坐标 矢量是积极的,标量产品给我直角     逆时针方向。否则(z坐标为负),我     计算矢量之间的角度为360°角度     产品
    3. 结果我得到了一个具有最大角度的边(和一个对应的下一个顶点)。

      我将每个传递的顶点添加到结果列表中。结果列表是联合多边形。 Vectors

      说明

      1. 此算法允许我们合并多个多边形 - 迭代地应用多边形对。
      2. 如果您的路径包含许多贝塞尔曲线和线条,则应首先展平此路径。

答案 1 :(得分:7)

这是一个具有挑战性但很容易理解的话题 名为“多边形上的正则化布尔运算”。 你可能会看 this MathOverflow answer, 其中包括下图 (来自Alan Murta's clipping library), 使用粉红色联合OP的组合

<小时/> BooleanOps

答案 2 :(得分:6)

您需要determine which points lie inside。删除这些点后,您可以将一组“外部”点插入另一组。您的插入点(例如,右侧图片中有箭头的位置)是您必须从输入集中删除点的位置。

答案 3 :(得分:4)

好问题!我以前从未尝试过这个,但我现在会对它进行一次破解。

首先:您需要知道这两个形状重叠的位置。要做到这一点,你可以查看Polygon A中的每一条边,看看它在Polygon B中的相交和边缘。在这个例子中,应该有两个交点。

然后:使联合形状。您可以获取A和B中的所有顶点,以及交点,然后排除最终形状包含的顶点。为了找到这些点,看起来你可以找到B内部的A的任何顶点,以及A内部的任何B的椎骨。

答案 4 :(得分:4)

尝试gpc

答案 5 :(得分:2)

我已经看到了使用BSP树的解决方案here

基本上,它根据多边形 A 边缘的并集来描述交集,这些边在多边形 B 内(包括部分边缘,并使用{{3计算) }})。然后,您可以将 A / B 定义为〜(〜 A / \〜 B ),其中〜表示反转多边形的绕组,/表示联合和/ \表示交叉。

答案 6 :(得分:1)

在对国家进行分组时,我希望没有重叠 - 您可以采用一种相当天真的算法来寻找共享顶点 - 一个简单的视图就是迭代一个多边形上的点,看看它是否在任何一个上您的其他多边形,并分享相同的下一个或上一个点,以查看是否匹配。然后只需删除共享顶点即可创建联合

答案 7 :(得分:1)

我今天需要解决同样的问题并找到了这个lib的解决方案:http://www.cs.man.ac.uk/~toby/alan/software/

它有很多语言实现the list here,包括Java,Obj-C,C#,Lua,python等。

答案 8 :(得分:1)

我遇到了同样的问题,并通过以下方式解决了问题

Cython包装器,用于Angus Johnson's Clipper库的C ++翻译(版本6.4.2) https://github.com/fonttools/pyclipper

pc = pyclipper.Pyclipper()
def get_poly_union(polygons):
    pc.AddPaths(polygons, pyclipper.PT_SUBJECT, True)
    solution = pc.Execute(pyclipper.CT_UNION, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO)
    return solution[0]

print_image = image.copy()
solution = get_poly_union(polygons_array) 
#polygons_array=[polygon,polygon,polygon, ...,polygon] and polygon=[point,point,point...,point]

cv2.drawContours(print_image, [np.asarray(solution)], -1, (0, 255, 0), 2)

plt.imshow(print_image)

答案 9 :(得分:0)

这是一个非常老的问题,但是Boost的Union_函数对我有用。

请参见以下代码段:

#include <iostream>
#include <vector>

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>

#include <boost/foreach.hpp>


int main()
{
    typedef boost::geometry::model::polygon<boost::geometry::model::d2::point_xy<double> > polygon;

    polygon green, blue;

    boost::geometry::read_wkt(
        "POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))", green);

    boost::geometry::read_wkt(
        "POLYGON((5 5, 5 15, 15 15, 15 5, 5 5))", blue);

    std::vector<polygon> output;
    boost::geometry::union_(green, blue, output);

    int i = 0;
    std::cout << "green || blue:" << std::endl;
    BOOST_FOREACH(polygon const& p, output)
    {
        std::cout << i++ << ": " << boost::geometry::area(p) << std::endl;

        for (int i = 0; i < p.outer().size(); i++)
        {
            std::cout << p.outer().at(i).x() << " " << p.outer().at(i).y() << std::endl;
        }
    }



    return 0;
}