예제 #1
0
        /// <summary>
        /// Subtracts corrections to ecliptical coordinates
        /// </summary>
        public static CrdsEcliptical operator -(CrdsEcliptical lhs, CrdsEcliptical rhs)
        {
            CrdsEcliptical ecl = new CrdsEcliptical();

            ecl.Lambda   = Angle.To360(lhs.Lambda - rhs.Lambda);
            ecl.Beta     = lhs.Beta - rhs.Beta;
            ecl.Distance = lhs.Distance;
            return(ecl);
        }
예제 #2
0
        /// <summary>
        /// Calculates the aberration effect for a celestial body (star or planet) for given instant.
        /// </summary>
        /// <param name="ecl">Ecliptical coordinates of the body (not corrected).</param>
        /// <param name="ae">Aberration elements needed for calculation of aberration correction.</param>
        /// <returns>Returns aberration correction values for ecliptical coordinates.</returns>
        /// <remarks>
        /// AA(II), formula 23.2
        /// </remarks>
        public static CrdsEcliptical AberrationEffect(CrdsEcliptical ecl, AberrationElements ae)
        {
            double thetaLambda = Angle.ToRadians(ae.lambda - ecl.Lambda);
            double piLambda    = Angle.ToRadians(ae.pi - ecl.Lambda);
            double beta        = Angle.ToRadians(ecl.Beta);

            double dLambda = (-k * Math.Cos(thetaLambda) + ae.e * k * Math.Cos(piLambda)) / Math.Cos(beta);
            double dBeta   = -k *Math.Sin(beta) * (Math.Sin(thetaLambda) - ae.e * Math.Sin(piLambda));

            return(new CrdsEcliptical(dLambda / 3600, dBeta / 3600));
        }
예제 #3
0
        /// <summary>
        /// Calculates appearance of Saturn rings
        /// </summary>
        /// <param name="jd">Julian date to calculate for</param>
        /// <param name="saturn">Heliocentric coordinates of Saturn.</param>
        /// <param name="earth">Heliocentric coordinates of Earth.</param>
        /// <param name="epsilon">True obliquity of ecliptic.</param>
        /// <returns>
        /// Appearance data for Saturn rings.
        /// </returns>
        /// <remarks>
        /// Method is taken from AA(II), chapter 45.
        /// </remarks>
        public static RingsAppearance SaturnRings(double jd, CrdsHeliocentrical saturn, CrdsHeliocentrical earth, double epsilon)
        {
            RingsAppearance rings = new RingsAppearance();
            double          T     = (jd - 2451545.0) / 36525.0;
            double          T2    = T * T;

            double i     = 28.075216 - 0.012998 * T + 0.000004 * T2;
            double Omega = 169.508470 + 1.394681 * T + 0.000412 * T2;

            double lambda0 = Omega - 90;
            double beta0   = 90 - i;

            i     = Angle.ToRadians(i);
            Omega = Angle.ToRadians(Omega);

            CrdsEcliptical ecl = saturn.ToRectangular(earth).ToEcliptical();

            double beta   = Angle.ToRadians(ecl.Beta);
            double lambda = Angle.ToRadians(ecl.Lambda);

            rings.B = Angle.ToDegrees(Math.Asin(Math.Sin(i) * Math.Cos(beta) * Math.Sin(lambda - Omega) - Math.Cos(i) * Math.Sin(beta)));
            rings.a = 375.35 / ecl.Distance;
            rings.b = rings.a * Math.Sin(Math.Abs(Angle.ToRadians(rings.B)));

            double N  = 113.6655 + 0.8771 * T;
            double l_ = Angle.ToRadians(saturn.L - 0.01759 / saturn.R);
            double b_ = Angle.ToRadians(saturn.B - 0.000764 * Math.Cos(Angle.ToRadians(saturn.L - N)) / saturn.R);

            double U1 = Angle.ToDegrees(Math.Atan((Math.Sin(i) * Math.Sin(b_) + Math.Cos(i) * Math.Cos(b_) * Math.Sin(l_ - Omega)) / (Math.Cos(b_) * Math.Cos(l_ - Omega))));
            double U2 = Angle.ToDegrees(Math.Atan((Math.Sin(i) * Math.Sin(beta) + Math.Cos(i) * Math.Cos(beta) * Math.Sin(lambda - Omega)) / (Math.Cos(beta) * Math.Cos(lambda - Omega))));

            rings.DeltaU = Math.Abs(U1 - U2);

            CrdsEcliptical eclPole = new CrdsEcliptical();

            eclPole.Set(lambda0, beta0);

            CrdsEquatorial eq     = ecl.ToEquatorial(epsilon);
            CrdsEquatorial eqPole = eclPole.ToEquatorial(epsilon);

            double alpha  = Angle.ToRadians(eq.Alpha);
            double delta  = Angle.ToRadians(eq.Delta);
            double alpha0 = Angle.ToRadians(eqPole.Alpha);
            double delta0 = Angle.ToRadians(eqPole.Delta);

            double y = Math.Cos(delta0) * Math.Sin(alpha0 - alpha);
            double x = Math.Sin(delta0) * Math.Cos(delta) - Math.Cos(delta0) * Math.Sin(delta) * Math.Cos(alpha0 - alpha);

            rings.P = Angle.ToDegrees(Math.Atan2(y, x));

            return(rings);
        }
예제 #4
0
        /// <summary>
        /// Calculates angular separation between two points with ecliptical coordinates
        /// </summary>
        /// <param name="p1">Ecliptical coordinates of the first point</param>
        /// <param name="p2">Ecliptical coordinates of the second point</param>
        /// <returns>Angular separation in degrees</returns>
        public static double Separation(CrdsEcliptical p1, CrdsEcliptical p2)
        {
            double a1 = ToRadians(p1.Beta);
            double a2 = ToRadians(p2.Beta);
            double A1 = p1.Lambda;
            double A2 = p2.Lambda;

            double a = Math.Acos(
                Math.Sin(a1) * Math.Sin(a2) +
                Math.Cos(a1) * Math.Cos(a2) * Math.Cos(ToRadians(A1 - A2)));

            return(double.IsNaN(a) ? 0 : ToDegrees(a));
        }
예제 #5
0
        /// <summary>
        /// Gets correction for ecliptical coordinates obtained by VSOP87 theory,
        /// needed for conversion to standard FK5 system.
        /// This correction should be used only for high-precision version of VSOP87.
        /// </summary>
        /// <param name="jde">Julian Ephemeris Day</param>
        /// <param name="ecl">Non-corrected ecliptical coordinates of the body.</param>
        /// <returns>Corrections values for longutude and latitude, in degrees.</returns>
        /// <remarks>
        /// AA(II), formula 32.3.
        /// </remarks>
        public static CrdsEcliptical CorrectionForFK5(double jde, CrdsEcliptical ecl)
        {
            double T = (jde - 2451545) / 36525.0;

            double L_ = Angle.ToRadians(ecl.Lambda - 1.397 * T - 0.00031 * T * T);

            double sinL_ = Math.Sin(L_);
            double cosL_ = Math.Cos(L_);

            double deltaL = -0.09033 + 0.03916 * (cosL_ + sinL_) * Math.Tan(Angle.ToRadians(ecl.Beta));
            double deltaB = 0.03916 * (cosL_ - sinL_);

            return(new CrdsEcliptical(deltaL / 3600, deltaB / 3600));
        }
예제 #6
0
 /// <summary>
 /// Gets ecliptical coordinates of Neptunian moon
 /// </summary>
 /// <param name="jd">Julian day of calculation</param>
 /// <param name="neptune">Ecliptical coordinates of Neptune for the specified date</param>
 /// <param name="index">Moon index, 1 = Triton, 2 = Nereid</param>
 /// <returns></returns>
 public static CrdsEcliptical Position(double jd, CrdsEcliptical neptune, int index)
 {
     if (index == 1)
     {
         return(TritonPosition(jd, neptune));
     }
     else if (index == 2)
     {
         return(NereidPosition(jd, neptune));
     }
     else
     {
         throw new ArgumentException("Incorrect moon index", nameof(index));
     }
 }
예제 #7
0
        /// <summary>
        /// Converts ecliptical coordinates to equatorial.
        /// </summary>
        /// <param name="ecl">Pair of ecliptical cooordinates.</param>
        /// <param name="epsilon">Obliquity of the ecliptic, in degrees.</param>
        /// <returns>Pair of equatorial coordinates.</returns>
        public static CrdsEquatorial ToEquatorial(this CrdsEcliptical ecl, double epsilon)
        {
            CrdsEquatorial eq = new CrdsEquatorial();

            epsilon = Angle.ToRadians(epsilon);
            double lambda = Angle.ToRadians(ecl.Lambda);
            double beta   = Angle.ToRadians(ecl.Beta);

            double Y = Math.Sin(lambda) * Math.Cos(epsilon) - Math.Tan(beta) * Math.Sin(epsilon);
            double X = Math.Cos(lambda);

            eq.Alpha = Angle.To360(Angle.ToDegrees(Math.Atan2(Y, X)));
            eq.Delta = Angle.ToDegrees(Math.Asin(Math.Sin(beta) * Math.Cos(epsilon) + Math.Cos(beta) * Math.Sin(epsilon) * Math.Sin(lambda)));

            return(eq);
        }
예제 #8
0
        /// <summary>
        /// Converts ecliptical coordinates to rectangular coordinates.
        /// </summary>
        /// <param name="ecl">Ecliptical coordinates</param>
        /// <param name="epsilon">Obliquity of the ecliptic, in degrees.</param>
        /// <returns>Rectangular coordinates.</returns>
        public static CrdsRectangular ToRectangular(this CrdsEcliptical ecl, double epsilon)
        {
            CrdsRectangular rect = new CrdsRectangular();

            double beta   = Angle.ToRadians(ecl.Beta);
            double lambda = Angle.ToRadians(ecl.Lambda);
            double R      = ecl.Distance;

            epsilon = Angle.ToRadians(epsilon);

            double cosBeta    = Math.Cos(beta);
            double sinBeta    = Math.Sin(beta);
            double sinLambda  = Math.Sin(lambda);
            double cosLambda  = Math.Cos(lambda);
            double sinEpsilon = Math.Sin(epsilon);
            double cosEpsilon = Math.Cos(epsilon);

            rect.X = R * cosBeta * cosLambda;
            rect.Y = R * (cosBeta * sinLambda * cosEpsilon - sinBeta * sinEpsilon);
            rect.Z = R * (cosBeta * sinLambda * sinEpsilon + sinBeta * cosEpsilon);
            return(rect);
        }
예제 #9
0
        /// <summary>
        /// Gets geocentric elongation angle of the celestial body
        /// </summary>
        /// <param name="sun">Ecliptical geocentrical coordinates of the Sun</param>
        /// <param name="body">Ecliptical geocentrical coordinates of the body</param>
        /// <returns>Geocentric elongation angle, in degrees, from -180 to 180.
        /// Negative sign means western elongation, positive eastern.
        /// </returns>
        /// <remarks>
        /// AA(II), formula 48.2
        /// </remarks>
        // TODO: tests
        public static double Elongation(CrdsEcliptical sun, CrdsEcliptical body)
        {
            double beta    = Angle.ToRadians(body.Beta);
            double lambda  = Angle.ToRadians(body.Lambda);
            double lambda0 = Angle.ToRadians(sun.Lambda);

            double s = sun.Lambda;
            double b = body.Lambda;

            if (Math.Abs(s - b) > 180)
            {
                if (s < b)
                {
                    s += 360;
                }
                else
                {
                    b += 360;
                }
            }

            return(Math.Sign(b - s) * Angle.ToDegrees(Math.Acos(Math.Cos(beta) * Math.Cos(lambda - lambda0))));
        }
예제 #10
0
        /// <summary>
        /// Converts ecliptical coordinates for one equinox to another one
        /// </summary>
        /// <param name="jd0">Initial epoch (can be J2000 = 2451545.0)</param>
        /// <param name="jd">Target (final) epoch </param>
        /// <returns>Returns ecliptical coordinates for the target epoch</returns>
        /// <remarks>Method is taken from AA(II), p. 134</remarks>
        private static CrdsEcliptical ConvertCoordinatesToEquinox(double jd0, double jd, CrdsEcliptical e0)
        {
            double T = (jd0 - 2451545.0) / 36525.0;
            double t = (jd - jd0) / 36525.0;

            double eta = (47.0029 - 0.06603 * T + 0.000598 * T * T) * t
                         + (-0.03302 + 0.000598 * T) * t * t + 0.000060 * t * t * t;

            eta /= 3600.0;

            double Pi = 3289.4789 * T + 0.60622 * T * T
                        - (869.8089 + 0.50491 * T) * t + 0.03536 * t * t;

            Pi /= 3600.0;
            Pi += 174.876384;

            double p = (5029.0966 + 2.22226 * T - 0.000042 * T * T) * t
                       + (1.11113 - 0.000042 * T) * t * t - 0.000006 * t * t * t;

            p /= 3600.0;

            double A_ = Cos(ToRadians(eta)) * Cos(ToRadians(e0.Beta)) * Sin(ToRadians(Pi - e0.Lambda)) - Sin(ToRadians(eta)) * Sin(ToRadians(e0.Beta));
            double B_ = Cos(ToRadians(e0.Beta)) * Cos(ToRadians(Pi - e0.Lambda));
            double C_ = Cos(ToRadians(eta)) * Sin(ToRadians(e0.Beta)) + Sin(ToRadians(eta)) * Cos(ToRadians(e0.Beta)) * Sin(ToRadians(Pi - e0.Lambda));

            CrdsEcliptical e = new CrdsEcliptical();

            e.Lambda = p + Pi - ToDegrees(Atan2(A_, B_));
            e.Lambda = To360(e.Lambda);

            e.Beta = ToDegrees(Asin(C_));

            e.Distance = e0.Distance;

            return(e);
        }
예제 #11
0
        /// <summary>
        /// Calculates ecliptical coordinates of Triton, largest moon of Neptune.
        /// </summary>
        /// <param name="jd">Julian Day of calculation</param>
        /// <param name="neptune">Ecliptical coordinates of Neptune for the Julian Day specified.</param>
        /// <returns>Ecliptical coordinates of Triton for specified date.</returns>
        /// <remarks>
        ///
        /// The method is based on following works:
        ///
        /// 1. Harris, A.W. (1984), "Physical Properties of Neptune and Triton Inferred from the Orbit of Triton" NASA CP-2330, pages 357-373:
        ///    http://articles.adsabs.harvard.edu/cgi-bin/nph-iarticle_query?1984NASCP2330..357H&defaultprint=YES&filetype=.pdf
        ///
        /// 2. Seidelmann, P. K.: Explanatory Supplement to The Astronomical Almanac,
        ///    University Science Book, Mill Valley (California), 1992,
        ///    Chapter 6 "Orbital Ephemerides and Rings of Satellites", page 373, 6.61-1 Triton
        ///    https://archive.org/download/131123ExplanatorySupplementAstronomicalAlmanac/131123-explanatory-supplement-astronomical-almanac.pdf
        ///
        /// </remarks>
        private static CrdsEcliptical TritonPosition(double jd, CrdsEcliptical neptune)
        {
            NutationElements ne      = Nutation.NutationElements(jd);
            double           epsilon = Date.TrueObliquity(jd, ne.deltaEpsilon);

            // convert current coordinates to J1950 epoch, as algorithm requires
            CrdsEquatorial       eq            = neptune.ToEquatorial(epsilon);
            PrecessionalElements pe1950        = Precession.ElementsFK5(jd, Date.EPOCH_J1950);
            CrdsEquatorial       eqNeptune1950 = Precession.GetEquatorialCoordinates(eq, pe1950);

            const double t0 = 2433282.5;       // 1.0 Jan 1950
            const double a  = 0.0023683;       // semimajor axis of Triton, in a.u.

            const double n       = 61.2588532; // nodal mean motion, degrees per day
            const double lambda0 = 200.913;    // longitude from ascending node through the invariable plane at epoch
            const double i       = 158.996;    // inclination of orbit to the invariable plane

            const double Omega0 = 151.401;     // angle from the intersection of invariable plane with the earth's
                                               // equatorial plane of 1950.0 to the ascending node
                                               // of the orbit through the invariable plane

            const double OmegaDot = 0.57806;   // nodal precision rate, degrees per year

            // Calculate J2000.0 RA and Declination of the pole of the invariable plane
            // These formulae are taken from the book:
            // Seidelmann, P. K.: Explanatory Supplement to The Astronomical Almanac,
            // University Science Book, Mill Valley (California), 1992,
            // Chapter 6 "Orbital Ephemerides and Rings of Satellites", page 373, 6.61-1 Triton
            double T  = (jd - 2451545.0) / 36525.0;
            double N  = ToRadians(359.28 + 54.308 * T);
            double ap = 298.72 + 2.58 * Sin(N) - 0.04 * Sin(2 * N);
            double dp = 42.63 - 1.90 * Cos(N) + 0.01 * Cos(2 * N);

            // Convert pole coordinates to J1950
            CrdsEquatorial eqPole1950 = Precession.GetEquatorialCoordinates(new CrdsEquatorial(ap, dp), pe1950);

            ap = eqPole1950.Alpha;
            dp = eqPole1950.Delta;

            // take light-time effect into account
            double tau = PlanetPositions.LightTimeEffect(neptune.Distance);

            double lambda = To360(lambda0 + n * (jd - t0 - tau));
            double omega  = Omega0 + OmegaDot * (jd - t0 - tau) / 365.25;

            // cartesian state vector of Triton
            var r =
                Matrix.R3(ToRadians(-ap - 90)) *
                Matrix.R1(ToRadians(dp - 90)) *
                Matrix.R3(ToRadians(-omega)) *
                Matrix.R1(ToRadians(-i)) *
                new Matrix(new[, ] {
                { a *Cos(ToRadians(lambda)) }, { a *Sin(ToRadians(lambda)) }, { 0 }
            });

            // normalize by distance to Neptune
            r.Values[0, 0] /= neptune.Distance;
            r.Values[1, 0] /= neptune.Distance;
            r.Values[2, 0] /= neptune.Distance;

            // offsets vector
            var d =
                Matrix.R2(ToRadians(-eqNeptune1950.Delta)) *
                Matrix.R3(ToRadians(eqNeptune1950.Alpha)) *
                r;

            // radial component, positive away from observer
            // converted to degrees
            double x = ToDegrees(d.Values[0, 0]);

            // semimajor axis, expressed in degrees, as visible from Earth
            double theta = ToDegrees(Atan(a / neptune.Distance));

            // offsets values in degrees
            double dAlphaCosDelta = ToDegrees(d.Values[1, 0]);
            double dDelta         = ToDegrees(d.Values[2, 0]);

            double delta  = eqNeptune1950.Delta + dDelta;
            double dAlpha = dAlphaCosDelta / Cos(ToRadians(eqNeptune1950.Delta));
            double alpha  = eqNeptune1950.Alpha + dAlpha;

            CrdsEquatorial eqTriton1950 = new CrdsEquatorial(alpha, delta);

            // convert J1950 equatorial coordinates to current epoch
            // and to ecliptical
            PrecessionalElements pe        = Precession.ElementsFK5(Date.EPOCH_J1950, jd);
            CrdsEquatorial       eqTriton  = Precession.GetEquatorialCoordinates(eqTriton1950, pe);
            CrdsEcliptical       eclTriton = eqTriton.ToEcliptical(epsilon);

            // calculate distance to Earth
            eclTriton.Distance = neptune.Distance + x / theta * a;

            return(eclTriton);
        }
예제 #12
0
        /// <summary>
        /// Calculates ecliptical coordinates of Nereid, the third-largest moon of Neptune.
        /// </summary>
        /// <param name="jd">Julian Day of calculation</param>
        /// <param name="neptune">Ecliptical coordinates of Neptune for the Julian Day specified.</param>
        /// <returns>Ecliptical coordinates of Nereid for specified date.</returns>
        /// <remarks>
        ///
        /// The method is based on work of F. Mignard (1981), "The Mean Elements of Nereid",
        /// The Astronomical Journal, Vol 86, Number 11, pages 1728-1729
        /// The work can be found by link: http://adsabs.harvard.edu/full/1981AJ.....86.1728M
        ///
        /// There are some changes from the original algorithm were made,
        /// to be compliant with ephemeris provided by Nasa JPL Horizons system (https://ssd.jpl.nasa.gov/?ephemerides):
        ///
        /// 1. Other value of mean motion (n) is used:
        ///    - original work : n = 0.999552
        ///    - implementation: n = 360.0 / 360.1362 (where 360.1362 is an orbital period)
        ///
        /// 2. Rotation around Z axis by angle OmegaN should by taken with NEGATIVE sign,
        ///    insted of POSITIVE sign in original work (possible typo?),
        ///    note the NEGATIVE sign for "Ne" angle (same meaning as "OmegaN" in original work) in the book:
        ///    Seidelmann, P. K.: Explanatory Supplement to The Astronomical Almanac,
        ///    University Science Book, Mill Valley (California), 1992,
        ///    Chapter 6 "Orbital Ephemerides and Rings of Satellites", page 376, formula 6.62-3
        ///
        /// </remarks>
        private static CrdsEcliptical NereidPosition(double jd, CrdsEcliptical neptune)
        {
            NutationElements ne      = Nutation.NutationElements(jd);
            double           epsilon = Date.TrueObliquity(jd, ne.deltaEpsilon);

            // convert current coordinates to J1950 epoch, as algorithm requires
            CrdsEquatorial       eq            = neptune.ToEquatorial(epsilon);
            PrecessionalElements pe1950        = Precession.ElementsFK5(jd, Date.EPOCH_J1950);
            CrdsEquatorial       eqNeptune1950 = Precession.GetEquatorialCoordinates(eq, pe1950);

            const double jd0 = 2433680.5;           // Initial Epoch: 3.0 Feb 1951

            const double a      = 0.036868;         // Semi-major axis, in a.u.
            const double e0     = 0.74515;          // Orbit eccentricity for jd0 epoch
            const double i0     = 10.041;           // Inclination of the orbit for jd0 epoch, in degrees
            const double Omega0 = 329.3;            // Longitude of the node of the orbit for jd0 epoch, in degrees
            const double M0     = 358.91;           // Mean anomaly for jd0 epoch, in degrees
            const double n      = 360.0 / 360.1362; // Mean motion, in degrees per day
            const double OmegaN = 3.552;            // Longitude of ascending node of the orbit of Neptune, for J1950.0 epoch, in degrees
            const double gamma  = 22.313;           // Inclination of the orbit of Neptune, for J1950.0 epoch, in degrees

            // take light-time effect into account
            double tau = PlanetPositions.LightTimeEffect(neptune.Distance);

            double t = jd - tau - jd0;          // in days
            double T = t / 36525.0;             // in Julian centuries

            double psi      = ToRadians(To360(282.9 + 2.68 * T));
            double twoTheta = ToRadians(To360(107.4 + 0.01196 * t));

            // Equation to found omega, argument of pericenter
            Func <double, double> omegaEquation = (om) => To360(282.9 + 2.68 * T - 19.25 * Sin(2 * psi) + 3.23 * Sin(4 * psi) - 0.725 * Sin(6 * psi) - 0.351 * Sin(twoTheta) - 0.7 * Sin(ToRadians(2 * om) - twoTheta)) - om;

            // Solve equation (find root: omega value)
            double omega = ToRadians(FindRoots(omegaEquation, 0, 360, 1e-8));

            // Find longitude of the node
            double Omega = Omega0 - 2.4 * T + 19.7 * Sin(2 * psi) - 3.3 * Sin(4 * psi) + 0.7 * Sin(6 * psi) + 0.357 * Sin(twoTheta) + 0.276 * Sin(2 * omega - twoTheta);

            // Find orbit eccentricity
            double e = e0 - 0.006 * Cos(2 * psi) + 0.0056 * Cos(2 * omega - twoTheta);

            // Find mean anomaly
            double M = To360(M0 + n * t - 0.38 * Sin(2 * psi) + 1.0 * Sin(2 * omega - twoTheta));

            // Find inclination
            double cosi = Cos(ToRadians(i0)) - 9.4e-3 * Cos(2 * psi);
            double i    = Acos(cosi);

            // Find eccentric anomaly by solving Kepler equation
            double E = SolveKepler(M, e);

            double X = a * (Cos(E) - e);
            double Y = a * Sqrt(1 - e * e) * Sin(E);

            Matrix d =
                Matrix.R2(ToRadians(-eqNeptune1950.Delta)) *
                Matrix.R3(ToRadians(eqNeptune1950.Alpha)) *
                Matrix.R3(ToRadians(-OmegaN)) *
                Matrix.R1(ToRadians(-gamma)) *
                Matrix.R3(ToRadians(-Omega)) *
                Matrix.R1(-i) *
                Matrix.R3(-omega) *
                new Matrix(new double[, ] {
                { X / neptune.Distance }, { Y / neptune.Distance }, { 0 }
            });

            // radial component, positive away from observer
            // converted to degrees
            double x = ToDegrees(d.Values[0, 0]);

            // offsets values in degrees
            double dAlphaCosDelta = ToDegrees(d.Values[1, 0]);
            double dDelta         = ToDegrees(d.Values[2, 0]);

            double delta  = eqNeptune1950.Delta + dDelta;
            double dAlpha = dAlphaCosDelta / Cos(ToRadians(eqNeptune1950.Delta));
            double alpha  = eqNeptune1950.Alpha + dAlpha;

            CrdsEquatorial eqNereid1950 = new CrdsEquatorial(alpha, delta);

            // convert J1950 equatorial coordinates to current epoch
            // and to ecliptical
            PrecessionalElements pe        = Precession.ElementsFK5(Date.EPOCH_J1950, jd);
            CrdsEquatorial       eqNereid  = Precession.GetEquatorialCoordinates(eqNereid1950, pe);
            CrdsEcliptical       eclNereid = eqNereid.ToEcliptical(epsilon);

            // semimajor axis, expressed in degrees, as visible from Earth
            double theta = ToDegrees(Atan(a / neptune.Distance));

            // calculate distance to Earth
            eclNereid.Distance = neptune.Distance + x / theta * a;

            return(eclNereid);
        }
예제 #13
0
        public static CrdsRectangular[] Positions(double jd, CrdsHeliocentrical earth, CrdsHeliocentrical mars)
        {
            CrdsRectangular[] moons = new CrdsRectangular[MOONS_COUNT];

            // Rectangular topocentrical coordinates of Mars
            CrdsRectangular rectMars = mars.ToRectangular(earth);

            // Ecliptical coordinates of Mars
            CrdsEcliptical eclMars = rectMars.ToEcliptical();

            // Distance from Earth to Mars, in AU
            double distanceMars = eclMars.Distance;

            // light-time effect
            double tau = PlanetPositions.LightTimeEffect(distanceMars);

            // ESAPHODEI model
            double t = jd - 2451545.0 + 6491.5 - tau;

            GenerateMarsSatToVSOP87(t, ref mars_sat_to_vsop87);

            // Get rectangular (Mars-reffered) coordinates of moons
            CrdsRectangular[] esaphodeiRect = new CrdsRectangular[MOONS_COUNT];

            for (int body = 0; body < MOONS_COUNT; body++)
            {
                MarsSatBody bp = mars_sat_bodies[body];

                double[] elem = new double[6];
                for (int n = 0; n < 6; n++)
                {
                    elem[n] = bp.constants[n];
                }

                for (int j = 0; j < 2; j++)
                {
                    for (int i = bp.lists[j].size - 1; i >= 0; i--)
                    {
                        double d = bp.lists[j].terms[i].phase + t * bp.lists[j].terms[i].frequency;
                        elem[j] += bp.lists[j].terms[i].amplitude * Cos(d);
                    }
                }

                for (int j = 2; j < 4; j++)
                {
                    for (int i = bp.lists[j].size - 1; i >= 0; i--)
                    {
                        double d = bp.lists[j].terms[i].phase + t * bp.lists[j].terms[i].frequency;
                        elem[2 * j - 2] += bp.lists[j].terms[i].amplitude * Cos(d);
                        elem[2 * j - 1] += bp.lists[j].terms[i].amplitude * Sin(d);
                    }
                }

                elem[1] += (bp.l + bp.acc * t) * t;

                double[] x = new double[3];
                EllipticToRectangularA(mars_sat_bodies[body].mu, elem, ref x);


                esaphodeiRect[body] = new CrdsRectangular();

                esaphodeiRect[body].X = mars_sat_to_vsop87[0] * x[0]
                                        + mars_sat_to_vsop87[1] * x[1]
                                        + mars_sat_to_vsop87[2] * x[2];
                esaphodeiRect[body].Y = mars_sat_to_vsop87[3] * x[0]
                                        + mars_sat_to_vsop87[4] * x[1]
                                        + mars_sat_to_vsop87[5] * x[2];
                esaphodeiRect[body].Z = mars_sat_to_vsop87[6] * x[0]
                                        + mars_sat_to_vsop87[7] * x[1]
                                        + mars_sat_to_vsop87[8] * x[2];

                moons[body] = new CrdsRectangular(
                    rectMars.X + esaphodeiRect[body].X,
                    rectMars.Y + esaphodeiRect[body].Y,
                    rectMars.Z + esaphodeiRect[body].Z
                    );
            }

            return(moons);
        }
예제 #14
0
        public static CrdsEcliptical Position(double jd, GenericSatelliteOrbit orbit, CrdsEcliptical planet)
        {
            NutationElements ne      = Nutation.NutationElements(jd);
            double           epsilon = Date.TrueObliquity(jd, ne.deltaEpsilon);

            // convert current coordinates to epoch, as algorithm requires
            CrdsEquatorial       eq            = planet.ToEquatorial(epsilon);
            PrecessionalElements peEpoch       = Precession.ElementsFK5(jd, Date.EPOCH_J2000);
            CrdsEquatorial       eqPlanetEpoch = Precession.GetEquatorialCoordinates(eq, peEpoch);

            // ecliptical pole
            CrdsEquatorial pole = new CrdsEcliptical(0, 90).ToEquatorial(epsilon);

            double distance0;
            double distance = planet.Distance;

            CrdsEcliptical eclSatellite;

            do
            {
                distance0 = distance;

                // take light-time effect into account
                double tau = PlanetPositions.LightTimeEffect(distance);

                double t = jd - tau - orbit.jd;

                double M = To360(orbit.M + orbit.n * t);

                double omega = To360(orbit.w + t * 360.0 / (orbit.Pw * 365.25));
                double node  = To360(orbit.Om + t * 360.0 / (orbit.POm * 365.25));

                // Find eccentric anomaly by solving Kepler equation
                double E = SolveKepler(M, orbit.e);

                double X = orbit.a * (Cos(E) - orbit.e);
                double Y = orbit.a * Sqrt(1 - orbit.e * orbit.e) * Sin(E);

                // cartesian state vector of satellite
                var d =
                    Matrix.R2(ToRadians(-eqPlanetEpoch.Delta)) *
                    Matrix.R3(ToRadians(eqPlanetEpoch.Alpha)) *
                    Matrix.R3(ToRadians(-pole.Alpha - 90)) *
                    Matrix.R1(ToRadians(pole.Delta - 90)) *
                    Matrix.R3(ToRadians(-node)) *
                    Matrix.R1(ToRadians(-orbit.i)) *
                    Matrix.R3(ToRadians(-omega)) *
                    new Matrix(new double[, ] {
                    { X / distance }, { Y / distance }, { 0 }
                });

                // radial component, positive away from observer
                // converted to degrees
                double x = ToDegrees(d.Values[0, 0]);

                // semimajor axis, expressed in degrees, as visible from Earth
                double theta = ToDegrees(Atan(orbit.a / distance));

                // offsets values in degrees
                double dAlphaCosDelta = ToDegrees(d.Values[1, 0]);
                double dDelta         = ToDegrees(d.Values[2, 0]);

                double delta  = eqPlanetEpoch.Delta + dDelta;
                double dAlpha = dAlphaCosDelta / Cos(ToRadians(delta));
                double alpha  = eqPlanetEpoch.Alpha + dAlpha;

                CrdsEquatorial eqSatelliteEpoch = new CrdsEquatorial(alpha, delta);

                // convert jd0 equatorial coordinates to current epoch
                // and to ecliptical
                PrecessionalElements pe          = Precession.ElementsFK5(Date.EPOCH_J2000, jd);
                CrdsEquatorial       eqSatellite = Precession.GetEquatorialCoordinates(eqSatelliteEpoch, pe);
                eclSatellite = eqSatellite.ToEcliptical(epsilon);

                // calculate distance to Earth
                distance = planet.Distance + x / theta * orbit.a;
            }while (Abs(distance - distance0) > 1e-6);

            eclSatellite.Distance = distance;

            return(eclSatellite);
        }
예제 #15
0
        /// <summary>
        /// Gets ecliptical coordinates of the Moon for given instant.
        /// </summary>
        /// <param name="jd">Julian Day.</param>
        /// <returns>Geocentric ecliptical coordinates of the Moon, referred to mean equinox of the date.</returns>
        /// <remarks>
        /// This method is taken from AA(II), chapter 47,
        /// and based on the Charpont ELP-2000/82 lunar theory.
        /// Accuracy of the method is 10" in longitude and 4" in latitude.
        /// </remarks>
        // TODO: use full ELP2000/82 theory:
        // http://totaleclipse.eu/Astronomy/ELP2000.html
        // http://cdsarc.u-strasbg.fr/viz-bin/cat/VI/79
        public static CrdsEcliptical GetCoordinates(double jd)
        {
            Initialize();

            double T = (jd - 2451545.0) / 36525.0;

            double T2 = T * T;
            double T3 = T2 * T;
            double T4 = T3 * T;

            // Moon's mean longitude
            double L_ = 218.3164477 + 481267.88123421 * T - 0.0015786 * T2 + T3 / 538841.0 - T4 / 65194000.0;

            // Preserve the L_ value in degrees
            double Lm = L_;

            // Mean elongation of the Moon
            double D = 297.8501921 + 445267.1114034 * T - 0.0018819 * T2 + T3 / 545868.0 - T4 / 113065000.0;

            // Sun's mean anomaly
            double M = 357.5291092 + 35999.0502909 * T - 0.0001536 * T2 + T3 / 24490000.0;

            // Moon's mean anomaly
            double M_ = 134.9633964 + 477198.8675055 * T + 0.0087414 * T2 + T3 / 69699.0 - T4 / 14712000.0;

            // Moon's argument of latitude (mean dinstance of the Moon from its ascending node)
            double F = 93.2720950 + 483202.0175233 * T - 0.0036539 * T2 - T3 / 3526000.0 + T4 / 863310000.0;

            // Correction arguments
            double A1 = 119.75 + 131.849 * T;
            double A2 = 53.09 + 479264.290 * T;
            double A3 = 313.45 + 481266.484 * T;

            // Multiplier related to the eccentricity of the Earth orbit
            double E = 1 - 0.002516 * T - 0.0000074 * T2;

            L_ = Angle.ToRadians(L_);
            D  = Angle.ToRadians(D);
            M  = Angle.ToRadians(M);
            M_ = Angle.ToRadians(M_);
            F  = Angle.ToRadians(F);
            A1 = Angle.ToRadians(A1);
            A2 = Angle.ToRadians(A2);
            A3 = Angle.ToRadians(A3);

            double Sum_l = 0;
            double Sum_b = 0;
            double Sum_r = 0;

            double[] DMMF = new double[] { D, M, M_, F };
            double[] powE = new double[3] {
                1, E, E *E
            };

            double lrArg, bArg;

            for (int i = 0; i < 60; i++)
            {
                lrArg = 0;
                bArg  = 0;

                for (int j = 0; j < 4; j++)
                {
                    lrArg += DMMF[j] * ArgsLR[i, j];
                    bArg  += DMMF[j] * ArgsB[i, j];
                }

                Sum_l += SinCoeffLR[i] * Math.Sin(lrArg) * powE[Math.Abs(ArgsLR[i, 1])];
                Sum_r += CosCoeffLR[i] * Math.Cos(lrArg) * powE[Math.Abs(ArgsLR[i, 1])];
                Sum_b += CoeffB[i] * Math.Sin(bArg) * powE[Math.Abs(ArgsB[i, 1])];
            }

            Sum_l += 3958 * Math.Sin(A1)
                     + 1962 * Math.Sin(L_ - F)
                     + 318 * Math.Sin(A2);

            Sum_b += -2235 * Math.Sin(L_)
                     + 382 * Math.Sin(A3)
                     + 175 * Math.Sin(A1 - F)
                     + 175 * Math.Sin(A1 + F)
                     + 127 * Math.Sin(L_ - M_)
                     - 115 * Math.Sin(L_ + M_);

            CrdsEcliptical ecl = new CrdsEcliptical();

            ecl.Lambda   = Lm + Sum_l / 1e6;
            ecl.Lambda   = Angle.To360(ecl.Lambda);
            ecl.Beta     = Sum_b / 1e6;
            ecl.Distance = 385000.56 + Sum_r / 1e3;

            return(ecl);
        }
예제 #16
0
        public static CrdsRectangular[] Positions(double jd, CrdsHeliocentrical earth, CrdsHeliocentrical uranus)
        {
            CrdsRectangular[] moons = new CrdsRectangular[MOONS_COUNT];

            // Rectangular topocentrical coordinates of Uranus
            CrdsRectangular rectUranus = uranus.ToRectangular(earth);

            // Ecliptical coordinates of Uranus
            CrdsEcliptical eclUranus = rectUranus.ToEcliptical();

            // Distance from Earth to Uranus, in AU
            double distanceUranus = eclUranus.Distance;

            // light-time effect
            double tau = PlanetPositions.LightTimeEffect(distanceUranus);

            double t = jd - 2444239.5 - tau;

            double[] elem = new double[6 * MOONS_COUNT];
            double[] an   = new double[MOONS_COUNT];
            double[] ae   = new double[MOONS_COUNT];
            double[] ai   = new double[MOONS_COUNT];

            // Calculate GUST86 elements:

            for (int i = 0; i < 5; i++)
            {
                an[i] = IEEERemainder(fqn[i] * t + phn[i], 2 * PI);
                ae[i] = IEEERemainder(fqe[i] * t + phe[i], 2 * PI);
                ai[i] = IEEERemainder(fqi[i] * t + phi[i], 2 * PI);
            }

            elem[0 * 6 + 0] = 4.44352267
                              - Cos(an[0] - an[1] * 3.0 + an[2] * 2.0) * 3.492e-5
                              + Cos(an[0] * 2.0 - an[1] * 6.0 + an[2] * 4.0) * 8.47e-6
                              + Cos(an[0] * 3.0 - an[1] * 9.0 + an[2] * 6.0) * 1.31e-6
                              - Cos(an[0] - an[1]) * 5.228e-5
                              - Cos(an[0] * 2.0 - an[1] * 2.0) * 1.3665e-4;
            elem[0 * 6 + 1] =
                Sin(an[0] - an[1] * 3.0 + an[2] * 2.0) * .02547217
                - Sin(an[0] * 2.0 - an[1] * 6.0 + an[2] * 4.0) * .00308831
                - Sin(an[0] * 3.0 - an[1] * 9.0 + an[2] * 6.0) * 3.181e-4
                - Sin(an[0] * 4.0 - an[1] * 12 + an[2] * 8.0) * 3.749e-5
                - Sin(an[0] - an[1]) * 5.785e-5
                - Sin(an[0] * 2.0 - an[1] * 2.0) * 6.232e-5
                - Sin(an[0] * 3.0 - an[1] * 3.0) * 2.795e-5
                + t * 4.44519055 - .23805158;
            elem[0 * 6 + 2] = Cos(ae[0]) * .00131238
                              + Cos(ae[1]) * 7.181e-5
                              + Cos(ae[2]) * 6.977e-5
                              + Cos(ae[3]) * 6.75e-6
                              + Cos(ae[4]) * 6.27e-6
                              + Cos(an[0]) * 1.941e-4
                              - Cos(-an[0] + an[1] * 2.0) * 1.2331e-4
                              + Cos(an[0] * -2.0 + an[1] * 3.0) * 3.952e-5;
            elem[0 * 6 + 3] = Sin(ae[0]) * .00131238
                              + Sin(ae[1]) * 7.181e-5
                              + Sin(ae[2]) * 6.977e-5
                              + Sin(ae[3]) * 6.75e-6
                              + Sin(ae[4]) * 6.27e-6
                              + Sin(an[0]) * 1.941e-4
                              - Sin(-an[0] + an[1] * 2.0) * 1.2331e-4
                              + Sin(an[0] * -2.0 + an[1] * 3.0) * 3.952e-5;
            elem[0 * 6 + 4] = Cos(ai[0]) * .03787171
                              + Cos(ai[1]) * 2.701e-5
                              + Cos(ai[2]) * 3.076e-5
                              + Cos(ai[3]) * 1.218e-5
                              + Cos(ai[4]) * 5.37e-6;
            elem[0 * 6 + 4] = Sin(ai[0]) * .03787171
                              + Sin(ai[1]) * 2.701e-5
                              + Sin(ai[2]) * 3.076e-5
                              + Sin(ai[3]) * 1.218e-5
                              + Sin(ai[4]) * 5.37e-6;

            elem[1 * 6 + 0] = 2.49254257
                              + Cos(an[0] - an[1] * 3.0 + an[2] * 2.0) * 2.55e-6
                              - Cos(an[1] - an[2]) * 4.216e-5
                              - Cos(an[1] * 2.0 - an[2] * 2.0) * 1.0256e-4;
            elem[1 * 6 + 1] =
                -Sin(an[0] - an[1] * 3.0 + an[2] * 2.0) * .0018605
                + Sin(an[0] * 2.0 - an[1] * 6.0 + an[2] * 4.0) * 2.1999e-4
                + Sin(an[0] * 3.0 - an[1] * 9.0 + an[2] * 6.0) * 2.31e-5
                + Sin(an[0] * 4.0 - an[1] * 12 + an[2] * 8.0) * 4.3e-6
                - Sin(an[1] - an[2]) * 9.011e-5
                - Sin(an[1] * 2.0 - an[2] * 2.0) * 9.107e-5
                - Sin(an[1] * 3.0 - an[2] * 3.0) * 4.275e-5
                - Sin(an[1] * 2.0 - an[3] * 2.0) * 1.649e-5
                + t * 2.49295252 + 3.09804641;
            elem[1 * 6 + 2] = Cos(ae[0]) * -3.35e-6
                              + Cos(ae[1]) * .00118763
                              + Cos(ae[2]) * 8.6159e-4
                              + Cos(ae[3]) * 7.15e-5
                              + Cos(ae[4]) * 5.559e-5
                              - Cos(-an[1] + an[2] * 2.0) * 8.46e-5
                              + Cos(an[1] * -2.0 + an[2] * 3.0) * 9.181e-5
                              + Cos(-an[1] + an[3] * 2.0) * 2.003e-5
                              + Cos(an[1]) * 8.977e-5;
            elem[1 * 6 + 3] = Sin(ae[0]) * -3.35e-6
                              + Sin(ae[1]) * .00118763
                              + Sin(ae[2]) * 8.6159e-4
                              + Sin(ae[3]) * 7.15e-5
                              + Sin(ae[4]) * 5.559e-5
                              - Sin(-an[1] + an[2] * 2.0) * 8.46e-5
                              + Sin(an[1] * -2.0 + an[2] * 3.0) * 9.181e-5
                              + Sin(-an[1] + an[3] * 2.0) * 2.003e-5
                              + Sin(an[1]) * 8.977e-5;
            elem[1 * 6 + 4] = Cos(ai[0]) * -1.2175e-4
                              + Cos(ai[1]) * 3.5825e-4
                              + Cos(ai[2]) * 2.9008e-4
                              + Cos(ai[3]) * 9.778e-5
                              + Cos(ai[4]) * 3.397e-5;
            elem[1 * 6 + 5] = Sin(ai[0]) * -1.2175e-4
                              + Sin(ai[1]) * 3.5825e-4
                              + Sin(ai[2]) * 2.9008e-4
                              + Sin(ai[3]) * 9.778e-5
                              + Sin(ai[4]) * 3.397e-5;
            elem[2 * 6 + 0] = 1.5159549
                              + Cos(an[2] - an[3] * 2.0 + ae[2]) * 9.74e-6
                              - Cos(an[1] - an[2]) * 1.06e-4
                              + Cos(an[1] * 2.0 - an[2] * 2.0) * 5.416e-5
                              - Cos(an[2] - an[3]) * 2.359e-5
                              - Cos(an[2] * 2.0 - an[3] * 2.0) * 7.07e-5
                              - Cos(an[2] * 3.0 - an[3] * 3.0) * 3.628e-5;
            elem[2 * 6 + 1] =
                Sin(an[0] - an[1] * 3.0 + an[2] * 2.0) * 6.6057e-4
                - Sin(an[0] * 2.0 - an[1] * 6.0 + an[2] * 4.0) * 7.651e-5
                - Sin(an[0] * 3.0 - an[1] * 9.0 + an[2] * 6.0) * 8.96e-6
                - Sin(an[0] * 4.0 - an[1] * 12.0 + an[2] * 8.0) * 2.53e-6
                - Sin(an[2] - an[3] * 4.0 + an[4] * 3.0) * 5.291e-5
                - Sin(an[2] - an[3] * 2.0 + ae[4]) * 7.34e-6
                - Sin(an[2] - an[3] * 2.0 + ae[3]) * 1.83e-6
                + Sin(an[2] - an[3] * 2.0 + ae[2]) * 1.4791e-4
                + Sin(an[2] - an[3] * 2.0 + ae[1]) * -7.77e-6
                + Sin(an[1] - an[2]) * 9.776e-5
                + Sin(an[1] * 2.0 - an[2] * 2.0) * 7.313e-5
                + Sin(an[1] * 3.0 - an[2] * 3.0) * 3.471e-5
                + Sin(an[1] * 4.0 - an[2] * 4.0) * 1.889e-5
                - Sin(an[2] - an[3]) * 6.789e-5
                - Sin(an[2] * 2.0 - an[3] * 2.0) * 8.286e-5
                + Sin(an[2] * 3.0 - an[3] * 3.0) * -3.381e-5
                - Sin(an[2] * 4.0 - an[3] * 4.0) * 1.579e-5
                - Sin(an[2] - an[4]) * 1.021e-5
                - Sin(an[2] * 2.0 - an[4] * 2.0) * 1.708e-5
                + t * 1.51614811 + 2.28540169;
            elem[2 * 6 + 2] = Cos(ae[0]) * -2.1e-7
                              - Cos(ae[1]) * 2.2795e-4
                              + Cos(ae[2]) * .00390469
                              + Cos(ae[3]) * 3.0917e-4
                              + Cos(ae[4]) * 2.2192e-4
                              + Cos(an[1]) * 2.934e-5
                              + Cos(an[2]) * 2.62e-5
                              + Cos(-an[1] + an[2] * 2.0) * 5.119e-5
                              - Cos(an[1] * -2.0 + an[2] * 3.0) * 1.0386e-4
                              - Cos(an[1] * -3.0 + an[2] * 4.0) * 2.716e-5
                              + Cos(an[3]) * -1.622e-5
                              + Cos(-an[2] + an[3] * 2.0) * 5.4923e-4
                              + Cos(an[2] * -2.0 + an[3] * 3.0) * 3.47e-5
                              + Cos(an[2] * -3.0 + an[3] * 4.0) * 1.281e-5
                              + Cos(-an[2] + an[4] * 2.0) * 2.181e-5
                              + Cos(an[2]) * 4.625e-5;
            elem[2 * 6 + 3] = Sin(ae[0]) * -2.1e-7
                              - Sin(ae[1]) * 2.2795e-4
                              + Sin(ae[2]) * .00390469
                              + Sin(ae[3]) * 3.0917e-4
                              + Sin(ae[4]) * 2.2192e-4
                              + Sin(an[1]) * 2.934e-5
                              + Sin(an[2]) * 2.62e-5
                              + Sin(-an[1] + an[2] * 2.0) * 5.119e-5
                              - Sin(an[1] * -2.0 + an[2] * 3.0) * 1.0386e-4
                              - Sin(an[1] * -3.0 + an[2] * 4.0) * 2.716e-5
                              + Sin(an[3]) * -1.622e-5
                              + Sin(-an[2] + an[3] * 2.0) * 5.4923e-4
                              + Sin(an[2] * -2.0 + an[3] * 3.0) * 3.47e-5
                              + Sin(an[2] * -3.0 + an[3] * 4.0) * 1.281e-5
                              + Sin(-an[2] + an[4] * 2.0) * 2.181e-5
                              + Sin(an[2]) * 4.625e-5;
            elem[2 * 6 + 4] = Cos(ai[0]) * -1.086e-5
                              - Cos(ai[1]) * 8.151e-5
                              + Cos(ai[2]) * .00111336
                              + Cos(ai[3]) * 3.5014e-4
                              + Cos(ai[4]) * 1.065e-4;
            elem[2 * 6 + 5] = Sin(ai[0]) * -1.086e-5
                              - Sin(ai[1]) * 8.151e-5
                              + Sin(ai[2]) * .00111336
                              + Sin(ai[3]) * 3.5014e-4
                              + Sin(ai[4]) * 1.065e-4;
            elem[3 * 6 + 0] = .72166316
                              - Cos(an[2] - an[3] * 2.0 + ae[2]) * 2.64e-6
                              - Cos(an[3] * 2.0 - an[4] * 3.0 + ae[4]) * 2.16e-6
                              + Cos(an[3] * 2.0 - an[4] * 3.0 + ae[3]) * 6.45e-6
                              - Cos(an[3] * 2.0 - an[4] * 3.0 + ae[2]) * 1.11e-6
                              + Cos(an[1] - an[3]) * -6.223e-5
                              - Cos(an[2] - an[3]) * 5.613e-5
                              - Cos(an[3] - an[4]) * 3.994e-5
                              - Cos(an[3] * 2.0 - an[4] * 2.0) * 9.185e-5
                              - Cos(an[3] * 3.0 - an[4] * 3.0) * 5.831e-5
                              - Cos(an[3] * 4.0 - an[4] * 4.0) * 3.86e-5
                              - Cos(an[3] * 5.0 - an[4] * 5.0) * 2.618e-5
                              - Cos(an[3] * 6.0 - an[4] * 6.0) * 1.806e-5;
            elem[3 * 6 + 1] =
                Sin(an[2] - an[3] * 4.0 + an[4] * 3.0) * 2.061e-5
                - Sin(an[2] - an[3] * 2.0 + ae[4]) * 2.07e-6
                - Sin(an[2] - an[3] * 2.0 + ae[3]) * 2.88e-6
                - Sin(an[2] - an[3] * 2.0 + ae[2]) * 4.079e-5
                + Sin(an[2] - an[3] * 2.0 + ae[1]) * 2.11e-6
                - Sin(an[3] * 2.0 - an[4] * 3.0 + ae[4]) * 5.183e-5
                + Sin(an[3] * 2.0 - an[4] * 3.0 + ae[3]) * 1.5987e-4
                + Sin(an[3] * 2.0 - an[4] * 3.0 + ae[2]) * -3.505e-5
                - Sin(an[3] * 3.0 - an[4] * 4.0 + ae[4]) * 1.56e-6
                + Sin(an[1] - an[3]) * 4.054e-5
                + Sin(an[2] - an[3]) * 4.617e-5
                - Sin(an[3] - an[4]) * 3.1776e-4
                - Sin(an[3] * 2.0 - an[4] * 2.0) * 3.0559e-4
                - Sin(an[3] * 3.0 - an[4] * 3.0) * 1.4836e-4
                - Sin(an[3] * 4.0 - an[4] * 4.0) * 8.292e-5
                + Sin(an[3] * 5.0 - an[4] * 5.0) * -4.998e-5
                - Sin(an[3] * 6.0 - an[4] * 6.0) * 3.156e-5
                - Sin(an[3] * 7.0 - an[4] * 7.0) * 2.056e-5
                - Sin(an[3] * 8.0 - an[4] * 8.0) * 1.369e-5
                + t * .72171851 + .85635879;
            elem[3 * 6 + 2] = Cos(ae[0]) * -2e-8
                              - Cos(ae[1]) * 1.29e-6
                              - Cos(ae[2]) * 3.2451e-4
                              + Cos(ae[3]) * 9.3281e-4
                              + Cos(ae[4]) * .00112089
                              + Cos(an[1]) * 3.386e-5
                              + Cos(an[3]) * 1.746e-5
                              + Cos(-an[1] + an[3] * 2.0) * 1.658e-5
                              + Cos(an[2]) * 2.889e-5
                              - Cos(-an[2] + an[3] * 2.0) * 3.586e-5
                              + Cos(an[3]) * -1.786e-5
                              - Cos(an[4]) * 3.21e-5
                              - Cos(-an[3] + an[4] * 2.0) * 1.7783e-4
                              + Cos(an[3] * -2.0 + an[4] * 3.0) * 7.9343e-4
                              + Cos(an[3] * -3.0 + an[4] * 4.0) * 9.948e-5
                              + Cos(an[3] * -4.0 + an[4] * 5.0) * 4.483e-5
                              + Cos(an[3] * -5.0 + an[4] * 6.0) * 2.513e-5
                              + Cos(an[3] * -6.0 + an[4] * 7.0) * 1.543e-5;
            elem[3 * 6 + 3] = Sin(ae[0]) * -2e-8
                              - Sin(ae[1]) * 1.29e-6
                              - Sin(ae[2]) * 3.2451e-4
                              + Sin(ae[3]) * 9.3281e-4
                              + Sin(ae[4]) * .00112089
                              + Sin(an[1]) * 3.386e-5
                              + Sin(an[3]) * 1.746e-5
                              + Sin(-an[1] + an[3] * 2.0) * 1.658e-5
                              + Sin(an[2]) * 2.889e-5
                              - Sin(-an[2] + an[3] * 2.0) * 3.586e-5
                              + Sin(an[3]) * -1.786e-5
                              - Sin(an[4]) * 3.21e-5
                              - Sin(-an[3] + an[4] * 2.0) * 1.7783e-4
                              + Sin(an[3] * -2.0 + an[4] * 3.0) * 7.9343e-4
                              + Sin(an[3] * -3.0 + an[4] * 4.0) * 9.948e-5
                              + Sin(an[3] * -4.0 + an[4] * 5.0) * 4.483e-5
                              + Sin(an[3] * -5.0 + an[4] * 6.0) * 2.513e-5
                              + Sin(an[3] * -6.0 + an[4] * 7.0) * 1.543e-5;
            elem[3 * 6 + 4] = Cos(ai[0]) * -1.43e-6
                              - Cos(ai[1]) * 1.06e-6
                              - Cos(ai[2]) * 1.4013e-4
                              + Cos(ai[3]) * 6.8572e-4
                              + Cos(ai[4]) * 3.7832e-4;
            elem[3 * 6 + 5] = Sin(ai[0]) * -1.43e-6
                              - Sin(ai[1]) * 1.06e-6
                              - Sin(ai[2]) * 1.4013e-4
                              + Sin(ai[3]) * 6.8572e-4
                              + Sin(ai[4]) * 3.7832e-4;
            elem[4 * 6 + 0] = .46658054
                              + Cos(an[3] * 2.0 - an[4] * 3.0 + ae[4]) * 2.08e-6
                              - Cos(an[3] * 2.0 - an[4] * 3.0 + ae[3]) * 6.22e-6
                              + Cos(an[3] * 2.0 - an[4] * 3.0 + ae[2]) * 1.07e-6
                              - Cos(an[1] - an[4]) * 4.31e-5
                              + Cos(an[2] - an[4]) * -3.894e-5
                              - Cos(an[3] - an[4]) * 8.011e-5
                              + Cos(an[3] * 2.0 - an[4] * 2.0) * 5.906e-5
                              + Cos(an[3] * 3.0 - an[4] * 3.0) * 3.749e-5
                              + Cos(an[3] * 4.0 - an[4] * 4.0) * 2.482e-5
                              + Cos(an[3] * 5.0 - an[4] * 5.0) * 1.684e-5;
            elem[4 * 6 + 1] =
                -Sin(an[2] - an[3] * 4.0 + an[4] * 3.0) * 7.82e-6
                + Sin(an[3] * 2.0 - an[4] * 3.0 + ae[4]) * 5.129e-5
                - Sin(an[3] * 2.0 - an[4] * 3.0 + ae[3]) * 1.5824e-4
                + Sin(an[3] * 2.0 - an[4] * 3.0 + ae[2]) * 3.451e-5
                + Sin(an[1] - an[4]) * 4.751e-5
                + Sin(an[2] - an[4]) * 3.896e-5
                + Sin(an[3] - an[4]) * 3.5973e-4
                + Sin(an[3] * 2.0 - an[4] * 2.0) * 2.8278e-4
                + Sin(an[3] * 3.0 - an[4] * 3.0) * 1.386e-4
                + Sin(an[3] * 4.0 - an[4] * 4.0) * 7.803e-5
                + Sin(an[3] * 5.0 - an[4] * 5.0) * 4.729e-5
                + Sin(an[3] * 6.0 - an[4] * 6.0) * 3e-5
                + Sin(an[3] * 7.0 - an[4] * 7.0) * 1.962e-5
                + Sin(an[3] * 8.0 - an[4] * 8.0) * 1.311e-5
                + t * .46669212 - .9155918;
            elem[4 * 6 + 2] = Cos(ae[1]) * -3.5e-7
                              + Cos(ae[2]) * 7.453e-5
                              - Cos(ae[3]) * 7.5868e-4
                              + Cos(ae[4]) * .00139734
                              + Cos(an[1]) * 3.9e-5
                              + Cos(-an[1] + an[4] * 2.0) * 1.766e-5
                              + Cos(an[2]) * 3.242e-5
                              + Cos(an[3]) * 7.975e-5
                              + Cos(an[4]) * 7.566e-5
                              + Cos(-an[3] + an[4] * 2.0) * 1.3404e-4
                              - Cos(an[3] * -2.0 + an[4] * 3.0) * 9.8726e-4
                              - Cos(an[3] * -3.0 + an[4] * 4.0) * 1.2609e-4
                              - Cos(an[3] * -4.0 + an[4] * 5.0) * 5.742e-5
                              - Cos(an[3] * -5.0 + an[4] * 6.0) * 3.241e-5
                              - Cos(an[3] * -6.0 + an[4] * 7.0) * 1.999e-5
                              - Cos(an[3] * -7.0 + an[4] * 8.0) * 1.294e-5;
            elem[4 * 6 + 3] = Sin(ae[1]) * -3.5e-7
                              + Sin(ae[2]) * 7.453e-5
                              - Sin(ae[3]) * 7.5868e-4
                              + Sin(ae[4]) * .00139734
                              + Sin(an[1]) * 3.9e-5
                              + Sin(-an[1] + an[4] * 2.0) * 1.766e-5
                              + Sin(an[2]) * 3.242e-5
                              + Sin(an[3]) * 7.975e-5
                              + Sin(an[4]) * 7.566e-5
                              + Sin(-an[3] + an[4] * 2.0) * 1.3404e-4
                              - Sin(an[3] * -2.0 + an[4] * 3.0) * 9.8726e-4
                              - Sin(an[3] * -3.0 + an[4] * 4.0) * 1.2609e-4
                              - Sin(an[3] * -4.0 + an[4] * 5.0) * 5.742e-5
                              - Sin(an[3] * -5.0 + an[4] * 6.0) * 3.241e-5
                              - Sin(an[3] * -6.0 + an[4] * 7.0) * 1.999e-5
                              - Sin(an[3] * -7.0 + an[4] * 8.0) * 1.294e-5;
            elem[4 * 6 + 4] = Cos(ai[0]) * -4.4e-7
                              - Cos(ai[1]) * 3.1e-7
                              + Cos(ai[2]) * 3.689e-5
                              - Cos(ai[3]) * 5.9633e-4
                              + Cos(ai[4]) * 4.5169e-4;
            elem[4 * 6 + 5] = Sin(ai[0]) * -4.4e-7
                              - Sin(ai[1]) * 3.1e-7
                              + Sin(ai[2]) * 3.689e-5
                              - Sin(ai[3]) * 5.9633e-4
                              + Sin(ai[4]) * 4.5169e-4;

            // Get rectangular (Uranus-reffered) coordinates of moons
            CrdsRectangular[] gust86Rect = new CrdsRectangular[MOONS_COUNT];

            for (int body = 0; body < MOONS_COUNT; body++)
            {
                double[] elem_body = new double[6];
                for (int i = 0; i < 6; i++)
                {
                    elem_body[i] = elem[body * 6 + i];
                }

                double[] x = new double[3];
                EllipticToRectangularN(gust86_rmu[body], elem_body, ref x);

                gust86Rect[body]   = new CrdsRectangular();
                gust86Rect[body].X = GUST86toVsop87[0] * x[0] + GUST86toVsop87[1] * x[1] + GUST86toVsop87[2] * x[2];
                gust86Rect[body].Y = GUST86toVsop87[3] * x[0] + GUST86toVsop87[4] * x[1] + GUST86toVsop87[5] * x[2];
                gust86Rect[body].Z = GUST86toVsop87[6] * x[0] + GUST86toVsop87[7] * x[1] + GUST86toVsop87[8] * x[2];
            }

            for (int i = 0; i < MOONS_COUNT; i++)
            {
                moons[i] = new CrdsRectangular(
                    rectUranus.X + gust86Rect[i].X,
                    rectUranus.Y + gust86Rect[i].Y,
                    rectUranus.Z + gust86Rect[i].Z
                    );
            }

            return(moons);
        }