diff --git a/libs/map/bookmark_manager.cpp b/libs/map/bookmark_manager.cpp index 30d54ef55..0a404cf80 100644 --- a/libs/map/bookmark_manager.cpp +++ b/libs/map/bookmark_manager.cpp @@ -1096,7 +1096,7 @@ kml::CompilationType BookmarkManager::GetCompilationType(kml::MarkGroupId id) co kml::TrackId BookmarkManager::SaveTrackRecording(std::string trackName) { CHECK_THREAD_CHECKER(m_threadChecker, ()); - auto const & tracker = GpsTracker::Instance(); + auto & tracker = GpsTracker::Instance(); CHECK(!tracker.IsEmpty(), ("Track recording should be not be empty")); kml::MultiGeometry geometry; @@ -1104,11 +1104,12 @@ kml::TrackId BookmarkManager::SaveTrackRecording(std::string trackName) geometry.m_timestamps.emplace_back(); auto & line = geometry.m_lines.back(); auto & timestamps = geometry.m_timestamps.back(); - auto const trackSize = tracker.GetTrackSize(); + + auto const trackSize = tracker.Finalize(); line.reserve(trackSize); timestamps.reserve(trackSize); - tracker.ForEachTrackPoint([&line, ×tamps](location::GpsInfo const & pt, size_t id) -> bool + tracker.ForEachTrackPoint([&line, ×tamps](location::GpsInfo const & pt, size_t id) { line.emplace_back(mercator::FromLatLon(pt.m_latitude, pt.m_longitude), pt.m_altitude); timestamps.emplace_back(pt.m_timestamp); diff --git a/libs/map/gps_track.cpp b/libs/map/gps_track.cpp index 1c13b724c..b39577d89 100644 --- a/libs/map/gps_track.cpp +++ b/libs/map/gps_track.cpp @@ -3,36 +3,7 @@ #include "base/assert.hpp" #include "base/logging.hpp" -#include - using namespace std; -using namespace std::chrono; - -namespace gps_track -{ - -inline pair UnionRanges(pair const & a, pair const & b) -{ - if (a.first == GpsTrack::kInvalidId) - { - ASSERT_EQUAL(a.second, GpsTrack::kInvalidId, ()); - return b; - } - if (b.first == GpsTrack::kInvalidId) - { - ASSERT_EQUAL(b.second, GpsTrack::kInvalidId, ()); - return a; - } - ASSERT_LESS_OR_EQUAL(a.first, a.second, ()); - ASSERT_LESS_OR_EQUAL(b.first, b.second, ()); - return make_pair(min(a.first, b.first), max(a.second, b.second)); -} - -size_t constexpr kItemBlockSize = 1000; - -} // namespace gps_track - -size_t const GpsTrack::kInvalidId = GpsTrackCollection::kInvalidId; GpsTrack::GpsTrack(string const & filePath, unique_ptr && filter) : m_filePath(filePath) @@ -99,12 +70,6 @@ void GpsTrack::Clear() ScheduleTask(); } -size_t GpsTrack::GetSize() const -{ - CHECK(m_collection != nullptr, ()); - return m_collection->GetSize(); -} - bool GpsTrack::IsEmpty() const { if (!m_collection) @@ -126,6 +91,7 @@ void GpsTrack::ScheduleTask() { lock_guard lg(m_threadGuard); + /// @todo Replace with !m_thread.joinable() ? if (m_thread.get_id() == std::thread::id()) { m_thread = threads::SimpleThread([this]() @@ -133,11 +99,16 @@ void GpsTrack::ScheduleTask() unique_lock ul(m_threadGuard); while (true) { - m_cv.wait(ul, [this]() -> bool { return m_threadExit || m_threadWakeup; }); + m_cv.wait(ul, [this]() { return m_threadExit || m_threadWakeup; }); + + if (m_threadWakeup) + { + m_threadWakeup = false; + ProcessPoints(); + } + if (m_threadExit) break; - m_threadWakeup = false; - ProcessPoints(); } m_storage.reset(); @@ -179,7 +150,7 @@ void GpsTrack::InitCollection() // and filtered points are inserted in the runtime collection. vector originPoints; - originPoints.reserve(gps_track::kItemBlockSize); + originPoints.reserve(GpsTrackStorage::kItemBlockSize); m_storage->ForEach([this, &originPoints](location::GpsInfo const & originPoint) -> bool { @@ -239,13 +210,35 @@ void GpsTrack::ProcessPoints() vector points; m_filter->Process(originPoints, points); - pair addedIds; - pair evictedIds; + pair addedIds, evictedIds; UpdateCollection(needClear, points, addedIds, evictedIds); NotifyCallback(addedIds, evictedIds); } +size_t GpsTrack::Finalize() +{ + if (m_thread.joinable()) + { + { + lock_guard lg(m_threadGuard); + m_threadWakeup = true; + m_threadExit = true; + m_cv.notify_one(); + } + m_thread.join(); + m_thread = {}; + } + + vector points; + m_filter->Finalize(points); + + if (!points.empty()) + m_collection->Add(points); + + return m_collection->GetSize(); +} + bool GpsTrack::HasCallback() { lock_guard lg(m_callbackGuard); diff --git a/libs/map/gps_track.hpp b/libs/map/gps_track.hpp index fb29c4ae1..493ee0c14 100644 --- a/libs/map/gps_track.hpp +++ b/libs/map/gps_track.hpp @@ -11,13 +11,12 @@ #include #include #include -#include #include class GpsTrack final { public: - static size_t const kInvalidId; // = numeric_limits::max(); + static size_t constexpr kInvalidId = GpsTrackCollection::kInvalidId; /// @param filePath - path to the file on disk to persist track /// @param filter - filter object used for filtering points, GpsTrackNullFilter is created by default @@ -40,7 +39,6 @@ public: void Clear(); bool IsEmpty() const; - size_t GetSize() const; /// Notification callback about a change of the gps track. /// @param toAdd - collection of points and ids to add. @@ -57,10 +55,13 @@ public: /// next time callbacks it receives only modifications. It simplifies getter/callback model. void SetCallback(TGpsTrackDiffCallback callback); - template - void ForEachPoint(F && f) const + size_t Finalize(); + + /// @pre Finalize should be called before. + template + void ForEachPoint(FnT && fn) { - m_collection->ForEach(std::move(f)); + m_collection->ForEach(fn); } private: diff --git a/libs/map/gps_track_collection.cpp b/libs/map/gps_track_collection.cpp index 9ed3c0b43..0716e6673 100644 --- a/libs/map/gps_track_collection.cpp +++ b/libs/map/gps_track_collection.cpp @@ -2,8 +2,6 @@ #include "base/assert.hpp" -#include - namespace { @@ -27,8 +25,6 @@ private: } // namespace -size_t const GpsTrackCollection::kInvalidId = std::numeric_limits::max(); - GpsTrackCollection::GpsTrackCollection() : m_lastId(0), m_elevationInfoDirty(true) {} std::pair GpsTrackCollection::Add(std::vector const & items) diff --git a/libs/map/gps_track_collection.hpp b/libs/map/gps_track_collection.hpp index 7026a7d9d..f582b65fe 100644 --- a/libs/map/gps_track_collection.hpp +++ b/libs/map/gps_track_collection.hpp @@ -7,13 +7,12 @@ #include #include -#include #include class GpsTrackCollection final { public: - static size_t const kInvalidId; // = numeric_limits::max(); + static size_t constexpr kInvalidId = std::numeric_limits::max(); using TItem = location::GpsInfo; diff --git a/libs/map/gps_track_filter.cpp b/libs/map/gps_track_filter.cpp index 67c08971e..b68f12622 100644 --- a/libs/map/gps_track_filter.cpp +++ b/libs/map/gps_track_filter.cpp @@ -9,7 +9,7 @@ namespace { -char const kMinHorizontalAccuracyKey[] = "GpsTrackingMinAccuracy"; +std::string_view constexpr kMinHorizontalAccuracyKey = "GpsTrackingMinAccuracy"; // Minimal horizontal accuracy is required to skip 'bad' points. // Use 250 meters to allow points from a pure GPS + GPS through wifi. @@ -56,8 +56,7 @@ GpsTrackFilter::GpsTrackFilter() settings::TryGet(kMinHorizontalAccuracyKey, m_minAccuracy); } -void GpsTrackFilter::Process(std::vector const & inPoints, - std::vector & outPoints) +void GpsTrackFilter::Process(GpsVectorT const & inPoints, GpsVectorT & outPoints) { outPoints.reserve(inPoints.size()); @@ -88,6 +87,20 @@ void GpsTrackFilter::Process(std::vector const & inPoints, } } +void GpsTrackFilter::Finalize(GpsVectorT & outPoints) +{ + if (m_countLastInfo > 0) + { + // Force append the last point, if wasn't added before. + auto const & info = GetLastInfo(); + if (m_countAcceptedInfo == 0 || info.m_timestamp > GetLastAcceptedInfo().m_timestamp) + { + outPoints.push_back(info); + AddLastAcceptedInfo(info); + } + } +} + bool GpsTrackFilter::IsGoodVector(location::GpsInfo const & info) const { ASSERT_GREATER(m_countLastInfo, 1, ()); diff --git a/libs/map/gps_track_filter.hpp b/libs/map/gps_track_filter.hpp index 1308eeb6d..65028ab50 100644 --- a/libs/map/gps_track_filter.hpp +++ b/libs/map/gps_track_filter.hpp @@ -9,14 +9,16 @@ class IGpsTrackFilter public: virtual ~IGpsTrackFilter() = default; - virtual void Process(std::vector const & inPoints, std::vector & outPoints) = 0; + using GpsVectorT = std::vector; + virtual void Process(GpsVectorT const & inPoints, GpsVectorT & outPoints) = 0; + virtual void Finalize(GpsVectorT & outPoints) {} }; class GpsTrackNullFilter : public IGpsTrackFilter { public: // IGpsTrackFilter overrides - void Process(std::vector const & inPoints, std::vector & outPoints) override; + void Process(GpsVectorT const & inPoints, GpsVectorT & outPoints) override; }; class GpsTrackFilter : public IGpsTrackFilter @@ -28,7 +30,8 @@ public: GpsTrackFilter(); // IGpsTrackFilter overrides - void Process(std::vector const & inPoints, std::vector & outPoints) override; + void Process(GpsVectorT const & inPoints, GpsVectorT & outPoints) override; + void Finalize(GpsVectorT & outPoints) override; private: bool IsGoodPoint(location::GpsInfo const & info) const; diff --git a/libs/map/gps_track_storage.cpp b/libs/map/gps_track_storage.cpp index d547eebe1..31b92dd72 100644 --- a/libs/map/gps_track_storage.cpp +++ b/libs/map/gps_track_storage.cpp @@ -1,13 +1,12 @@ #include "map/gps_track_storage.hpp" #include "coding/endianness.hpp" -#include "coding/internal/file_data.hpp" #include "base/assert.hpp" #include "base/logging.hpp" #include -#include +#include // for memcpy using namespace std; @@ -20,9 +19,6 @@ uint32_t constexpr kCurrentVersion = 1; // Header size in bytes, header consists of uint32_t 'version' only uint32_t constexpr kHeaderSize = sizeof(uint32_t); -// Number of items for batch processing -size_t constexpr kItemBlockSize = 1000; - // TODO // Now GpsInfo written as plain values, but values can be compressed. diff --git a/libs/map/gps_track_storage.hpp b/libs/map/gps_track_storage.hpp index 5f3dc7896..fd83bc266 100644 --- a/libs/map/gps_track_storage.hpp +++ b/libs/map/gps_track_storage.hpp @@ -17,6 +17,9 @@ public: DECLARE_EXCEPTION(WriteException, RootException); DECLARE_EXCEPTION(ReadException, RootException); + // Number of items for batch processing. + static size_t constexpr kItemBlockSize = 1000; + using TItem = location::GpsInfo; /// Opens storage with track data. diff --git a/libs/map/gps_tracker.cpp b/libs/map/gps_tracker.cpp index ca7a17fa8..da29ebfdd 100644 --- a/libs/map/gps_tracker.cpp +++ b/libs/map/gps_tracker.cpp @@ -1,20 +1,16 @@ #include "map/gps_tracker.hpp" -#include "map/framework.hpp" #include "platform/platform.hpp" +#include "platform/settings.hpp" #include "base/file_name_utils.hpp" -#include - #include "defines.hpp" -using namespace std::chrono; - namespace { -char const kEnabledKey[] = "GpsTrackingEnabled"; +std::string_view constexpr kEnabledKey = "GpsTrackingEnabled"; inline std::string GetFilePath() { @@ -72,11 +68,6 @@ bool GpsTracker::IsEmpty() const return m_track.IsEmpty(); } -size_t GpsTracker::GetTrackSize() const -{ - return m_track.GetSize(); -} - TrackStatistics GpsTracker::GetTrackStatistics() const { return m_track.GetTrackStatistics(); @@ -103,9 +94,3 @@ void GpsTracker::OnLocationUpdated(location::GpsInfo const & info) return; m_track.AddPoint(info); } - -void GpsTracker::ForEachTrackPoint(GpsTrackCallback const & callback) const -{ - CHECK(callback != nullptr, ("Callback should be provided")); - m_track.ForEachPoint(callback); -} diff --git a/libs/map/gps_tracker.hpp b/libs/map/gps_tracker.hpp index 05f98269f..f0b5cdf36 100644 --- a/libs/map/gps_tracker.hpp +++ b/libs/map/gps_tracker.hpp @@ -4,7 +4,6 @@ #include #include -#include #include class GpsTracker @@ -17,7 +16,7 @@ public: void Clear(); bool IsEmpty() const; - size_t GetTrackSize() const; + TrackStatistics GetTrackStatistics() const; ElevationInfo const & GetElevationInfo() const; @@ -30,8 +29,14 @@ public: void OnLocationUpdated(location::GpsInfo const & info); - using GpsTrackCallback = std::function; - void ForEachTrackPoint(GpsTrackCallback const & callback) const; + size_t Finalize() { return m_track.Finalize(); } + + /// @pre Finalize should be called before. + template + void ForEachTrackPoint(FnT && fn) + { + m_track.ForEachPoint(fn); + } private: GpsTracker();