diff --git a/map/framework.cpp b/map/framework.cpp index 806d6fef34..763616f4dd 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -1818,7 +1818,6 @@ bool Framework::GetGuideInfo(TIndex const & index, guides::GuideInfo & info) con return m_storage.GetGuideManager().GetGuideInfo(m_storage.CountryFileName(index), info); } -///////////////////////////// ROUTING ///////////////////////////////////////////////// bool Framework::IsRoutingActive() const { @@ -1908,24 +1907,13 @@ void Framework::CheckLocationForRouting(GpsInfo const & info) if (!IsRoutingActive()) return; - shared_ptr const & state = GetLocationState(); - m2::PointD const & position = state->Position(); - - switch (m_routingSession.OnLocationPositionChanged(position, state->GetErrorRadius())) + m2::PointD const & position = GetLocationState()->Position(); + if (m_routingSession.OnLocationPositionChanged(position, info) == RoutingSession::RouteLeft) { - case RoutingSession::RouteLeft: m_routingSession.RebuildRoute(position, [this] (Route const & route, routing::IRouter::ResultCode e) { InsertRoute(route); }); - break; - - case RoutingSession::OnRoute: - m_routingSession.MoveRoutePosition(position, info); - break; - - default: - break; } } diff --git a/map/routing_session.cpp b/map/routing_session.cpp index 4789ff7706..0bf94d3213 100644 --- a/map/routing_session.cpp +++ b/map/routing_session.cpp @@ -9,11 +9,14 @@ using namespace location; namespace routing { +static int const ON_ROUTE_MISSED_COUNT = 10; + + RoutingSession::RoutingSession() : m_router(nullptr) , m_route(string()) , m_state(RoutingNotActive) - , m_lastMinDist(0.0) + , m_lastDistance(0.0) { } @@ -31,10 +34,6 @@ void RoutingSession::RebuildRoute(m2::PointD const & startPoint, ReadyCallback c Reset(); m_state = RouteNotReady; - m2::RectD const errorRect = MercatorBounds::RectByCenterXYAndSizeInMeters( - startPoint, Route::GetOnRoadTolerance()); - m_tolerance = (errorRect.SizeX() + errorRect.SizeY()) / 2.0; - m_router->CalculateRoute(startPoint, [&] (Route & route, IRouter::ResultCode e) { AssignRoute(route); @@ -44,18 +43,18 @@ void RoutingSession::RebuildRoute(m2::PointD const & startPoint, ReadyCallback c bool RoutingSession::IsActive() const { - return m_state != RoutingNotActive; + return (m_state != RoutingNotActive); } void RoutingSession::Reset() { m_state = RoutingNotActive; - m_lastMinDist = 0.0; + m_lastDistance = 0.0; Route(string()).Swap(m_route); } RoutingSession::State RoutingSession::OnLocationPositionChanged(m2::PointD const & position, - double errorRadius) + GpsInfo const & info) { ASSERT(m_state != RoutingNotActive, ()); ASSERT(m_router != nullptr, ()); @@ -63,48 +62,45 @@ RoutingSession::State RoutingSession::OnLocationPositionChanged(m2::PointD const if (m_state == RouteNotReady || m_state == RouteLeft || m_state == RouteFinished) return m_state; - if (IsOnDestPoint(position, errorRadius)) - m_state = RouteFinished; + ASSERT(m_route.IsValid(), ()); + + if (m_route.MoveIterator(position, info)) + { + m_moveAwayCounter = 0; + m_lastDistance = 0.0; + + if (m_route.IsCurrentOnEnd()) + m_state = RouteFinished; + else + m_state = OnRoute; + } else { - double currentDist = 0.0; - if (IsOnRoute(position, errorRadius, currentDist)) + // distance from the last known projection on route + double const dist = m_route.GetCurrentSqDistance(position); + if (dist > m_lastDistance) { - m_state = OnRoute; - m_moveAwayCounter = 0; - m_lastMinDist = 0.0; + ++m_moveAwayCounter; + m_lastDistance = dist; } else { - if (currentDist > m_lastMinDist) - { - ++m_moveAwayCounter; - m_lastMinDist = currentDist; - } - else - { - m_moveAwayCounter = 0; - m_lastMinDist = 0.0; - } - - if (m_moveAwayCounter > 10) - m_state = RouteLeft; + m_moveAwayCounter = 0; + m_lastDistance = 0.0; } + + if (m_moveAwayCounter > ON_ROUTE_MISSED_COUNT) + m_state = RouteLeft; } return m_state; } -void RoutingSession::MoveRoutePosition(m2::PointD const & position, GpsInfo const & info) -{ - ASSERT_EQUAL(m_state, OnRoute, ()); - m_route.MoveIterator(position, info); -} - -void RoutingSession::GetRouteFollowingInfo(location::FollowingInfo & info) const +void RoutingSession::GetRouteFollowingInfo(FollowingInfo & info) const { if (m_route.IsValid()) { + /// @todo Make better formatting of distance and units. MeasurementUtils::FormatDistance(m_route.GetCurrentDistanceToEnd(), info.m_distToTarget); size_t const delim = info.m_distToTarget.find(' '); @@ -114,25 +110,6 @@ void RoutingSession::GetRouteFollowingInfo(location::FollowingInfo & info) const } } -bool RoutingSession::IsOnRoute(m2::PointD const & position, double errorRadius, double & minDist) const -{ - minDist = sqrt(m_route.GetPoly().GetShortestSquareDistance(position)); - if (errorRadius > m_tolerance || minDist < (errorRadius + m_tolerance)) - return true; - - return false; -} - -bool RoutingSession::IsOnDestPoint(m2::PointD const & position, double errorRadius) const -{ - if (errorRadius > m_tolerance) - return false; - - if (m_route.GetPoly().Back().SquareLength(position) < errorRadius * errorRadius) - return true; - return false; -} - void RoutingSession::AssignRoute(Route & route) { if (route.IsValid()) diff --git a/map/routing_session.hpp b/map/routing_session.hpp index bee618f7f4..b9cec0629c 100644 --- a/map/routing_session.hpp +++ b/map/routing_session.hpp @@ -51,16 +51,10 @@ public: bool IsActive() const; void Reset(); - State OnLocationPositionChanged(m2::PointD const & position, double errorRadius); - - void MoveRoutePosition(m2::PointD const & position, location::GpsInfo const & info); + State OnLocationPositionChanged(m2::PointD const & position, location::GpsInfo const & info); void GetRouteFollowingInfo(location::FollowingInfo & info) const; private: - /// @param[in] errorRadius Tolerance determining that position belongs to the route (mercator). - bool IsOnRoute(m2::PointD const & position, double errorRadius, double & minDist) const; - bool IsOnDestPoint(m2::PointD const & position, double errorRadius) const; - void AssignRoute(Route & route); private: @@ -68,9 +62,9 @@ private: Route m_route; State m_state; - double m_tolerance; //!< Default tolerance for point-on-route checking (mercator). - double m_lastMinDist; //!< Last calculated position-on-route (mercator). - uint32_t m_moveAwayCounter; + /// Current position metrics to check for RouteLeft state. + double m_lastDistance; + int m_moveAwayCounter; }; } diff --git a/map/track.cpp b/map/track.cpp index ea0ca5a590..7ad9123329 100644 --- a/map/track.cpp +++ b/map/track.cpp @@ -150,11 +150,6 @@ double Track::GetLengthMeters() const return res; } -double Track::GetShortestSquareDistance(m2::PointD const & point) const -{ - return m_polyline.GetShortestSquareDistance(point); -} - void Track::Swap(Track & rhs) { swap(m_isVisible, rhs.m_isVisible); diff --git a/map/track.hpp b/map/track.hpp index 11fa61e86b..ef5c5e7d10 100644 --- a/map/track.hpp +++ b/map/track.hpp @@ -68,7 +68,6 @@ public: graphics::EPosition pos, double depth); double GetLengthMeters() const; - double GetShortestSquareDistance(m2::PointD const & point) const; void Swap(Track & rhs); diff --git a/routing/route.cpp b/routing/route.cpp index 71bf9c5f18..96c82a96ed 100644 --- a/routing/route.cpp +++ b/routing/route.cpp @@ -14,6 +14,11 @@ namespace routing { +static double const LOCATION_TIME_THRESHOLD = 60.0*1.0; +static double const ON_ROAD_TOLERANCE_M = 20.0; +static double const ON_END_TOLERANCE_M = 10.0; + + double GetDistanceOnEarth(m2::PointD const & p1, m2::PointD const & p2) { return ms::DistanceOnEarth(MercatorBounds::YToLat(p1.y), @@ -47,7 +52,7 @@ double Route::GetDistance() const double Route::GetCurrentDistanceFromBegin() const { - ASSERT(IsValid() && m_current.IsValid(), ()); + ASSERT(m_current.IsValid(), ()); return ((m_current.m_ind > 0 ? m_segDistance[m_current.m_ind - 1] : 0.0) + GetDistanceOnEarth(m_poly.GetPoint(m_current.m_ind), m_current.m_pt)); @@ -55,34 +60,46 @@ double Route::GetCurrentDistanceFromBegin() const double Route::GetCurrentDistanceToEnd() const { - ASSERT(IsValid() && m_current.IsValid(), ()); + ASSERT(m_current.IsValid(), ()); return (m_segDistance.back() - m_segDistance[m_current.m_ind] + GetDistanceOnEarth(m_current.m_pt, m_poly.GetPoint(m_current.m_ind + 1))); } -void Route::MoveIterator(m2::PointD const & currPos, location::GpsInfo const & info) const +bool Route::MoveIterator(m2::PointD const & currPos, location::GpsInfo const & info) const { double predictDistance = -1.0; if (m_currentTime > 0.0 && info.HasSpeed()) { /// @todo Need to distinguish GPS and WiFi locations. /// They may have different time metrics in case of incorrect system time on a device. - static double const LOCATION_TIME_THRESHOLD = 60.0*1.0; - double const deltaT = info.m_timestamp - m_currentTime; if (deltaT > 0.0 && deltaT < LOCATION_TIME_THRESHOLD) predictDistance = info.m_speed * deltaT; } IterT const res = FindProjection(currPos, - max(GetOnRoadTolerance(), info.m_horizontalAccuracy), + max(ON_ROAD_TOLERANCE_M, info.m_horizontalAccuracy), predictDistance); if (res.IsValid()) { m_current = res; m_currentTime = info.m_timestamp; + return true; } + else + return false; +} + +double Route::GetCurrentSqDistance(m2::PointD const & pt) const +{ + ASSERT(m_current.IsValid(), ()); + return pt.SquareLength(m_current.m_pt); +} + +bool Route::IsCurrentOnEnd() const +{ + return (GetCurrentDistanceToEnd() < ON_END_TOLERANCE_M); } Route::IterT Route::FindProjection(m2::PointD const & currPos, diff --git a/routing/route.hpp b/routing/route.hpp index bf823e0c89..837edc5134 100644 --- a/routing/route.hpp +++ b/routing/route.hpp @@ -33,9 +33,6 @@ public: Update(); } - /// Assume that position within road with this tolerance (meters). - static double GetOnRoadTolerance() { return 20.0; } - string const & GetRouterId() const { return m_router; } m2::PolylineD const & GetPoly() const { return m_poly; } string const & GetName() const { return m_name; } @@ -59,7 +56,13 @@ public: double GetCurrentDistanceToEnd() const; //@} - void MoveIterator(m2::PointD const & currPos, location::GpsInfo const & info) const; + /// @return true If position was updated successfully (projection within gps error radius). + bool MoveIterator(m2::PointD const & currPos, location::GpsInfo const & info) const; + + /// Square distance to current projection in mercator. + double GetCurrentSqDistance(m2::PointD const & pt) const; + + bool IsCurrentOnEnd() const; private: /// @param[in] errorRadius Radius to check projection candidates (meters).