我尝试在基于经纬度查找距离中实现公式。applet对我正在测试的两点很好:

但是我的代码没有工作。

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


当前回答

对于像我这样通过搜索引擎来到这里的人,以及正在寻找开箱即用的解决方案的人,我建议安装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()

另一种替代方案是haversine:

from haversine import haversine, Unit

lyon = (45.7597, 4.8422) # (latitude, longitude)
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) # (latitude, longitude)
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])

其他回答

最简单的方法是用哈弗辛包装。

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

在2022年,人们可以发布JavaScript和Python混合代码,使用最新的Python库,即地理库来解决这个问题。总的好处是,用户可以在运行在现代设备上的web页面上看到结果。

async function main(){ let pyodide = await loadPyodide(); await pyodide.loadPackage(["micropip"]); console.log(pyodide.runPythonAsync(` import micropip await micropip.install('geographiclib') from geographiclib.geodesic import Geodesic lat1 = 52.2296756; lon1 = 21.0122287; lat2 = 52.406374; lon2 = 16.9251681; ans = Geodesic.WGS84.Inverse(lat1, lon1, lat2, lon2) dkm = ans["s12"] / 1000 print("Geodesic solution", ans) print(f"Distance = {dkm:.4f} km.") `)); } main(); <script src="https://cdn.jsdelivr.net/pyodide/v0.21.0/full/pyodide.js"></script>

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

例子:

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

对于像我这样通过搜索引擎来到这里的人,以及正在寻找开箱即用的解决方案的人,我建议安装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()

另一种替代方案是haversine:

from haversine import haversine, Unit

lyon = (45.7597, 4.8422) # (latitude, longitude)
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) # (latitude, longitude)
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])

我找到了一个更简单、更健壮的解决方案,即使用geogeoy包中的测地线,因为你很可能在你的项目中使用它,所以不需要额外的包安装。

以下是我的解决方案:

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

地珞