diff --git a/map/routing_manager.cpp b/map/routing_manager.cpp index f56fb20927..0425805581 100644 --- a/map/routing_manager.cpp +++ b/map/routing_manager.cpp @@ -308,8 +308,7 @@ void RoutingManager::InsertRoute(routing::Route const & route) for (size_t subrouteIndex = 0; subrouteIndex < route.GetSubrouteCount(); ++subrouteIndex) { route.GetSubrouteInfo(subrouteIndex, segments); - Route::SubrouteAttrs attrs; - route.GetSubrouteAttrs(subrouteIndex, attrs); + auto const & attrs = route.GetSubrouteAttrs(subrouteIndex); // Fill points. double const currentBaseDistance = distance; @@ -587,7 +586,7 @@ void RoutingManager::BuildRoute(uint32_t timeoutSec) for (auto const & point : routePoints) points.push_back(point.m_position); - m_routingSession.BuildRoute(Checkpoints(0 /* arriveIdx */, std::move(points)), timeoutSec); + m_routingSession.BuildRoute(Checkpoints(std::move(points)), timeoutSec); } void RoutingManager::SetUserCurrentPosition(m2::PointD const & position) diff --git a/routing/checkpoints.hpp b/routing/checkpoints.hpp index 5276be7902..963c6f0f46 100644 --- a/routing/checkpoints.hpp +++ b/routing/checkpoints.hpp @@ -17,28 +17,21 @@ public: Checkpoints(m2::PointD const & start, m2::PointD const & finish) : m_points({start, finish}) {} - Checkpoints(size_t passedIdx, std::vector && points) - : m_points(std::move(points)), m_passedIdx(passedIdx) + Checkpoints(std::vector && points) : m_points(std::move(points)) { - CheckValid(); + CHECK_GREATER_OR_EQUAL(m_points.size(), 2, + ("Checkpoints should at least contain start and finish")); } - m2::PointD const & GetStart() const - { - CheckValid(); - return m_points.front(); - } + m2::PointD const & GetStart() const { return m_points.front(); } + m2::PointD const & GetFinish() const { return m_points.back(); } + std::vector const & GetPoints() const { return m_points; } + size_t GetPassedIdx() const { return m_passedIdx; } - m2::PointD const & GetFinish() const + void SetPointFrom(m2::PointD const & point) { - CheckValid(); - return m_points.back(); - } - - void SetStart(m2::PointD const & start) - { - CheckValid(); - m_points.front() = start; + CHECK_LESS(m_passedIdx, m_points.size(), ()); + m_points[m_passedIdx] = point; } m2::PointD const & GetPoint(size_t pointIdx) const @@ -47,36 +40,23 @@ public: return m_points[pointIdx]; } - std::vector const & GetPoints() const - { - CheckValid(); - return m_points; - } + m2::PointD const & GetPointFrom() const { return GetPoint(m_passedIdx); } + m2::PointD const & GetPointTo() const { return GetPoint(m_passedIdx + 1); } - size_t GetNumSubroutes() const - { - CheckValid(); - return m_points.size() - 1; - } + size_t GetNumSubroutes() const { return m_points.size() - 1; } + size_t GetNumRemainingSubroutes() const { return GetNumSubroutes() - m_passedIdx; } - size_t GetPassedIdx() const { return m_passedIdx; } + bool IsFinished() const { return m_passedIdx >= GetNumSubroutes(); } void PassNextPoint() { + CHECK(!IsFinished(), ()); ++m_passedIdx; - CheckValid(); - } - - void CheckValid() const - { - CHECK_GREATER_OR_EQUAL(m_points.size(), 2, - ("Checkpoints should at least contain start and finish")); - CHECK_LESS(m_passedIdx, m_points.size(), ()); } private: // m_points contains start, finish and intermediate points. - std::vector m_points; + std::vector m_points = {m2::PointD::Zero(), m2::PointD::Zero()}; // m_passedIdx is the index of the checkpoint by which the user passed by. // By default, user has passed 0, it is start point. size_t m_passedIdx = 0; diff --git a/routing/index_router.cpp b/routing/index_router.cpp index db4a1a0987..adcf3bb48c 100644 --- a/routing/index_router.cpp +++ b/routing/index_router.cpp @@ -190,7 +190,7 @@ IRouter::ResultCode IndexRouter::CalculateRoute(Checkpoints const & checkpoints, double const distanceToFinish = MercatorBounds::DistanceOnEarth(startPoint, finalPoint); if (distanceToRoute <= kAdjustRangeM && distanceToFinish >= kMinDistanceToFinishM) { - auto const code = AdjustRoute(startPoint, startDirection, finalPoint, delegate, route); + auto const code = AdjustRoute(checkpoints, startDirection, delegate, route); if (code != IRouter::RouteNotFound) return code; @@ -245,6 +245,9 @@ IRouter::ResultCode IndexRouter::DoCalculateRoute(Checkpoints const & checkpoint Segment startSegment; if (!FindClosestSegment(checkpoints.GetStart(), true /* isOutgoing */, graph, startSegment)) return IRouter::StartPointNotFound; + + size_t subrouteSegmentsBegin = 0; + std::vector subroutes; for (size_t i = checkpoints.GetPassedIdx(); i < checkpoints.GetNumSubroutes(); ++i) { @@ -254,11 +257,29 @@ IRouter::ResultCode IndexRouter::DoCalculateRoute(Checkpoints const & checkpoint return result; IndexGraphStarter::CheckValidRoute(subroute); - auto const nonFakefinish = IndexGraphStarter::GetNonFakeFinish(subroute); - startSegment = *nonFakefinish; - segments.insert(segments.end(), IndexGraphStarter::GetNonFakeStart(subroute), nonFakefinish); + auto const nonFakeStart = IndexGraphStarter::GetNonFakeStart(subroute); + auto const nonFakeFinish = IndexGraphStarter::GetNonFakeFinish(subroute); + segments.insert(segments.end(), nonFakeStart, nonFakeFinish); + + size_t subrouteSegmentsEnd = subrouteSegmentsBegin + (nonFakeFinish - nonFakeStart); + // Lets there are N checkpoints and N-1 subroutes. + // There is corresponding nearest segment for each checkpoint - checkpoint segment. + // Each subroute except the last contains exactly one checkpoint segment - first segment. + // Last subroute contains two checkpoint segments: the first and the last. + if (i + 1 == checkpoints.GetNumSubroutes()) + ++subrouteSegmentsEnd; + + subroutes.emplace_back( + Junction(graph.GetPoint(*nonFakeStart, false /* front */), feature::kDefaultAltitudeMeters), + Junction(graph.GetPoint(*nonFakeFinish, true /* front */), feature::kDefaultAltitudeMeters), + subrouteSegmentsBegin, subrouteSegmentsEnd); + + startSegment = *nonFakeFinish; + subrouteSegmentsBegin = subrouteSegmentsEnd; } + route.SetSubrotes(move(subroutes)); + segments.push_back(startSegment); segments.push_back(IndexGraphStarter::kFinishFakeSegment); IndexGraphStarter::CheckValidRoute(segments); @@ -274,7 +295,8 @@ IRouter::ResultCode IndexRouter::DoCalculateRoute(Checkpoints const & checkpoint if (redressResult != IRouter::NoError) return redressResult; - m_lastRoute = make_unique(checkpoints.GetStart(), checkpoints.GetFinish()); + m_lastRoute = make_unique(checkpoints.GetStart(), checkpoints.GetFinish(), + route.GetSubroutes()); for (Segment const & segment : segments) { if (!IndexGraphStarter::IsFakeSegment(segment)) @@ -346,9 +368,8 @@ IRouter::ResultCode IndexRouter::CalculateSubroute(Checkpoints const & checkpoin return IRouter::NoError; } -IRouter::ResultCode IndexRouter::AdjustRoute(m2::PointD const & startPoint, +IRouter::ResultCode IndexRouter::AdjustRoute(Checkpoints const & checkpoints, m2::PointD const & startDirection, - m2::PointD const & finalPoint, RouterDelegate const & delegate, Route & route) { my::Timer timer; @@ -357,24 +378,35 @@ IRouter::ResultCode IndexRouter::AdjustRoute(m2::PointD const & startPoint, graph.SetMode(WorldGraph::Mode::NoLeaps); Segment startSegment; - if (!FindClosestSegment(startPoint, true /* isOutgoing */, graph, startSegment)) + m2::PointD const pointFrom = checkpoints.GetPointFrom(); + if (!FindClosestSegment(pointFrom, true /* isOutgoing */, graph, startSegment)) return IRouter::StartPointNotFound; + auto const & lastSubroutes = m_lastRoute->GetSubroutes(); + CHECK(!lastSubroutes.empty(), ()); + CHECK_GREATER_OR_EQUAL(lastSubroutes.size(), checkpoints.GetNumRemainingSubroutes(), ()); + size_t const currentSubrouteIdx = lastSubroutes.size() - checkpoints.GetNumRemainingSubroutes(); + auto const & lastSubroute = m_lastRoute->GetSubroute(currentSubrouteIdx); + auto const & steps = m_lastRoute->GetSteps(); CHECK(!steps.empty(), ()); IndexGraphStarter starter( - IndexGraphStarter::FakeVertex(startSegment, startPoint, false /* strictForward */), - IndexGraphStarter::FakeVertex(steps.back().GetSegment(), finalPoint, - false /* strictForward */), + IndexGraphStarter::FakeVertex(startSegment, pointFrom, false /* strictForward */), + IndexGraphStarter::FakeVertex(steps[lastSubroute.GetEndSegmentIdx() - 1].GetSegment(), + checkpoints.GetPointTo(), false /* strictForward */), graph); AStarProgress progress(0, 95); progress.Initialize(starter.GetStartVertex().GetPoint(), starter.GetFinishVertex().GetPoint()); - + vector prevEdges; - for (auto const & step : steps) + CHECK_LESS_OR_EQUAL(lastSubroute.GetEndSegmentIdx(), steps.size(), ()); + for (size_t i = lastSubroute.GetBeginSegmentIdx(); i < lastSubroute.GetEndSegmentIdx(); ++i) + { + auto const & step = steps[i]; prevEdges.emplace_back(step.GetSegment(), starter.CalcSegmentWeight(step.GetSegment())); + } uint32_t visitCount = 0; @@ -398,16 +430,40 @@ IRouter::ResultCode IndexRouter::AdjustRoute(m2::PointD const & startPoint, if (resultCode != IRouter::NoError) return resultCode; + CHECK_GREATER_OR_EQUAL(result.path.size(), 2, ()); + CHECK(IndexGraphStarter::IsFakeSegment(result.path.front()), ()); + CHECK(!IndexGraphStarter::IsFakeSegment(result.path.back()), ()); + + vector subroutes; + size_t subrouteOffset = result.path.size() - 1; // -1 for the fake start. + subroutes.emplace_back( + Junction(starter.GetStartVertex().GetPoint(), feature::kDefaultAltitudeMeters), + Junction(starter.GetFinishVertex().GetPoint(), feature::kDefaultAltitudeMeters), 0, + subrouteOffset); + + for (size_t i = currentSubrouteIdx + 1; i < lastSubroutes.size(); ++i) + { + auto const & subroute = lastSubroutes[i]; + + for (size_t j = subroute.GetBeginSegmentIdx(); j < subroute.GetEndSegmentIdx(); ++j) + result.path.push_back(steps[j].GetSegment()); + + subroutes.emplace_back(subroute, subrouteOffset); + subrouteOffset = subroutes.back().GetEndSegmentIdx(); + } + + // +1 for the fake start. + CHECK_EQUAL(result.path.size(), subrouteOffset + 1, ()); + + route.SetSubrotes(move(subroutes)); + result.path.push_back(starter.GetFinish()); auto const redressResult = RedressRoute(result.path, delegate, starter, route); if (redressResult != IRouter::NoError) return redressResult; - LOG(LINFO, - ("Adjust route, elapsed:", timer.ElapsedSeconds(), ", prev start:", - MercatorBounds::ToLatLon(m_lastRoute->GetStart()), ", start:", - MercatorBounds::ToLatLon(startPoint), ", finish:", MercatorBounds::ToLatLon(finalPoint), - ", prev route:", steps.size(), ", new route:", result.path.size())); + LOG(LINFO, ("Adjust route, elapsed:", timer.ElapsedSeconds(), ", prev start:", checkpoints, + ", prev route:", steps.size(), ", new route:", result.path.size())); return IRouter::NoError; } diff --git a/routing/index_router.hpp b/routing/index_router.hpp index 27e3fcae39..4d79b11980 100644 --- a/routing/index_router.hpp +++ b/routing/index_router.hpp @@ -59,9 +59,9 @@ private: Segment const & startSegment, RouterDelegate const & delegate, WorldGraph & graph, vector & subroute); - IRouter::ResultCode AdjustRoute(m2::PointD const & startPoint, m2::PointD const & startDirection, - m2::PointD const & finalPoint, RouterDelegate const & delegate, - Route & route); + IRouter::ResultCode AdjustRoute(Checkpoints const & checkpoints, + m2::PointD const & startDirection, + RouterDelegate const & delegate, Route & route); WorldGraph MakeWorldGraph(); diff --git a/routing/road_graph_router.cpp b/routing/road_graph_router.cpp index 5af5073057..b26eac1d05 100644 --- a/routing/road_graph_router.cpp +++ b/routing/road_graph_router.cpp @@ -208,6 +208,7 @@ IRouter::ResultCode RoadGraphRouter::CalculateRoute(Checkpoints const & checkpoi CalculateMaxSpeedTimes(*m_roadGraph, result.path, times); CHECK(m_directionsEngine, ()); + route.SetSubrotes({Route::SubrouteAttrs(startPos, finalPos, 0, result.path.size() - 1)}); ReconstructRoute(*m_directionsEngine, *m_roadGraph, nullptr /* trafficStash */, delegate, true /* hasAltitude */, result.path, std::move(times), route); } diff --git a/routing/route.cpp b/routing/route.cpp index 2d4b101c82..77ede9fe13 100644 --- a/routing/route.cpp +++ b/routing/route.cpp @@ -54,6 +54,8 @@ void Route::Swap(Route & rhs) m_absentCountries.swap(rhs.m_absentCountries); m_altitudes.swap(rhs.m_altitudes); m_traffic.swap(rhs.m_traffic); + m_routeSegments.swap(rhs.m_routeSegments); + m_subroutes.swap(rhs.m_subroutes); } void Route::AddAbsentCountry(string const & name) @@ -313,11 +315,6 @@ void Route::MatchLocationToRoute(location::GpsInfo & location, location::RouteMa } } -bool Route::IsCurrentOnEnd() const -{ - return (m_poly.GetDistanceToEndM() < kOnEndToleranceM); -} - void Route::Update() { if (!m_poly.IsValid()) @@ -339,73 +336,24 @@ void Route::Update() m_currentTime = 0.0; } -// Subroute interface fake implementation --------------------------------------------------------- -// This implementation is valid for one subroute which is equal to the route. -size_t Route::GetSubrouteCount() const { return IsValid() ? 1 : 0; } +size_t Route::GetSubrouteCount() const { return m_subroutes.size(); } -void Route::GetSubrouteInfo(size_t segmentIdx, std::vector & segments) const +void Route::GetSubrouteInfo(size_t subrouteIdx, std::vector & segments) const { - CHECK_LESS(segmentIdx, GetSubrouteCount(), ()); - CHECK(IsValid(), ()); segments.clear(); + SubrouteAttrs const & attrs = GetSubrouteAttrs(subrouteIdx); - auto const & points = m_poly.GetPolyline().GetPoints(); - size_t const polySz = m_poly.GetPolyline().GetSize(); + CHECK_LESS_OR_EQUAL(attrs.GetEndSegmentIdx(), m_routeSegments.size(), ()); - CHECK(!m_turns.empty(), ()); - CHECK_LESS(m_turns.back().m_index, polySz, ()); - CHECK(std::is_sorted(m_turns.cbegin(), m_turns.cend(), - [](TurnItem const & lhs, TurnItem const & rhs) { return lhs.m_index < rhs.m_index; }), - ()); - - if (!m_altitudes.empty()) - CHECK_EQUAL(m_altitudes.size(), polySz, ()); - - CHECK(!m_times.empty(), ()); - CHECK_LESS(m_times.back().first, polySz, ()); - CHECK(std::is_sorted(m_times.cbegin(), m_times.cend(), - [](TTimeItem const & lhs, TTimeItem const & rhs) { return lhs.first < rhs.first; }), - ()); - - if (!m_traffic.empty()) - CHECK_EQUAL(m_traffic.size() + 1, polySz, ()); - - // |m_index| of the first turn may be equal to zero. If there's a turn at very beginning of the route. - // The turn should be skipped in case of segement oriented route which is filled by the method. - size_t turnItemIdx = (m_turns[0].m_index == 0 ? 1 : 0); - size_t timeIdx = (m_times[0].first ? 1 : 0); - double distFromBeginningMeters = 0.0; - double distFromBeginningMerc = 0.0; - segments.reserve(polySz - 1); - - for (size_t i = 1; i < points.size(); ++i) - { - TurnItem turn; - if (m_turns[turnItemIdx].m_index == i) - { - turn = m_turns[turnItemIdx]; - ++turnItemIdx; - } - CHECK_LESS_OR_EQUAL(turnItemIdx, m_turns.size(), ()); - - if (m_times[timeIdx].first == i) - ++timeIdx; - - distFromBeginningMeters += MercatorBounds::DistanceOnEarth(points[i - 1], points[i]); - distFromBeginningMerc += points[i - 1].Length(points[i]); - - segments.emplace_back(Segment(), turn, GetJunction(i), string(), distFromBeginningMeters, - distFromBeginningMerc, m_times[timeIdx - 1].second, - m_traffic.empty() ? SpeedGroup::Unknown : m_traffic[i - 1]); - } + for (size_t i = attrs.GetBeginSegmentIdx(); i < attrs.GetEndSegmentIdx(); ++i) + segments.push_back(m_routeSegments[i]); } -void Route::GetSubrouteAttrs(size_t segmentIdx, SubrouteAttrs & attrs) const +Route::SubrouteAttrs const & Route::GetSubrouteAttrs(size_t subrouteIdx) const { - CHECK_LESS(segmentIdx, GetSubrouteCount(), ()); CHECK(IsValid(), ()); - - attrs = SubrouteAttrs(GetJunction(0), GetJunction(m_poly.GetPolyline().GetSize() - 1)); + CHECK_LESS(subrouteIdx, m_subroutes.size(), ()); + return m_subroutes[subrouteIdx]; } Route::SubrouteSettings const Route::GetSubrouteSettings(size_t segmentIdx) const @@ -414,6 +362,15 @@ Route::SubrouteSettings const Route::GetSubrouteSettings(size_t segmentIdx) cons return SubrouteSettings(m_routingSettings, m_router, m_subrouteUid); } +bool Route::IsSubroutePassed(size_t subrouteIdx) const +{ + size_t const segmentIdx = GetSubrouteAttrs(subrouteIdx).GetEndSegmentIdx() - 1; + CHECK_LESS(segmentIdx, m_routeSegments.size(), ()); + double const endDistance = m_routeSegments[segmentIdx].GetDistFromBeginningMeters(); + double const passedDistance = m_poly.GetDistanceFromBeginM(); + return endDistance - passedDistance < kOnEndToleranceM; +} + void Route::SetSubrouteUid(size_t segmentIdx, SubrouteUid subrouteUid) { CHECK_LESS(segmentIdx, GetSubrouteCount(), ()); diff --git a/routing/route.hpp b/routing/route.hpp index 4ea09c3d45..5f4629c12a 100644 --- a/routing/route.hpp +++ b/routing/route.hpp @@ -92,17 +92,38 @@ public: { public: SubrouteAttrs() = default; - SubrouteAttrs(Junction const & start, Junction const & finish) - : m_start(start), m_finish(finish) + + SubrouteAttrs(Junction const & start, Junction const & finish, size_t beginSegmentIdx, + size_t endSegmentIdx) + : m_start(start) + , m_finish(finish) + , m_beginSegmentIdx(beginSegmentIdx) + , m_endSegmentIdx(endSegmentIdx) + { + CHECK_LESS_OR_EQUAL(beginSegmentIdx, endSegmentIdx, ()); + } + + SubrouteAttrs(SubrouteAttrs const & subroute, size_t beginSegmentIdx) + : m_start(subroute.m_start) + , m_finish(subroute.m_finish) + , m_beginSegmentIdx(beginSegmentIdx) + , m_endSegmentIdx(beginSegmentIdx + subroute.GetSize()) { } Junction const & GetStart() const { return m_start; } Junction const & GetFinish() const { return m_finish; } + size_t GetBeginSegmentIdx() const { return m_beginSegmentIdx; } + size_t GetEndSegmentIdx() const { return m_endSegmentIdx; } + size_t GetSize() const { return m_endSegmentIdx - m_beginSegmentIdx; } private: Junction m_start; Junction m_finish; + // Index of the first subroute segment in the whole route. + size_t m_beginSegmentIdx = 0; + // Non inclusive index of the last subroute segment in the whole route. + size_t m_endSegmentIdx = 0; }; /// \brief For every subroute some attributes are kept the following stucture. @@ -152,6 +173,8 @@ public: template void SetRouteSegments(SI && v) { m_routeSegments = std::forward(v); } + void SetSubrotes(std::vector && subroutes) { m_subroutes = std::move(subroutes); } + uint32_t GetTotalTimeSec() const; uint32_t GetCurrentTimeToEndSec() const; @@ -162,6 +185,7 @@ public: TTurns const & GetTurns() const { return m_turns; } feature::TAltitudes const & GetAltitudes() const { return m_altitudes; } vector const & GetTraffic() const { return m_traffic; } + vector const & GetSubroutes() const { return m_subroutes; } vector const & GetSegDistanceMeters() const { return m_poly.GetSegDistanceM(); } bool IsValid() const { return (m_poly.GetPolyline().GetSize() > 1); } @@ -198,8 +222,6 @@ public: void MatchLocationToRoute(location::GpsInfo & location, location::RouteMatchingInfo & routeMatchingInfo) const; - bool IsCurrentOnEnd() const; - /// Add country name if we have no country filename to make route void AddAbsentCountry(string const & name); @@ -218,7 +240,7 @@ public: size_t GetSubrouteCount() const; /// \brief Fills |info| with full subroute information. - /// \param segmentIdx zero base number of subroute. |segmentIdx| should be less than GetSubrouteCount(); + /// \param subrouteIdx zero base number of subroute. |segmentIdx| should be less than GetSubrouteCount(); /// \note |info| is a segment oriented route. Size of |info| is equal to number of points in |m_poly| - 1. /// Class Route is a point oriented route. While this conversion some attributes of zero point will be lost. /// It happens with zero turn for example. @@ -226,15 +248,17 @@ public: /// intermediate points. /// Note. SegmentInfo::m_segment is filled with default Segment instance. /// Note. SegmentInfo::m_streetName is filled with an empty string. - void GetSubrouteInfo(size_t segmentIdx, std::vector & segments) const; + void GetSubrouteInfo(size_t subrouteIdx, std::vector & segments) const; - void GetSubrouteAttrs(size_t segmentIdx, SubrouteAttrs & info) const; + SubrouteAttrs const & GetSubrouteAttrs(size_t subrouteIdx) const; /// \returns Subroute settings by |segmentIdx|. // @TODO(bykoianko) This method should return SubrouteSettings by reference. Now it returns by value // because of fake implementation. SubrouteSettings const GetSubrouteSettings(size_t segmentIdx) const; + bool IsSubroutePassed(size_t subrouteIdx) const; + /// \brief Sets subroute unique id (|subrouteUid|) by |segmentIdx|. /// \note |subrouteUid| is a permanent id of a subroute. This id can be used to address to a subroute /// after the route is removed. @@ -272,5 +296,6 @@ private: // Subroute SubrouteUid m_subrouteUid = kInvalidSubrouteId; + std::vector m_subroutes; }; } // namespace routing diff --git a/routing/routing_session.cpp b/routing/routing_session.cpp index 5aab585f94..8344d1fceb 100644 --- a/routing/routing_session.cpp +++ b/routing/routing_session.cpp @@ -85,14 +85,13 @@ void RoutingSession::RebuildRoute(m2::PointD const & startPoint, TReadyCallback const & readyCallback, uint32_t timeoutSec, State routeRebuildingState, bool adjustToPrevRoute) { - ASSERT(m_router != nullptr, ()); - m_checkpoints.CheckValid(); + CHECK(m_router, ()); RemoveRoute(); SetState(routeRebuildingState); m_routingRebuildCount++; m_lastCompletionPercent = 0; - m_checkpoints.SetStart(startPoint); + m_checkpoints.SetPointFrom(startPoint); // Use old-style callback construction, because lambda constructs buggy function on Android // (callback param isn't captured by value). m_router->CalculateRoute(m_checkpoints, startPoint - m_lastGoodPosition, adjustToPrevRoute, @@ -201,11 +200,12 @@ RoutingSession::State RoutingSession::OnLocationPositionChanged(GpsInfo const & m_moveAwayCounter = 0; m_lastDistance = 0.0; - if (m_route->IsCurrentOnEnd()) + PassCheckpoints(); + + if (m_checkpoints.IsFinished()) { m_passedDistanceOnRouteMeters += m_route->GetTotalDistanceMeters(); SetState(RouteFinished); - m_checkpointCallback(m_checkpoints.GetPoints().size() - 1); alohalytics::TStringMap params = {{"router", m_route->GetRouterId()}, {"passedDistance", strings::to_string(m_passedDistanceOnRouteMeters)}, @@ -233,6 +233,7 @@ RoutingSession::State RoutingSession::OnLocationPositionChanged(GpsInfo const & } } } + m_lastGoodPosition = m_userCurrentPosition; } else @@ -373,6 +374,16 @@ double RoutingSession::GetCompletionPercent() const return percent; } +void RoutingSession::PassCheckpoints() +{ + while (!m_checkpoints.IsFinished() && m_route->IsSubroutePassed(m_checkpoints.GetPassedIdx())) + { + m_checkpoints.PassNextPoint(); + LOG(LINFO, ("Pass checkpoint, ", m_checkpoints)); + m_checkpointCallback(m_checkpoints.GetPassedIdx()); + } +} + void RoutingSession::GenerateTurnNotifications(vector & turnNotifications) { turnNotifications.clear(); diff --git a/routing/routing_session.hpp b/routing/routing_session.hpp index 2dfae480b9..940bb0c50f 100644 --- a/routing/routing_session.hpp +++ b/routing/routing_session.hpp @@ -199,6 +199,7 @@ private: bool HasRouteAltitudeImpl() const; double GetCompletionPercent() const; + void PassCheckpoints(); private: unique_ptr m_router; diff --git a/routing/routing_tests/route_tests.cpp b/routing/routing_tests/route_tests.cpp index fcbf1eb203..7db0d941cc 100644 --- a/routing/routing_tests/route_tests.cpp +++ b/routing/routing_tests/route_tests.cpp @@ -1,6 +1,7 @@ #include "testing/testing.hpp" #include "routing/route.hpp" +#include "routing/routing_helpers.hpp" #include "routing/turns.hpp" #include "platform/location.hpp" @@ -15,6 +16,8 @@ using namespace routing; namespace { static vector const kTestGeometry({{0, 0}, {0,1}, {1,1}, {1,2}, {1,3}}); +static vector const kTestSegments( + {{0, 0, 0, true}, {0, 0, 1, true}, {0, 0, 2, true}, {0, 0, 3, true}}); static Route::TTurns const kTestTurns( {turns::TurnItem(1, turns::TurnDirection::TurnLeft), turns::TurnItem(2, turns::TurnDirection::TurnRight), @@ -211,6 +214,16 @@ UNIT_TEST(GetSubrouteInfoTest) Route::TTimes times(kTestTimes); route.SetSectionTimes(move(times)); + vector junctions; + for (auto const & point : kTestGeometry) + junctions.emplace_back(point, feature::kDefaultAltitudeMeters); + + vector segmentInfo; + FillSegmentInfo(kTestSegments, junctions, kTestTurns, kTestNames, kTestTimes, nullptr, segmentInfo); + route.SetRouteSegments(move(segmentInfo)); + route.SetSubrotes( + {Route::SubrouteAttrs(junctions.front(), junctions.back(), 0, kTestSegments.size())}); + TEST_EQUAL(route.GetSubrouteCount(), 1, ()); vector info; route.GetSubrouteInfo(0, info); diff --git a/routing/segmented_route.cpp b/routing/segmented_route.cpp index 9fdf6aa3ae..5c82505d4e 100644 --- a/routing/segmented_route.cpp +++ b/routing/segmented_route.cpp @@ -11,8 +11,9 @@ namespace routing { -SegmentedRoute::SegmentedRoute(m2::PointD const & start, m2::PointD const & finish) - : m_start(start), m_finish(finish) +SegmentedRoute::SegmentedRoute(m2::PointD const & start, m2::PointD const & finish, + std::vector const & subroutes) + : m_start(start), m_finish(finish), m_subroutes(subroutes) { } @@ -26,4 +27,10 @@ double SegmentedRoute::CalcDistance(m2::PointD const & point) const return result; } + +Route::SubrouteAttrs const & SegmentedRoute::GetSubroute(size_t i) const +{ + CHECK_LESS(i, m_subroutes.size(), ()); + return m_subroutes[i]; +} } // namespace routing diff --git a/routing/segmented_route.hpp b/routing/segmented_route.hpp index 296e8eb1c0..2f3f8a9ad3 100644 --- a/routing/segmented_route.hpp +++ b/routing/segmented_route.hpp @@ -1,5 +1,6 @@ #pragma once +#include "routing/route.hpp" #include "routing/segment.hpp" #include "geometry/point2d.hpp" @@ -26,7 +27,8 @@ public: m2::PointD const m_point = m2::PointD::Zero(); }; - SegmentedRoute(m2::PointD const & start, m2::PointD const & finish); + SegmentedRoute(m2::PointD const & start, m2::PointD const & finish, + std::vector const & subroutes); void AddStep(Segment const & segment, m2::PointD const & point) { @@ -39,10 +41,13 @@ public: m2::PointD const & GetFinish() const { return m_finish; } std::vector const & GetSteps() const { return m_steps; } bool IsEmpty() const { return m_steps.empty(); } + std::vector const & GetSubroutes() const { return m_subroutes; } + Route::SubrouteAttrs const & GetSubroute(size_t i) const; private: m2::PointD const m_start; m2::PointD const m_finish; std::vector m_steps; + std::vector m_subroutes; }; } // namespace routing