/// <summary> /// Get <see cref="CoordinatePoint" /> at distance and direction on an ellipsoid. /// </summary> /// <param name="basePoint">Source <see cref="CoordinatePoint"/>.</param> /// <param name="distance">Distance to a new point, meters.</param> /// <param name="azimuth">Azimuth to a new point, radians.</param> /// <param name="backAzimuth">Azimuth from a new point to base point, radians.</param> /// <returns><see cref="CoordinatePoint" /> at specified distance and direction from the base point.</returns> public static CoordinatePoint GetCoordinatePointAtDistanceAndDirectionOnAnEllipsoid(CoordinatePoint basePoint, LinearDimension distance, double azimuth, out double backAzimuth) { double deltaLatitude; double deltaLongitude; double deltaAzimuth; double newDeltaLatitude = 0; double newDeltaLongitude = 0; double newDeltaAzimuth = 0; do { deltaLatitude = newDeltaLatitude; deltaLongitude = newDeltaLongitude; deltaAzimuth = newDeltaAzimuth; double iterationLatitude = basePoint.Latitude.ToRadians() + deltaLatitude / 2; double iterationAzimuth = azimuth + deltaAzimuth / 2; double beta = distance.GetMeters() * Math.Cos(iterationAzimuth) / GetMeridionalForLatitude(Latitude.FromRadians(iterationLatitude)); double sigma = distance.GetMeters() * Math.Sin(iterationAzimuth) / (GetPrimeVerticalForLatitude(Latitude.FromRadians(iterationLatitude)) * Math.Cos(iterationLatitude)); double alpha = deltaLongitude * Math.Sin(iterationLatitude); newDeltaLatitude = beta * (1 + (2 * Math.Pow(sigma, 2d) + Math.Pow(alpha, 2d)) / 24); newDeltaLongitude = sigma * (1 + (Math.Pow(alpha, 2d) - Math.Pow(beta, 2d)) / 24); newDeltaAzimuth = alpha * (1 + (3 * Math.Pow(beta, 2d) + 2 * Math.Pow(sigma, 2d) - 2 * Math.Pow(alpha, 2d)) / 24); }while (Math.Abs(newDeltaLatitude - deltaLatitude) > 0.0000001d || Math.Abs(deltaLongitude - newDeltaLongitude) > 0.0000001d); backAzimuth = azimuth + newDeltaAzimuth + Math.PI; return(new CoordinatePoint(Latitude.FromRadians(basePoint.Latitude.ToRadians() + newDeltaLatitude), Longitude.FromRadians(basePoint.Longitude.ToRadians() + newDeltaLongitude))); }
/// <summary> /// Get <see cref="CoordinatePoint" /> at distance and direction on the flat. /// </summary> /// <param name="basePoint">Source <see cref="CoordinatePoint"/></param> /// <param name="distance">Distance to a new point.</param> /// <param name="azimuth">Direction from one point to another in radians.</param> /// <returns><see cref="CoordinatePoint"/> at specified distance and direction from the given point.</returns> public static CoordinatePoint GetCoordinatePointAtDistanceAndDirectionOnTheFlat(CoordinatePoint basePoint, LinearDimension distance, double azimuth) { var deltaLatitudeGrad = distance.GetMeters() * Math.Cos(azimuth) / (_earthWgs84MeanRadius * _d2R); var deltaLongitudeGrad = distance.GetMeters() * Math.Sin(azimuth) / (_earthWgs84MeanRadius * _d2R); return(new CoordinatePoint(basePoint.Latitude.ToDegrees() + deltaLatitudeGrad, basePoint.Longitude.ToDegrees() + deltaLongitudeGrad)); }
/// <summary> /// Get <see cref="CoordinatePoint" /> at distance and direction on sphere with Haversine. /// </summary> /// <param name="basePoint">Source <see cref="CoordinatePoint"/>.</param> /// <param name="distance">Distance to a new point, meters.</param> /// <param name="azimuth">Azimuth to a new point, radians.</param> /// <param name="backAzimuth">Azimuth from a new point to base point, radians.</param> /// <returns><see cref="CoordinatePoint" /> at specified distance and direction from the base point.</returns> /// <seealso cref="http://www.movable-type.co.uk/scripts/latlong.html"/> public static CoordinatePoint GetCoordinatePointAtDistanceAndDirectionWithHaversine(CoordinatePoint basePoint, LinearDimension distance, double azimuth, out double backAzimuth) { var startLatitudeRadians = basePoint.Latitude.ToRadians(); var dR = distance.GetMeters() / _earthWgs84MeanRadius; var finishLatitudeRadians = Math.Asin(Math.Sin(startLatitudeRadians) * Math.Cos(dR) + Math.Cos(startLatitudeRadians) * Math.Sin(dR) * Math.Cos(azimuth)); var finishLongitudeRadians = basePoint.Longitude.ToRadians() + Math.Atan2(Math.Sin(azimuth) * Math.Sin(dR) * Math.Cos(startLatitudeRadians), Math.Cos(dR) - Math.Sin(startLatitudeRadians) * Math.Sin(finishLatitudeRadians)); var y = Math.Sin(finishLongitudeRadians - basePoint.Longitude.ToRadians()) * Math.Cos(finishLatitudeRadians); var x = Math.Cos(startLatitudeRadians) * Math.Sin(finishLatitudeRadians) - Math.Sin(startLatitudeRadians) * Math.Cos(finishLatitudeRadians) * Math.Cos(finishLongitudeRadians - basePoint.Longitude.ToRadians()); backAzimuth = Math.Atan2(y, x) + Math.PI; return(new CoordinatePoint(Latitude.FromRadians(finishLatitudeRadians), Longitude.FromRadians(finishLongitudeRadians))); }