1. 程式人生 > >C# 計算地圖上某個坐標點的到多邊形各邊的距離

C# 計算地圖上某個坐標點的到多邊形各邊的距離

半徑 常常 for current ext 一個 技術分享 長度 private

通過兩個位置的經緯度坐標計算距離(C#版本)

轉自:https://blog.csdn.net/jasonsong2008/article/details/78423496

經緯坐標系中求點到線段距離的方法

轉自C語言版本: https://blog.csdn.net/ufoxiong21/article/details/46487001

依據地圖上的經緯度坐標計算某個點到多邊形各邊的距離

轉自JAVA版本 https://blog.csdn.net/james_laughing/article/details/72881056?locationNum=12&fps=1

在一些地圖的應用中(如求偏航),常常需要求一個點到一條線程的距離,以判斷是否遠離航線。然而在經緯度坐標中,並沒有類似直角坐標系中的公式來計算。在經緯度中,一般應用最廣的公式是求兩點距離的方法,如何通過兩點之間的距離公式來達到計算出點到線段的方法呢,我們先來看在經緯度中求兩點距離的計算方法。

一、經緯度中求兩點距離的計算方法

網上有很多介紹該計算方法,此處不再 一一闡述。在北半球中:

C = sin(LatA*Pi/180)*sin(LatB*Pi/180) + cos(LatA*Pi/180)*cos(LatB*Pi/180)*cos((MLonA-MLonB)*Pi/180)

Distance = R*Arccos(C)*Pi/180

註1:其中LonA、LatA、LonB、LatB分別是A、B兩個點的經緯度值,其中三角函數的輸入和輸出都采用弧度值

註2:R(地球半徑)和Distance單位是相同,如果是采用6378.137千米作為半徑,那麽Distance就是千米為單位

C語言代碼:

技術分享圖片
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;
}
技術分享圖片

二、經緯坐標中求點到線段的距離的方法

在經緯坐標系中,求點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;

1、首先如何判斷是屬於哪種情況

我們可以利用勾股定理逆定理的推廣,假如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的情況;

2、求圖1情況的距離D

我們希望可以通過距離公式即可求出距離D,從而聯想到海倫公式。

在海倫公式中,三角形的面積技術分享圖片,其中技術分享圖片,則距離D=2S/a;

三、計算方法總結

對於圖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;
        }

C# 計算地圖上某個坐標點的到多邊形各邊的距離