How to calculate distance from a point to a line segment, on a sphere?

后端 未结 7 1343
一向
一向 2020-11-27 04:47

I have a line segment (great circle part) on earth. The line segment is defined by the coordinates of its ends. Obviously, two points define two line segments, so assume I a

相关标签:
7条回答
  • 2020-11-27 05:18

    If someone needs it this is loleksy answer ported to c#

            private static double _eQuatorialEarthRadius = 6378.1370D;
            private static double _d2r = (Math.PI / 180D);
            private static double PRECISION = 0.1;
    
            // Haversine Algorithm
            // source: http://stackoverflow.com/questions/365826/calculate-distance-between-2-gps-coordinates
    
            private static double HaversineInM(double lat1, double long1, double lat2, double long2) {
                return  (1000D * HaversineInKM(lat1, long1, lat2, long2));
            }
    
            private static double HaversineInKM(double lat1, double long1, double lat2, double long2) {
                double dlong = (long2 - long1) * _d2r;
                double dlat = (lat2 - lat1) * _d2r;
                double a = Math.Pow(Math.Sin(dlat / 2D), 2D) + Math.Cos(lat1 * _d2r) * Math.Cos(lat2 * _d2r)
                        * Math.Pow(Math.Sin(dlong / 2D), 2D);
                double c = 2D * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1D - a));
                double d = _eQuatorialEarthRadius * c;
                return d;
            }
    
            // Distance between a point and a line
            static double pointLineDistanceGEO(double[] a, double[] b, double[] c)
            {
    
                double[] nearestNode = nearestPointGreatCircle(a, b, c);
                double result = HaversineInKM(c[0], c[1], nearestNode[0], nearestNode[1]);
    
                return result;
            }
    
            // source: http://stackoverflow.com/questions/1299567/how-to-calculate-distance-from-a-point-to-a-line-segment-on-a-sphere
            private static double[] nearestPointGreatCircle(double[] a, double[] b, double [] c)
            {
                double[] a_ = toCartsian(a);
                double[] b_ = toCartsian(b);
                double[] c_ = toCartsian(c);
    
                double[] G = vectorProduct(a_, b_);
                double[] F = vectorProduct(c_, G);
                double[] t = vectorProduct(G, F);
    
                return fromCartsian(multiplyByScalar(normalize(t), _eQuatorialEarthRadius));
            }
    
            private static double[] nearestPointSegment (double[] a, double[] b, double[] c)
            {
               double[] t= nearestPointGreatCircle(a,b,c);
               if (onSegment(a,b,t))
                 return t;
               return (HaversineInKM(a[0], a[1], c[0], c[1]) < HaversineInKM(b[0], b[1], c[0], c[1])) ? a : b;
            }
    
             private static bool onSegment (double[] a, double[] b, double[] t)
               {
                 // should be   return distance(a,t)+distance(b,t)==distance(a,b), 
                 // but due to rounding errors, we use: 
                 return Math.Abs(HaversineInKM(a[0], a[1], b[0], b[1])-HaversineInKM(a[0], a[1], t[0], t[1])-HaversineInKM(b[0], b[1], t[0], t[1])) < PRECISION;
               }
    
    
            // source: http://stackoverflow.com/questions/1185408/converting-from-longitude-latitude-to-cartesian-coordinates
            private static double[] toCartsian(double[] coord) {
                double[] result = new double[3];
                result[0] = _eQuatorialEarthRadius * Math.Cos(deg2rad(coord[0])) * Math.Cos(deg2rad(coord[1]));
                result[1] = _eQuatorialEarthRadius * Math.Cos(deg2rad(coord[0])) * Math.Sin(deg2rad(coord[1]));
                result[2] = _eQuatorialEarthRadius * Math.Sin(deg2rad(coord[0]));
                return result;
            }
    
            private static double[] fromCartsian(double[] coord){
                double[] result = new double[2];
                result[0] = rad2deg(Math.Asin(coord[2] / _eQuatorialEarthRadius));
                result[1] = rad2deg(Math.Atan2(coord[1], coord[0]));
    
                return result;
            }
    
    
            // Basic functions
            private static double[] vectorProduct (double[] a, double[] b){
                double[] result = new double[3];
                result[0] = a[1] * b[2] - a[2] * b[1];
                result[1] = a[2] * b[0] - a[0] * b[2];
                result[2] = a[0] * b[1] - a[1] * b[0];
    
                return result;
            }
    
            private static double[] normalize(double[] t) {
                double length = Math.Sqrt((t[0] * t[0]) + (t[1] * t[1]) + (t[2] * t[2]));
                double[] result = new double[3];
                result[0] = t[0]/length;
                result[1] = t[1]/length;
                result[2] = t[2]/length;
                return result;
            }
    
            private static double[] multiplyByScalar(double[] normalize, double k) {
                double[] result = new double[3];
                result[0] = normalize[0]*k;
                result[1] = normalize[1]*k;
                result[2] = normalize[2]*k;
                return result;
            }
    
    0 讨论(0)
提交回复
热议问题