GIS工具箱
几何计算

经纬度两点距离计算:Haversine 与 Vincenty 对比

球面距离与椭球距离的算法原理、精度差异,以及何时该用哪种方法。

HaversineVincenty球面距离椭球距离

经纬度两点距离计算:Haversine 与 Vincenty 对比

计算两个经纬度坐标之间的距离,是 GIS 开发中的高频需求。一个常见误区是直接用欧氏距离公式计算经纬度差值——这是错误的,因为经纬度是球面坐标,不同纬度上单位经度对应的实际距离并不相同。本文对比两种主流算法。

为什么不能用欧氏距离

地球近似球体,经线在两极汇聚,纬线圈长度随纬度升高而减小。在赤道附近,1 度经度约 111 公里;而在纬度 60 度处,1 度经度仅约 55 公里。因此必须使用球面或椭球面距离公式。

Haversine 公式

Haversine 假设地球为完美球体(半径取约 6371km),基于球面三角学的半正矢函数推导而来。

推导思路

球面余弦定理在两点距离较近时会出现大数相消问题,精度下降。Haversine 用半正矢函数 hav(θ) = sin²(θ/2) 改写,避免了这一问题:

function haversine(p1, p2) {
  const R = 6371008.8; // 地球平均半径(米)
  const dLat = toRad(p2.lat - p1.lat);
  const dLng = toRad(p2.lng - p1.lng);
  const a = Math.sin(dLat / 2) ** 2 +
            Math.cos(toRad(p1.lat)) * Math.cos(toRad(p2.lat)) *
            Math.sin(dLng / 2) ** 2;
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
  return R * c; // 返回米
}

Haversine 计算简单、速度快,是大多数应用的首选。

Vincenty 公式

Vincenty 基于地球为旋转椭球体的假设,采用 WGS84 椭球参数:

  • 长半轴 a = 6378137 m
  • 扁率 f = 1/298.257223563

该公式通过迭代法求解大地线方程,收敛后即可得到两点间的大地线距离:

function vincenty(p1, p2) {
  const a = 6378137.0;
  const f = 1 / 298.257223563;
  const b = (1 - f) * a;
  let lambda = (p2.lng - p1.lng) * DEG;
  let iter = 0;
  do {
    // 迭代修正 lambda 直至收敛
    // ...
  } while (Math.abs(lambda - lambdaP) > 1e-12 && ++iter < 200);
  // 根据收敛后的参数计算最终距离
  return b * A_ * (sigma - deltaSigma);
}
注意:Vincenty 在某些近乎对跖点的情况下可能不收敛,实际实现需加入兜底处理,通常回退到 Haversine。

精度与适用场景对比

  • 模型:Haversine 假设球体,Vincenty 采用 WGS84 椭球。
  • 相对误差:Haversine 约 0.3%-0.5%,Vincenty 精度可达毫米级。
  • 计算量:Haversine 较小,Vincenty 较大(需迭代)。
  • 适用场景:Haversine 适合快速估算、短距离;Vincenty 适合高精度测量。

总结来说,若只是估算距离,Haversine 足够;若涉及精确测量,应选 Vincenty。如需在线计算,可使用 两点距离计算工具

本文涉及的工具

打开工具 →

相关文章