예제 #1
0
        /// <summary>
        /// Initialize a geod_geodesicline object.
        /// </summary>
        /// <param name="g">The <see cref="geod_geodesic"/> object specifying the ellipsoid.</param>
        /// <param name="lat1">Latitude of point 1 (degrees).</param>
        /// <param name="lon1">Longitude of point 1 (degrees).</param>
        /// <param name="azi1">Azimuth at point 1 (degrees).</param>
        /// <param name="caps">Bitor'ed combination of <see cref="geod_mask"/> values. See remarks for more informations.</param>
        /// <remarks>
        /// <paramref name="caps"/> bitor'ed combination of geod_mask() values specifying
        /// the capabilities the geod_geodesicline object should possess, i.e., which
        /// quantities can be returned in calls to geod_position() and
        /// geod_genposition().
        ///
        /// <paramref name="lat1"/> should be in the range [-90deg, 90deg].
        /// <paramref name="lon1"/> and <paramref name="azi1"/> should be in the range [-540deg, 540deg).
        ///
        /// The geod_mask values are:
        /// - caps|=GEOD_LATITUDE for the latitude lat2; this is added automatically,
        /// - caps|=GEOD_LONGITUDE for the latitude lon2,
        /// - caps|=GEOD_AZIMUTH for the latitude azi2; this is added automatically,
        /// - caps|=GEOD_DISTANCE for the distance s12,
        /// - caps|=GEOD_REDUCEDLENGTH for the reduced length m12,
        /// - caps|=GEOD_GEODESICSCALE for the geodesic scales M12 and M21,
        /// - caps|=GEOD_AREA for the area S12,
        /// - caps|=GEOD_DISTANCE_IN permits the length of the
        ///   geodesic to be given in terms of s12; without this capability the
        ///   length can only be specified in terms of arc length.
        ///
        /// A value of caps=0 is treated as GEOD.LATITUDE|GEOD.LONGITUDE|GEOD.AZIMUTH|GEOD.DISTANCE_IN
        /// (to support the solution of the "standard" direct problem).
        /// </remarks>
        public geod_geodesicline(geod_geodesic g, double lat1, double lon1, double azi1, GEOD caps)
        {
            a  = g.a;
            f  = g.f;
            b  = g.b;
            c2 = g.c2;
            f1 = g.f1;

            // If caps is 0 assume the standard direct calculation
            this.caps = (caps != 0?caps:GEOD.DISTANCE_IN | GEOD.LONGITUDE) |
                        GEOD.LATITUDE | GEOD.AZIMUTH | GEOD.LONG_UNROLL;     // always allow latitude and azimuth and unrolling of longitude

            this.lat1 = lat1;
            this.lon1 = lon1;

            // Guard against underflow in salp0
            this.azi1 = AngRound(AngNormalize(azi1));

            // alp1 is in [0, pi]
            double alp1 = this.azi1 * degree;

            // Enforce sin(pi)==0 and cos(pi/2)==0. Better to face the ensuing
            // problems directly than to skirt them.
            salp1 = this.azi1 == -180?0:Math.Sin(alp1);
            calp1 = Math.Abs(this.azi1) == 90?0:Math.Cos(alp1);
            double phi = lat1 * degree;

            // Ensure cbet1=+epsilon at poles
            double sbet1 = f1 * Math.Sin(phi);
            double cbet1 = Math.Abs(lat1) == 90?tiny:Math.Cos(phi);

            norm2(ref sbet1, ref cbet1);
            dn1 = Math.Sqrt(1 + g.ep2 * 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 = hypotx(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;
            norm2(ref ssig1, ref csig1);             // sig1 in (-pi, pi]
            // norm2(ref somg1, ref comg1); -- don't need to normalize!

            k2 = sq(calp0) * g.ep2;
            double eps = k2 / (2 * (1 + Math.Sqrt(1 + k2)) + k2);

            if ((this.caps & GEOD.CAP_C1) != 0)
            {
                double s, c;
                A1m1 = geod_geodesic.A1m1f(eps);
                geod_geodesic.C1f(eps, C1a);
                B11 = SinCosSeries(true, ssig1, csig1, C1a, nC1);
                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 ((this.caps & GEOD.CAP_C1p) != 0)
            {
                geod_geodesic.C1pf(eps, C1pa);
            }

            if ((this.caps & GEOD.CAP_C2) != 0)
            {
                A2m1 = geod_geodesic.A2m1f(eps);
                geod_geodesic.C2f(eps, C2a);
                B21 = SinCosSeries(true, ssig1, csig1, C2a, nC2);
            }

            if ((this.caps & GEOD.CAP_C3) != 0)
            {
                g.C3f(eps, C3a);
                A3c = -f *salp0 *g.A3f(eps);

                B31 = SinCosSeries(true, ssig1, csig1, C3a, nC3 - 1);
            }

            if ((this.caps & GEOD.CAP_C4) != 0)
            {
                g.C4f(eps, C4a);
                // Multiplier=a^2*e^2*cos(alpha0)*sin(alpha0)
                A4  = sq(a) * calp0 * salp0 * g.e2;
                B41 = SinCosSeries(false, ssig1, csig1, C4a, nC4);
            }
        }