From 9236305fa0008d622f1dc4ba4af25ff992c148e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BE=D0=B1=D1=80=D1=8B=D0=B8=CC=86=20=D0=AD=D1=8D?= =?UTF-8?q?=D1=85?= Date: Tue, 8 Aug 2017 17:54:08 +0300 Subject: [PATCH] Add fake vertex tree to IndexGraphStarter --- routing/bicycle_directions.cpp | 2 +- routing/index_graph_starter.cpp | 434 ++++++++++++++---- routing/index_graph_starter.hpp | 244 ++++++---- routing/index_road_graph.cpp | 50 +- routing/index_road_graph.hpp | 19 +- routing/index_router.cpp | 220 ++++----- routing/index_router.hpp | 8 +- .../routing_tests/applying_traffic_test.cpp | 54 ++- .../cumulative_restriction_test.cpp | 63 ++- routing/routing_tests/index_graph_test.cpp | 157 ++++--- routing/routing_tests/index_graph_tools.cpp | 32 +- routing/routing_tests/index_graph_tools.hpp | 11 +- routing/routing_tests/restriction_test.cpp | 176 ++++--- routing/routing_tests/road_access_test.cpp | 5 +- 14 files changed, 925 insertions(+), 550 deletions(-) diff --git a/routing/bicycle_directions.cpp b/routing/bicycle_directions.cpp index e8e81f19f8..75911ae352 100644 --- a/routing/bicycle_directions.cpp +++ b/routing/bicycle_directions.cpp @@ -293,7 +293,7 @@ void BicycleDirectionsEngine::FillPathSegmentsAndAdjacentEdgesMap( { size_t const pathSize = path.size(); CHECK_GREATER(pathSize, 1, ()); - CHECK_EQUAL(routeEdges.size(), pathSize - 1, ()); + CHECK_EQUAL(routeEdges.size() + 1, pathSize, ()); // Filling |m_adjacentEdges|. auto constexpr kInvalidSegId = numeric_limits::max(); // |startSegId| is a value to keep start segment id of a new instance of LoadedPathSegment. diff --git a/routing/index_graph_starter.cpp b/routing/index_graph_starter.cpp index 570e9e3d45..4bffc02ae2 100644 --- a/routing/index_graph_starter.cpp +++ b/routing/index_graph_starter.cpp @@ -7,6 +7,35 @@ namespace using namespace routing; using namespace std; +Segment InvertDirection(Segment const & segment) +{ + return Segment(segment.GetMwmId(), segment.GetFeatureId(), segment.GetSegmentIdx(), + !segment.IsForward()); +} + +Junction InterpolateJunction(Segment const & segment, m2::PointD const & point, WorldGraph & graph) +{ + Junction const & begin = graph.GetJunction(segment, false /* front */); + Junction const & end = graph.GetJunction(segment, true /* front */); + + m2::PointD const segmentDir = end.GetPoint() - begin.GetPoint(); + if (segmentDir.IsAlmostZero()) + return Junction(point, begin.GetAltitude()); + + m2::PointD const pointDir = point - begin.GetPoint(); + + double const ratio = m2::DotProduct(segmentDir, pointDir) / segmentDir.SquaredLength(); + if (ratio <= 0.0) + return Junction(point, begin.GetAltitude()); + + if (ratio >= 1.0) + return Junction(point, end.GetAltitude()); + + return Junction(point, static_cast( + (1.0 - ratio) * static_cast(begin.GetAltitude()) + + ratio * (static_cast(end.GetAltitude())))); +} + Junction CalcProjectionToSegment(Segment const & segment, Junction const & junction, WorldGraph & graph) { @@ -19,162 +48,373 @@ Junction CalcProjectionToSegment(Segment const & segment, Junction const & junct namespace routing { -// static -Segment constexpr IndexGraphStarter::kStartFakeSegment; -Segment constexpr IndexGraphStarter::kFinishFakeSegment; +void IndexGraphStarter::AddFakeVertex(Segment const & existentSegment, Segment const & newSegment, + FakeVertex const & newVertex, bool isOutgoing, + bool isPartOfReal, Segment const & realSegment) +{ + auto const & segmentFrom = isOutgoing ? existentSegment : newSegment; + auto const & segmentTo = isOutgoing ? newSegment : existentSegment; + m_fake.m_outgoing[segmentFrom].insert(segmentTo); + m_fake.m_ingoing[segmentTo].insert(segmentFrom); + m_fake.m_segmentToVertex[newSegment] = newVertex; + if (isPartOfReal) + { + m_fake.m_realToFake[realSegment].insert(newSegment); + m_fake.m_fakeToReal[newSegment] = realSegment; + } +} -IndexGraphStarter::IndexGraphStarter(FakeVertex const & start, FakeVertex const & finish, - WorldGraph & graph) +Segment IndexGraphStarter::GetSegment(FakeVertex const & vertex, uint32_t & newNumber) const +{ + for (auto const & v : m_fake.m_segmentToVertex) + { + if (v.second == vertex) + return v.first; + } + + return GetFakeSegment(newNumber++); +} + +void IndexGraphStarter::AddEnding(FakeEnding const & thisEnding, FakeEnding const & otherEnding, + bool isStart, uint32_t & fakeNumerationStart, bool strictForward) +{ + CHECK_EQUAL(thisEnding.m_projectionJunctions.size(), thisEnding.m_projectionSegments.size(), ()); + CHECK_EQUAL(otherEnding.m_projectionJunctions.size(), otherEnding.m_projectionSegments.size(), ()); + Segment dummy; + + map otherSegments; + for (size_t i = 0; i < otherEnding.m_projectionSegments.size(); ++i) + otherSegments[otherEnding.m_projectionSegments[i]] = otherEnding.m_projectionJunctions[i]; + + // Add pure fake vertex + auto fakeSegment = GetFakeSegment(fakeNumerationStart++); + FakeVertex fakeVertex(thisEnding.m_originJunction, thisEnding.m_originJunction, + FakeVertex::Type::PureFake); + m_fake.m_segmentToVertex[fakeSegment] = fakeVertex; + for (uint32_t i = 0; i < thisEnding.m_projectionJunctions.size(); ++i) + { + // Add projection edges + auto projectionSegment = GetFakeSegment(fakeNumerationStart++); + FakeVertex projection( + isStart ? thisEnding.m_originJunction : thisEnding.m_projectionJunctions[i], + isStart ? thisEnding.m_projectionJunctions[i] : thisEnding.m_originJunction, + FakeVertex::Type::Projection); + AddFakeVertex(fakeSegment, projectionSegment, projection, isStart /* isOutgoing */, + false /* isPartOfReal */, dummy /* realSegment */); + + // Add fake parts of real + auto frontJunction = m_graph.GetJunction(thisEnding.m_projectionSegments[i], + thisEnding.m_projectionSegments[i].IsForward()); + auto backJunction = m_graph.GetJunction(thisEnding.m_projectionSegments[i], + !thisEnding.m_projectionSegments[i].IsForward()); + + // Check whether we have projections to same real segment from both endings. + auto const & it = otherSegments.find(thisEnding.m_projectionSegments[i]); + if (it != otherSegments.end()) + { + auto const & otherJunction = it->second; + auto distBackToThis = m_graph.GetEstimator().CalcLeapWeight( + backJunction.GetPoint(), thisEnding.m_projectionJunctions[i].GetPoint()); + auto distBackToOther = + m_graph.GetEstimator().CalcLeapWeight(backJunction.GetPoint(), otherJunction.GetPoint()); + distBackToThis < distBackToOther ? frontJunction = otherJunction + : backJunction = otherJunction; + } + + FakeVertex forwardPartOfReal(isStart ? thisEnding.m_projectionJunctions[i] : backJunction, + isStart ? frontJunction : thisEnding.m_projectionJunctions[i], + FakeVertex::Type::PartOfReal); + auto fakeForwardSegment = GetSegment(forwardPartOfReal, fakeNumerationStart); + AddFakeVertex(projectionSegment, fakeForwardSegment, forwardPartOfReal, + isStart /* isOutgoing */, true /* isPartOfReal */, + thisEnding.m_projectionSegments[i]); + + bool oneWay = m_graph + .GetRoadGeometry(thisEnding.m_projectionSegments[i].GetMwmId(), + thisEnding.m_projectionSegments[i].GetFeatureId()) + .IsOneWay(); + if (!strictForward && !oneWay) + { + Segment backwardSegment = InvertDirection(thisEnding.m_projectionSegments[i]); + FakeVertex backwardPartOfReal(isStart ? thisEnding.m_projectionJunctions[i] : frontJunction, + isStart ? backJunction : thisEnding.m_projectionJunctions[i], + FakeVertex::Type::PartOfReal); + auto fakeBackwardSegment = GetSegment(backwardPartOfReal, fakeNumerationStart); + AddFakeVertex(projectionSegment, fakeBackwardSegment, backwardPartOfReal, + isStart /* isOutgoing */, true /* isPartOfReal */, backwardSegment); + } + } +} + +void IndexGraphStarter::AddStart(FakeEnding const & startEnding, FakeEnding const & finishEnding, + uint32_t & fakeNumerationStart, bool strictForward) +{ + AddEnding(startEnding, finishEnding, true /* isStart */, fakeNumerationStart, strictForward); +} +void IndexGraphStarter::AddFinish(FakeEnding const & finishEnding, FakeEnding const & startEnding, + uint32_t & fakeNumerationStart) +{ + AddEnding(finishEnding, startEnding, false /* isStart */, fakeNumerationStart, + false /* strictForward */); +} + +IndexGraphStarter::IndexGraphStarter(FakeEnding const & startEnding, + FakeEnding const & finishEnding, uint32_t fakeNumerationStart, + bool strictForward, WorldGraph & graph) : m_graph(graph) - , m_start(start.GetSegment(), - CalcProjectionToSegment(start.GetSegment(), start.GetJunction(), graph), - start.GetStrictForward()) - , m_finish(finish.GetSegment(), - CalcProjectionToSegment(finish.GetSegment(), finish.GetJunction(), graph), - finish.GetStrictForward()) { + m_startId = fakeNumerationStart; + AddStart(startEnding, finishEnding, fakeNumerationStart, strictForward); + m_finishId = fakeNumerationStart; + AddFinish(finishEnding, startEnding, fakeNumerationStart); } -Junction const & IndexGraphStarter::GetJunction(Segment const & segment, bool front) +IndexGraphStarter::IndexGraphStarter(vector starters) + : m_graph(starters.front().m_graph) { - if (segment == kStartFakeSegment) - return m_start.GetJunction(); + m_startId = starters.front().m_startId; + m_finishId = starters.back().m_finishId; - if (segment == kFinishFakeSegment) - return m_finish.GetJunction(); + for (auto const & starter : starters) + { + m_fake.m_segmentToVertex.insert(starter.m_fake.m_segmentToVertex.begin(), + starter.m_fake.m_segmentToVertex.end()); - return m_graph.GetJunction(segment, front); + for (auto const & s : starter.m_fake.m_outgoing) + m_fake.m_outgoing[s.first].insert(s.second.begin(), s.second.end()); + + for (auto const & s : starter.m_fake.m_ingoing) + m_fake.m_ingoing[s.first].insert(s.second.begin(), s.second.end()); + + for (auto const & s : starter.m_fake.m_realToFake) + m_fake.m_realToFake[s.first].insert(s.second.begin(), s.second.end()); + + m_fake.m_fakeToReal.insert(starter.m_fake.m_fakeToReal.begin(), + starter.m_fake.m_fakeToReal.end()); + } } -m2::PointD const & IndexGraphStarter::GetPoint(Segment const & segment, bool front) +void IndexGraphStarter::Append(FakeEdgesContainer const & container) +{ + m_finishId = container.m_finishId; + + m_fake.m_segmentToVertex.insert(container.m_fake.m_segmentToVertex.begin(), + container.m_fake.m_segmentToVertex.end()); + + for (auto const & s : container.m_fake.m_outgoing) + m_fake.m_outgoing[s.first].insert(s.second.begin(), s.second.end()); + + for (auto const & s : container.m_fake.m_ingoing) + m_fake.m_ingoing[s.first].insert(s.second.begin(), s.second.end()); + + for (auto const & s : container.m_fake.m_realToFake) + m_fake.m_realToFake[s.first].insert(s.second.begin(), s.second.end()); + + m_fake.m_fakeToReal.insert(container.m_fake.m_fakeToReal.begin(), + container.m_fake.m_fakeToReal.end()); +} + +// static +IndexGraphStarter::FakeEnding IndexGraphStarter::MakeFakeEnding(Segment const & segment, + m2::PointD const & point, + WorldGraph & graph) +{ + IndexGraphStarter::FakeEnding ending; + ending.m_originJunction = InterpolateJunction(segment, point, graph); + ending.m_projectionJunctions.push_back( + CalcProjectionToSegment(segment, ending.m_originJunction, graph)); + ending.m_projectionSegments.push_back(segment); + return ending; +} + +Junction const & IndexGraphStarter::GetStartJunction() const +{ + auto const & startSegment = GetFakeSegment(m_startId); + + auto it = m_fake.m_segmentToVertex.find(startSegment); + + CHECK(it != m_fake.m_segmentToVertex.end(), ("Requested junction for invalid fake segment.")); + return it->second.GetJunctionFrom(); +} + +Junction const & IndexGraphStarter::GetFinishJunction() const +{ + auto const & finishSegment = GetFakeSegment(m_finishId); + + auto it = m_fake.m_segmentToVertex.find(finishSegment); + + CHECK(it != m_fake.m_segmentToVertex.end(), ("Requested junction for invalid fake segment.")); + return it->second.GetJunctionTo(); +} + +bool IndexGraphStarter::ConvertToReal(Segment & segment) const +{ + if (!IsFakeSegment(segment)) + return true; + + auto const & it = m_fake.m_fakeToReal.find(segment); + if (it == m_fake.m_fakeToReal.end()) + return false; + + segment = it->second; + return true; +} + +Junction const & IndexGraphStarter::GetJunction(Segment const & segment, bool front) const +{ + if (!IsFakeSegment(segment)) + return m_graph.GetJunction(segment, front); + + auto fakeVertexIt = m_fake.m_segmentToVertex.find(segment); + + CHECK(fakeVertexIt != m_fake.m_segmentToVertex.end(), + ("Requested junction for invalid fake segment.")); + return front ? fakeVertexIt->second.GetJunctionTo() : fakeVertexIt->second.GetJunctionFrom(); +} + +m2::PointD const & IndexGraphStarter::GetPoint(Segment const & segment, bool front) const { return GetJunction(segment, front).GetPoint(); } // static -void IndexGraphStarter::CheckValidRoute(vector const &segments) +void IndexGraphStarter::CheckValidRoute(vector const & segments) { // Valid route contains at least 3 segments: // start fake, finish fake and at least one normal nearest segment. CHECK_GREATER_OR_EQUAL(segments.size(), 3, ()); - CHECK_EQUAL(segments.front(), kStartFakeSegment, ()); - CHECK_EQUAL(segments.back(), kFinishFakeSegment, ()); + CHECK(IsFakeSegment(segments.front()), ()); + CHECK(IsFakeSegment(segments.back()), ()); } -// static -vector::const_iterator IndexGraphStarter::GetNonFakeStartIt(vector const & segments) +set IndexGraphStarter::GetMwms() const { - CheckValidRoute(segments); - // See CheckValidRoute comment. - return segments.begin() + 1; -} + set mwms; + for (auto const & s : m_fake.m_fakeToReal) + mwms.insert(s.second.GetMwmId()); -// static -vector::const_iterator IndexGraphStarter::GetNonFakeFinishIt(vector const & segments) -{ - CheckValidRoute(segments); - // See CheckValidRoute comment. - return segments.end() - 2; + return mwms; } // static size_t IndexGraphStarter::GetRouteNumPoints(vector const & segments) { CheckValidRoute(segments); - return segments.size() - 1; + return segments.size() + 1; } Junction const & IndexGraphStarter::GetRouteJunction(vector const & segments, - size_t pointIndex) + size_t pointIndex) const { - if (pointIndex == 0) - return m_start.GetJunction(); - - if (pointIndex + 1 == GetRouteNumPoints(segments)) - return m_finish.GetJunction(); - - CHECK_LESS(pointIndex, segments.size(), ()); - return GetJunction(segments[pointIndex], true /* front */); + CHECK_LESS_OR_EQUAL( + pointIndex, segments.size(), + ("Point with index", pointIndex, "does not exist in route with size", segments.size())); + if (pointIndex == segments.size()) + return GetJunction(segments[pointIndex - 1], true); + return GetJunction(segments[pointIndex], false); } -void IndexGraphStarter::GetEdgesList(Segment const & segment, bool isOutgoing, - vector & edges) +double IndexGraphStarter::CalcSegmentWeight(Segment const & segment) const { - edges.clear(); + if (!IsFakeSegment(segment)) + return m_graph.GetEstimator().CalcSegmentWeight( + segment, m_graph.GetRoadGeometry(segment.GetMwmId(), segment.GetFeatureId())); - if (segment == kStartFakeSegment) + auto fakeVertexIt = m_fake.m_segmentToVertex.find(segment); + + CHECK(fakeVertexIt != m_fake.m_segmentToVertex.end(), + ("Requested junction for invalid fake segment.")); + return m_graph.GetEstimator().CalcLeapWeight(fakeVertexIt->second.GetPointFrom(), + fakeVertexIt->second.GetPointTo()); +} + +double IndexGraphStarter::CalcRouteSegmentWeight(vector const & route, + size_t segmentIndex) const +{ + CHECK_LESS( + segmentIndex, route.size(), + ("Segment with index", segmentIndex, "does not exist in route with size", route.size())); + return CalcSegmentWeight(route[segmentIndex]); +} + +bool IndexGraphStarter::IsLeap(NumMwmId mwmId) const +{ + bool inProjectedMwmIds = false; + for (auto const & s : m_fake.m_fakeToReal) { - GetFakeToNormalEdges(m_start, isOutgoing, edges); - return; + if (s.second.GetMwmId() == mwmId) + { + inProjectedMwmIds = true; + break; + } } - if (segment == kFinishFakeSegment) - { - GetFakeToNormalEdges(m_finish, isOutgoing, edges); - return; - } + return mwmId != kFakeNumMwmId && !inProjectedMwmIds && + m_graph.GetEstimator().LeapIsAllowed(mwmId); +} - if (m_graph.GetMode() == WorldGraph::Mode::LeapsOnly && (m_start.Fits(segment) || m_finish.Fits(segment))) +void IndexGraphStarter::AddFakeEdges(vector & edges) const +{ + for (auto const & edge : edges) + { + auto const & it = m_fake.m_realToFake.find(edge.GetTarget()); + if (it == m_fake.m_realToFake.end()) + continue; + for (auto const & s : it->second) + edges.emplace_back(s, RouteWeight(edge.GetWeight())); + } +} + +void IndexGraphStarter::AddRealEdges(Segment const & segment, bool isOutgoing, + std::vector & edges) const +{ + if (m_graph.GetMode() == WorldGraph::Mode::LeapsOnly && + m_fake.m_realToFake.find(segment) != m_fake.m_realToFake.end()) { 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); } -void IndexGraphStarter::GetFakeToNormalEdges(FakeVertex const & fakeVertex, bool isOutgoing, - vector & edges) +void IndexGraphStarter::GetEdgesList(Segment const & segment, bool isOutgoing, + vector & edges) const { - if (fakeVertex.GetStrictForward()) + edges.clear(); + if (IsFakeSegment(segment)) { - GetFakeToNormalEdge(fakeVertex, fakeVertex.GetSegment().IsForward(), edges); + auto const & vertexIt = m_fake.m_segmentToVertex.find(segment); + CHECK(vertexIt != m_fake.m_segmentToVertex.end(), + ("Can not map fake segment", segment, "to fake vertex.")); + + if (vertexIt->second.GetType() == FakeVertex::Type::PartOfReal) + { + auto const & realIt = m_fake.m_fakeToReal.find(segment); + CHECK(realIt != m_fake.m_fakeToReal.end(), + ("Can not map fake segment", segment, "to real segment.")); + AddRealEdges(realIt->second, isOutgoing, edges); + } + + auto const & fakeGraph = isOutgoing ? m_fake.m_outgoing : m_fake.m_ingoing; + + auto it = fakeGraph.find(segment); + if (it != fakeGraph.end()) + { + for (auto const & s : it->second) + edges.emplace_back(s, RouteWeight(CalcSegmentWeight(isOutgoing ? s : segment))); + } } else { - GetFakeToNormalEdge(fakeVertex, true /* forward */, edges); - - if (!m_graph.GetRoadGeometry(fakeVertex.GetMwmId(), fakeVertex.GetFeatureId()).IsOneWay()) - GetFakeToNormalEdge(fakeVertex, false /* forward */, edges); - } -} - -void IndexGraphStarter::GetFakeToNormalEdge(FakeVertex const & fakeVertex, bool forward, - vector & edges) -{ - auto const segment = fakeVertex.GetSegmentWithDirection(forward); - m2::PointD const & pointTo = GetPoint(segment, true /* front */); - RouteWeight const weight(m_graph.GetEstimator().CalcLeapWeight(fakeVertex.GetPoint(), pointTo)); - edges.emplace_back(segment, weight); -} - -void IndexGraphStarter::GetNormalToFakeEdge(Segment const & segment, FakeVertex const & fakeVertex, - Segment const & fakeSegment, bool isOutgoing, - vector & edges) -{ - m2::PointD const & pointFrom = GetPoint(segment, isOutgoing); - if (segment.GetMwmId() == fakeVertex.GetMwmId() && - m_graph.GetMode() == WorldGraph::Mode::LeapsOnly) - { - if (m_graph.IsTransition(segment, isOutgoing)) - { - edges.emplace_back(fakeSegment, RouteWeight(m_graph.GetEstimator().CalcLeapWeight( - pointFrom, fakeVertex.GetPoint()))); - } - return; + AddRealEdges(segment, isOutgoing, edges); } - if (fakeVertex.Fits(segment)) - { - edges.emplace_back(fakeSegment, RouteWeight(m_graph.GetEstimator().CalcLeapWeight( - pointFrom, fakeVertex.GetPoint()))); - } + AddFakeEdges(edges); } void IndexGraphStarter::ConnectLeapToTransitions(Segment const & segment, bool isOutgoing, - vector & edges) + vector & edges) const { edges.clear(); m2::PointD const & segmentPoint = GetPoint(segment, true /* front */); diff --git a/routing/index_graph_starter.hpp b/routing/index_graph_starter.hpp index ce5c3a364b..96122dd106 100644 --- a/routing/index_graph_starter.hpp +++ b/routing/index_graph_starter.hpp @@ -6,12 +6,17 @@ #include "routing/route_point.hpp" #include "routing/world_graph.hpp" -#include "std/limits.hpp" -#include "std/utility.hpp" -#include "std/vector.hpp" +#include +#include +#include +#include +#include +#include namespace routing { +class FakeEdgesContainer; + // IndexGraphStarter adds fake start and finish vertexes for AStarAlgorithm. class IndexGraphStarter final { @@ -21,113 +26,73 @@ public: using TEdgeType = IndexGraph::TEdgeType; using TWeightType = IndexGraph::TWeightType; - class FakeVertex final + struct FakeEnding { - public: - FakeVertex(NumMwmId mwmId, uint32_t featureId, uint32_t segmentIdx, m2::PointD const & point) - : m_segment(mwmId, featureId, segmentIdx, true /* forward */) - , m_junction(point, feature::kDefaultAltitudeMeters) - { - } - - FakeVertex(Segment const & segment, m2::PointD const & point, bool strictForward) - : m_segment(segment) - , m_junction(point, feature::kDefaultAltitudeMeters) - , m_strictForward(strictForward) - { - } - - FakeVertex(Segment const & segment, Junction const & junction, bool strictForward) - : m_segment(segment), m_junction(junction), m_strictForward(strictForward) - { - } - - NumMwmId GetMwmId() const { return m_segment.GetMwmId(); } - uint32_t GetFeatureId() const { return m_segment.GetFeatureId(); } - Junction const & GetJunction() const { return m_junction; } - m2::PointD const & GetPoint() const { return m_junction.GetPoint(); } - Segment const & GetSegment() const { return m_segment; } - - Segment GetSegmentWithDirection(bool forward) const - { - return Segment(m_segment.GetMwmId(), m_segment.GetFeatureId(), m_segment.GetSegmentIdx(), - forward); - } - - bool Fits(Segment const & segment) const - { - return segment.GetMwmId() == m_segment.GetMwmId() && - segment.GetFeatureId() == m_segment.GetFeatureId() && - segment.GetSegmentIdx() == m_segment.GetSegmentIdx() && - (!m_strictForward || segment.IsForward() == m_segment.IsForward()); - } - - uint32_t GetSegmentIdxForTesting() const { return m_segment.GetSegmentIdx(); } - bool GetStrictForward() const { return m_strictForward; } - - private: - Segment m_segment; - Junction m_junction; - // This flag specifies which fake edges should be placed from the fake vertex. - // true: place exactly one fake edge to the m_segment with indicated m_forward. - // false: place two fake edges to the m_segment with both directions. - bool m_strictForward = false; + Junction m_originJunction; + std::vector m_projectionJunctions; + std::vector m_projectionSegments; }; - static uint32_t constexpr kFakeFeatureId = numeric_limits::max(); - static uint32_t constexpr kFakeSegmentIdx = numeric_limits::max(); - static Segment constexpr kStartFakeSegment = - Segment(kFakeNumMwmId, kFakeFeatureId, kFakeSegmentIdx, false); - static Segment constexpr kFinishFakeSegment = - Segment(kFakeNumMwmId, kFakeFeatureId, kFakeSegmentIdx, true); + friend class FakeEdgesContainer; - IndexGraphStarter(FakeVertex const & start, FakeVertex const & finish, WorldGraph & graph); + static uint32_t constexpr kFakeFeatureId = numeric_limits::max(); + + static FakeEnding MakeFakeEnding(Segment const & segment, m2::PointD const & point, + WorldGraph & graph); + static void CheckValidRoute(std::vector const & segments); + static size_t GetRouteNumPoints(std::vector const & route); + + // strictForward flag specifies which parts of real segment should be placed from the start + // vertex. true: place exactly one fake edge to the m_segment with indicated m_forward. false: + // place two fake edges to the m_segment with both directions. + IndexGraphStarter(FakeEnding const & startEnding, FakeEnding const & finishEnding, + uint32_t fakeNumerationStart, bool strictForward, WorldGraph & graph); + + // Merge starters to single IndexGraphStarter. + // Expects starters[0] has WorldGraph which is valid for all starters, starters.size() >= 1. + IndexGraphStarter(std::vector starters); + + void Append(FakeEdgesContainer const & container); WorldGraph & GetGraph() { return m_graph; } - Segment const & GetStart() const { return kStartFakeSegment; } - Segment const & GetFinish() const { return kFinishFakeSegment; } - FakeVertex const & GetStartVertex() const { return m_start; } - FakeVertex const & GetFinishVertex() const { return m_finish; } - Junction const & GetJunction(Segment const & segment, bool front); - m2::PointD const & GetPoint(Segment const & segment, bool front); - bool FitsStart(Segment const & s) const { return m_start.Fits(s); } - bool FitsFinish(Segment const & s) const { return m_finish.Fits(s); } + Junction const & GetStartJunction() const; + Junction const & GetFinishJunction() const; + Segment GetStartSegment() const { return GetFakeSegment(m_startId); } + Segment GetFinishSegment() const { return GetFakeSegment(m_finishId); } + // If segment is real return true and does not modify segment. + // If segment is part of real converts it to real and returns true. + // Otherwise returns false and does not modify segment. + bool ConvertToReal(Segment & segment) const; + Junction const & GetJunction(Segment const & segment, bool front) const; + Junction const & GetRouteJunction(std::vector const & route, size_t pointIndex) const; + m2::PointD const & GetPoint(Segment const & segment, bool front) const; + size_t GetNumFakeSegments() const { return m_fake.m_segmentToVertex.size(); } - static void CheckValidRoute(vector const &segments); - static size_t GetRouteNumPoints(vector const & route); - static vector::const_iterator GetNonFakeStartIt(vector const & segments); - static vector::const_iterator GetNonFakeFinishIt(vector const & segments); - Junction const & GetRouteJunction(vector const & route, size_t pointIndex); + std::set GetMwms() const; - void GetEdgesList(Segment const & segment, bool isOutgoing, vector & edges); + void GetEdgesList(Segment const & segment, bool isOutgoing, + std::vector & edges) const; - void GetOutgoingEdgesList(TVertexType const & segment, vector & edges) + void GetOutgoingEdgesList(TVertexType const & segment, std::vector & edges) const { GetEdgesList(segment, true /* isOutgoing */, edges); } - void GetIngoingEdgesList(TVertexType const & segment, vector & edges) + void GetIngoingEdgesList(TVertexType const & segment, std::vector & edges) const { GetEdgesList(segment, false /* isOutgoing */, edges); } - RouteWeight HeuristicCostEstimate(TVertexType const & from, TVertexType const & to) + RouteWeight HeuristicCostEstimate(TVertexType const & from, TVertexType const & to) const { return RouteWeight(m_graph.GetEstimator().CalcHeuristic(GetPoint(from, true /* front */), GetPoint(to, true /* front */))); } - double CalcSegmentWeight(Segment const & segment) const - { - return m_graph.GetEstimator().CalcSegmentWeight( - segment, m_graph.GetRoadGeometry(segment.GetMwmId(), segment.GetFeatureId())); - } + double CalcSegmentWeight(Segment const & segment) const; + double CalcRouteSegmentWeight(std::vector const & route, size_t segmentIndex) const; - bool IsLeap(NumMwmId mwmId) const - { - return mwmId != kFakeNumMwmId && mwmId != m_start.GetMwmId() && mwmId != m_finish.GetMwmId() && - m_graph.GetEstimator().LeapIsAllowed(mwmId); - } + bool IsLeap(NumMwmId mwmId) const; static bool IsFakeSegment(Segment const & segment) { @@ -135,22 +100,107 @@ public: } private: - void GetFakeToNormalEdges(FakeVertex const & fakeVertex, bool isOutgoing, - vector & edges); - void GetFakeToNormalEdge(FakeVertex const & fakeVertex, bool forward, - vector & edges); - void GetNormalToFakeEdge(Segment const & segment, FakeVertex const & fakeVertex, - Segment const & fakeSegment, bool isOutgoing, - vector & edges); + static Segment GetFakeSegment(uint32_t i) + { + return Segment(kFakeNumMwmId, kFakeFeatureId, i, false); + } + + class FakeVertex final + { + public: + enum class Type + { + PureFake, + Projection, + PartOfReal, + }; + // For unit tests only. + FakeVertex(NumMwmId mwmId, uint32_t featureId, uint32_t segmentIdx, m2::PointD const & point) + : m_junctionFrom(point, feature::kDefaultAltitudeMeters) + , m_junctionTo(point, feature::kDefaultAltitudeMeters) + { + } + + FakeVertex(Junction const & junctionFrom, Junction const & junctionTo, Type type) + : m_junctionFrom(junctionFrom), m_junctionTo(junctionTo), m_type(type) + { + } + + FakeVertex(FakeVertex const &) = default; + FakeVertex() = default; + + bool operator==(FakeVertex const & rhs) const + { + return m_junctionFrom == rhs.m_junctionFrom && m_junctionTo == rhs.m_junctionTo && + m_type == rhs.m_type; + } + + Type GetType() const { return m_type; } + + Junction const & GetJunctionFrom() const { return m_junctionFrom; } + m2::PointD const & GetPointFrom() const { return m_junctionFrom.GetPoint(); } + Junction const & GetJunctionTo() const { return m_junctionTo; } + m2::PointD const & GetPointTo() const { return m_junctionTo.GetPoint(); } + + private: + Junction m_junctionFrom; + Junction m_junctionTo; + Type m_type = Type::PureFake; + }; + + struct FakeGraph + { + std::map> m_outgoing; + std::map> m_ingoing; + std::map m_segmentToVertex; + std::map m_fakeToReal; + std::map> m_realToFake; + }; + + void AddFakeVertex(Segment const & existentSegment, Segment const & newSegment, + FakeVertex const & newVertex, bool isOutgoing, bool isPartOfReal, + Segment const & realSegment); + void AddEnding(FakeEnding const & thisEnding, FakeEnding const & otherEnding, bool isStart, + uint32_t & fakeNumerationStart, bool strictForward); + void AddStart(FakeEnding const & startEnding, FakeEnding const & finishEnding, + uint32_t & fakeNumerationStart, bool strictForward); + void AddFinish(FakeEnding const & finishEnding, FakeEnding const & startEnding, + uint32_t & fakeNumerationStart); + + // Returns existent segment if possible. If segment does not exist makes new segment, + // increments newNumber. + Segment GetSegment(FakeVertex const & vertex, uint32_t & newNumber) const; + + void AddFakeEdges(vector & edges) const; + void AddRealEdges(Segment const & segment, bool isOutgoing, + std::vector & edges) const; /// \brief If |isOutgoing| == true fills |edges| with SegmentEdge(s) which connects /// |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(Segment const & segment, bool isOutgoing, - vector & edges); + std::vector & edges) const; WorldGraph & m_graph; - FakeVertex const m_start; - FakeVertex const m_finish; + uint32_t m_startId; + uint32_t m_finishId; + FakeGraph m_fake; +}; + +class FakeEdgesContainer final +{ + friend class IndexGraphStarter; + +public: + FakeEdgesContainer(IndexGraphStarter && starter) + : m_finishId(move(starter.m_finishId)), m_fake(move(starter.m_fake)) + { + } + + size_t GetNumFakeEdges() const { return m_fake.m_segmentToVertex.size(); } + +private: + uint32_t m_finishId; + IndexGraphStarter::FakeGraph m_fake; }; } // namespace routing diff --git a/routing/index_road_graph.cpp b/routing/index_road_graph.cpp index 8f79cc8310..787c153942 100644 --- a/routing/index_road_graph.cpp +++ b/routing/index_road_graph.cpp @@ -2,6 +2,13 @@ #include "routing/routing_exceptions.hpp" +#include + +namespace +{ +using namespace std; +} // namespace + namespace routing { IndexRoadGraph::IndexRoadGraph(shared_ptr numMwmIds, IndexGraphStarter & starter, @@ -9,13 +16,17 @@ IndexRoadGraph::IndexRoadGraph(shared_ptr numMwmIds, IndexGraphStarte Index & index) : m_index(index), m_numMwmIds(numMwmIds), m_starter(starter), m_segments(segments) { - CHECK_EQUAL(segments.size(), junctions.size() + 1, ()); + // j0 j1 j2 j3 + // *--s0--*--s1--*--s2--* + CHECK_EQUAL(segments.size() + 1, junctions.size(), ()); for (size_t i = 0; i < junctions.size(); ++i) { Junction const & junction = junctions[i]; - m_endToSegment[junction].push_back(segments[i]); - m_beginToSegment[junction].push_back(segments[i + 1]); + if (i > 0) + m_endToSegment[junction].push_back(segments[i - 1]); + if (i < segments.size()) + m_beginToSegment[junction].push_back(segments[i]); } } @@ -78,18 +89,20 @@ void IndexRoadGraph::GetRouteEdges(TEdgeVector & edges) const for (Segment const & segment : m_segments) { - if (IndexGraphStarter::IsFakeSegment(segment)) - continue; + auto featureIdHandle = FeatureID(); - platform::CountryFile const & file = m_numMwmIds->GetFile(segment.GetMwmId()); - MwmSet::MwmHandle const handle = m_index.GetMwmHandleByCountryFile(file); - if (!handle.IsAlive()) - MYTHROW(RoutingException, ("Can't get mwm handle for", file)); + if (!IndexGraphStarter::IsFakeSegment(segment)) + { + platform::CountryFile const & file = m_numMwmIds->GetFile(segment.GetMwmId()); + MwmSet::MwmHandle const handle = m_index.GetMwmHandleByCountryFile(file); + if (!handle.IsAlive()) + MYTHROW(RoutingException, ("Can't get mwm handle for", file)); - auto featureId = FeatureID(handle.GetId(), segment.GetFeatureId()); - edges.emplace_back(featureId, segment.IsForward(), segment.GetSegmentIdx(), - GetJunction(segment, false /* front */), - GetJunction(segment, true /* front */)); + featureIdHandle = FeatureID(handle.GetId(), segment.GetFeatureId()); + } + edges.emplace_back(featureIdHandle, segment.IsForward(), segment.GetSegmentIdx(), + m_starter.GetJunction(segment, false /* front */), + m_starter.GetJunction(segment, true /* front */)); } } @@ -124,17 +137,6 @@ void IndexRoadGraph::GetEdges(Junction const & junction, bool isOutgoing, TEdgeV } } -Junction const & IndexRoadGraph::GetJunction(Segment const & segment, bool front) const -{ - if (!front && m_starter.FitsStart(segment)) - return m_starter.GetStartVertex().GetJunction(); - - if (front && m_starter.FitsFinish(segment)) - return m_starter.GetFinishVertex().GetJunction(); - - return m_starter.GetJunction(segment, front); -} - vector const & IndexRoadGraph::GetSegments(Junction const & junction, bool isOutgoing) const { diff --git a/routing/index_road_graph.hpp b/routing/index_road_graph.hpp index bde8775d72..e6dcdd7d3d 100644 --- a/routing/index_road_graph.hpp +++ b/routing/index_road_graph.hpp @@ -7,16 +7,17 @@ #include "indexer/index.hpp" -#include "std/map.hpp" -#include "std/vector.hpp" +#include +#include +#include namespace routing { class IndexRoadGraph : public RoadGraphBase { public: - IndexRoadGraph(shared_ptr numMwmIds, IndexGraphStarter & starter, - vector const & segments, vector const & junctions, + IndexRoadGraph(std::shared_ptr numMwmIds, IndexGraphStarter & starter, + std::vector const & segments, std::vector const & junctions, Index & index); // IRoadGraphBase overrides: @@ -33,13 +34,13 @@ public: private: void GetEdges(Junction const & junction, bool isOutgoing, TEdgeVector & edges) const; Junction const & GetJunction(Segment const & segment, bool front) const; - vector const & GetSegments(Junction const & junction, bool isOutgoing) const; + std::vector const & GetSegments(Junction const & junction, bool isOutgoing) const; Index & m_index; - shared_ptr m_numMwmIds; + std::shared_ptr m_numMwmIds; IndexGraphStarter & m_starter; - vector m_segments; - map> m_beginToSegment; - map> m_endToSegment; + std::vector m_segments; + std::map> m_beginToSegment; + std::map> m_endToSegment; }; } // namespace routing diff --git a/routing/index_router.cpp b/routing/index_router.cpp index 59c05793a6..76298ce6f9 100644 --- a/routing/index_router.cpp +++ b/routing/index_router.cpp @@ -6,7 +6,6 @@ #include "routing/index_graph.hpp" #include "routing/index_graph_loader.hpp" #include "routing/index_graph_serialization.hpp" -#include "routing/index_graph_starter.hpp" #include "routing/index_road_graph.hpp" #include "routing/pedestrian_directions.hpp" #include "routing/restriction_loader.hpp" @@ -146,35 +145,6 @@ bool IsDeadEnd(Segment const & segment, bool isOutgoing, WorldGraph & worldGraph getVertexByEdgeFn, getOutgoingEdgesFn); } -Junction InterpolateJunction(Segment const & segment, m2::PointD const & point, WorldGraph & graph) -{ - Junction const & begin = graph.GetJunction(segment, false /* front */); - Junction const & end = graph.GetJunction(segment, true /* front */); - - m2::PointD const segmentDir = end.GetPoint() - begin.GetPoint(); - if (segmentDir.IsAlmostZero()) - return Junction(point, begin.GetAltitude()); - - m2::PointD const pointDir = point - begin.GetPoint(); - - double const ratio = m2::DotProduct(segmentDir, pointDir) / segmentDir.SquaredLength(); - if (ratio <= 0.0) - return Junction(point, begin.GetAltitude()); - - if (ratio >= 1.0) - return Junction(point, end.GetAltitude()); - - return Junction(point, static_cast( - (1.0 - ratio) * static_cast(begin.GetAltitude()) + - ratio * (static_cast(end.GetAltitude())))); -} - -IndexGraphStarter::FakeVertex MakeFakeVertex(Segment const & segment, m2::PointD const & point, - bool strictForward, WorldGraph & graph) -{ - return {segment, InterpolateJunction(segment, point, graph), strictForward}; -} - bool MwmHasRoutingData(version::MwmTraits const & traits, VehicleType vehicleType) { if (!traits.HasRoutingIndex()) @@ -352,7 +322,8 @@ IRouter::ResultCode IndexRouter::CalculateRoute(Checkpoints const & checkpoints, try { - if (adjustToPrevRoute && m_lastRoute && finalPoint == m_lastRoute->GetFinish()) + if (adjustToPrevRoute && m_lastRoute && m_lastFakeEdges && + finalPoint == m_lastRoute->GetFinish()) { double const distanceToRoute = m_lastRoute->CalcDistance(startPoint); double const distanceToFinish = MercatorBounds::DistanceOnEarth(startPoint, finalPoint); @@ -368,7 +339,6 @@ IRouter::ResultCode IndexRouter::CalculateRoute(Checkpoints const & checkpoints, MercatorBounds::ToLatLon(finalPoint))); } } - return DoCalculateRoute(checkpoints, startDirection, delegate, route); } catch (RootException const & e) @@ -408,7 +378,6 @@ IRouter::ResultCode IndexRouter::DoCalculateRoute(Checkpoints const & checkpoint WorldGraph graph = MakeWorldGraph(); vector segments; - segments.push_back(IndexGraphStarter::kStartFakeSegment); Segment startSegment; bool startSegmentIsAlmostCodirectionalDirection = false; @@ -419,53 +388,63 @@ IRouter::ResultCode IndexRouter::DoCalculateRoute(Checkpoints const & checkpoint } size_t subrouteSegmentsBegin = 0; + uint32_t fakeSegmentsNumerationStart = 0; vector subroutes; PushPassedSubroutes(checkpoints, subroutes); + vector starters; for (size_t i = checkpoints.GetPassedIdx(); i < checkpoints.GetNumSubroutes(); ++i) { + if (!FindBestSegment(checkpoints.GetPoint(i), startDirection, true /* isOutgoing */, graph, + startSegment, startSegmentIsAlmostCodirectionalDirection)) + { + return IRouter::StartPointNotFound; + } + + auto const & startCheckpoint = checkpoints.GetPoint(i); + auto const & finishCheckpoint = checkpoints.GetPoint(i + 1); + + Segment finishSegment; + bool dummy = false; + if (!FindBestSegment(finishCheckpoint, m2::PointD::Zero() /* direction */, + false /* isOutgoing */, graph, finishSegment, + dummy /* bestSegmentIsAlmostCodirectional */)) + { + bool const isLastSubroute = i == checkpoints.GetNumSubroutes() - 1; + return isLastSubroute ? IRouter::EndPointNotFound : IRouter::IntermediatePointNotFound; + } + + bool const isStartSegmentStrictForward = + i == checkpoints.GetPassedIdx() ? startSegmentIsAlmostCodirectionalDirection : true; + starters.emplace_back(IndexGraphStarter::MakeFakeEnding(startSegment, startCheckpoint, graph), + IndexGraphStarter::MakeFakeEnding(finishSegment, finishCheckpoint, graph), + fakeSegmentsNumerationStart, isStartSegmentStrictForward, graph); + vector subroute; Junction startJunction; - auto const result = - CalculateSubroute(checkpoints, i, startSegment, startSegmentIsAlmostCodirectionalDirection, - delegate, graph, subroute, startJunction); + auto const result = CalculateSubroute(checkpoints, i, startSegment, delegate, starters.back(), + subroute, startJunction); if (result != IRouter::NoError) return result; IndexGraphStarter::CheckValidRoute(subroute); - auto const nonFakeStartIt = IndexGraphStarter::GetNonFakeStartIt(subroute); - auto const nonFakeFinishIt = IndexGraphStarter::GetNonFakeFinishIt(subroute); - segments.insert(segments.end(), nonFakeStartIt, nonFakeFinishIt); - size_t subrouteSegmentsEnd = subrouteSegmentsBegin + (nonFakeFinishIt - nonFakeStartIt); - // There are N checkpoints and N-1 subroutes. - // There is corresponding nearest segment for each checkpoint - checkpoint segment. - // Each subroute except the last contains exactly one checkpoint segment - first segment. - // Last subroute contains two checkpoint segments: the first and the last. - if (i + 1 == checkpoints.GetNumSubroutes()) - ++subrouteSegmentsEnd; + segments.insert(segments.end(), subroute.begin(), subroute.end()); - subroutes.emplace_back(startJunction, graph.GetJunction(*nonFakeFinishIt, true /* front */), + size_t subrouteSegmentsEnd = segments.size(); + subroutes.emplace_back(starters.back().GetStartJunction(), starters.back().GetFinishJunction(), subrouteSegmentsBegin, subrouteSegmentsEnd); - - startSegment = *nonFakeFinishIt; subrouteSegmentsBegin = subrouteSegmentsEnd; + fakeSegmentsNumerationStart += starters.back().GetNumFakeSegments(); } route.SetCurrentSubrouteIdx(checkpoints.GetPassedIdx()); route.SetSubroteAttrs(move(subroutes)); - segments.push_back(startSegment); - segments.push_back(IndexGraphStarter::kFinishFakeSegment); IndexGraphStarter::CheckValidRoute(segments); - IndexGraphStarter starter( - MakeFakeVertex(*IndexGraphStarter::GetNonFakeStartIt(segments), checkpoints.GetStart(), - false /* strictForward */, graph), - MakeFakeVertex(*IndexGraphStarter::GetNonFakeFinishIt(segments), checkpoints.GetFinish(), - false /* strictForward */, graph), - graph); + IndexGraphStarter starter(starters); auto redressResult = RedressRoute(segments, delegate, starter, route); if (redressResult != IRouter::NoError) @@ -474,65 +453,47 @@ IRouter::ResultCode IndexRouter::DoCalculateRoute(Checkpoints const & checkpoint m_lastRoute = make_unique(checkpoints.GetStart(), checkpoints.GetFinish(), route.GetSubroutes()); for (Segment const & segment : segments) - { - if (!IndexGraphStarter::IsFakeSegment(segment)) - m_lastRoute->AddStep(segment, graph.GetPoint(segment, true /* front */)); - } + m_lastRoute->AddStep(segment, starter.GetPoint(segment, true /* front */)); + + m_lastFakeEdges = make_unique(move(starter)); return IRouter::NoError; } IRouter::ResultCode IndexRouter::CalculateSubroute(Checkpoints const & checkpoints, size_t subrouteIdx, Segment const & startSegment, - bool startSegmentIsAlmostCodirectional, RouterDelegate const & delegate, - WorldGraph & graph, vector & subroute, + IndexGraphStarter & starter, + vector & subroute, Junction & startJunction) { subroute.clear(); - auto const & startCheckpoint = checkpoints.GetPoint(subrouteIdx); - auto const & finishCheckpoint = checkpoints.GetPoint(subrouteIdx + 1); - - Segment finishSegment; - bool dummy = false; - if (!FindBestSegment(finishCheckpoint, m2::PointD::Zero() /* direction */, false /* isOutgoing */, graph, - finishSegment, dummy /* bestSegmentIsAlmostCodirectional */)) - { - bool const isLastSubroute = subrouteIdx == checkpoints.GetNumSubroutes() - 1; - return isLastSubroute ? IRouter::EndPointNotFound : IRouter::IntermediatePointNotFound; - } - // We use leaps for cars only. Other vehicle types do not have weights in their cross-mwm sections. switch (m_vehicleType) { case VehicleType::Pedestrian: case VehicleType::Bicycle: - graph.SetMode(WorldGraph::Mode::NoLeaps); + starter.SetMode(WorldGraph::Mode::NoLeaps); break; case VehicleType::Car: - graph.SetMode(AreMwmsNear(startSegment.GetMwmId(), finishSegment.GetMwmId()) - ? WorldGraph::Mode::LeapsIfPossible - : WorldGraph::Mode::LeapsOnly); + starter.SetMode(AreMwmsNear(startSegment.GetMwmId(), finishSegment.GetMwmId()) + ? WorldGraph::Mode::LeapsIfPossible + : WorldGraph::Mode::LeapsOnly); break; } - LOG(LINFO, ("Routing in mode:", graph.GetMode())); - - bool const isStartSegmentStrictForward = - subrouteIdx == checkpoints.GetPassedIdx() ? startSegmentIsAlmostCodirectional : true; - IndexGraphStarter starter( - MakeFakeVertex(startSegment, startCheckpoint, isStartSegmentStrictForward, graph), - MakeFakeVertex(finishSegment, finishCheckpoint, false /* strictForward */, graph), graph); + LOG(LINFO, ("Routing in mode:", starter.GetGraph().GetMode())); if (subrouteIdx == checkpoints.GetPassedIdx()) - startJunction = starter.GetStartVertex().GetJunction(); + startJunction = starter.GetStartJunction(); else startJunction = starter.GetJunction(startSegment, false /* front */); auto const progressRange = CalcProgressRange(checkpoints, subrouteIdx); AStarProgress progress(progressRange.startValue, progressRange.stopValue); - progress.Initialize(starter.GetStartVertex().GetPoint(), starter.GetFinishVertex().GetPoint()); + progress.Initialize(starter.GetStartJunction().GetPoint(), + starter.GetFinishJunction().GetPoint()); uint32_t visitCount = 0; auto lastValue = progress.GetLastValue(); @@ -554,13 +515,13 @@ IRouter::ResultCode IndexRouter::CalculateSubroute(Checkpoints const & checkpoin }; RoutingResult routingResult; - IRouter::ResultCode const result = FindPath(starter.GetStart(), starter.GetFinish(), delegate, - starter, onVisitJunction, routingResult); + IRouter::ResultCode const result = FindPath(starter.GetStartSegment(), starter.GetFinishSegment(), + delegate, starter, onVisitJunction, routingResult); if (result != IRouter::NoError) return result; IRouter::ResultCode const leapsResult = - ProcessLeaps(routingResult.path, delegate, graph.GetMode(), starter, subroute); + ProcessLeaps(routingResult.path, delegate, starter.GetGraph().GetMode(), starter, subroute); if (leapsResult != IRouter::NoError) return leapsResult; @@ -591,14 +552,17 @@ IRouter::ResultCode IndexRouter::AdjustRoute(Checkpoints const & checkpoints, auto const & steps = m_lastRoute->GetSteps(); CHECK(!steps.empty(), ()); - IndexGraphStarter starter( - MakeFakeVertex(startSegment, pointFrom, bestSegmentIsAlmostCodirectional, graph), - MakeFakeVertex(steps[lastSubroute.GetEndSegmentIdx() - 1].GetSegment(), - checkpoints.GetPointTo(), false /* strictForward */, graph), graph); + IndexGraphStarter::FakeEnding dummy; + IndexGraphStarter starter(IndexGraphStarter::MakeFakeEnding(startSegment, pointFrom, graph), + dummy, m_lastFakeEdges->GetNumFakeEdges(), + bestSegmentIsAlmostCodirectional, graph); + + starter.Append(*m_lastFakeEdges); AStarProgress progress(0, 95); - progress.Initialize(starter.GetStartVertex().GetPoint(), starter.GetFinishVertex().GetPoint()); - + progress.Initialize(starter.GetStartJunction().GetPoint(), + starter.GetFinishJunction().GetPoint()); + vector prevEdges; CHECK_LESS_OR_EQUAL(lastSubroute.GetEndSegmentIdx(), steps.size(), ()); for (size_t i = lastSubroute.GetBeginSegmentIdx(); i < lastSubroute.GetEndSegmentIdx(); ++i) @@ -626,22 +590,21 @@ IRouter::ResultCode IndexRouter::AdjustRoute(Checkpoints const & checkpoints, AStarAlgorithm algorithm; RoutingResult result; auto resultCode = ConvertResult( - algorithm.AdjustRoute(starter, starter.GetStart(), prevEdges, RouteWeight(kAdjustLimitSec), - result, delegate, onVisitJunction)); + algorithm.AdjustRoute(starter, starter.GetStartSegment(), prevEdges, + RouteWeight(kAdjustLimitSec), result, delegate, onVisitJunction)); if (resultCode != IRouter::NoError) return resultCode; CHECK_GREATER_OR_EQUAL(result.path.size(), 2, ()); CHECK(IndexGraphStarter::IsFakeSegment(result.path.front()), ()); - CHECK(!IndexGraphStarter::IsFakeSegment(result.path.back()), ()); + CHECK(IndexGraphStarter::IsFakeSegment(result.path.back()), ()); vector subroutes; PushPassedSubroutes(checkpoints, subroutes); - size_t subrouteOffset = result.path.size() - 1; // -1 for the fake start. - subroutes.emplace_back(starter.GetStartVertex().GetJunction(), - starter.GetFinishVertex().GetJunction(), 0 /* beginSegmentIdx */, - subrouteOffset); + size_t subrouteOffset = result.path.size(); + subroutes.emplace_back(starter.GetStartJunction(), starter.GetFinishJunction(), + 0 /* beginSegmentIdx */, subrouteOffset); for (size_t i = checkpoints.GetPassedIdx() + 1; i < lastSubroutes.size(); ++i) { @@ -654,13 +617,11 @@ IRouter::ResultCode IndexRouter::AdjustRoute(Checkpoints const & checkpoints, subrouteOffset = subroutes.back().GetEndSegmentIdx(); } - // +1 for the fake start. - CHECK_EQUAL(result.path.size(), subrouteOffset + 1, ()); + CHECK_EQUAL(result.path.size(), subrouteOffset, ()); route.SetCurrentSubrouteIdx(checkpoints.GetPassedIdx()); route.SetSubroteAttrs(move(subroutes)); - result.path.push_back(starter.GetFinish()); auto const redressResult = RedressRoute(result.path, delegate, starter, route); if (redressResult != IRouter::NoError) return redressResult; @@ -738,7 +699,8 @@ IRouter::ResultCode IndexRouter::ProcessLeaps(vector const & input, for (size_t i = 0; i < input.size(); ++i) { - Segment const & current = input[i]; + Segment current = input[i]; + starter.ConvertToReal(current); if ((prevMode == WorldGraph::Mode::LeapsOnly && IndexGraphStarter::IsFakeSegment(current)) || (prevMode != WorldGraph::Mode::LeapsOnly && !starter.IsLeap(current.GetMwmId()))) @@ -752,7 +714,8 @@ IRouter::ResultCode IndexRouter::ProcessLeaps(vector const & input, ++i; CHECK_LESS(i, input.size(), ()); - Segment const & next = input[i]; + Segment next = input[i]; + starter.ConvertToReal(next); CHECK(!IndexGraphStarter::IsFakeSegment(current), ()); CHECK(!IndexGraphStarter::IsFakeSegment(next), ()); @@ -764,9 +727,7 @@ IRouter::ResultCode IndexRouter::ProcessLeaps(vector const & input, RoutingResult routingResult; // In case of leaps from the start to its mwm transition and from finish mwm transition // route calculation should be made on the world graph (WorldGraph::Mode::NoLeaps). - if ((current.GetMwmId() == starter.GetStartVertex().GetMwmId() - || current.GetMwmId() == starter.GetFinishVertex().GetMwmId()) - && prevMode == WorldGraph::Mode::LeapsOnly) + if (starter.GetMwms().count(current.GetMwmId()) && prevMode == WorldGraph::Mode::LeapsOnly) { // World graph route. result = FindPath(current, next, delegate, worldGraph, {} /* onVisitedVertexCallback */, routingResult); @@ -803,11 +764,11 @@ IRouter::ResultCode IndexRouter::RedressRoute(vector const & segments, times.reserve(segments.size()); double time = 0.0; times.emplace_back(static_cast(0), 0.0); - // First and last segments are fakes: skip it. - for (size_t i = 1; i < segments.size() - 1; ++i) + + for (size_t i = 0; i < numPoints - 1; ++i) { - time += starter.CalcSegmentWeight(segments[i]); - times.emplace_back(static_cast(i), time); + time += starter.CalcRouteSegmentWeight(segments, i); + times.emplace_back(static_cast(i + 1), time); } CHECK(m_directionsEngine, ()); @@ -826,14 +787,25 @@ IRouter::ResultCode IndexRouter::RedressRoute(vector const & segments, return IRouter::NoError; } -bool IndexRouter::AreMwmsNear(NumMwmId startId, NumMwmId finishId) const +bool IndexRouter::AreMwmsNear(std::set mwmIds) const { - m2::RectD const startMwmRect = m_countryRectFn(m_numMwmIds->GetFile(startId).GetName()); - bool areMwmsNear = false; - m_numMwmTree->ForEachInRect(startMwmRect, [&](NumMwmId id) { - if (id == finishId) - areMwmsNear = true; - }); - return areMwmsNear; + // Function fails on first mwm which is not near to all other mwms. + // Maximal complexity is O((size of mwms clique)^2). + // Mwm clique maximal size is 4 (4 color theorem). + for (auto const & outerId : mwmIds) + { + m2::RectD const startMwmRect = m_countryRectFn(m_numMwmIds->GetFile(outerId).GetName()); + for (auto const & innerId : mwmIds) + { + bool areMwmsNear = false; + m_numMwmTree->ForEachInRect(startMwmRect, [&](NumMwmId id) { + if (id == innerId) + areMwmsNear = true; + }); + if (!areMwmsNear) + return false; + } + } + return true; } } // namespace routing diff --git a/routing/index_router.hpp b/routing/index_router.hpp index 3a1568ca34..571c72c9eb 100644 --- a/routing/index_router.hpp +++ b/routing/index_router.hpp @@ -4,6 +4,7 @@ #include "routing/directions_engine.hpp" #include "routing/edge_estimator.hpp" #include "routing/features_road_graph.hpp" +#include "routing/index_graph_starter.hpp" #include "routing/joint.hpp" #include "routing/num_mwm_id.hpp" #include "routing/router.hpp" @@ -20,6 +21,7 @@ #include #include +#include #include #include @@ -72,8 +74,7 @@ private: RouterDelegate const & delegate, Route & route); IRouter::ResultCode CalculateSubroute(Checkpoints const & checkpoints, size_t subrouteIdx, Segment const & startSegment, - bool startSegmentIsAlmostCodirectional, - RouterDelegate const & delegate, WorldGraph & graph, + RouterDelegate const & delegate, IndexGraphStarter & graph, std::vector & subroute, Junction & startJunction); IRouter::ResultCode AdjustRoute(Checkpoints const & checkpoints, @@ -102,7 +103,7 @@ private: RouterDelegate const & delegate, IndexGraphStarter & starter, Route & route) const; - bool AreMwmsNear(NumMwmId startId, NumMwmId finishId) const; + bool AreMwmsNear(std::set mwmIds) const; VehicleType m_vehicleType; bool m_loadAltitudes; @@ -121,5 +122,6 @@ private: std::shared_ptr m_estimator; std::unique_ptr m_directionsEngine; std::unique_ptr m_lastRoute; + std::unique_ptr m_lastFakeEdges; }; } // namespace routing diff --git a/routing/routing_tests/applying_traffic_test.cpp b/routing/routing_tests/applying_traffic_test.cpp index 4d84d18cac..47c013185e 100644 --- a/routing/routing_tests/applying_traffic_test.cpp +++ b/routing/routing_tests/applying_traffic_test.cpp @@ -124,9 +124,12 @@ UNIT_CLASS_TEST(ApplyingTrafficTest, XXGraph_EmptyTrafficColoring) TEST(!GetTrafficStash()->Has(kTestNumMwmId), ()); unique_ptr graph = BuildXXGraph(GetEstimator()); - IndexGraphStarter::FakeVertex const start(kTestNumMwmId, 9, 0, m2::PointD(2.0, -1.0)); - IndexGraphStarter::FakeVertex const finish(kTestNumMwmId, 6, 0, m2::PointD(3.0, 3.0)); - IndexGraphStarter starter(start, finish, *graph); + auto const start = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 9, 0, true /* forward */), m2::PointD(2.0, -1.0), *graph); + auto const finish = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 6, 0, true /* forward */), m2::PointD(3.0, 3.0), *graph); + IndexGraphStarter starter(start, finish, 0 /* fakeNumerationStart */, false /* strictForward */, + *graph); vector const expectedGeom = {{2 /* x */, -1 /* y */}, {2, 0}, {1, 1}, {2, 2}, {3, 3}}; TestRouteGeometry(starter, AStarAlgorithm::Result::OK, expectedGeom); } @@ -140,9 +143,12 @@ UNIT_CLASS_TEST(ApplyingTrafficTest, XXGraph_G0onF3) SetTrafficColoring(make_shared(coloring)); unique_ptr graph = BuildXXGraph(GetEstimator()); - IndexGraphStarter::FakeVertex const start(kTestNumMwmId, 9, 0, m2::PointD(2.0, -1.0)); - IndexGraphStarter::FakeVertex const finish(kTestNumMwmId, 6, 0, m2::PointD(3.0, 3.0)); - IndexGraphStarter starter(start, finish, *graph); + auto const start = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 9, 0, true /* forward */), m2::PointD(2.0, -1.0), *graph); + auto const finish = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 6, 0, true /* forward */), m2::PointD(3.0, 3.0), *graph); + IndexGraphStarter starter(start, finish, 0 /* fakeNumerationStart */, false /* strictForward */, + *graph); vector const expectedGeom = {{2 /* x */, -1 /* y */}, {2, 0}, {3, 0}, {3, 1}, {2, 2}, {3, 3}}; TestRouteGeometry(starter, AStarAlgorithm::Result::OK, expectedGeom); } @@ -156,9 +162,12 @@ UNIT_CLASS_TEST(ApplyingTrafficTest, XXGraph_TempBlockonF3) SetTrafficColoring(make_shared(coloring)); unique_ptr graph = BuildXXGraph(GetEstimator()); - IndexGraphStarter::FakeVertex const start(kTestNumMwmId, 9, 0, m2::PointD(2.0, -1.0)); - IndexGraphStarter::FakeVertex const finish(kTestNumMwmId, 6, 0, m2::PointD(3.0, 3.0)); - IndexGraphStarter starter(start, finish, *graph); + auto const start = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 9, 0, true /* forward */), m2::PointD(2.0, -1.0), *graph); + auto const finish = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 6, 0, true /* forward */), m2::PointD(3.0, 3.0), *graph); + IndexGraphStarter starter(start, finish, 0 /* fakeNumerationStart */, false /* strictForward */, + *graph); vector const expectedGeom = {{2 /* x */, -1 /* y */}, {2, 0}, {3, 0}, {3, 1}, {2, 2}, {3, 3}}; TestRouteGeometry(starter, AStarAlgorithm::Result::OK, expectedGeom); } @@ -172,9 +181,12 @@ UNIT_CLASS_TEST(ApplyingTrafficTest, XXGraph_G0onF3ReverseDir) SetTrafficColoring(make_shared(coloring)); unique_ptr graph = BuildXXGraph(GetEstimator()); - IndexGraphStarter::FakeVertex const start(kTestNumMwmId, 9, 0, m2::PointD(2.0, -1.0)); - IndexGraphStarter::FakeVertex const finish(kTestNumMwmId, 6, 0, m2::PointD(3.0, 3.0)); - IndexGraphStarter starter(start, finish, *graph); + auto const start = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 9, 0, true /* forward */), m2::PointD(2.0, -1.0), *graph); + auto const finish = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 6, 0, true /* forward */), m2::PointD(3.0, 3.0), *graph); + IndexGraphStarter starter(start, finish, 0 /* fakeNumerationStart */, false /* strictForward */, + *graph); vector const expectedGeom = {{2 /* x */, -1 /* y */}, {2, 0}, {1, 1}, {2, 2}, {3, 3}}; TestRouteGeometry(starter, AStarAlgorithm::Result::OK, expectedGeom); } @@ -194,9 +206,12 @@ UNIT_CLASS_TEST(ApplyingTrafficTest, XXGraph_G0onF3andF6andG4onF8andF4) SetTrafficColoring(make_shared(coloring)); unique_ptr graph = BuildXXGraph(GetEstimator()); - IndexGraphStarter::FakeVertex const start(kTestNumMwmId, 9, 0, m2::PointD(2.0, -1.0)); - IndexGraphStarter::FakeVertex const finish(kTestNumMwmId, 6, 0, m2::PointD(3.0, 3.0)); - IndexGraphStarter starter(start, finish, *graph); + auto const start = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 9, 0, true /* forward */), m2::PointD(2.0, -1.0), *graph); + auto const finish = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 6, 0, true /* forward */), m2::PointD(3.0, 3.0), *graph); + IndexGraphStarter starter(start, finish, 0 /* fakeNumerationStart */, false /* strictForward */, + *graph); vector const expectedGeom = {{2 /* x */, -1 /* y */}, {2, 0}, {3, 0}, {3, 1}, {2, 2}, {3, 3}}; TestRouteGeometry(starter, AStarAlgorithm::Result::OK, expectedGeom); } @@ -208,9 +223,12 @@ UNIT_CLASS_TEST(ApplyingTrafficTest, XXGraph_ChangingTraffic) TEST(!GetTrafficStash()->Has(kTestNumMwmId), ()); unique_ptr graph = BuildXXGraph(GetEstimator()); - IndexGraphStarter::FakeVertex const start(kTestNumMwmId, 9, 0, m2::PointD(2.0, -1.0)); - IndexGraphStarter::FakeVertex const finish(kTestNumMwmId, 6, 0, m2::PointD(3.0, 3.0)); - IndexGraphStarter starter(start, finish, *graph); + auto const start = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 9, 0, true /* forward */), m2::PointD(2.0, -1.0), *graph); + auto const finish = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 6, 0, true /* forward */), m2::PointD(3.0, 3.0), *graph); + IndexGraphStarter starter(start, finish, 0 /* fakeNumerationStart */, false /* strictForward */, + *graph); vector const noTrafficGeom = {{2 /* x */, -1 /* y */}, {2, 0}, {1, 1}, {2, 2}, {3, 3}}; { TestRouteGeometry(starter, AStarAlgorithm::Result::OK, noTrafficGeom); diff --git a/routing/routing_tests/cumulative_restriction_test.cpp b/routing/routing_tests/cumulative_restriction_test.cpp index 1dfbbc0b5d..f82a8da9f7 100644 --- a/routing/routing_tests/cumulative_restriction_test.cpp +++ b/routing/routing_tests/cumulative_restriction_test.cpp @@ -71,9 +71,12 @@ unique_ptr BuildXYGraph() UNIT_TEST(XYGraph) { unique_ptr graph = BuildXYGraph(); - IndexGraphStarter starter( - IndexGraphStarter::FakeVertex(kTestNumMwmId, 1, 0, m2::PointD(2, 0)) /* start */, - IndexGraphStarter::FakeVertex(kTestNumMwmId, 5, 0, m2::PointD(2, 3)) /* finish */, *graph); + auto const start = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 1, 0, true /* forward */), m2::PointD(2, 0), *graph); + auto const finish = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 5, 0, true /* forward */), m2::PointD(2, 3), *graph); + IndexGraphStarter starter(start, finish, 0 /* fakeNumerationStart */, false /* strictForward */, + *graph); vector const expectedGeom = {{2 /* x */, 0 /* y */}, {1, 1}, {2, 2}, {2, 3}}; TestRouteGeometry(starter, AStarAlgorithm::Result::OK, expectedGeom); } @@ -88,8 +91,10 @@ UNIT_CLASS_TEST(RestrictionTest, XYGraph_RestrictionF1F3Only) vector const expectedGeom = {{2 /* x */, 0 /* y */}, {1, 1}, {2, 2}, {2, 3}}; TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 1, 0, m2::PointD(2, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 5, 0, m2::PointD(2, 3)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 1, 0, true /* forward */), + m2::PointD(2, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 5, 0, true /* forward */), + m2::PointD(2, 3), *m_graph), move(restrictions), *this); } @@ -103,8 +108,10 @@ UNIT_CLASS_TEST(RestrictionTest, XYGraph_RestrictionF3F5Only) vector const expectedGeom = {{2 /* x */, 0 /* y */}, {1, 1}, {2, 2}, {2, 3}}; TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 1, 0, m2::PointD(2, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 5, 0, m2::PointD(2, 3)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 1, 0, true /* forward */), + m2::PointD(2, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 5, 0, true /* forward */), + m2::PointD(2, 3), *m_graph), move(restrictions), *this); } @@ -120,8 +127,10 @@ UNIT_CLASS_TEST(RestrictionTest, XYGraph_PermutationsF3F5OnlyF1F3Only) vector const expectedGeom = {{2 /* x */, 0 /* y */}, {1, 1}, {2, 2}, {2, 3}}; TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 1, 0, m2::PointD(2, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 5, 0, m2::PointD(2, 3)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 1, 0, true /* forward */), + m2::PointD(2, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 5, 0, true /* forward */), + m2::PointD(2, 3), *m_graph), move(restrictions), *this); } @@ -137,8 +146,10 @@ UNIT_CLASS_TEST(RestrictionTest, XYGraph_PermutationsF3F5OnlyAndF0F2No) vector const expectedGeom = {{2 /* x */, 0 /* y */}, {1, 1}, {2, 2}, {2, 3}}; TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 1, 0, m2::PointD(2, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 5, 0, m2::PointD(2, 3)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 1, 0, true /* forward */), + m2::PointD(2, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 5, 0, true /* forward */), + m2::PointD(2, 3), *m_graph), move(restrictions), *this); } @@ -154,8 +165,10 @@ UNIT_CLASS_TEST(RestrictionTest, XYGraph_RestrictionF3F5OnlyAndF1F3No) TestRestrictions( {} /* expectedGeom */, AStarAlgorithm::Result::NoPath, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 1, 0, m2::PointD(2, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 5, 0, m2::PointD(2, 3)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 1, 0, true /* forward */), + m2::PointD(2, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 5, 0, true /* forward */), + m2::PointD(2, 3), *m_graph), move(restrictions), *this); } @@ -230,8 +243,10 @@ UNIT_CLASS_TEST(RestrictionTest, XXGraph) vector const expectedGeom = {{2 /* x */, -1 /* y */}, {2, 0}, {1, 1}, {2, 2}, {3, 3}}; TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 9, 0, m2::PointD(2, -1)), /* start */ - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 6, 0, m2::PointD(3, 3)), /* finish */ + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 9, 0, true /* forward */), + m2::PointD(2, -1), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 6, 0, true /* forward */), + m2::PointD(3, 3), *m_graph), move(restrictions), *this); } @@ -247,8 +262,10 @@ UNIT_CLASS_TEST(RestrictionTest, XXGraph_PermutationsF1F3OnlyAndF3F6Only) vector const expectedGeom = {{2 /* x */, -1 /* y */}, {2, 0}, {1, 1}, {2, 2}, {3, 3}}; TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 9, 0, m2::PointD(2, -1)), /* start */ - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 6, 0, m2::PointD(3, 3)), /* finish */ + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 9, 0, true /* forward */), + m2::PointD(2, -1), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 6, 0, true /* forward */), + m2::PointD(3, 3), *m_graph), move(restrictions), *this); } @@ -263,8 +280,10 @@ UNIT_CLASS_TEST(RestrictionTest, XXGraph_RestrictionF1F3No) TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 9, 0, m2::PointD(2, -1)), /* start */ - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 6, 0, m2::PointD(3, 3)), /* finish */ + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 9, 0, true /* forward */), + m2::PointD(2, -1), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 6, 0, true /* forward */), + m2::PointD(3, 3), *m_graph), move(restrictions), *this); } @@ -283,8 +302,10 @@ UNIT_CLASS_TEST(RestrictionTest, XXGraph_PermutationsF1F3NoF7F8OnlyF8F4OnlyF4F6O {2 /* x */, -1 /* y */}, {2, 0}, {3, 0}, {3, 1}, {2, 2}, {3, 3}}; TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 9, 0, m2::PointD(2, -1)), /* start */ - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 6, 0, m2::PointD(3, 3)), /* finish */ + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 9, 0, true /* forward */), + m2::PointD(2, -1), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 6, 0, true /* forward */), + m2::PointD(3, 3), *m_graph), move(restrictions), *this); } } // namespace diff --git a/routing/routing_tests/index_graph_test.cpp b/routing/routing_tests/index_graph_test.cpp index 7679539b7e..a2eaf1850a 100644 --- a/routing/routing_tests/index_graph_test.cpp +++ b/routing/routing_tests/index_graph_test.cpp @@ -35,25 +35,35 @@ using namespace routing_test; using TestEdge = TestIndexGraphTopology::Edge; -void TestRoute(IndexGraphStarter::FakeVertex const & start, - IndexGraphStarter::FakeVertex const & finish, size_t expectedLength, +void TestRoute(IndexGraphStarter::FakeEnding const & start, + IndexGraphStarter::FakeEnding const & finish, size_t expectedLength, vector const * expectedRoute, WorldGraph & graph) { - IndexGraphStarter starter(start, finish, graph); + IndexGraphStarter starter(start, finish, 0 /* fakeNumerationStart */, false /* strictForward */, + graph); vector route; double timeSec; auto const resultCode = CalculateRoute(starter, route, timeSec); TEST_EQUAL(resultCode, AStarAlgorithm::Result::OK, ()); TEST_GREATER(route.size(), 2, ()); - // Erase fake points. - route.erase(route.begin()); - route.pop_back(); - TEST_EQUAL(route.size(), expectedLength, ("route =", route)); + vector noFakeRoute; + for (auto const & s : route) + { + auto real = s; + if (IndexGraphStarter::IsFakeSegment(real)) + { + if (!starter.ConvertToReal(real)) + continue; + } + noFakeRoute.push_back(real); + } + + TEST_EQUAL(noFakeRoute.size(), expectedLength, ("route =", noFakeRoute)); if (expectedRoute) - TEST_EQUAL(route, *expectedRoute, ()); + TEST_EQUAL(noFakeRoute, *expectedRoute, ()); } void TestEdges(IndexGraph & graph, Segment const & segment, vector const & expectedTargets, @@ -187,11 +197,13 @@ UNIT_TEST(FindPathCross) unique_ptr worldGraph = BuildWorldGraph(move(loader), estimator, {MakeJoint({{0, 2}, {1, 2}})}); - vector endPoints; + vector endPoints; for (uint32_t i = 0; i < 4; ++i) { - endPoints.emplace_back(kTestNumMwmId, 0, i, m2::PointD(-1.5 + i, 0.0)); - endPoints.emplace_back(kTestNumMwmId, 1, i, m2::PointD(0.0, -1.5 + i)); + endPoints.push_back(IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 0, i, true /*forward*/), m2::PointD(-1.5 + i, 0.0), *worldGraph)); + endPoints.push_back(IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 1, i, true /*forward*/), m2::PointD(0.0, -1.5 + i), *worldGraph)); } for (auto const & start : endPoints) @@ -199,22 +211,24 @@ UNIT_TEST(FindPathCross) for (auto const & finish : endPoints) { uint32_t expectedLength = 0; - if (start.GetFeatureId() == finish.GetFeatureId()) + if (start.m_projectionSegments[0].GetFeatureId() == + finish.m_projectionSegments[0].GetFeatureId()) { - expectedLength = - AbsDelta(start.GetSegmentIdxForTesting(), finish.GetSegmentIdxForTesting()) + 1; + expectedLength = AbsDelta(start.m_projectionSegments[0].GetSegmentIdx(), + finish.m_projectionSegments[0].GetSegmentIdx()) + + 1; } else { - if (start.GetSegmentIdxForTesting() < 2) - expectedLength += 2 - start.GetSegmentIdxForTesting(); + if (start.m_projectionSegments[0].GetSegmentIdx() < 2) + expectedLength += 2 - start.m_projectionSegments[0].GetSegmentIdx(); else - expectedLength += start.GetSegmentIdxForTesting() - 1; + expectedLength += start.m_projectionSegments[0].GetSegmentIdx() - 1; - if (finish.GetSegmentIdxForTesting() < 2) - expectedLength += 2 - finish.GetSegmentIdxForTesting(); + if (finish.m_projectionSegments[0].GetSegmentIdx() < 2) + expectedLength += 2 - finish.m_projectionSegments[0].GetSegmentIdx(); else - expectedLength += finish.GetSegmentIdxForTesting() - 1; + expectedLength += finish.m_projectionSegments[0].GetSegmentIdx() - 1; } TestRoute(start, finish, expectedLength, nullptr, *worldGraph); } @@ -260,15 +274,17 @@ UNIT_TEST(FindPathManhattan) unique_ptr worldGraph = BuildWorldGraph(move(loader), estimator, joints); - vector endPoints; + vector endPoints; for (uint32_t featureId = 0; featureId < kCitySize; ++featureId) { for (uint32_t segmentId = 0; segmentId < kCitySize - 1; ++segmentId) { - endPoints.emplace_back(kTestNumMwmId, featureId, segmentId, - m2::PointD(0.5 + segmentId, featureId)); - endPoints.emplace_back(kTestNumMwmId, featureId + kCitySize, segmentId, - m2::PointD(featureId, 0.5 + segmentId)); + endPoints.push_back(IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, featureId, segmentId, true /*forward*/), + m2::PointD(0.5 + segmentId, featureId), *worldGraph)); + endPoints.push_back(IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, featureId + kCitySize, segmentId, true /*forward*/), + m2::PointD(featureId, 0.5 + segmentId), *worldGraph)); } } @@ -278,33 +294,37 @@ UNIT_TEST(FindPathManhattan) { uint32_t expectedLength = 0; - auto const startFeatureOffset = start.GetFeatureId() < kCitySize - ? start.GetFeatureId() - : start.GetFeatureId() - kCitySize; - auto const finishFeatureOffset = finish.GetFeatureId() < kCitySize - ? finish.GetFeatureId() - : finish.GetFeatureId() - kCitySize; + auto const startFeatureOffset = + start.m_projectionSegments[0].GetFeatureId() < kCitySize + ? start.m_projectionSegments[0].GetFeatureId() + : start.m_projectionSegments[0].GetFeatureId() - kCitySize; + auto const finishFeatureOffset = + finish.m_projectionSegments[0].GetFeatureId() < kCitySize + ? finish.m_projectionSegments[0].GetFeatureId() + : finish.m_projectionSegments[0].GetFeatureId() - kCitySize; - if (start.GetFeatureId() < kCitySize == finish.GetFeatureId() < kCitySize) + if (start.m_projectionSegments[0].GetFeatureId() < kCitySize == + finish.m_projectionSegments[0].GetFeatureId() < kCitySize) { - uint32_t segDelta = - AbsDelta(start.GetSegmentIdxForTesting(), finish.GetSegmentIdxForTesting()); - if (segDelta == 0 && start.GetFeatureId() != finish.GetFeatureId()) + uint32_t segDelta = AbsDelta(start.m_projectionSegments[0].GetSegmentIdx(), + finish.m_projectionSegments[0].GetSegmentIdx()); + if (segDelta == 0 && start.m_projectionSegments[0].GetFeatureId() != + finish.m_projectionSegments[0].GetFeatureId()) segDelta = 1; expectedLength += segDelta; expectedLength += AbsDelta(startFeatureOffset, finishFeatureOffset) + 1; } else { - if (start.GetSegmentIdxForTesting() < finishFeatureOffset) - expectedLength += finishFeatureOffset - start.GetSegmentIdxForTesting(); + if (start.m_projectionSegments[0].GetSegmentIdx() < finishFeatureOffset) + expectedLength += finishFeatureOffset - start.m_projectionSegments[0].GetSegmentIdx(); else - expectedLength += start.GetSegmentIdxForTesting() - finishFeatureOffset + 1; + expectedLength += start.m_projectionSegments[0].GetSegmentIdx() - finishFeatureOffset + 1; - if (finish.GetSegmentIdxForTesting() < startFeatureOffset) - expectedLength += startFeatureOffset - finish.GetSegmentIdxForTesting(); + if (finish.m_projectionSegments[0].GetSegmentIdx() < startFeatureOffset) + expectedLength += startFeatureOffset - finish.m_projectionSegments[0].GetSegmentIdx(); else - expectedLength += finish.GetSegmentIdxForTesting() - startFeatureOffset + 1; + expectedLength += finish.m_projectionSegments[0].GetSegmentIdx() - startFeatureOffset + 1; } TestRoute(start, finish, expectedLength, nullptr, *worldGraph); @@ -342,8 +362,10 @@ UNIT_TEST(RoadSpeed) unique_ptr worldGraph = BuildWorldGraph(move(loader), estimator, joints); - IndexGraphStarter::FakeVertex const start(kTestNumMwmId, 1, 0, m2::PointD(0.5, 0)); - IndexGraphStarter::FakeVertex const finish(kTestNumMwmId, 1, 3, m2::PointD(5.5, 0)); + auto const start = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 1, 0, true /* forward */), m2::PointD(0.5, 0), *worldGraph); + auto const finish = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 1, 3, true /* forward */), m2::PointD(5.5, 0), *worldGraph); vector const expectedRoute({{kTestNumMwmId, 1, 0, true}, {kTestNumMwmId, 0, 0, true}, @@ -373,31 +395,13 @@ UNIT_TEST(OneSegmentWay) shared_ptr estimator = CreateEstimatorForCar(trafficCache); unique_ptr worldGraph = BuildWorldGraph(move(loader), estimator, vector()); - IndexGraphStarter::FakeVertex const start(kTestNumMwmId, 0, 0, m2::PointD(1, 0)); - IndexGraphStarter::FakeVertex const finish(kTestNumMwmId, 0, 0, m2::PointD(2, 0)); + auto const start = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 0, 0, true /* forward */), m2::PointD(1, 0), *worldGraph); + auto const finish = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 0, 0, true /* forward */), m2::PointD(2, 0), *worldGraph); - // According to picture below 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 */}}); + vector const expectedRoute( + {{kTestNumMwmId, 0 /* featureId */, 0 /* seg id */, true /* forward */}}); TestRoute(start, finish, 1 /* expectedLength */, &expectedRoute, *worldGraph); } @@ -525,18 +529,19 @@ unique_ptr BuildLoopGraph() UNIT_CLASS_TEST(RestrictionTest, LoopGraph) { Init(BuildLoopGraph()); - SetStarter(routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 1, 0 /* seg id */, - m2::PointD(0.0002, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 2, 0 /* seg id */, - m2::PointD(0.00005, 0.0004)) /* finish */); + auto start = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 1, 0 /* seg id */, true /* forward */), m2::PointD(0.0002, 0), + *m_graph); + auto finish = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 2, 0 /* seg id */, true /* forward */), m2::PointD(0.00005, 0.0004), + *m_graph); vector const expectedRoute = {{kTestNumMwmId, 1, 0, true}, {kTestNumMwmId, 0, 0, true}, {kTestNumMwmId, 0, 1, true}, {kTestNumMwmId, 0, 8, false}, {kTestNumMwmId, 0, 7, false}, {kTestNumMwmId, 0, 6, false}, {kTestNumMwmId, 2, 0, true}}; - TestRoute(m_starter->GetStartVertex(), m_starter->GetFinishVertex(), 7, &expectedRoute, - m_starter->GetGraph()); + TestRoute(start, finish, 7, &expectedRoute, *m_graph); } UNIT_TEST(IndexGraph_OnlyTopology_1) @@ -551,7 +556,8 @@ UNIT_TEST(IndexGraph_OnlyTopology_1) graph.AddDirectedEdge(2, 3, 2.0); double const expectedWeight = 2.0; - vector const expectedEdges = {{0, 1}, {1, 3}}; + // Firs and last edges are projections. + vector const expectedEdges = {{0, 0}, {0, 1}, {1, 3}, {3, 3}}; TestTopologyGraph(graph, 0, 3, true /* pathFound */, expectedWeight, expectedEdges); TestTopologyGraph(graph, 0, 4, false /* pathFound */, 0.0, {}); @@ -577,7 +583,8 @@ UNIT_TEST(IndexGraph_OnlyTopology_3) graph.AddDirectedEdge(0, 1, 1.0); graph.AddDirectedEdge(1, 0, 1.0); double const expectedWeight = 1.0; - vector const expectedEdges = {{0, 1}}; + // Firs and last edges are projections. + vector const expectedEdges = {{0, 0}, {0, 1}, {1, 1}}; TestTopologyGraph(graph, 0, 1, true /* pathFound */, expectedWeight, expectedEdges); } diff --git a/routing/routing_tests/index_graph_tools.cpp b/routing/routing_tests/index_graph_tools.cpp index c50e080f45..78c3624408 100644 --- a/routing/routing_tests/index_graph_tools.cpp +++ b/routing/routing_tests/index_graph_tools.cpp @@ -113,12 +113,15 @@ bool TestIndexGraphTopology::FindPath(Vertex start, Vertex finish, double & path auto const worldGraph = builder.PrepareIndexGraph(); CHECK(worldGraph != nullptr, ()); - auto const fakeStart = IndexGraphStarter::FakeVertex(kTestNumMwmId, startFeatureId, - 0 /* pointId */, m2::PointD::Zero()); - auto const fakeFinish = IndexGraphStarter::FakeVertex(kTestNumMwmId, finishFeatureId, - 0 /* pointId */, m2::PointD::Zero()); + auto const fakeStart = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, startFeatureId, 0 /* segmentIdx */, true /* forward */), + m2::PointD::Zero(), *worldGraph); + auto const fakeFinish = IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, finishFeatureId, 0 /* segmentIdx */, true /* forward */), + m2::PointD::Zero(), *worldGraph); - IndexGraphStarter starter(fakeStart, fakeFinish, *worldGraph); + IndexGraphStarter starter(fakeStart, fakeFinish, 0 /* fakeNumerationStart */, + false /* strictForward */, *worldGraph); vector routeSegs; double timeSec; @@ -129,15 +132,20 @@ bool TestIndexGraphTopology::FindPath(Vertex start, Vertex finish, double & path CHECK_EQUAL(resultCode, AStarAlgorithm::Result::OK, ()); CHECK_GREATER_OR_EQUAL(routeSegs.size(), 2, ()); - CHECK_EQUAL(routeSegs.front(), starter.GetStart(), ()); - CHECK_EQUAL(routeSegs.back(), starter.GetFinish(), ()); + CHECK_EQUAL(routeSegs.front(), starter.GetStartSegment(), ()); + CHECK_EQUAL(routeSegs.back(), starter.GetFinishSegment(), ()); // We are not interested in the fake start and finish. pathEdges.resize(routeSegs.size() - 2); pathWeight = 0.0; for (size_t i = 1; i + 1 < routeSegs.size(); ++i) { - auto const & seg = routeSegs[i]; + auto seg = routeSegs[i]; + if (IndexGraphStarter::IsFakeSegment(seg)) + { + if (!starter.ConvertToReal(seg)) + continue; + } auto const it = builder.m_segmentToEdge.find(seg); CHECK(it != builder.m_segmentToEdge.cend(), ()); auto const & edge = it->second; @@ -278,8 +286,8 @@ AStarAlgorithm::Result CalculateRoute(IndexGraphStarter & sta RoutingResult routingResult; auto const resultCode = algorithm.FindPathBidirectional( - starter, starter.GetStart(), starter.GetFinish(), routingResult, {} /* cancellable */, - {} /* onVisitedVertexCallback */); + starter, starter.GetStartSegment(), starter.GetFinishSegment(), routingResult, + {} /* cancellable */, {} /* onVisitedVertexCallback */); timeSec = routingResult.distance.GetWeight(); roadPoints = routingResult.path; @@ -328,8 +336,8 @@ void TestRouteGeometry(IndexGraphStarter & starter, void TestRestrictions(vector const & expectedRouteGeom, AStarAlgorithm::Result expectedRouteResult, - routing::IndexGraphStarter::FakeVertex const & start, - routing::IndexGraphStarter::FakeVertex const & finish, + routing::IndexGraphStarter::FakeEnding const & start, + routing::IndexGraphStarter::FakeEnding const & finish, RestrictionVec && restrictions, RestrictionTest & restrictionTest) { restrictionTest.SetRestrictions(move(restrictions)); diff --git a/routing/routing_tests/index_graph_tools.hpp b/routing/routing_tests/index_graph_tools.hpp index 816e19d81b..946b885070 100644 --- a/routing/routing_tests/index_graph_tools.hpp +++ b/routing/routing_tests/index_graph_tools.hpp @@ -39,10 +39,11 @@ struct RestrictionTest { RestrictionTest() { classificator::Load(); } void Init(unique_ptr graph) { m_graph = move(graph); } - void SetStarter(IndexGraphStarter::FakeVertex const & start, - IndexGraphStarter::FakeVertex const & finish) + void SetStarter(IndexGraphStarter::FakeEnding const & start, + IndexGraphStarter::FakeEnding const & finish) { - m_starter = make_unique(start, finish, *m_graph); + m_starter = make_unique(start, finish, 0 /* fakeNumerationStart */, + false /* strictForward */, *m_graph); } void SetRestrictions(RestrictionVec && restrictions) @@ -199,8 +200,8 @@ void TestRouteGeometry( /// \note restrictionTest should have a valid |restrictionTest.m_graph|. void TestRestrictions(vector const & expectedRouteGeom, AStarAlgorithm::Result expectedRouteResult, - routing::IndexGraphStarter::FakeVertex const & start, - routing::IndexGraphStarter::FakeVertex const & finish, + routing::IndexGraphStarter::FakeEnding const & start, + routing::IndexGraphStarter::FakeEnding const & finish, RestrictionVec && restrictions, RestrictionTest & restrictionTest); // Tries to find a unique path from |from| to |to| in |graph|. diff --git a/routing/routing_tests/restriction_test.cpp b/routing/routing_tests/restriction_test.cpp index c970ee1a5d..fd9073b539 100644 --- a/routing/routing_tests/restriction_test.cpp +++ b/routing/routing_tests/restriction_test.cpp @@ -64,9 +64,10 @@ unique_ptr BuildCrossGraph() UNIT_CLASS_TEST(RestrictionTest, CrossGraph_NoUTurn) { Init(BuildCrossGraph()); - SetStarter( - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 0, 0, m2::PointD(-1, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 7, 0, m2::PointD(1, 2)) /* finish */); + SetStarter(routing::IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 0, 0, true /* forward */), m2::PointD(-1, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 7, 0, true /* forward */), m2::PointD(1, 2), *m_graph)); vector const expectedGeom = { {-1.0 /* x */, 0.0 /* y */}, {0.0, 0.0}, {1.0, 0.0}, {1.0, 1.0}, {1.0, 2.0}}; @@ -76,9 +77,10 @@ UNIT_CLASS_TEST(RestrictionTest, CrossGraph_NoUTurn) UNIT_CLASS_TEST(RestrictionTest, CrossGraph_UTurn) { Init(BuildCrossGraph()); - SetStarter( - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 0, 0, m2::PointD(-1, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 7, 0, m2::PointD(1, 2)) /* finish */); + SetStarter(routing::IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 0, 0, true /* forward */), m2::PointD(-1, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 7, 0, true /* forward */), m2::PointD(1, 2), *m_graph)); RestrictionVec restrictions = { {Restriction::Type::No, {1 /* feature from */, 6 /* feature to */}}}; @@ -87,8 +89,10 @@ UNIT_CLASS_TEST(RestrictionTest, CrossGraph_UTurn) TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 0, 0, m2::PointD(-1, 0)), /* start */ - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 7, 0, m2::PointD(1, 2)), /* finish */ + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 0, 0, true /* forward */), + m2::PointD(-1, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 7, 0, true /* forward */), + m2::PointD(1, 2), *m_graph), move(restrictions), *this); } @@ -148,8 +152,10 @@ UNIT_CLASS_TEST(RestrictionTest, TriangularGraph) TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 5, 0, m2::PointD(3, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 4, 0, m2::PointD(0, 3)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 5, 0, true /* forward */), + m2::PointD(3, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 4, 0, true /* forward */), + m2::PointD(0, 3), *m_graph), {}, *this); } @@ -164,8 +170,10 @@ UNIT_CLASS_TEST(RestrictionTest, TriangularGraph_RestrictionNoF2F1) TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 5, 0, m2::PointD(3, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 4, 0, m2::PointD(0, 3)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 5, 0, true /* forward */), + m2::PointD(3, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 4, 0, true /* forward */), + m2::PointD(0, 3), *m_graph), move(restrictions), *this); } @@ -179,8 +187,10 @@ UNIT_CLASS_TEST(RestrictionTest, TriangularGraph_RestrictionNoF5F2) TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 5, 0, m2::PointD(3, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 4, 0, m2::PointD(0, 3)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 5, 0, true /* forward */), + m2::PointD(3, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 4, 0, true /* forward */), + m2::PointD(0, 3), *m_graph), move(restrictions), *this); } @@ -197,8 +207,10 @@ UNIT_CLASS_TEST(RestrictionTest, TriangularGraph_RestrictionOnlyF5F3) TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 5, 0, m2::PointD(3, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 4, 0, m2::PointD(0, 3)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 5, 0, true /* forward */), + m2::PointD(3, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 4, 0, true /* forward */), + m2::PointD(0, 3), *m_graph), move(restrictionsNo), *this); } @@ -213,8 +225,10 @@ UNIT_CLASS_TEST(RestrictionTest, TriangularGraph_RestrictionNoF5F2RestrictionOnl TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 5, 0, m2::PointD(3, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 4, 0, m2::PointD(0, 3)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 5, 0, true /* forward */), + m2::PointD(3, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 4, 0, true /* forward */), + m2::PointD(0, 3), *m_graph), move(restrictions), *this); } @@ -268,8 +282,10 @@ UNIT_CLASS_TEST(RestrictionTest, TwowayCornerGraph) TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 3, 0, m2::PointD(3, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 4, 0, m2::PointD(0, 3)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 3, 0, true /* forward */), + m2::PointD(3, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 4, 0, true /* forward */), + m2::PointD(0, 3), *m_graph), {}, *this); } @@ -283,8 +299,10 @@ UNIT_CLASS_TEST(RestrictionTest, TwowayCornerGraph_RestrictionF3F2No) TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 3, 0, m2::PointD(3, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 4, 0, m2::PointD(0, 3)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 3, 0, true /* forward */), + m2::PointD(3, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 4, 0, true /* forward */), + m2::PointD(0, 3), *m_graph), move(restrictions), *this); } @@ -301,8 +319,10 @@ UNIT_CLASS_TEST(RestrictionTest, TwowayCornerGraph_RestrictionF3F1Only) TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 3, 0, m2::PointD(3, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 4, 0, m2::PointD(0, 3)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 3, 0, true /* forward */), + m2::PointD(3, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 4, 0, true /* forward */), + m2::PointD(0, 3), *m_graph), move(restrictionsNo), *this); } @@ -377,8 +397,10 @@ UNIT_CLASS_TEST(RestrictionTest, TwoSquaresGraph) TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 10, 0, m2::PointD(3, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 11, 0, m2::PointD(0, 3)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 10, 0, true /* forward */), + m2::PointD(3, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 11, 0, true /* forward */), + m2::PointD(0, 3), *m_graph), {}, *this); } @@ -396,8 +418,10 @@ UNIT_CLASS_TEST(RestrictionTest, TwoSquaresGraph_RestrictionF10F3Only) TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 10, 0, m2::PointD(3, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 11, 0, m2::PointD(0, 3)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 10, 0, true /* forward */), + m2::PointD(3, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 11, 0, true /* forward */), + m2::PointD(0, 3), *m_graph), move(restrictionsNo), *this); } @@ -416,8 +440,10 @@ UNIT_CLASS_TEST(RestrictionTest, TwoSquaresGraph_RestrictionF10F3OnlyF3F4Only) TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 10, 0, m2::PointD(3, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 11, 0, m2::PointD(0, 3)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 10, 0, true /* forward */), + m2::PointD(3, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 11, 0, true /* forward */), + m2::PointD(0, 3), *m_graph), move(restrictionsNo), *this); } @@ -436,8 +462,10 @@ UNIT_CLASS_TEST(RestrictionTest, TwoSquaresGraph_RestrictionF2F8NoRestrictionF9F TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 10, 0, m2::PointD(3, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 11, 0, m2::PointD(0, 3)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 10, 0, true /* forward */), + m2::PointD(3, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 11, 0, true /* forward */), + m2::PointD(0, 3), *m_graph), move(restrictionsNo), *this); } @@ -491,9 +519,11 @@ UNIT_TEST(FlagGraph) { unique_ptr graph = BuildFlagGraph(); IndexGraphStarter starter( - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 0, 0, m2::PointD(2, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 6, 0, m2::PointD(0.5, 1)) /* finish */, - *graph); + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 0, 0, true /* forward */), + m2::PointD(2, 0), *graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 6, 0, true /* forward */), + m2::PointD(0.5, 1), *graph), + 0 /* fakeNumerationStart */, false /* strictForward */, *graph); vector const expectedGeom = {{2 /* x */, 0 /* y */}, {1, 0}, {1, 1}, {0.5, 1}}; TestRouteGeometry(starter, AStarAlgorithm::Result::OK, expectedGeom); } @@ -509,8 +539,10 @@ UNIT_CLASS_TEST(RestrictionTest, FlagGraph_RestrictionF0F3No) TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 0, 0, m2::PointD(2, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 6, 0, m2::PointD(0.5, 1)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 0, 0, true /* forward */), + m2::PointD(2, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 6, 0, true /* forward */), + m2::PointD(0.5, 1), *m_graph), move(restrictions), *this); } @@ -524,8 +556,10 @@ UNIT_CLASS_TEST(RestrictionTest, FlagGraph_RestrictionF0F1Only) TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 0, 0, m2::PointD(2, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 6, 0, m2::PointD(0.5, 1)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 0, 0, true /* forward */), + m2::PointD(2, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 6, 0, true /* forward */), + m2::PointD(0.5, 1), *m_graph), move(restrictions), *this); } @@ -541,8 +575,10 @@ UNIT_CLASS_TEST(RestrictionTest, FlagGraph_PermutationsF1F3NoF7F8OnlyF8F4OnlyF4F {2 /* x */, 0 /* y */}, {1, 0}, {0, 0}, {0, 1}, {0.5, 1}}; TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 0, 0, m2::PointD(2, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 6, 0, m2::PointD(0.5, 1)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 0, 0, true /* forward */), + m2::PointD(2, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 6, 0, true /* forward */), + m2::PointD(0.5, 1), *m_graph), move(restrictions), *this); } @@ -592,9 +628,11 @@ UNIT_TEST(PosterGraph) { unique_ptr graph = BuildPosterGraph(); IndexGraphStarter starter( - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 0, 0, m2::PointD(2, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 6, 0, m2::PointD(2, 1)) /* finish */, - *graph); + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 0, 0, true /* forward */), + m2::PointD(2, 0), *graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 6, 0, true /* forward */), + m2::PointD(2, 1), *graph), + 0 /* fakeNumerationStart */, false /* strictForward */, *graph); vector const expectedGeom = {{2 /* x */, 0 /* y */}, {1, 0}, {1, 1}, {2, 1}}; TestRouteGeometry(starter, AStarAlgorithm::Result::OK, expectedGeom); @@ -611,8 +649,10 @@ UNIT_CLASS_TEST(RestrictionTest, PosterGraph_RestrictionF0F3No) TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 0, 0, m2::PointD(2, 0)), /* start */ - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 6, 0, m2::PointD(2, 1)), /* finish */ + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 0, 0, true /* forward */), + m2::PointD(2, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 6, 0, true /* forward */), + m2::PointD(2, 1), *m_graph), move(restrictions), *this); } @@ -631,8 +671,10 @@ UNIT_CLASS_TEST(RestrictionTest, PosterGraph_RestrictionF0F1Only) {2 /* x */, 0 /* y */}, {1, 0}, {0, 0}, {0, 1}, {0.5, 1}, {1, 1}, {2, 1}}; TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 0, 0, m2::PointD(2, 0)), /* start */ - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 6, 0, m2::PointD(2, 1)), /* finish */ + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 0, 0, true /* forward */), + m2::PointD(2, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 6, 0, true /* forward */), + m2::PointD(2, 1), *m_graph), move(restrictionsNo), *this); } @@ -674,9 +716,11 @@ UNIT_TEST(TwoWayGraph) { unique_ptr graph = BuildTwoWayGraph(); IndexGraphStarter starter( - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 3, 0, m2::PointD(-1, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 2, 0, m2::PointD(4, 0)) /* finish */, - *graph); + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 3, 0, true /* forward */), + m2::PointD(-1, 0), *graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 2, 0, true /* forward */), + m2::PointD(4, 0), *graph), + 0 /* fakeNumerationStart */, false /* strictForward */, *graph); vector const expectedGeom = {{-1 /* x */, 0 /* y */}, {0, 0}, {1, 0}, {3, 0}, {4, 0}}; TestRouteGeometry(starter, AStarAlgorithm::Result::OK, expectedGeom); @@ -725,9 +769,11 @@ UNIT_TEST(SquaresGraph) { unique_ptr graph = BuildSquaresGraph(); IndexGraphStarter starter( - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 0, 0, m2::PointD(3, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 5, 0, m2::PointD(0, 0)) /* finish */, - *graph); + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 0, 0, true /* forward */), + m2::PointD(3, 0), *graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 5, 0, true /* forward */), + m2::PointD(0, 0), *graph), + 0 /* fakeNumerationStart */, false /* strictForward */, *graph); vector const expectedGeom = {{3 /* x */, 0 /* y */}, {2, 0}, {1, 0}, {0, 0}}; TestRouteGeometry(starter, AStarAlgorithm::Result::OK, expectedGeom); } @@ -745,8 +791,10 @@ UNIT_CLASS_TEST(RestrictionTest, SquaresGraph_RestrictionF0F1OnlyF1F5Only) TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 0, 0, m2::PointD(3, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 5, 0, m2::PointD(0, 0)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 0, 0, true /* forward */), + m2::PointD(3, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 5, 0, true /* forward */), + m2::PointD(0, 0), *m_graph), move(restrictions), *this); } @@ -788,9 +836,11 @@ UNIT_CLASS_TEST(RestrictionTest, LineGraph_RestrictionF1F1No) TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 0 /* feature id */, 0 /* seg id */, - m2::PointD(0, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 2, 0, m2::PointD(5, 0)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 0 /* feature id */, 0 /* seg id */, true /* forward */), + m2::PointD(0, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 2, 0, true /* forward */), + m2::PointD(5, 0), *m_graph), move(restrictions), *this); } @@ -839,9 +889,11 @@ UNIT_CLASS_TEST(RestrictionTest, FGraph_RestrictionF0F2Only) TestRestrictions( expectedGeom, AStarAlgorithm::Result::OK, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 0 /* feature id */, 0 /* seg id */, - m2::PointD(0, 0)) /* start */, - routing::IndexGraphStarter::FakeVertex(kTestNumMwmId, 1, 0, m2::PointD(1, 1)) /* finish */, + routing::IndexGraphStarter::MakeFakeEnding( + Segment(kTestNumMwmId, 0 /* feature id */, 0 /* seg id */, true /* forward */), + m2::PointD(0, 0), *m_graph), + routing::IndexGraphStarter::MakeFakeEnding(Segment(kTestNumMwmId, 1, 0, true /* forward */), + m2::PointD(1, 1), *m_graph), move(restrictions), *this); } } // namespace routing_test diff --git a/routing/routing_tests/road_access_test.cpp b/routing/routing_tests/road_access_test.cpp index 79dfe92845..34d9775949 100644 --- a/routing/routing_tests/road_access_test.cpp +++ b/routing/routing_tests/road_access_test.cpp @@ -108,12 +108,13 @@ UNIT_TEST(RoadAccess_BarrierBypassing) vector expectedEdges; expectedWeight = 3.0; - expectedEdges = {{0, 1}, {1, 2}, {2, 5}}; + // First and last edges are projectios + expectedEdges = {{0, 0}, {0, 1}, {1, 2}, {2, 5}, {5, 5}}; TestTopologyGraph(graph, 0, 5, true /* pathFound */, expectedWeight, expectedEdges); graph.BlockEdge(1, 2); expectedWeight = 4.0; - expectedEdges = {{0, 3}, {3, 4}, {4, 5}}; + expectedEdges = {{0, 0}, {0, 3}, {3, 4}, {4, 5}, {5, 5}}; TestTopologyGraph(graph, 0, 5, true /* pathFound */, expectedWeight, expectedEdges); graph.BlockEdge(3, 4);