private void LineInit(Geodesic g, double lat1, double lon1, double azi1, double salp1, double calp1, int caps) { _a = g._a; _f = g._f; _b = g._b; _c2 = g._c2; _f1 = g._f1; // Always allow latitude and azimuth and unrolling the longitude _caps = caps | GeodesicMask.LATITUDE | GeodesicMask.AZIMUTH | GeodesicMask.LONG_UNROLL; _lat1 = GeoMath.LatFix(lat1); _lon1 = lon1; _azi1 = azi1; _salp1 = salp1; _calp1 = calp1; double cbet1, sbet1; { Pair p = GeoMath.Sincosd(GeoMath.AngRound(_lat1)); sbet1 = _f1 * p.First; cbet1 = p.Second; } // Ensure cbet1 = +epsilon at poles { Pair p = GeoMath.Norm(sbet1, cbet1); sbet1 = p.First; cbet1 = Math.Max(Geodesic.tiny_, p.Second); } _dn1 = Math.Sqrt(1 + g._ep2 * GeoMath.Sq(sbet1)); // Evaluate alp0 from sin(alp1) * cos(bet1) = sin(alp0), _salp0 = _salp1 * cbet1; // alp0 in [0, pi/2 - |bet1|] // Alt: calp0 = hypot(sbet1, calp1 * cbet1). The following // is slightly better (consider the case salp1 = 0). _calp0 = GeoMath.Hypot(_calp1, _salp1 * sbet1); // Evaluate sig with tan(bet1) = tan(sig1) * cos(alp1). // sig = 0 is nearest northward crossing of equator. // With bet1 = 0, alp1 = pi/2, we have sig1 = 0 (equatorial line). // With bet1 = pi/2, alp1 = -pi, sig1 = pi/2 // With bet1 = -pi/2, alp1 = 0 , sig1 = -pi/2 // Evaluate omg1 with tan(omg1) = sin(alp0) * tan(sig1). // With alp0 in (0, pi/2], quadrants for sig and omg coincide. // No atan2(0,0) ambiguity at poles since cbet1 = +epsilon. // With alp0 = 0, omg1 = 0 for alp1 = 0, omg1 = pi for alp1 = pi. _ssig1 = sbet1; _somg1 = _salp0 * sbet1; _csig1 = _comg1 = sbet1 != 0 || _calp1 != 0 ? cbet1 * _calp1 : 1; { Pair p = GeoMath.Norm(_ssig1, _csig1); _ssig1 = p.First; _csig1 = p.Second; } // sig1 in (-pi, pi] // GeoMath.norm(_somg1, _comg1); -- don't need to normalize! _k2 = GeoMath.Sq(_calp0) * g._ep2; double eps = _k2 / (2 * (1 + Math.Sqrt(1 + _k2)) + _k2); if ((_caps & GeodesicMask.CAP_C1) != 0) { _A1m1 = Geodesic.A1m1f(eps); _C1a = new double[nC1_ + 1]; Geodesic.C1f(eps, _C1a); _B11 = Geodesic.SinCosSeries(true, _ssig1, _csig1, _C1a); double s = Math.Sin(_B11), c = Math.Cos(_B11); // tau1 = sig1 + B11 _stau1 = _ssig1 * c + _csig1 * s; _ctau1 = _csig1 * c - _ssig1 * s; // Not necessary because C1pa reverts C1a // _B11 = -SinCosSeries(true, _stau1, _ctau1, _C1pa, nC1p_); } if ((_caps & GeodesicMask.CAP_C1p) != 0) { _C1pa = new double[nC1p_ + 1]; Geodesic.C1pf(eps, _C1pa); } if ((_caps & GeodesicMask.CAP_C2) != 0) { _C2a = new double[nC2_ + 1]; _A2m1 = Geodesic.A2m1f(eps); Geodesic.C2f(eps, _C2a); _B21 = Geodesic.SinCosSeries(true, _ssig1, _csig1, _C2a); } if ((_caps & GeodesicMask.CAP_C3) != 0) { _C3a = new double[nC3_]; g.C3f(eps, _C3a); _A3c = -_f *_salp0 *g.A3f(eps); _B31 = Geodesic.SinCosSeries(true, _ssig1, _csig1, _C3a); } if ((_caps & GeodesicMask.CAP_C4) != 0) { _C4a = new double[nC4_]; g.C4f(eps, _C4a); // Multiplier = a^2 * e^2 * cos(alpha0) * sin(alpha0) _A4 = GeoMath.Sq(_a) * _calp0 * _salp0 * g._e2; _B41 = Geodesic.SinCosSeries(false, _ssig1, _csig1, _C4a); } }