/// <summary> /// Calculate how far the point is along a track from the start-point, heading towards the end-point. /// <para>That is, if a perpendicular is drawn from the point to the (great circle) path, the along-track distance is the distance from the start point to where the perpendicular crosses the path.</para> /// </summary> /// <param name="pointA">The point to calculate the distance from.</param> /// <param name="startPoint">Start point of great circle path.</param> /// <param name="endPoint">End point of great circle path.</param> /// <param name="radius">Radius of earth.</param> /// <returns>The distance along great circle to point nearest point A in the same units as the radius.</returns> public double AlongTrackDistance(ICoordinate pointA, ICoordinate startPoint, ICoordinate endPoint, double radius) { if (pointA == null) { throw new ArgumentNullException(nameof(pointA), "The argument cannot be null."); } if (startPoint == null) { throw new ArgumentNullException(nameof(startPoint), "The argument cannot be null."); } if (endPoint == null) { throw new ArgumentNullException(nameof(endPoint), "The argument cannot be null."); } ValidateRadius(radius); var δ13 = startPoint.DistanceTo(pointA, radius) / radius; var θ13 = startPoint.BearingTo(pointA).ToRadians(); var θ12 = startPoint.BearingTo(endPoint).ToRadians(); var δxt = Math.Asin(Math.Sin(δ13) * Math.Sin(θ13 - θ12)); var δat = Math.Acos(Math.Cos(δ13) / Math.Abs(Math.Cos(δxt))); var result = δat * Math.Sign(Math.Cos(θ12 - θ13)) * radius; return(result); }
/// <summary> /// Calculate final bearing arriving at destination point from point A. /// <para>The final bearing will differ from the initial bearing by varying degrees according to distance and latitude.</para> /// </summary> /// <param name="pointA">The start point.</param> /// <param name="pointB">The end point.</param> /// <returns>Final bearing in degrees from north.</returns> public double FinalBearing(ICoordinate pointA, ICoordinate pointB) { if (pointA == null) { throw new ArgumentNullException(nameof(pointA), "The argument cannot be null."); } if (pointB == null) { throw new ArgumentNullException(nameof(pointB), "The argument cannot be null."); } // Get initial bearing from destination point to this point & reverse it by adding 180°. var result = (pointB.BearingTo(pointA) + 180) % 360; return(result); }