/// <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);
        }
Beispiel #2
0
        /// <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);
        }