Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can you find the centroid of a concave irregular polygon in JavaScript?

How can you find the centroid of a concave irregular polygon given its vertices in JavaScript?

I want to pass a set of x,y points to a JavaScript function and be given an x,y point.

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);

The my_points variable is only supposed to represent the format of the points to be given, not to represent the specific count of points to be given.

The centroid returned will be a point somewhere inside the polygon.

The end goal would be to add a marker at the centroid of a polygon in a Google Maps V3 application.

like image 971
iambriansreed Avatar asked Mar 13 '12 21:03

iambriansreed


People also ask

How do you find the center of gravity of a polygon?

The general method for finding the center of gravity of a polygon is to use its diagonals to split it into several triangles and then find the intersection of the lines connecting the centroids of the pairs of triangles that share a common diagonal [1,2].

What is the center of a polygon?

The center of the incircle, called the incenter, can be considered a center of the polygon. A cyclic polygon has each of its vertices on a particular circle, called the circumcircle or circumscribed circle. The center of the circumcircle, called the circumcenter, can be considered a center of the polygon.


2 Answers

For the centroid of the 2D surface (which is likely to be what you need), The best is to start with a little bit of maths.

I adapted it here to your own notation :

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 };
}
like image 136
Myobis Avatar answered Oct 13 '22 00:10

Myobis


The accepted answer has an issue which becomes prominent as the polygon's area becomes smaller. It would not be visible in most cases, but can result in some weird results at very small dimensions. Here's an update to that solution to account for this issue.

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 };
}

Here's a case of a centroid ending up outside of a small polygon for anyone curious as to what I'm talking about:

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 }
like image 34
pragmar Avatar answered Oct 13 '22 00:10

pragmar