diff --git a/routing/route.cpp b/routing/route.cpp index 23024ec211..43d14b1a2f 100644 --- a/routing/route.cpp +++ b/routing/route.cpp @@ -18,7 +18,11 @@ #include "std/numeric.hpp" +#include +#include + using namespace traffic; +using namespace routing::turns; namespace routing { @@ -91,7 +95,7 @@ void Route::GetTurnsDistances(vector & distances) const //TODO (ldragunov) Extract CalculateMercatorDistance higher to avoid including turns generator. double const mercatorDistanceBetweenTurns = - turns::CalculateMercatorDistanceAlongPath(formerTurnIndex, currentTurn->m_index, polyline.GetPoints()); + CalculateMercatorDistanceAlongPath(formerTurnIndex, currentTurn->m_index, polyline.GetPoints()); mercatorDistance += mercatorDistanceBetweenTurns; distances.push_back(mercatorDistance); @@ -160,10 +164,10 @@ Route::TTurns::const_iterator Route::GetCurrentTurn() const { ASSERT(!m_turns.empty(), ()); - turns::TurnItem t; + TurnItem t; t.m_index = static_cast(m_poly.GetCurrentIter().m_ind); return upper_bound(m_turns.cbegin(), m_turns.cend(), t, - [](turns::TurnItem const & lhs, turns::TurnItem const & rhs) + [](TurnItem const & lhs, TurnItem const & rhs) { return lhs.m_index < rhs.m_index; }); @@ -216,7 +220,7 @@ Route::TStreets::const_iterator Route::GetCurrentStreetNameIterAfter(FollowedPol return curIter->first == iter.m_ind ? curIter : prevIter; } -bool Route::GetCurrentTurn(double & distanceToTurnMeters, turns::TurnItem & turn) const +bool Route::GetCurrentTurn(double & distanceToTurnMeters, TurnItem & turn) const { auto it = GetCurrentTurn(); if (it == m_turns.end()) @@ -232,7 +236,7 @@ bool Route::GetCurrentTurn(double & distanceToTurnMeters, turns::TurnItem & turn return true; } -bool Route::GetNextTurn(double & distanceToTurnMeters, turns::TurnItem & turn) const +bool Route::GetNextTurn(double & distanceToTurnMeters, TurnItem & turn) const { auto it = GetCurrentTurn(); auto const turnsEnd = m_turns.end(); @@ -240,7 +244,7 @@ bool Route::GetNextTurn(double & distanceToTurnMeters, turns::TurnItem & turn) c if (it == turnsEnd || (it + 1) == turnsEnd) { - turn = turns::TurnItem(); + turn = TurnItem(); distanceToTurnMeters = 0; return false; } @@ -252,16 +256,16 @@ bool Route::GetNextTurn(double & distanceToTurnMeters, turns::TurnItem & turn) c return true; } -bool Route::GetNextTurns(vector & turns) const +bool Route::GetNextTurns(vector & turns) const { - turns::TurnItemDist currentTurn; + TurnItemDist currentTurn; if (!GetCurrentTurn(currentTurn.m_distMeters, currentTurn.m_turnItem)) return false; turns.clear(); turns.emplace_back(move(currentTurn)); - turns::TurnItemDist nextTurn; + TurnItemDist nextTurn; if (GetNextTurn(nextTurn.m_distMeters, nextTurn.m_turnItem)) turns.emplace_back(move(nextTurn)); return true; @@ -416,7 +420,7 @@ void Route::AppendRoute(Route const & route) 2 /* meters */, ()); m_poly.PopBack(); CHECK(!m_turns.empty(), ()); - ASSERT_EQUAL(m_turns.back().m_turn, turns::TurnDirection::ReachedYourDestination, ()); + ASSERT_EQUAL(m_turns.back().m_turn, TurnDirection::ReachedYourDestination, ()); m_turns.pop_back(); CHECK(!m_times.empty(), ()); m_times.pop_back(); @@ -466,21 +470,64 @@ void Route::AppendRoute(Route const & route) // This implementation is valid for one subroute which is equal to the route. size_t Route::GetSubrouteCount() const { return IsValid() ? 1 : 0; } -void Route::GetSubrouteJunctions(size_t subrouteInx, vector & junctions) const +void Route::GetSubrouteInfo(size_t subrouteInx, vector & info) const { CHECK_LESS(subrouteInx, GetSubrouteCount(), ()); - junctions.clear(); + info.clear(); + + if (!IsValid()) + return; + vector const & points = m_poly.GetPolyline().GetPoints(); + size_t const polySz = m_poly.GetPolyline().GetSize(); + + 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(), points.size(), ()); + CHECK_EQUAL(m_altitudes.size(), polySz, ()); - for (size_t i = 0; i <= points.size(); ++i) - junctions.emplace_back(points[i], m_altitudes.empty() ? feature::kInvalidAltitude : m_altitudes[i]); -} + 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; }), + ()); -void Route::GetSubrouteFullInfo(size_t /* subrouteInx */, vector & /* info */) const -{ - NOTIMPLEMENTED(); + 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; + 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]); + + info.emplace_back( + Segment(), turn, + Junction(points[i], m_altitudes.empty() ? feature::kInvalidAltitude : m_altitudes[i]), + string(), distFromBeginningMeters, + distFromBeginningMerc, m_times[timeIdx - 1].second, + m_traffic.empty() ? SpeedGroup::Unknown : m_traffic[i - 1]); + } } Route::SubrouteSettings const Route::GetSubrouteSettings(size_t subrouteInx) const diff --git a/routing/route.hpp b/routing/route.hpp index f4a5af4aa4..4f97dafd00 100644 --- a/routing/route.hpp +++ b/routing/route.hpp @@ -18,6 +18,7 @@ #include "std/string.hpp" #include +#include namespace location { @@ -43,12 +44,34 @@ public: /// For every Segment is kept some attributes in the structure SegmentInfo. struct SegmentInfo { + SegmentInfo(Segment const & segment, turns::TurnItem const & turn, Junction const & junction, + std::string const & streetName, double distFromBeginningMeters, double distFromBeginningMerc, + double timeFromBeginningS, traffic::SpeedGroup traffic) + : m_segment(segment) + , m_turn(turn) + , m_junction(junction) + , m_streetName(streetName) + , m_distFromBeginningMeters(distFromBeginningMeters) + , m_distFromBeginningMerc(distFromBeginningMerc) + , m_timeFromBeginningS(timeFromBeginningS) + , m_traffic(traffic) + { + } + Segment m_segment; - string m_streetName; + /// Turn (maneuver) information for the turn next to the |m_segment| if any. + /// If not |m_turn::m_turn| is equal to TurnDirection::NoTurn. turns::TurnItem m_turn; - Junction m_junction; // The front point of segment. - traffic::SpeedGroup m_traffic = traffic::SpeedGroup::Unknown; + Junction m_junction; ///< The front point of segment. + /// Street name of |m_segment| if any. Otherwise |m_streetName| is empty. + std::string m_streetName; + /// Distance from the route beginning to the farthest end of |m_segment| in meters. + double m_distFromBeginningMeters = 0.0; + /// Distance from the route beginning to the farthest end of |m_segment| in mercator. + double m_distFromBeginningMerc = 0.0; + /// ETA from the route beginning in seconds to reach the farthest from the route beginning end of |m_segment|. double m_timeFromBeginningS = 0.0; + traffic::SpeedGroup m_traffic = traffic::SpeedGroup::Unknown; }; /// \brief For every subroute some attributes are kept the following stucture. @@ -61,6 +84,8 @@ public: RoutingSettings m_routingSettings; string m_router; + /// Some subsystems (for example drape) which is used Route class need to have an id of any subroute. + /// This subsystems may set the id and then use it. The id is kept in |m_id|. uint64_t m_id = kInvalidId; }; @@ -113,6 +138,7 @@ public: feature::TAltitudes const & GetAltitudes() const { return m_altitudes; } vector const & GetTraffic() const { return m_traffic; } vector const & GetSegDistanceM() const { return m_poly.GetSegDistanceM(); } + /// \returns distance to all turns in mercator. void GetTurnsDistances(vector & distances) const; bool IsValid() const { return (m_poly.GetPolyline().GetSize() > 1); } @@ -167,13 +193,23 @@ public: /// \returns Number of subroutes. /// \note Intermediate points separate a route into several subroutes. size_t GetSubrouteCount() const; - /// \brief Fills |junctions| with subroute geometry. - /// \param subrouteInx zero base number of subroute. |subrouteInx| should be less than GetSubrouteCount(); - void GetSubrouteJunctions(size_t subrouteInx, vector & junctions) const; + /// \brief Fills |info| with full subroute information. - void GetSubrouteFullInfo(size_t subrouteInx, vector & info) const; + /// \param subrouteInx zero base number of subroute. |subrouteInx| 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. + /// \note It's a fake implementation for single subroute which is equal to route without any + /// 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 subrouteInx, vector & info) const; + /// \returns Subroute settings by |subRouteInx|. + // @TODO(bykoianko) This method should return SubrouteSettings by reference. Now it returns by value + // because of fake implementation. SubrouteSettings const GetSubrouteSettings(size_t subrouteInx) const; + /// \brief Sets subroute id by |subRouteInx|. /// \note |subrouteId| is a permanent id of a subroute. This id can be used to address to a subroute /// after the route is removed.