From e9246ee0bcfe1f66634da5f14e8c98ff1ea6df0e Mon Sep 17 00:00:00 2001 From: tatiana-kondakova Date: Tue, 17 Oct 2017 15:53:24 +0300 Subject: [PATCH] Add TransitInfo to RouteSegment to draw transit route properly --- routing/index_router.cpp | 11 ++-- routing/road_graph_router.cpp | 3 +- routing/route.hpp | 52 ++++++++++++++++++- routing/routing_helpers.cpp | 32 ++++++++---- routing/routing_helpers.hpp | 6 ++- routing/routing_tests/route_tests.cpp | 9 ++-- .../routing_tests/routing_helpers_tests.cpp | 8 ++- .../routing_tests/routing_session_test.cpp | 6 ++- routing/single_vehicle_world_graph.cpp | 5 ++ routing/single_vehicle_world_graph.hpp | 2 + routing/transit_graph.cpp | 34 ++++++------ routing/transit_graph.hpp | 7 +-- routing/transit_world_graph.cpp | 20 +++++-- routing/transit_world_graph.hpp | 4 +- routing/world_graph.hpp | 5 ++ 15 files changed, 155 insertions(+), 49 deletions(-) diff --git a/routing/index_router.cpp b/routing/index_router.cpp index a25c2636c8..351bbb8a12 100644 --- a/routing/index_router.cpp +++ b/routing/index_router.cpp @@ -817,10 +817,15 @@ IRouter::ResultCode IndexRouter::RedressRoute(vector const & segments, time += starter.CalcRouteSegmentWeight(segments, i).GetWeight(); times.emplace_back(static_cast(i + 1), time); } - + + map segmentToTransitInfo; + auto & worldGraph = starter.GetGraph(); + for (auto const & segment : segments) + segmentToTransitInfo.emplace(segment, worldGraph.GetTransitInfo(segment)); + CHECK(m_directionsEngine, ()); - ReconstructRoute(*m_directionsEngine, roadGraph, m_trafficStash, delegate, junctions, move(times), - route); + ReconstructRoute(*m_directionsEngine, roadGraph, m_trafficStash, delegate, junctions, + segmentToTransitInfo, move(times), route); if (!route.IsValid()) { diff --git a/routing/road_graph_router.cpp b/routing/road_graph_router.cpp index 16b640b24d..8888446594 100644 --- a/routing/road_graph_router.cpp +++ b/routing/road_graph_router.cpp @@ -27,6 +27,7 @@ #include "base/assert.hpp" #include "std/algorithm.hpp" +#include "std/map.hpp" #include "std/queue.hpp" #include "std/set.hpp" @@ -211,7 +212,7 @@ IRouter::ResultCode RoadGraphRouter::CalculateRoute(Checkpoints const & checkpoi route.SetSubroteAttrs(vector( {Route::SubrouteAttrs(startPos, finalPos, 0, result.m_path.size() - 1)})); ReconstructRoute(*m_directionsEngine, *m_roadGraph, nullptr /* trafficStash */, delegate, - result.m_path, std::move(times), route); + result.m_path, map(), std::move(times), route); } m_roadGraph->ResetFakes(); diff --git a/routing/route.hpp b/routing/route.hpp index 6eee5e0acf..ee8390ad56 100644 --- a/routing/route.hpp +++ b/routing/route.hpp @@ -7,6 +7,8 @@ #include "routing/base/followed_polyline.hpp" +#include "routing_common/transit_types.hpp" + #include "traffic/speed_groups.hpp" #include "indexer/feature_altitude.hpp" @@ -32,14 +34,44 @@ namespace routing using SubrouteUid = uint64_t; SubrouteUid constexpr kInvalidSubrouteId = std::numeric_limits::max(); +class TransitInfo final +{ +public: + enum class Type + { + None, + Gate, + Edge, + Transfer + }; + + explicit TransitInfo(Type type) : m_type(type) { ASSERT_NOT_EQUAL(type, Type::Edge, ()); } + explicit TransitInfo(transit::Edge const & edge) + : m_type(Type::Edge), m_lineId(edge.GetLineId()), m_shapeIds(edge.GetShapeIds()) + { + } + + Type GetType() const { return m_type; } + transit::LineId GetLineId() const { return m_lineId; } + std::vector const & GetShapeIds() const { return m_shapeIds; } + +private: + Type m_type = Type::None; + // Valid for m_type == Type::Edge only. + transit::LineId m_lineId = transit::kInvalidLineId; + // Valid for m_type == Type::Edge only. + std::vector m_shapeIds; +}; + /// \brief The route is composed of one or several subroutes. Every subroute is composed of segments. /// For every Segment is kept some attributes in the structure SegmentInfo. class RouteSegment final { public: RouteSegment(Segment const & segment, turns::TurnItem const & turn, Junction const & junction, - std::string const & street, double distFromBeginningMeters, double distFromBeginningMerc, - double timeFromBeginningS, traffic::SpeedGroup traffic) + std::string const & street, double distFromBeginningMeters, + double distFromBeginningMerc, double timeFromBeginningS, traffic::SpeedGroup traffic, + TransitInfo transitInfo) : m_segment(segment) , m_turn(turn) , m_junction(junction) @@ -48,6 +80,7 @@ public: , m_distFromBeginningMerc(distFromBeginningMerc) , m_timeFromBeginningS(timeFromBeginningS) , m_traffic(traffic) + , m_transitInfo(transitInfo) { } @@ -59,6 +92,7 @@ public: double GetDistFromBeginningMerc() const { return m_distFromBeginningMerc; } double GetTimeFromBeginningSec() const { return m_timeFromBeginningS; } traffic::SpeedGroup GetTraffic() const { return m_traffic; } + TransitInfo const & GetTransitInfo() const { return m_transitInfo; } private: Segment m_segment; @@ -76,6 +110,9 @@ private: /// 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; + /// Information needed to display transit segments properly. + /// Nontransit segments have m_transitInfo.m_type == TransitInfo::Type::None. + TransitInfo m_transitInfo; }; class Route @@ -331,4 +368,15 @@ private: size_t m_currentSubrouteIdx = 0; std::vector m_subrouteAttrs; }; + +inline std::string DebugPrint(TransitInfo::Type type) +{ + switch (type) + { + case TransitInfo::Type::None: return "None"; + case TransitInfo::Type::Gate: return "Gate"; + case TransitInfo::Type::Edge: return "Edge"; + case TransitInfo::Type::Transfer: return "Transfer"; + } +} } // namespace routing diff --git a/routing/routing_helpers.cpp b/routing/routing_helpers.cpp index ee3c6f1bd0..224de95ecb 100644 --- a/routing/routing_helpers.cpp +++ b/routing/routing_helpers.cpp @@ -8,7 +8,6 @@ #include #include -#include namespace { @@ -23,15 +22,15 @@ using namespace traffic; void FillSegmentInfo(vector const & segments, vector const & junctions, Route::TTurns const & turns, Route::TStreets const & streets, Route::TTimes const & times, shared_ptr const & trafficStash, - vector & routeSegment) + vector const & transitInfo, vector & routeSegment) { CHECK_EQUAL(segments.size() + 1, junctions.size(), ()); CHECK(!turns.empty(), ()); CHECK(!times.empty(), ()); - CHECK(std::is_sorted(turns.cbegin(), turns.cend(), my::LessBy(&turns::TurnItem::m_index)), ()); - CHECK(std::is_sorted(streets.cbegin(), streets.cend(), my::LessBy(&Route::TStreetItem::first)), ()); - CHECK(std::is_sorted(times.cbegin(), times.cend(), my::LessBy(&Route::TTimeItem::first)), ()); + CHECK(is_sorted(turns.cbegin(), turns.cend(), my::LessBy(&turns::TurnItem::m_index)), ()); + CHECK(is_sorted(streets.cbegin(), streets.cend(), my::LessBy(&Route::TStreetItem::first)), ()); + CHECK(is_sorted(times.cbegin(), times.cend(), my::LessBy(&Route::TTimeItem::first)), ()); CHECK_LESS(turns.back().m_index, junctions.size(), ()); if (!streets.empty()) @@ -92,15 +91,17 @@ void FillSegmentInfo(vector const & segments, vector const & routeLengthMerc += junctions[i].GetPoint().Length(junctions[i + 1].GetPoint()); routeSegment.emplace_back( - segments[i], curTurn, junctions[i + 1], curStreet, routeLengthMeters, - routeLengthMerc, timeFromBeginningS, - trafficStash ? trafficStash->GetSpeedGroup(segments[i]) : traffic::SpeedGroup::Unknown); + segments[i], curTurn, junctions[i + 1], curStreet, routeLengthMeters, routeLengthMerc, + timeFromBeginningS, + trafficStash ? trafficStash->GetSpeedGroup(segments[i]) : traffic::SpeedGroup::Unknown, + transitInfo[i]); } } void ReconstructRoute(IDirectionsEngine & engine, RoadGraphBase const & graph, shared_ptr const & trafficStash, my::Cancellable const & cancellable, vector const & path, + map const & segmentToTransitInfo, Route::TTimes && times, Route & route) { if (path.empty()) @@ -115,10 +116,22 @@ void ReconstructRoute(IDirectionsEngine & engine, RoadGraphBase const & graph, vector junctions; Route::TStreets streetNames; vector segments; + vector transitInfo; if (!engine.Generate(graph, path, cancellable, turnsDir, streetNames, junctions, segments)) return; + for (auto const & segment : segments) + { + auto const it = segmentToTransitInfo.find(segment); + if (it != segmentToTransitInfo.cend()) + transitInfo.push_back(it->second); + else + transitInfo.push_back(TransitInfo(TransitInfo::Type::None)); + } + + CHECK_EQUAL(transitInfo.size(), segments.size(), ()); + if (cancellable.IsCancelled()) return; @@ -133,7 +146,8 @@ void ReconstructRoute(IDirectionsEngine & engine, RoadGraphBase const & graph, ("Size of path:", path.size(), "size of junctions:", junctions.size())); vector segmentInfo; - FillSegmentInfo(segments, junctions, turnsDir, streetNames, times, trafficStash, segmentInfo); + FillSegmentInfo(segments, junctions, turnsDir, streetNames, times, trafficStash, transitInfo, + segmentInfo); CHECK_EQUAL(segmentInfo.size(), segments.size(), ()); route.SetRouteSegments(move(segmentInfo)); diff --git a/routing/routing_helpers.hpp b/routing/routing_helpers.hpp index 734c442dec..c5fb8331af 100644 --- a/routing/routing_helpers.hpp +++ b/routing/routing_helpers.hpp @@ -13,6 +13,7 @@ #include "base/cancellable.hpp" +#include #include #include #include @@ -31,12 +32,15 @@ bool IsRoad(TTypes const & types) void FillSegmentInfo(std::vector const & segments, std::vector const & junctions, Route::TTurns const & turns, Route::TStreets const & streets, - Route::TTimes const & times, std::shared_ptr const & trafficStash, + Route::TTimes const & times, + std::shared_ptr const & trafficStash, + std::vector const & transitInfo, std::vector & routeSegment); void ReconstructRoute(IDirectionsEngine & engine, RoadGraphBase const & graph, std::shared_ptr const & trafficStash, my::Cancellable const & cancellable, std::vector const & path, + std::map const & segmentToTransitInfo, Route::TTimes && times, Route & route); /// \brief Converts |edge| to |segment|. diff --git a/routing/routing_tests/route_tests.cpp b/routing/routing_tests/route_tests.cpp index 1e86dfdc66..db17e9c5c9 100644 --- a/routing/routing_tests/route_tests.cpp +++ b/routing/routing_tests/route_tests.cpp @@ -56,10 +56,11 @@ void GetTestRouteSegments(vector const & routePoints, Route::TTurns { routeLengthMeters += MercatorBounds::DistanceOnEarth(routePoints[i - 1], routePoints[i]); routeLengthMertc += routePoints[i - 1].Length(routePoints[i]); - routeSegments.emplace_back( - Segment(0 /* mwm id */, static_cast(i) /* feature id */, 0 /* seg id */, true /* forward */), turns[i], - Junction(routePoints[i], feature::kInvalidAltitude), streets[i], routeLengthMeters, - routeLengthMertc, times[i], traffic::SpeedGroup::Unknown); + routeSegments.emplace_back(Segment(0 /* mwm id */, static_cast(i) /* feature id */, + 0 /* seg id */, true /* forward */), + turns[i], Junction(routePoints[i], feature::kInvalidAltitude), + streets[i], routeLengthMeters, routeLengthMertc, times[i], + traffic::SpeedGroup::Unknown, TransitInfo(TransitInfo::Type::None)); } } diff --git a/routing/routing_tests/routing_helpers_tests.cpp b/routing/routing_tests/routing_helpers_tests.cpp index 1a6987c444..fe9d7c9d12 100644 --- a/routing/routing_tests/routing_helpers_tests.cpp +++ b/routing/routing_tests/routing_helpers_tests.cpp @@ -29,8 +29,10 @@ UNIT_TEST(FillSegmentInfoSmokeTest) Route::TStreets const streets = {}; Route::TTimes const times = {{0 /* point index */, 0.0 /* time in seconds */}, {1, 1.0}}; + vector const transitInfo(segments.size(), TransitInfo(TransitInfo::Type::None)); + vector segmentInfo; - FillSegmentInfo(segments, junctions, turnDirs, streets, times, nullptr, segmentInfo); + FillSegmentInfo(segments, junctions, turnDirs, streets, times, nullptr, transitInfo, segmentInfo); TEST_EQUAL(segmentInfo.size(), 1, ()); TEST_EQUAL(segmentInfo[0].GetTurn().m_turn, CarDirection::ReachedYourDestination, ()); @@ -51,8 +53,10 @@ UNIT_TEST(FillSegmentInfoTest) Route::TTimes const times = { {0 /* point index */, 0.0 /* time in seconds */}, {1, 1.0}, {2, 2.0}}; + vector const transitInfo(segments.size(), TransitInfo(TransitInfo::Type::None)); + vector segmentInfo; - FillSegmentInfo(segments, junctions, turnDirs, streets, times, nullptr, segmentInfo); + FillSegmentInfo(segments, junctions, turnDirs, streets, times, nullptr, transitInfo, segmentInfo); TEST_EQUAL(segmentInfo.size(), 2, ()); TEST_EQUAL(segmentInfo[0].GetTurn().m_turn, CarDirection::TurnRight, ()); diff --git a/routing/routing_tests/routing_session_test.cpp b/routing/routing_tests/routing_session_test.cpp index 8b17ca8f33..65df91a07a 100644 --- a/routing/routing_tests/routing_session_test.cpp +++ b/routing/routing_tests/routing_session_test.cpp @@ -83,9 +83,11 @@ void FillSubroutesInfo(Route & route) for (auto const & point : kTestRoute) junctions.emplace_back(point, feature::kDefaultAltitudeMeters); + vector const transitInfo(kTestSegments.size(), TransitInfo(TransitInfo::Type::None)); + vector segmentInfo; - FillSegmentInfo(kTestSegments, junctions, kTestTurns, {}, kTestTimes, - nullptr /* trafficStash */, segmentInfo); + FillSegmentInfo(kTestSegments, junctions, kTestTurns, {}, kTestTimes, nullptr /* trafficStash */, + transitInfo, segmentInfo); route.SetRouteSegments(move(segmentInfo)); route.SetSubroteAttrs(vector( {Route::SubrouteAttrs(junctions.front(), junctions.back(), 0, kTestSegments.size())})); diff --git a/routing/single_vehicle_world_graph.cpp b/routing/single_vehicle_world_graph.cpp index 315f1d9672..b748b2c76a 100644 --- a/routing/single_vehicle_world_graph.cpp +++ b/routing/single_vehicle_world_graph.cpp @@ -119,6 +119,11 @@ bool SingleVehicleWorldGraph::LeapIsAllowed(NumMwmId mwmId) const return m_estimator->LeapIsAllowed(mwmId); } +TransitInfo SingleVehicleWorldGraph::GetTransitInfo(Segment const & segment) +{ + return TransitInfo(TransitInfo::Type::None); +} + RoadGeometry const & SingleVehicleWorldGraph::GetRoadGeometry(NumMwmId mwmId, uint32_t featureId) { return m_loader->GetIndexGraph(mwmId).GetGeometry().GetRoad(featureId); diff --git a/routing/single_vehicle_world_graph.hpp b/routing/single_vehicle_world_graph.hpp index e0ee8a0c77..e0a1f8f264 100644 --- a/routing/single_vehicle_world_graph.hpp +++ b/routing/single_vehicle_world_graph.hpp @@ -6,6 +6,7 @@ #include "routing/index_graph.hpp" #include "routing/index_graph_loader.hpp" #include "routing/road_graph.hpp" +#include "routing/route.hpp" #include "routing/segment.hpp" #include "routing/world_graph.hpp" @@ -42,6 +43,7 @@ public: RouteWeight CalcSegmentWeight(Segment const & segment) override; RouteWeight CalcLeapWeight(m2::PointD const & from, m2::PointD const & to) const override; bool LeapIsAllowed(NumMwmId mwmId) const override; + TransitInfo GetTransitInfo(Segment const & segment) override; // This method should be used for tests only IndexGraph & GetIndexGraphForTests(NumMwmId numMwmId) diff --git a/routing/transit_graph.cpp b/routing/transit_graph.cpp index a60b51c6ad..11dd001ae2 100644 --- a/routing/transit_graph.cpp +++ b/routing/transit_graph.cpp @@ -113,6 +113,23 @@ void TransitGraph::Fill(vector const & stops, vector 0; +} + +bool TransitGraph::IsEdge(Segment const & segment) const +{ + return m_segmentToEdge.count(segment) > 0; +} + +transit::Edge const & TransitGraph::GetEdge(Segment const & segment) const +{ + auto const it = m_segmentToEdge.find(segment); + CHECK(it != m_segmentToEdge.cend(), ("Unknown transit segment.")); + return it->second; +} + Segment TransitGraph::GetTransitSegment(uint32_t segmentIdx) const { return Segment(m_mwmId, kTransitFeatureId, segmentIdx, false); @@ -211,23 +228,6 @@ void TransitGraph::AddConnections(map> const & con } } -bool TransitGraph::IsGate(Segment const & segment) const -{ - return m_segmentToGate.count(segment) > 0; -} - -bool TransitGraph::IsEdge(Segment const & segment) const -{ - return m_segmentToEdge.count(segment) > 0; -} - -transit::Edge const & TransitGraph::GetEdge(Segment const & segment) const -{ - auto const it = m_segmentToEdge.find(segment); - CHECK(it != m_segmentToEdge.cend(), ("Unknown transit segment.")); - return it->second; -} - transit::Gate const & TransitGraph::GetGate(Segment const & segment) const { auto const it = m_segmentToGate.find(segment); diff --git a/routing/transit_graph.hpp b/routing/transit_graph.hpp index d767cbf9af..e888288add 100644 --- a/routing/transit_graph.hpp +++ b/routing/transit_graph.hpp @@ -39,6 +39,10 @@ public: std::vector const & edges, EdgeEstimator const & estimator, NumMwmId numMwmId, IndexGraph & indexGraph); + bool IsGate(Segment const & segment) const; + bool IsEdge(Segment const & segment) const; + transit::Edge const & GetEdge(Segment const & segment) const; + private: Segment GetTransitSegment(uint32_t segmentIdx) const; Segment GetNewTransitSegment() const; @@ -51,9 +55,6 @@ private: void AddConnections(std::map> const & connections, bool isOutgoing); - bool IsGate(Segment const & segment) const; - bool IsEdge(Segment const & segment) const; - transit::Edge const & GetEdge(Segment const & segment) const; transit::Gate const & GetGate(Segment const & segment) const; static uint32_t constexpr kTransitFeatureId = FakeFeatureIds::kTransitGraphId; diff --git a/routing/transit_world_graph.cpp b/routing/transit_world_graph.cpp index 872a8ba0c5..aede49935b 100644 --- a/routing/transit_world_graph.cpp +++ b/routing/transit_world_graph.cpp @@ -137,10 +137,24 @@ RouteWeight TransitWorldGraph::CalcLeapWeight(m2::PointD const & from, m2::Point bool TransitWorldGraph::LeapIsAllowed(NumMwmId /* mwmId */) const { return false; } -//static -bool TransitWorldGraph::IsTransitSegment(Segment const & segment) +TransitInfo TransitWorldGraph::GetTransitInfo(Segment const & segment) { - return TransitGraph::IsTransitSegment(segment); + if (!TransitGraph::IsTransitSegment(segment)) + return TransitInfo(TransitInfo::Type::None); + + auto & transitGraph = GetTransitGraph(segment.GetMwmId()); + if (transitGraph.IsGate(segment)) + return TransitInfo(TransitInfo::Type::Gate); + + // Fake segment between pedestrian feature and gate. + if (!transitGraph.IsEdge(segment)) + return TransitInfo(TransitInfo::Type::None); + + auto const & edge = transitGraph.GetEdge(segment); + if (edge.GetTransfer()) + return TransitInfo(TransitInfo::Type::Transfer); + + return TransitInfo(edge); } void TransitWorldGraph::GetTwins(Segment const & segment, bool isOutgoing, diff --git a/routing/transit_world_graph.hpp b/routing/transit_world_graph.hpp index cf9d0e465d..d776ab3314 100644 --- a/routing/transit_world_graph.hpp +++ b/routing/transit_world_graph.hpp @@ -5,6 +5,7 @@ #include "routing/geometry.hpp" #include "routing/index_graph_loader.hpp" #include "routing/road_graph.hpp" +#include "routing/route.hpp" #include "routing/segment.hpp" #include "routing/transit_graph_loader.hpp" #include "routing/world_graph.hpp" @@ -47,8 +48,7 @@ public: RouteWeight CalcSegmentWeight(Segment const & segment) override; RouteWeight CalcLeapWeight(m2::PointD const & from, m2::PointD const & to) const override; bool LeapIsAllowed(NumMwmId mwmId) const override; - - static bool IsTransitSegment(Segment const & segment); + TransitInfo GetTransitInfo(Segment const & segment) override; private: RoadGeometry const & GetRealRoadGeometry(NumMwmId mwmId, uint32_t featureId); diff --git a/routing/world_graph.hpp b/routing/world_graph.hpp index 898851ab9f..cf4ba0ed02 100644 --- a/routing/world_graph.hpp +++ b/routing/world_graph.hpp @@ -3,6 +3,7 @@ #include "routing/geometry.hpp" #include "routing/index_graph.hpp" #include "routing/road_graph.hpp" +#include "routing/route.hpp" #include "routing/segment.hpp" #include "routing_common/num_mwm_id.hpp" @@ -67,6 +68,10 @@ public: virtual RouteWeight CalcSegmentWeight(Segment const & segment) = 0; virtual RouteWeight CalcLeapWeight(m2::PointD const & from, m2::PointD const & to) const = 0; virtual bool LeapIsAllowed(NumMwmId mwmId) const = 0; + + // Returns transit-specific information for segment. For nontransit segments returns + // TransitInfo with m_type == TransitInfo::Type::None. + virtual TransitInfo GetTransitInfo(Segment const & segment) = 0; }; std::string DebugPrint(WorldGraph::Mode mode);