/// <summary> /// Gets the distance between two coordinates using a rhumb line /// </summary> /// <param name="source">The source coordinate</param> /// <param name="destination">The destination coordinate</param> /// <param name="distanceType">The unit of measure for the distance, this defaults to KILOMETERS</param> /// <returns>The distance between the two coordinates</returns> public static double GetRhumbDistance(ICoordinate source, ICoordinate destination, DistanceType distanceType = DistanceType.KILOMETERS) { double Radius = 0; switch (distanceType) { case DistanceType.KILOMETERS: { Radius = EarthRadiusInKilometers; break; } case DistanceType.METERS: { Radius = EarthRadiusInKilometers * 1000; break; } case DistanceType.MILES: { Radius = EarthRadiusInMiles; break; } } double Lat1 = DegreeToRadian(source.GetLatitude().DecimalDegrees); double Lat2 = DegreeToRadian(destination.GetLatitude().DecimalDegrees); double DeltaLatitude = DegreeToRadian(destination.GetLatitude().DecimalDegrees - source.GetLatitude().DecimalDegrees); double DeltaLongitude = DegreeToRadian(Math.Abs(destination.GetLongitude().DecimalDegrees - source.GetLongitude().DecimalDegrees)); double DeltaPhi = Math.Log(Math.Tan(Lat2 / 2 + Math.PI / 4) / Math.Tan(Lat1 / 2 + Math.PI / 4)); double Q = Math.Cos(Lat1); if (DeltaPhi != 0) { Q = DeltaLatitude / DeltaPhi; // E-W line gives DeltaPhi=0 } // if DeltaLongitude over 180° take shorter rhumb across 180° meridian if (DeltaLongitude > Math.PI) { DeltaLongitude = 2 * Math.PI - DeltaLongitude; } double Distance = Math.Sqrt(Math.Pow(DeltaLatitude, 2) + Math.Pow(Q, 2) * Math.Pow(DeltaLongitude, 2)) * Radius; return(Distance); }
/// <summary> /// Gets the distance between two coordinates using the Haversine formula /// </summary> /// <param name="source">The source coordinate</param> /// <param name="destination">The destination coordinate</param> /// <param name="distanceType">The unit of measure for the distance, this defaults to KILOMETERS</param> /// <returns>The distance between the two coordinates</returns> public static double GetDistance(ICoordinate source, ICoordinate destination, DistanceType distanceType = DistanceType.KILOMETERS) { double Radius = 0; switch (distanceType) { case DistanceType.KILOMETERS: { Radius = EarthRadiusInKilometers; break; } case DistanceType.METERS: { Radius = EarthRadiusInKilometers * 1000; break; } case DistanceType.MILES: { Radius = EarthRadiusInMiles; break; } } double DeltaLatitude = DegreeToRadian(destination.GetLatitude().DecimalDegrees - source.GetLatitude().DecimalDegrees); double DeltaLongitude = DegreeToRadian(destination.GetLongitude().DecimalDegrees - source.GetLongitude().DecimalDegrees); double A = Math.Pow(Math.Sin(DeltaLatitude / 2), 2) + Math.Cos(DegreeToRadian(source.GetLatitude().DecimalDegrees)) * Math.Cos(DegreeToRadian(destination.GetLatitude().DecimalDegrees)) * Math.Pow(Math.Sin(DeltaLongitude / 2), 2); double C = 2 * Math.Atan2(Math.Sqrt(A), Math.Sqrt(1 - A)); double Distance = C * Radius; return(Distance); }
/// <summary> /// Gets the initial bearing from one geocoordinate to another based on the Haversine formula /// </summary> /// <param name="source">The source coordinate</param> /// <param name="destination">The destination coordinate</param> /// <returns>The bearing from source to destination in degrees</returns> public static double GetInitialBearing(ICoordinate source, ICoordinate destination) { double Lat1 = DegreeToRadian(source.GetLatitude().DecimalDegrees); double Lat2 = DegreeToRadian(destination.GetLatitude().DecimalDegrees); double DeltaLongitude = DegreeToRadian(destination.GetLongitude().DecimalDegrees) - DegreeToRadian(source.GetLongitude().DecimalDegrees); double Y = Math.Cos(Lat2) * Math.Sin(DeltaLongitude); double X = Math.Cos(Lat1) * Math.Sin(Lat2) - Math.Sin(Lat1) * Math.Cos(Lat2) * Math.Cos(DeltaLongitude); // Multiply degrees per radian return((RadianToDegree(Math.Atan2(Y, X)) + 360) % 360); }
/// <summary> /// Gets the bearing from one latitude/longitude coordinate to another based on the Rhumb formula /// </summary> /// <param name="source">The source coordinate</param> /// <param name="destination">The destination coordinate</param> /// <returns>The bearing from source to destination in degrees</returns> public static double GetRhumbBearing(ICoordinate source, ICoordinate destination) { double Lat1 = DegreeToRadian(source.GetLatitude().DecimalDegrees); double Lat2 = DegreeToRadian(destination.GetLatitude().DecimalDegrees);; double DeltaLongitude = DegreeToRadian(destination.GetLongitude().DecimalDegrees - source.GetLongitude().DecimalDegrees); double X = Math.Log(Math.Tan(Lat2 / 2 + Math.PI / 4) / Math.Tan(Lat1 / 2 + Math.PI / 4)); if (Math.Abs(DeltaLongitude) > Math.PI) { DeltaLongitude = (DeltaLongitude > 0) ? -(2 * Math.PI - DeltaLongitude) : (2 * Math.PI + DeltaLongitude); } double Bearing = Math.Atan2(DeltaLongitude, X); return((RadianToDegree(Bearing) + 360) % 360); }
/// <summary> /// Finds the destination from a source using a rhumb line /// </summary> /// <param name="source">The source coordinate</param> /// <param name="bearing">The bearing to the destination in degrees</param> /// <param name="distance">The distance away from the source</param> /// <param name="distanceType">The unit of measure that the distance is provided in</param> /// <returns>The destination</returns> public static ICoordinate FindRhumbDestination(ICoordinate source, double bearing, double distance, DistanceType distanceType) { double DistanceRatio = distance / GetRadius(distanceType); double SourceLatitude = DegreeToRadian(source.GetLatitude().DecimalDegrees); double SourceLongitude = DegreeToRadian(source.GetLongitude().DecimalDegrees); bearing = DegreeToRadian(bearing); double DestinationLatitude = SourceLatitude + (DistanceRatio * Math.Cos(bearing)); double Delta = Math.Log(Math.Tan((Math.PI / 4) + (DestinationLatitude / 2)) / Math.Tan((Math.PI / 4) + (SourceLatitude / 2))); double Q = (DestinationLatitude - SourceLatitude) / Delta; double ShortestRoute = DistanceRatio * Math.Sin(bearing) / Q; double DestinationLongitude = SourceLongitude + ShortestRoute; return(new GeoCoordinate(RadianToDegree(DestinationLatitude), RadianToDegree(DestinationLongitude))); }
/// <summary> /// Finds the destination geocoordinate given a source coordinate, bearing, and distance /// </summary> /// <param name="source">The source coordinate</param> /// <param name="bearing">The direction of travel from the source in degrees</param> /// <param name="distance">The distance traveled</param> /// <param name="distanceType">The unit of measure that the distance is provided in</param> /// <returns>The destination geocoordinate</returns> public static ICoordinate FindDestination(ICoordinate source, double bearing, double distance, DistanceType distanceType) { double Radius = GetRadius(distanceType); double Latitude = DegreeToRadian(source.GetLatitude().DecimalDegrees); double Longitude = DegreeToRadian(source.GetLongitude().DecimalDegrees); bearing = DegreeToRadian(bearing); double DestinationLatitude = RadianToDegree(Math.Asin( Math.Sin(Latitude) * Math.Cos(distance / Radius) + Math.Cos(Latitude) * Math.Sin(distance / Radius) * Math.Cos(bearing) )); double DestinationLongitude = RadianToDegree(Longitude + Math.Atan2( Math.Sin(bearing) * Math.Sin(distance / Radius) * Math.Cos(Latitude), Math.Cos(distance / Radius) - Math.Sin(Latitude) * Math.Sin(DegreeToRadian(DestinationLatitude)) )); return(new GeoCoordinate(DestinationLatitude, ((DestinationLongitude + 540) % 360) - 180)); }
public void HaversineDestination() { // ARRANGE GeoCoordinate Source = new GeoCoordinate(40.7486, 5.4253); GeoCoordinate Destination = new GeoCoordinate(58.3838, 3.01412); // ACT ICoordinate CalculatedDestination = Source.FindDestination(355.84047394177765, 1967.0898177084771, DistanceType.KILOMETERS); // ASSERT Assert.Equal(Math.Round(Destination.Latitude.DecimalDegrees, 2), Math.Round(CalculatedDestination.GetLatitude().DecimalDegrees, 2)); Assert.Equal(Math.Round(Destination.Longitude.DecimalDegrees, 2), Math.Round(CalculatedDestination.GetLongitude().DecimalDegrees, 2)); }
public void RhumbDestination() { // ARRANGE GeoCoordinate Source = new GeoCoordinate(40.7486, 5.4253); GeoCoordinate Destination = new GeoCoordinate(58.3838, 3.01412); // ACT ICoordinate CalculatedDestination = Source.FindRhumbDestination(355, 1967, DistanceType.KILOMETERS); // ASSERT Assert.Equal(Math.Round(Destination.GetLatitude().DecimalDegrees, 2), Math.Round(CalculatedDestination.GetLatitude().DecimalDegrees, 2)); Assert.Equal(Math.Round(Destination.GetLongitude().DecimalDegrees, 2), Math.Round(CalculatedDestination.GetLongitude().DecimalDegrees, 2)); }