From e0bbd3afc92f191bcc901d7afb9072276cb07150 Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Thu, 19 Jan 2017 15:02:17 +0300 Subject: [PATCH] Converting restrictions to type No when they are loaded. --- .../generator_tests/restriction_test.cpp | 28 ++++++- routing/geometry.hpp | 2 + routing/index_graph.cpp | 52 +------------ routing/index_graph.hpp | 12 +++ routing/restriction_loader.cpp | 76 ++++++++++++++++++- routing/restriction_loader.hpp | 6 +- routing/restrictions_serialization.hpp | 8 +- routing/road_index.hpp | 15 +++- routing/routing_tests/restriction_test.cpp | 44 +++++++---- routing/single_mwm_router.cpp | 6 +- 10 files changed, 171 insertions(+), 78 deletions(-) diff --git a/generator/generator_tests/restriction_test.cpp b/generator/generator_tests/restriction_test.cpp index 34b3f7fabf..45dd0da2c4 100644 --- a/generator/generator_tests/restriction_test.cpp +++ b/generator/generator_tests/restriction_test.cpp @@ -45,6 +45,28 @@ void BuildEmptyMwm(LocalCountryFile & country) generator::tests_support::TestMwmBuilder builder(country, feature::DataHeader::country); } +void LoadRestrictions(MwmValue const & mwmValue, RestrictionVec & restrictions) +{ + if (!mwmValue.m_cont.IsExist(RESTRICTIONS_FILE_TAG)) + return; + + try + { + FilesContainerR::TReader const reader = mwmValue.m_cont.GetReader(RESTRICTIONS_FILE_TAG); + ReaderSource src(reader); + RestrictionHeader header; + header.Deserialize(src); + + RestrictionVec restrictionsOnly; + RestrictionSerializer::Deserialize(header, restrictions /* restriction no */, restrictionsOnly, src); + restrictions.insert(restrictions.end(), restrictionsOnly.cbegin(), restrictionsOnly.cend()); + } + catch (Reader::OpenException const & e) + { + LOG(LERROR, ("Error while reading", RESTRICTIONS_FILE_TAG, "section.", e.Msg())); + } +} + /// \brief Generates a restriction section, adds it to an empty mwm, /// loads the restriction section and test loaded restrictions. /// \param restrictionContent comma separated text with restrictions in osm id terms. @@ -83,10 +105,12 @@ void TestRestrictionBuilding(string const & restrictionContent, string const & m MwmSet::MwmHandle mwmHandle = index.GetMwmHandleById(regResult.first); TEST(mwmHandle.IsAlive(), ()); - RestrictionLoader restrictionLoader(*mwmHandle.GetValue()); + + RestrictionVec restrictionsFromMwm; + LoadRestrictions(*mwmHandle.GetValue(), restrictionsFromMwm); RestrictionCollector const restrictionCollector(restrictionFullPath, mappingFullPath); - TEST_EQUAL(restrictionLoader.StealRestrictions(), restrictionCollector.GetRestrictions(), ()); + TEST_EQUAL(restrictionsFromMwm, restrictionCollector.GetRestrictions(), ()); } UNIT_TEST(RestrictionGenerationTest_NoRestriction) diff --git a/routing/geometry.hpp b/routing/geometry.hpp index c172f4cf88..1c9e7b8821 100644 --- a/routing/geometry.hpp +++ b/routing/geometry.hpp @@ -74,6 +74,8 @@ public: return GetRoad(rp.GetFeatureId()).GetPoint(rp.GetPointId()); } + bool IsValid() const { return m_loader.operator bool(); } + private: // Feature id to RoadGeometry map. unordered_map m_roads; diff --git a/routing/index_graph.cpp b/routing/index_graph.cpp index f1aaaf6ded..2a2a51aeed 100644 --- a/routing/index_graph.cpp +++ b/routing/index_graph.cpp @@ -13,8 +13,7 @@ namespace using namespace routing; using namespace std; -bool IsRestricted(RestrictionVec const & restrictions, vector const & edges, - Segment const & u, Segment const & v, bool isOutgoing) +bool IsRestricted(RestrictionVec const & restrictions, Segment const & u, Segment const & v, bool isOutgoing) { uint32_t const featureIdFrom = isOutgoing ? u.GetFeatureId() : v.GetFeatureId(); uint32_t const featureIdTo = isOutgoing ? v.GetFeatureId() : u.GetFeatureId(); @@ -34,53 +33,6 @@ bool IsRestricted(RestrictionVec const & restrictions, vector const return u.GetSegmentIdx() == v.GetSegmentIdx() && u.IsForward() != v.IsForward(); } - // Taking into account that number of restrictions of type Only starting and - // ending with the same feature id is relevantly small it's possible to ignore such cases. - if (featureIdFrom == featureIdTo) - return false; - - // Looking for a range of restrictins of type Only starting from |featureIdFrom| - // and finishing with any feature. - auto const range = equal_range(restrictions.cbegin(), restrictions.cend(), - Restriction(Restriction::Type::Only, {featureIdFrom}), - [](Restriction const & r1, Restriction const & r2) { - CHECK(!r1.m_featureIds.empty(), ()); - CHECK(!r2.m_featureIds.empty(), ()); - if (r1.m_type != r2.m_type) - return r1.m_type < r2.m_type; - return r1.m_featureIds[0] < r2.m_featureIds[0]; - }); - auto const lower = range.first; - auto const upper = range.second; - - // Checking if there's restriction of type Only starting from |featureIdFrom|. If not returns false. - if (lower == upper) - return false; - - // Note. The loop is necessary because it's possible that there's several restriction - // of type Only starting from |featureIdFrom|. - for (auto i = lower; i != upper; ++i) - { - CHECK_EQUAL(i->m_featureIds.size(), 2, ("Only two link restrictions are support.")); - - // Checking if there's a restriction of type Only starting from |featureIdFrom| and - // ending with |featureIdTo|. If yes, returns false. - if (i->m_featureIds[isOutgoing ? 1 /* to */ : 0 /* from */] == (isOutgoing ? featureIdTo : featureIdFrom)) - return false; - - // Note. At this point it's clear that there is an item in |restrictions| with type Only - // and starting with |featureIdFrom|. So there are two possibilities: - // * |edges| contains |it->m_featureIds[1]| => the end of |featureIdFrom| which implies in - // |restrictions| is considered. - // * |edges| does not contain |it->m_featureIds[1]| => either the other end or an intermediate - // point of |featureIdFrom| is considered. - // See test FGraph_RestrictionF0F2Only for details. - for (SegmentEdge const & e : edges) - { - if (e.GetTarget().GetFeatureId() == i->m_featureIds[isOutgoing ? 1 /* to */ : 0 /* from */]) - return true; - } - } return false; } @@ -121,7 +73,7 @@ void IndexGraph::GetEdgeList(Segment const & segment, bool isOutgoing, vector void ForEachRoad(F && f) const { m_roadIndex.ForEachRoad(forward(f)); } + template + void ForEachPoint(Joint::Id jointId, F && f) const + { + m_jointIndex.ForEachPoint(jointId, forward(f)); + } + private: double CalcSegmentWeight(Segment const & segment); void GetNeighboringEdges(Segment const & from, RoadPoint const & rp, bool isOutgoing, diff --git a/routing/restriction_loader.cpp b/routing/restriction_loader.cpp index d2208e87eb..481fa5fb1d 100644 --- a/routing/restriction_loader.cpp +++ b/routing/restriction_loader.cpp @@ -1,9 +1,45 @@ #include "routing/restriction_loader.hpp" #include "routing/restrictions_serialization.hpp" +#include "routing/road_index.hpp" + +#include "base/stl_helpers.hpp" + +namespace +{ +using namespace routing; + +/// \returns if features |r1| and |r2| have a common end returns its joint id. +/// If not, returnfs Joint::kInvalidId. +/// \note It's possible that the both ends of |r1| and |r2| has common joint ids. +/// In that case returns any of them. +/// \note In general case ends of features don't have to be joints. For example all +/// loose feature ends aren't joints. But if ends of r1 and r2 are connected at this +/// point there has to be a joint. So the method is valid. +Joint::Id GetCommonEndJoint(routing::RoadJointIds const & r1, routing::RoadJointIds const & r2) +{ + auto const IsEqual = [](Joint::Id j1, Joint::Id j2) { + return j1 != Joint::kInvalidId && j1 == j2; + }; + if (IsEqual(r1.GetJointId(0 /* point id */), r2.GetLastJointId())) + return r1.GetJointId(0); + + if (IsEqual(r1.GetJointId(0 /* point id */), r2.GetJointId(0))) + return r1.GetJointId(0); + + if (IsEqual(r2.GetJointId(0 /* point id */), r1.GetLastJointId())) + return r2.GetJointId(0); + + Joint::Id const r1Last = r1.GetLastJointId(); + if (IsEqual(r1Last, r2.GetLastJointId())) + return r1Last; + + return Joint::kInvalidId; +} +} // namespace namespace routing { -RestrictionLoader::RestrictionLoader(MwmValue const & mwmValue) +RestrictionLoader::RestrictionLoader(MwmValue const & mwmValue, IndexGraph const & graph) : m_countryFileName(mwmValue.GetCountryFileName()) { if (!mwmValue.m_cont.IsExist(RESTRICTIONS_FILE_TAG)) @@ -15,7 +51,9 @@ RestrictionLoader::RestrictionLoader(MwmValue const & mwmValue) ReaderSource src(*m_reader); m_header.Deserialize(src); - RestrictionSerializer::Deserialize(m_header, m_restrictions, src); + RestrictionVec restrictionsOnly; + RestrictionSerializer::Deserialize(m_header, m_restrictions /* restriction no */, restrictionsOnly, src); + ConvertRestrictionOnlyToNo(graph, restrictionsOnly, m_restrictions); } catch (Reader::OpenException const & e) { @@ -24,4 +62,38 @@ RestrictionLoader::RestrictionLoader(MwmValue const & mwmValue) ("File", m_countryFileName, "Error while reading", RESTRICTIONS_FILE_TAG, "section.", e.Msg())); } } + +void ConvertRestrictionOnlyToNo(IndexGraph const & graph, RestrictionVec const & restrictionsOnly, + RestrictionVec & restrictionsNo) +{ + if (!graph.IsValid()) + { + LOG(LWARNING, ("Index graph is not valid. All the restrictions of type Only aren't used.")); + return; + } + + for (Restriction const & o : restrictionsOnly) + { + CHECK_EQUAL(o.m_featureIds.size(), 2, ("Only two link restrictions are support.")); + if (!graph.IsRoad(o.m_featureIds[0]) || !graph.IsRoad(o.m_featureIds[1])) + continue; + + // Looking for a joint of an intersection of |o| features. + Joint::Id const common = + GetCommonEndJoint(graph.GetRoad(o.m_featureIds[0]), graph.GetRoad(o.m_featureIds[1])); + if (common == Joint::kInvalidId) + continue; + + // Adding restriction of type No for all features of joint |common| except for + // the second feature of restriction |o|. + graph.ForEachPoint(common, [&] (RoadPoint const & rp){ + if (rp.GetFeatureId() != o.m_featureIds[1 /* to */]) + { + restrictionsNo.push_back( + Restriction(Restriction::Type::No, {o.m_featureIds[0 /* from */], rp.GetFeatureId()})); + } + }); + } + my::SortUnique(restrictionsNo); +} } // namespace routing diff --git a/routing/restriction_loader.hpp b/routing/restriction_loader.hpp index bae5c07aba..5074a743cb 100644 --- a/routing/restriction_loader.hpp +++ b/routing/restriction_loader.hpp @@ -1,5 +1,6 @@ #pragma once +#include "routing/index_graph.hpp" #include "routing/restrictions_serialization.hpp" #include "indexer/index.hpp" @@ -14,7 +15,7 @@ namespace routing class RestrictionLoader { public: - explicit RestrictionLoader(MwmValue const & mwmValue); + explicit RestrictionLoader(MwmValue const & mwmValue, IndexGraph const & graph); bool HasRestrictions() const { return !m_restrictions.empty(); } RestrictionVec && StealRestrictions() { return move(m_restrictions); } @@ -25,4 +26,7 @@ private: RestrictionVec m_restrictions; string const m_countryFileName; }; + +void ConvertRestrictionOnlyToNo(IndexGraph const & graph, RestrictionVec const & restrictionsOnly, + RestrictionVec & restrictionsNo); } // namespace routing diff --git a/routing/restrictions_serialization.hpp b/routing/restrictions_serialization.hpp index dbba6417bc..43d9a24f49 100644 --- a/routing/restrictions_serialization.hpp +++ b/routing/restrictions_serialization.hpp @@ -105,13 +105,13 @@ public: } template - static void Deserialize(RestrictionHeader const & header, routing::RestrictionVec & restrictions, - Source & src) + static void Deserialize(RestrictionHeader const & header, routing::RestrictionVec & restrictionsNo, + routing::RestrictionVec & restrictionsOnly, Source & src) { - DeserializeSingleType(routing::Restriction::Type::No, header.m_noRestrictionCount, restrictions, + DeserializeSingleType(routing::Restriction::Type::No, header.m_noRestrictionCount, restrictionsNo, src); DeserializeSingleType(routing::Restriction::Type::Only, header.m_onlyRestrictionCount, - restrictions, src); + restrictionsOnly, src); } private: diff --git a/routing/road_index.hpp b/routing/road_index.hpp index ada8b054ce..e614fac36b 100644 --- a/routing/road_index.hpp +++ b/routing/road_index.hpp @@ -29,6 +29,17 @@ public: return Joint::kInvalidId; } + Joint::Id GetLastJointId() const + { + Joint::Id lastJointId = Joint::kInvalidId; + for (Joint::Id const jointId : m_jointIds) + { + if (jointId != Joint::kInvalidId) + lastJointId = jointId; + } + return lastJointId; + } + void AddJoint(uint32_t pointId, Joint::Id jointId) { ASSERT_NOT_EQUAL(jointId, Joint::kInvalidId, ()); @@ -113,10 +124,12 @@ public: m_roads[rp.GetFeatureId()].AddJoint(rp.GetPointId(), jointId); } + bool IsRoad(uint32_t featureId) const { return m_roads.count(featureId) != 0; } + RoadJointIds const & GetRoad(uint32_t featureId) const { auto const & it = m_roads.find(featureId); - CHECK(it != m_roads.cend(), ()); + CHECK(it != m_roads.cend(), ("Feture id:", featureId)); return it->second; } diff --git a/routing/routing_tests/restriction_test.cpp b/routing/routing_tests/restriction_test.cpp index 0f38395103..f29089e7ba 100644 --- a/routing/routing_tests/restriction_test.cpp +++ b/routing/routing_tests/restriction_test.cpp @@ -4,6 +4,7 @@ #include "routing/car_model.hpp" #include "routing/geometry.hpp" +#include "routing/restriction_loader.hpp" #include "indexer/classificator_loader.hpp" @@ -187,15 +188,17 @@ UNIT_CLASS_TEST(RestrictionTest, TriangularGraph_RestrictionNoF5F2) UNIT_CLASS_TEST(RestrictionTest, TriangularGraph_RestrictionOnlyF5F3) { Init(BuildTriangularGraph()); - RestrictionVec restrictions = { + RestrictionVec restrictionsOnly = { {Restriction::Type::Only, {5 /* feature from */, 3 /* feature to */}}}; + RestrictionVec restrictionsNo; + ConvertRestrictionOnlyToNo(*m_graph, restrictionsOnly, restrictionsNo); vector const expectedGeom = { {3 /* x */, 0 /* y */}, {2, 0}, {1, 0}, {0, 0}, {0, 2}, {0, 3}}; TestRestrictions(expectedGeom, AStarAlgorithm::Result::OK, routing::IndexGraphStarter::FakeVertex(5, 0, m2::PointD(3, 0)) /* start */, routing::IndexGraphStarter::FakeVertex(4, 0, m2::PointD(0, 3)) /* finish */, - move(restrictions), *this); + move(restrictionsNo), *this); } UNIT_CLASS_TEST(RestrictionTest, TriangularGraph_RestrictionNoF5F2RestrictionOnlyF5F3) @@ -286,15 +289,17 @@ UNIT_CLASS_TEST(RestrictionTest, TwowayCornerGraph_RestrictionF3F2No) UNIT_CLASS_TEST(RestrictionTest, TwowayCornerGraph_RestrictionF3F1Only) { Init(BuildTwowayCornerGraph()); - RestrictionVec restrictions = { + RestrictionVec restrictionsOnly = { {Restriction::Type::Only, {3 /* feature from */, 1 /* feature to */}}}; + RestrictionVec restrictionsNo; + ConvertRestrictionOnlyToNo(*m_graph, restrictionsOnly, restrictionsNo); vector const expectedGeom = { {3 /* x */, 0 /* y */}, {2, 0}, {1, 0}, {0, 0}, {0, 1}, {0, 2}, {0, 3}}; TestRestrictions(expectedGeom, AStarAlgorithm::Result::OK, routing::IndexGraphStarter::FakeVertex(3, 0, m2::PointD(3, 0)) /* start */, routing::IndexGraphStarter::FakeVertex(4, 0, m2::PointD(0, 3)) /* finish */, - move(restrictions), *this); + move(restrictionsNo), *this); } // Finish @@ -377,8 +382,10 @@ UNIT_CLASS_TEST(RestrictionTest, TwoSquaresGraph) UNIT_CLASS_TEST(RestrictionTest, TwoSquaresGraph_RestrictionF10F3Only) { Init(BuildTwoSquaresGraph()); - RestrictionVec restrictions = { + RestrictionVec restrictionsOnly = { {Restriction::Type::Only, {10 /* feature from */, 3 /* feature to */}}}; + RestrictionVec restrictionsNo; + ConvertRestrictionOnlyToNo(*m_graph, restrictionsOnly, restrictionsNo); vector const expectedGeom = { {3 /* x */, 0 /* y */}, {2, 0}, {1, 0}, {1, 1}, {0, 2}, {0, 3}}; @@ -386,15 +393,17 @@ UNIT_CLASS_TEST(RestrictionTest, TwoSquaresGraph_RestrictionF10F3Only) TestRestrictions(expectedGeom, AStarAlgorithm::Result::OK, routing::IndexGraphStarter::FakeVertex(10, 0, m2::PointD(3, 0)) /* start */, routing::IndexGraphStarter::FakeVertex(11, 0, m2::PointD(0, 3)) /* finish */, - move(restrictions), *this); + move(restrictionsNo), *this); } UNIT_CLASS_TEST(RestrictionTest, TwoSquaresGraph_RestrictionF10F3OnlyF3F4Only) { Init(BuildTwoSquaresGraph()); - RestrictionVec restrictions = { + RestrictionVec restrictionsOnly = { {Restriction::Type::Only, {3 /* feature from */, 4 /* feature to */}}, {Restriction::Type::Only, {10 /* feature from */, 3 /* feature to */}}}; + RestrictionVec restrictionsNo; + ConvertRestrictionOnlyToNo(*m_graph, restrictionsOnly, restrictionsNo); vector const expectedGeom = { {3 /* x */, 0 /* y */}, {2, 0}, {1, 0}, {0, 0}, {0, 2}, {0, 3}}; @@ -402,23 +411,25 @@ UNIT_CLASS_TEST(RestrictionTest, TwoSquaresGraph_RestrictionF10F3OnlyF3F4Only) TestRestrictions(expectedGeom, AStarAlgorithm::Result::OK, routing::IndexGraphStarter::FakeVertex(10, 0, m2::PointD(3, 0)) /* start */, routing::IndexGraphStarter::FakeVertex(11, 0, m2::PointD(0, 3)) /* finish */, - move(restrictions), *this); + move(restrictionsNo), *this); } UNIT_CLASS_TEST(RestrictionTest, TwoSquaresGraph_RestrictionF2F8NoRestrictionF9F1Only) { Init(BuildTwoSquaresGraph()); - RestrictionVec restrictions = { - {Restriction::Type::No, {2 /* feature from */, 8 /* feature to */}}, - {Restriction::Type::Only, {9 /* feature from */, 1 /* feature to */}}}; + RestrictionVec restrictionsNo = { + {Restriction::Type::No, {2 /* feature from */, 8 /* feature to */}}}; // Invalid restriction. + RestrictionVec const restrictionsOnly = { + {Restriction::Type::Only, {9 /* feature from */, 1 /* feature to */}}}; // Invalid restriction. + ConvertRestrictionOnlyToNo(*m_graph, restrictionsOnly, restrictionsNo); vector const expectedGeom = { - {3 /* x */, 0 /* y */}, {2, 0}, {1, 1}, {1, 2}, {0, 2}, {0, 3}}; + {3 /* x */, 0 /* y */}, {2, 0}, {1, 1}, {0, 2}, {0, 3}}; TestRestrictions(expectedGeom, AStarAlgorithm::Result::OK, routing::IndexGraphStarter::FakeVertex(10, 0, m2::PointD(3, 0)) /* start */, routing::IndexGraphStarter::FakeVertex(11, 0, m2::PointD(0, 3)) /* finish */, - move(restrictions), *this); + move(restrictionsNo), *this); } // 2 * @@ -600,14 +611,17 @@ UNIT_CLASS_TEST(RestrictionTest, PosterGraph_RestrictionF0F1Only) { Init(BuildPosterGraph()); - RestrictionVec restrictions = { + RestrictionVec restrictionsOnly = { {Restriction::Type::Only, {0 /* feature from */, 1 /* feature to */}}}; + RestrictionVec restrictionsNo; + ConvertRestrictionOnlyToNo(*m_graph, restrictionsOnly, restrictionsNo); + vector const expectedGeom = { {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(0, 0, m2::PointD(2, 0)), /* start */ routing::IndexGraphStarter::FakeVertex(6, 0, m2::PointD(2, 1)), /* finish */ - move(restrictions), *this); + move(restrictionsNo), *this); } // 1 *--F1-->* diff --git a/routing/single_mwm_router.cpp b/routing/single_mwm_router.cpp index 190a5bcfce..93365a5316 100644 --- a/routing/single_mwm_router.cpp +++ b/routing/single_mwm_router.cpp @@ -191,7 +191,7 @@ bool SingleMwmRouter::LoadIndex(MwmSet::MwmId const & mwmId, string const & coun FilesContainerR::TReader reader(mwmValue->m_cont.GetReader(ROUTING_FILE_TAG)); ReaderSource src(reader); IndexGraphSerializer::Deserialize(graph, src, kCarMask); - RestrictionLoader restrictionLoader(*mwmValue); + RestrictionLoader restrictionLoader(*mwmValue, graph); if (restrictionLoader.HasRestrictions()) graph.SetRestrictions(restrictionLoader.StealRestrictions()); @@ -208,8 +208,8 @@ bool SingleMwmRouter::LoadIndex(MwmSet::MwmId const & mwmId, string const & coun } bool SingleMwmRouter::RedressRoute(MwmSet::MwmId const & mwmId, IVehicleModel const & vehicleModel, - vector const & segments, RouterDelegate const & delegate, - IndexGraphStarter & starter, Route & route) const + vector const & segments, RouterDelegate const & delegate, + IndexGraphStarter & starter, Route & route) const { vector junctions; size_t const numPoints = IndexGraphStarter::GetRouteNumPoints(segments);