開發經常會遇到經緯度計算的相關場景。這次對相關知識做了下整理。
首先回顧一下科普知識:
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 }
