利用第三方包spatial4j里面的三种方法实现两点之间的经纬度计算,并测试北京到上海两点经纬度的距离。
目录
1.环境配置
maven环境引入spatial4j包环境,使用DistanceUtils方法。import包环境:
import org.locationtech.spatial4j.distance.DistanceUtils;
<dependency>
<groupId>org.locationtech.spatial4j</groupId>
<artifactId>spatial4j</artifactId>
<version>0.8</version>
</dependency>
2.方法一:余弦定理
DistanceUtils.distLawOfCosinesRAD:余弦定理,平面计算通过三角函数,误差较大。这里我把distLawOfCosinesRAD方法的底层实现源码提供出来。
public static double distLawOfCosinesRAD(double lat1, double lon1, double lat2, double lon2) {
if (lat1 == lat2 && lon1 == lon2) {
return 0.0;
} else {
double dLon = lon2 - lon1;
double cosB = Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1) * Math.cos(lat2) * Math.cos(dLon);
if (cosB < -1.0) {
return Math.PI;
} else {
return cosB >= 1.0 ? 0.0 : Math.acos(cosB);
}
}
}
这个计算的实现过程和下面我将提到的distHaversineRAD、distVincentyRAD有区别,后面我会专门出一篇文章详细说一下区别。
3.方法二:Vincenty椭球模型
DistanceUtils.distVincentyRAD:椭球模型,类似于地球的椭圆形状,在多次计算的迭代情况下计算的经度较高。
public static double distVincentyRAD(double lat1, double lon1, double lat2, double lon2) {
if (lat1 == lat2 && lon1 == lon2) {
return 0.0;
} else {
double cosLat1 = Math.cos(lat1);
double cosLat2 = Math.cos(lat2);
double sinLat1 = Math.sin(lat1);
double sinLat2 = Math.sin(lat2);
double dLon = lon2 - lon1;
double cosDLon = Math.cos(dLon);
double sinDLon = Math.sin(dLon);
double a = cosLat2 * sinDLon;
double b = cosLat1 * sinLat2 - sinLat1 * cosLat2 * cosDLon;
double c = sinLat1 * sinLat2 + cosLat1 * cosLat2 * cosDLon;
return Math.atan2(Math.sqrt(a * a + b * b), c);
}
}
4.方法三:Haversine球面模型
DistanceUtils.distHaversineRAD:常用的Haversine公式,类似于球模型,以赤道的半径为基准,因此计算时纬度越高误差就会越大,但是计算的速度会很快。
public static double distHaversineRAD(double lat1, double lon1, double lat2, double lon2) {
if (lat1 == lat2 && lon1 == lon2) {
return 0.0;
} else {
double hsinX = Math.sin((lon1 - lon2) * 0.5);
double hsinY = Math.sin((lat1 - lat2) * 0.5);
double h = hsinY * hsinY + Math.cos(lat1) * Math.cos(lat2) * hsinX * hsinX;
if (h > 1.0) {
h = 1.0;
}
return 2.0 * Math.atan2(Math.sqrt(h), Math.sqrt(1.0 - h));
}
}