diff --git a/routing/edge_estimator.cpp b/routing/edge_estimator.cpp index 043ec75919..8f48511c00 100644 --- a/routing/edge_estimator.cpp +++ b/routing/edge_estimator.cpp @@ -44,6 +44,7 @@ public: double CalcSegmentWeight(Segment const & segment, RoadGeometry const & road) const override; double CalcHeuristic(m2::PointD const & from, m2::PointD const & to) const override; double GetUTurnPenalty() const override; + bool AllowLeap(NumMwmId mwmId) const override; private: shared_ptr m_trafficStash; @@ -100,6 +101,8 @@ double CarEdgeEstimator::GetUTurnPenalty() const // experiments. return 2 * 60; // seconds } + +bool CarEdgeEstimator::AllowLeap(NumMwmId mwmId) const { return !m_trafficStash->Has(mwmId); } } // namespace namespace routing diff --git a/routing/edge_estimator.hpp b/routing/edge_estimator.hpp index 2de89afdd2..e9ffcbb480 100644 --- a/routing/edge_estimator.hpp +++ b/routing/edge_estimator.hpp @@ -25,6 +25,7 @@ public: virtual double CalcSegmentWeight(Segment const & segment, RoadGeometry const & road) const = 0; virtual double CalcHeuristic(m2::PointD const & from, m2::PointD const & to) const = 0; virtual double GetUTurnPenalty() const = 0; + virtual bool AllowLeap(NumMwmId mwmId) const = 0; static shared_ptr CreateForCar(shared_ptr trafficStash, double maxSpeedKMpH); diff --git a/routing/index_graph_starter.cpp b/routing/index_graph_starter.cpp index 7c4ea15f4e..8fa511e2dd 100644 --- a/routing/index_graph_starter.cpp +++ b/routing/index_graph_starter.cpp @@ -65,7 +65,7 @@ void IndexGraphStarter::GetEdgesList(Segment const & segment, bool isOutgoing, return; } - m_graph.GetEdgeList(segment, isOutgoing, edges); + m_graph.GetEdgeList(segment, isOutgoing, IsLeap(segment.GetMwmId()), edges); GetNormalToFakeEdge(segment, m_start, kStartFakeSegment, isOutgoing, edges); GetNormalToFakeEdge(segment, m_finish, kFinishFakeSegment, isOutgoing, edges); } diff --git a/routing/index_graph_starter.hpp b/routing/index_graph_starter.hpp index 0daa4b4398..b21e70fb52 100644 --- a/routing/index_graph_starter.hpp +++ b/routing/index_graph_starter.hpp @@ -28,6 +28,14 @@ public: { } + FakeVertex(Segment const & segment, m2::PointD const & point) + : m_featureId(segment.GetFeatureId()) + , m_segmentIdx(segment.GetSegmentIdx()) + , m_mwmId(segment.GetMwmId()) + , m_point(point) + { + } + NumMwmId GetMwmId() const { return m_mwmId; } uint32_t GetFeatureId() const { return m_featureId; } uint32_t GetSegmentIdx() const { return m_segmentIdx; } @@ -48,6 +56,7 @@ public: IndexGraphStarter(FakeVertex const & start, FakeVertex const & finish, WorldGraph & graph); + WorldGraph & GetGraph() { return m_graph; } Segment const & GetStart() const { return kStartFakeSegment; } Segment const & GetFinish() const { return kFinishFakeSegment; } m2::PointD const & GetPoint(Segment const & segment, bool front); @@ -79,6 +88,12 @@ public: segment, m_graph.GetRoadGeometry(segment.GetMwmId(), segment.GetFeatureId())); } + bool IsLeap(NumMwmId mwmId) const + { + return mwmId != kFakeNumMwmId && mwmId != m_start.GetMwmId() && mwmId != m_finish.GetMwmId() && + m_graph.GetEstimator().AllowLeap(mwmId); + } + static bool IsFakeSegment(Segment const & segment) { return segment.GetFeatureId() == kFakeFeatureId; diff --git a/routing/segment.hpp b/routing/segment.hpp index 1b5b6bf620..01df618316 100644 --- a/routing/segment.hpp +++ b/routing/segment.hpp @@ -64,9 +64,8 @@ public: private: uint32_t m_featureId = 0; uint32_t m_segmentIdx = 0; - // @TODO(bykoianko, dobriy-eeh). It's a placeholder. Init m_mwmId in a proper way. NumMwmId m_mwmId = 0; - bool m_forward = true; + bool m_forward = false; }; class SegmentEdge final diff --git a/routing/single_mwm_router.cpp b/routing/single_mwm_router.cpp index 8cab095277..6f2797da2c 100644 --- a/routing/single_mwm_router.cpp +++ b/routing/single_mwm_router.cpp @@ -112,6 +112,9 @@ IRouter::ResultCode SingleMwmRouter::DoCalculateRoute(m2::PointD const & startPo m_trafficStash, m_index), m_estimator); + // TODO remove to activate CrossMwmGraph. + graph.BlockMwmBorders(); + IndexGraphStarter starter(start, finish, graph); AStarProgress progress(0, 100); @@ -141,7 +144,15 @@ IRouter::ResultCode SingleMwmRouter::DoCalculateRoute(m2::PointD const & startPo case AStarAlgorithm::Result::NoPath: return IRouter::RouteNotFound; case AStarAlgorithm::Result::Cancelled: return IRouter::Cancelled; case AStarAlgorithm::Result::OK: - if (!RedressRoute(routingResult.path, delegate, starter, route)) + vector segments; + IRouter::ResultCode const leapsResult = + ProcessLeaps(routingResult.path, delegate, starter, segments); + if (leapsResult != IRouter::NoError) + return leapsResult; + + CHECK_GREATER_OR_EQUAL(segments.size(), routingResult.path.size(), ()); + + if (!RedressRoute(segments, delegate, starter, route)) return IRouter::InternalError; if (delegate.IsCancelled()) return IRouter::Cancelled; @@ -187,6 +198,50 @@ bool SingleMwmRouter::FindClosestEdge(platform::CountryFile const & file, m2::Po return true; } +IRouter::ResultCode SingleMwmRouter::ProcessLeaps(vector const & input, + RouterDelegate const & delegate, + IndexGraphStarter & starter, + vector & output) +{ + starter.GetGraph().BlockMwmBorders(); + + for (size_t i = 0; i < input.size(); ++i) + { + Segment const & current = input[i]; + if (starter.IsLeap(current.GetMwmId())) + { + ++i; + CHECK_LESS(i, input.size(), ()); + Segment const & next = input[i]; + CHECK_EQUAL(current.GetMwmId(), next.GetMwmId(), ("i:", i)); + + IndexGraphStarter::FakeVertex const start(current, + starter.GetPoint(current, true /* front */)); + IndexGraphStarter::FakeVertex const finish(next, starter.GetPoint(next, true /* front */)); + + IndexGraphStarter leapStarter(start, finish, starter.GetGraph()); + + AStarAlgorithm algorithm; + RoutingResult routingResult; + auto const resultCode = + algorithm.FindPathBidirectional(leapStarter, leapStarter.GetStart(), + leapStarter.GetFinish(), routingResult, delegate, {}); + + switch (resultCode) + { + case AStarAlgorithm::Result::NoPath: return IRouter::RouteNotFound; + case AStarAlgorithm::Result::Cancelled: return IRouter::Cancelled; + case AStarAlgorithm::Result::OK: + output.insert(output.end(), routingResult.path.begin(), routingResult.path.end()); + } + } + else + output.push_back(current); + } + + return IRouter::NoError; +} + bool SingleMwmRouter::RedressRoute(vector const & segments, RouterDelegate const & delegate, IndexGraphStarter & starter, Route & route) const diff --git a/routing/single_mwm_router.hpp b/routing/single_mwm_router.hpp index 525ef3f003..ba23564651 100644 --- a/routing/single_mwm_router.hpp +++ b/routing/single_mwm_router.hpp @@ -52,6 +52,8 @@ private: RouterDelegate const & delegate, Route & route); bool FindClosestEdge(platform::CountryFile const & file, m2::PointD const & point, Edge & closestEdge) const; + IRouter::ResultCode ProcessLeaps(vector const & input, RouterDelegate const & delegate, + IndexGraphStarter & starter, vector & output); bool RedressRoute(vector const & segments, RouterDelegate const & delegate, IndexGraphStarter & starter, Route & route) const; diff --git a/routing/traffic_stash.hpp b/routing/traffic_stash.hpp index 772694e3ac..b7b04957a4 100644 --- a/routing/traffic_stash.hpp +++ b/routing/traffic_stash.hpp @@ -36,6 +36,11 @@ public: return it->second.get(); } + bool Has(NumMwmId numMwmId) const + { + return m_mwmToTraffic.find(numMwmId) != m_mwmToTraffic.cend(); + } + void Load(MwmSet::MwmId const & mwmId, NumMwmId numMwmId) { auto traffic = m_source.GetTrafficInfo(mwmId); diff --git a/routing/world_graph.cpp b/routing/world_graph.cpp index 2f8d584edb..b7fa3c059f 100644 --- a/routing/world_graph.cpp +++ b/routing/world_graph.cpp @@ -12,25 +12,35 @@ WorldGraph::WorldGraph(unique_ptr crossMwmGraph, CHECK(m_estimator, ()); } -void WorldGraph::GetEdgeList(Segment const & segment, bool isOutgoing, vector & edges) +void WorldGraph::GetEdgeList(Segment const & segment, bool isOutgoing, bool leap, + vector & edges) { + if (m_crossMwmGraph && leap) + { + if (m_crossMwmGraph->IsTransition(segment, isOutgoing)) + GetTwins(segment, isOutgoing, edges); + else + m_crossMwmGraph->GetEdgeList(segment, isOutgoing, edges); + return; + } + IndexGraph & indexGraph = GetIndexGraph(segment.GetMwmId()); indexGraph.GetEdgeList(segment, isOutgoing, edges); - // TODO remove this return to activate m_crossMwmGraph. - return; - - if (!m_crossMwmGraph || !m_crossMwmGraph->IsTransition(segment, isOutgoing)) - return; - - m_twins.clear(); - m_crossMwmGraph->GetTwins(segment, isOutgoing, m_twins); - for (Segment const & twin : m_twins) - edges.emplace_back(twin, 0.0 /* weight */); + if (m_crossMwmGraph && m_crossMwmGraph->IsTransition(segment, isOutgoing)) + GetTwins(segment, isOutgoing, edges); } RoadGeometry const & WorldGraph::GetRoadGeometry(NumMwmId mwmId, uint32_t featureId) { return GetIndexGraph(mwmId).GetGeometry().GetRoad(featureId); } + +void WorldGraph::GetTwins(Segment const & segment, bool isOutgoing, vector & edges) +{ + m_twins.clear(); + m_crossMwmGraph->GetTwins(segment, isOutgoing, m_twins); + for (Segment const & twin : m_twins) + edges.emplace_back(twin, 0.0 /* weight */); +} } // namespace routing diff --git a/routing/world_graph.hpp b/routing/world_graph.hpp index 504456793a..1b78154a9d 100644 --- a/routing/world_graph.hpp +++ b/routing/world_graph.hpp @@ -19,14 +19,19 @@ public: WorldGraph(std::unique_ptr crossMwmGraph, std::unique_ptr loader, std::shared_ptr estimator); - void GetEdgeList(Segment const & segment, bool isOutgoing, std::vector & edges); + void GetEdgeList(Segment const & segment, bool isOutgoing, bool leap, + std::vector & edges); IndexGraph & GetIndexGraph(NumMwmId numMwmId) { return m_loader->GetIndexGraph(numMwmId); } EdgeEstimator const & GetEstimator() const { return *m_estimator; } RoadGeometry const & GetRoadGeometry(NumMwmId mwmId, uint32_t featureId); -private: + void BlockMwmBorders() { m_crossMwmGraph = nullptr; } + +private: + void GetTwins(Segment const & s, bool isOutgoing, std::vector & edges); + std::unique_ptr m_crossMwmGraph; std::unique_ptr m_loader; std::shared_ptr m_estimator;