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); }
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)); }
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); }); }