在实际项目中,涉及定位和位置信息业务时,计算两个点的距离算是比较常见的问题。
以下是多个方案计算两个点坐标的方案,欢迎围观讨论。
需要注意的是:
- 中国大约位于4°N——53°N多之间,跨纬度近50°,位于73°E——135°E,东西跨经度62°
- 所有方案的入参说明:第一点的经度,第一点的纬度,第二点的经度,第二点的纬度
- 所有方案的返回距离单位:米
如果需要计算三维空间两点之间的的绝对距离,请点击此链接查看。
1.反余弦计算方式(地球平均半径(单位:米))
public static double getCoordinateDistanceOne(double longitude1, double latitude1,
double longitude2, double latitude2) {
// 经纬度(角度)转弧度。弧度作为作参数,用以调用Math.cos和Math.sin
// A经弧度
double radiansAX = Math.toRadians(longitude1);
// A纬弧度
double radiansAY = Math.toRadians(latitude1);
// B经弧度
double radiansBX = Math.toRadians(longitude2);
// B纬弧度
double radiansBY = Math.toRadians(latitude2);
// 公式中“cosβ1cosβ2cos(α1-α2)+sinβ1sinβ2”的部分,得到∠AOB的cos值
double cos = Math.cos(radiansAY) * Math.cos(radiansBY) * Math.cos(radiansAX - radiansBX) + Math.sin(radiansAY) * Math.sin(radiansBY);
// System.out.println("cos = " + cos); // 值域[-1,1]
// 反余弦值
double acos = Math.acos(cos);
// System.out.println("acos = " + acos); // 值域[0,π]
// System.out.println("∠AOB = " + Math.toDegrees(acos)); // 球心角 值域[0,180]
// 最终结果
return EARTH_AVG_RADIUS * acos;
}
2.基于googleMap中的算法得到两经纬度之间的距离
其计算精度与谷歌地图的距离精度类似
public static double getCoordinateDistanceTwo(double longitude1, double latitude1,
double longitude2, double latitude2) {
double radLat1 = rad(latitude1);
double radLat2 = rad(latitude2);
double a = radLat1 - radLat2;
double b = rad(longitude1) - rad(longitude2);
double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(radLat1) * Math.cos(radLat2) * Math.pow(Math.sin(b / 2), 2)));
s = s * EARTH_AVG_RADIUS;
s = Math.round(s * 10000d) / 10000d;
return s;
}
需要注意的是前两种方案都需要:地球平均半径(单位:米)
/**
* 地球平均半径(单位:米)
*/
private static final double EARTH_AVG_RADIUS = 6371000;
3.基于高德地图计算方法
public static double getCoordinateDistanceThree(double longitude1, double latitude1,
double longitude2, double latitude2) {
if (longitude1 == 0 || latitude1 == 0 || latitude2 == 0 || longitude2 == 0) {
return -1.0;
}
longitude1 *= 0.01745329251994329;
latitude1 *= 0.01745329251994329;
longitude2 *= 0.01745329251994329;
latitude2 *= 0.01745329251994329;
double var1 = Math.sin(longitude1);
double var2 = Math.sin(latitude1);
double var3 = Math.cos(longitude1);
double var4 = Math.cos(latitude1);
double var5 = Math.sin(longitude2);
double var6 = Math.sin(latitude2);
double var7 = Math.cos(longitude2);
double var8 = Math.cos(latitude2);
double[] var10 = new double[3];
double[] var20 = new double[3];
var10[0] = var4 * var3;
var10[1] = var4 * var1;
var10[2] = var2;
var20[0] = var8 * var7;
var20[1] = var8 * var5;
var20[2] = var6;
return Math.asin(Math.sqrt((var10[0] - var20[0]) * (var10[0] - var20[0]) + (var10[1] - var20[1]) * (var10[1] - var20[1]) + (var10[2] - var20[2]) * (var10[2] - var20[2])) / 2.0) * 1.27420015798544E7;
// 结果四舍五入 保留2位小数
}
4.反余弦计算方式(赤道半径(单位:米))
/**
* 赤道半径(单位:米)
*/
private static final double EQUATOR_RADIUS = 6378137;
public static double getCoordinateDistanceFour(double longitude1, double latitude1,
double longitude2, double latitude2) {
// 纬度
double lat1 = Math.toRadians(latitude1);
double lat2 = Math.toRadians(latitude2);
// 经度
double lon1 = Math.toRadians(longitude1);
double lon2 = Math.toRadians(longitude2);
// 纬度之差
double a = lat1 - lat2;
// 经度之差
double b = lon1 - lon2;
// 计算两点距离的公式
double s = 2 * Math.asin(Math.sqrt(Math.pow(Math.sin(a / 2), 2) + Math.cos(lat1) * Math.cos(lat2) * Math.pow(Math.sin(b / 2), 2)));
// 弧长乘赤道半径, 返回单位: 米
s = s * EQUATOR_RADIUS;
return s;
}