【问题标题】:How can you find the centroid of a concave irregular polygon in JavaScript?如何在 JavaScript 中找到凹不规则多边形的质心?
【发布时间】:2012-03-30 08:24:53
【问题描述】:

如何在 JavaScript 中给定顶点的凹不规则多边形的质心?

我想将一组 x,y 点传递给 JavaScript 函数并获得一个 x,y 点。

var my_points = [{x:3,y:1},{x:5,y:8},{x:2,y:9}];

function get_polygon_centroid(points){
    // answer
}

var my_centroid = get_polygon_centroid(my_points);

my_points变量应该只表示要给出的分数的格式,不代表具体给出的分数数

返回的 质心 将是多边形内的某个点。

最终目标是在 Google Maps V3 应用程序中的多边形质心处添加一个标记。

【问题讨论】:

标签: javascript polygon


【解决方案1】:

对于 2D 表面的质心(这可能是您需要的), 最好以a little bit of maths开头。

我在这里将它改编为您自己的符号:

function get_polygon_centroid(pts) {
   var first = pts[0], last = pts[pts.length-1];
   if (first.x != last.x || first.y != last.y) pts.push(first);
   var twicearea=0,
   x=0, y=0,
   nPts = pts.length,
   p1, p2, f;
   for ( var i=0, j=nPts-1 ; i<nPts ; j=i++ ) {
      p1 = pts[i]; p2 = pts[j];
      f = p1.x*p2.y - p2.x*p1.y;
      twicearea += f;          
      x += ( p1.x + p2.x ) * f;
      y += ( p1.y + p2.y ) * f;
   }
   f = twicearea * 3;
   return { x:x/f, y:y/f };
}

【讨论】:

  • 正如维基百科在参考文章中所说,重要的是要注意:“顶点被假定按照它们沿着多边形周长出现的顺序编号,并且顶点 (xn, yn)假定与 (x0, y0)" 相同
  • 调整为自动关闭多边形 if (x0, y0) != (xn, yn)
  • 我认为第一行var first = t[0]应该是var first = pts[0]
  • 感谢您发现这个@JoeRocc
  • pts.push(first)之前克隆数组pts = [...pts]
【解决方案2】:

接受的答案有一个问题,随着多边形的面积变小,这个问题变得越来越突出。在大多数情况下它是不可见的,但在非常小的尺寸下可能会导致一些奇怪的结果。这是该解决方案的更新以解决此问题。

function get_polygon_centroid(pts) {
   var first = pts[0], last = pts[pts.length-1];
   if (first.x != last.x || first.y != last.y) pts.push(first);
   var twicearea=0,
   x=0, y=0,
   nPts = pts.length,
   p1, p2, f;
   for ( var i=0, j=nPts-1 ; i<nPts ; j=i++ ) {
      p1 = pts[i]; p2 = pts[j];
      f = (p1.y - first.y) * (p2.x - first.x) - (p2.y - first.y) * (p1.x - first.x);
      twicearea += f;
      x += (p1.x + p2.x - 2 * first.x) * f;
      y += (p1.y + p2.y - 2 * first.y) * f;
   }
   f = twicearea * 3;
   return { x:x/f + first.x, y:y/f + first.y };
}

对于任何好奇我在说什么的人来说,这是一个质心最终在一个小多边形之外的例子:

var points = [
    {x:78.0001462, y: 40.0008827},
    {x:78.0000228, y: 40.0008940},
    {x:78.0000242, y: 40.0009264},
    {x:78.0001462, y: 40.0008827},
];
// original get_polygon_centroid(points)
// results in { x: 77.99957948181007, y: 40.00065236005001 }
console.log(get_polygon_centroid(points))
// result is { x: 78.0000644, y: 40.000901033333335 }

【讨论】:

  • +1 用于处理基本方法的实际问题,令人惊讶的是在维基百科和我检查的其他地方没有提到。但是,解决方案有一个错误:以x += (p1.y + p2.y ...y += (p1.x + p2.x ... 开头的行当然应该是x += (p1.x + p2.x ...y += (p1.y + p2.y ...
  • 哎呀!谢谢你明白,乔纳斯。固定。
  • 是什么导致了这个问题?舍入错误?
【解决方案3】:

这很简单。 centroid of a finite set of k points x1, x2, ... xk 用公式描述 p>

(x1 + x2 + ... + xk) / k

这意味着我们可以将所有点相加,然后除以点数,如下所示:

function getPolygonCentroid(points){ 
  var centroid = {x: 0, y: 0};
  for(var i = 0; i < points.length; i++) {
     var point = points[i];
     centroid.x += point.x;
     centroid.y += point.y;
  }
  centroid.x /= points.length;
  centroid.y /= points.length;
  return centroid;
} 

【讨论】:

  • -1:在同一 wiki 页面中给出的多边形的质心与形成它的点的质心不同。您对多个点的质心的定义是正确的。但是任何区域的质心都定义为其质心的位置,通常与顶点的质心不同。
  • 我试图纠正其中一个“点”引用中缺少的“i”,但愚蠢的编辑器要求我至少更改 6 个字符,所以我将示例中的方法名称更改为驼峰式(无论如何这在 JS 中更常见) - 希望这没关系 Peter Olson? (我不知道如何进行更改,因此该示例可以正常工作而不会因拼写错误而引发错误)
【解决方案4】:

如果您对“质心”的定义不随意,this 是多边形质心的公式。如您所见,它比一组点的质心复杂得多。如果你可以处理点的质心,那很好,但如果你想要多边形的质心,你就必须实现这个公式,顺便说一句,这不是很困难。请记住,在不规则多边形的一般情况下,即您的情况,这两个质心将不同(否则此公式将不存在)。

【讨论】:

  • 你给的质心仍然是一组点的质心;点的集合是无限的...... :)
  • 当然,我只是不想详细说明。在另一种情况下,我们认为这些点是质量相等的质点,这里我们认为质量在多边形内均匀分布。
【解决方案5】:

基于Myobis'pragmar's 的答案,没有必要通过复制第一个元素来更改数组。 事实上,在他们的实现中,for 循环的第一次迭代没有做任何事情,因为pts[i]pts[j] 是相同的。

这里是经过一些优化的相同算法(最初移植自Finding the centroid of a polygon?):

function get_polygon_centroid(points) {
    //Correction for very small polygons:
    const x0 = points[0].x , y0 = points[0].y;

    let x = 0, y = 0, twiceArea = 0;

    let prev = points[points.length - 1];
    for (const next of points)
    {
        const x1 = prev.x - x0, y1 = prev.y - y0,
              x2 = next.x - x0, y2 = next.y - y0,
              a  = x1 * y2 - x2 * y1;

        twiceArea += a;
        x += (x1 + x2) * a;
        y += (y1 + y2) * a;

        prev = next;
    }

    const factor = 3 * twiceArea;  // 6 * twiceArea/2
    x /= factor;
    y /= factor;

    return { x: x + x0, y: y + y0 };
}

const points = [
    { x: 78.0001462, y: 40.0008827 },
    { x: 78.0000228, y: 40.0008940 },
    { x: 78.0000242, y: 40.0009264 },
];
console.log(get_polygon_centroid(points));

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-09-01
    • 1970-01-01
    • 2013-11-22
    • 2012-11-05
    • 2017-01-09
    相关资源
    最近更新 更多