Dado un conjunto de latitud y longitud de los puntos, ¿cómo puedo calcular la latitud y longitud del punto central de ese conjunto (también conocido como un punto en el que sería el centro de una vista en todos los puntos)?

EDICIÓN: Python solución que yo he utilizado:

Convert lat/lon (must be in radians) to Cartesian coordinates for each location.
X = cos(lat) * cos(lon)
Y = cos(lat) * sin(lon)
Z = sin(lat)

Compute average x, y and z coordinates.
x = (x1 + x2 + ... + xn) / n
y = (y1 + y2 + ... + yn) / n
z = (z1 + z2 + ... + zn) / n

Convert average x, y, z coordinate to latitude and longitude.
Lon = atan2(y, x)
Hyp = sqrt(x * x + y * y)
Lat = atan2(z, hyp)
  • Con respecto a su solución: Probablemente sus errores no ser demasiado grande, con su asunción de una tierra esférica, pero la tierra se describe mejor como un elipsoide.
  • Escribió esto como una función de python y la compartió en gist.github.com/3718961
  • Es muy importante tener en cuenta que este se supone que la lat y long son en radianes! Yo estaba rascándome la cabeza por un rato no darse cuenta de ello. Para convertir a radianes de un decimal, multiplica el decimal * pi/180. A continuación, para convertir radianes a decimal, se multiplican por 180/pi. HTH
  • Lo siento por el retraso, pero me preguntaba, ¿qué es la matemática detrás de este algoritmo, podría alguien aconsejarme algunas lecturas donde esto se explica? Gracias!
  • Si no lo has hecho, echa un vistazo a el enlace en mi comentario bajo la aceptó responder
  • ¿Qué es z, pls?
  • Fijo función de python con este gist. Controladores de función de la lista de coordenadas en grados.

InformationsquelleAutor zeke | 2011-07-12

17 Comentarios

  1. 46

    El enfoque simple de sólo un promedio de las mismas ha raros casos de borde con ángulos cuando se envuelven de 359′ a 0′.

    Un mucho antes de la pregunta sobre LO preguntó acerca de encontrar el promedio de un conjunto de brújula ángulos.

    Una expansión del enfoque que se recomienda no para coordenadas esféricas sería:

    • Convertir cada lat/long par en una unidad de longitud vectorial 3D.
    • Suma de cada uno de los vectores de
    • Normalizar el vector resultante
    • Volver a convertir a coordenadas esféricas
    • Parece bueno, yo hice algo similar, basado en lo que he encontrado en este sitio web: geomidpoint.com/calculation.html.
    • downvoter – por favor, explicar y ofrecer una mejor solución si usted puede.
  2. 80

    Gracias! Aquí está una versión de C# de OP soluciones mediante el uso de grados. Utiliza el Sistema.Dispositivo.Ubicación.GeoCoordinate clase

        public static GeoCoordinate GetCentralGeoCoordinate(
            IList<GeoCoordinate> geoCoordinates)
        {
            if (geoCoordinates.Count == 1)
            {
                return geoCoordinates.Single();
            }
    
            double x = 0;
            double y = 0;
            double z = 0;
    
            foreach (var geoCoordinate in geoCoordinates)
            {
                var latitude = geoCoordinate.Latitude * Math.PI / 180;
                var longitude = geoCoordinate.Longitude * Math.PI / 180;
    
                x += Math.Cos(latitude) * Math.Cos(longitude);
                y += Math.Cos(latitude) * Math.Sin(longitude);
                z += Math.Sin(latitude);
            }
    
            var total = geoCoordinates.Count;
    
            x = x / total;
            y = y / total;
            z = z / total;
    
            var centralLongitude = Math.Atan2(y, x);
            var centralSquareRoot = Math.Sqrt(x * x + y * y);
            var centralLatitude = Math.Atan2(z, centralSquareRoot);
    
            return new GeoCoordinate(centralLatitude * 180 / Math.PI, centralLongitude * 180 / Math.PI);
        }
  3. 39

    He encontrado este post muy útil, así que aquí está la solución en PHP. He estado usando con éxito, y sólo quería salvar a otro dev algún tiempo.

    /**
     * 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 (!is_array($data)) return FALSE;
    
        $num_coords = count($data);
    
        $X = 0.0;
        $Y = 0.0;
        $Z = 0.0;
    
        foreach ($data as $coord)
        {
            $lat = $coord[0] * pi() / 180;
            $lon = $coord[1] * pi() / 180;
    
            $a = cos($lat) * cos($lon);
            $b = cos($lat) * sin($lon);
            $c = sin($lat);
    
            $X += $a;
            $Y += $b;
            $Z += $c;
        }
    
        $X /= $num_coords;
        $Y /= $num_coords;
        $Z /= $num_coords;
    
        $lon = atan2($Y, $X);
        $hyp = sqrt($X * $X + $Y * $Y);
        $lat = atan2($Z, $hyp);
    
        return array($lat * 180 / pi(), $lon * 180 / pi());
    }
    • He utilizado esta solución, sino que de alguna manera da una solución equivocada – si puedo buscar en el centro de algunas coordenadas sobre un mapa es una especie de «pesa» los puntos y tiende a permanecer donde hay más puntos.
    • eso es lo que un promedio…
    • Aquí queremos buscar en el centro de la zona circunscrita por las coordenadas. Estás seguro de que has comentado en el lugar correcto?
  4. 26

    Muy útil el post!!! He implementado esta en JavaScript, por medio de la presente mi código. La he usado con éxito.

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

    • Sé que el post es viejo, pero podría usted por favor enviar una referencia o algo explicando las Matemáticas detrás del algoritmo que has publicado? Gracias!
    • Su muy profundo..!
    • Funcionó A La Perfección! Gracias
    • He probado el script con Google Apps Script, pero el resultado no es el punto central exacto de una pista. Es en algún lugar cercano, pero no directamente EN la pista. Es la mejor fórmula para conseguir la exacta middlepoint EN LA PISTA?
  5. 12

    Versión de Javascript de la función original

    /**
     * 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);
    }
    
  6. 12

    En el interés de la posibilidad de salvar a alguien de un minuto o dos, aquí está la solución que se utilizó en Objective-C en lugar de python. Esta versión lleva un NSArray de NSValues que contienen MKMapCoordinates, que fue llamado para que en mi aplicación:

    #import <MapKit/MKGeometry.h>
    
    + (CLLocationCoordinate2D)centerCoordinateForCoordinates:(NSArray *)coordinateArray {
        double x = 0;
        double y = 0;
        double z = 0;
    
        for(NSValue *coordinateValue in coordinateArray) {
            CLLocationCoordinate2D coordinate = [coordinateValue MKCoordinateValue];
    
            double lat = GLKMathDegreesToRadians(coordinate.latitude);
            double lon = GLKMathDegreesToRadians(coordinate.longitude);
            x += cos(lat) * cos(lon);
            y += cos(lat) * sin(lon);
            z += sin(lat);
        }
    
        x = x / (double)coordinateArray.count;
        y = y / (double)coordinateArray.count;
        z = z / (double)coordinateArray.count;
    
        double resultLon = atan2(y, x);
        double resultHyp = sqrt(x * x + y * y);
        double resultLat = atan2(z, resultHyp);
    
        CLLocationCoordinate2D result = CLLocationCoordinate2DMake(GLKMathRadiansToDegrees(resultLat), GLKMathRadiansToDegrees(resultLon));
        return result;
    }
    • Para alguien por ahí, por lo que su valor, en Lugar de utilizar su propia macro de grados a radianes, importación <GLKit/GLKMath.h> y uso GLKMathDegreesToRadians y GLKMathRadiansToDegrees
  7. 7

    muy agradable soluciones, justo lo que necesitaba para mi swift proyecto, así que aquí un swift puerto. gracias & aquí hay también un parque infantil proyecto:
    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)")
    
    • Me gustaría poder dar más puntos. Gracias!!!
  8. 4

    Si usted está interesado en la obtención de una muy simplificado en el ‘centro’ de los puntos (por ejemplo, simplemente el centro de un mapa del centro de la gmaps polígono), entonces este es un enfoque que trabajó para mí.

    public function center() {
        $minlat = false;
        $minlng = false;
        $maxlat = false;
        $maxlng = false;
        $data_array = json_decode($this->data, true);
        foreach ($data_array as $data_element) {
            $data_coords = explode(',',$data_element);
            if (isset($data_coords[1])) {
                if ($minlat === false) { $minlat = $data_coords[0]; } else { $minlat = ($data_coords[0] < $minlat) ? $data_coords[0] : $minlat; }
                if ($maxlat === false) { $maxlat = $data_coords[0]; } else { $maxlat = ($data_coords[0] > $maxlat) ? $data_coords[0] : $maxlat; }
                if ($minlng === false) { $minlng = $data_coords[1]; } else { $minlng = ($data_coords[1] < $minlng) ? $data_coords[1] : $minlng; }
                if ($maxlng === false) { $maxlng = $data_coords[1]; } else { $maxlng = ($data_coords[1] > $maxlng) ? $data_coords[1] : $maxlng; }
            }
        }
        $lat = $maxlat - (($maxlat - $minlat) /2);
        $lng = $maxlng - (($maxlng - $minlng) /2);
        return $lat.','.$lng;
    }
    

    Esta devuelve la media lat/lng coordenadas del centro de un polígono.

  9. 3

    En Django esto es trivial (y realmente funciona, yo tuve problemas con un número de soluciones no devuelve correctamente negativos para la latitud).

    Por ejemplo, digamos que usted está usando django-geopostcodes (de los cuales yo soy el autor).

    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 es una Django Point instancia que puede entonces ser utilizado para cosas tales como recuperar todos los objetos que están a menos de 10 km de centre point;

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

    Cambiar esta cruda Python es 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

    Bajo el capó Django es el uso de GEOS – más detalles en https://docs.djangoproject.com/en/1.10/ref/contrib/gis/geos/

  10. 1

    Este es el mismo como un promedio ponderado de problema en el que todos los pesos son iguales, y hay dos dimensiones.

    Encontrar el promedio de todas las latitudes para su centro de latitud y el promedio de todas las longitudes para el centro de la longitud.

    Caveat Emptor: Esta es una corta distancia de aproximación y el error se vuelven ingobernables cuando las desviaciones de la media son más que un par de kilómetros debido a la curvatura de la Tierra. Recuerde que las latitudes y longitudes son grados (no es realmente una cuadrícula).

  11. 1

    Aquí es el de la Versión de python para encontrar el punto central.
    El lat1 y lon1 son la latitud y la longitud de las listas.
    se retuen la latitud y longitud del punto central.

    def GetCenterFromDegrees(lat1,lon1):    
        if (len(lat1) <= 0):
        return false;
    
    num_coords = len(lat1)
    
    X = 0.0
    Y = 0.0
    Z = 0.0
    
    for i in range (len(lat1)):
        lat = lat1[i] * np.pi /180
        lon = lon1[i] * np.pi /180
    
        a = np.cos(lat) * np.cos(lon)
        b = np.cos(lat) * np.sin(lon)
        c = np.sin(lat);
    
        X += a
        Y += b
        Z += c
    
    
    X /= num_coords
    Y /= num_coords
    Z /= num_coords
    
    lon = np.arctan2(Y, X)
    hyp = np.sqrt(X * X + Y * Y)
    lat = np.arctan2(Z, hyp)
    
    newX = (lat * 180 /np.pi)
    newY = (lon * 180 /np.pi)
    return newX, newY
    
  12. 0

    Si quieres todos los puntos para ser visibles en la imagen, usted quiere los extremos de latitud y longitud y asegúrese de que su punto de vista incluye los valores con lo borde que desee.

    (De Alnitak la respuesta, cómo se calcula la extrema puede ser un poco problemático, pero si son un par de grados a ambos lados de la longitud que se envuelve alrededor, entonces usted va a llamar a la toma y toma a la derecha el rango).

    Si usted no desea distorsionar cualquier mapa que estos puntos están en, a continuación, ajuste el cuadro delimitador de la relación de aspecto para que se adapte a cualquier píxeles que se ha asignado a la vista, pero todavía incluye los extremos.

    Para mantener los puntos de centrado en arbitraria en el nivel de zoom, calcular el centro del cuadro delimitador que «sólo se ajusta a» los puntos anteriormente citados, y mantener ese punto como el punto central.

  13. 0

    De objetos en PHP. Dada la matriz de pares de coordenadas, centro de devoluciones.

    /**
     * Calculate center of given coordinates
     * @param  array    $coordinates    Each array of coordinate pairs
     * @return array                    Center of coordinates
     */
    function getCoordsCenter($coordinates) {    
        $lats = $lons = array();
        foreach ($coordinates as $key => $value) {
            array_push($lats, $value[0]);
            array_push($lons, $value[1]);
        }
        $minlat = min($lats);
        $maxlat = max($lats);
        $minlon = min($lons);
        $maxlon = max($lons);
        $lat = $maxlat - (($maxlat - $minlat) /2);
        $lng = $maxlon - (($maxlon - $minlon) /2);
        return array("lat" => $lat, "lon" => $lng);
    }
    

    Tomado la idea de #4

    • Esto no iba a funcionar para las coordenadas de cruzar el meridiano 180º. Por ejemplo, dos longitudal puntos, -175 y 175 volvería un centro de 0 en su algoritmo, mediante el cual el centro real sería -180 y 180.
  14. 0

    Hice esta tarea en javascript, como el de abajo

    function GetCenterFromDegrees(data){
        //var data = [{lat:22.281610498720003,lng:70.77577162868579},{lat:22.28065743343672,lng:70.77624369747241},{lat:22.280860953131217,lng:70.77672113067706},{lat:22.281863655593973,lng:70.7762061465462}];
        var num_coords = data.length;
        var X = 0.0;
        var Y = 0.0;
        var Z = 0.0;
    
        for(i=0; i<num_coords; i++){
            var lat = data[i].lat * Math.PI /180;
            var lon = data[i].lng * 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;
    
        lon = Math.atan2(Y, X);
        var hyp = Math.sqrt(X * X + Y * Y);
        lat = Math.atan2(Z, hyp);
    
        var finalLat = lat * 180 /Math.PI;
        var finalLng =  lon * 180 /Math.PI; 
    
        var finalArray = Array();
        finalArray.push(finalLat);
        finalArray.push(finalLng);
        return finalArray;
    }
    
  15. 0

    Como un reconocimiento por este hilo, aquí está mi pequeña aportación con la aplicación en Ruby, con la esperanza de que voy a salvar a alguien de un par de minutos de su precioso tiempo:

    def self.find_center(locations)
    
     number_of_locations = locations.length
    
     return locations.first if number_of_locations == 1
    
     x = y = z = 0.0
     locations.each do |station|
       latitude = station.latitude * Math::PI /180
       longitude = station.longitude * Math::PI /180
    
       x += Math.cos(latitude) * Math.cos(longitude)
       y += Math.cos(latitude) * Math.sin(longitude)
       z += Math.sin(latitude)
     end
    
     x = x/number_of_locations
     y = y/number_of_locations
     z = z/number_of_locations
    
     central_longitude =  Math.atan2(y, x)
     central_square_root = Math.sqrt(x * x + y * y)
     central_latitude = Math.atan2(z, central_square_root)
    
     [latitude: central_latitude * 180 /Math::PI, 
     longitude: central_longitude * 180 /Math::PI]
    end
    
  16. 0

    He utilizado una fórmula que recibí de http://www.geomidpoint.com y escribió la siguiente implementación en C++. El array y geocoords son mis propias clases cuya funcionalidad debe ser auto-explicativo.

    /*
     * midpoints calculated using formula from www.geomidpoint.com
     */
       geocoords geocoords::calcmidpoint( array<geocoords>& points )
       {
          if( points.empty() ) return geocoords();
    
          float cart_x = 0,
                cart_y = 0,
                cart_z = 0;
    
          for( auto& point : points )
          {
             cart_x += cos( point.lat.rad() ) * cos( point.lon.rad() );
             cart_y += cos( point.lat.rad() ) * sin( point.lon.rad() );
             cart_z += sin( point.lat.rad() );
          }
    
          cart_x /= points.numelems();
          cart_y /= points.numelems();
          cart_z /= points.numelems();
    
          geocoords mean;
    
          mean.lat.rad( atan2( cart_z, sqrt( pow( cart_x, 2 ) + pow( cart_y, 2 ))));
          mean.lon.rad( atan2( cart_y, cart_x ));
    
          return mean;
       }
    

Dejar respuesta

Please enter your comment!
Please enter your name here