#pragma once #include #include namespace roro::gnss { // Great-circle distance in metres (haversine, mean Earth radius). double distanceMeters(double lat1, double lon1, double lat2, double lon2); // When a Track takes its next point (Q63): the first one always, then at least every 5 s and only // after moving at least 5 m, so standing still doesn't fill the card. class TrackRule { public: static constexpr uint32_t kEveryMs = 5000; static constexpr double kMinMeters = 5.0; // True if this position should be recorded (and is then remembered as the last point). bool due(uint32_t nowMs, double lat, double lon); void reset() { any_ = false; } private: bool any_ = false; uint32_t lastMs_ = 0; double lat_ = 0, lon_ = 0; }; // "/gnss/tracks/YYYYMMDD-HHMMSS.gpx", from the UTC start time (Storage Clean-up reads its date). std::string trackPath(int64_t utcSeconds); // GPX 1.1, written a line at a time: the header when a Track starts, a point per line, the footer // when it stops. A file whose footer never came (power lost) is closed at the next boot. namespace gpx { std::string header(const std::string& name); std::string point(double lat, double lon, bool hasElevation, float elevationM, int64_t utcSeconds); std::string footer(); bool finished(const std::string& tail); // the end of a file: does it close the GPX? } // namespace gpx } // namespace roro::gnss