/** * Reverse projection, from Lambert conformal conic to geographic. * * @param[in] lon0 central meridian longitude (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 azimuthal scale of projection at point; the radial * scale is the 1/\e k. * * The latitude origin is given by AlbersEqualArea::LatitudeOrigin(). No * false easting or northing is added. The value of \e lon returned is in * the range [−180°, 180°]. The value of \e lat returned is * in the range [−90°, 90°]. If the input point is outside * the legal projected space the nearest pole is returned. **********************************************************************/ public void Reverse(double lon0, double x, double y, out double lat, out double lon, out double gamma, out double k) { y *= _sign; double nx = _k0 * _n0 * x, ny = _k0 * _n0 * y, y1 = _nrho0 - ny, den = GeoMath.Hypot(nx, y1) + _nrho0, // 0 implies origin with polar aspect drho = den != 0 ? (_k0 * x * nx - 2 * _k0 * y * _nrho0 + _k0 * y * ny) / den : 0, // dsxia = scxi0 * dsxi dsxia = -_scxi0 * (2 * _nrho0 + _n0 * drho) * drho / (GeoMath.Square(_a) * _qZ), txi = (_txi0 + dsxia) / Math.Sqrt(Math.Max(1 - dsxia * (2 * _txi0 + dsxia), epsx2_)), tphi = tphif(txi), theta = Math.Atan2(nx, y1), lam = _n0 != 0 ? theta / (_k2 * _n0) : x / (y1 * _k0); gamma = _sign * theta / GeoMath.Degree; lat = GeoMath.Atand(_sign * tphi); lon = lam / GeoMath.Degree; lon = GeoMath.AngNormalize(lon + GeoMath.AngNormalize(lon0)); k = _k0 * (den != 0 ? (_nrho0 + _n0 * drho) * hyp(_fm * tphi) / _a : 1); }
/** * 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; }