void Flight::Reduce(const BrokenDateTime start, const BrokenDateTime end, const unsigned num_levels, const unsigned zoom_factor, const double threshold, const bool force_endpoints, const unsigned max_delta_time, const unsigned max_points) { // we need the whole flight, so read it now... if (!keep_flight) { ReadFlight(); keep_flight = true; } DouglasPeuckerMod dp(num_levels, zoom_factor, threshold, force_endpoints, max_delta_time, max_points); unsigned start_index = 0, end_index = 0; int64_t start_time = start.ToUnixTimeUTC(), end_time = end.ToUnixTimeUTC(); for (auto fix : *fixes) { if (BrokenDateTime(fix.date, fix.time).ToUnixTimeUTC() < start_time) start_index++; if (BrokenDateTime(fix.date, fix.time).ToUnixTimeUTC() < end_time) end_index++; else break; } end_index = std::min(end_index, unsigned(fixes->size())); start_index = std::min(start_index, end_index); dp.Encode(*fixes, start_index, end_index); }
bool NMEALogger::Start() { if (writer != nullptr) return true; BrokenDateTime dt = BrokenDateTime::NowUTC(); assert(dt.IsPlausible()); StaticString<64> name; name.Format(_T("%04u-%02u-%02u_%02u-%02u.nmea"), dt.year, dt.month, dt.day, dt.hour, dt.minute); const auto logs_path = MakeLocalPath(_T("logs")); const auto path = AllocatedPath::Build(logs_path, name); writer = new TextWriter(path, false); if (writer == nullptr) return false; if (!writer->IsOpen()) { delete writer; writer = nullptr; return false; } return true; }
Result() { takeoff_time.Clear(); landing_time.Clear(); release_time.Clear(); takeoff_location.SetInvalid(); landing_location.SetInvalid(); release_location.SetInvalid(); }
/** * Reinitialize phase */ void Clear() { phase_type = NO_PHASE; start_datetime.Clear(); end_datetime.Clear(); start_time = 0; end_time = 0; duration = 0; fraction = 0; circling_direction = NO_DIRECTION; alt_diff = 0; distance = 0; merges = 0; }
static void WriteEvent(JSON::ObjectWriter &object, const char *name, const BrokenDateTime &time, const GeoPoint &location) { if (time.IsPlausible() || location.IsValid()) object.WriteElement(name, WriteEventAttributes, time, location); }
fixed SunEphemeris::FNday(const BrokenDateTime &date_time) { assert(date_time.Plausible()); long int luku = -7 * (date_time.year + (date_time.month + 9) / 12) / 4 + 275 * date_time.month / 9 + date_time.day + (long int)date_time.year * 367; return fixed(luku) - fixed(730531.5) + fixed(date_time.hour % 24) / 24; }
static bool RawLoggerStart() { if (RawLoggerWriter != NULL) return true; BrokenDateTime dt = XCSoarInterface::Basic().DateTime; assert(dt.Plausible()); TCHAR path[MAX_PATH]; LocalPath(path, _T("logs")); unsigned len = _tcslen(path); _sntprintf(path+len, MAX_PATH-len, _T(DIR_SEPARATOR_S "%04u-%02u-%02u_%02u-%02u.nmea"), dt.year, dt.month, dt.day, dt.hour, dt.minute); RawLoggerWriter = new BatchTextWriter(path, false); return RawLoggerWriter != NULL; }
bool NMEALogger::Start() { if (writer != NULL) return true; BrokenDateTime dt = XCSoarInterface::Basic().date_time_utc; assert(dt.Plausible()); StaticString<64> name; name.Format(_T("%04u-%02u-%02u_%02u-%02u.nmea"), dt.year, dt.month, dt.day, dt.hour, dt.minute); TCHAR path[MAX_PATH]; LocalPath(path, _T("logs")); Directory::Create(path); LocalPath(path, _T("logs"), name); writer = new BatchTextWriter(path, false); return writer != NULL; }
void IGCWriter::WriteHeader(const BrokenDateTime &date_time, const TCHAR *pilot_name, const TCHAR *aircraft_model, const TCHAR *aircraft_registration, const TCHAR *competition_id, const char *logger_id, const TCHAR *driver_name, bool simulator) { /* * HFDTE141203 <- should be UTC, same as time in filename * HFFXA100 * HFPLTPILOT:JOHN WHARINGTON * HFGTYGLIDERTYPE:LS 3 * HFGIDGLIDERID:VH-WUE * HFDTM100GPSDATUM:WGS84 * HFRFWFIRMWAREVERSION:3.6 * HFRHWHARDWAREVERSION:3.4 * HFFTYFR TYPE:GARRECHT INGENIEURGESELLSCHAFT,VOLKSLOGGER 1.0 * HFCIDCOMPETITIONID:WUE * HFCCLCOMPETITIONCLASS:FAI */ assert(date_time.Plausible()); assert(logger_id != NULL); assert(strlen(logger_id) == 3); char buffer[100]; // Flight recorder ID number MUST go first.. sprintf(buffer, "AXCS%s", logger_id); WriteLine(buffer); sprintf(buffer, "HFDTE%02u%02u%02u", date_time.day, date_time.month, date_time.year % 100); WriteLine(buffer); if (!simulator) WriteLine(GetHFFXARecord()); WriteLine("HFPLTPILOT:", pilot_name); WriteLine("HFGTYGLIDERTYPE:", aircraft_model); WriteLine("HFGIDGLIDERID:", aircraft_registration); WriteLine("HFCIDCOMPETITIONID:", competition_id); WriteLine("HFFTYFRTYPE:XCSOAR,XCSOAR ", XCSoar_VersionStringOld); WriteLine("HFGPS:", driver_name); WriteLine("HFDTM100DATUM:WGS-84"); WriteLine(GetIRecord()); }
bool NMEALogger::Start() { if (writer != nullptr) return true; BrokenDateTime dt = BrokenDateTime::NowUTC(); assert(dt.IsPlausible()); StaticString<64> name; name.Format(_T("%04u-%02u-%02u_%02u-%02u.nmea"), dt.year, dt.month, dt.day, dt.hour, dt.minute); TCHAR path[MAX_PATH]; LocalPath(path, _T("logs")); Directory::Create(path); LocalPath(path, _T("logs"), name); writer = new TextWriter(path, false); return writer != nullptr; }
static void WriteEventAttributes(TextWriter &writer, const BrokenDateTime &time, const GeoPoint &location) { JSON::ObjectWriter object(writer); if (time.IsPlausible()) { NarrowString<64> buffer; FormatISO8601(buffer.buffer(), time); object.WriteElement("time", JSON::WriteString, buffer); } if (location.IsValid()) JSON::WriteGeoPointAttributes(object, location); }
void FormatIGCTaskTimestamp(char *buffer, const BrokenDateTime &date_time, unsigned number_of_turnpoints) { assert(date_time.IsPlausible()); sprintf(buffer, "C%02u%02u%02u%02u%02u%02u0000000000%02u", // DD MM YY HH MM SS DD MM YY IIII TT date_time.day, date_time.month, date_time.year % 100, date_time.hour, date_time.minute, date_time.second, number_of_turnpoints - 2); }
Angle SunEphemeris::CalcAzimuth(const GeoPoint &location, const BrokenDateTime &date_time, const fixed time_zone) { assert(date_time.Plausible()); fixed days_to_j2000 = FNday(date_time); Angle l = GetMeanSunLongitude(days_to_j2000); // Use GetEclipticLongitude to find the ecliptic longitude of the Sun Angle lambda = GetEclipticLongitude(days_to_j2000, l); // Obliquity of the ecliptic Angle obliquity = Angle::Degrees(fixed(23.439) - fixed(.0000004) * days_to_j2000); // Find the DEC of the Sun Angle delta = Angle::asin(obliquity.sin() * lambda.sin()); return CalculateAzimuth(location, date_time, time_zone, delta); }
void IGCWriter::StartDeclaration(const BrokenDateTime &date_time, const int number_of_turnpoints) { assert(date_time.Plausible()); // IGC GNSS specification 3.6.1 char buffer[100]; sprintf(buffer, "C%02u%02u%02u%02u%02u%02u0000000000%02d", // DD MM YY HH MM SS DD MM YY IIII TT date_time.day, date_time.month, date_time.year % 100, date_time.hour, date_time.minute, date_time.second, number_of_turnpoints - 2); WriteLine(buffer); // takeoff line // IGC GNSS specification 3.6.3 WriteLine("C0000000N00000000ETAKEOFF"); }
int BrokenDateTime::operator-(const BrokenDateTime &other) const { return ToUnixTimeUTC() - other.ToUnixTimeUTC(); }
SunEphemeris::Result SunEphemeris::CalcSunTimes(const GeoPoint &location, const BrokenDateTime &date_time, const fixed time_zone) { Result result; assert(date_time.Plausible()); fixed days_to_j2000 = FNday(date_time); Angle l = GetMeanSunLongitude(days_to_j2000); // Use GetEclipticLongitude to find the ecliptic longitude of the Sun Angle lambda = GetEclipticLongitude(days_to_j2000, l); // Obliquity of the ecliptic Angle obliquity = Angle::Degrees(fixed(23.439) - fixed(.0000004) * days_to_j2000); // Find the RA and DEC of the Sun Angle alpha = Angle::FromXY(lambda.cos(), obliquity.cos() * lambda.sin()); Angle delta = Angle::asin(obliquity.sin() * lambda.sin()); // Find the Equation of Time in minutes // Correction suggested by David Smith fixed ll = (l - alpha).Radians(); if (l.Radians() < fixed_pi) ll += fixed_two_pi; fixed equation = fixed(1440) * (fixed(1) - ll / fixed_two_pi); Angle hour_angle = GetHourAngle(location.latitude, delta); Angle hour_angle_twilight = GetHourAngleTwilight(location.latitude, delta); result.azimuth = CalculateAzimuth(location, date_time, time_zone, delta); // length of twilight in hours fixed twilight_hours = (hour_angle_twilight - hour_angle).Hours(); // Conversion of angle to hours and minutes result.day_length = Double(hour_angle.Hours()); if (result.day_length < fixed(0.0001)) // arctic winter result.day_length = fixed(0); result.time_of_sunrise = fixed(12) - hour_angle.Hours() + time_zone - location.longitude.Degrees() / 15 + equation / 60; if (result.time_of_sunrise > fixed(24)) result.time_of_sunrise -= fixed(24); result.time_of_sunset = result.time_of_sunrise + result.day_length; result.time_of_noon = result.time_of_sunrise + hour_angle.Hours(); // morning twilight begin result.morning_twilight = result.time_of_sunrise - twilight_hours; // evening twilight end result.evening_twilight = result.time_of_sunset + twilight_hours; return result; }
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(); }