public Redfearn(Ellipsoid ellipsoid, Projection projection, int zone) { this.ellipsoid = ellipsoid; this.projection = projection; this.zone = zone; double lon_zero_degrees = projection.first_lon + projection.zone_width / 2.0 + projection.zone_width * (zone - projection.first_zone); lon_zero = Math.PI * lon_zero_degrees / 180.0; PrecalculateMeridianDistance(); }
public static void CalculateDistanceAndBearing(Position a, Position b, Ellipsoid e, out double distance, out Angle bearing) { if (PointsEqual(a, b, 1e-12)) { distance = 0.0; bearing = Angle.FromAngleInDegrees(0.0); } double lambda = Radians(b.Longitude - a.Longitude); double last_lambda = 2 * Math.PI; double U1 = Math.Atan((1 - e.F) * Math.Tan(Radians(a.Latitude))); double U2 = Math.Atan((1 - e.F) * Math.Tan(Radians(b.Latitude))); double sin_U1 = Math.Sin(U1); double sin_U2 = Math.Sin(U2); double cos_U1 = Math.Cos(U1); double cos_U2 = Math.Cos(U2); double alpha, sin_sigma, cos_sigma, sigma, cos_2sigma_m, sqr_cos_2sigma_m; int loop_limit = 30; const double threshold = 1e-12; do { double sin_lambda = Math.Sin(lambda); double cos_lambda = Math.Cos(lambda); sin_sigma = Math.Sqrt( Math.Pow(cos_U2 * sin_lambda, 2) + Math.Pow(cos_U1 * sin_U2 - sin_U1 * cos_U2 * cos_lambda, 2) ); cos_sigma = sin_U1 * sin_U2 + cos_U1 * cos_U2 * cos_lambda; sigma = Math.Atan2(sin_sigma, cos_sigma); alpha = Math.Asin(cos_U1 * cos_U2 * sin_lambda / sin_sigma); double sqr_cos_alpha = Math.Pow(Math.Cos(alpha), 2); cos_2sigma_m = cos_sigma - 2 * sin_U1 * sin_U2 / sqr_cos_alpha; sqr_cos_2sigma_m = Math.Pow(cos_2sigma_m, 2); double C = e.F / 16 * sqr_cos_alpha * (4 + e.F * (4 - 3 * sqr_cos_alpha)); last_lambda = lambda; lambda = Radians(b.Longitude - a.Longitude) + (1 - C) * e.F * Math.Sin(alpha) * (sigma + C * sin_sigma * (cos_2sigma_m + C * cos_sigma * (-1 + 2 * sqr_cos_2sigma_m)) ); loop_limit -= 1; } while (Math.Abs(lambda - last_lambda) > threshold && loop_limit > 0); // As in Vincenty 1975, "The inverse formula may give no // solution over a line between two nearly antipodal points": if (loop_limit == 0) { distance = double.NaN; bearing = Angle.FromAngleInDegrees(0.0); return; } double sqr_u = Math.Pow(Math.Cos(alpha), 2) * (e.A * e.A - e.B * e.B) / (e.B * e.B); double A = 1 + sqr_u / 16384 * (4096 + sqr_u * (-768 + sqr_u * (320 - 175 * sqr_u))); double B = sqr_u / 1024 * (256 + sqr_u * (-128 + sqr_u * (74 - 47 * sqr_u))); double delta_sigma = B * sin_sigma * (cos_2sigma_m + B / 4 * (cos_sigma * (-1 + 2 * sqr_cos_2sigma_m) - B / 6 * cos_2sigma_m * (-3 + 4 * Math.Pow(sin_sigma, 2)) * (-3 + 4 * sqr_cos_2sigma_m) )); distance = e.B * A * (sigma - delta_sigma); bearing = Angle.FromHeadingInDegrees(180.0 / Math.PI * Math.Atan2(cos_U2 * Math.Sin(lambda), cos_U1 * sin_U2 - sin_U1 * cos_U2 * Math.Cos(lambda))); }
// Calculates the distance between two points, using the method // described in: // // Vincenty, T. Direct and Inverse Solutions of Geodesics of the // Ellipsoid with Applications of Nested Equations, Survey Review, // No. 176, 1975. // // Points that are nearly antipodal yield no solution; a // Double.NaN is returned. public static double CalculateDistance(Position a, Position b, Ellipsoid e) { double distance; Angle bearing; CalculateDistanceAndBearing(a, b, e, out distance, out bearing); return distance; }