static void Run(DebugReplay &replay, Result &result, Trace &full_trace, Trace &triangle_trace, Trace &sprint_trace) { CirclingSettings circling_settings; circling_settings.SetDefaults(); bool released = false; GeoPoint last_location = GeoPoint::Invalid(); constexpr Angle max_longitude_change = Angle::Degrees(30); constexpr Angle max_latitude_change = Angle::Degrees(1); while (replay.Next()) { ComputeCircling(replay, circling_settings); const MoreData &basic = replay.Basic(); Update(basic, replay.Calculated(), result); flight_phase_detector.Update(replay.Basic(), replay.Calculated()); if (!basic.time_available || !basic.location_available || !basic.NavAltitudeAvailable()) continue; if (last_location.IsValid() && ((last_location.latitude - basic.location.latitude).Absolute() > max_latitude_change || (last_location.longitude - basic.location.longitude).Absolute() > max_longitude_change)) /* there was an implausible warp, which is usually triggered by an invalid point declared "valid" by a bugged logger; if that happens, we stop the analysis, because the IGC file is obviously broken */ break; last_location = basic.location; if (!released && !negative(replay.Calculated().flight.release_time)) { released = true; full_trace.EraseEarlierThan(replay.Calculated().flight.release_time); triangle_trace.EraseEarlierThan(replay.Calculated().flight.release_time); sprint_trace.EraseEarlierThan(replay.Calculated().flight.release_time); } if (released && !replay.Calculated().flight.flying) /* the aircraft has landed, stop here */ /* TODO: at some point, we might want to emit the analysis of all flights in this IGC file */ break; const TracePoint point(basic); full_trace.push_back(point); triangle_trace.push_back(point); sprint_trace.push_back(point); } Update(replay.Basic(), replay.Calculated(), result); Finish(replay.Basic(), replay.Calculated(), result); flight_phase_detector.Finish(); }
int main(int argc, char **argv) { Args args(argc, argv, "DRIVER FILE"); DebugReplay *replay = CreateDebugReplay(args); if (replay == NULL) return EXIT_FAILURE; args.ExpectEnd(); Result result; Run(*replay, result); delete replay; const ContestStatistics olc_plus = SolveContest(Contest::OLC_PLUS); const ContestStatistics dmst = SolveContest(Contest::DMST); TextWriter writer("/dev/stdout", true); { JSON::ObjectWriter root(writer); WriteResult(root, result); root.WriteElement("phases", WritePhaseList, flight_phase_detector.GetPhases()); root.WriteElement("performance", WritePerformanceStats, flight_phase_detector.GetTotals()); root.WriteElement("contests", WriteContests, olc_plus, dmst); } }
void Run(DebugReplay &replay, FlightPhaseDetector &flight_phase_detector, WindList &wind_list, const BrokenDateTime &takeoff_time, const BrokenDateTime &scoring_start_time, const BrokenDateTime &scoring_end_time, const BrokenDateTime &landing_time, Trace &full_trace, Trace &triangle_trace, Trace &sprint_trace, ComputerSettings &computer_settings) { GeoPoint last_location = GeoPoint::Invalid(); constexpr Angle max_longitude_change = Angle::Degrees(30); constexpr Angle max_latitude_change = Angle::Degrees(1); CirclingSettings circling_settings; circling_settings.SetDefaults(); CirclingComputer circling_computer; circling_computer.Reset(); GlidePolar glide_polar(0); WindSettings wind_settings; wind_settings.SetDefaults(); WindComputer wind_computer; wind_computer.Reset(); Validity last_wind; last_wind.Clear(); const Waypoints waypoints; AutoQNH auto_qnh(5); auto_qnh.Reset(); const int64_t takeoff_unix = takeoff_time.ToUnixTimeUTC(); const int64_t landing_unix = landing_time.ToUnixTimeUTC(); int64_t scoring_start_unix, scoring_end_unix; if (scoring_start_time.IsPlausible()) scoring_start_unix = scoring_start_time.ToUnixTimeUTC(); else scoring_start_unix = std::numeric_limits<int64_t>::max(); if (scoring_end_time.IsPlausible()) scoring_end_unix = scoring_end_time.ToUnixTimeUTC(); else scoring_end_unix = 0; while (replay.Next()) { const MoreData &basic = replay.Basic(); const int64_t date_time_utc = basic.date_time_utc.ToUnixTimeUTC(); if (date_time_utc < takeoff_unix) continue; if (date_time_utc > landing_unix) break; circling_computer.TurnRate(replay.SetCalculated(), replay.Basic(), replay.Calculated().flight); circling_computer.Turning(replay.SetCalculated(), replay.Basic(), replay.Calculated().flight, circling_settings); flight_phase_detector.Update(replay.Basic(), replay.Calculated()); wind_computer.Compute(wind_settings, glide_polar, basic, replay.SetCalculated()); if (replay.Calculated().estimated_wind_available.Modified(last_wind)) { wind_list.push_back(WindListItem(basic.date_time_utc, basic.gps_altitude, replay.Calculated().estimated_wind)); } last_wind = replay.Calculated().estimated_wind_available; auto_qnh.Process(basic, replay.SetCalculated(), computer_settings, waypoints); if (!computer_settings.pressure_available && replay.Calculated().pressure_available) { computer_settings.pressure = replay.Calculated().pressure; computer_settings.pressure_available = replay.Calculated().pressure_available; } if (!basic.time_available || !basic.location_available || !basic.NavAltitudeAvailable()) continue; if (last_location.IsValid() && ((last_location.latitude - basic.location.latitude).Absolute() > max_latitude_change || (last_location.longitude - basic.location.longitude).Absolute() > max_longitude_change)) /* there was an implausible warp, which is usually triggered by an invalid point declared "valid" by a bugged logger; if that happens, we stop the analysis, because the IGC file is obviously broken */ break; last_location = basic.location; if (date_time_utc >= scoring_start_unix && date_time_utc <= scoring_end_unix) { const TracePoint point(basic); full_trace.push_back(point); triangle_trace.push_back(point); sprint_trace.push_back(point); } } flight_phase_detector.Finish(); }
int main(int argc, char **argv) { unsigned full_max_points = 512, triangle_max_points = 1024, sprint_max_points = 64; Args args(argc, argv, "[options] DRIVER FILE\n" "Options:\n" " --full-points=512 Maximum number of full trace points (default = 512)\n" " --triangle-points=1024 Maximum number of triangle trace points (default = 1024)\n" " --sprint-points=64 Maximum number of sprint trace points (default = 64)"); const char *arg; while ((arg = args.PeekNext()) != nullptr && *arg == '-') { args.Skip(); const char *value; if ((value = StringAfterPrefix(arg, "--full-points=")) != nullptr) { unsigned _points = strtol(value, NULL, 10); if (_points > 0) full_max_points = _points; else { fputs("The start parameter could not be parsed correctly.\n", stderr); args.UsageError(); } } else if ((value = StringAfterPrefix(arg, "--triangle-points=")) != nullptr) { unsigned _points = strtol(value, NULL, 10); if (_points > 0) triangle_max_points = _points; else { fputs("The start parameter could not be parsed correctly.\n", stderr); args.UsageError(); } } else if ((value = StringAfterPrefix(arg, "--sprint-points=")) != nullptr) { unsigned _points = strtol(value, NULL, 10); if (_points > 0) sprint_max_points = _points; else { fputs("The start parameter could not be parsed correctly.\n", stderr); args.UsageError(); } } else { args.UsageError(); } } DebugReplay *replay = CreateDebugReplay(args); if (replay == NULL) return EXIT_FAILURE; args.ExpectEnd(); static Trace full_trace(0, Trace::null_time, full_max_points); static Trace triangle_trace(0, Trace::null_time, triangle_max_points); static Trace sprint_trace(0, 9000, sprint_max_points); Result result; Run(*replay, result, full_trace, triangle_trace, sprint_trace); delete replay; const ContestStatistics olc_plus = SolveContest(Contest::OLC_PLUS, full_trace, triangle_trace, sprint_trace); const ContestStatistics dmst = SolveContest(Contest::DMST, full_trace, triangle_trace, sprint_trace); TextWriter writer("/dev/stdout", true); { JSON::ObjectWriter root(writer); WriteResult(root, result); root.WriteElement("phases", WritePhaseList, flight_phase_detector.GetPhases()); root.WriteElement("performance", WritePerformanceStats, flight_phase_detector.GetTotals()); root.WriteElement("contests", WriteContests, olc_plus, dmst); } }