diff --git a/map/extrapolation/extrapolator.cpp b/map/extrapolation/extrapolator.cpp index cd4e7178f2..b70f412cbb 100644 --- a/map/extrapolation/extrapolator.cpp +++ b/map/extrapolation/extrapolator.cpp @@ -100,20 +100,20 @@ bool AreCoordsGoodForExtrapolation(location::GpsInfo const & beforeLastGpsInfo, Extrapolator::Extrapolator(ExtrapolatedLocationUpdateFn const & update) : m_isEnabled(false), m_extrapolatedLocationUpdate(update) { - GetPlatform().RunTask(Platform::Thread::Background, [this] - { - ExtrapolatedLocationUpdate(); - }); + RunTaskOnBackgroundThread(false /* delayed */); } void Extrapolator::OnLocationUpdate(location::GpsInfo const & gpsInfo) { - // @TODO Consider calling ExtrapolatedLocationUpdate() on background thread immediately - // after OnLocationUpdate() was called. - lock_guard guard(m_mutex); - m_beforeLastGpsInfo = m_lastGpsInfo; - m_lastGpsInfo = gpsInfo; - m_extrapolationCounter = 0; + { + lock_guard guard(m_mutex); + m_beforeLastGpsInfo = m_lastGpsInfo; + m_lastGpsInfo = gpsInfo; + m_extrapolationCounter = 0; + // Canceling all background tasks which are put to the queue before the task run in this method. + m_extrapolatedUpdateMinValid = m_extrapolatedUpdateCounter + 1; + } + RunTaskOnBackgroundThread(false /* delayed */); } void Extrapolator::Enable(bool enabled) @@ -122,11 +122,15 @@ void Extrapolator::Enable(bool enabled) m_isEnabled = enabled; } -void Extrapolator::ExtrapolatedLocationUpdate() +void Extrapolator::ExtrapolatedLocationUpdate(uint64_t extrapolatedUpdateCounter) { location::GpsInfo gpsInfo; { lock_guard guard(m_mutex); + // Canceling all calls of the method which were activated before |m_extrapolatedUpdateMinValid|. + if (extrapolatedUpdateCounter < m_extrapolatedUpdateMinValid) + return; + uint64_t const extrapolationTimeMs = kExtrapolationPeriodMs * m_extrapolationCounter; if (extrapolationTimeMs < kMaxExtrapolationTimeMs && m_lastGpsInfo.IsValid()) { @@ -154,11 +158,30 @@ void Extrapolator::ExtrapolatedLocationUpdate() ++m_extrapolationCounter; } - // Call ExtrapolatedLocationUpdate() every |kExtrapolationPeriodMs| milliseconds. - auto constexpr kSExtrapolationPeriod = std::chrono::milliseconds(kExtrapolationPeriodMs); - GetPlatform().RunDelayedTask(Platform::Thread::Background, kSExtrapolationPeriod, [this] + // Calling ExtrapolatedLocationUpdate() in |kExtrapolationPeriodMs| milliseconds. + RunTaskOnBackgroundThread(true /* delayed */); +} + +void Extrapolator::RunTaskOnBackgroundThread(bool delayed) +{ { - ExtrapolatedLocationUpdate(); + lock_guard guard(m_mutex); + ++m_extrapolatedUpdateCounter; + } + + auto const extrapolatedUpdateCounter = m_extrapolatedUpdateCounter; + if (delayed) + { + auto constexpr kSExtrapolationPeriod = std::chrono::milliseconds(kExtrapolationPeriodMs); + GetPlatform().RunDelayedTask(Platform::Thread::Background, kSExtrapolationPeriod, + [this, extrapolatedUpdateCounter] { + ExtrapolatedLocationUpdate(extrapolatedUpdateCounter); + }); + return; + } + + GetPlatform().RunTask(Platform::Thread::Background, [this, extrapolatedUpdateCounter] { + ExtrapolatedLocationUpdate(extrapolatedUpdateCounter); }); } diff --git a/map/extrapolation/extrapolator.hpp b/map/extrapolation/extrapolator.hpp index d0a71d6ff0..70cd6556af 100644 --- a/map/extrapolation/extrapolator.hpp +++ b/map/extrapolation/extrapolator.hpp @@ -48,7 +48,8 @@ private: /// \returns true if there's enough information for extrapolation and extrapolation is enabled. /// \note This method should be called only when |m_mutex| is locked. bool DoesExtrapolationWork() const; - void ExtrapolatedLocationUpdate(); + void ExtrapolatedLocationUpdate(uint64_t extrapolatedUpdateCounter); + void RunTaskOnBackgroundThread(bool delayed); bool m_isEnabled; @@ -57,5 +58,11 @@ private: location::GpsInfo m_lastGpsInfo; location::GpsInfo m_beforeLastGpsInfo; uint64_t m_extrapolationCounter = kExtrapolationCounterUndefined; + // Number of calls Extrapolator::RunTaskOnBackgroundThread() method. + uint64_t m_extrapolatedUpdateCounter = 0; + // If |m_extrapolatedUpdateCounter| < |m_extrapolatedUpdateMinValid| when + // ExtrapolatedLocationUpdate() is called (on background thread) + // ExtrapolatedLocationUpdate() cancels its execution. + uint64_t m_extrapolatedUpdateMinValid = 0; }; } // namespace extrapolation diff --git a/map/extrapolation_benchmark/extrapolation_benchmark.cpp b/map/extrapolation_benchmark/extrapolation_benchmark.cpp index d9fd187e56..0c83aaebb4 100644 --- a/map/extrapolation_benchmark/extrapolation_benchmark.cpp +++ b/map/extrapolation_benchmark/extrapolation_benchmark.cpp @@ -173,6 +173,7 @@ bool Parse(string const & pathToCsv, Tracks & tracks) void GpsPointToGpsInfo(GpsPoint const gpsPoint, GpsInfo & gpsInfo) { + gpsInfo = {}; gpsInfo.m_source = TLocationSource::EAppleNative; gpsInfo.m_timestamp = gpsPoint.m_timestampS; gpsInfo.m_latitude = gpsPoint.m_lat; @@ -268,14 +269,17 @@ int main(int argc, char * argv[]) GpsInfo const extrapolated = LinearExtrapolation(info1, info2, timeMs); m2::PointD const extrapolatedMerc = MercatorBounds::FromLatLon(extrapolated.m_latitude, extrapolated.m_longitude); - m2::RectD const posRect = MercatorBounds::MetresToXY( + // To generate |posSquare| the method below requires the size of half square in meters. + // This constant is chosen based on maximum value of GpsInfo::m_horizontalAccuracy + // which is used calculation of projection in production code. + m2::RectD const posSquare = MercatorBounds::MetresToXY( extrapolated.m_longitude, extrapolated.m_latitude, 100.0 /* half square in meters */); // Note 1. One is deducted from polyline size because in GetClosestProjectionInInterval() // is used segment indices but not point indices. // Note 2. Calculating projection of the center of |posRect| to polyline segments which // are inside of |posRect|. auto const & iter = followedPoly.GetClosestProjectionInInterval( - posRect, + posSquare, [&extrapolatedMerc](FollowedPolyline::Iter const & it) { return MercatorBounds::DistanceOnEarth(it.m_pt, extrapolatedMerc); },