轉自:https://blog.csdn.net/jasonsong2008/article/details/78423496函數
轉自JAVA版本 https://blog.csdn.net/james_laughing/article/details/72881056?locationNum=12&fps=1spa
在一些地圖的應用中(如求偏航),經常須要求一個點到一條線程的距離,以判斷是否遠離航線。然而在經緯度座標中,並無相似直角座標系中的公式來計算。在經緯度中,通常應用最廣的公式是求兩點距離的方法,如何經過兩點之間的距離公式來達到計算出點到線段的方法呢,咱們先來看在經緯度中求兩點距離的計算方法。.net
1、經緯度中求兩點距離的計算方法線程
網上有不少介紹該計算方法,此處再也不 一一闡述。在北半球中:rest
C = sin(LatA*Pi/180)*sin(LatB*Pi/180) + cos(LatA*Pi/180)*cos(LatB*Pi/180)*cos((MLonA-MLonB)*Pi/180)code
Distance = R*Arccos(C)*Pi/180blog
注1:其中LonA、LatA、LonB、LatB分別是A、B兩個點的經緯度值,其中三角函數的輸入和輸出都採用弧度值get
注2:R(地球半徑)和Distance單位是相同,若是是採用6378.137公里做爲半徑,那麼Distance就是公里爲單位it
C語言代碼:io
double getDistanceBtwP(double LonA, double LatA,double LonB, double LatB)//根據兩點經緯度計算距離,X經度,Y緯度 { double radLng1 = LatA * M_PI / 180.0; double radLng2 = LatB * M_PI / 180.0; double a = radLng1 - radLng2; double b = (LonA - LonB) * M_PI/ 180.0; double s = 2 * asin(sqrt(pow(sin(a / 2), 2)+ cos(radLng1) * cos(radLng2) * pow(sin(b / 2), 2))) * 6378.137; //返回單位爲千米 return s; }
2、經緯座標中求點到線段的距離的方法
在經緯座標系中,求點C(LonC,LatC)到以點A(LonA,LatA)和點B(LonB,LatB)爲端點的線段的距離D。此問題能夠分爲三種狀況:
①點C在線段AB的正上方時,則距離D=點C到直線AB的垂直距離,如圖1;
②AC與AB造成鈍角時,則距離D=線段AC的長度,如圖2;
③BC與AB造成鈍角時,則距離D=線段BC的長度,如圖3;
一、首先如何判斷是屬於哪一種狀況
咱們能夠利用勾股定理逆定理的推廣,假如AB、BC、AC的長度分別爲a,b,c
①若b*b+c*c<a*a,則邊a所對的角爲鈍角,即圖1的狀況;
②若a*a+c*c<b*b,則邊b所對的角爲鈍角,即圖2的狀況;
③若a*a+b*b<c*c,則邊c所對的角爲鈍角,即圖3的狀況;
二、求圖1狀況的距離D
咱們但願能夠經過距離公式便可求出距離D,從而聯想到海倫公式。
在海倫公式中,三角形的面積,其中,則距離D=2S/a;
3、計算方法總結
對於圖1狀況以及計算出,對於圖2和圖3的計算均已轉換爲兩個點之間的距離公式,此處再也不累贅。所以,在經緯度座標系中,求點到線段的距離的C語言代碼以下:
//點PCx,PCy到線段PAx,PAy,PBx,PBy的距離 double GetNearestDistance(double PAx, double PAy,double PBx, double PBy,double PCx, double PCy) { double a,b,c; a=getDistanceBtwP(PAy,PAx,PBy,PBx);//經緯座標系中求兩點的距離公式 b=getDistanceBtwP(PBy,PBx,PCy,PCx);//經緯座標系中求兩點的距離公式 c=getDistanceBtwP(PAy,PAx,PCy,PCx);//經緯座標系中求兩點的距離公式 if(b*b>=c*c+a*a)return c; if(c*c>=b*b+a*a)return b; double l=(a+b+c)/2; //周長的一半 double s=sqrt(l*(l-a)*(l-b)*(l-c)); //海倫公式求面積 return 2*s/a; }
好了上面是引用的C語言版本的邏輯,咱們能夠了解了基本的計算邏輯
下面是我通過簡單修改事後的C#版本
//地球半徑,單位米 private const double EARTH_RADIUS = 6378137; /// <summary> /// 判斷是否在偏差範圍內 /// </summary> /// <param name="point"></param> /// <param name="points"></param> /// <param name="limitDistance"></param> /// <returns></returns> public static bool InLimitDistance(location point, List<location> points, double limitDistance) { List<double> distance=new List<double>(); var len = points.Count; var maxIndex = len - 1; for (int i = 0; i < len; i++) { //多邊形中當前點 var currentPoint = points[i]; var nearPoint = maxIndex == i ? points[0] : points[i + 1]; double a, b, c; a = GetDistance(point, currentPoint);//經緯座標系中求兩點的距離公式 b = GetDistance(point, nearPoint);//經緯座標系中求兩點的距離公式 c = GetDistance(currentPoint, nearPoint);//經緯座標系中求兩點的距離公式 if (b * b >= c * c + a * a) { distance.Add(c); continue; } if (c * c >= b * b + a * a) { distance.Add(b); continue; } double l = (a + b + c) / 2; //周長的一半 double s = Math.Sqrt(l * (l - a) * (l - b) * (l - c)); //海倫公式求面積 distance.Add(2 * s / a); } if (!distance.Any()) { return false; } var count = distance.Where(s => s < limitDistance).Count(); if (count > 0) return true; return false; } /// <summary> /// 計算兩點位置的距離,返回兩點的距離,單位:米 /// 該公式爲GOOGLE提供,偏差小於0.2米 /// </summary> /// <param name="lng1">第一點經度</param> /// <param name="lat1">第一點緯度</param> /// <param name="lng2">第二點經度</param> /// <param name="lat2">第二點緯度</param> /// <returns></returns> private static double GetDistance(location point1, location point2) { double radLat1 = Rad(point1.lat); double radLng1 = Rad(point1.lng); double radLat2 = Rad(point2.lat); double radLng2 = Rad(point2.lng); double a = radLat1 - radLat2; double b = radLng1 - radLng2; double result = 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))) * EARTH_RADIUS; return result; } /// <summary> /// 經緯度轉化成弧度 /// </summary> /// <param name="d"></param> /// <returns></returns> private static double Rad(double d) { return (double)d * Math.PI / 180d; }