经纬度计算
开发经常会遇到经纬度计算的相关场景。这次对相关知识做了下整理。
首先回顾一下科普知识:
1,经度: 英文 longitude 缩写 lng;纬度:英文 latitude 缩写 lat。
2,经度 是地球上一个地点离一根被称为本初子午线的南北方向走线以东或以西的度数。本初子午线的经度是0°。
纬度 是指某点与地球球心的连线和地球赤道面所成的线面角。
3,角度的是60进制的,在程序中为了计算方便都存成了10进制的形式。
4,程序中的经纬度范围: 经度[-180,180] 纬度[-90,90]
5,在坐标系中怎么根据经纬度标柱一个点。
如图,建立一个空间直角坐标系,在赤道平面上,X轴指向本初子午线,Y轴在赤道平面垂直X轴,Z轴指向北极。
A[θ1,θ2],经度θ2 ,纬度θ1。假设半径为单位1,A在坐标系的坐标(x,y,z)=(cosθ1*cosθ2, cosθ1*sinθ2, sinθ1)
6,正弦sin ,在坐标系中的曲线图
7,余弦cos, 在坐标系中的曲线图
9,空间两向量的夹角
10,圆的周长:d=2∏r
弧度: 弧长等于半径的弧,其所对的圆心角为1弧度。一个周长即2∏ 弧度(单位缩写是rad)。
根据角度计算弧度: θ/360 *2∏= θ*∏/180
根据弧度计算角度: Ø*180 /∏ (Ø为弧度)
根据弧度计算弧长: 弧度*半径
11,地球的赤道半径: 6377.830 = 6356.9088 + 20.9212 千米
极地半径:6356.9088 千米
根据两点经纬度 A[lat1,lng1],B[lat2,lng2],计算两点间的球面距离。
方法:先计算出两点的弧度,然后再算球面距离。弧度可过通过两点对球心的夹角的余弦求出。
先假设地球半径为1
A点的坐标表示为(cos lat1*cos lng1, cos lat1*sin lng1, sin lat1)
B点的坐标表示为(cos lat2*cos lng2, cos lat2*sin lng2, sin lat2)
cos A^B= cos lat1*cos lng1 *cos lat2*cos lng2 +cos lat1*sin lng1*cos lat2*sin lng2+sin lat1*sin lat2
= cos lat1*cos lat2(cos lng1*cos lng2+sin lng1*sin lng2) +sin lat1*sin lat2
= cos lat1*cos lat2*cos(lng1-lng2) +sin lat1*sin lat2
球面距离= R*arccos(cos lat1*cos lat2*cos(lng1-lng2) +sin lat1*sin lat2)
注:lat1,lng1,lat2,lng2 为弧度,数学计算都是用弧度单位来计算的。
代码如下:
1 private const double EARTH_RADIUS = 6377.830;//地球半径(千米) 2 3 /// <summary> 4 /// 角度换算成弧度 5 /// </summary> 6 /// <param name="d">角度</param> 7 /// <returns>弧度</returns> 8 private static double rad(double d) 9 { 10 return d * Math.PI / 180.0; 11 } 12 /// <summary> 13 /// 计算距离 14 /// </summary> 15 /// <param name="lat1">纬度1</param> 16 /// <param name="lng1">经度1</param> 17 /// <param name="lat2">纬度2</param> 18 /// <param name="lng2">经度2</param> 19 /// <returns>距离(千米)</returns> 20 public static double GetDistance(double lat1, double lng1, double lat2, double lng2) 21 { 22 double radLat1 = rad(lat1); 23 double radLat2 = rad(lat2); 24 double radLng1 = rad(lng1); 25 double radLng2 = rad(lng2); 26 double s = Math.Acos(Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Cos(radLng1 - radLng2) + Math.Sin(radLat1) * Math.Sin(radLat2)); 27 s = s * EARTH_RADIUS; 28 s = Math.Round(s * 10000) / 10000; 29 return s; 30 }
另外网上还有另一种算法:
1 /// <summary> 2 /// 计算距离 3 /// </summary> 4 /// <param name="lat1">纬度1</param> 5 /// <param name="lng1">经度1</param> 6 /// <param name="lat2">纬度2</param> 7 /// <param name="lng2">经度2</param> 8 /// <returns>距离(千米)</returns> 9 public static double GetDistance2(double lat1, double lng1, double lat2, double lng2) 10 { 11 double radLat1 = rad(lat1); 12 double radLat2 = rad(lat2); 13 double a = radLat1 - radLat2; 14 double b = rad(lng1) - rad(lng2); 15 double s = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a / 2), 2) + 16 Math.Cos(radLat1) * Math.Cos(radLat2) * Math.Pow(Math.Sin(b / 2), 2))); 17 s = s * EARTH_RADIUS; 18 s = Math.Round(s * 10000) / 10000; 19 return s; 20 }
根据某点A[lat,lng],从地标库中查找周边N公里的地标。
方法:根据点A算出经线上N公里的角度偏差,和纬线上N公里的角度偏差。然后根据最大最小经纬度,画出矩形范围。再遍历矩形范围中的坐标计算出周边N公里的地标。
设地球半径为Re,则经线上的半径为R,纬线上的半径为 R*cos(lat) 。
经线上1公里对应角度=360/2∏R=180/∏R,
纬线上1公里对应角度=360/[2∏R*cos(lat)]=180/[∏R*cos(lat)]
代码如下:
1 /// <summary> 2 /// 根据距离计算某点角度偏差 3 /// </summary> 4 /// <param name="lat">纬度</param> 5 /// <param name="distance">距离(千米)</param> 6 /// <param name="latDeviation">纬度偏差</param> 7 /// <param name="lngDeviation">经度偏差</param> 8 public static void GetMaxDeviation(double lat, double distance, out double latDeviation, out double lngDeviation) 9 { 10 double radLat1 = rad(lat); 11 //另一种根据纬度计算地球半径的写法,因为极地半径和赤道半径有偏差。 12 //EARTH_RADIUS = 6356.9088 + 20.9212 * (90.0 - lat) / 90.0; 13 double latRatio = 180 / (Math.PI * EARTH_RADIUS); //经线上1公里对应纬度偏差 14 double lngRatio = latRatio / Math.Cos(radLat1);//纬线上1公里对应经度偏差 15 latDeviation = distance * latRatio; 16 lngDeviation = distance * lngRatio; 17 }