根据纬度/经度获取两点之间的距离

Posted

技术标签:

【中文标题】根据纬度/经度获取两点之间的距离【英文标题】:Getting distance between two points based on latitude/longitude 【发布时间】:2013-10-25 02:26:04 【问题描述】:

我尝试实现这个公式:http://andrew.hedges.name/experiments/haversine/ aplet 对我正在测试的两点有好处:

但我的代码不起作用。

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。为什么?

【问题讨论】:

【参考方案1】:

您可以使用Uber's H3,point_dist() 函数来计算两个 (lat, lng) 点之间的球面距离。我们可以设置返回单位('km'、'm' 或 'rads')。默认单位为公里。

例子:

import h3

coords_1 = (52.2296756, 21.0122287)
coords_2 = (52.406374, 16.9251681)
distance = h3.point_dist(coords_1, coords_2, unit='m') # to get distance in meters

希望这会有用!

【讨论】:

【参考方案2】:

更新:04/2018:文森蒂距离改为deprecated since GeoPy version 1.13 - you should use geopy.distance.distance()


以上答案基于Haversine formula,假设地球是一个球体,导致误差高达约0.5%(根据help(geopy.distance))。 Vincenty distance使用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

将使用默认椭球 WGS-84 打印279.352901604 公里的距离。 (您也可以选择.miles 或其他几个距离单位之一)。

【讨论】:

谢谢。您能否使用我提供的坐标而不是纽波特和克利夫兰来更新您的答案。它将让未来的读者更好地理解。 Newport 和 Cleveland 的任意位置来自 PyPI 列表中的示例 geopy 文档:pypi.python.org/pypi/geopy 我不得不修改 Kurt Peek 对此的回答:需要大写:print geopy.distance.VincentyDistance(coords_1, coords_2).km 279.352901604 您可能应该在代码中使用geopy.distance.distance(…),它是当前最佳(=最准确)距离公式的别名。 (现在是文森蒂。) 在 geopy-1.18.1 输出中使用 geopy.distance.vincenty:Vincenty 已弃用,将在 geopy 2.0 中删除。改用geopy.distance.geodesic(或默认的geopy.distance.distance),这样更准确且始终收敛。【参考方案3】:

最简单的方法是使用haversine包。


import haversine as hs


coord_1 = (lat, lon)
coord_2 = (lat, lon)
x = hs.haversine(coord_1,coord_2)
print(f'The distance is x km')

【讨论】:

【参考方案4】:

对于通过搜索引擎来到这里并只是寻找开箱即用的解决方案的人(如我),我建议安装mpu。通过pip install mpu --user 安装它并像这样使用它来获取haversine distance:

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

另一个替代包是haversine

from haversine import haversine, Unit

lyon = (45.7597, 4.8422) # (lat, lon)
paris = (48.8567, 2.3508)

haversine(lyon, paris)
>> 392.2172595594006  # in kilometers

haversine(lyon, paris, unit=Unit.MILES)
>> 243.71201856934454  # in miles

# you can also use the string abbreviation for units:
haversine(lyon, paris, unit='mi')
>> 243.71201856934454  # in miles

haversine(lyon, paris, unit=Unit.NAUTICAL_MILES)
>> 211.78037755311516  # in nautical miles

他们声称对两个向量中所有点之间的距离进行了性能优化

from haversine import haversine_vector, Unit

lyon = (45.7597, 4.8422) # (lat, lon)
paris = (48.8567, 2.3508)
new_york = (40.7033962, -74.2351462)

haversine_vector([lyon, lyon], [paris, new_york], Unit.KILOMETERS)

>> array([ 392.21725956, 6163.43638211])

【讨论】:

有没有办法改变其中一个点的给定高度? 您可以简单地将高度差添加到距离中。不过,我不会那样做。 “里昂,巴黎,392.2172595594006 公里”,哇,最后一个数字甚至不是氢原子的大小。非常准确!【参考方案5】:

有多种方法可以根据坐标(即纬度和经度)计算距离

安装和导入

from geopy import distance
from math import sin, cos, sqrt, atan2, radians
from sklearn.neighbors import DistanceMetric
import osrm
import numpy as np

定义坐标

lat1, lon1, lat2, lon2, R = 20.9467,72.9520, 21.1702, 72.8311, 6373.0
coordinates_from = [lat1, lon1]
coordinates_to = [lat2, lon2]

使用半正弦

dlon = radians(lon2) - radians(lon1)
dlat = radians(lat2) - radians(lat1)
    
a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
c = 2 * atan2(sqrt(a), sqrt(1 - a))
    
distance_haversine_formula = R * c
print('distance using haversine formula: ', distance_haversine_formula)

在 sklearn 中使用 hasrsine

dist = DistanceMetric.get_metric('haversine')
    
X = [[radians(lat1), radians(lon1)], [radians(lat2), radians(lon2)]]
distance_sklearn = R * dist.pairwise(X)
print('distance using sklearn: ', np.array(distance_sklearn).item(1))

使用 OSRM

osrm_client = osrm.Client(host='http://router.project-osrm.org')
coordinates_osrm = [[lon1, lat1], [lon2, lat2]] # note that order is lon, lat
    
osrm_response = osrm_client.route(coordinates=coordinates_osrm, overview=osrm.overview.full)
dist_osrm = osrm_response.get('routes')[0].get('distance')/1000 # in km
print('distance using OSRM: ', dist_osrm)

使用地理位置

distance_geopy = distance.distance(coordinates_from, coordinates_to).km
print('distance using geopy: ', distance_geopy)
    
distance_geopy_great_circle = distance.great_circle(coordinates_from, coordinates_to).km 
print('distance using geopy great circle: ', distance_geopy_great_circle)

输出

distance using haversine formula:  26.07547017310917
distance using sklearn:  27.847882224769783
distance using OSRM:  33.091699999999996
distance using geopy:  27.7528030550408
distance using geopy great circle:  27.839182219511834

【讨论】:

【参考方案6】:

我得到了一个更简单和强大的解决方案,它使用来自geopy 包的geodesic,因为无论如何您很可能在您的项目中使用它,因此不需要额外的包安装。

这是我的解决方案:

from geopy.distance import geodesic


origin = (30.172705, 31.526725)  # (latitude, longitude) don't confuse
dist = (30.288281, 31.732326)

print(geodesic(origin, dist).meters)  # 23576.805481751613
print(geodesic(origin, dist).kilometers)  # 23.576805481751613
print(geodesic(origin, dist).miles)  # 14.64994773134371

geopy

【讨论】:

感谢哥们提到纬度是第一,然后是经度。干杯!【参考方案7】:
import numpy as np


def Haversine(lat1,lon1,lat2,lon2, **kwarg):
    """
    This uses the ‘haversine’ formula to calculate the great-circle distance between two points – that is, 
    the shortest distance over the earth’s surface – giving an ‘as-the-crow-flies’ distance between the points 
    (ignoring any hills they fly over, of course!).
    Haversine
    formula:    a = sin²(Δφ/2) + cos φ1 ⋅ cos φ2 ⋅ sin²(Δλ/2)
    c = 2 ⋅ atan2( √a, √(1−a) )
    d = R ⋅ c
    where   φ is latitude, λ is longitude, R is earth’s radius (mean radius = 6,371km);
    note that angles need to be in radians to pass to trig functions!
    """
    R = 6371.0088
    lat1,lon1,lat2,lon2 = map(np.radians, [lat1,lon1,lat2,lon2])

    dlat = lat2 - lat1
    dlon = lon2 - lon1
    a = np.sin(dlat/2)**2 + np.cos(lat1) * np.cos(lat2) * np.sin(dlon/2) **2
    c = 2 * np.arctan2(a**0.5, (1-a)**0.5)
    d = R * c
    return round(d,4)

【讨论】:

您好,您认为有一种方法可以直接从模板中获取数据吗?【参考方案8】:

编辑:请注意,如果您只需要一种快速简便的方法来查找两点之间的距离,我强烈建议使用下面Kurt's answer 中描述的方法,而不是重新实施 Haversine - 查看他的帖子了解基本原理。

此答案仅侧重于回答 OP 遇到的特定错误。


这是因为在 Python 中,所有三角函数 use radians,而不是度数。

您可以手动将数字转换为弧度,或使用数学模块中的radians 函数:

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.545589351km。

【讨论】:

这在任何编程语言中都是正确的,在微积分中也是如此。使用度数是个例外,仅用于人类语音。 聪明人的话,这个公式要求所有度数都是正数。 radians(abs(52.123)) 应该可以解决问题... 您确定所有度数(角度?)都是正数吗?我认为这是错误的。考虑 lat1, lon1 = 10, 10 (度) 和 lat2, lon2 = -10, -10 (度)。通过在度数周围添加 abs(),距离将为零,这是不正确的。也许您打算取 dlon 和/或 dlat 的绝对值,但是如果您查看计算 a 中的 dlon、dlat 值,正弦是偶函数,余弦平方是偶函数,所以我不也可以看到采用 dlat 或 dlon 的绝对值有什么好处。 只是想知道上面的距离是两个位置之间的弧距还是平面距离?

以上是关于根据纬度/经度获取两点之间的距离的主要内容,如果未能解决你的问题,请参考以下文章

两个经纬度算距离公式 方法是啥

经纬度之间距离怎么算?

怎样计算两个经纬度之间的距离 百度百科

怎么知道经纬度算距离,

使用纬度经度计算两点之间的距离?

2020-06-03 两点经纬度计算距离-原理及SQL