예제 #1
0
        /**
         * Reverse projection, from transverse Mercator to geographic.
         *
         * @param[in] lon0 central meridian of the projection (degrees).
         * @param[in] x easting of point (meters).
         * @param[in] y northing of point (meters).
         * @param[out] lat latitude of point (degrees).
         * @param[out] lon longitude of point (degrees).
         * @param[out] gamma meridian convergence at point (degrees).
         * @param[out] k scale of projection at point.
         *
         * No false easting or northing is added.  The value of \e lon returned is
         * in the range [−180°, 180°].
         **********************************************************************/
        public void Reverse(double lon0, double x, double y,
                            out double lat, out double lon, out double gamma, out double k)
        {
            // This undoes the steps in Forward.  The wrinkles are: (1) Use of the
            // reverted series to express zeta' in terms of zeta. (2) Newton's method
            // to solve for phi in terms of tan(phi).
            double
                xi  = y / (_a1 * _k0),
                eta = x / (_a1 * _k0);
            // Explicitly enforce the parity
            int
                xisign  = (xi < 0) ? -1 : 1,
                etasign = (eta < 0) ? -1 : 1;

            xi  *= xisign;
            eta *= etasign;
            bool backside = xi > Math.PI / 2;

            if (backside)
            {
                xi = Math.PI - xi;
            }
            double
                c0 = Math.Cos(2 * xi), ch0 = Math.Cosh(2 * eta),
                s0 = Math.Sin(2 * xi), sh0 = Math.Sinh(2 * eta);


            int     n  = maxpow_;
            Complex a  = new Complex(2 * c0 * ch0, -2 * s0 * sh0); // 2 * Math.Cos(2*zeta')
            Complex y0 = new Complex((n & 1) != 0 ? -_bet[n] : 0, 0);
            Complex y1;                                            // default initializer is 0+i0
            Complex z0 = new Complex((n & 1) != 0 ? -2 * n * _bet[n] : 0, 0);
            Complex z1;

            if ((n & 1) != 0)
            {
                --n;
            }
            while (n > 0)
            {
                y1 = a * y0 - y1 - _bet[n];
                z1 = a * z0 - z1 - 2 * n * _bet[n];
                --n;
                y0 = a * y1 - y0 - _bet[n];
                z0 = a * z1 - z0 - 2 * n * _bet[n];
                --n;
            }
            a /= 2;                               // Math.Cos(2*zeta)
            z1 = 1 - z1 + a * z0;
            a  = new Complex(s0 * ch0, c0 * sh0); // Math.Sin(2*zeta)
            y1 = new Complex(xi, eta) + a * y0;
            // Convergence and scale for Gauss-Schreiber TM to Gauss-Krueger TM.
            gamma = GeoMath.Atan2d(z1.Imaginary, z1.Real);
            k     = _b1 / Complex.Abs(z1);
            // JHS 154 has
            //
            //   phi' = asin(Math.Sin(xi') / Math.Cosh(eta')) (Krueger p 17 (25))
            //   lam = asin(tanh(eta') / Math.Cos(phi')
            //   psi = asinh(tan(phi'))
            double
                xip = y1.Real, etap = y1.Imaginary,
                s = Math.Sinh(etap),
                c = Math.Max(0, Math.Cos(xip)), // Math.Cos(pi/2) might be negative
                r = GeoMath.Hypot(s, c);

            if (r != 0)
            {
                lon = GeoMath.Atan2d(s, c); // Krueger p 17 (25)
                                            // Use Newton's method to solve for tau
                double
                    sxip = Math.Sin(xip),
                    tau  = GeoMath.Tauf(sxip / r, _es);
                gamma += GeoMath.Atan2d(sxip * Math.Tanh(etap), c); // Krueger p 19 (31)
                lat    = GeoMath.Atand(tau);
                // Note Math.Cos(phi') * Math.Cosh(eta') = r
                k *= Math.Sqrt(_e2m + _e2 / (1 + GeoMath.Square(tau))) *
                     GeoMath.Hypot(1, tau) * r;
            }
            else
            {
                lat = 90;
                lon = 0;
                k  *= _c;
            }
            lat *= xisign;
            if (backside)
            {
                lon = 180 - lon;
            }
            lon *= etasign;
            lon  = GeoMath.AngNormalize(lon + lon0);
            if (backside)
            {
                gamma = 180 - gamma;
            }
            gamma *= xisign * etasign;
            gamma  = GeoMath.AngNormalize(gamma);
            k     *= _k0;
        }