【问题标题】:Find polygon perimeter of points quickly in Javascript在Javascript中快速查找点的多边形周长
【发布时间】:2014-08-27 07:21:36
【问题描述】:

我正在制作一个地形编辑器,我需要找到一组点的周边多边形。如果我只需要一个凸包,那么速度就没有问题了。要制作一个凹形船体,我必须经过几圈。我发现我可以对这些点进行三角测量,然后丢弃任何边长于已知点之间距离的三角形。

接下来的问题是:使用 JSTS 几何库 (http://github.com/bjornharrtell/jsts) 将三角形(作为迷你多边形)组合成一个大多边形真的很慢。

查看完整代码:http://codepen.io/anon/pen/oCfDh

我有一个数组(多边形),它被合并形成最终的多边形。问题是 552 点(我想支持 15k+),运行大约需要 3500 毫秒。查看 codepen 链接中的控制台以了解您的速度。

  var reader = new jsts.io.WKTReader(),
      merged = reader.read(polys[0]).union(reader.read(polys[1]));
  console.time('jsts mergization');
  for(var i = 2; i<polys.length; i++){
    try{
      merged = merged.union(reader.read(polys[i]));
    }catch(err){
      console.log('Error triangulating points!');
    };
  };
  console.timeEnd('jsts mergization');

有没有人知道任何更快的方法可以将三角形合并成一个多边形,或者更宽一些并以完全不同的方式从一组点构建一个凹多边形?

【问题讨论】:

  • 在 Firefox 中运行大约需要 9269.50 毫秒,并且会冻结整个浏览器 :( 只是稍作修正.. 抱歉,不知道如何解决。
  • 既然知道是三角剖分,就不能只索引每个三角形的相邻点,从顶部三角形开始排序遍历边界吗?

标签: javascript optimization polygon convex-polygon


【解决方案1】:

谢谢西蒙扎克!

我已经根据你的建议重写了算法,而且速度更快!

重做的codepen:http://codepen.io/anon/pen/Btdyj

同样的例子现在运行大约 15 毫秒!

function pointsToPolygon(points, triangles, maxEdgeLength){
  console.time('homebrewed mergization');
  var dist = function(a, b){
    if(typeof a === "number"){
      a = points[a];
    };
    if(typeof b === "number"){
      b = points[b];
    };
    return Math.sqrt(Math.pow(a[0] - b[0], 2) + 
            Math.pow(a[1] - b[1], 2));
  };
  if(!points.length){
    return undefined;
  };
  var pointFreq = [];
  points.forEach(function(v){
    pointFreq.push(0);
  });
  for(var i = triangles.length; i; i-=3){
    if(dist(triangles[i-1], triangles[i-2]) < maxEdgeLength &&
       dist(triangles[i-3], triangles[i-2]) < maxEdgeLength &&
       dist(triangles[i-1], triangles[i-3]) < maxEdgeLength){
      pointFreq[triangles[i-1]]++;
      pointFreq[triangles[i-2]]++;
      pointFreq[triangles[i-3]]++;
    };
  };

  // Keep points that are used in 3 or fewer triangles
  var output =[];
  pointFreq.forEach(function(freq, i){
    if(freq<4){
      output.push(points[i]);
    };
  });

  // Sort points by looping around by each next closest point
  var sorted = [];
  while(output.length>0){
    sorted.push(output.pop());
    output=output.sort(function(a,b){
      var distA =dist(sorted[sorted.length-1], a),
          distB =dist(sorted[sorted.length-1], b);
      if(distA < distB){
        return 1;
      }else if(distA === distB){
        return 0;
      };
      return -1;
    });
  };

  sorted=simplifyPath(sorted,0.1);

  console.timeEnd('homebrewed mergization');
  return sorted;

};

我可以通过过滤在 3 个或更少的三角形中使用的点来找到边界,然后通过从任意点的每个下一个最近点循环来对点进行排序。

由于 Douglas-Peucker 简化算法(改编自 https://gist.github.com/adammiller/826148),可能不是 100% 准确,但对我来说似乎已经足够了。

【讨论】:

  • 我做了一些模组来进一步加速:我添加了simplify.js,它非常快,删除了一些sqrts和阻碍优化的东西。代码现在以 1.5 毫秒而不是 3.2 毫秒运行。更快:jsbin.com/qekovo/1/edit?console,output,更慢:jsbin.com/nitata/1/edit?console,output。这似乎是很小的加速,但如果点数是 15k+ 而不是当前的 552,这很重要。
猜你喜欢
  • 2013-04-23
  • 2021-02-02
  • 2018-10-21
  • 2017-03-18
  • 2016-01-23
  • 2018-06-27
  • 1970-01-01
  • 2013-12-16
  • 2019-12-07
相关资源
最近更新 更多