Calculate the center point of multiple latitude/longitude coordinate pairs

后端 未结 21 1338
暖寄归人
暖寄归人 2020-11-27 09:27

Given a set of latitude and longitude points, how can I calculate the latitude and longitude of the center point of that set (aka a point that would center a view on all poi

相关标签:
21条回答
  • 2020-11-27 09:38

    In Django this is trivial (and actually works, I had issues with a number of the solutions not correctly returning negatives for latitude).

    For instance, let's say you are using django-geopostcodes (of which I am the author).

    from django.contrib.gis.geos import MultiPoint
    from django.contrib.gis.db.models.functions import Distance
    from django_geopostcodes.models import Locality
    
    qs = Locality.objects.anything_icontains('New York')
    points = [locality.point for locality in qs]
    multipoint = MultiPoint(*points)
    point = multipoint.centroid
    

    point is a Django Point instance that can then be used to do things such as retrieve all objects that are within 10km of that centre point;

    Locality.objects.filter(point__distance_lte=(point, D(km=10)))\
        .annotate(distance=Distance('point', point))\
        .order_by('distance')
    

    Changing this to raw Python is trivial;

    from django.contrib.gis.geos import Point, MultiPoint
    
    points = [
        Point((145.137075, -37.639981)),
        Point((144.137075, -39.639981)),
    ]
    multipoint = MultiPoint(*points)
    point = multipoint.centroid
    

    Under the hood Django is using GEOS - more details at https://docs.djangoproject.com/en/1.10/ref/contrib/gis/geos/

    0 讨论(0)
  • 2020-11-27 09:39

    Very useful post! I've implemented this in JavaScript, hereby my code. I've used this successfully.

    function rad2degr(rad) { return rad * 180 / Math.PI; }
    function degr2rad(degr) { return degr * Math.PI / 180; }
    
    /**
     * @param latLngInDeg array of arrays with latitude and longtitude
     *   pairs in degrees. e.g. [[latitude1, longtitude1], [latitude2
     *   [longtitude2] ...]
     *
     * @return array with the center latitude longtitude pairs in 
     *   degrees.
     */
    function getLatLngCenter(latLngInDegr) {
        var LATIDX = 0;
        var LNGIDX = 1;
        var sumX = 0;
        var sumY = 0;
        var sumZ = 0;
    
        for (var i=0; i<latLngInDegr.length; i++) {
            var lat = degr2rad(latLngInDegr[i][LATIDX]);
            var lng = degr2rad(latLngInDegr[i][LNGIDX]);
            // sum of cartesian coordinates
            sumX += Math.cos(lat) * Math.cos(lng);
            sumY += Math.cos(lat) * Math.sin(lng);
            sumZ += Math.sin(lat);
        }
    
        var avgX = sumX / latLngInDegr.length;
        var avgY = sumY / latLngInDegr.length;
        var avgZ = sumZ / latLngInDegr.length;
    
        // convert average x, y, z coordinate to latitude and longtitude
        var lng = Math.atan2(avgY, avgX);
        var hyp = Math.sqrt(avgX * avgX + avgY * avgY);
        var lat = Math.atan2(avgZ, hyp);
    
        return ([rad2degr(lat), rad2degr(lng)]);
    }
    

    0 讨论(0)
  • 2020-11-27 09:39

    If you wish to take into account the ellipsoid being used you can find the formulae here http://www.ordnancesurvey.co.uk/oswebsite/gps/docs/A_Guide_to_Coordinate_Systems_in_Great_Britain.pdf

    see Annexe B

    The document contains lots of other useful stuff

    B

    0 讨论(0)
  • 2020-11-27 09:43

    The simple approach of just averaging them has weird edge cases with angles when they wrap from 359' back to 0'.

    A much earlier question on SO asked about finding the average of a set of compass angles.

    An expansion of the approach recommended there for spherical coordinates would be:

    • Convert each lat/long pair into a unit-length 3D vector.
    • Sum each of those vectors
    • Normalise the resulting vector
    • Convert back to spherical coordinates
    0 讨论(0)
  • 2020-11-27 09:43

    Javascript version of the original function

    /**
     * Get a center latitude,longitude from an array of like geopoints
     *
     * @param array data 2 dimensional array of latitudes and longitudes
     * For Example:
     * $data = array
     * (
     *   0 = > array(45.849382, 76.322333),
     *   1 = > array(45.843543, 75.324143),
     *   2 = > array(45.765744, 76.543223),
     *   3 = > array(45.784234, 74.542335)
     * );
    */
    function GetCenterFromDegrees(data)
    {       
        if (!(data.length > 0)){
            return false;
        } 
    
        var num_coords = data.length;
    
        var X = 0.0;
        var Y = 0.0;
        var Z = 0.0;
    
        for(i = 0; i < data.length; i++){
            var lat = data[i][0] * Math.PI / 180;
            var lon = data[i][1] * Math.PI / 180;
    
            var a = Math.cos(lat) * Math.cos(lon);
            var b = Math.cos(lat) * Math.sin(lon);
            var c = Math.sin(lat);
    
            X += a;
            Y += b;
            Z += c;
        }
    
        X /= num_coords;
        Y /= num_coords;
        Z /= num_coords;
    
        var lon = Math.atan2(Y, X);
        var hyp = Math.sqrt(X * X + Y * Y);
        var lat = Math.atan2(Z, hyp);
    
        var newX = (lat * 180 / Math.PI);
        var newY = (lon * 180 / Math.PI);
    
        return new Array(newX, newY);
    }
    
    0 讨论(0)
  • 2020-11-27 09:43

    very nice solutions, just what i needed for my swift project, so here's a swift port. thanks & here's also a playground project: https://github.com/ppoh71/playgounds/tree/master/centerLocationPoint.playground

    /*
    * calculate the center point of multiple latitude longitude coordinate-pairs
    */
    
    import CoreLocation
    import GLKit
    
    var LocationPoints = [CLLocationCoordinate2D]()
    
    //add some points to Location ne, nw, sw, se , it's a rectangle basicaly
    LocationPoints.append(CLLocationCoordinate2D(latitude: 37.627512369999998, longitude: -122.38780611999999))
    LocationPoints.append(CLLocationCoordinate2D(latitude: 37.627512369999998, longitude:  -122.43105867))
    LocationPoints.append(CLLocationCoordinate2D(latitude: 37.56502528, longitude: -122.43105867))
    LocationPoints.append(CLLocationCoordinate2D(latitude: 37.56502528, longitude: -122.38780611999999))
    
    // center func
    func getCenterCoord(LocationPoints: [CLLocationCoordinate2D]) -> CLLocationCoordinate2D{
    
        var x:Float = 0.0;
        var y:Float = 0.0;
        var z:Float = 0.0;
    
        for points in LocationPoints {
    
         let lat = GLKMathDegreesToRadians(Float(points.latitude));
         let long = GLKMathDegreesToRadians(Float(points.longitude));
    
            x += cos(lat) * cos(long);
            y += cos(lat) * sin(long);
            z += sin(lat);
        }
    
        x = x / Float(LocationPoints.count);
        y = y / Float(LocationPoints.count);
        z = z / Float(LocationPoints.count);
    
        let resultLong = atan2(y, x);
        let resultHyp = sqrt(x * x + y * y);
        let resultLat = atan2(z, resultHyp);
    
    
    
        let result = CLLocationCoordinate2D(latitude: CLLocationDegrees(GLKMathRadiansToDegrees(Float(resultLat))), longitude: CLLocationDegrees(GLKMathRadiansToDegrees(Float(resultLong))));
    
        return result;
    
    }
    
    //get the centerpoint
    var centerPoint = getCenterCoord(LocationPoints)
    print("Latitude: \(centerPoint.latitude) / Longitude: \(centerPoint.longitude)")
    
    0 讨论(0)
提交回复
热议问题