private async void GetObjectEphemeris(CelestialObject body) { var es = ViewManager.CreateViewModel <EphemerisSettingsVM>(); es.SelectedBody = body; es.JulianDayFrom = sky.Context.JulianDay; es.JulianDayTo = sky.Context.JulianDay + 30; if (ViewManager.ShowDialog(es) ?? false) { var tokenSource = new CancellationTokenSource(); var progress = new Progress <double>(); ViewManager.ShowProgress("Please wait", "Calculating ephemerides...", tokenSource, progress); var ephem = await Task.Run(() => sky.GetEphemerides( es.SelectedBody, es.JulianDayFrom, es.JulianDayTo, es.Step.TotalDays, es.Categories, tokenSource.Token, progress )); if (!tokenSource.IsCancellationRequested) { tokenSource.Cancel(); var vm = ViewManager.CreateViewModel <EphemerisVM>(); vm.SetData(es.SelectedBody, es.JulianDayFrom, es.JulianDayTo, es.Step, ephem); ViewManager.ShowWindow(vm); } } }
private void AddOrEditTrack(Track track) { var categories = sky.GetEphemerisCategories(track.Body); if (!(categories.Contains("Equatorial.Alpha") && categories.Contains("Equatorial.Delta"))) { throw new Exception($"Ephemeris provider for type {track.Body.GetType().Name} does not provide \"Equatorial.Alpha\" and \"Equatorial.Delta\" ephemeris."); } var positions = sky.GetEphemerides(track.Body, track.From, track.To, track.Step, new[] { "Equatorial.Alpha", "Equatorial.Delta" }); foreach (var eq in positions) { track.Points.Add(new CelestialPoint() { Equatorial0 = new CrdsEquatorial((double)eq[0].Value, (double)eq[1].Value) }); } int index = tracksProvider.Tracks.FindIndex(t => t.Id == track.Id); if (index > -1) { tracksProvider.Tracks[index] = track; } else { tracksProvider.Tracks.Add(track); } }
private void AddOrEditTrack(Track track) { var categories = sky.GetEphemerisCategories(track.Body); if (!(categories.Contains("Equatorial.Alpha") && categories.Contains("Equatorial.Delta"))) { throw new Exception($"Ephemeris provider for type {track.Body.GetType().Name} does not provide \"Equatorial.Alpha\" and \"Equatorial.Delta\" ephemeris."); } var positions = sky.GetEphemerides(track.Body, track.From, track.To + track.Step, track.Step, new[] { "Equatorial.Alpha", "Equatorial.Delta" }); foreach (var eq in positions) { track.Points.Add(new CelestialPoint() { Equatorial0 = new CrdsEquatorial(eq.GetValue <double>("Equatorial.Alpha"), eq.GetValue <double>("Equatorial.Delta")) }); } Track existing = trackCalc.Tracks.FirstOrDefault(t => t.Id == track.Id); if (existing != null) { int index = trackCalc.Tracks.IndexOf(existing); trackCalc.Tracks[index] = track; } else { trackCalc.Tracks.Add(track); } }
/// <summary> /// Calculates solar and lunar positions at five uniformly spaced times /// over a specified period centered at t0, where t0 is an integer hour of day /// nearest to the specified time instant of eclipse maximum. /// </summary> /// <param name="jdMaximum">Instant of eclipse maximum.</param> /// <param name="period">Period, in hours.</param> /// <returns></returns> private SunMoonPosition[] GetSunMoonPositions(double jdMaximum, double period) { // found t0 (nearest integer hour closest to the eclipse maximum) double t0; Date d = new Date(jdMaximum); if (d.Minute < 30) { t0 = jdMaximum - new TimeSpan(0, d.Minute, d.Second).TotalDays; } else { t0 = jdMaximum - new TimeSpan(0, d.Minute, d.Second).TotalDays + TimeSpan.FromHours(1).TotalDays; } // The Besselian elements are derived from a least-squares fit to elements // calculated at five uniformly spaced times over a period centered at t0. SunMoonPosition[] pos = new SunMoonPosition[5]; double dt = TimeSpan.FromHours(period / 2).TotalDays; double step = TimeSpan.FromHours(period / 4).TotalDays; string[] ephemerides = new[] { "Equatorial0.Alpha", "Equatorial0.Delta", "Distance" }; var sunEphem = sky.GetEphemerides(sun, t0 - dt, t0 + dt + 1e-6, step, ephemerides); var moonEphem = sky.GetEphemerides(moon, t0 - dt, t0 + dt + 1e-6, step, ephemerides); // astronomical unit, in km const double AU = 149597870; // earth radius, in km const double EARTH_RADIUS = 6371; for (int i = 0; i < 5; i++) { pos[i] = new SunMoonPosition() { JulianDay = t0 + step * (i - 2), Sun = new CrdsEquatorial(sunEphem[i].GetValue <double>("Equatorial0.Alpha"), sunEphem[i].GetValue <double>("Equatorial0.Delta")), Moon = new CrdsEquatorial(moonEphem[i].GetValue <double>("Equatorial0.Alpha"), moonEphem[i].GetValue <double>("Equatorial0.Delta")), DistanceSun = sunEphem[i].GetValue <double>("Distance") * AU / EARTH_RADIUS, DistanceMoon = moonEphem[i].GetValue <double>("Distance") / EARTH_RADIUS }; } return(pos); }
public double LunarPhaseAtMax(SkyContext ctx, Meteor m) { if (Moon == null) { Moon = sky.Search("Moon"); } return(Moon != null ? (double)sky.GetEphemerides(Moon, ctx, new[] { "Phase" }).First().Value : 0); }
private Ephemerides GetObservationDetails(PlanningFilter filter, SkyContext context, CelestialObject body, bool force = false) { float? magLimit = filter.MagLimit; double timeFrom = filter.TimeFrom / 24.0; double timeTo = filter.TimeTo / 24.0; double obsDuration = timeTo < timeFrom ? timeTo - timeFrom + 1 : timeTo - timeFrom; double?durationLimit = filter.DurationLimit != null ? filter.DurationLimit / 60.0 : null; // Planned observation range, expressed as circular sector (angles) // It represents a timeframe to be compared with each celestial body visibility conditions. AngleRange obsRange = new AngleRange(timeFrom * 360, obsDuration * 360); // Ephemerides for particular celestial body Ephemerides bodyEphemerides = new Ephemerides(body); // Ephemerides available for the body var categories = sky.GetEphemerisCategories(body); var visibilityEphems = sky.GetEphemerides(body, context, new[] { "Visibility.Begin", "Visibility.End", "Visibility.Duration", "RTS.Rise", "RTS.Transit", "RTS.Set", "RTS.RiseAzimuth", "RTS.TransitAltitude", "RTS.SetAzimuth", "Magnitude" }); bodyEphemerides.AddRange(visibilityEphems); // Body does not have magnitude if (!categories.Contains("Magnitude")) { if (!force && filter.SkipUnknownMagnitude) { return(null); } // Apply "skip unknown mag" filter bodyEphemerides.Add(new Ephemeris("Magnitude", null, Formatters.Magnitude)); } if (!force && filter.MagLimit != null) { float?mag = bodyEphemerides.GetValue <float?>("Magnitude"); // Apply magnitude filter if (mag > magLimit) { return(null); } } // If body has visibility ephemerides, it can be planned. if (categories.Contains("Visibility.Duration")) { double visDuration = visibilityEphems.GetValue <double>("Visibility.Duration"); if (visDuration > 0) { Date visBegin = visibilityEphems.GetValue <Date>("Visibility.Begin"); AngleRange visRange = new AngleRange(visBegin.Time * 360, visDuration / 24 * 360); var ranges = visRange.Overlaps(obsRange); if (ranges.Any()) { double beginTime = ranges.First().Start / 360; if (beginTime < timeFrom) { beginTime += 1; } double endTime = beginTime + ranges.First().Range / 360; // Begin of body observation, limited by desired observation begin and end time, // and expressed in Date Date bodyObsBegin = new Date(context.JulianDayMidnight + beginTime, context.GeoLocation.UtcOffset); // Real duration of body observation, limited by desired observation begin and end time, // and expressed in hours (convert from angle range expressed in degrees): double bodyObsDuration = ranges.First().Range / 360 * 24; // Apply duration filter if (!force && durationLimit > bodyObsDuration) { return(null); } // End of body observation, limited by desired observation begin and end time, // and expressed in Date Date bodyObsEnd = new Date(context.JulianDayMidnight + endTime, context.GeoLocation.UtcOffset); bodyEphemerides.Add(new Ephemeris("Observation.Begin", bodyObsBegin, Formatters.Time)); bodyEphemerides.Add(new Ephemeris("Observation.Duration", bodyObsDuration, Formatters.VisibilityDuration)); bodyEphemerides.Add(new Ephemeris("Observation.End", bodyObsEnd, Formatters.Time)); // best time of observation (in the expected time range) { var transit = visibilityEphems.GetValue <Date>("RTS.Transit"); var transitAlt = visibilityEphems.GetValue <double>("RTS.TransitAltitude"); AngleRange bodyObsRange = new AngleRange(bodyObsBegin.Time * 360, bodyObsDuration / 24 * 360); AngleRange tranRange = new AngleRange(transit.Time * 360, 1e-6); if (bodyObsRange.Overlaps(tranRange).Any()) { bodyEphemerides.Add(new Ephemeris("Observation.Best", transit, Formatters.Time)); bodyEphemerides.Add(new Ephemeris("Observation.BestAltitude", transitAlt, Formatters.Altitude)); bodyEphemerides.Add(new Ephemeris("Observation.BestAzimuth", 0.0, Formatters.Azimuth)); var ctxBest = new SkyContext(transit.ToJulianEphemerisDay(), context.GeoLocation, preferFast: true); var bestEphemerides = sky.GetEphemerides(body, ctxBest, new[] { "Equatorial.Alpha", "Equatorial.Delta", "Constellation" }); bodyEphemerides.AddRange(bestEphemerides); } else { var ctxBegin = new SkyContext(bodyObsBegin.ToJulianEphemerisDay(), context.GeoLocation, preferFast: true); var beginEphemerides = sky.GetEphemerides(body, ctxBegin, new[] { "Horizontal.Altitude", "Horizontal.Azimuth", "Equatorial.Alpha", "Equatorial.Delta", "Constellation" }); double altBegin = beginEphemerides.GetValue <double>("Horizontal.Altitude"); double aziBegin = beginEphemerides.GetValue <double>("Horizontal.Azimuth"); var ctxEnd = new SkyContext(bodyObsEnd.ToJulianEphemerisDay(), context.GeoLocation, preferFast: true); var endEphemerides = sky.GetEphemerides(body, ctxEnd, new[] { "Horizontal.Altitude", "Horizontal.Azimuth", "Equatorial.Alpha", "Equatorial.Delta", "Constellation" }); double altEnd = endEphemerides.GetValue <double>("Horizontal.Altitude"); double aziEnd = endEphemerides.GetValue <double>("Horizontal.Azimuth"); if (altBegin >= altEnd) { bodyEphemerides.Add(new Ephemeris("Observation.Best", bodyObsBegin, Formatters.Time)); bodyEphemerides.Add(new Ephemeris("Observation.BestAltitude", altBegin, Formatters.Altitude)); bodyEphemerides.Add(new Ephemeris("Observation.BestAzimuth", aziBegin, Formatters.Azimuth)); bodyEphemerides.AddRange(beginEphemerides); } else { bodyEphemerides.Add(new Ephemeris("Observation.Best", bodyObsEnd, Formatters.Time)); bodyEphemerides.Add(new Ephemeris("Observation.BestAltitude", altEnd, Formatters.Altitude)); bodyEphemerides.Add(new Ephemeris("Observation.BestAzimuth", aziEnd, Formatters.Azimuth)); bodyEphemerides.AddRange(endEphemerides); } } } return(bodyEphemerides); } } } // body observation duration does not match with desired time // or body does not observable at all, // or no info provided about observation if (force) { bodyEphemerides.Add(new Ephemeris("Observation.Begin", new Date(double.NaN), Formatters.Time)); bodyEphemerides.Add(new Ephemeris("Observation.Duration", double.NaN, Formatters.VisibilityDuration)); bodyEphemerides.Add(new Ephemeris("Observation.End", new Date(double.NaN), Formatters.Time)); bodyEphemerides.Add(new Ephemeris("Observation.Best", new Date(double.NaN), Formatters.Time)); bodyEphemerides.Add(new Ephemeris("Observation.BestAltitude", double.NaN, Formatters.Altitude)); bodyEphemerides.Add(new Ephemeris("Observation.BestAzimuth", double.NaN, Formatters.Azimuth)); bodyEphemerides.AddRange(visibilityEphems); var ctx = new SkyContext(filter.JulianDayMidnight, filter.ObserverLocation, preferFast: true); bodyEphemerides.AddRange(sky.GetEphemerides(body, ctx, new[] { "Horizontal.Altitude", "Horizontal.Azimuth", "Equatorial.Alpha", "Equatorial.Delta", "Constellation" })); // final check: add fictive/empty ephemerides as it needed by planner AddEphemIfMissing(bodyEphemerides, "Constellation", null); AddEphemIfMissing(bodyEphemerides, "Equatorial.Alpha", double.NaN); AddEphemIfMissing(bodyEphemerides, "Equatorial.Delta", double.NaN); AddEphemIfMissing(bodyEphemerides, "Horizontal.Altitude", double.NaN); AddEphemIfMissing(bodyEphemerides, "Horizontal.Azimuth", double.NaN); AddEphemIfMissing(bodyEphemerides, "Constellation", null); AddEphemIfMissing(bodyEphemerides, "RTS.RiseAzimuth", double.NaN); AddEphemIfMissing(bodyEphemerides, "RTS.SetAzimuth", double.NaN); AddEphemIfMissing(bodyEphemerides, "RTS.TransitAltitude", double.NaN); return(bodyEphemerides); } return(null); }