给定两个多边形:
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](https://istack.dev59.com/N5P2R.webp)
给定两个多边形:
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))
我如何计算并集(组合多边形)?
这是一个非常好的问题。我之前在c#上实现了相同的算法。该算法构建两个多边形的公共轮廓(即构建没有洞的并集)。如下所示。
输入:第一个多边形(n个点),第二个多边形(m个点)。输出:图形。顶点-多边形交点。
我们应该找到交叉点。迭代遍历两个多边形中的所有多边形边缘[O(n*m)],找到任何交点。
如果没有发现交点,则简单地添加顶点并将它们连接到边缘。
如果发现任何交叉点,请按其到起点的长度对它们进行排序,添加所有顶点(起点、终点和交叉点)并将它们(已按排序顺序)连接到边。
如果在构建图形时未发现任何交点,则有以下几种情况:
找到最小的x和y坐标(minx,miny)。然后找到(minx,miny)与多边形的点之间的最小距离。这个点将是左下角的点。
我们从左下角的点开始遍历图形,直到回到它为止。开始时,我们将所有边缘标记为未访问。在每次迭代中,您应该选择下一个点并将其标记为已访问。
选择下一个点时,选择逆时针方向具有最大内角的边。这是一个具有挑战性但易于理解的主题,通常被称为“多边形上的正则化布尔运算”。您可以查看这个MathOverflow答案,其中包括下面的图示(来自Alan Murta的剪辑库),其中粉色联合体是OP的combine:
您需要确定哪些点在内部。在删除这些点之后,您可以将一个“外部”点集插入到另一个点集中。您的插入点(例如,在右侧图片中箭头所示的位置)是您必须从输入集中删除点的位置。
我曾经面临过同样的问题,而我是通过以下方式解决的:
使用Cython封装了Angus Johnson的Clipper库(版本6.4.2)的C++翻译 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)
好问题!我以前从未尝试过这个,但我现在会试着解决。
首先:您需要知道这两个形状重叠的位置。为此,您可以查看多边形A中的每条边,并查看它与多边形B中的边相交的位置。在此示例中,应该有两个交点。
然后:制作联合形状。您可以获取A和B中的所有顶点以及交点,然后排除包含在最终形状中的顶点。要找到这些点,看起来您只需找到任何一个在B中的A的顶点,以及在A中的B的顶点即可。
请看下面的代码片段:
#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;
}
今天我需要解决同样的问题,找到了这个库的解决方案:https://en.wikipedia.org/wiki/General_Polygon_Clipper。
它有很多语言实现,包括Java、Obj-C、C#、Lua、Python等。这里是列表。