diff --git a/routing/index_graph_starter.cpp b/routing/index_graph_starter.cpp index 183ae6ddc2..5f31d0fc8a 100644 --- a/routing/index_graph_starter.cpp +++ b/routing/index_graph_starter.cpp @@ -22,22 +22,21 @@ namespace routing Segment constexpr IndexGraphStarter::kStartFakeSegment; Segment constexpr IndexGraphStarter::kFinishFakeSegment; -IndexGraphStarter::IndexGraphStarter(FakeVertex const & start, FakeVertex const & finish, - WorldGraph & graph) +IndexGraphStarter::IndexGraphStarter(FakeVertex const & start, FakeVertex const & finish, WorldGraph & graph) : m_graph(graph) , m_start(start.GetSegment(), - CalcProjectionToSegment(start.GetSegment(), start.GetPoint(), graph)) + CalcProjectionToSegment(start.GetSegment(), start.GetPoint(), graph), start.GetSoft()) , m_finish(finish.GetSegment(), - CalcProjectionToSegment(finish.GetSegment(), finish.GetPoint(), graph)) + CalcProjectionToSegment(finish.GetSegment(), finish.GetPoint(), graph), finish.GetSoft()) { } m2::PointD const & IndexGraphStarter::GetPoint(Segment const & segment, bool front) { - if (segment == kStartFakeSegment || (!front && m_start.Fits(segment))) + if (segment == kStartFakeSegment) return m_start.GetPoint(); - if (segment == kFinishFakeSegment || (front && m_finish.Fits(segment))) + if (segment == kFinishFakeSegment) return m_finish.GetPoint(); return m_graph.GetPoint(segment, front); @@ -61,6 +60,9 @@ m2::PointD const & IndexGraphStarter::GetRoutePoint(vector const & segm if (pointIndex == 0) return m_start.GetPoint(); + if (pointIndex + 1 == GetRouteNumPoints(segments)) + return m_finish.GetPoint(); + CHECK_LESS(pointIndex, segments.size(), ()); return GetPoint(segments[pointIndex], true /* front */); } @@ -82,6 +84,12 @@ void IndexGraphStarter::GetEdgesList(Segment const & segment, bool isOutgoing, return; } + if (m_graph.GetMode() == WorldGraph::Mode::LeapsOnly && (m_start.Fits(segment) || m_finish.Fits(segment))) + { + ConnectLeapToTransitions(segment, isOutgoing, edges); + return; + } + m_graph.GetEdgeList(segment, isOutgoing, IsLeap(segment.GetMwmId()), edges); GetNormalToFakeEdge(segment, m_start, kStartFakeSegment, isOutgoing, edges); GetNormalToFakeEdge(segment, m_finish, kFinishFakeSegment, isOutgoing, edges); @@ -90,9 +98,9 @@ void IndexGraphStarter::GetEdgesList(Segment const & segment, bool isOutgoing, void IndexGraphStarter::GetFakeToNormalEdges(FakeVertex const & fakeVertex, bool isOutgoing, vector & edges) { - if (m_graph.GetMode() == WorldGraph::Mode::LeapsOnly) + if (!fakeVertex.GetSoft()) { - ConnectLeapToTransitions(fakeVertex, isOutgoing, edges); + GetFakeToNormalEdge(fakeVertex, fakeVertex.GetSegment().IsForward(), edges); return; } @@ -134,18 +142,18 @@ void IndexGraphStarter::GetNormalToFakeEdge(Segment const & segment, FakeVertex m_graph.GetEstimator().CalcLeapWeight(pointFrom, fakeVertex.GetPoint())); } -void IndexGraphStarter::ConnectLeapToTransitions(FakeVertex const & fakeVertex, bool isOutgoing, +void IndexGraphStarter::ConnectLeapToTransitions(Segment const & segment, bool isOutgoing, vector & edges) { edges.clear(); - m2::PointD const & segmentPoint = fakeVertex.GetPoint(); + m2::PointD const & segmentPoint = GetPoint(segment, true /* front */); // Note. If |isOutgoing| == true it's necessary to add edges which connect the start with all // exits of its mwm. So |isEnter| below should be set to false. // If |isOutgoing| == false all enters of the finish mwm should be connected with the finish point. // So |isEnter| below should be set to true. m_graph.ForEachTransition( - fakeVertex.GetMwmId(), !isOutgoing /* isEnter */, [&](Segment const & transition) { + segment.GetMwmId(), !isOutgoing /* isEnter */, [&](Segment const & transition) { edges.emplace_back(transition, m_graph.GetEstimator().CalcLeapWeight( segmentPoint, GetPoint(transition, isOutgoing))); }); diff --git a/routing/index_graph_starter.hpp b/routing/index_graph_starter.hpp index 197fc7aa4c..3ae981d196 100644 --- a/routing/index_graph_starter.hpp +++ b/routing/index_graph_starter.hpp @@ -24,12 +24,12 @@ public: { public: FakeVertex(NumMwmId mwmId, uint32_t featureId, uint32_t segmentIdx, m2::PointD const & point) - : m_segment(mwmId, featureId, segmentIdx, true /* forward */), m_point(point) + : m_segment(mwmId, featureId, segmentIdx, true /* forward */), m_point(point), m_soft(true) { } - FakeVertex(Segment const & segment, m2::PointD const & point) - : m_segment(segment), m_point(point) + FakeVertex(Segment const & segment, m2::PointD const & point, bool soft) + : m_segment(segment), m_point(point), m_soft(soft) { } @@ -37,6 +37,7 @@ public: uint32_t GetFeatureId() const { return m_segment.GetFeatureId(); } m2::PointD const & GetPoint() const { return m_point; } Segment const & GetSegment() const { return m_segment; } + bool GetSoft() const { return m_soft; } Segment GetSegmentWithDirection(bool forward) const { @@ -46,10 +47,11 @@ public: bool Fits(Segment const & segment) const { - // Note. Comparing |segment| and |m_segment| without field |Segment::m_forward|. - return segment.GetMwmId() == m_segment.GetMwmId() && - segment.GetFeatureId() == m_segment.GetFeatureId() && - segment.GetSegmentIdx() == m_segment.GetSegmentIdx(); + bool const softFits = segment.GetMwmId() == m_segment.GetMwmId() && + segment.GetFeatureId() == m_segment.GetFeatureId() && + segment.GetSegmentIdx() == m_segment.GetSegmentIdx(); + return m_soft ? softFits : softFits && m_segment.IsForward() == segment.IsForward(); + } uint32_t GetSegmentIdxForTesting() const { return m_segment.GetSegmentIdx(); } @@ -57,6 +59,7 @@ public: private: Segment m_segment; m2::PointD const m_point; + bool const m_soft; }; static uint32_t constexpr kFakeFeatureId = numeric_limits::max(); @@ -74,6 +77,7 @@ public: FakeVertex const & GetStartVertex() const { return m_start; } FakeVertex const & GetFinishVertex() const { return m_finish; } m2::PointD const & GetPoint(Segment const & segment, bool front); + bool FitsFinish(Segment const & s) const { return m_finish.Fits(s); } static size_t GetRouteNumPoints(vector const & route); m2::PointD const & GetRoutePoint(vector const & route, size_t pointIndex); @@ -125,7 +129,7 @@ private: /// |fakeVertex| with all exits of mwm. /// \brief If |isOutgoing| == false fills |edges| with SegmentEdge(s) which connects /// all enters to mwm with |fakeVertex|. - void ConnectLeapToTransitions(FakeVertex const & fakeVertex, bool isOutgoing, + void ConnectLeapToTransitions(Segment const & segment, bool isOutgoing, vector & edges); WorldGraph & m_graph; diff --git a/routing/index_road_graph.cpp b/routing/index_road_graph.cpp index d28838ab51..9f063bd0ce 100644 --- a/routing/index_road_graph.cpp +++ b/routing/index_road_graph.cpp @@ -97,10 +97,16 @@ void IndexRoadGraph::GetEdges(Junction const & junction, bool isOutgoing, TEdgeV } } +m2::PointD IndexRoadGraph::GetJunctionPoint(Segment const & segment, bool front) const +{ + return front && m_starter.FitsFinish(segment) ? m_starter.GetFinishVertex().GetPoint() + : m_starter.GetPoint(segment, front); +} + Junction IndexRoadGraph::GetJunction(Segment const & segment, bool front) const { // TODO: Use real altitudes for pedestrian and bicycle routing. - return Junction(m_starter.GetPoint(segment, front), feature::kDefaultAltitudeMeters); + return Junction(GetJunctionPoint(segment, front), feature::kDefaultAltitudeMeters); } vector const & IndexRoadGraph::GetSegments(Junction const & junction, diff --git a/routing/index_road_graph.hpp b/routing/index_road_graph.hpp index 383ca5ff50..36495e65b6 100644 --- a/routing/index_road_graph.hpp +++ b/routing/index_road_graph.hpp @@ -29,6 +29,7 @@ public: private: void GetEdges(Junction const & junction, bool isOutgoing, TEdgeVector & edges) const; + m2::PointD GetJunctionPoint(Segment const & segment, bool front) const; Junction GetJunction(Segment const & segment, bool front) const; vector const & GetSegments(Junction const & junction, bool isOutgoing) const; diff --git a/routing/index_router.cpp b/routing/index_router.cpp index 4fbb94863f..8417b92398 100644 --- a/routing/index_router.cpp +++ b/routing/index_router.cpp @@ -193,11 +193,11 @@ IRouter::ResultCode IndexRouter::DoCalculateRoute(string const & startCountry, IndexGraphStarter::FakeVertex const start( Segment(m_numMwmIds->GetId(startFile), startEdge.GetFeatureId().m_index, startEdge.GetSegId(), true /* forward */), - startPoint); + startPoint, true /* soft */); IndexGraphStarter::FakeVertex const finish( Segment(m_numMwmIds->GetId(finishFile), finishEdge.GetFeatureId().m_index, finishEdge.GetSegId(), true /* forward */), - finalPoint); + finalPoint, true /* soft */); WorldGraph::Mode mode = WorldGraph::Mode::SingleMwm; if (forSingleMwm) @@ -310,7 +310,9 @@ IRouter::ResultCode IndexRouter::ProcessLeaps(vector const & input, for (size_t i = 0; i < input.size(); ++i) { Segment const & current = input[i]; - if (worldRouteMode == WorldGraph::Mode::LeapsIfPossible && !starter.IsLeap(current.GetMwmId())) + + if ((worldRouteMode == WorldGraph::Mode::LeapsOnly && IndexGraphStarter::IsFakeSegment(current)) + || (worldRouteMode != WorldGraph::Mode::LeapsOnly && !starter.IsLeap(current.GetMwmId()))) { output.push_back(current); continue; @@ -330,14 +332,8 @@ IRouter::ResultCode IndexRouter::ProcessLeaps(vector const & input, ("Different mwm ids for leap enter and exit, i:", i, "size of input:", input.size())); } - IndexGraphStarter::FakeVertex const start = - (current == IndexGraphStarter::kStartFakeSegment) - ? starter.GetStartVertex() - : IndexGraphStarter::FakeVertex(current, starter.GetPoint(current, true /* front */)); - IndexGraphStarter::FakeVertex const finish = - (next == IndexGraphStarter::kFinishFakeSegment) - ? starter.GetFinishVertex() - : IndexGraphStarter::FakeVertex(next, starter.GetPoint(next, true /* front */)); + IndexGraphStarter::FakeVertex const start(current, starter.GetPoint(current, true /* front */), false /* soft */); + IndexGraphStarter::FakeVertex const finish(next, starter.GetPoint(next, true /* front */), false /* soft */); IndexGraphStarter leapStarter(start, finish, starter.GetGraph()); diff --git a/routing/routing_tests/index_graph_test.cpp b/routing/routing_tests/index_graph_test.cpp index 44505eaf01..0dd7702792 100644 --- a/routing/routing_tests/index_graph_test.cpp +++ b/routing/routing_tests/index_graph_test.cpp @@ -375,7 +375,28 @@ UNIT_TEST(OneSegmentWay) IndexGraphStarter::FakeVertex const start(kTestNumMwmId, 0, 0, m2::PointD(1, 0)); IndexGraphStarter::FakeVertex const finish(kTestNumMwmId, 0, 0, m2::PointD(2, 0)); - vector const expectedRoute({{kTestNumMwmId, 0, 0, true}}); + // According to picture above it seems that direction of route segment should be true but it's false + // according to current code. The reason is the start and the finish of the route are projected to + // the same segment. In IndexGraphStarter::GetEdgesList() two fake edges are added. One of them + // from start to end of the segment. The other one is from beginning of the segment to the finish. + // So the route will be built in opposite direction of segment 0 of feature 0. See IndexGraphStarter + // for details. + // + // finish + // O + // ↗ + // ↗ + // ↗ + // R0 * - - - - - - - - * + // ↗ + // ↗ + // ↗ + // O + // start + // + // x: 0 1 2 3 + vector const expectedRoute({{kTestNumMwmId, 0 /* featureId */, 0 /* seg id */, + false /* forward */}}); TestRoute(start, finish, 1 /* expectedLength */, &expectedRoute, *worldGraph); }