Beispiel #1
0
        private double NearestPassWithPlanet(SkyContext ctx, int planet)
        {
            double minute = TimeSpan.FromMinutes(1).TotalDays;
            double days   = double.MaxValue;

            while (Math.Abs(days) > minute)
            {
                CrdsEquatorial eqMoon   = ctx.Get(lunarCalc.Equatorial);
                CrdsEquatorial eqPlanet = ctx.Get(planetsCalc.Planet_Equatorial, planet);

                double[] alpha = new[] { eqMoon.Alpha, eqPlanet.Alpha };
                Angle.Align(alpha);

                days = (alpha[1] - alpha[0]) / LunarEphem.AVERAGE_DAILY_MOTION;

                ctx.JulianDay += days;
            }

            return(ctx.JulianDay);
        }
Beispiel #2
0
        private CrdsRectangular NeptuneMoon_Rectangular(SkyContext c, int m)
        {
            CrdsEquatorial moonEq     = c.Get(NeptuneMoon_Equatorial, m);
            CrdsEcliptical moonEcl    = c.Get(NeptuneMoon_Ecliptical, m);
            CrdsEquatorial neptuneEq  = c.Get(Planet_Equatorial, Planet.NEPTUNE);
            CrdsEcliptical neptuneEcl = c.Get(Planet_Ecliptical, Planet.NEPTUNE);

            double sd = c.Get(Planet_Semidiameter, Planet.NEPTUNE) / 3600;
            double P  = c.Get(Planet_Appearance, Planet.NEPTUNE).P;

            double[] alpha = new double[] { moonEq.Alpha, neptuneEq.Alpha };
            Angle.Align(alpha);

            double[] delta = new double[] { moonEq.Delta, neptuneEq.Delta };

            double x = (alpha[0] - alpha[1]) * Math.Cos(Angle.ToRadians(neptuneEq.Delta)) / sd;
            double y = (delta[0] - delta[1]) / sd;

            // radius-vector of moon, in planet's equatorial radii
            double r = Math.Sqrt(x * x + y * y);

            // rotation angle
            double theta = Angle.ToDegrees(Math.Atan2(x, y));

            // rotate with position angle of the planet
            theta -= P;

            // convert back to rectangular coordinates, but rotated with P angle:
            y = r * Math.Cos(Angle.ToRadians(theta));
            x = -r *Math.Sin(Angle.ToRadians(theta));

            const double NEPTUNE_RADIUS = 24622;
            const double AU             = 149597870;

            // z is expressed in Uranus equatorial radii
            double z = (moonEcl.Distance - neptuneEcl.Distance) / (2 * NEPTUNE_RADIUS / AU);

            return(new CrdsRectangular(x, y, z));
        }
Beispiel #3
0
 public void Align()
 {
     {
         var array = new double[] { 359, 0, 1, 2, 3 };
         Angle.Align(array);
         CollectionAssert.AreEqual(new double[] { 359, 360, 361, 362, 363 }, array);
     }
     {
         var array = new double[] { -3, -7, -11 };
         Angle.Align(array);
         CollectionAssert.AreEqual(new double[] { -3, -7, -11 }, array);
     }
     {
         var array = new double[] { 4, 350, 340 };
         Angle.Align(array);
         CollectionAssert.AreEqual(new double[] { 4, -10, -20 }, array);
     }
     {
         var array = new double[] { 350, 10, 20 };
         Angle.Align(array);
         CollectionAssert.AreEqual(new double[] { 350, 370, 380 }, array);
     }
 }
        private void ParseOrbit(GenericMoonData orbit, string response)
        {
            List <string> lines     = response.Split('\n').ToList();
            string        soeMarker = lines.FirstOrDefault(ln => ln == "$$SOE");

            if (soeMarker == null)
            {
                throw new Exception($"Unable to parse ephemeris data for satellite {orbit.names.First().Value}");
            }

            int soeMarkerIndex = lines.IndexOf(soeMarker);

            string header = lines[soeMarkerIndex - 2];

            List <string> headerItems = header.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(item => item.Trim()).ToList();

            int dateIndex = headerItems.IndexOf(headerItems.FirstOrDefault(item => item.StartsWith("Calendar Date")));

            List <double> day1 = lines[soeMarkerIndex + 1].Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select((item, ind) => ind != dateIndex ? double.Parse(item.Trim(), CultureInfo.InvariantCulture) : 0).ToList();
            List <double> day2 = lines[soeMarkerIndex + 2].Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select((item, ind) => ind != dateIndex ? double.Parse(item.Trim(), CultureInfo.InvariantCulture) : 0).ToList();

            orbit.jd = day1[headerItems.IndexOf("JDTDB")];
            orbit.e  = day1[headerItems.IndexOf("EC")];
            orbit.i  = day1[headerItems.IndexOf("IN")];
            orbit.Om = day1[headerItems.IndexOf("OM")];
            orbit.w  = day1[headerItems.IndexOf("W")];
            orbit.n  = day1[headerItems.IndexOf("N")];
            orbit.M  = day1[headerItems.IndexOf("MA")];
            orbit.a  = day1[headerItems.IndexOf("A")];

            double[] Omega = new double[] { orbit.Om, day2[headerItems.IndexOf("OM")] };
            double[] w     = new double[] { orbit.w, day2[headerItems.IndexOf("W")] };
            double[] MA    = new double[] { orbit.M, day2[headerItems.IndexOf("MA")] };

            Angle.Align(Omega);
            Angle.Align(w);

            orbit.POm = 360.0 / (Omega[1] - Omega[0]) / 365.25;
            orbit.Pw  = 360.0 / (w[1] - w[0]) / 365.25;

            MA[0] = MA[0] + orbit.n % 360;

            // add correction to mean motion
            Angle.Align(MA);
            double dn = MA[1] - MA[0];

            if (orbit.n + dn > 0)
            {
                orbit.n += dn;
            }

            string magLine = lines.FirstOrDefault(ln => ln.Contains("V(1,0)"));

            if (orbit.mag == 0 && !string.IsNullOrEmpty(magLine))
            {
                magLine = magLine.Substring(magLine.IndexOf("V(1,0)"));
                List <string> magItems = magLine.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries).Select(item => item.Trim()).ToList();
                string        mag      = magItems.ElementAt(1).Split(' ').First();
                orbit.mag = double.Parse(mag, CultureInfo.InvariantCulture);
            }

            string radiusLine = lines.FirstOrDefault(ln => ln.Contains("Radius"));

            if (orbit.radius == 0 && !string.IsNullOrEmpty(radiusLine))
            {
                radiusLine = radiusLine.Substring(radiusLine.IndexOf("Radius"));
                List <string> radiusItems = radiusLine.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries).Select(item => item.Trim()).ToList();
                string        radius      = radiusItems.ElementAt(1).Split(' ').First().Split('x').First();
                orbit.radius = double.Parse(radius, CultureInfo.InvariantCulture);
            }
        }
        private ICollection <Conjunction> MutualConjunctions(
            AstroEventsContext context,
            Func <PlanetData, double> longitude,
            Func <PlanetData, double> latitude)
        {
            // resulting collection of conjunctions
            List <Conjunction> conjunctions = new List <Conjunction>();

            // planets ephemeris data for the requested period
            ICollection <PlanetData[]> data = context.Get(PlanetEphemeris);

            // current index in data array
            int day = 0;

            // current calculated value of Julian Day
            double jd = context.From;

            // Time shifts, in days, from starting point to each point in a range to be interpolated
            double[] t = { 0, 1, 2, 3, 4 };

            for (jd = context.From; jd < context.To; jd++)
            {
                // check for cancel
                if (context.CancelToken?.IsCancellationRequested == true)
                {
                    return(new Conjunction[0]);
                }

                // "a" is a difference in longitude coordinate (Right Ascension or Ecliptical Longitude) between two planets (5 points)
                double[] a = new double[5];

                // "d" is a difference in latitude coordinate (Declination or Ecliptical Latitude) between two planets (5 points)
                double[] d = new double[5];

                // p1 is a number of first planet
                for (int p1 = 1; p1 <= 8; p1++)
                {
                    // p2 is a number for second planet
                    for (int p2 = p1 + 1; p2 <= 8; p2++)
                    {
                        // skip Earth
                        if (p1 != 3 && p2 != 3)
                        {
                            // "a1" is longitude coordinates for the first planet (5 points)
                            double[] a1 = new double[5];

                            // "a2" is latitude coordinates for the second planet (5 points)
                            double[] a2 = new double[5];

                            // collect longitudes for both planets
                            for (int i = 0; i < 5; i++)
                            {
                                a1[i] = longitude(data.ElementAt(day + i)[p1]);
                                a2[i] = longitude(data.ElementAt(day + i)[p2]);
                            }

                            // Align values to avoid 360 degrees point crossing
                            Angle.Align(a1);
                            Angle.Align(a2);

                            for (int i = 0; i < 5; i++)
                            {
                                // "a" is a difference in longitudes between two planets (5 points)
                                a[i] = a1[i] - a2[i];

                                // "d" is a difference in latitudes between two planets (5 points)
                                d[i] = latitude(data.ElementAt(day + i)[p1]) - latitude(data.ElementAt(day + i)[p2]);
                            }

                            // If difference in longitude changes its sign, it means a conjunction takes place
                            // Will use interpolation to find a point where the conjunction occurs ("zero point")
                            if (a[1] * a[2] < 0)
                            {
                                Interpolation.FindRoot(t, a, 1e-6, out double t0);

                                Conjunction conj = new Conjunction();

                                conj.JulianDay = jd - 2 + t0;

                                // planet names
                                conj.Planet1 = p1;
                                conj.Planet2 = p2;

                                // passage direction
                                conj.Direction = latitude(data.ElementAt(day + 2)[p1]) < latitude(data.ElementAt(day + 2)[p2]) ? "North" : "South";

                                // find the angular distance at the "zero point"
                                conj.AngularDistance       = Math.Abs(Interpolation.Lagrange(t, d, t0));
                                conj.AngularDistanceString = conjunctionSeparationFormatter.Format(conj.AngularDistance);

                                // magnitude of the first planet
                                conj.Magnitude1 = Formatters.Magnitude.Format(data.ElementAt(day + 2)[p1].Magnitude);

                                // magnitude of the second planet
                                conj.Magnitude2 = Formatters.Magnitude.Format(data.ElementAt(day + 2)[p2].Magnitude);

                                conjunctions.Add(conj);
                            }
                        }
                    }
                }

                day++;
            }

            return(conjunctions);
        }
        private ICollection <AstroEvent> Stationaries(AstroEventsContext context)
        {
            // resulting collection of events
            List <AstroEvent> events = new List <AstroEvent>();

            // planets ephemeris data for the requested period
            ICollection <PlanetData[]> data = context.Get(PlanetEphemeris);

            // current index in data array
            int day = 0;

            // current calculated value of Julian Day
            double jd = context.From;

            // Time shifts, in days, from starting point to each point in a range to be interpolated
            double[] t = { 0, 1, 2, 3, 4 };

            for (jd = context.From; jd < context.To; jd++)
            {
                // check for cancel
                if (context.CancelToken?.IsCancellationRequested == true)
                {
                    return(new AstroEvent[0]);
                }

                // "lon" is a planet ecliptical longitude
                double[] lon = new double[5];

                // p is a number of the planet
                for (int p = 1; p <= 8; p++)
                {
                    // skip Earth
                    if (p != 3)
                    {
                        // "lon" is a planet ecliptical longitude (5 points)
                        for (int i = 0; i < 5; i++)
                        {
                            lon[i] = data.ElementAt(day + i)[p].Ecliptical.Lambda;
                        }

                        // Align values to avoid 360 degrees point crossing
                        Angle.Align(lon);

                        // If magnitude has minimum value at central point
                        if (lon[1] > lon[2] && lon[2] < lon[3])
                        {
                            Interpolation.FindMinimum(t, lon, 1e-6, out double t0, out double lon0);

                            events.Add(new AstroEvent(jd - 2 + t0,
                                                      Text.Get("PlanetEvents.Stationaries.ProgradeText",
                                                               ("planetName", GetPlanetName(p)),
                                                               ("planetGenitiveName", GetPlanetGenitiveName(p))),
                                                      GetPlanet(p)));
                        }
                        else if (lon[1] < lon[2] && lon[2] > lon[3])
                        {
                            Interpolation.FindMaximum(t, lon, 1e-6, out double t0, out double lon0);

                            events.Add(new AstroEvent(jd - 2 + t0,
                                                      Text.Get("PlanetEvents.Stationaries.RetrogradeText",
                                                               ("planetName", GetPlanetName(p)),
                                                               ("planetGenitiveName", GetPlanetGenitiveName(p))),
                                                      GetPlanet(p)));
                        }
                    }
                }

                day++;
            }

            return(events);
        }
        public async Task SetDate(Date date, CrdsGeographical geoLocation)
        {
            await Task.Run(() =>
            {
                double jd0  = date.ToJulianEphemerisDay();
                daysInMonth = Date.DaysInMonth(date.Year, date.Month);

                var eL = new PointF[5];
                var eB = new PointF[5];
                var eR = new PointF[5];
                var jL = new PointF[5];
                var jB = new PointF[5];
                var jR = new PointF[5];

                var earth   = new CrdsHeliocentrical[5];
                var jupiter = new CrdsHeliocentrical[5];

                // calculate heliocentrical positions of Earth and Jupiter for 5 instants
                // and find least squares approximation model of planets position
                // to quick calculation of Galilean moons postions.
                for (int i = 0; i < 5; i++)
                {
                    double jd  = jd0 + (i / 4.0) * daysInMonth;
                    earth[i]   = PlanetPositions.GetPlanetCoordinates(3, jd);
                    jupiter[i] = PlanetPositions.GetPlanetCoordinates(5, jd);
                }

                double[] earthL = earth.Select(x => x.L).ToArray();
                double[] earthB = earth.Select(x => x.B).ToArray();
                double[] earthR = earth.Select(x => x.R).ToArray();

                double[] jupiterL = jupiter.Select(x => x.L).ToArray();
                double[] jupiterB = jupiter.Select(x => x.B).ToArray();
                double[] jupiterR = jupiter.Select(x => x.R).ToArray();

                // it's important to align longitudes (avoid 0 degrees crossing)
                // before applying least squares method
                earthL   = Angle.Align(earthL);
                jupiterL = Angle.Align(jupiterL);

                for (int i = 0; i < 5; i++)
                {
                    eL[i] = new PointF(i, (float)earthL[i]);
                    eB[i] = new PointF(i, (float)earthB[i]);
                    eR[i] = new PointF(i, (float)earthR[i]);
                    jL[i] = new PointF(i, (float)jupiterL[i]);
                    jB[i] = new PointF(i, (float)jupiterB[i]);
                    jR[i] = new PointF(i, (float)jupiterR[i]);
                }

                Begin       = jd0;
                End         = jd0 + daysInMonth;
                GeoLocation = geoLocation;
                this.eL     = LeastSquares.FindCoeffs(eL, 3);
                this.eB     = LeastSquares.FindCoeffs(eB, 3);
                this.eR     = LeastSquares.FindCoeffs(eR, 3);
                this.jL     = LeastSquares.FindCoeffs(jL, 3);
                this.jB     = LeastSquares.FindCoeffs(jB, 3);
                this.jR     = LeastSquares.FindCoeffs(jR, 3);
            });
        }