我怎样才能简化复杂的多边形?

时间:2012-05-20 06:17:41

标签: javascript geometry polygon

最近我一直在考虑如何将复杂多边形转换为非复杂多边形。这是怎么做到的?

这是我想要做的事情:

Example

当我完成时,我将最终使用JavaScript,但任何形式的解决方案都很好(语言,算法或简单的英语)。

6 个答案:

答案 0 :(得分:6)

我会使用与手工绘制多边形时相同的启发式方法(这可能不是用于对多边形进行caluclaute的最有效的方法,但可能最容易理解/实现)。

  1. 从一点开始
  2. 查找我当前的观点与我想要的观点之间的所有交叉点
  3. 如果不存在则绘制到下一个点
  4. 如果有,则绘制到那里,然后将下一个点设置为下一个点
  5. 如果你没有回到开头那么转到2。
  6. 在jsfiddle上实现

    Here is an example。注意:它没有优化。

答案 1 :(得分:3)

我认为最简单的方法是执行plane sweep来检测所有边缘交叉点。增加基本的平面扫描算法实现来维护并不困难 最外层的边界,这就是你想要的。几乎每个textbook on computational geometry都能很好地解释这一点。

答案 2 :(得分:1)

您应该维护每个交叉点的事件边缘列表。

然后永远选择边缘(外出),它与前一个(入射)边缘具有最小角度(逆时针)。

答案 3 :(得分:1)

这是一个迟到的答案,但可以使用Javascript Clipper Library完成。所需的操作是简化(内部使用Union操作),它删除了边(s)穿过其他边的自交叉。

请注意! Javascript Clipper 5无法确保在所有情况下解决方案仅包含真正简单的多边形。这种特殊情况就是顶点接触边缘。 Clipper 6(Javascript版尚未准备好)也可以处理这些特殊情况。


使用Javascript Clipper主要演示简化多边形

您可以使用Javascript Clipper Main Demo玩Clipper。单击“多边形 - 自定义”,您可以在其中输入自己的多边形,然后进行所需的操作。

我们举个例子:
[[7,86,196,24,199,177,47,169,51,21,224,102,223,146,7,140,​​7,86]]

如果您在演示中输入这些点(作为主题或剪辑),您将获得以下多边形: enter image description here

然后进行简化操作,产生以下解决方案:

enter image description here

如果单击“多边形资源管理器”中的“解决方案”,则可以看到简化多边形的坐标: [[199,177,47,169,47.75,141.13,7,140,​​7,86,49.62,72.02,51,21,114.51,50.73,196,24,197.28,89.49,224,102,223,146,198.38,145.32]]


简化多边形的代码示例

最后,我将完整的功能代码放在JSBIN中,其中包含SVG绘图函数,因此相当长:

<html>
  <head>
    <title>Javascript Clipper Library / Simplifying Polygons</title>
    <script src="clipper.js"></script>
    <script>
function draw() {
  var subj_polygons = [[{"X":7,"Y":86},{"X":196,"Y":24},{"X":199,"Y":177},{"X":47,"Y":169},{"X":51,"Y":21},{"X":224,"Y":102},{"X":223,"Y":146},{"X":7,"Y":140},{"X":7,"Y":86}]];
  var scale = 100;
  subj_polygons = scaleup(subj_polygons, scale);
  var cpr = new ClipperLib.Clipper();
  cpr.AddPolygons(subj_polygons, ClipperLib.PolyType.ptSubject);

  var solution_polygons = new ClipperLib.Polygons();
solution_polygons = cpr.SimplifyPolygons(subj_polygons, ClipperLib.PolyFillType.pftNonZero);
  //console.log(JSON.stringify(solution_polygons));
  var svg = '<svg style="margin-top:10px; margin-right:10px;margin-bottom:10px;background-color:#dddddd" width="240" height="200">';
  svg += '<path stroke="black" fill="yellow" stroke-width="2" d="' + polys2path(solution_polygons, scale) + '"/>';
  svg += '</svg>';
  document.getElementById('svgcontainer').innerHTML = svg;
}

// helper function to scale up polygon coordinates
function scaleup(poly, scale) {
  var i, j;
  if (!scale) scale = 1;
  for(i = 0; i < poly.length; i++) {
    for(j = 0; j < poly[i].length; j++) {
      poly[i][j].X *= scale;
      poly[i][j].Y *= scale;
    }
  }
  return poly;
}

// converts polygons to SVG path string
function polys2path (poly, scale) {
  var path = "", i, j;
  if (!scale) scale = 1;
  for(i = 0; i < poly.length; i++) {
    for(j = 0; j < poly[i].length; j++) {
      if (!j) path += "M";
      else path += "L";
      path += (poly[i][j].X / scale) + ", " + (poly[i][j].Y / scale);
    }
    path += "Z";
  }
  return path;
}
    </script>
  </head>
  <body onload="draw()">
  <h2>Javascript Clipper Library / Simplifying Polygons</h2>
  This page shows an example of simplifying polygon and drawing it using SVG.
    <div id="svgcontainer"></div>
  </body>
</html>

答案 4 :(得分:0)

您似乎想要查看Convex Hull algorithms。这是几个Convex Hull算法的applet。您可能可以修改其中一种算法以获得极限点并从那里开始。

答案 5 :(得分:0)

好吧,我似乎已经找到了可行的解决方案:

http://mrpyo.github.com/Polygon/

这是ActionScript所以你应该没有问题将它翻译成JavaScript。 如果有人感兴趣,我可以解释使用过的算法......