/// <summary> /// The forward transform from geodetic units to linear units /// </summary> /// <param name="lp">The array of lambda, phi coordinates</param> /// <param name="xy">The array of x, y coordinates</param> protected override void OnForward(double[] lp, double[] xy) { double sp = E * Math.Sin(lp[Phi]); double phip = 2 * Math.Atan(Math.Exp(_c * ( Math.Log(Math.Tan(FortPi + 0.5 * lp[Phi])) - _hlfE * Math.Log((1 + sp) / (1 - sp))) + _k)) - HalfPi; double lamp = _c * lp[Lambda]; double cp = Math.Cos(phip); double phipp = Proj.Aasin(_cosp0 * Math.Sin(phip) - _sinp0 * cp * Math.Cos(lamp)); double lampp = Proj.Aasin(cp * Math.Sin(lamp) / Math.Cos(phipp)); xy[X] = _kR * lampp; xy[Y] = _kR * Math.Log(Math.Tan(FortPi + 0.5 * phipp)); }
/// <summary> /// Performs the inverse transfrom from a single coordinate of linear units to the same coordinate in geodetic units /// </summary> /// <param name="xy">The double linear input x and y values organized into a 1 dimensional array</param> /// <param name="lp">The double geodetic output lambda and phi values organized into a 1 dimensional array</param> protected override void EllipticalInverse(double[] xy, double[] lp) { if (_isGuam) { GuamInverse(xy, lp); } double c; if ((c = Proj.Hypot(xy[X], xy[Y])) < EPS10) { lp[Phi] = Phi0; lp[Lambda] = 0; return; } if (_mode == Modes.Oblique || _mode == Modes.Equitorial) { double az; double cosAz = Math.Cos(az = Math.Atan2(xy[X], xy[Y])); double t = _cosph0 * cosAz; double b = Es * t / OneEs; double a = -b * t; b *= 3 * (1 - a) * _sinph0; double d = c / _N1; double e = d * (1 - d * d * (a * (1 + a) / 6 + b * (1 + 3 * a) * d / 24)); double f = 1 - e * e * (a / 2 + b * e / 6); double psi = Proj.Aasin(_sinph0 * Math.Cos(e) + t * Math.Sin(e)); lp[Lambda] = Proj.Aasin(Math.Sin(az) * Math.Sin(e) / Math.Cos(psi)); if ((t = Math.Abs(psi)) < EPS10) { lp[Phi] = 0; } else if (Math.Abs(t - HalfPi) < 0) { lp[Phi] = HalfPi; } else { lp[Phi] = Math.Atan((1 - Es * f * _sinph0 / Math.Sin(psi)) * Math.Tan(psi) / OneEs); } } else { /* Polar */ lp[Phi] = Proj.InvMlfn(_mode == Modes.NorthPole ? _Mp - c : _Mp + c, Es, _en); lp[Lambda] = Math.Atan2(xy[X], _mode == Modes.NorthPole ? -xy[Y] : xy[Y]); } }
/// <summary> /// The forward transform from geodetic units to linear units /// </summary> /// <param name="lp">The array of lambda, phi coordinates</param> /// <param name="xy">The array of x, y coordinates</param> protected override void OnForward(double[] lp, double[] xy) { if ((_rho = _c - (IsElliptical ? _n * Proj.Qsfn(Math.Sin(lp[Phi]), E, OneEs) : _n2 *Math.Sin(lp[Phi]))) < 0) { xy[X] = double.NaN; xy[Y] = double.NaN; //throw new ProjectionException(20); return; } _rho = _dd * Math.Sqrt(_rho); xy[X] = _rho * Math.Sin(lp[Lambda] *= _n); xy[Y] = _rho0 - _rho * Math.Cos(lp[Lambda]); }
/// <summary> /// Performs the inverse transform from a single coordinate of linear units to the same coordinate in geodetic lambda and /// phi units in the special case where the shape of the earth is being approximated as a perfect sphere. /// </summary> /// <param name="xy">The double linear input x and y values organized into a 1 dimensional array</param> /// <param name="lp">The double geodetic output lambda and phi values organized into a 1 dimensional array</param> protected override void SphericalInverse(double[] xy, double[] lp) { double cRh; if ((cRh = Proj.Hypot(xy[X], xy[Y])) > Math.PI) { if (cRh - EPS10 > Math.PI) { throw new ProjectionException(20); } cRh = Math.PI; } else if (cRh < EPS10) { lp[Phi] = Phi0; lp[Lambda] = 0; return; } if (_mode == Modes.Oblique || _mode == Modes.Equitorial) { double sinc = Math.Sin(cRh); double cosc = Math.Cos(cRh); if (_mode == Modes.Equitorial) { lp[Phi] = Proj.Aasin(xy[Y] * sinc / cRh); xy[X] *= sinc; xy[Y] = cosc * cRh; } else { lp[Phi] = Proj.Aasin(cosc * _sinph0 + xy[Y] * sinc * _cosph0 / cRh); xy[Y] = (cosc - _sinph0 * Math.Sin(lp[Phi])) * cRh; xy[X] *= sinc * _cosph0; } lp[Lambda] = xy[Y] == 0 ? 0 : Math.Atan2(xy[X], xy[Y]); } else if (_mode == Modes.NorthPole) { lp[Phi] = HalfPi - cRh; lp[Lambda] = Math.Atan2(xy[X], -xy[Y]); } else { lp[Phi] = cRh - HalfPi; lp[Lambda] = Math.Atan2(xy[X], xy[Y]); } }
/// <summary> /// Initializes the transform using the parameters from the specified coordinate system information /// </summary> /// <param name="projInfo">A ProjectionInfo class contains all the standard and custom parameters needed to initialize this transform</param> protected override void OnInit(ProjectionInfo projInfo) { double sinphi; if (projInfo.StandardParallel1 != null) { _phi1 = projInfo.StandardParallel1.Value * Math.PI / 180; } if (projInfo.StandardParallel2 != null) { _phi2 = projInfo.StandardParallel2.Value * Math.PI / 180; } if (Math.Abs(_phi1 + _phi2) < EPS10) { throw new ProjectionException(-21); } _en = Proj.Enfn(Es); _n = sinphi = Math.Sin(_phi1); double cosphi = Math.Cos(_phi1); bool secant = Math.Abs(_phi1 - _phi2) >= EPS10; if (IsElliptical) { double m1 = Proj.Msfn(sinphi, cosphi, Es); double ml1 = Proj.Mlfn(_phi1, sinphi, cosphi, _en); if (secant) { /* secant cone */ sinphi = Math.Sin(_phi2); cosphi = Math.Cos(_phi2); _n = (m1 - Proj.Msfn(sinphi, cosphi, Es)) / (Proj.Mlfn(_phi2, sinphi, cosphi, _en) - ml1); } _c = ml1 + m1 / _n; _rho0 = _c - Proj.Mlfn(Phi0, Math.Sin(Phi0), Math.Cos(Phi0), _en); } else { if (secant) { _n = (cosphi - Math.Cos(_phi2)) / (_phi2 - _phi1); } _c = _phi1 + Math.Cos(_phi1) / _n; _rho0 = _c - Phi0; } }
/// <summary> /// Performs the inverse transfrom from a single coordinate of linear units to the same coordinate in geodetic units /// </summary> /// <param name="xy">The double linear input x and y values organized into a 1 dimensional array</param> /// <param name="lp">The double geodetic output lambda and phi values organized into a 1 dimensional array</param> protected override void EllipticalInverse(double[] xy, double[] lp) { double ph1 = Proj.InvMlfn(_m0 + xy[Y], Es, _en); _tn = Math.Tan(ph1); _t = _tn * _tn; _n = Math.Sin(ph1); _r = 1 / (1 - Es * _n * _n); _n = Math.Sqrt(_r); _r *= (1 - Es) * _n; _dd = xy[X] / _n; _d2 = _dd * _dd; lp[Phi] = ph1 - (_n * _tn / _r) * _d2 * (.5 - (1 + 3 * _t) * _d2 * C3); lp[Lambda] = _dd * (1 + _t * _d2 * (-C4 + (1 + 3 * _t) * _d2 * C5)) / Math.Cos(ph1); }
private void GuamInverse(double[] xy, double[] lp) { double t = 0; int i; double x2 = 0.5 * xy[X] * xy[X]; lp[Phi] = Phi0; for (i = 0; i < 3; ++i) { t = E * Math.Sin(lp[Phi]); lp[Phi] = Proj.InvMlfn(_M1 + xy[Y] - x2 * Math.Tan(lp[Phi]) * (t = Math.Sqrt(1 - t * t)), Es, _en); } lp[Lambda] = xy[X] * t / Math.Cos(lp[Phi]); }
/// <summary> /// The forward transform where the spheroidal model of the earth has a flattening factor, /// matching more closely with the oblique spheroid of the actual earth /// </summary> /// <param name="lp">The double values for geodetic lambda and phi organized into a one dimensional array</param> /// <param name="xy">The double values for linear x and y organized into a one dimensional array</param> protected override void EllipticalForward(double[] lp, double[] xy) { if (Math.Abs(lp[Phi]) <= TOL) { xy[X] = lp[Lambda]; xy[Y] = -_ml0; } else { double sp = Math.Sin(lp[Phi]); double cp; double ms = Math.Abs(cp = Math.Cos(lp[Phi])) > TOL?Proj.Msfn(sp, cp, Es) / sp : 0; xy[X] = ms * Math.Sin(lp[Lambda] *= sp); xy[Y] = (Proj.Mlfn(lp[Phi], sp, cp, _en) - _ml0) + ms * (1 - Math.Cos(lp[Lambda])); } }
/// <summary> /// The inverse transform from linear units to geodetic units /// </summary> /// <param name="xy">The double values for the input x and y values stored in an array</param> /// <param name="lp">The double values for the output lambda and phi values stored in an array</param> protected override void OnInverse(double[] xy, double[] lp) { xy[Y] /= _cY; double c = Math.Cos(lp[Phi] = _tanMode ? Math.Atan(xy[Y]) : Proj.Aasin(xy[Y])); lp[Phi] /= _cP; lp[Lambda] = xy[X] / (_cX * Math.Cos(lp[Phi] /= _cP)); if (_tanMode) { lp[Lambda] /= c * c; } else { lp[Lambda] *= c; } }
/// <summary> /// The forward transform from geodetic units to linear units /// </summary> /// <param name="lp">The array of lambda, phi coordinates</param> /// <param name="xy">The array of x, y coordinates</param> protected override void OnForward(double[] lp, double[] xy) { double[] p = new double[2]; lp[Phi] = (lp[Phi] - Phi0) * RadToSec5; p[R] = _tpsi[Ntpsi]; for (int i = Ntpsi - 1; i >= 0; i--) { p[R] = _tpsi[i] + lp[Phi] * p[R]; } p[R] *= lp[Phi]; p[I] = lp[Lambda]; p = Proj.Zpoly1(p, _bf, Nbf); xy[X] = p[I]; xy[Y] = p[R]; }
/// <summary> /// The forward transform from geodetic units to linear units /// </summary> /// <param name="lp">The array of lambda, phi coordinates</param> /// <param name="xy">The array of x, y coordinates</param> protected override void OnForward(double[] lp, double[] xy) { double ul, us; double vl = Math.Sin(_bl * lp[Lambda]); if (Math.Abs(Math.Abs(lp[Phi]) - Math.PI / 2) <= EPS10) { ul = lp[Phi] < 0 ? -_singam : _singam; us = _al * lp[Phi] / _bl; } else { double q = _el / (_ellips ? Math.Pow(Proj.Tsfn(lp[Phi], Math.Sin(lp[Phi]), E), _bl) : TSFN0(lp[Phi])); double s = .5 * (q - 1 / q); ul = 2 * (s * _singam - vl * _cosgam) / (q + 1 / q); double con = Math.Cos(_bl * lp[Lambda]); if (Math.Abs(con) >= Tol) { us = _al * Math.Atan((s * _cosgam + vl * _singam) / con) / _bl; if (con < 0) { us += Math.PI * _al / _bl; } } else { us = _al * _bl * lp[Lambda]; } } if (Math.Abs(Math.Abs(ul) - 1) <= EPS10) { throw new ProjectionException(20); } double vs = .5 * _al * Math.Log((1 - ul) / (1 + ul)) / _bl; us -= _u0; if (!_rot) { xy[X] = us; xy[Y] = vs; } else { xy[X] = vs * _cosrot + us * _sinrot; xy[Y] = us * _cosrot - vs * _sinrot; } }
/// <summary> /// The forward transform from geodetic units to linear units /// </summary> /// <param name="lp">The array of lambda, phi coordinates</param> /// <param name="xy">The array of x, y coordinates</param> protected override void OnForward(double[] lp, double[] xy) { double t, dl1, dl2; double sp = Math.Sin(lp[Phi]); double cp = Math.Cos(lp[Phi]); double z1 = Proj.Aacos(_sp1 * sp + _cp1 * cp * Math.Cos(dl1 = lp[Lambda] + _dlam2)); double z2 = Proj.Aacos(_sp2 * sp + _cp2 * cp * Math.Cos(dl2 = lp[Lambda] - _dlam2)); z1 *= z1; z2 *= z2; xy[X] = _r2z0 * (t = z1 - z2); t = _z02 - t; xy[Y] = _r2z0 * Proj.Asqrt(4 * _z02 * z2 - t * t); if ((_ccs * sp - cp * (_cs * Math.Sin(dl1) - _sc * Math.Sin(dl2))) < 0) { xy[Y] = -xy[Y]; } }
/// <summary> /// Performs the inverse transfrom from a single coordinate of linear units to the same coordinate in geodetic units /// </summary> /// <param name="xy">The double linear input x and y values organized into a 1 dimensional array</param> /// <param name="lp">The double geodetic output lambda and phi values organized into a 1 dimensional array</param> protected override void EllipticalInverse(double[] xy, double[] lp) { double s; if ((s = Math.Abs(lp[Phi] = Proj.InvMlfn(xy[Y], Es, _en))) < HalfPi) { s = Math.Sin(lp[Phi]); lp[Lambda] = xy[X] * Math.Sqrt(1 - Es * s * s) / Math.Cos(lp[Phi]); } else if ((s - EPS10) < HalfPi) { lp[Lambda] = 0; } else { throw new ProjectionException(20); } }
/// <summary> /// Performs the inverse transform from a single coordinate of linear units to the same coordinate in geodetic lambda and /// phi units in the special case where the shape of the earth is being approximated as a perfect sphere. /// </summary> /// <param name="xy">The double linear input x and y values organized into a 1 dimensional array</param> /// <param name="lp">The double geodetic output lambda and phi values organized into a 1 dimensional array</param> protected override void SphericalInverse(double[] xy, double[] lp) { double rh = Proj.Hypot(xy[X], xy[Y] = _cphi1 - xy[Y]); lp[Phi] = _cphi1 + _phi1 - rh; if (Math.Abs(lp[Phi]) > HalfPi) { throw new ProjectionException(20); } if (Math.Abs(Math.Abs(lp[Phi]) - HalfPi) <= EPS10) { lp[Lambda] = 0; } else { lp[Lambda] = rh * Math.Atan2(xy[X], xy[Y]) / Math.Cos(lp[Phi]); } }
/// <summary> /// Initializes the transform using the parameters from the specified coordinate system information /// </summary> /// <param name="projInfo">A ProjectionInfo class contains all the standard and custom parameters needed to initialize this transform</param> protected override void OnInit(ProjectionInfo projInfo) { double phip0; _hlfE = 0.5 * E; double cp = Math.Cos(Phi0); cp *= cp; _c = Math.Sqrt(1 + Es * cp * cp * ROneEs); double sp = Math.Sin(Phi0); _cosp0 = Math.Cos(phip0 = Proj.Aasin(_sinp0 = sp / _c)); sp *= E; _k = Math.Log(Math.Tan(FortPi + 0.5 * phip0)) - _c * ( Math.Log(Math.Tan(FortPi + 0.5 * Phi0)) - _hlfE * Math.Log((1 + sp) / (1 - sp))); _kR = K0 * Math.Sqrt(OneEs) / (1 - sp * sp); }
/// <summary> /// Performs the inverse transfrom from a single coordinate of linear units to the same coordinate in geodetic units /// </summary> /// <param name="xy">The double linear input x and y values organized into a 1 dimensional array</param> /// <param name="lp">The double geodetic output lambda and phi values organized into a 1 dimensional array</param> protected override void EllipticalInverse(double[] xy, double[] lp) { xy[Y] += _ml0; if (Math.Abs(xy[Y]) <= TOL) { lp[Lambda] = xy[X]; lp[Phi] = 0; } else { double c; int i; double r = xy[Y] * xy[Y] + xy[X] * xy[X]; for (lp[Phi] = xy[Y], i = I_ITER; i > 0; --i) { double sp = Math.Sin(lp[Phi]); double cp; double s2ph = sp * (cp = Math.Cos(lp[Phi])); if (Math.Abs(cp) < ITOL) { throw new ProjectionException(20); } double mlp; c = sp * (mlp = Math.Sqrt(1 - Es * sp * sp)) / cp; double ml = Proj.Mlfn(lp[Phi], sp, cp, _en); double mlb = ml * ml + r; mlp = OneEs / (mlp * mlp * mlp); double dPhi; lp[Phi] += (dPhi = (ml + ml + c * mlb - 2 * xy[Y] * (c * ml + 1)) / (Es * s2ph * (mlb - 2 * xy[Y] * ml) / c + 2 * (xy[Y] - ml) * (c * mlp - 1 / s2ph) - mlp - mlp)); if (Math.Abs(dPhi) <= ITOL) { break; } } if (i == 0) { throw new ProjectionException(20); } c = Math.Sin(lp[Phi]); lp[Lambda] = Math.Asin(xy[X] * Math.Tan(lp[Phi]) * Math.Sqrt(1 - Es * c * c)) / Math.Sin(lp[Phi]); } }
/// <summary> /// The forward transform where the spheroidal model of the earth has a flattening factor, /// matching more closely with the oblique spheroid of the actual earth /// </summary> /// <param name="lp">The double values for geodetic lambda and phi organized into a one dimensional array</param> /// <param name="xy">The double values for linear x and y organized into a one dimensional array</param> protected override void EllipticalForward(double[] lp, double[] xy) { double sinX = 0.0, cosX = 0.0; double coslam = Math.Cos(lp[Lambda]); double sinlam = Math.Sin(lp[Lambda]); double sinphi = Math.Sin(lp[Phi]); if (_mode == Modes.Oblique || _mode == Modes.Equitorial) { double x; sinX = Math.Sin(x = 2 * Math.Atan(Ssfn(lp[Phi], sinphi, E)) - HalfPi); cosX = Math.Cos(x); } if (_mode == Modes.Oblique || _mode == Modes.Equitorial) { double a; if (_mode == Modes.Oblique) { a = _akm1 / (_cosX1 * (1 + _sinX1 * sinX + _cosX1 * cosX * coslam)); xy[Y] = a * (_cosX1 * sinX - _sinX1 * cosX * coslam); } else { a = 2 * _akm1 / (1 + cosX * coslam); xy[Y] = a * sinX; } xy[X] = a * cosX; } else { if (_mode == Modes.SouthPole) { lp[Phi] = -lp[Phi]; coslam = -coslam; sinphi = -sinphi; } xy[X] = _akm1 * Proj.Tsfn(lp[Phi], sinphi, E); xy[Y] = -xy[X] * coslam; } xy[X] = xy[X] * sinlam; }
/// <summary> /// The inverse transform from linear units to geodetic units /// </summary> /// <param name="xy">The double values for the input x and y values stored in an array</param> /// <param name="lp">The double values for the output lambda and phi values stored in an array</param> protected override void OnInverse(double[] xy, double[] lp) { double us, vs; if (!_rot) { us = xy[X]; vs = xy[Y]; } else { vs = xy[X] * _cosrot - xy[Y] * _sinrot; us = xy[Y] * _cosrot + xy[X] * _sinrot; } us += _u0; double q = Math.Exp(-_bl * vs / _al); double s = .5 * (q - 1 / q); double vl = Math.Sin(_bl * us / _al); double ul = 2 * (vl * _cosgam + s * _singam) / (q + 1 / q); if (Math.Abs(Math.Abs(ul) - 1) < EPS10) { lp[Lambda] = 0; lp[Phi] = ul < 0 ? -HalfPi : HalfPi; } else { lp[Phi] = _el / Math.Sqrt((1 + ul) / (1 - ul)); if (_ellips) { if ((lp[Phi] = Proj.Phi2(Math.Pow(lp[Phi], 1 / _bl), E)) == double.MaxValue) { throw new ProjectionException(20); } } else { lp[Phi] = HalfPi - 2 * Math.Atan(lp[Phi]); } lp[Lambda] = -Math.Atan2((s * _cosgam - vl * _singam), Math.Cos(_bl * us / _al)) / _bl; } }
/// <summary> /// Performs the inverse transform from a single coordinate of linear units to the same coordinate in geodetic lambda and /// phi units in the special case where the shape of the earth is being approximated as a perfect sphere. /// </summary> /// <param name="xy">The double linear input x and y values organized into a 1 dimensional array</param> /// <param name="lp">The double geodetic output lambda and phi values organized into a 1 dimensional array</param> protected override void SphericalInverse(double[] xy, double[] lp) { double cosz = 0, sinz = 0; double x = xy[X]; double y = xy[Y]; double rh = Proj.Hypot(x, y); if ((lp[Phi] = rh * .5) > 1) { throw new ProjectionException(20); } lp[Phi] = 2 * Math.Asin(lp[Phi]); if (_mode == Modes.Oblique || _mode == Modes.Equitorial) { sinz = Math.Sin(lp[Phi]); cosz = Math.Cos(lp[Phi]); } switch (_mode) { case Modes.Equitorial: lp[Phi] = Math.Abs(rh) <= EPS10 ? 0 : Math.Asin(y * sinz / rh); x *= sinz; y = cosz * rh; break; case Modes.Oblique: lp[Phi] = Math.Abs(rh) <= EPS10 ? Phi0 : Math.Asin(cosz * _sinb1 + y * sinz * _sinb1 / rh); x *= sinz * _cosb1; y = (cosz - Math.Sin(lp[Phi]) * _sinb1) * rh; break; case Modes.NorthPole: y = -y; lp[Phi] = HalfPi - lp[Phi]; break; case Modes.SouthPole: lp[Phi] -= HalfPi; break; } lp[Lambda] = (y == 0 && (_mode == Modes.Equitorial || _mode == Modes.Oblique)) ? 0 : Math.Atan2(x, y); }
/// <summary> /// The inverse transform from linear units to geodetic units /// </summary> /// <param name="xy">The double values for the input x and y values stored in an array</param> /// <param name="lp">The double values for the output lambda and phi values stored in an array</param> protected override void OnInverse(double[] xy, double[] lp) { if ((_rho = Proj.Hypot(xy[X], xy[Y] = _rho0 - xy[Y])) != 0.0) { if (_n < 0) { _rho = -_rho; xy[X] = -xy[X]; xy[Y] = -xy[Y]; } lp[Phi] = _rho / _dd; if (IsElliptical) { lp[Phi] = (_c - lp[Phi] * lp[Phi]) / _n; if (Math.Abs(_ec - Math.Abs(lp[Phi])) > TOL7) { if ((lp[Phi] = PhiFn(lp[Phi], E, OneEs)) == double.MaxValue) { throw new ProjectionException(20); } } else { lp[Phi] = lp[Phi] < 0 ? -HalfPi : HalfPi; } } else if (Math.Abs(lp[Phi] = (_c - lp[Phi] * lp[Phi]) / _n2) <= 1) { lp[Phi] = Math.Asin(lp[Phi]); } else { lp[Phi] = lp[Phi] < 0 ? -HalfPi : HalfPi; } lp[Lambda] = Math.Atan2(xy[X], xy[Y]) / _n; } else { lp[Lambda] = 0; lp[Phi] = _n > 0? HalfPi : -HalfPi; } }
/// <summary> /// Special factor calculations for a factors calculation /// </summary> /// <param name="lp">lambda-phi</param> /// <param name="p">The projection</param> /// <param name="fac">The Factors</param> protected override void OnSpecial(double[] lp, ProjectionInfo p, Factors fac) { if (Math.Abs(Math.Abs(lp[Phi]) - HalfPi) < EPS10) { if ((lp[Phi] * _n) <= 0) { return; } _rho = 0; } else { _rho = _c * (_ellipse ? Math.Pow(Proj.Tsfn(lp[Phi], Math.Sin(lp[Phi]), p.GeographicInfo.Datum.Spheroid.Eccentricity()), _n) : Math.Pow(Math.Tan(Math.PI / 4 + .5 * lp[Phi]), -_n)); } fac.code = AnalyticModes.IsAnalHK | AnalyticModes.IsAnalConv; fac.k = fac.h = p.ScaleFactor * _n * _rho / Proj.Msfn(Math.Sin(lp[Phi]), Math.Cos(lp[Phi]), p.GeographicInfo.Datum.Spheroid.EccentricitySquared()); fac.conv = -_n * lp[Lambda]; }
/// <summary> /// The inverse transform from linear units to geodetic units /// </summary> /// <param name="xy">The double values for the input x and y values stored in an array</param> /// <param name="lp">The double values for the output lambda and phi values stored in an array</param> protected override void OnInverse(double[] xy, double[] lp) { double cz1 = Math.Cos(Proj.Hypot(xy[Y], xy[X] + _hz0)); double cz2 = Math.Cos(Proj.Hypot(xy[Y], xy[X] - _hz0)); double s = cz1 + cz2; double d = cz1 - cz2; lp[Lambda] = -Math.Atan2(d, (s * _thz0)); lp[Phi] = Proj.Aacos(Proj.Hypot(_thz0 * s, d) * _rhshz0); if (xy[Y] < 0) { lp[Phi] = -lp[Phi]; } /* lam--phi now in system relative to P1--P2 base equator */ double sp = Math.Sin(lp[Phi]); double cp = Math.Cos(lp[Phi]); lp[Phi] = Proj.Aasin(_sa * sp + _ca * cp * (s = Math.Cos(lp[Lambda] -= _lp))); lp[Lambda] = Math.Atan2(cp * Math.Sin(lp[Lambda]), _sa * cp * s - _ca * sp) + _lamc; }
/// <summary> /// Internal code handling the setup operations for the transform /// </summary> protected void Setup() { double sinphi; if (Math.Abs(_phi1 + _phi2) < EPS10) { throw new ProjectionException(-21); } _n = sinphi = Math.Sin(_phi1); double cosphi = Math.Cos(_phi1); bool secant = Math.Abs(_phi1 - _phi2) >= EPS10; if (IsElliptical) { double m1 = Proj.Msfn(sinphi, cosphi, Es); double ml1 = Proj.Qsfn(sinphi, E, OneEs); if (secant) { /* secant cone */ sinphi = Math.Sin(_phi2); cosphi = Math.Cos(_phi2); double m2 = Proj.Msfn(sinphi, cosphi, Es); double ml2 = Proj.Qsfn(sinphi, E, OneEs); _n = (m1 * m1 - m2 * m2) / (ml2 - ml1); } _ec = 1 - .5 * OneEs * Math.Log((1 - E) / (1 + E)) / E; _c = m1 * m1 + _n * ml1; _dd = 1 / _n; _rho0 = _dd * Math.Sqrt(_c - _n * Proj.Qsfn(Math.Sin(Phi0), E, OneEs)); } else { if (secant) { _n = .5 * (_n + Math.Sin(_phi2)); } _n2 = _n + _n; _c = cosphi * cosphi + _n2 * sinphi; _dd = 1 / _n; _rho0 = _dd * Math.Sqrt(_c - _n2 * Math.Sin(Phi0)); } }
/// <summary> /// Performs the inverse transfrom from a single coordinate of linear units to the same coordinate in geodetic units /// </summary> /// <param name="xy">The double linear input x and y values organized into a 1 dimensional array</param> /// <param name="lp">The double geodetic output lambda and phi values organized into a 1 dimensional array</param> protected override void EllipticalInverse(double[] xy, double[] lp) { double s; double rh = Proj.Hypot(xy[X], xy[Y] = _am1 - xy[Y]); lp[Phi] = Proj.InvMlfn(_am1 + _m1 - rh, Es, _en); if ((s = Math.Abs(lp[Phi])) < HalfPi) { s = Math.Sin(lp[Phi]); lp[Lambda] = rh * Math.Atan2(xy[X], xy[Y]) * Math.Sqrt(1 - Es * s * s) / Math.Cos(lp[Phi]); } else if (Math.Abs(s - HalfPi) <= EPS10) { lp[Lambda] = 0; } else { throw new ProjectionException(20); } }
/// <summary> /// Initializes the transform using the parameters from the specified coordinate system information /// </summary> /// <param name="projInfo">A ProjectionInfo class contains all the standard and custom parameters needed to initialize this transform</param> protected override void OnInit(ProjectionInfo projInfo) { double pp; /* get control point locations */ double phi1 = projInfo.GetPhi1(); double lam1 = projInfo.GetLam1(); double phi2 = projInfo.GetPhi2(); double lam2 = projInfo.GetLam2(); if (phi1 == phi2 && lam1 == lam2) { throw new ProjectionException(-25); } Lam0 = Proj.Adjlon(0.5 * (lam1 + lam2)); _dlam2 = Proj.Adjlon(lam2 - lam1); _cp1 = Math.Cos(phi1); _cp2 = Math.Cos(phi2); _sp1 = Math.Sin(phi1); _sp2 = Math.Sin(phi2); _cs = _cp1 * _sp2; _sc = _sp1 * _cp2; _ccs = _cp1 * _cp2 * Math.Sin(_dlam2); _z02 = Proj.Aacos(_sp1 * _sp2 + _cp1 * _cp2 * Math.Cos(_dlam2)); _hz0 = .5 * _z02; double A12 = Math.Atan2(_cp2 * Math.Sin(_dlam2), _cp1 * _sp2 - _sp1 * _cp2 * Math.Cos(_dlam2)); _ca = Math.Cos(pp = Proj.Aasin(_cp1 * Math.Sin(A12))); _sa = Math.Sin(pp); _lp = Proj.Adjlon(Math.Atan2(_cp1 * Math.Cos(A12), _sp1) - _hz0); _dlam2 *= .5; _lamc = HalfPi - Math.Atan2(Math.Sin(A12) * _sp1, Math.Cos(A12)) - _dlam2; _thz0 = Math.Tan(_hz0); _rhshz0 = .5 / Math.Sin(_hz0); _r2z0 = 0.5 / _z02; _z02 *= _z02; }
/// <summary> /// The forward transform in the special case where there is no flattening of the spherical model of the earth. /// </summary> /// <param name="lp">The input lambda and phi geodetic values organized in an array</param> /// <param name="xy">The output x and y values organized in an array</param> protected override void SphericalForward(double[] lp, double[] xy) { /* Calculation of the three components of the vector from satellite to ** position on earth surface (lon,lat).*/ double tmp = Math.Cos(lp[Phi]); double vx = Math.Cos(lp[Lambda]) * tmp; double vy = Math.Sin(lp[Lambda]) * tmp; double vz = Math.Sin(lp[Phi]); /* Check visibility.*/ if (((_radiusG - vx) * vx - vy * vy - vz * vz) < 0) { xy[X] = double.NaN; xy[Y] = double.NaN; //throw new ProjectionException(20); return; } /* Calculation based on view angles from satellite.*/ tmp = _radiusG - vx; xy[X] = _radiusG1 * Math.Atan(vy / tmp); xy[Y] = _radiusG1 * Math.Atan(vz / Proj.Hypot(vy, tmp)); }
/// <summary> /// The inverse transform from linear units to geodetic units /// </summary> /// <param name="xy">The double values for the input x and y values stored in an array</param> /// <param name="lp">The double values for the output lambda and phi values stored in an array</param> protected override void OnInverse(double[] xy, double[] lp) { if ((_rho = Proj.Hypot(xy[X], xy[Y] = _rho0 - xy[Y])) != 0.0) { if (_n < 0) { _rho = -_rho; xy[X] = -xy[X]; xy[Y] = -xy[Y]; } lp[Phi] = _c - _rho; if (IsElliptical) { lp[Phi] = Proj.InvMlfn(lp[Phi], Es, _en); } lp[Lambda] = Math.Atan2(xy[X], xy[Y]) / _n; } else { lp[Lambda] = 0; lp[Phi] = _n > 0 ? HalfPi : -HalfPi; } }
/// <summary> /// Initializes the transform using the parameters from the specified coordinate system information /// </summary> /// <param name="projInfo">A ProjectionInfo class contains all the standard and custom parameters needed to initialize this transform</param> protected override void OnInit(ProjectionInfo projInfo) { double t = 0; if (projInfo.StandardParallel1 != null) { t = projInfo.StandardParallel1.Value * Math.PI / 180; } t = projInfo.ParamD("lat_ts") * Math.PI / 180; if ((K0 = Math.Cos(t)) < 0) { throw new ProjectionException(-24); } if (!IsElliptical) { return; } t = Math.Sin(t); K0 /= Math.Sqrt(1 - Es * t * t); E = Math.Sqrt(Es); _apa = Proj.Authset(Es); _qp = Proj.Qsfn(1, E, OneEs); }
/// <summary> /// The inverse transform from linear units to geodetic units /// </summary> /// <param name="xy">The double values for the input x and y values stored in an array</param> /// <param name="lp">The double values for the output lambda and phi values stored in an array</param> protected override void OnInverse(double[] xy, double[] lp) { int nn; double[] p = new double[2]; double[] dp = new double[2]; p[R] = xy[Y]; p[I] = xy[X]; for (nn = 20; nn > 0; --nn) { double[] fp; double[] f = Proj.Zpolyd1(p, _bf, Nbf, out fp); f[R] -= xy[Y]; f[I] -= xy[X]; double den = fp[R] * fp[R] + fp[I] * fp[I]; p[R] += dp[R] = -(f[R] * fp[R] + f[I] * fp[I]) / den; p[I] += dp[I] = -(f[I] * fp[R] - f[R] * fp[I]) / den; if ((Math.Abs(dp[R]) + Math.Abs(dp[I])) <= EPS10) { break; } } if (nn > 0) { lp[Lambda] = p[I]; lp[Phi] = _tphi[Ntphi]; for (int i = Ntphi - 1; i > 0; i++) { lp[Phi] = _tphi[i] + p[R] * lp[Phi]; } lp[Phi] = Phi0 + p[R] * lp[Phi] * Sec5ToRad; } else { lp[Lambda] = lp[Phi] = double.MaxValue; } }
/// <summary> /// The inverse transform from linear units to geodetic units /// </summary> /// <param name="xy">The double values for the input x and y values stored in an array</param> /// <param name="lp">The double values for the output lambda and phi values stored in an array</param> protected override void OnInverse(double[] xy, double[] lp) { double rho; xy[X] /= K0; xy[Y] /= K0; if ((rho = Proj.Hypot(xy[X], xy[Y])) > 0) { double c = 2 * Math.Atan2(rho, _r2); double sinc = Math.Sin(c); double cosc = Math.Cos(c); lp[Phi] = Math.Asin(cosc * _sinc0 + xy[Y] * sinc * _cosc0 / rho); lp[Lambda] = Math.Atan2(xy[X] * sinc, rho * _cosc0 * cosc - xy[Y] * _sinc0 * sinc); } else { lp[Phi] = _phic0; lp[Lambda] = 0; } double[] temp = _gauss.Inverse(lp); lp[Phi] = temp[Phi]; lp[Lambda] = temp[Lambda]; }