将弱简单多边形拆分为真正的简单多边形或多边形

时间:2013-04-24 14:28:07

标签: javascript graph svg polygon

我想将弱的简单多边形划分为简单的多边形。

背景

用例是使用Javascript Clipper简化简化(联合)的多边形。 Javascript Clipper以及original Clipper's SimplifyPolygon()函数删除了自交叉并组合了常见边,但它无法生成真正的简单多边形。输出用于three.js,其中TriangulateShapes()需要多边形很简单。 Three.js接受具有一个轮廓和零个或多个孔的多边形结构。

输入,弱简单多边形

弱简单多边形不能具有连续复制顶点(真实重复点),也不能具有孔(岛)或自交叉(边缘跨越其他边),但可以有非连续多顶点(顶点)具有完全相同的坐标但不是顺序的)。输入多边形可以具有CW或CCW绕组顺序,这意味着CW输入是外多边形而CCW是一个孔。输入是CW或CCW多边形。

输入是一个多边形点数组,例如:


// This is a true example of weakly-simple polygon:

var input = [{"X":270,"Y":520},{"X":130,"Y":490},{"X":210,"Y":250},{"X":60,"Y":170},{"X":130,"Y":490},{"X":20,"Y":410},{"X":60,"Y":300},{"X":60,"Y":20},{"X":780,"Y":40}, {"X":680,"Y":180},{"X":460,"Y":130},{"X":210,"Y":250},{"X":320,"Y":100},{"X":220,"Y":80}, {"X":210,"Y":250},{"X":520,"Y":250},{"X":680,"Y":180},{"X":770,"Y":480},{"X":540,"Y":470}, {"X":520,"Y":250},{"X":380,"Y":280},{"X":430,"Y":390},{"X":540,"Y":470},{"X":270,"Y":520},{"X":330,"Y":350},{"X":210,"Y":250}];

这是上面的input多边形作为图像:

enter image description here

以下是编号的点,您可以在其中轻松查看哪些点是重复的:

enter image description here

如您所见,上述多边形可以分为多种方式,例如: - 一个带五个孔的外部多边形 - 五个外部多边形,其中一个有一个孔

输出,简单多边形作为exPolygon结构

简单多边形是一个没有自相交的多边形,没有重复坐标,无论它们是顺序还是非顺序,没有孔。输出的简单多边形可以具有CW或CCW绕组顺序。 CW表示外部和CCW孔。

输出可能有(并且很多时候会有)孔,但在某些情况下输出没有孔。输出始终至少有一个外部多边形,但也可能有多个外部多边形具有零个或多个孔。

输出应该是具有“outer”和“holes”属性的exPolygon对象数组。 “outer”是点对象的数组,“holes”是点对象数组的数组。如果填充“孔”,则其中的孔必须是exPolygon对象中的“外”多边形孔。

输出示例:


// This is an example of output, but the points are random:

[ { "outer": [{"X":54,"Y":4},{"X":2,"Y":50},{"X":30,"Y":5},{"X":10,"Y":50}],
    "holes": [ [{"X":0,"Y":8},{"X":60,"Y":13},{"X":21,"Y":2},{"X":3,"Y":1}],
               [{"X":21,"Y":2},{"X":50,"Y":2},{"X":6,"Y":1}] ] },
  { "outer": [{"X":54,"Y":4},{"X":2,"Y":50},{"X":30,"Y":5},{"X":10,"Y":50}],
    "holes": [ [{"X":0,"Y":8},{"X":60,"Y":13},{"X":21,"Y":2},{"X":3,"Y":1}],
               [{"X":21,"Y":2},{"X":50,"Y":2},{"X":6,"Y":1}] ] },
  { "outer": [{"X":54,"Y":4},{"X":2,"Y":50},{"X":30,"Y":5},{"X":10,"Y":50}],
    "holes": [] }
];

输出的“外”多边形是CW,“孔”是CCW。

多边形中的点数,exPolygons对象的数量和孔的数量没有限制。

以下是弱简单多边形的其他示例:

enter image description here

分割示例

以下是输入多边形的示例:

enter image description here

以下是如何划分的:

enter image description here

其他一些多边形可能有多种可能的输出替代方案,具体取决于伪重复点。


我的问题

如何以这种方式划分多边形并实现所需的输出结构?我不是要问完整的代码(但是如果你有空闲时间并希望证明它是可行的)。对可能的算法的想法也很受欢迎。


我已经搜索了几个小时的解决方案并尝试找到算法。

如果您想尝试解决方案,我在这里有一个代码,我用它来查找重复项:http://jsbin.com/unuyev/7/edit。它在SVG中显示多边形,并将点显示为红色圆圈和每个点的数组索引(在按下“Run with JS”按钮后)。

以下是相同的,但有12个示例多边形(在Javascript窗口中更改pindex以更改多边形): http://jsbin.com/unuyev/4/edit


编辑:Javascript Clipper 6现已推出,并且支持StrictlySimple。但根据文档“目前无法保证多边形将严格简单,因为'简化'仍然是一项正在进行中的工作”。我测试了StrictlySimple,但在某些情况下它失败了:Orientation problemslack of rotation invariance。我们希望很快就能解决这些问题并StrictlySimple按预期工作。


1 个答案:

答案 0 :(得分:2)

可能有一些我缺少的东西,但这看起来像是找到图形的清晰度顶点的经典问题。从本质上讲,你试图在图中找到最弱点,这样当你在那一点切割图形时,最终得到两个独立的图形。因此,在您的示例中,如果您在该顶点处剪切多边形,则最终会得到多个多边形。您可以非常容易地将多边形表示为图形,每个顶点表示图形顶点,多边形边缘表示图形边缘。

如果我必须解决问题,这就是我要采取的方法。您可以查看以下资源:

<强>更新

我会尝试简要介绍一下问题和解决方案,以便为您指明正确的方向。使用图形实现此算法必然会进入图形算法术语,因此如果您不熟悉图形,则可能需要阅读它们。

您的情况下的暴力方法是遍历图形,暂时删除每个vetex,然后在修改的图形上执行DFS / BFS遍历时查看图形是否已连接。这不是非常有效,并且将以二次时间O(n(m + n))运行。但是有一种线性时间算法,它基于对由DFS遍历形成的结果DFS树的边缘进行分类。

在不包含任何后边缘的DFS树中(将“较低”节点连接到树中“更高”节点的边缘[假设“更高”节点是更接近根的节点]叶节点是没有清晰度节点,因为删除它们中的任何一个仍然会使图形连接。但是,删除任何内部节点将断开跟随它的任何节点。

删除树的根取决于它是否有一个或多个子节点。如果它只有一个孩子,那么它或多或少是一片叶子,所以删除它将没有任何效果。但是,删除具有多个子节点的根节点将断开图形。

但是在一般图表中,您可以拥有后边缘,因此删除其间的任何节点都不会断开图形。因此,找出关节顶点可以归结为通过后边缘确定树的哪些部分与祖先节点相关联(即,找出顶点的“可达祖先”)。

在我从算法设计手册链接到的页面中,Skiena描述了三种情况,其中顶点可以是关节顶点(根,桥和父剪切节点)。使用他描述的算法,您可以确定您正在处理的顶点是否满足任何这些条件。如果是,它就是一个清晰节点。

希望这有助于您开始使用!