Calcular el punto central de múltiples pares de coordenadas de latitud / longitud

148

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

EDITAR: solución de Python que he usado:

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)
zeke
fuente
2
Con respecto a su solución: Probablemente sus errores no serán demasiado grandes con su suposición de una tierra esférica, pero la tierra se describe mejor como un elipsoide.
John
1
Escribió esto como una función de Python y lo compartió en gist.github.com/3718961
Alvin
14
¡Es muy importante tener en cuenta que esto supone que su lat y long están en radianes! Estuve rascándome la cabeza por un tiempo sin darme cuenta de eso. Para convertir a radianes de decimal, multiplique el decimal * pi / 180. Luego, para volver a convertir de radianes a decimal, multiplique por 180 / pi. HTH
Ryan Guill
1
Perdón por llegar tarde, pero me preguntaba, ¿cuál es la matemática detrás de este algoritmo, alguien podría aconsejarme algunas lecturas donde se explica esto? ¡Gracias!
tonix
1
¿Qué es z, por favor?
SoS

Respuestas:

48

El enfoque simple de simplemente promediarlos tiene casos de borde extraños con ángulos cuando se ajustan desde 359 'de nuevo a 0'.

Una pregunta mucho anterior sobre SO preguntó acerca de encontrar el promedio de un conjunto de ángulos de brújula.

Una expansión del enfoque recomendado allí para las coordenadas esféricas sería:

  • Convierta cada par lat / largo en un vector 3D de longitud unitaria.
  • Suma cada uno de esos vectores
  • Normalizar el vector resultante
  • Convertir de nuevo a coordenadas esféricas
Alnitak
fuente
66
Parece bueno, hice algo similar según lo que encontré en este sitio web: geomidpoint.com/calculation.html .
zeke
44
votante negativo: explique y ofrezca una mejor solución si puede.
Alnitak
90

¡Gracias! Aquí hay una versión C # de las soluciones de OP usando grados. Utiliza la clase System.Device.Location.GeoCoordinate

    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);
    }
Yodacheese
fuente
40

Esta publicación me pareció muy útil, así que aquí está la solución en PHP. He estado usando esto con éxito y solo quería guardar otro desarrollador en algún momento.

/**
 * 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());
}
Tom Tucker
fuente
1
He usado esta solución pero proporciona una solución de alguna manera incorrecta: si busco el centro de algunas coordenadas en un mapa, "pesa" los puntos y tiende a permanecer donde hay más puntos.
LowFieldTheory
2
@Alnitak Aquí queremos buscar el centro del área circunscrita por las coordenadas. ¿Estás seguro de que has comentado sobre el lugar correcto?
LowFieldTheory
29

Publicación muy útil! He implementado esto en JavaScript, por la presente mi código. He usado esto 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)]);
}

Gio
fuente
1
Sé que la publicación es antigua, pero ¿podría publicar una referencia o algo que explique las matemáticas detrás del algoritmo que publicó? ¡Gracias!
tonix
Funcionó perfectamente! Gracias
andrewoodleyjr
Probé el script con Google Apps Script pero el resultado no es el punto central exacto de una pista. Está en algún lugar cercano pero no directamente EN la pista. ¿Existe una fórmula mejor para obtener el punto medio exacto EN LA PISTA?
Dirk
12

Versión 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);
}
Kelvin Spencer
fuente
12

En aras de posiblemente salvar a alguien un minuto o dos, aquí está la solución que se utilizó en Objective-C en lugar de Python. Esta versión toma un NSArray de NSValues ​​que contienen MKMapCoordinates, que fue requerido en mi implementació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;
}
Daryll H.
fuente
2
Para alguien por ahí, por lo que su valor, en lugar de su propia macro para grados a radianes, la importación <GLKit/GLKMath.h>y el uso GLKMathDegreesToRadiansyGLKMathRadiansToDegrees
pnizzle
8

Muy buenas soluciones, justo lo que necesitaba para mi proyecto rápido, así que aquí hay un puerto rápido. gracias y aquí también hay un proyecto de patio de juegos: 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)")
Peter Pohlmann
fuente
4

Si está interesado en obtener un 'centro' muy simplificado de los puntos (por ejemplo, simplemente centrar un mapa en el centro de su polígono gmaps), aquí hay un enfoque básico que funcionó 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;
}

Esto devuelve la coordenada media lat / lng para el centro de un polígono.

Kerry Emerson
fuente
4

En Django esto es trivial (y en realidad funciona, tuve problemas con una serie de soluciones que no devolvían correctamente los negativos para la latitud).

Por ejemplo, supongamos que está utilizando 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

pointes una Pointinstancia de Django que luego se puede usar para hacer cosas como recuperar todos los objetos que están dentro de los 10 km de ese punto central;

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

Cambiar esto a Python sin formato 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 está utilizando GEOS - más detalles en https://docs.djangoproject.com/en/1.10/ref/contrib/gis/geos/

alexhayes
fuente
3

Versión de Java si alguien lo necesita. Las constantes definieron estática para no calcularlas dos veces.

/**************************************************************************************************************
 *   Center of geometry defined by coordinates
 **************************************************************************************************************/
private static double pi = Math.PI / 180;
private static double xpi = 180 / Math.PI;

public static Coordinate center(Coordinate... arr) {
    if (arr.length == 1) {
        return arr[0];
    }
    double x = 0, y = 0, z = 0;

    for (Coordinate c : arr) {
        double latitude = c.lat() * pi, longitude = c.lon() * pi;
        double cl = Math.cos(latitude);//save it as we need it twice
        x += cl * Math.cos(longitude);
        y += cl * Math.sin(longitude);
        z += Math.sin(latitude);
    }

    int total = arr.length;

    x = x / total;
    y = y / total;
    z = z / total;

    double centralLongitude = Math.atan2(y, x);
    double centralSquareRoot = Math.sqrt(x * x + y * y);
    double centralLatitude = Math.atan2(z, centralSquareRoot);

    return new Coordinate(centralLatitude * xpi, centralLongitude * xpi);
}
Stan Sokolov
fuente
3

Aquí está la versión de Android basada en la respuesta C # de @Yodacheese usando la API de Google Maps:

public static LatLng GetCentralGeoCoordinate(List<LatLng> geoCoordinates) {        
    if (geoCoordinates.size() == 1)
    {
        return geoCoordinates.get(0);
    }

    double x = 0;
    double y = 0;
    double z = 0;

    for(LatLng geoCoordinate : geoCoordinates)
    {
        double  latitude = geoCoordinate.latitude * Math.PI / 180;
        double longitude = geoCoordinate.longitude * Math.PI / 180;

        x += Math.cos(latitude) * Math.cos(longitude);
        y += Math.cos(latitude) * Math.sin(longitude);
        z += Math.sin(latitude);
    }

    int total = geoCoordinates.size();

    x = x / total;
    y = y / total;
    z = z / total;

    double centralLongitude = Math.atan2(y, x);
    double centralSquareRoot = Math.sqrt(x * x + y * y);
    double centralLatitude = Math.atan2(z, centralSquareRoot);

    return new LatLng(centralLatitude * 180 / Math.PI, centralLongitude * 180 / Math.PI);

}

en la aplicación build.gradle agregar:

implementation 'com.google.android.gms:play-services-maps:17.0.0'
Hossein Amini
fuente
1

Esto es lo mismo que un problema promedio ponderado donde todos los pesos son iguales y hay dos dimensiones.

Encuentre el promedio de todas las latitudes para su latitud central y el promedio de todas las longitudes para la longitud central.

Advertencia Emptor: Esta es una aproximación a corta distancia y el error se volverá rebelde cuando las desviaciones de la media sean más de unas pocas millas debido a la curvatura de la Tierra. Recuerde que las latitudes y longitudes son grados (no realmente una cuadrícula).

jpredham
fuente
1
[-179,0], [+ 179,0] promedio en [0,0], que está un poco lejos del resultado correcto;)
Piskvor salió del edificio el
1

Fuera de objeto en PHP. Dado conjunto de pares de coordenadas, devuelve el centro.

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

Idea tomada del # 4

DabitNG
fuente
1
Esto no funcionaría para las coordenadas que cruzan el meridiano 180. Por ejemplo, dos puntos largos, -175 y 175 devolverían un centro de 0 en su algoritmo, por lo que el centro real sería -180 o 180.
Winch
1

Aquí está la versión de Python para encontrar el punto central. Lat1 y lon1 son listas de latitud y longitud. 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
Faisal
fuente
1

Implementación de Dart para Flutter para encontrar el punto central para Latitud múltiple, Longitud.

paquete de importación de matemáticas

import 'dart:math' as math;

Lista de latitud y longitud

List<LatLng> latLongList = [LatLng(12.9824, 80.0603),LatLng(13.0569,80.2425,)];

void getCenterLatLong(List<LatLng> latLongList) {
    double pi = math.pi / 180;
    double xpi = 180 / math.pi;
    double x = 0, y = 0, z = 0;

    if(latLongList.length==1)
    {
        return latLongList[0];
    }
    for (int i = 0; i < latLongList.length; i++) {
      double latitude = latLongList[i].latitude * pi;
      double longitude = latLongList[i].longitude * pi;
      double c1 = math.cos(latitude);
      x = x + c1 * math.cos(longitude);
      y = y + c1 * math.sin(longitude);
      z = z + math.sin(latitude);
    }

    int total = loadList.length;
    x = x / total;
    y = y / total;
    z = z / total;

    double centralLongitude = math.atan2(y, x);
    double centralSquareRoot = math.sqrt(x * x + y * y);
    double centralLatitude = math.atan2(z, centralSquareRoot);

    return LatLng(centralLatitude*xpi,centralLongitude*xpi);
}
MSARKrish
fuente
0

Si desea que todos los puntos sean visibles en la imagen, querrá los extremos en latitud y longitud y asegúrese de que su vista incluya esos valores con cualquier borde que desee.

(Según la respuesta de Alnitak, cómo calcular los extremos puede ser un poco problemático, pero si están a unos pocos grados a cada lado de la longitud que se envuelve, entonces llamarás el tiro y tomarás el rango correcto).

Si no desea distorsionar el mapa en el que se encuentran estos puntos, ajuste la relación de aspecto del cuadro delimitador para que se ajuste a los píxeles que haya asignado a la vista pero que aún incluya los extremos.

Para mantener los puntos centrados en algún nivel de zoom arbitrario, calcule el centro del cuadro delimitador que "simplemente se ajusta" a los puntos como se indicó anteriormente, y mantenga ese punto como el punto central.

Juan
fuente
0

Hice esta tarea en javascript como a continuación

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;
}
Renote Gotecha
fuente
0

Como agradecimiento por este hilo, aquí está mi pequeña contribución con la implementación en Ruby, con la esperanza de salvar a alguien unos minutos de su valioso 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
Fatos Morina
fuente
0

Utilicé una fórmula que obtuve de www.geomidpoint.com y escribí la siguiente implementación de C ++. Las arrayy geocoordsson mis propias clases cuya funcionalidad debería explicarse por sí misma.

/*
 * 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;
   }
Chris Lang
fuente
0

Dart / Flutter Calcular el punto central de múltiples pares de coordenadas de latitud / longitud

Map<String, double> getLatLngCenter(List<List<double>> coords) {
    const LATIDX = 0;
    const LNGIDX = 1;
    double sumX = 0;
    double sumY = 0;
    double sumZ = 0;

    for (var i = 0; i < coords.length; i++) {
      var lat = VectorMath.radians(coords[i][LATIDX]);
      var lng = VectorMath.radians(coords[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 / coords.length;
    var avgY = sumY / coords.length;
    var avgZ = sumZ / coords.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 {
      "latitude": VectorMath.degrees(lat),
      "longitude": VectorMath.degrees(lng)
    };
  }
Miguel Chiquin
fuente