1、介绍
Haversine 距离用于计算地球上两点之间的大圆距离
当考虑地球真实曲率时,它特别适用于计算两个经纬度坐标之间的距离

2、Java实现
public class HaversineUtil {
/**
* Great-circle distance on a spherical Earth using the haversine formula.
* 返回两点间球面最短距离(大圆距离)。
*
* 注意:
* - 结果适用于大多数业务距离计算(附近/范围/配送),属于“球体近似”。
* - 单位:公里(km)
*/
public static double haversineDistanceKm(double lat1, double lon1, double lat2, double lon2) {
// 平均地球半径(km),用 6371.0 也可以
final double R_KM = 6371.0088;
validateLatLon(lat1, lon1);
validateLatLon(lat2, lon2);
// 归一化经度到 [-180, 180)
lon1 = normalizeLonDeg(lon1);
lon2 = normalizeLonDeg(lon2);
// 计算差值(经度差做最短角差归一化,避免跨国际日期变更线时误差)
double dLatDeg = lat2 - lat1;
double dLonDeg = shortestDeltaLonDeg(lon1, lon2);
double dLat = Math.toRadians(dLatDeg);
double dLon = Math.toRadians(dLonDeg);
double rLat1 = Math.toRadians(lat1);
double rLat2 = Math.toRadians(lat2);
double sinDLat = Math.sin(dLat / 2.0);
double sinDLon = Math.sin(dLon / 2.0);
double a = sinDLat * sinDLat
+ Math.cos(rLat1) * Math.cos(rLat2) * sinDLon * sinDLon;
// 浮点保护:防止极端情况下 a 略超出 [0,1] 导致 NaN
a = Math.min(1.0, Math.max(0.0, a));
double c = 2.0 * Math.atan2(Math.sqrt(a), Math.sqrt(1.0 - a));
return R_KM * c;
}
/**
* Great-circle distance on a spherical Earth using the haversine formula.
* 返回两点间球面最短距离(大圆距离)。
*
* 注意:
* - 结果适用于大多数业务距离计算(附近/范围/配送),属于“球体近似”。
* - 单位:米(m)
*/
public static double haversineDistanceMeters(double lat1, double lon1, double lat2, double lon2) {
return haversineDistanceKm(lat1, lon1, lat2, lon2) * 1000.0;
}
/** 校验纬度/经度输入是否合理 */
private static void validateLatLon(double lat, double lon) {
if (!Double.isFinite(lat) || !Double.isFinite(lon)) {
throw new IllegalArgumentException("lat/lon must be finite numbers (not NaN/Infinity).");
}
if (lat < -90.0 || lat > 90.0) {
throw new IllegalArgumentException("lat out of range [-90, 90]: " + lat);
}
}
/** 把经度归一化到 [-180, 180) */
private static double normalizeLonDeg(double lon) {
// 结果落在 [-180, 180)
lon = ((lon + 180.0) % 360.0 + 360.0) % 360.0 - 180.0;
return lon;
}
/** 计算两经度的最短角差(单位:度),结果落在 [-180, 180] */
private static double shortestDeltaLonDeg(double lon1, double lon2) {
double d = lon2 - lon1;
// 归一化到 (-180, 180]
d = ((d + 180.0) % 360.0 + 360.0) % 360.0 - 180.0;
return d;
}
}
微信扫码查看本文
发表评论