示例#1
0
        /// <summary>
        /// Calculates distance between two geographic locations on equirectangular map projection
        /// <para>Using Pythagoras’ theorem </para>
        /// </summary>
        public static GeoDistance GetDistanceAppx(IGeoLocatable origin, IGeoLocatable destination, double radius = GeoGlobal.Earths.Radius)
        {
            origin      = origin.ToRadians();
            destination = destination.ToRadians();
            var dLat = (destination.Latitude - origin.Latitude);
            var dLon = (destination.Longitude - origin.Longitude);

            var x        = (dLon) * Math.Cos((origin.Latitude + destination.Latitude) / 2);
            var y        = (dLat);
            var distance = Math.Sqrt(x * x + y * y) * radius;

            return(new GeoDistance {
                Kilometers = distance
            });
            //return distance;

            //var yMin = Math.Min(origin.Latitude, destination.Latitude);
            //var yMax = Math.Max(origin.Latitude, destination.Latitude);
            //var xMin = Math.Min(origin.Longitude, destination.Longitude);
            //var xMax = Math.Max(origin.Longitude, destination.Longitude);
            //var yDelta = (yMax - yMin) * (yMax - yMin);
            //var xDelta = (xMax - xMin) * (xMax - xMin);

            //var distance = Math.Sqrt(xDelta + yDelta);
            //return new GeoDistance { Degrees = distance };
        }
示例#2
0
        /// <summary>
        /// Calculates the maximum latitude of a great circle path from origin location in direction of bearing angle
        /// <para>using Clairaut’s formula</para>
        /// </summary>
        /// <param name="origin">origin location in geographic degrees</param>
        /// <param name="bearing">bearing from origin in geographic degrees</param>
        public static double GetLatitudeMax(IGeoLocatable origin, double bearing)
        {
            origin  = origin.ToRadians();
            bearing = bearing.ToRadians();
            var latMax = Math.Acos(Math.Abs(Math.Sin(bearing) * Math.Cos(origin.Latitude)));

            return(latMax);
        }
示例#3
0
        /// <summary>
        /// Calculates the initial bearing from origin location in direction of destination location, in degrees from true North
        /// <para> North = 0, East = 90, South = 180, West = 270 </para>
        /// </summary>
        /// <param name="origin">origin location in geographic degrees</param>
        /// <param name="destination">destination location in geographic degrees</param>
        public static double GetBearing(IGeoLocatable origin, IGeoLocatable destination)
        {
            origin      = origin.ToRadians();
            destination = destination.ToRadians();

            var dLat = (destination.Latitude - origin.Latitude);
            var dLon = (destination.Longitude - origin.Longitude);
            var y    = Math.Sin(dLon) * Math.Cos(destination.Latitude);
            var x    = Math.Cos(origin.Latitude) * Math.Sin(destination.Latitude) -
                       Math.Sin(origin.Latitude) * Math.Cos(destination.Latitude) * Math.Cos(dLon);
            var angle = Math.Atan2(y, x);

            return(angle.ToDegreesNormalized());
        }
示例#4
0
        /// <summary>
        /// Calculates distance between two geographic locations on the Great Circle
        /// <para>Using the Spherical law of cosines </para>
        /// </summary>
        /// <param name="origin">origin location in geographic degrees</param>
        /// <param name="destination">destination location in geographic degrees</param>
        /// <param name="radius">radius of a geographic sphere, in kilometers</param>
        /// <remarks>radius defaults to Earth's mean radius</remarks>
        public static GeoDistance GetDistance(IGeoLocatable origin, IGeoLocatable destination, double radius = GeoGlobal.Earths.Radius)
        {
            origin      = origin.ToRadians();
            destination = destination.ToRadians();
            var sinProd = Math.Sin(origin.Latitude) * Math.Sin(destination.Latitude);
            var cosProd = Math.Cos(origin.Latitude) * Math.Cos(destination.Latitude);
            var dLon    = (destination.Longitude - origin.Longitude);

            var angle    = Math.Acos(sinProd + cosProd * Math.Cos(dLon));
            var distance = angle * radius;

            return(new GeoDistance {
                Kilometers = distance
            });
        }
示例#5
0
        /// <summary>
        /// Calculates mid point between two geographic locations on the Great Circle
        /// <para>Using the Spherical law of cosines </para>
        /// </summary>
        /// <param name="origin">origin location in geographic degrees</param>
        /// <param name="destination">destination location in geographic degrees</param>
        public static GeoPoint GetMidpoint(IGeoLocatable origin, IGeoLocatable destination)
        {
            origin      = origin.ToRadians();
            destination = destination.ToRadians();
            var dLat = (destination.Latitude - origin.Latitude);
            var dLon = (destination.Longitude - origin.Longitude);

            var bx  = Math.Cos(destination.Latitude) * Math.Cos(dLon);
            var by  = Math.Cos(destination.Latitude) * Math.Sin(dLon);
            var lat = Math.Atan2(Math.Sin(origin.Latitude) + Math.Sin(destination.Latitude),
                                 Math.Sqrt((Math.Cos(origin.Latitude) + bx) * (Math.Cos(origin.Latitude) + bx) + by * by));
            var lon = origin.Longitude + Math.Atan2(by, Math.Cos(origin.Latitude) + bx);

            lon = (lon + 3 * Math.PI) % (2 * Math.PI) - Math.PI; // normalize to -180..+180º

            return(new GeoPoint(lon.ToDegrees(), lat.ToDegrees()));
        }
示例#6
0
        /// <summary>
        /// Calculates the destination location at distance and in direction of bearing from origin location
        /// <para>Using the Spherical law of cosines </para>
        /// </summary>
        /// <param name="origin">location in geographic degrees </param>
        /// <param name="bearing">bearing in geographic degrees from origin</param>
        /// <param name="distance">distance in km</param>
        /// <param name="radius">radius in km</param>
        /// <remarks>radius defaults to Earth's mean radius</remarks>
        public static GeoPoint GetDestination(IGeoLocatable origin, double bearing, double distance, double radius = GeoGlobal.Earths.Radius)
        {
            origin   = origin.ToRadians();
            bearing  = bearing.ToRadians();
            distance = distance / radius; // angular distance in radians

            var latitude = Math.Asin(Math.Sin(origin.Latitude) * Math.Cos(distance) +
                                     Math.Cos(origin.Latitude) * Math.Sin(distance) * Math.Cos(bearing));
            var x         = Math.Sin(bearing) * Math.Sin(distance) * Math.Cos(origin.Latitude);
            var y         = Math.Cos(distance) - Math.Sin(origin.Latitude) * Math.Sin(origin.Latitude);
            var longitude = origin.Longitude + Math.Atan2(x, y);

            longitude = (longitude + 3 * Math.PI) % (2 * Math.PI) - Math.PI;  // normalize to -180..+180º

            var destination = new GeoPoint(longitude.ToDegrees(), latitude.ToDegrees());

            return(destination);
        }
示例#7
0
        /// <summary>
        /// Calculates distance between two geographic locations on the Great Circle
        /// <para>Using the Haversine formula</para>
        /// <remarks>"Virtues of the Haversine" by R. W. Sinnott, Sky and Telescope, vol 68, no 2, 1984</remarks>
        /// </summary>
        /// <param name="origin">origin location in geographic degrees</param>
        /// <param name="destination">destination location in geographic degrees</param>
        /// <param name="radius">radius of a geographic sphere, in kilometers</param>
        /// <remarks>radius defaults to Earth's mean radius</remarks>
        public static GeoDistance GetDistanceH(IGeoLocatable origin, IGeoLocatable destination, double radius = GeoGlobal.Earths.Radius)
        {
            origin      = origin.ToRadians();
            destination = destination.ToRadians();

            var dLat = (destination.Latitude - origin.Latitude);
            var dLon = (destination.Longitude - origin.Longitude);

            var a = Math.Sin(dLat / 2) * Math.Sin(dLat / 2) +
                    Math.Sin(dLon / 2) * Math.Sin(dLon / 2) *
                    Math.Cos(origin.Latitude) * Math.Cos(destination.Latitude);
            var c        = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a));
            var distance = radius * c;

            return(new GeoDistance {
                Kilometers = distance
            });
        }
示例#8
0
        /// <summary>
        /// Calculates intersection point of paths from two geographic locations
        /// </summary>
        /// <param name="origin1">origin of first location in geographic degrees</param>
        /// <param name="origin2">origin of second location in geographic degrees</param>
        /// <param name="bearing1">bearing from first location in geographic degrees</param>
        /// <param name="bearing2">bearing from second location in geographic degrees</param>
        /// <param name="radius">radius of a geographic sphere, in kilometers</param>
        /// <remarks>radius defaults to Earth's mean radius</remarks>
        public static GeoPoint GetIntersection(
            IGeoLocatable origin1, double bearing1,
            IGeoLocatable origin2, double bearing2, double radius = GeoGlobal.Earths.Radius)
        {
            origin1 = origin1.ToRadians();
            origin2 = origin2.ToRadians();
            var brng13 = bearing1.ToRadians();
            var brng23 = bearing2.ToRadians();
            var dLat   = (origin2.Latitude - origin1.Latitude);
            var dLon   = (origin2.Longitude - origin1.Longitude);

            var dist12 = 2 * Math.Asin(Math.Sqrt(Math.Sin(dLat / 2) * Math.Sin(dLat / 2) +
                                                 Math.Cos(origin1.Latitude) * Math.Cos(origin2.Latitude) *
                                                 Math.Sin(dLon / 2) * Math.Sin(dLon / 2)));

            if (dist12 == 0)
            {
                return(GeoPoint.Invalid);
            }

            // initial/final bearings between points
            var brngA = Math.Acos((Math.Sin(origin2.Latitude) - Math.Sin(origin1.Latitude) * Math.Cos(dist12)) /
                                  (Math.Sin(dist12) * Math.Cos(origin1.Latitude)));

            if (double.IsNaN(brngA))
            {
                brngA = 0;                       // protect against rounding
            }
            var brngB = Math.Acos((Math.Sin(origin1.Latitude) - Math.Sin(origin2.Latitude) * Math.Cos(dist12)) /
                                  (Math.Sin(dist12) * Math.Cos(origin2.Latitude)));

            double brng12, brng21;

            if (Math.Sin(dLon) > 0)
            {
                brng12 = brngA;
                brng21 = 2 * Math.PI - brngB;
            }
            else
            {
                brng12 = 2 * Math.PI - brngA;
                brng21 = brngB;
            }
            var alpha1 = (brng13 - brng12 + Math.PI) % (2 * Math.PI) - Math.PI;  // angle 2-1-3
            var alpha2 = (brng21 - brng23 + Math.PI) % (2 * Math.PI) - Math.PI;  // angle 1-2-3

            if (Math.Sin(alpha1) == 0 && Math.Sin(alpha2) == 0)
            {
                return(GeoPoint.Invalid);                                                 // infinite intersections
            }
            if (Math.Sin(alpha1) * Math.Sin(alpha2) < 0)
            {
                return(GeoPoint.Invalid);                                                 // ambiguous intersection
            }
            var alpha3 = Math.Acos(-Math.Cos(alpha1) * Math.Cos(alpha2) +
                                   Math.Sin(alpha1) * Math.Sin(alpha2) * Math.Cos(dist12));
            var dist13 = Math.Atan2(Math.Sin(dist12) * Math.Sin(alpha1) * Math.Sin(alpha2),
                                    Math.Cos(alpha2) + Math.Cos(alpha1) * Math.Cos(alpha3));
            var lat3 = Math.Asin(Math.Sin(origin1.Latitude) * Math.Cos(dist13) +
                                 Math.Cos(origin1.Latitude) * Math.Sin(dist13) * Math.Cos(brng13));
            var dLon13 = Math.Atan2(Math.Sin(brng13) * Math.Sin(dist13) * Math.Cos(origin1.Latitude),
                                    Math.Cos(dist13) - Math.Sin(origin1.Latitude) * Math.Sin(lat3));

            var lon3 = origin1.Longitude + dLon13;

            lon3 = (lon3 + 3 * Math.PI) % (2 * Math.PI) - Math.PI;  // normalize to -180..+180º

            return(new GeoPoint(lat3.ToDegrees(), lon3.ToDegrees()));
        }