private void AddEphemIfMissing(Ephemerides bodyEphemerides, string key, object value) { if (!bodyEphemerides.Select(e => e.Key).Contains(key)) { bodyEphemerides.Add(new Ephemeris(key, value, Formatters.GetDefault(key))); } }
// TODO: add ability to specify location and preferFast flag public List <Ephemerides> GetEphemerides(CelestialObject body, double from, double to, double step, IEnumerable <string> categories, CancellationToken?cancelToken = null, IProgress <double> progress = null) { List <Ephemerides> all = new List <Ephemerides>(); var config = EphemConfigs[body.GetType()]; var itemsToBeCalled = config.Filter(categories); for (double jd = from; jd < to; jd += step) { if (cancelToken != null && cancelToken.Value.IsCancellationRequested) { break; } else { progress?.Report((jd - from) / (to - from) * 100); } var context = new SkyContext(jd, Context.GeoLocation); Ephemerides ephemerides = new Ephemerides(body); foreach (var item in itemsToBeCalled) { ephemerides.Add(new Ephemeris(item.Category, item.Formula.DynamicInvoke(context, body), item.Formatter ?? Formatters.GetDefault(item.Category))); } all.Add(ephemerides); } return(all); }
public Ephemerides GetEphemerides(CelestialObject body, SkyContext context, IEnumerable <string> categories) { var config = EphemConfigs[body.GetType()]; var itemsToBeCalled = config.Filter(categories); Ephemerides ephemerides = new Ephemerides(body); foreach (var item in itemsToBeCalled) { ephemerides.Add(new Ephemeris(item.Category, item.Formula.DynamicInvoke(context, body), item.Formatter ?? Formatters.GetDefault(item.Category))); } return(ephemerides); }
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); }