网上有很多资料都只讲个大概,对于我这种数学渣渣来说比较难理解(曾经学校里的都还给老师了),现在把计算的原理梳理一下。
计算经纬度坐标距离的原理就是就算球面两点间的距离,经纬度表示法实际是用角度描述的坐标。纬度上下一共180度,经度360度。
假设地球是标准的球形,计算距离就等于计算一个截面圆的弧长。计算弧长的话需要先求出两点相对于球芯的夹角。然后根据半径就可以求出弧长了,也就是距离。
假设A点纬度lat1,精度lng1.B点纬度lat2, 经度lng2, 地球半径为R
求这个夹角之前,先把坐标转换为直角空间坐标系的点,并让地心为坐标中心点,即
A(Rcos(lat1)cos(lng1), Rcos(lat1)sin(lng1), Rsin(lat1))
B(Rcos(lat2)cos(lng2), Rcos(lat2)sin(lng2), Rsin(lat2))
然后算夹角,这里用向量的夹角计算方法,可以求出夹角余弦值,那么夹角COS为
COS = (向量A*向量B) / (向量A的模 * 向量B的模)
令A为(x,y,z),B(a,b,c)
COS = (xa+yb+zc)/[√(x2+y2+z2)*√(a2+b2+c2)]
把经纬度的坐标代进去
COS = cos(lat2) * cos(lat1) * cos(lng1-lng2) + sin(lat2)*sin(lat1)
得到夹角的余弦值可得角度,然后就可以算出弧长了,即得距离(arccos 为反余弦函数,这里反余弦的结果得到的是弧度)
d = 2PIR * (arccos(COS) / 2 * PI)
d = R * arccos(COS)
最终
d = R * arccos( cos(lat2) * cos(lat1) * cos(lng2-lng1) + sin(lat2)*sin(lat1))
嗯,那么就是半径乘以夹角的弧度值....弧度的定义好像这么来的哈
java代码
/**
* 计算距离
* @param lat1 纬度
* @param lng1 经度
* @param lat2 纬度
* @param lng2 经度
* @return 距离 KM
*/
public static double distance(double lat1, double lng1, double lat2, double lng2) {
//转弧度
lat1 = lat1 * Math.PI / 180;
lat2 = lat2 * Math.PI / 180;
lng1 = lng1 * Math.PI / 180;
lng2 = lng2 * Math.PI / 180;
double cos = Math.cos(lat2) * Math.cos(lat1) * Math.cos(lng2 -lng1) + Math.sin(lat1) * Math.sin(lat2);
return EARTH_R * Math.acos(cos);
}
要注意经纬度是角度,而一些库API给的是弧度参数。
验证
public static void main(String[] args) {
double lat1 = 23;
double lng1 = 113;
double lat2 = 25;
double lng2 = 114;
System.out.println(distance(lat1, lng1, lat2, lng2));
}
输出为 244.48810435,和谷歌地球上的差不多