将圆连接成多边形的算法

Posted

技术标签:

【中文标题】将圆连接成多边形的算法【英文标题】:Algorithm for joining circles into a polygon 【发布时间】:2016-04-30 05:24:24 【问题描述】:

将重叠的圆组合成多边形的最佳方法是什么?

我得到了一个具有固定直径的圆的中心点列表。

我需要将所有重叠的圆圈连接在一起,并在生成的多边形中输出一个点列表。

这似乎是一个相当普遍的问题(GIS 系统、矢量等)。这可以通过 Google Maps API 完成,但我正在寻找实际的算法。

我试图通过计算每个圆周围的点来解决这个问题。

然后删除位于任何圆圈内的任何点。

这为我提供了所需多边形中正确的点列表。

然而,点的顺序是这个解决方案的一个问题。每个圆的点都存储在一个数组中。将它们与 2 个重叠的圆圈正确合并是相对简单的。但是,当处理多个重叠的圆圈时,它会变得复杂。

希望您有一些想法可以使这个解决方案发挥作用,或者让另一种算法达到预期的效果。

提前致谢!

【问题讨论】:

在您的示例中,应该将所有五个圆组合为 一个 多边形还是 三个 多边形? 可能不是很快,但是如何:从一组合并圆的任意一点开始,找到下一个最近的点,将它们连接起来,然后重复直到合并圆的所有点都连接起来? (不过,如果两个圆几乎不重叠,这可能会失败,因此它们会形成两个锐角;在这种情况下,拐角处的点会被跳过。) @tobias_k 在本例中,输出将是 3 个多边形。 嗯,这里有什么问题?您所要做的就是连接最后两个未连接的点,您就有了一个有效的多边形。 @tobias_k 这在简单的情况下会起作用,但当有几个多边形重叠时肯定会失败,就像你说的那样。 【参考方案1】:

您应该能够使用如下方法:

    首先,识别属于同一组重叠圆的圆。显然,如果两个圆的中心的绝对距离小于它们的组合半径,则两个圆重叠。对于每个圆圈,将其迭代的圆圈存储在 hashmap/dictionary 中。 (您可以使用 union-find algorithm, or disjoint sets 将其扩展到整个圈子组,但这并不是真正需要的。) 创建属于一个圆的点时,记住每个点的左右邻居。您只需将它们存储在有序数组中即可免费获得。 删除“内部”点,即距离与第一个圆相交的任何圆心的距离小于一个半径的点。 标记那些内部点的邻居,这些点没有被移除圆圈的“松散端”。 将未删除的点(包括松散端)连接到它们原来的左右相邻点。 对于每个松散的端点,找到同一组中不同圆的最近的松散端并将它们连接起来。

这里有一张图片来说明这个方法。

红点是被移除的“内部”点 蓝点是“内部”点的邻居,是“松散的末端”;每个“松散端”都有另一个不同圆的“松散端”,距离不到两个“点距离” 绿点可以很容易地连接到它们的邻居(包括“松散的末端”),按照它们在圆圈周围的排列顺序。

您可以通过区分 leftright 松散端来进一步减少可能组合的数量,并利用一个圆的每个左松散端都必须连接的事实到另一个圆圈的右端。对于组中的 n 圈子,无论每个圈子的点数如何,都只剩下 (n-1)! 连接这些圈子的方法。

如果您只考虑组中那些与松散端实际相交的圆圈(只需将它们存储在哈希图/字典中),即使这也可以进一步减少。因此,如果您的 n 圈子平均与 k 其他圈子相交,那么只有 n*k 可能的组合。

您还可以使用另一个松散端的距离不能超过圆上两点之间距离的两倍的事实。让我们将此距离称为d,然后您可以创建分辨率为d 的空间地图(例如哈希图,或只是一个二维数组)并将每个松散端分配给该地图中的单元格,然后另一个松散端必须在与第一个松散端周围的一个单元格相同。

因此,点可以相互连接的方式的数量大大减少了(特别是,它们在最终图像中的连接方式将不允许开始):除非您在同一组中有 很多 个重叠的圆圈,并且您可以使用更智能的 nearest-neighbor search 算法,否则即使使用蛮力,这也应该是可行的。


更新:一段时间后查看此答案,您似乎可以相当容易地确定“松散端”点的匹配对:假设您在圆 A 中有一个“右”松散端,那么匹配的“左”松散端end 必须属于半径与下一个“内”点重叠到第一个“松散端”的圆。因此,如果您将该关系存储在另一个映射中,您可以立即确定匹配的松散端。 (如果一个内部点与多个其他圆圈重叠,则地图应包含与其重叠最多的圆圈。)

【讨论】:

仔细观察,甚至不需要不相交的集合;只需创建一个哈希图,将每个圆映射到与之相交的其他圆。计算不需要整个组。【参考方案2】:

这是一个 O(n log n) 时间算法的草图。

    使用您最喜欢的算法/库计算圆心上的Delaunay triangulation。

    删除不重叠的圆之间的边缘。

    绕着每个连接组件的无限面走。使用doubly connected edge list 表示很容易做到这一点,其中边列表的排序用于指示平面图的拓扑。该边界上的每条半边都变成一个顶点,属于其尾点的弧段结束,属于其头点的弧段开始。

    (可选)用折线逼近每个弧段。

如果 Google 的任何人正在阅读本文,请注意我没有查看相关代码。

【讨论】:

我不知道(还)这是否正确,但我赞成与 Dealaunay 三角测量的链接(我不知道)。

以上是关于将圆连接成多边形的算法的主要内容,如果未能解决你的问题,请参考以下文章

ArcGIS中生成蜂窝多边形算法解析

算法设计与分析——凸多边形最优三角剖分

Three.js将多边形线条(Line)转换成模型(Mesh)

将相邻矩形合并为多​​边形的算法

如何在openlayers中测量从圆心到边缘的距离

如何将单调多边形分解为两个单调链