【发布时间】:2016-01-24 22:25:31
【问题描述】:
我们有一个由连接器和段组成的数据集。每个段正好有两个连接器,但每个连接器可以属于零个或多个段(即下图中左图中的连接器“A”没有段,而连接器“M”有三个,MR、ML 和 MN。)
据了解,任何线相交或相交的地方都会有一个连接器,因此我们不必担心偶数/奇数规则、重叠或部分封闭的多边形等,因为它们不适用。
简而言之,我们正在尝试识别所有创建的多边形(右图中的彩色形状)。我相信这可以分两步完成。
第 1 部分:删除多余的项目
独立连接器(此处为连接器“A”)可以简单地移除,因为它们不能成为形状轮廓的一部分。
引用单个段(连接器“B”和“E”)的浮动端点也可以被删除,因为它们也不能成为形状轮廓的一部分。这也将删除它们引用的片段(B-C 和 E-D)。
递归执行上述操作将接下来将“C”标识为端点(因为“B”和 B-C 已被删除),因此它及其剩余的段 C-D 也可以被删除。在下一次递归过程中,连接器“D”和段 D-F 也将被删除,等等。
但是,我还没有找到识别细分 H-I 的好方法。也就是说,我认为这可以在多边形检测期间实现,因为这些片段只会是复合路径的结果,并且会在一个形状的检测过程中在两个方向上进行跟踪。 (更多内容见下文。)
第 2 步:多边形检测
可以在两个方向上跟踪每个段。例如,连接“O”和“P”的段可以是 O-P 或 P-O。选取顺时针方向的轨迹,O-P 属于多边形 O-P-Q-N,而 P-O 属于多边形 P-O-I。
以下逻辑假设跟踪方向为顺时针。
从任何线段开始,当追踪时,如果你回到你的起点,你已经确定了一个潜在的多边形。通过在跟踪时保持航向角度的运行增量(这是航向转动的角度,不要与简单地添加线段之间的角度混淆),完成后,如果该角度为正,您已经检测到有效的多边形。如果它是否定的,则您检测到“包含”多边形,即包含一个或多个“有效”多边形的多边形。整个形状(或形状)的外周边都包含多边形。
考虑一个正方形的情况,对角线分成两个三角形。跟踪每个线段两次——每个方向一次——你最终会得到三个可能有效的多边形:一个正方形和两个三角形。三角形将有一个正的角度增量,告诉您它们是有效的,但正方形的角度增量是负的,告诉您这是包含多边形。
注意:包含多边形也可以等于有效多边形。它只会向相反的方向“缠绕”。
考虑一个简单的三角形。顺时针跟踪将产生有效的多边形。第二次尝试顺时针追踪实际上会产生一个逆时针追踪,这会给你一个负角增量,告诉你这实际上是形状的轮廓。
注意:您还必须测试沿途遇到的其他多边形,方法是在形状检测期间测试每个点是否有任何先前遇到的点。如果您发现您重新访问了同一点,请保存自第一次遇到该点以来创建的多边形,检查它的角度。如果它是正的,它是一个有效的多边形(并且你实际上正在追踪一个包含的多边形。)如果它是负的,你已经检测到一个包含的多边形(在这种情况下,你当前正在追踪一个有效的多边形。)最后,删除所有将累积堆栈上的段返回到上次遇到该点的第一个实例,然后继续进行检测。
例如,如果您从“J”开始并逆时针追踪,您将经过“I”、“H”,然后是“G”,然后是“F”,然后您会回到“H” '。您刚刚找到了一个多边形 H-G-F,它有一个负角,所以您知道它是一个包含多边形。从堆栈中删除这三个段并继续。现在你将再次点击“我”。在这种情况下,您已经在此过程中访问了同一段,但是在另一个方向,所以只需从堆栈中完全删除该段并继续,在“O”旁边,然后是“N”等。你最终会回到'J'。
当一个片段在两个方向上都被追踪时,它可以被认为是“使用过的”,并且不需要对该片段进行进一步的处理。继续处理所有未使用的段。一旦在两个方向上跟踪了所有线段,您就可以确定所有多边形(有效的和包含的)都已找到。
最后,检查每个包含的多边形,看看它是否在任何有效的多边形内。如果是这样,请将其从创建复合路径的有效多边形中排除。在此处的示例中,包含多边形 H-G-F 包含在有效的青色多边形中,因此应将其排除。注意还有一个有效的 H-F-G 多边形,这里用红色标记。
无论如何,这就是我想出的,但我想知道是否有更好/更简单的方法。想法?
【问题讨论】:
-
我费了一番周折才决定明白您的要求。为了看看我是否正确,让我用稍微数学的术语来表达:给定一个平面图,是否有一种算法可以选择一组最大的多边形(当然,其边是从图中绘制的)使得每个点在该平面要么在多边形边界上,要么恰好包含在一个多边形中?这似乎是对您的问题的公平重述?
-
谷歌搜索后:看起来 boost 有planar_face_traversal,它的功能与您想要的类似(尽管可能不完全相等)。您可能会查看他们的实现以获取一些想法 - 或者甚至可以按原样使用它。
-
HI 的情况尚不清楚。如果你把它拿掉,脸 KJINML 就会有一个洞。这允许吗?
-
@DanielWagner 的链接为双连通图提供了 O(n+m) 时间的算法。您所要做的就是首先删除所有悬垂边(很容易找到——一个端点的度数为 1)和桥(删除会断开图形的边)——还有相当简单、有效的算法。然后你可以寻找完全包含其他多边形的多边形——这应该相当快,因为你可以先减少面积来排序,然后你只需要检查一个较早的多边形是否包含后面的多边形,测试一个点是够了。
-
@Yves,是的,这是允许的。请参阅右图的标题。
标签: algorithm geometry polygon detection shapes