Получение расстояния между двумя точками на основе широты / долготы

Я попытался реализовать эту формулу:http://andrew.hedges.name/experiments/haversine/ В aplet для двух точек, которые я тестирую:

enter image description here

но мой код не работает.

from math import sin, cos, sqrt, atan2

R = 6373.0

lat1 = 52.2296756
lon1 = 21.0122287
lat2 = 52.406374
lon2 = 16.9251681

dlon = lon2 - lon1
dlat = lat2 - lat1
a = (sin(dlat/2))**2 + cos(lat1) * cos(lat2) * (sin(dlon/2))**2
c = 2 * atan2(sqrt(a), sqrt(1-a))
distance = R * c

print "Result", distance
print "Should be", 278.546

расстояние, которое он возвращает,5447.05546147. Почему?

3 ответов


Это потому, что в Python, все тригонометрические функции использовать радианы, а не в градусах.

вы можете либо преобразовать числа вручную в радианы, либо использовать radians функции модуля Math:

from math import sin, cos, sqrt, atan2, radians

# approximate radius of earth in km
R = 6373.0

lat1 = radians(52.2296756)
lon1 = radians(21.0122287)
lat2 = radians(52.406374)
lon2 = radians(16.9251681)

dlon = lon2 - lon1
dlat = lat2 - lat1

a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
c = 2 * atan2(sqrt(a), sqrt(1 - a))

distance = R * c

print("Result:", distance)
print("Should be:", 278.546, "km")

расстояние теперь возвращает правильное значение 278.545589351 km.

Edit: просто как Примечание, Если вы наткнулись на этот пост, потому что вы просто нужен быстрый и простой способ нахождения расстояния между два момента, я рекомендую вам использовать подход, рекомендованный в Курт ниже-см. свой пост для обоснования.


обновление: 04/2018: обратите внимание, что расстояние Vincenty устарело с версии GeoPy 1.13 - вы должны использовать geopy.расстояние.расстояние() вместо этого!


ответы выше основаны на формула Гаверсинуса, который предполагает, что Земля является сферой, что приводит к ошибкам до 0,5% (согласно help(geopy.distance)). расстояние Vincenty использует более точные эллипсоидальные модели, такие как WGS-84, и реализовано в geopy. Например,

import geopy.distance

coords_1 = (52.2296756, 21.0122287)
coords_2 = (52.406374, 16.9251681)

print geopy.distance.vincenty(coords_1, coords_2).km

будет печатать расстоянии 279.352901604 километры с использованием эллипсоида WGS-84 по умолчанию. (Вы также можете выбрать .miles или один из нескольких других единицах расстояния).


для людей (таких как я), приходящих сюда через поисковую систему и просто ищущих решение, которое работает из коробки, я рекомендую установить mpu. Установите его через pip install mpu --user и используйте его так, чтобы получить haversine расстояние:

import mpu

# Point one
lat1 = 52.2296756
lon1 = 21.0122287

# Point two
lat2 = 52.406374
lon2 = 16.9251681

# What you were looking for
dist = mpu.haversine_distance((lat1, lon1), (lat2, lon2))
print(dist)  # gives 278.45817507541943.

альтернативный пакет gpxpy.

если вы не хотите зависимостей, вы можете использовать:

import math


def distance(origin, destination):
    """
    Calculate the Haversine distance.

    Parameters
    ----------
    origin : tuple of float
        (lat, long)
    destination : tuple of float
        (lat, long)

    Returns
    -------
    distance_in_km : float

    Examples
    --------
    >>> origin = (48.1372, 11.5756)  # Munich
    >>> destination = (52.5186, 13.4083)  # Berlin
    >>> round(distance(origin, destination), 1)
    504.2
    """
    lat1, lon1 = origin
    lat2, lon2 = destination
    radius = 6371  # km

    dlat = math.radians(lat2 - lat1)
    dlon = math.radians(lon2 - lon1)
    a = (math.sin(dlat / 2) * math.sin(dlat / 2) +
         math.cos(math.radians(lat1)) * math.cos(math.radians(lat2)) *
         math.sin(dlon / 2) * math.sin(dlon / 2))
    c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
    d = radius * c

    return d


if __name__ == '__main__':
    import doctest
    doctest.testmod()