Javascript 如何简化复杂多边形?

Javascript 如何简化复杂多边形?,javascript,geometry,polygon,Javascript,Geometry,Polygon,最近我一直在思考如何将复杂多边形转换为非复杂多边形。这是怎么做到的 这就是我想做的事情: 完成后,我将使用JavaScript,但任何形式的解决方案都可以(语言、算法或简单的英语)。您似乎想研究一下。下面是一些凸包算法的示例。您可能可以修改其中一个算法,以获得极值点,然后从那里开始。您应该维护每个交点的事件边列表 然后选择与上一条(传入)边成最小角度(逆时针方向)的边(传出)。我将使用与手动绘制多边形时相同的启发式方法(这可能不是计算多边形的最有效数学方法,但可能是最容易理解/实现的方法) 从

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

这就是我想做的事情:


完成后,我将使用JavaScript,但任何形式的解决方案都可以(语言、算法或简单的英语)。

您似乎想研究一下。下面是一些凸包算法的示例。您可能可以修改其中一个算法,以获得极值点,然后从那里开始。

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


然后选择与上一条(传入)边成最小角度(逆时针方向)的边(传出)。我将使用与手动绘制多边形时相同的启发式方法(这可能不是计算多边形的最有效数学方法,但可能是最容易理解/实现的方法)

  • 从某一点开始
  • 找到当前点和我要到达的点之间的所有交点
  • 如果不存在,则绘制到下一点
  • 如果有,则绘制到那里,然后从那里设置下一个点到下一个点
  • 如果你还没有回到起点,那就转到第二步

  • 在JSFIDLE上实现。注意:它没有经过优化。

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

    好的,看来我制定了有效的解决方案:

    它是ActionScript,所以将其转换为JavaScript应该没有问题。
    如果有人感兴趣,我可以解释使用的算法…

    这是一个迟来的答案,但这可以通过使用来完成。所需的操作是简化(内部使用并集操作),并删除边与其他边交叉的自相交

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


    使用Javascript Clipper主演示简化多边形 您可以使用“裁剪器”。单击“多边形自定义”,您可以在那里输入自己的多边形,然后进行所需的操作

    让我们以您为例:
    [7,86196241991774716951,21224102223146 71407,86]]

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

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

    如果在多边形资源管理器中单击“解决方案”,可以看到简化多边形的坐标: [1991774716947.75141.137140,7,86,49.62,72.02,51,21,114.51,50.73,196,24197.28,89.49,224102223146,198.38145.32]]


    简化多边形的代码示例 最后,我加入了完整的功能代码,其中包括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>
    
    
    Javascript裁剪器库/简化多边形
    函数绘图(){
    var subcèu 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量表=100;
    Subc_多边形=缩放(Subc_多边形,缩放);
    var cpr=new ClipperLib.Clipper();
    cpr.AddPolygons(subc_polygons,ClipperLib.PolyType.ptSubject);
    var solution_polygons=新ClipperLib.polygons();
    solution_polygons=cpr.SimplifiedPolygons(Subc_polygons,ClipperLib.PolyFillType.pftNonZero);
    //log(JSON.stringify(solution_polygons));
    var svg='';
    svg+='';
    svg+='';
    document.getElementById('svgcontainer')。innerHTML=svg;
    }
    //用于放大多边形坐标的辅助函数
    函数缩放(多边形,缩放){
    varⅠ,j;
    如果(!scale)scale=1;
    对于(i=0;i


    这是一个(硬的)数学问题,你可能会在别处得到更好的答案。@TND,如果你在别处找到了解决方案,或者找到了更好的解决方案,一定要在这里发布……期待它。这里没有两个多边形,而是一个自相交的多边形!@Alnitak同样的前提也适用于一个自相交的多边形——实际上更简单。+1表示fiddle-只有一个问题-如果(len>0.1&&…
    中的数字0.1代表什么?这是一个设计非常糟糕的检查,以确保相交不会发生在段端点。是的,我是这样想的。我对算法中出现的“神奇数字”有点担心。“首先,抓住你的野猪。”(19世纪配方)获取交点并不是特别简单,更不用说维护边和外部顶点的列表了。@Andreweach为什么获取交点“不是特别简单”?检查两个线段是否相交相对简单(不提在线资源广泛可用)它几乎解决了这个问题。是的,最佳解决方案很难,但谁说它必须是最佳的呢?@Andrew Leach在确定复杂油料的外部轮廓时存在一些问题