用于创建非自相交多边形的算法的有效性

时间:2011-03-11 21:54:28

标签: algorithm geometry polygon computational-geometry vertex

作为my thread的扩展和部分答案,我写了一个简单的算法,给出一组点(带有xy坐标)可以形成一个非自相交的多边形。


声明:给定一组具有不同坐标的任意点,总是可以构造一个规则或不规则的非自相交多边形。

算法:

假设有一个包含所有顶点的集合

1)按V坐标

对V中的所有顶点进行排序

2)想象一条与x轴平行的直线(我们称之为“分隔线”),从第一个节点开始扩展到无穷大并将顶点分割成两组。

3)现在考虑两组:

A =分隔线上方或上方的所有顶点的集合

B =所有剩余顶点的集合

4)从A的最左边顶点开始,连接A中的所有顶点,直到到达最右边

5)如果有序集V的最右边顶点(具有最大x坐标的顶点)不在A中,那么最后一个顶点(A的最右边)与它连接。

6)向后工作并从有序集合V​​的最右边顶点开始(具有最大x坐标的顶点)连接B中的所有顶点

7)将B的第一个(B的最左侧顶点)顶点与A的最左侧顶点连接起来


我认为算法是正确的,无法找到它会失败的测试,但也许我错过了一些东西。

我很感激你,如果你能看一眼并给我一个例子,如果有的话就行不通(我肯定必须这样做)。

5 个答案:

答案 0 :(得分:3)

这是一个反例。当步骤5没有画线时,可以自相交。

counterexample

答案 1 :(得分:2)

我不确定我是否理解你正在尝试做什么。在另一个帖子中,在the corresponding thread at math.SE(我带到这里),你说你有一个多边形,并试图找到它的重心。这里你说你有一组点,你想从它构造一个非相交的多边形。这是两件完全不同的事情。正如我在math.SE中提到的,如果不知道多边形是凸的,那么一组点不能唯一地定义多边形 - 所以你在这里建议的算法可以构造一些任意的非自相交多边形(我的避风港)不检查它是否成功地执行了此操作)但是这可能与您最初感兴趣的多边形有任何关系。或者我在math.SE中误解了您的问题而您实际上只有一些要点并且想要构建任何来自它们的非自相交多边形并不关心可能有几个不等价的解决方案吗?

答案 2 :(得分:2)

我认为我有一个更简单的算法来创建这样的多边形。可能更难在软件中实现,但更容易用文字描述。

  • 选择套装中的任意一点作为开始。从它开始以0角创建一条线。
  • 开始围绕该点旋转线。在遇到任何其他点的那一刻,从起点到新发现的点画一条边。
  • 继续围绕起点旋转,将任何新找到的点与最后找到的点连接起来。
  • 在旋转结束时,通过满足起点关闭形状。

如果在一个方向上有多个发现,请将它们连接到一个方向(例如,从最内部结束到最外部的方向开始)

形状通常有点像星形,但符合要求。

计算执行就像:

  • 将所有点转换为其中一个点的原点[0,0]的坐标集。
  • 将所有点转换为极坐标集
  • 排序依据:角度上升,半径上升。
  • 按排序顺序连接所有点。
  • 最后连接到第一个([0,0])点。

答案 3 :(得分:1)

通过将“分隔线”设置为最左侧和最右侧点之间的连接,而不是平行于x轴,我会证明它略有不同。可能会发生并行到x线以下没有点,这可能会给您的证明带来麻烦。

此外,连接(5)可能导致与点(6)中生成的连接发生一些自相交

当所有点都是共线并且多边形降级为直线时,还有一种特殊情况。

我们假设顶点的集合V是有限的;)

除此之外 - 我相信你的说法属实。

答案 4 :(得分:0)

我在javascript和OpenLayers库中遇到了同样的问题。所以这是我在'vectors'层中检测多边形有效性的解决方案,作为OpenLayers.Layer.Vector:

var ps = vectors.features[0].geometry.getVertices(), i, j, inx, x1, x2, x3, x4, y1, y2, y3, y4, x43, x21, y21, y43, y31, maxx12, maxx34, minx12, minx34;
ps.push(ps[0]);
for(i = 0; i < ps.length -1 ; i++ ) {
  x1 = ps[i].x; x2 = ps[i+1].x;
  y1 = ps[i].y; y2 = ps[i+1].y;
  for(j = i + 2; j < ps.length -1 ; j++ ) {
    x3 = ps[j].x; x4 = ps[j+1].x;
    y3 = ps[j].y; y4 = ps[j+1].y;
    x43 = x4 - x3; x21 = x2 - x1; y21 = y2 - y1; y43 = y4 - y3; y31 = y3 - y1;
    inx = ( x43*y21*x1 - x21*y43*x3 + y31*x21*x43 )/( x43*y21 - x21*y43 );
    if( x1 < x2 ){
      minx12 = x1; maxx12 = x2;
    } else {
      minx12 = x2; maxx12 = x1;
    }
    if( x3 < x4 ){
      minx34 = x3; maxx34 = x4;
    } else {
      minx34 = x4; maxx34 = x3;
    }
    if (minx12 < inx && inx < maxx12 && minx34 < inx && inx < maxx34 ){
      console.log('intersected!'+' ,x1: '+x1+' ,x2: '+x2+' ,inx: '+inx+' ,i: '+i+' ,j: '+j);

      return;
    }
  }
}
希望你喜欢它!