/// <summary> /// Set the central point of the projection /// </summary> /// <param name="lat0">latitude of center point of projection (degrees).</param> /// <param name="lon0">longitude of center point of projection (degrees).</param> /// <remarks> /// <paramref name="lat0"/> should be in the range [−90°, 90°]. /// </remarks> public void Reset(double lat0, double lon0) { _meridian = _earth.Line(lat0, lon0, 0, GeodesicFlags.Latitude | GeodesicFlags.Longitude | GeodesicFlags.Distance | GeodesicFlags.DistanceIn | GeodesicFlags.Azimuth); var f = _earth.Flattening; SinCosd(LatitudeOrigin, out _sbet0, out _cbet0); _sbet0 *= (1 - f); Norm(ref _sbet0, ref _cbet0); }
/// <summary> /// Reverse projection, from gnomonic to geographic. /// </summary> /// <param name="lat0">latitude of center point of projection (degrees).</param> /// <param name="lon0">longitude of center point of projection (degrees).</param> /// <param name="x">easting of point (meters).</param> /// <param name="y">northing of point (meters).</param> /// <param name="azi">azimuth of geodesic at point (degrees).</param> /// <param name="rk">reciprocal of azimuthal scale at point.</param> /// <returns> /// <i>lat</i>, latitude of point (degrees) and <i>lon</i>, longitude of point (degrees). /// </returns> /// <remarks> /// <paramref name="lat0"/> should be in the range [−90°, 90°]. /// <i>lat</i> will be in the range [−90°, 90°] and <i>lon</i> will be in the range [−180°, 180°]. /// The scale of the projection is 1/<paramref name="rk"/>^2 in the "radial" direction, <paramref name="azi"/> clockwise from true north, /// and is 1/<paramref name="rk"/> in the direction perpendicular to this. Even though all inputs should return a valid <i>lat</i> and <i>lon</i>, /// it's possible that the procedure fails to converge for very large <paramref name="x"/> or <paramref name="y"/>; /// in this case <see cref="double.NaN"/>s are returned for all the output arguments. /// A call to <see cref="Reverse(double, double, double, double, out double, out double)"/> followed by a call to /// <see cref="Forward(double, double, double, double, out double, out double)"/> /// will return the original (<paramref name="x"/>, <paramref name="y"/>) (to roundoff). /// </remarks> public (double lat, double lon) Reverse(double lat0, double lon0, double x, double y, out double azi, out double rk) { double lat, lon, azi0 = Atan2d(x, y), rho = Hypot(x, y), s = _a * Atan(rho / _a); bool little = rho <= _a; if (!little) { rho = 1 / rho; } var line = _earth.Line(lat0, lon0, azi0, GeodesicFlags.Latitude | GeodesicFlags.Longitude | GeodesicFlags.Azimuth | GeodesicFlags.DistanceIn | GeodesicFlags.ReducedLength | GeodesicFlags.GeodesicScale); int count = numit_, trip = 0; double lat1 = 0, lon1 = 0, azi1 = 0, M = 0; while (count-- != 0 || GEOGRAPHICLIB_PANIC) { line.Position(s, out lat1, out lon1, out azi1, out var m, out M, out _); if (trip != 0) { break; } // If little, solve rho(s) = rho with drho(s)/ds = 1/M^2 // else solve 1/rho(s) = 1/rho with d(1/rho(s))/ds = -1/m^2 var ds = little ? (m - rho * M) * M : (rho * m - M) * m; s -= ds; // Reversed test to allow escape with NaNs if (!(Abs(ds) >= eps_ * _a)) { ++trip; } } if (trip != 0) { (lat, lon, azi, rk) = (lat1, lon1, azi1, M); } else { lat = lon = azi = rk = double.NaN; } return(lat, lon); }