예제 #1
0
        /// <summary>
        /// Forward projection, from geographic to Cassini-Soldner.
        /// </summary>
        /// <param name="lat">latitude of point (degrees).</param>
        /// <param name="lon">longitude of point (degrees).</param>
        /// <param name="azi">azimuth of easting direction at point (degrees).</param>
        /// <param name="rk">reciprocal of azimuthal northing scale at point.</param>
        /// <returns>
        /// <i>x</i>, easting of point and <i>y</i>, northing of point, in meters.
        /// </returns>
        /// <remarks>
        /// <paramref name="lat"/> should be in the range [−90°, 90°].
        /// A call to <see cref="Forward(double, double, out double, out double)"/>
        /// followed by a call to <see cref="Reverse(double, double, out double, out double)"/>
        /// will return the original (<paramref name="lat"/>, <paramref name="lon"/>) (to within roundoff).
        /// The routine does nothing if the origin has not been set.
        /// </remarks>
        public (double x, double y) Forward(double lat, double lon, out double azi, out double rk)
        {
            var dlon  = AngDiff(LongitudeOrigin, lon);
            var sig12 =
                _earth.Inverse(lat, -Abs(dlon), lat, Abs(dlon), out var s12, out var azi1, out var azi2);

            sig12 *= 0.5;
            s12   *= 0.5;
            if (s12 == 0)
            {
                var da = AngDiff(azi1, azi2) / 2;
                if (Abs(dlon) <= 90)
                {
                    azi1 = 90 - da;
                    azi2 = 90 + da;
                }
                else
                {
                    azi1 = -90 - da;
                    azi2 = -90 + da;
                }
            }
            if (dlon < 0)
            {
                azi2  = azi1;
                s12   = -s12;
                sig12 = -sig12;
            }
            var x = s12;

            azi = AngNormalize(azi2);
            var perp = _earth.Line(lat, dlon, azi, GeodesicFlags.GeodesicScale);

            perp.GenPosition(true, -sig12,
                             GeodesicFlags.GeodesicScale,
                             out _, out _, out _, out _, out _, out _, out rk, out _);

            SinCosd(perp.EquatorialAzimuth, out var salp0, out var calp0);
            double
                sbet1  = lat >= 0 ? calp0 : -calp0,
                cbet1  = Abs(dlon) <= 90 ? Abs(salp0) : -Abs(salp0),
                sbet01 = sbet1 * _cbet0 - cbet1 * _sbet0,
                cbet01 = cbet1 * _cbet0 + sbet1 * _sbet0,
                sig01  = Atan2(sbet01, cbet01) / Degree;

            _meridian.GenPosition(true, sig01,
                                  GeodesicFlags.Distance,
                                  out _, out _, out _, out var y, out _, out _, out _, out _);

            return(x, y);
        }