From 822657f3fdef5721c480b19976f3b10c7ae6dc58 Mon Sep 17 00:00:00 2001 From: Maxim Pimenov Date: Fri, 28 Apr 2017 20:46:19 +0300 Subject: [PATCH] [routing] Implemented blocking of features. --- routing/index_graph.cpp | 5 +++ routing/index_graph.hpp | 3 ++ routing/index_graph_loader.cpp | 22 +++++++++ routing/routing_tests/index_graph_test.cpp | 18 -------- routing/routing_tests/index_graph_tools.cpp | 47 ++++++++++++++++++- routing/routing_tests/index_graph_tools.hpp | 16 +++++++ routing/routing_tests/road_access_test.cpp | 50 +++++++++++++++++++++ 7 files changed, 142 insertions(+), 19 deletions(-) diff --git a/routing/index_graph.cpp b/routing/index_graph.cpp index bedb6583cd..dedc9e5f76 100644 --- a/routing/index_graph.cpp +++ b/routing/index_graph.cpp @@ -95,6 +95,8 @@ void IndexGraph::SetRestrictions(RestrictionVec && restrictions) m_restrictions = move(restrictions); } +void IndexGraph::SetRoadAccess(RoadAccess && roadAccess) { m_roadAccess = move(roadAccess); } + double IndexGraph::CalcSegmentWeight(Segment const & segment) { return m_estimator->CalcSegmentWeight(segment, m_geometry.GetRoad(segment.GetFeatureId())); @@ -139,6 +141,9 @@ void IndexGraph::GetNeighboringEdge(Segment const & from, Segment const & to, bo if (IsRestricted(m_restrictions, from, to, isOutgoing)) return; + if (m_roadAccess.GetSegmentType(to) != RoadAccess::Type::Yes) + return; + double const weight = CalcSegmentWeight(isOutgoing ? to : from) + GetPenalties(isOutgoing ? from : to, isOutgoing ? to : from); edges.emplace_back(to, weight); diff --git a/routing/index_graph.hpp b/routing/index_graph.hpp index 9f521ac4b8..a7e6ac390a 100644 --- a/routing/index_graph.hpp +++ b/routing/index_graph.hpp @@ -5,6 +5,7 @@ #include "routing/joint.hpp" #include "routing/joint_index.hpp" #include "routing/restrictions_serialization.hpp" +#include "routing/road_access.hpp" #include "routing/road_index.hpp" #include "routing/road_point.hpp" #include "routing/segment.hpp" @@ -42,6 +43,7 @@ public: void Import(vector const & joints); void SetRestrictions(RestrictionVec && restrictions); + void SetRoadAccess(RoadAccess && roadAccess); void PushFromSerializer(Joint::Id jointId, RoadPoint const & rp) { @@ -73,5 +75,6 @@ private: RoadIndex m_roadIndex; JointIndex m_jointIndex; RestrictionVec m_restrictions; + RoadAccess m_roadAccess; }; } // namespace routing diff --git a/routing/index_graph_loader.cpp b/routing/index_graph_loader.cpp index 380df7598b..67be2991a1 100644 --- a/routing/index_graph_loader.cpp +++ b/routing/index_graph_loader.cpp @@ -2,6 +2,7 @@ #include "routing/index_graph_serialization.hpp" #include "routing/restriction_loader.hpp" +#include "routing/road_access_serialization.hpp" #include "routing/routing_exceptions.hpp" #include "coding/file_container.hpp" @@ -82,6 +83,23 @@ IndexGraph & IndexGraphLoaderImpl::Load(NumMwmId numMwmId) } void IndexGraphLoaderImpl::Clear() { m_graphs.clear(); } + +bool ReadRoadAccessFromMwm(MwmValue const & mwmValue, RoadAccess & roadAccess) +{ + try + { + FilesContainerR::TReader const reader = mwmValue.m_cont.GetReader(ROAD_ACCESS_FILE_TAG); + ReaderSource src(reader); + + RoadAccessSerializer::Deserialize(src, VehicleType::Car, roadAccess); + } + catch (Reader::OpenException const & e) + { + LOG(LERROR, ("Error while reading", ROAD_ACCESS_FILE_TAG, "section.", e.Msg())); + return false; + } + return true; +} } // namespace namespace routing @@ -102,5 +120,9 @@ void DeserializeIndexGraph(MwmValue const & mwmValue, IndexGraph & graph) RestrictionLoader restrictionLoader(mwmValue, graph); if (restrictionLoader.HasRestrictions()) graph.SetRestrictions(restrictionLoader.StealRestrictions()); + + RoadAccess roadAccess; + if (ReadRoadAccessFromMwm(mwmValue, roadAccess)) + graph.SetRoadAccess(move(roadAccess)); } } // namespace routing diff --git a/routing/routing_tests/index_graph_test.cpp b/routing/routing_tests/index_graph_test.cpp index ef92644d38..12b6a11179 100644 --- a/routing/routing_tests/index_graph_test.cpp +++ b/routing/routing_tests/index_graph_test.cpp @@ -89,24 +89,6 @@ void TestIngoingEdges(IndexGraph & graph, Segment const & segment, } uint32_t AbsDelta(uint32_t v0, uint32_t v1) { return v0 > v1 ? v0 - v1 : v1 - v0; } - -void TestTopologyGraph(TestIndexGraphTopology const & graph, TestIndexGraphTopology::Vertex from, - TestIndexGraphTopology::Vertex to, bool expectedPathFound, - double const expectedWeight, vector const & expectedEdges) -{ - double const kEpsilon = 1e-6; - - double pathWeight = 0.0; - vector pathEdges; - bool const pathFound = graph.FindPath(from, to, pathWeight, pathEdges); - TEST_EQUAL(pathFound, expectedPathFound, ()); - if (!pathFound) - return; - - TEST(my::AlmostEqualAbs(pathWeight, expectedWeight, kEpsilon), - (pathWeight, expectedWeight, pathEdges)); - TEST_EQUAL(pathEdges, expectedEdges, ()); -} } // namespace namespace routing_test diff --git a/routing/routing_tests/index_graph_tools.cpp b/routing/routing_tests/index_graph_tools.cpp index b64221a261..a267709e2a 100644 --- a/routing/routing_tests/index_graph_tools.cpp +++ b/routing/routing_tests/index_graph_tools.cpp @@ -86,6 +86,19 @@ void TestIndexGraphTopology::AddDirectedEdge(Vertex from, Vertex to, double weig AddDirectedEdge(m_edgeRequests, from, to, weight); } +void TestIndexGraphTopology::BlockEdge(Vertex from, Vertex to) +{ + for (auto & r : m_edgeRequests) + { + if (r.m_from == from && r.m_to == to) + { + r.m_isBlocked = true; + return; + } + } + CHECK(false, ("Cannot block edge that is not in the graph", from, to)); +} + bool TestIndexGraphTopology::FindPath(Vertex start, Vertex finish, double & pathWeight, vector & pathEdges) const { @@ -169,7 +182,9 @@ unique_ptr TestIndexGraphTopology::Builder::PrepareIndexGraph() BuildJoints(); - return BuildWorldGraph(move(loader), estimator, m_joints); + auto worldGraph = BuildWorldGraph(move(loader), estimator, m_joints); + worldGraph->GetIndexGraph(kTestNumMwmId).SetRoadAccess(move(m_roadAccess)); + return worldGraph; } void TestIndexGraphTopology::Builder::BuildJoints() @@ -189,8 +204,19 @@ void TestIndexGraphTopology::Builder::BuildJoints() void TestIndexGraphTopology::Builder::BuildGraphFromRequests(vector const & requests) { + vector blockedFeatureIds; for (auto const & request : requests) + { BuildSegmentFromEdge(request); + if (request.m_isBlocked) + blockedFeatureIds.push_back(request.m_id); + } + + map segmentTypes; + for (auto const fid : blockedFeatureIds) + segmentTypes[Segment(kFakeNumMwmId, fid, 0 /* wildcard segmentIdx */, true)] = + RoadAccess::Type::No; + m_roadAccess.SetSegmentTypes(move(segmentTypes)); } void TestIndexGraphTopology::Builder::BuildSegmentFromEdge(EdgeRequest const & request) @@ -331,4 +357,23 @@ void TestRestrictions(vector const & expectedRouteGeom, restrictionTest.SetStarter(start, finish); TestRouteGeometry(*restrictionTest.m_starter, expectedRouteResult, expectedRouteGeom); } + +void TestTopologyGraph(TestIndexGraphTopology const & graph, TestIndexGraphTopology::Vertex from, + TestIndexGraphTopology::Vertex to, bool expectedPathFound, + double const expectedWeight, + vector const & expectedEdges) +{ + double const kEpsilon = 1e-6; + + double pathWeight = 0.0; + vector pathEdges; + bool const pathFound = graph.FindPath(from, to, pathWeight, pathEdges); + TEST_EQUAL(pathFound, expectedPathFound, ()); + if (!pathFound) + return; + + TEST(my::AlmostEqualAbs(pathWeight, expectedWeight, kEpsilon), + (pathWeight, expectedWeight, pathEdges)); + TEST_EQUAL(pathEdges, expectedEdges, ()); +} } // namespace routing_test diff --git a/routing/routing_tests/index_graph_tools.hpp b/routing/routing_tests/index_graph_tools.hpp index 476651a0d2..345c891960 100644 --- a/routing/routing_tests/index_graph_tools.hpp +++ b/routing/routing_tests/index_graph_tools.hpp @@ -6,6 +6,7 @@ #include "routing/index_graph_starter.hpp" #include "routing/num_mwm_id.hpp" #include "routing/restrictions_serialization.hpp" +#include "routing/road_access.hpp" #include "routing/road_point.hpp" #include "routing/segment.hpp" @@ -127,6 +128,9 @@ public: // and the graph itself is built only after a call to FindPath. void AddDirectedEdge(Vertex from, Vertex to, double weight); + // Blocks a previously added edge without removing it from the graph. + void BlockEdge(Vertex from, Vertex to); + // Finds a path between the start and finish vertices. Returns true iff a path exists. bool FindPath(Vertex start, Vertex finish, double & pathWeight, vector & pathEdges) const; @@ -137,6 +141,7 @@ private: Vertex m_from = 0; Vertex m_to = 0; double m_weight = 0.0; + bool m_isBlocked = false; EdgeRequest(uint32_t id, Vertex from, Vertex to, double weight) : m_id(id), m_from(from), m_to(to), m_weight(weight) @@ -160,6 +165,7 @@ private: map> m_outgoingSegments; map> m_ingoingSegments; vector m_joints; + RoadAccess m_roadAccess; }; void AddDirectedEdge(vector & edgeRequests, Vertex from, Vertex to, @@ -202,4 +208,14 @@ void TestRestrictions(vector const & expectedRouteGeom, routing::IndexGraphStarter::FakeVertex const & start, routing::IndexGraphStarter::FakeVertex const & finish, RestrictionVec && restrictions, RestrictionTest & restrictionTest); + +// Tries to find a unique path from |from| to |to| in |graph|. +// If |expectedPathFound| is true, |expectedWeight| and |expectedEdges| must +// specify the weight and edges of the unique shortest path. +// If |expectedPathFound| is false, |expectedWeight| and |expectedEdges| may +// take arbitrary values. +void TestTopologyGraph(TestIndexGraphTopology const & graph, TestIndexGraphTopology::Vertex from, + TestIndexGraphTopology::Vertex to, bool expectedPathFound, + double const expectedWeight, + vector const & expectedEdges); } // namespace routing_test diff --git a/routing/routing_tests/road_access_test.cpp b/routing/routing_tests/road_access_test.cpp index fecf63cd79..6089a045e9 100644 --- a/routing/routing_tests/road_access_test.cpp +++ b/routing/routing_tests/road_access_test.cpp @@ -16,6 +16,8 @@ using namespace routing; using namespace routing_test; using namespace std; +using Edge = TestIndexGraphTopology::Edge; + namespace { UNIT_TEST(RoadAccess_Serialization) @@ -69,4 +71,52 @@ UNIT_TEST(RoadAccess_Serialization) TEST_EQUAL(roadAccessPedestrian, deserializedRoadAccess, ()); } } + +UNIT_TEST(RoadAccess_WayBlocked) +{ + // Add edges to the graph in the following format: (from, to, weight). + // Block edges in the following format: (from, to). + + uint32_t const numVertices = 4; + TestIndexGraphTopology graph(numVertices); + + graph.AddDirectedEdge(0, 1, 1.0); + graph.AddDirectedEdge(1, 2, 1.0); + graph.AddDirectedEdge(2, 3, 1.0); + + double const expectedWeight = 0.0; + vector const expectedEdges = {}; + + graph.BlockEdge(1, 2); + + TestTopologyGraph(graph, 0, 3, false /* pathFound */, expectedWeight, expectedEdges); +} + +UNIT_TEST(RoadAccess_BarrierBypassing) +{ + uint32_t const numVertices = 6; + TestIndexGraphTopology graph(numVertices); + + graph.AddDirectedEdge(0, 1, 1.0); + graph.AddDirectedEdge(1, 2, 1.0); + graph.AddDirectedEdge(2, 5, 1.0); + graph.AddDirectedEdge(0, 3, 1.0); + graph.AddDirectedEdge(3, 4, 2.0); + graph.AddDirectedEdge(4, 5, 1.0); + + double expectedWeight; + vector expectedEdges; + + expectedWeight = 3.0; + expectedEdges = {{0, 1}, {1, 2}, {2, 5}}; + TestTopologyGraph(graph, 0, 5, true /* pathFound */, expectedWeight, expectedEdges); + + graph.BlockEdge(1, 2); + expectedWeight = 4.0; + expectedEdges = {{0, 3}, {3, 4}, {4, 5}}; + TestTopologyGraph(graph, 0, 5, true /* pathFound */, expectedWeight, expectedEdges); + + graph.BlockEdge(3, 4); + TestTopologyGraph(graph, 0, 5, false /* pathFound */, expectedWeight, expectedEdges); +} } // namespace