From 451c081f8cef7d9ff75d924ecb8ea11b5279cc70 Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Fri, 19 May 2017 15:11:22 +0300 Subject: [PATCH] Routing issue fixes. A star invariant violation because of it was possible to get to different coords for the same segment. Stopping making uturn at non joint road point near two cross mwm route gathering point. Route segment is correct now. --- routing/index_graph_starter.cpp | 30 ++++++++++++++-------- routing/index_graph_starter.hpp | 20 +++++++++------ routing/index_road_graph.cpp | 8 +++++- routing/index_road_graph.hpp | 1 + routing/index_router.cpp | 18 +++++-------- routing/routing_tests/index_graph_test.cpp | 23 ++++++++++++++++- 6 files changed, 68 insertions(+), 32 deletions(-) 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); }