pelias / pbf2json

An OpenStreetMap pbf parser which exports json, allows you to cherry-pick tags and handles denormalizing ways and relations. Available as a standalone binary and comes with a convenient npm wrapper.
https://pelias.io
MIT License
143 stars 36 forks source link

compute way centroids #22

Closed missinglink closed 9 years ago

missinglink commented 9 years ago

Move the centroid calcs to Go; because CPU

riordan commented 9 years ago

👍🏿

Sent from my iPhone

On May 18, 2015, at 3:26 PM, Peter Johnson a.k.a. insertcoffee notifications@github.com wrote:

— Reply to this email directly or view it on GitHub.

missinglink commented 9 years ago

we should be able to port this js function except when I read the trig code my brain exploded...

/**
* Calculates the center of a collection of geo coordinates
*
* @param        array       Collection of coords [{latitude: 51.510, longitude: 7.1321}, {latitude: 49.1238, longitude: "8° 30' W"}, ...]
* @return       object      {latitude: centerLat, longitude: centerLng}
*/

getCenter: function(coords) {

    if (!coords.length) {
        return false;
    }

    var X = 0.0;
    var Y = 0.0;
    var Z = 0.0;
    var lat, lon, hyp;

    coords.forEach(function(coord) {

        lat = coord.latitude * Math.PI / 180;
        lon = coord.longitude * Math.PI / 180;

        X += Math.cos(lat) * Math.cos(lon);
        Y += Math.cos(lat) * Math.sin(lon);
        Z += Math.sin(lat);

    });

    var nb_coords = coords.length;
    X = X / nb_coords;
    Y = Y / nb_coords;
    Z = Z / nb_coords;

    lon = Math.atan2(Y, X);
    hyp = Math.sqrt(X * X + Y * Y);
    lat = Math.atan2(Z, hyp);

    return {
        latitude: (lat * 180 / Math.PI).toFixed(6),
        longitude: (lon * 180 / Math.PI).toFixed(6)
    };
}
missinglink commented 9 years ago

It's important to note that there are X different algorithms for computing the centroid of an irregular polygon; all of which are correct and wrong at the same time (there is no 'real' answer to be had here), this paradox is nicely summed up here:

"Irregular polygons are not considered as having a center, since there is unlikely to be any one point equally distant form each vertex. However, an irregular polygon can have a centroid, or center of gravity."

The simplest algo is to compute the centroid of the points which form the polygon is: ref: https://en.wikipedia.org/wiki/Centroid#Of_a_finite_set_of_points

This is actually super easy and could be done with a simple function like this:

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

The function in my previous comment seems to do a better job of computing a 'center of gravity' which is more computationally expensive but may be 'better'!? ref: https://en.wikipedia.org/wiki/Centroid#Centroid_of_polygon

Either way, when we are talking about buildings the difference will be negligible, yet it would be ideal if the centroid fell within the polygon itself (think of building with a U shaped foundation), however when we are talking about large country-size polygons the algo we choose could vary the centroid by many km.

missinglink commented 9 years ago

resolved by https://github.com/pelias/pbf2json/pull/23