我尝试在基于经纬度查找距离中实现公式。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。为什么?


当前回答

(2022年,JavaScript版本)下面是使用最新的JavaScript库解决这个问题的代码。总的好处是,用户可以在运行在现代设备上的web页面上看到结果。

// Using the WGS84 ellipsoid model for computation var geod84 = geodesic.Geodesic.WGS84; // Input data lat1 = 52.2296756; lon1 = 21.0122287; lat2 = 52.406374; lon2 = 16.9251681; // Do the classic `geodetic inversion` computation geod84inv = geod84.Inverse(lat1, lon1, lat2, lon2); // Present the solution (only the geodetic distance) console.log("The distance is " + (geod84inv.s12/1000).toFixed(5) + " km."); <script type="text/javascript" src="https://cdn.jsdelivr.net/npm/geographiclib-geodesic@2.0.0/geographiclib-geodesic.min.js"> </script>

其他回答

在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>

有多种方法来计算基于坐标的距离,即纬度和经度

安装和导入

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

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)

使用geopy

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

另一种有趣的方法是通过Pyodide和WebAssembly实现混合JavaScript和Python,使用Python的库Pandas和geographiclib来获得解决方案,这也是可行的。

我用Pandas做了额外的工作来准备输入数据,当输出可用时,将它们附加到解决方案列中。Pandas为常见需求提供了许多有用的输入/输出特性。它的toHtml方法可以方便地在网页上呈现最终的解决方案。

我发现这个答案中的代码在某些iPhone和iPad设备上执行不成功。但在较新的中端Android设备上,它运行得很好。

async function main(){ let pyodide = await loadPyodide(); await pyodide.loadPackage(["pandas", "micropip"]); console.log(pyodide.runPythonAsync(` import micropip import pandas as pd import js print("Pandas version: " + pd.__version__) await micropip.install('geographiclib') from geographiclib.geodesic import Geodesic import geographiclib as gl print("Geographiclib version: " + gl.__version__) data = {'Description': ['Answer to the question', 'Bangkok to Tokyo'], 'From_long': [21.0122287, 100.6], 'From_lat': [52.2296756, 13.8], 'To_long': [16.9251681, 139.76], 'To_lat': [52.406374, 35.69], 'Distance_km': [0, 0]} df1 = pd.DataFrame(data) collist = ['Description','From_long','From_lat','To_long','To_lat'] div2 = js.document.createElement("div") div2content = df1.to_html(buf=None, columns=collist, col_space=None, header=True, index=True) div2.innerHTML = div2content js.document.body.append(div2) arr="<i>by Swatchai</i>" def dkm(frLat,frLon,toLat,toLon): print("frLon,frLat,toLon,toLat:", frLon, "|", frLat, "|", toLon, "|", toLat) dist = Geodesic.WGS84.Inverse(frLat, frLon, toLat, toLon) return dist["s12"] / 1000 collist = ['Description','From_long','From_lat','To_long','To_lat','Distance_km'] dist = [] for ea in zip(df1['From_lat'].values, df1['From_long'].values, df1['To_lat'].values, df1['To_long'].values): ans = dkm(*ea) print("ans=", ans) dist.append(ans) df1['Distance_km'] = dist # Update content div2content = df1.to_html(buf=None, columns=collist, col_space=None, header=True, index=False) div2.innerHTML = div2content js.document.body.append(div2) # Using the haversine formula from math import sin, cos, sqrt, atan2, radians, asin # Approximate radius of earth in km from Wikipedia R = 6371 lat1 = radians(52.2296756) lon1 = radians(21.0122287) lat2 = radians(52.406374) lon2 = radians(16.9251681) # https://en.wikipedia.org/wiki/Haversine_formula def hav(angrad): return (1-cos(angrad))/2 h = hav(lat2-lat1)+cos(lat2)*cos(lat1)*hav(lon2-lon1) dist2 = 2*R*asin(sqrt(h)) print(f"Distance by haversine formula = {dist2:8.6f} km.") `)); } main(); <script src="https://cdn.jsdelivr.net/pyodide/v0.21.0/full/pyodide.js"></script> Pyodide implementation<br>

我找到了一个更简单、更健壮的解决方案,即使用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

地珞

您可以使用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