Berechnen Sie den Mittelpunkt mehrerer Breiten- / Längenkoordinatenpaare

147

Wie kann ich bei einer Reihe von Breiten- und Längengraden die Breite und Länge des Mittelpunkts dieser Menge berechnen (auch bekannt als ein Punkt, der eine Ansicht auf alle Punkte zentrieren würde)?

EDIT: Python-Lösung, die ich verwendet habe:

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
quelle
2
Zu Ihrer Lösung: Wahrscheinlich werden Ihre Fehler bei der Annahme einer kugelförmigen Erde nicht zu groß sein, aber die Erde wird besser als Ellipsoid beschrieben.
John
1
Schrieb dies als Python-Funktion und teilte es unter gist.github.com/3718961
Alvin
14
Es ist sehr wichtig zu beachten, dass dies voraussetzt, dass Ihr Lat und Long im Bogenmaß sind! Ich kratzte mir eine Weile am Kopf und merkte das nicht. Um von der Dezimalstelle in Bogenmaß umzurechnen, multiplizieren Sie die Dezimalstelle * pi / 180. Um dann vom Bogenmaß zum Dezimalwert zurückzukehren, multiplizieren Sie mit 180 / pi. HTH
Ryan Guill
1
Es tut mir leid, dass ich zu spät gekommen bin, aber ich habe mich gefragt, was die Mathematik hinter diesem Algorithmus ist. Könnte mir jemand einige Lesungen empfehlen, in denen dies erklärt wird? Vielen Dank!
Tonix
1
Was ist z, bitte?
SoS

Antworten:

48

Der einfache Ansatz, sie nur zu mitteln, hat seltsame Randfälle mit Winkeln, wenn sie von 359 'zurück auf 0' gewickelt werden.

In einer viel früheren Frage zu SO wurde nach dem Durchschnitt eines Satzes von Kompasswinkeln gefragt.

Eine Erweiterung des dort empfohlenen Ansatzes für sphärische Koordinaten wäre:

  • Konvertieren Sie jedes Lat / Long-Paar in einen 3D-Vektor mit Einheitslänge.
  • Summiere jeden dieser Vektoren
  • Normalisieren Sie den resultierenden Vektor
  • Zurück in Kugelkoordinaten konvertieren
Alnitak
quelle
6
Scheint gut zu sein, ich habe etwas Ähnliches gemacht, basierend auf dem, was ich auf dieser Website gefunden habe: geomidpoint.com/calculation.html .
Zeke
4
downvoter - bitte erklären Sie und bieten Sie eine bessere Lösung an, wenn Sie können.
Alnitak
90

Vielen Dank! Hier ist eine C # -Version der OP-Lösungen mit Grad. Es verwendet die System.Device.Location.GeoCoordinate- Klasse

    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);
    }
Jododese
quelle
40

Ich fand diesen Beitrag sehr nützlich, daher hier die Lösung in PHP. Ich habe dies erfolgreich verwendet und wollte nur einen anderen Entwickler etwas Zeit sparen.

/**
 * 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
quelle
1
Ich habe diese Lösung verwendet, aber sie ergibt eine irgendwie falsche Lösung. Wenn ich die Mitte einiger Koordinaten auf einer Karte suche, "wiegt" sie die Punkte und bleibt dort, wo mehr Punkte vorhanden sind.
LowFieldTheory
2
@Alnitak Hier wollen wir die Mitte des durch die Koordinaten umschriebenen Bereichs durchsuchen. Sind Sie sicher, dass Sie den richtigen Ort kommentiert haben?
LowFieldTheory
29

Sehr nützlicher Beitrag! Ich habe dies in JavaScript implementiert, hiermit meinen Code. Ich habe das erfolgreich genutzt.

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
quelle
1
Ich weiß, dass der Beitrag alt ist, aber können Sie bitte eine Referenz oder eine Erklärung zur Mathematik hinter dem von Ihnen veröffentlichten Algorithmus veröffentlichen? Vielen Dank!
Tonix
Perfekt funktioniert! Vielen Dank
andrewoodleyjr
Ich habe das Skript mit Google Apps Script getestet, aber das Ergebnis ist nicht der genaue Mittelpunkt einer Spur. Es ist irgendwo in der Nähe, aber nicht direkt auf der Strecke. Gibt es eine bessere Formel, um den genauen Mittelpunkt auf der Spur zu erhalten?
Dirk
12

Javascript-Version der ursprünglichen Funktion

/**
 * 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
quelle
12

Im Interesse einer möglichen Einsparung von ein oder zwei Minuten ist hier die Lösung, die in Objective-C anstelle von Python verwendet wurde. Diese Version verwendet ein NSArray von NSValues, die MKMapCoordinates enthalten, was in meiner Implementierung gefordert wurde:

#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.
quelle
2
Für jeden da draußen, für was es wert ist, anstatt Ihr eigenes Makro für Grad zu Bogenmaß zu verwenden, importieren <GLKit/GLKMath.h>und verwenden GLKMathDegreesToRadiansundGLKMathRadiansToDegrees
pnizzle
8

Sehr schöne Lösungen, genau das, was ich für mein schnelles Projekt brauchte, also hier ist ein schneller Port. danke & hier ist auch ein Spielplatzprojekt: 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
quelle
4

Wenn Sie daran interessiert sind, ein sehr vereinfachtes "Zentrum" der Punkte zu erhalten (z. B. um einfach eine Karte auf das Zentrum Ihres gmaps-Polygons zu zentrieren), dann ist hier ein grundlegender Ansatz, der für mich funktioniert hat.

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

Dies gibt die mittlere Lat / Lng-Koordinate für die Mitte eines Polygons zurück.

Kerry Emerson
quelle
4

In Django ist dies trivial (und funktioniert tatsächlich, ich hatte Probleme mit einer Reihe von Lösungen, die Negative für den Breitengrad nicht korrekt zurückgaben).

Angenommen , Sie verwenden Django-Geopostcodes (deren Autor ich bin).

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

pointist eine Django- PointInstanz, die dann verwendet werden kann, um beispielsweise alle Objekte abzurufen, die sich innerhalb von 10 km von diesem Mittelpunkt befinden.

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

Das Ändern in rohes Python ist 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

Unter der Haube nutzt Django GEOS - weitere Details unter https://docs.djangoproject.com/de/1.10/ref/contrib/gis/geos/

alexhayes
quelle
3

Java-Version, wenn jemand es braucht. Konstanten definiert statisch, um sie nicht zweimal zu berechnen.

/**************************************************************************************************************
 *   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
quelle
3

Hier ist die Android-Version, die auf der C # -Antwort von @ Yodacheese mit der Google Maps-API basiert:

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

}

in app build.gradle hinzufügen:

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

Dies ist dasselbe wie ein gewichtetes Durchschnittsproblem, bei dem alle Gewichte gleich sind und es zwei Dimensionen gibt.

Finden Sie den Durchschnitt aller Breiten für Ihren mittleren Breitengrad und den Durchschnitt aller Längengrade für den mittleren Längengrad.

Vorbehalt Emptor: Dies ist eine Näherung aus nächster Nähe, und der Fehler wird unruhig, wenn die Abweichungen vom Mittelwert aufgrund der Erdkrümmung mehr als einige Meilen betragen. Denken Sie daran, dass Breiten- und Längengrade Grad sind (nicht wirklich ein Gitter).

jpredham
quelle
1
[-179,0], [+ 179,0] Durchschnitt bei [0,0], was etwas weit vom korrekten Ergebnis entfernt ist;)
Piskvor verließ das Gebäude
1

In PHP kein Objekt. Bei einem gegebenen Array von Koordinatenpaaren wird die Mitte zurückgegeben.

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

Idee von # 4 übernommen

DabitNG
quelle
1
Dies würde bei Koordinaten, die den 180. Meridian überschreiten, nicht funktionieren. Zum Beispiel würden zwei Längspunkte, -175 und 175, ein Zentrum von 0 in Ihrem Algorithmus zurückgeben, wobei das reale Zentrum entweder -180 oder 180 wäre.
Winch
1

Hier ist die Python-Version zum Finden des Mittelpunkts. Lat1 und lon1 sind Breiten- und Längengrade. Dadurch werden Breite und Länge des Mittelpunkts geändert.

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
quelle
1

Dart- Implementierung für Flatter , um den Mittelpunkt für mehrere Breiten- und Längengrade zu finden.

Mathe-Paket importieren

import 'dart:math' as math;

Längen- und Breitengradliste

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
quelle
0

Wenn Sie möchten, dass alle Punkte im Bild sichtbar sind, möchten Sie die Extrema in Breiten- und Längengrad und stellen sicher, dass Ihre Ansicht diese Werte mit dem gewünschten Rand enthält.

(Nach Alnitaks Antwort mag es ein wenig problematisch sein, wie Sie die Extrema berechnen. Wenn sie jedoch ein paar Grad auf beiden Seiten des Längengrads liegen, der sich um sie dreht, rufen Sie den Schuss und nehmen die richtige Reichweite.)

Wenn Sie die Karte, auf der sich diese Punkte befinden, nicht verzerren möchten, passen Sie das Seitenverhältnis des Begrenzungsrahmens so an, dass es zu den Pixeln passt, die Sie der Ansicht zugewiesen haben, aber dennoch die Extrema enthalten.

Um die Punkte auf einer beliebigen Zoomstufe zentriert zu halten, berechnen Sie die Mitte des Begrenzungsrahmens, der wie oben "nur zu den Punkten passt", und behalten Sie diesen Punkt als Mittelpunkt bei.

John
quelle
0

Ich habe diese Aufgabe in Javascript wie unten ausgeführt

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;
}
Renish Gotecha
quelle
0

Als Anerkennung für diesen Thread ist hier mein kleiner Beitrag zur Implementierung in Ruby, in der Hoffnung, dass ich jemanden ein paar Minuten vor seiner kostbaren Zeit retten kann:

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
quelle
0

Ich habe eine Formel verwendet, die ich von www.geomidpoint.com erhalten habe, und die folgende C ++ - Implementierung geschrieben. Die arrayund geocoordssind meine eigenen Klassen, deren Funktionalität selbsterklärend sein sollte.

/*
 * 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
quelle
0

Pfeil / Flattern Berechnen Sie den Mittelpunkt mehrerer Breiten- / Längenkoordinatenpaare

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
quelle