Рассчитать центральную точку нескольких пар координат широта / долгота - PullRequest
131 голосов
/ 13 июля 2011

Учитывая набор точек широты и долготы, как я могу вычислить широту и долготу центральной точки этого набора (то есть точки, которая бы центрировала вид по всем точкам)?

РЕДАКТИРОВАТЬ: PythonРешение, которое я использовал:

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)

Ответы [ 16 ]

78 голосов
/ 09 января 2013

Спасибо! Вот C # версия решений OP с использованием степеней. Он использует System.Device.Location.GeoCoordinate class

    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);
    }
46 голосов
/ 13 июля 2011

В простом подходе простого их усреднения есть странные граничные случаи с углами, когда они переходят от 359 'к 0'.

A гораздо более ранний вопрос по SO , заданный для нахождения среднегонабора углов компаса.

Расширение подхода, рекомендуемого там для сферических координат, будет:

  • Преобразование каждой пары широта / длинна в трехмерный вектор единичной длины.
  • Сумма каждого из этих векторов
  • Нормализация результирующего вектора
  • Преобразование обратно в сферические координаты
39 голосов
/ 05 сентября 2013

Я нашел этот пост очень полезным, так что вот решение в PHP. Я успешно этим пользуюсь и просто хотел спасти еще одного разработчика некоторое время.

/**
 * 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());
}
26 голосов
/ 04 мая 2015

Очень полезный пост!Я реализовал это в JavaScript, настоящим мой код.Я использовал это успешно.

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

12 голосов
/ 14 февраля 2017

Javascript версия оригинальной функции

/**
 * 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);
}
12 голосов
/ 23 января 2014

В интересах возможной экономии кому-то минуты или двух, вот решение, которое использовалось в Objective-C вместо python. Эта версия принимает NSArray NSValues, которые содержат MKMapCoordinates, который был вызван в моей реализации:

#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;
}
7 голосов
/ 02 июня 2016

очень хорошие решения, как раз то, что мне нужно для моего быстрого проекта, так что вот быстрый порт.спасибо и вот еще проект детской площадки: 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)")
4 голосов
/ 15 мая 2013

Если вы заинтересованы в получении очень упрощенного «центра» точек (например, просто центрирование карты по центру вашего многоугольника gmaps), то вот базовый подход, который мне помог.

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

Возвращает среднюю координату широты / долготы для центра многоугольника.

3 голосов
/ 28 марта 2017

В Django это тривиально (и на самом деле работает, у меня были проблемы с рядом решений, неправильно возвращающих отрицательные значения для широты).

Например, допустим, вы используете django-геопосткоды (автором которого я являюсь).

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 - это экземпляр Django Point, который затем можно использовать для таких вещей, как извлечение всех объектов, которые находятся в пределах 10 км от этогоцентральная точка;

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

Изменение этого в необработанный Python тривиально;

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

Под капотом Django использует GEOS - подробнее на https://docs.djangoproject.com/en/1.10/ref/contrib/gis/geos/

1 голос
/ 06 февраля 2019

Вот версия Python для нахождения центральной точки. Lat1 и lon1 - списки широты и долготы. это вернет широту и долготу центральной точки.

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...