From 81ed08055f4d20ee7540d60892fd7c9d2c2c681b Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Wed, 11 Jan 2017 16:16:29 +0300 Subject: [PATCH 1/8] Implementing restrictions and uturns graph where vertixs are edges and tests on it. --- .../restriction_collector_test.cpp | 2 +- .../generator_tests/restriction_test.cpp | 4 +- generator/restriction_collector.hpp | 2 +- generator/restriction_generator.cpp | 4 +- generator/restriction_writer.cpp | 2 +- routing/edge_estimator.cpp | 9 + routing/edge_estimator.hpp | 1 + routing/index_graph.cpp | 119 ++- routing/index_graph.hpp | 6 + routing/index_graph_starter.cpp | 10 + routing/index_graph_starter.hpp | 12 +- routing/restriction_loader.cpp | 2 +- routing/restriction_loader.hpp | 7 +- ...ion.cpp => restrictions_serialization.cpp} | 7 +- ...ion.hpp => restrictions_serialization.hpp} | 40 +- routing/routing.pro | 4 +- .../cumulative_restriction_test.cpp | 283 ++++++ routing/routing_tests/index_graph_test.cpp | 81 +- routing/routing_tests/index_graph_tools.cpp | 68 +- routing/routing_tests/index_graph_tools.hpp | 44 +- routing/routing_tests/restriction_test.cpp | 824 ++++++++++++++++++ routing/routing_tests/routing_tests.pro | 2 + routing/single_mwm_router.cpp | 5 + 23 files changed, 1470 insertions(+), 68 deletions(-) rename routing/{routing_serialization.cpp => restrictions_serialization.cpp} (86%) rename routing/{routing_serialization.hpp => restrictions_serialization.hpp} (82%) create mode 100644 routing/routing_tests/cumulative_restriction_test.cpp create mode 100644 routing/routing_tests/restriction_test.cpp diff --git a/generator/generator_tests/restriction_collector_test.cpp b/generator/generator_tests/restriction_collector_test.cpp index be561e4867..7dd9556b32 100644 --- a/generator/generator_tests/restriction_collector_test.cpp +++ b/generator/generator_tests/restriction_collector_test.cpp @@ -5,7 +5,7 @@ #include "generator/osm_id.hpp" #include "generator/restriction_collector.hpp" -#include "routing/routing_serialization.hpp" +#include "routing/restrictions_serialization.hpp" #include "platform/platform_tests_support/scoped_dir.hpp" #include "platform/platform_tests_support/scoped_file.hpp" diff --git a/generator/generator_tests/restriction_test.cpp b/generator/generator_tests/restriction_test.cpp index d0e4d2d03a..34b3f7fabf 100644 --- a/generator/generator_tests/restriction_test.cpp +++ b/generator/generator_tests/restriction_test.cpp @@ -83,10 +83,10 @@ void TestRestrictionBuilding(string const & restrictionContent, string const & m MwmSet::MwmHandle mwmHandle = index.GetMwmHandleById(regResult.first); TEST(mwmHandle.IsAlive(), ()); - RestrictionLoader const restrictionLoader(*mwmHandle.GetValue()); + RestrictionLoader restrictionLoader(*mwmHandle.GetValue()); RestrictionCollector const restrictionCollector(restrictionFullPath, mappingFullPath); - TEST_EQUAL(restrictionLoader.GetRestrictions(), restrictionCollector.GetRestrictions(), ()); + TEST_EQUAL(restrictionLoader.StealRestrictions(), restrictionCollector.GetRestrictions(), ()); } UNIT_TEST(RestrictionGenerationTest_NoRestriction) diff --git a/generator/restriction_collector.hpp b/generator/restriction_collector.hpp index 432acdc159..e9df69a428 100644 --- a/generator/restriction_collector.hpp +++ b/generator/restriction_collector.hpp @@ -1,6 +1,6 @@ #pragma once -#include "routing/routing_serialization.hpp" +#include "routing/restrictions_serialization.hpp" #include "std/functional.hpp" #include "std/limits.hpp" diff --git a/generator/restriction_generator.cpp b/generator/restriction_generator.cpp index 6613e12cd3..5ab6d9b395 100644 --- a/generator/restriction_generator.cpp +++ b/generator/restriction_generator.cpp @@ -33,9 +33,11 @@ bool BuildRoadRestrictions(string const & mwmPath, string const & restrictionPat auto const firstOnlyIt = lower_bound(restrictions.cbegin(), restrictions.cend(), Restriction(Restriction::Type::Only, {} /* links */), my::LessBy(&Restriction::m_type)); - RoutingHeader header; + + RestrictionHeader header; header.m_noRestrictionCount = base::checked_cast(distance(restrictions.cbegin(), firstOnlyIt)); header.m_onlyRestrictionCount = base::checked_cast(restrictions.size() - header.m_noRestrictionCount); + LOG(LINFO, ("Header info. There are", header.m_noRestrictionCount, "of type No restrictions and", header.m_onlyRestrictionCount, "of type Only restrictions")); diff --git a/generator/restriction_writer.cpp b/generator/restriction_writer.cpp index 604bc09e1e..97aee60ada 100644 --- a/generator/restriction_writer.cpp +++ b/generator/restriction_writer.cpp @@ -4,7 +4,7 @@ #include "generator/osm_id.hpp" #include "generator/restriction_collector.hpp" -#include "routing/routing_serialization.hpp" +#include "routing/restrictions_serialization.hpp" #include "base/logging.hpp" diff --git a/routing/edge_estimator.cpp b/routing/edge_estimator.cpp index 354b1283d1..31bbe0107a 100644 --- a/routing/edge_estimator.cpp +++ b/routing/edge_estimator.cpp @@ -43,6 +43,7 @@ public: void Finish() override; double CalcSegmentWeight(Segment const & segment, RoadGeometry const & road) const override; double CalcHeuristic(m2::PointD const & from, m2::PointD const & to) const override; + double GetUTurnPenalty() const override; private: TrafficCache const & m_trafficCache; @@ -101,6 +102,14 @@ double CarEdgeEstimator::CalcHeuristic(m2::PointD const & from, m2::PointD const { return TimeBetweenSec(from, to, m_maxSpeedMPS); } + +double CarEdgeEstimator::GetUTurnPenalty() const +{ + // Adds 2 minutes penalty for U-turn. The value is quite arbitrary + // and needs to be properly selected after a number of real-world + // experiments. + return 2 * 60; // seconds +} } // namespace namespace routing diff --git a/routing/edge_estimator.hpp b/routing/edge_estimator.hpp index 1b64e84fa0..8c4f59f1e8 100644 --- a/routing/edge_estimator.hpp +++ b/routing/edge_estimator.hpp @@ -24,6 +24,7 @@ public: virtual void Finish() = 0; virtual double CalcSegmentWeight(Segment const & segment, RoadGeometry const & road) const = 0; virtual double CalcHeuristic(m2::PointD const & from, m2::PointD const & to) const = 0; + virtual double GetUTurnPenalty() const = 0; static shared_ptr CreateForCar(IVehicleModel const & vehicleModel, traffic::TrafficCache const & trafficCache); diff --git a/routing/index_graph.cpp b/routing/index_graph.cpp index cba0dd3b56..f660d3940f 100644 --- a/routing/index_graph.cpp +++ b/routing/index_graph.cpp @@ -1,9 +1,94 @@ -#include "index_graph.hpp" +#include "routing/index_graph.hpp" + +#include "routing/restrictions_serialization.hpp" #include "base/assert.hpp" #include "base/exception.hpp" -#include "std/limits.hpp" +#include +#include + +namespace +{ +using namespace routing; +using namespace std; + +bool IsRestricted(RestrictionVec const & restrictions, vector const & edges, + 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(); + + // Looking for at least one restriction of type No from |featureIdFrom| to |featureIdTo|. + if (binary_search(restrictions.cbegin(), restrictions.cend(), + Restriction(Restriction::Type::No, {featureIdFrom, featureIdTo}))) + { + if (featureIdFrom != featureIdTo) + return true; + + // @TODO(bykoianko) According to current code if a feature id is marked as a feature with + // restrictricted U-turn it's restricted to make a U-turn on the both ends of the feature. + // Generally speaking it's wrong. In osm there's information about the end of the feature + // where the U-turn is restricted. It's necessary to pass the data to mwm and to use it here. + // Please see test LineGraph_RestrictionF1F1No for details. + 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 at least one restrictions of type Only from |featureIdFrom| and + // ending with |featureIdTo|. If yes, returns false. + if (lower != upper && lower->m_featureIds[1] == featureIdTo) + return false; + + // Checking if there's at least one Only starting from |featureIdFrom|. + // If not, returns false. + if (lower == restrictions.cend() || lower->m_type != Restriction::Type::Only || + lower->m_featureIds[0] != 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. + CHECK_EQUAL(lower->m_featureIds.size(), 2, ("Only two link restrictions are support.")); + for (SegmentEdge const & e : edges) + { + if (e.GetTarget().GetFeatureId() == lower->m_featureIds[isOutgoing ? 1 /* to */ : 0 /* from */]) + return true; + } + return false; +} + +bool IsUTurn(Segment const & u, Segment const & v) +{ + return u.GetFeatureId() == v.GetFeatureId() + && u.GetSegmentIdx() == v.GetSegmentIdx() + && u.IsForward() != v.IsForward(); +} +} // namespace namespace routing { @@ -28,6 +113,16 @@ void IndexGraph::GetEdgeList(Segment const & segment, bool isOutgoing, vector filteredEdges; + filteredEdges.reserve(edges.size()); + for (SegmentEdge const & e : edges) + { + if (!IsRestricted(m_restrictions, edges, segment, e.GetTarget(), isOutgoing)) + filteredEdges.push_back(e); + } + edges.swap(filteredEdges); } void IndexGraph::Build(uint32_t numJoints) { m_jointIndex.Build(m_roadIndex, numJoints); } @@ -39,6 +134,12 @@ void IndexGraph::Import(vector const & joints) Build(static_cast(joints.size())); } +void IndexGraph::SetRestrictions(RestrictionVec && restrictions) +{ + ASSERT(is_sorted(restrictions.cbegin(), restrictions.cend()), ()); + m_restrictions = move(restrictions); +} + double IndexGraph::CalcSegmentWeight(Segment const & segment) { return m_estimator->CalcSegmentWeight(segment, m_geometry.GetRoad(segment.GetFeatureId())); @@ -71,8 +172,7 @@ void IndexGraph::GetNeighboringEdge(Segment const & from, Segment const & to, bo vector & edges) { RoadPoint const rp = from.GetRoadPoint(isOutgoing); - if (from.GetFeatureId() == to.GetFeatureId() && from.GetSegmentIdx() == to.GetSegmentIdx() - && from.IsForward() != to.IsForward() + if (IsUTurn(from, to) && m_roadIndex.GetJointId(rp) == Joint::kInvalidId && rp.GetPointId() != 0 && rp.GetPointId() + 1 != m_geometry.GetRoad(from.GetFeatureId()).GetPointsCount()) @@ -80,7 +180,16 @@ void IndexGraph::GetNeighboringEdge(Segment const & from, Segment const & to, bo return; } - double const weight = CalcSegmentWeight(isOutgoing ? to : from); + double const weight = CalcSegmentWeight(isOutgoing ? to : from) + + GetPenalties(isOutgoing ? from : to, isOutgoing ? to : from); edges.emplace_back(to, weight); } + +double IndexGraph::GetPenalties(Segment const & u, Segment const & v) +{ + if (IsUTurn(u, v)) + return GetEstimator().GetUTurnPenalty(); + + return 0.0; +} } // namespace routing diff --git a/routing/index_graph.hpp b/routing/index_graph.hpp index e9b441dc02..36c4d87e1b 100644 --- a/routing/index_graph.hpp +++ b/routing/index_graph.hpp @@ -4,6 +4,7 @@ #include "routing/geometry.hpp" #include "routing/joint.hpp" #include "routing/joint_index.hpp" +#include "routing/restrictions_serialization.hpp" #include "routing/road_index.hpp" #include "routing/road_point.hpp" #include "routing/segment.hpp" @@ -40,6 +41,8 @@ public: void Build(uint32_t numJoints); void Import(vector const & joints); + void SetRestrictions(RestrictionVec && restrictions); + void PushFromSerializer(Joint::Id jointId, RoadPoint const & rp) { m_roadIndex.PushFromSerializer(jointId, rp); @@ -57,10 +60,13 @@ private: vector & edges); void GetNeighboringEdge(Segment const & from, Segment const & to, bool isOutgoing, vector & edges); + double GetPenalties(Segment const & u, Segment const & v); Geometry m_geometry; shared_ptr m_estimator; RoadIndex m_roadIndex; JointIndex m_jointIndex; + + RestrictionVec m_restrictions; }; } // namespace routing diff --git a/routing/index_graph_starter.cpp b/routing/index_graph_starter.cpp index 0ba068c559..58e9d63053 100644 --- a/routing/index_graph_starter.cpp +++ b/routing/index_graph_starter.cpp @@ -47,6 +47,16 @@ m2::PointD const & IndexGraphStarter::GetRoutePoint(vector const & segm return GetPoint(segments[pointIndex], true /* front */); } +void IndexGraphStarter::GetOutgoingEdgesList(TVertexType const & segment, vector & edges) +{ + GetEdgesList(segment, true /* isOutgoing */, edges); +} + +void IndexGraphStarter::GetIngoingEdgesList(TVertexType const & segment, vector & edges) +{ + GetEdgesList(segment, false /* isOutgoing */, edges); +} + void IndexGraphStarter::GetEdgesList(Segment const & segment, bool isOutgoing, vector & edges) { diff --git a/routing/index_graph_starter.hpp b/routing/index_graph_starter.hpp index 4ad31a298a..cf5d415108 100644 --- a/routing/index_graph_starter.hpp +++ b/routing/index_graph_starter.hpp @@ -52,16 +52,8 @@ public: m2::PointD const & GetRoutePoint(vector const & route, size_t pointIndex); void GetEdgesList(Segment const & segment, bool isOutgoing, vector & edges); - - void GetOutgoingEdgesList(TVertexType const & segment, vector & edges) - { - GetEdgesList(segment, true /* isOutgoing */, edges); - } - - void GetIngoingEdgesList(TVertexType const & segment, vector & edges) - { - GetEdgesList(segment, false /* isOutgoing */, edges); - } + void GetOutgoingEdgesList(TVertexType const & segment, vector & edges); + void GetIngoingEdgesList(TVertexType const & segment, vector & edges); double HeuristicCostEstimate(TVertexType const & from, TVertexType const & to) { diff --git a/routing/restriction_loader.cpp b/routing/restriction_loader.cpp index caba4ea903..d2208e87eb 100644 --- a/routing/restriction_loader.cpp +++ b/routing/restriction_loader.cpp @@ -1,5 +1,5 @@ #include "routing/restriction_loader.hpp" -#include "routing/routing_serialization.hpp" +#include "routing/restrictions_serialization.hpp" namespace routing { diff --git a/routing/restriction_loader.hpp b/routing/restriction_loader.hpp index 5cb2a8987a..6e58134225 100644 --- a/routing/restriction_loader.hpp +++ b/routing/restriction_loader.hpp @@ -1,6 +1,6 @@ #pragma once -#include "routing/routing_serialization.hpp" +#include "routing/restrictions_serialization.hpp" #include "indexer/index.hpp" @@ -17,11 +17,10 @@ public: explicit RestrictionLoader(MwmValue const & mwmValue); bool HasRestrictions() const { return !m_restrictions.empty(); } - RestrictionVec const & GetRestrictions() const { return m_restrictions; } - + RestrictionVec && StealRestrictions() { return move(m_restrictions); } private: unique_ptr m_reader; - RoutingHeader m_header; + RestrictionHeader m_header; RestrictionVec m_restrictions; string const m_countryFileName; }; diff --git a/routing/routing_serialization.cpp b/routing/restrictions_serialization.cpp similarity index 86% rename from routing/routing_serialization.cpp rename to routing/restrictions_serialization.cpp index a64aa441ad..1a72524b68 100644 --- a/routing/routing_serialization.cpp +++ b/routing/restrictions_serialization.cpp @@ -1,4 +1,4 @@ -#include "routing/routing_serialization.hpp" +#include "routing/restrictions_serialization.hpp" #include "std/sstream.hpp" @@ -15,8 +15,8 @@ uint32_t const Restriction::kInvalidFeatureId = numeric_limits::max(); bool Restriction::IsValid() const { - return !m_featureIds.empty() && find(begin(m_featureIds), end(m_featureIds), kInvalidFeatureId) - == end(m_featureIds); + return !m_featureIds.empty() && + find(begin(m_featureIds), end(m_featureIds), kInvalidFeatureId) == end(m_featureIds); } bool Restriction::operator==(Restriction const & restriction) const @@ -42,7 +42,6 @@ string ToString(Restriction::Type const & type) } string DebugPrint(Restriction::Type const & type) { return ToString(type); } - string DebugPrint(Restriction const & restriction) { ostringstream out; diff --git a/routing/routing_serialization.hpp b/routing/restrictions_serialization.hpp similarity index 82% rename from routing/routing_serialization.hpp rename to routing/restrictions_serialization.hpp index 8e1b747a7c..f0a75cb7df 100644 --- a/routing/routing_serialization.hpp +++ b/routing/restrictions_serialization.hpp @@ -37,7 +37,6 @@ struct Restriction }; Restriction(Type type, vector const & links) : m_featureIds(links), m_type(type) {} - bool IsValid() const; bool operator==(Restriction const & restriction) const; bool operator<(Restriction const & restriction) const; @@ -53,10 +52,9 @@ string ToString(Restriction::Type const & type); string DebugPrint(Restriction::Type const & type); string DebugPrint(Restriction const & restriction); -struct RoutingHeader +struct RestrictionHeader { - RoutingHeader() { Reset(); } - + RestrictionHeader() { Reset(); } template void Serialize(Sink & sink) const { @@ -89,13 +87,13 @@ struct RoutingHeader uint32_t m_onlyRestrictionCount; }; -static_assert(sizeof(RoutingHeader) == 12, "Wrong header size of routing section."); +static_assert(sizeof(RestrictionHeader) == 12, "Wrong header size of routing section."); class RestrictionSerializer { public: template - static void Serialize(RoutingHeader const & header, + static void Serialize(RestrictionHeader const & header, routing::RestrictionVec::const_iterator begin, routing::RestrictionVec::const_iterator end, Sink & sink) { @@ -105,11 +103,11 @@ public: } template - static void Deserialize(RoutingHeader const & header, routing::RestrictionVec & restrictions, + static void Deserialize(RestrictionHeader const & header, routing::RestrictionVec & restrictions, Source & src) { - DeserializeSingleType(routing::Restriction::Type::No, header.m_noRestrictionCount, - restrictions, src); + DeserializeSingleType(routing::Restriction::Type::No, header.m_noRestrictionCount, restrictions, + src); DeserializeSingleType(routing::Restriction::Type::Only, header.m_onlyRestrictionCount, restrictions, src); } @@ -139,17 +137,20 @@ private: routing::Restriction const & restriction = *begin; CHECK(restriction.IsValid(), ()); - CHECK_LESS(1, restriction.m_featureIds.size(), ("No sense in zero or one link restrictions.")); + CHECK_LESS(1, restriction.m_featureIds.size(), + ("No sense in zero or one link restrictions.")); - coding::DeltaCoder::Encode(bits, restriction.m_featureIds.size() - 1 /* number of link is two or more */); + coding::DeltaCoder::Encode( + bits, restriction.m_featureIds.size() - 1 /* number of link is two or more */); CHECK_LESS_OR_EQUAL(prevFirstLinkFeatureId, restriction.m_featureIds[0], ()); - coding::DeltaCoder::Encode(bits, - restriction.m_featureIds[0] - prevFirstLinkFeatureId + 1 /* making it greater than zero */); + coding::DeltaCoder::Encode(bits, restriction.m_featureIds[0] - prevFirstLinkFeatureId + + 1 /* making it greater than zero */); for (size_t i = 1; i < restriction.m_featureIds.size(); ++i) { - uint32_t const delta = bits::ZigZagEncode(static_cast(restriction.m_featureIds[i]) - - static_cast(restriction.m_featureIds[i - 1])); + uint32_t const delta = + bits::ZigZagEncode(static_cast(restriction.m_featureIds[i]) - + static_cast(restriction.m_featureIds[i - 1])); coding::DeltaCoder::Encode(bits, delta + 1 /* making it greater than zero */); } prevFirstLinkFeatureId = restriction.m_featureIds[0]; @@ -172,7 +173,7 @@ private: } size_t const numLinks = biasedLinkNumber + 1 /* number of link is two or more */; - routing::Restriction restriction(type, {} /* links */); + routing::Restriction restriction(type, {} /* links */); restriction.m_featureIds.resize(numLinks); auto const biasedFirstFeatureId = coding::DeltaCoder::Decode(bits); if (biasedFirstFeatureId == 0) @@ -189,9 +190,10 @@ private: LOG(LERROR, ("Decoded link restriction feature id delta is zero.")); return false; } - auto const delta = biasedDelta - 1; - restriction.m_featureIds[i] = static_cast( - bits::ZigZagDecode(delta) + restriction.m_featureIds[i - 1]); + + uint32_t const delta = biasedDelta - 1; + restriction.m_featureIds[i] = + static_cast(bits::ZigZagDecode(delta) + restriction.m_featureIds[i - 1]); } prevFirstLinkFeatureId = restriction.m_featureIds[0]; diff --git a/routing/routing.pro b/routing/routing.pro index 1635233426..44426f226b 100644 --- a/routing/routing.pro +++ b/routing/routing.pro @@ -42,6 +42,7 @@ SOURCES += \ pedestrian_directions.cpp \ pedestrian_model.cpp \ restriction_loader.cpp \ + restrictions_serialization.cpp \ road_graph.cpp \ road_graph_router.cpp \ road_index.cpp \ @@ -51,7 +52,6 @@ SOURCES += \ routing_algorithm.cpp \ routing_helpers.cpp \ routing_mapping.cpp \ - routing_serialization.cpp \ routing_session.cpp \ single_mwm_router.cpp \ speed_camera.cpp \ @@ -96,6 +96,7 @@ HEADERS += \ pedestrian_directions.hpp \ pedestrian_model.hpp \ restriction_loader.hpp \ + restrictions_serialization.hpp \ road_graph.hpp \ road_graph_router.hpp \ road_index.hpp \ @@ -109,7 +110,6 @@ HEADERS += \ routing_helpers.hpp \ routing_mapping.hpp \ routing_result_graph.hpp \ - routing_serialization.hpp \ routing_session.hpp \ routing_settings.hpp \ segment.hpp \ diff --git a/routing/routing_tests/cumulative_restriction_test.cpp b/routing/routing_tests/cumulative_restriction_test.cpp new file mode 100644 index 0000000000..ad5d4fe06b --- /dev/null +++ b/routing/routing_tests/cumulative_restriction_test.cpp @@ -0,0 +1,283 @@ +#include "testing/testing.hpp" + +#include "routing/routing_tests/index_graph_tools.hpp" + +#include "routing/car_model.hpp" +#include "routing/geometry.hpp" + +#include "traffic/traffic_cache.hpp" + +#include "geometry/point2d.hpp" + +#include +#include + +namespace +{ +using namespace routing; +using namespace routing_test; + +// Finish +// 3 * +// ^ +// F5 +// | +// 2 * * +// ↖ ↗ ↖ +// F2 F3 F4 +// ↖ ↗ ↖ +// 1 * * +// ↗ ↖ +// F0 F1 +// ↗ ↖ +// 0 * * +// 0 1 2 3 +// Start +// Note. This graph contains of 6 one segment directed features. +unique_ptr BuildXYGraph() +{ + unique_ptr loader = make_unique(); + loader->AddRoad(0 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{0.0, 0.0}, {1.0, 1.0}})); + loader->AddRoad(1 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{2.0, 0.0}, {1.0, 1.0}})); + loader->AddRoad(2 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, 1.0}, {0.0, 2.0}})); + loader->AddRoad(3 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, 1.0}, {2.0, 2.0}})); + loader->AddRoad(4 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{3.0, 1.0}, {2.0, 2.0}})); + loader->AddRoad(5 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{2.0, 2.0}, {2.0, 3.0}})); + + vector const joints = { + MakeJoint({{0 /* feature id */, 0 /* point id */}}), /* joint at point (0, 0) */ + MakeJoint({{1, 0}}), /* joint at point (2, 0) */ + MakeJoint({{0, 1}, {1, 1}, {2, 0}, {3, 0}}), /* joint at point (1, 1) */ + MakeJoint({{2, 1}}), /* joint at point (0, 2) */ + MakeJoint({{3, 1}, {4, 1}, {5, 0}}), /* joint at point (2, 2) */ + MakeJoint({{4, 0}}), /* joint at point (3, 1) */ + MakeJoint({{5, 1}}), /* joint at point (2, 3) */ + }; + + traffic::TrafficCache const trafficCache; + unique_ptr graph = + make_unique(move(loader), CreateEstimator(trafficCache)); + graph->Import(joints); + return graph; +} + +// Route through XY graph without any restrictions. +UNIT_TEST(XYGraph) +{ + unique_ptr graph = BuildXYGraph(); + IndexGraphStarter starter(*graph, + IndexGraphStarter::FakeVertex(1, 0, m2::PointD(2, 0)) /* start */, + IndexGraphStarter::FakeVertex(5, 0, m2::PointD(2, 3)) /* finish */); + vector const expectedGeom = {{2 /* x */, 0 /* y */}, {1, 1}, {2, 2}, {2, 3}}; + TestRouteGeometry(starter, AStarAlgorithm::Result::OK, expectedGeom); +} + +// Route through XY graph with one restriciton (type only) from F1 to F3. +UNIT_CLASS_TEST(RestrictionTest, XYGraph_RestrictionF1F3Only) +{ + Init(BuildXYGraph()); + RestrictionVec restrictions = { + {Restriction::Type::Only, {1 /* feature from */, 3 /* feature to */}}}; + + vector const expectedGeom = {{2 /* x */, 0 /* y */}, {1, 1}, {2, 2}, {2, 3}}; + TestRestrictions(expectedGeom, AStarAlgorithm::Result::OK, + routing::IndexGraphStarter::FakeVertex(1, 0, m2::PointD(2, 0)) /* start */, + routing::IndexGraphStarter::FakeVertex(5, 0, m2::PointD(2, 3)) /* finish */, + move(restrictions), *this); +} + +// Route through XY graph with one restriciton (type only) from F3 to F5. +UNIT_CLASS_TEST(RestrictionTest, XYGraph_RestrictionF3F5Only) +{ + Init(BuildXYGraph()); + RestrictionVec restrictions = { + {Restriction::Type::Only, {3 /* feature from */, 5 /* feature to */}}}; + + vector const expectedGeom = {{2 /* x */, 0 /* y */}, {1, 1}, {2, 2}, {2, 3}}; + TestRestrictions(expectedGeom, AStarAlgorithm::Result::OK, + routing::IndexGraphStarter::FakeVertex(1, 0, m2::PointD(2, 0)) /* start */, + routing::IndexGraphStarter::FakeVertex(5, 0, m2::PointD(2, 3)) /* finish */, + move(restrictions), *this); +} + +// Cumulative case. Route through XY graph with two restricitons (type only) applying +// in all possible orders. +UNIT_CLASS_TEST(RestrictionTest, XYGraph_PermutationsF3F5OnlyF1F3Only) +{ + Init(BuildXYGraph()); + RestrictionVec restrictions = { + {Restriction::Type::Only, {1 /* feature from */, 3 /* feature to */}}, + {Restriction::Type::Only, {3 /* feature from */, 5 /* feature to */}}}; + + vector const expectedGeom = {{2 /* x */, 0 /* y */}, {1, 1}, {2, 2}, {2, 3}}; + TestRestrictions(expectedGeom, AStarAlgorithm::Result::OK, + routing::IndexGraphStarter::FakeVertex(1, 0, m2::PointD(2, 0)) /* start */, + routing::IndexGraphStarter::FakeVertex(5, 0, m2::PointD(2, 3)) /* finish */, + move(restrictions), *this); +} + +// Cumulative case. Route through XY graph with two restricitons (type only and type no) applying +// in all possible orders. +UNIT_CLASS_TEST(RestrictionTest, XYGraph_PermutationsF3F5OnlyAndF0F2No) +{ + Init(BuildXYGraph()); + + RestrictionVec restrictions = { + {Restriction::Type::No, {1 /* feature from */, 2 /* feature to */}}, + {Restriction::Type::Only, {3 /* feature from */, 5 /* feature to */}}}; + vector const expectedGeom = {{2 /* x */, 0 /* y */}, {1, 1}, {2, 2}, {2, 3}}; + TestRestrictions(expectedGeom, AStarAlgorithm::Result::OK, + routing::IndexGraphStarter::FakeVertex(1, 0, m2::PointD(2, 0)) /* start */, + routing::IndexGraphStarter::FakeVertex(5, 0, m2::PointD(2, 3)) /* finish */, + move(restrictions), *this); +} + +// Cumulative case. Trying to build route through XY graph with two restricitons applying +// according to the order. First from F3 to F5 (type only) +// and then and from F1 to F3 (type no). +UNIT_CLASS_TEST(RestrictionTest, XYGraph_RestrictionF3F5OnlyAndF1F3No) +{ + Init(BuildXYGraph()); + RestrictionVec restrictions = { + {Restriction::Type::No, {1 /* feature from */, 3 /* feature to */}}, + {Restriction::Type::Only, {3 /* feature from */, 5 /* feature to */}}}; + + TestRestrictions({} /* expectedGeom */, AStarAlgorithm::Result::NoPath, + routing::IndexGraphStarter::FakeVertex(1, 0, m2::PointD(2, 0)) /* start */, + routing::IndexGraphStarter::FakeVertex(5, 0, m2::PointD(2, 3)) /* finish */, + move(restrictions), *this); +} + +// Finish +// 3 * * +// ↖ ↗ +// F5 F6 +// ↖ ↗ +// 2 * * +// ↖ ↗ ↖ +// F2 F3 F4 +// ↖ ↗ ↖ +// 1 * * +// ↗ ↖ ^ +// F0 F1 F8 +// ↗ ↖ | +// 0 * *--F7--->* +// ^ +// F9 +// | +//-1 * +// 0 1 2 3 +// Start +// Note. This graph contains of 9 one segment directed features. +unique_ptr BuildXXGraph() +{ + unique_ptr loader = make_unique(); + loader->AddRoad(0 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{0.0, 0.0}, {1.0, 1.0}})); + loader->AddRoad(1 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{2.0, 0.0}, {1.0, 1.0}})); + loader->AddRoad(2 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, 1.0}, {0.0, 2.0}})); + loader->AddRoad(3 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, 1.0}, {2.0, 2.0}})); + loader->AddRoad(4 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{3.0, 1.0}, {2.0, 2.0}})); + loader->AddRoad(5 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{2.0, 2.0}, {1.0, 3.0}})); + loader->AddRoad(6 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{2.0, 2.0}, {3.0, 3.0}})); + loader->AddRoad(7 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{2.0, 0.0}, {3.0, 0.0}})); + loader->AddRoad(8 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{3.0, 0.0}, {3.0, 1.0}})); + loader->AddRoad(9 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{2.0, -1.0}, {2.0, 0.0}})); + + vector const joints = { + MakeJoint({{0 /* feature id */, 0 /* point id */}}), /* joint at point (0, 0) */ + MakeJoint({{1, 0}, {7, 0}, {9, 1}}), /* joint at point (2, 0) */ + MakeJoint({{0, 1}, {1, 1}, {2, 0}, {3, 0}}), /* joint at point (1, 1) */ + MakeJoint({{2, 1}}), /* joint at point (0, 2) */ + MakeJoint({{3, 1}, {4, 1}, {5, 0}, {6, 0}}), /* joint at point (2, 2) */ + MakeJoint({{4, 0}, {8, 1}}), /* joint at point (3, 1) */ + MakeJoint({{5, 1}}), /* joint at point (1, 3) */ + MakeJoint({{6, 1}}), /* joint at point (3, 3) */ + MakeJoint({{7, 1}, {8, 0}}), /* joint at point (3, 0) */ + MakeJoint({{9, 0}}), /* joint at point (2, -1) */ + }; + + traffic::TrafficCache const trafficCache; + unique_ptr graph = + make_unique(move(loader), CreateEstimator(trafficCache)); + graph->Import(joints); + return graph; +} + +// Route through XY graph without any restrictions. +UNIT_CLASS_TEST(RestrictionTest, XXGraph) +{ + Init(BuildXXGraph()); + RestrictionVec restrictions = {}; + vector const expectedGeom = {{2 /* x */, -1 /* y */}, {2, 0}, {1, 1}, {2, 2}, {3, 3}}; + TestRestrictions(expectedGeom, AStarAlgorithm::Result::OK, + routing::IndexGraphStarter::FakeVertex(9, 0, m2::PointD(2, -1)), /* start */ + routing::IndexGraphStarter::FakeVertex(6, 0, m2::PointD(3, 3)), /* finish */ + move(restrictions), *this); +} + +// Cumulative case. Route through XX graph with two restricitons (type only) applying +// in all possible orders. +UNIT_CLASS_TEST(RestrictionTest, XXGraph_PermutationsF1F3OnlyAndF3F6Only) +{ + Init(BuildXXGraph()); + RestrictionVec restrictions = { + {Restriction::Type::Only, {1 /* feature from */, 3 /* feature to */}}, + {Restriction::Type::Only, {3 /* feature from */, 6 /* feature to */}}}; + + vector const expectedGeom = {{2 /* x */, -1 /* y */}, {2, 0}, {1, 1}, {2, 2}, {3, 3}}; + TestRestrictions(expectedGeom, AStarAlgorithm::Result::OK, + routing::IndexGraphStarter::FakeVertex(9, 0, m2::PointD(2, -1)), /* start */ + routing::IndexGraphStarter::FakeVertex(6, 0, m2::PointD(3, 3)), /* finish */ + move(restrictions), *this); +} + +// Route through XX graph with one restriciton (type no) from F1 to F3. +UNIT_CLASS_TEST(RestrictionTest, XXGraph_RestrictionF1F3No) +{ + Init(BuildXXGraph()); + RestrictionVec restrictions = { + {Restriction::Type::No, {1 /* feature from */, 3 /* feature to */}}}; + vector const expectedGeom = { + {2 /* x */, -1 /* y */}, {2, 0}, {3, 0}, {3, 1}, {2, 2}, {3, 3}}; + + TestRestrictions(expectedGeom, AStarAlgorithm::Result::OK, + routing::IndexGraphStarter::FakeVertex(9, 0, m2::PointD(2, -1)), /* start */ + routing::IndexGraphStarter::FakeVertex(6, 0, m2::PointD(3, 3)), /* finish */ + move(restrictions), *this); +} + +// Cumulative case. Route through XX graph with four restricitons of different types applying +// in all possible orders. +UNIT_CLASS_TEST(RestrictionTest, XXGraph_PermutationsF1F3NoF7F8OnlyF8F4OnlyF4F6Only) +{ + Init(BuildXXGraph()); + RestrictionVec restrictions = { + {Restriction::Type::No, {1 /* feature from */, 3 /* feature to */}}, + {Restriction::Type::Only, {4 /* feature from */, 6 /* feature to */}}, + {Restriction::Type::Only, {7 /* feature from */, 8 /* feature to */}}, + {Restriction::Type::Only, {8 /* feature from */, 4 /* feature to */}}}; + + vector const expectedGeom = { + {2 /* x */, -1 /* y */}, {2, 0}, {3, 0}, {3, 1}, {2, 2}, {3, 3}}; + TestRestrictions(expectedGeom, AStarAlgorithm::Result::OK, + routing::IndexGraphStarter::FakeVertex(9, 0, m2::PointD(2, -1)), /* start */ + routing::IndexGraphStarter::FakeVertex(6, 0, m2::PointD(3, 3)), /* finish */ + move(restrictions), *this); +} +} // namespace diff --git a/routing/routing_tests/index_graph_test.cpp b/routing/routing_tests/index_graph_test.cpp index 2e690f5219..d76872de60 100644 --- a/routing/routing_tests/index_graph_test.cpp +++ b/routing/routing_tests/index_graph_test.cpp @@ -31,12 +31,10 @@ void TestRoute(IndexGraph & graph, IndexGraphStarter::FakeVertex const & start, IndexGraphStarter::FakeVertex const & finish, size_t expectedLength, vector const * expectedRoute = nullptr) { - LOG(LINFO, ("Test route", start.GetFeatureId(), ",", start.GetSegmentIdx(), "=>", - finish.GetFeatureId(), ",", finish.GetSegmentIdx())); - IndexGraphStarter starter(graph, start, finish); vector route; - auto const resultCode = CalculateRoute(starter, route); + double timeSec; + auto const resultCode = CalculateRoute(starter, route, timeSec); TEST_EQUAL(resultCode, AStarAlgorithm::Result::OK, ()); TEST_GREATER(route.size(), 2, ()); @@ -386,4 +384,79 @@ UNIT_TEST(SerializeSimpleGraph) TEST_EQUAL(graph.GetJointId({2, 1}), Joint::kInvalidId, ()); } } + +// Finish +// 0.0004 * +// ^ +// | +// F2 +// | +// | +// 0.0003 *---------* +// | | +// | | +// | | +// | | +// | | +// 0.0002 * * +// | | +// | | +// 0.00015 * F0 * +// \ / +// \ / +// 0.0001 *---F0-*----* +// ^ +// | +// F1 +// | +// | +// 0 * Start +// 0 0.0001 0.0002 +// F0 is a two-way feature with a loop and F1 and F2 are an one-way one-segment features. +unique_ptr BuildLoopGraph() +{ + unique_ptr loader = make_unique(); + loader->AddRoad(0 /* feature id */, false /* one way */, 100.0 /* speed */, + RoadGeometry::Points({{0.0002, 0.0001}, + {0.00015, 0.0001}, + {0.0001, 0.0001}, + {0.00015, 0.00015}, + {0.00015, 0.0002}, + {0.00015, 0.0003}, + {0.00005, 0.0003}, + {0.00005, 0.0002}, + {0.00005, 0.00015}, + {0.0001, 0.0001}})); + loader->AddRoad(1 /* feature id */, true /* one way */, 100.0 /* speed */, + RoadGeometry::Points({{0.0002, 0.0}, {0.0002, 0.0001}})); + loader->AddRoad(2 /* feature id */, true /* one way */, 100.0 /* speed */, + RoadGeometry::Points({{0.00005, 0.0003}, {0.00005, 0.0004}})); + + vector const joints = { + MakeJoint({{0 /* feature id */, 2 /* point id */}, {0, 9}}), /* joint at point (0.0002, 0) */ + MakeJoint({{1, 1}, {0, 0}}), /* joint at point (0.0002, 0.0001) */ + MakeJoint({{0, 6}, {2, 0}}), /* joint at point (0.00005, 0.0003) */ + MakeJoint({{2, 1}}), /* joint at point (0.00005, 0.0004) */ + }; + + traffic::TrafficCache const trafficCache; + unique_ptr graph = + make_unique(move(loader), CreateEstimator(trafficCache)); + graph->Import(joints); + return graph; +} + +// This test checks that the route from Start to Finish doesn't make an extra loop in F0. +// If it was so the route time had been much more. +UNIT_CLASS_TEST(RestrictionTest, LoopGraph) +{ + Init(BuildLoopGraph()); + SetStarter( + routing::IndexGraphStarter::FakeVertex(1, 0 /* seg id */, m2::PointD(0.0002, 0)) /* start */, + routing::IndexGraphStarter::FakeVertex(2, 0 /* seg id */, + m2::PointD(0.00005, 0.0004)) /* finish */); + + double constexpr kExpectedRouteTimeSec = 3.48; + TestRouteTime(*m_starter, AStarAlgorithm::Result::OK, kExpectedRouteTimeSec); +} } // namespace routing_test diff --git a/routing/routing_tests/index_graph_tools.cpp b/routing/routing_tests/index_graph_tools.cpp index 3859f2c417..f8fad8ef2c 100644 --- a/routing/routing_tests/index_graph_tools.cpp +++ b/routing/routing_tests/index_graph_tools.cpp @@ -41,13 +41,16 @@ shared_ptr CreateEstimator(traffic::TrafficCache const & trafficC } AStarAlgorithm::Result CalculateRoute(IndexGraphStarter & starter, - vector & roadPoints) + vector & roadPoints, + double & timeSec) { AStarAlgorithm algorithm; RoutingResult routingResult; auto const resultCode = algorithm.FindPathBidirectional( starter, starter.GetStart(), starter.GetFinish(), routingResult, {}, {}); + timeSec = routingResult.distance; + roadPoints = routingResult.path; return resultCode; } @@ -56,12 +59,63 @@ void TestRouteGeometry(IndexGraphStarter & starter, AStarAlgorithm::Result expectedRouteResult, vector const & expectedRouteGeom) { - vector route; - auto const resultCode = CalculateRoute(starter, route); - TEST_EQUAL(resultCode, expectedRouteResult, ()); - TEST_EQUAL(IndexGraphStarter::GetRouteNumPoints(route), expectedRouteGeom.size(), ()); + vector routeSegs; + double timeSec = 0.0; + auto const resultCode = CalculateRoute(starter, routeSegs, timeSec); - for (size_t i = 0; i < IndexGraphStarter::GetRouteNumPoints(route); ++i) - TEST_EQUAL(expectedRouteGeom[i], starter.GetRoutePoint(route, i), ()); + if (AStarAlgorithm::Result::NoPath == expectedRouteResult && + expectedRouteGeom == vector()) + { + // The route goes through a restriction. So there's no choice for building route + // except for going through restriction. So no path. + return; + } + + TEST_EQUAL(resultCode, expectedRouteResult, ()); + if (resultCode != AStarAlgorithm::Result::OK) + return; + + CHECK(!routeSegs.empty(), ()); + vector geom; + + auto const pushPoint = [&geom](m2::PointD const & point) { + if (geom.empty() || geom.back() != point) + geom.push_back(point); + }; + + for (size_t i = 0; i < routeSegs.size(); ++i) + { + m2::PointD const & pnt = starter.GetPoint(routeSegs[i], false /* front */); + // Note. In case of A* router all internal points of route are duplicated. + // So it's necessary to exclude the duplicates. + pushPoint(pnt); + } + + pushPoint(starter.GetPoint(routeSegs.back(), false /* front */)); + TEST_EQUAL(geom, expectedRouteGeom, ()); +} + +void TestRouteTime(IndexGraphStarter & starter, + AStarAlgorithm::Result expectedRouteResult, + double expectedTime) +{ + vector routeSegs; + double timeSec = 0.0; + auto const resultCode = CalculateRoute(starter, routeSegs, timeSec); + + TEST_EQUAL(resultCode, expectedRouteResult, ()); + double const kEpsilon = 1e-5; + TEST(my::AlmostEqualAbs(timeSec, expectedTime, kEpsilon), ()); +} + +void TestRestrictions(vector const & expectedRouteGeom, + AStarAlgorithm::Result expectedRouteResult, + routing::IndexGraphStarter::FakeVertex const & start, + routing::IndexGraphStarter::FakeVertex const & finish, + RestrictionVec && restrictions, RestrictionTest & restrictionTest) +{ + restrictionTest.SetRestrictions(move(restrictions)); + restrictionTest.SetStarter(start, finish); + TestRouteGeometry(*restrictionTest.m_starter, expectedRouteResult, expectedRouteGeom); } } // namespace routing_test diff --git a/routing/routing_tests/index_graph_tools.hpp b/routing/routing_tests/index_graph_tools.hpp index 4c5494b1b3..e03cdc8aa6 100644 --- a/routing/routing_tests/index_graph_tools.hpp +++ b/routing/routing_tests/index_graph_tools.hpp @@ -3,6 +3,7 @@ #include "routing/edge_estimator.hpp" #include "routing/index_graph.hpp" #include "routing/index_graph_starter.hpp" +#include "routing/restrictions_serialization.hpp" #include "routing/road_point.hpp" #include "routing/segment.hpp" @@ -10,6 +11,8 @@ #include "traffic/traffic_info.hpp" +#include "indexer/classificator_loader.hpp" + #include "geometry/point2d.hpp" #include "std/algorithm.hpp" @@ -20,6 +23,27 @@ namespace routing_test { +using namespace routing; + +struct RestrictionTest +{ + RestrictionTest() { classificator::Load(); } + void Init(unique_ptr graph) { m_graph = move(graph); } + void SetStarter(IndexGraphStarter::FakeVertex const & start, + IndexGraphStarter::FakeVertex const & finish) + { + m_starter = make_unique(*m_graph, start, finish); + } + + void SetRestrictions(RestrictionVec && restrictions) + { + m_graph->SetRestrictions(move(restrictions)); + } + + unique_ptr m_graph; + unique_ptr m_starter; +}; + class TestGeometryLoader final : public routing::GeometryLoader { public: @@ -38,15 +62,23 @@ routing::Joint MakeJoint(vector const & points); shared_ptr CreateEstimator(traffic::TrafficCache const & trafficCache); routing::AStarAlgorithm::Result CalculateRoute( - routing::IndexGraphStarter & starter, vector & roadPoints); - -void TestRouteSegments( - routing::IndexGraphStarter & starter, - routing::AStarAlgorithm::Result expectedRouteResult, - vector const & expectedRoute); + routing::IndexGraphStarter & starter, vector & roadPoints, double & timeSec); void TestRouteGeometry( routing::IndexGraphStarter & starter, routing::AStarAlgorithm::Result expectedRouteResult, vector const & expectedRouteGeom); + +void TestRouteTime(IndexGraphStarter & starter, + AStarAlgorithm::Result expectedRouteResult, + double expectedTime); + +/// \brief Applies |restrictions| to graph in |restrictionTest| and +/// tests the resulting route. +/// \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, + RestrictionVec && restrictions, RestrictionTest & restrictionTest); } // namespace routing_test diff --git a/routing/routing_tests/restriction_test.cpp b/routing/routing_tests/restriction_test.cpp new file mode 100644 index 0000000000..0f38395103 --- /dev/null +++ b/routing/routing_tests/restriction_test.cpp @@ -0,0 +1,824 @@ +#include "testing/testing.hpp" + +#include "routing/routing_tests/index_graph_tools.hpp" + +#include "routing/car_model.hpp" +#include "routing/geometry.hpp" + +#include "indexer/classificator_loader.hpp" + +#include "geometry/point2d.hpp" + +#include +#include + +namespace routing_test +{ +using namespace routing; + +// Finish +// * +// ^ +// | +// F7 +// | +// * +// ^ +// | +// F6 +// | +// Start * -- F0 --> * -- F1 --> * <-- F2 --> * -- F3 --> * +// | ^ +// | | +// F4 F5 +// | | +// ⌄ | +// * +unique_ptr BuildCrossGraph() +{ + unique_ptr loader = make_unique(); + loader->AddRoad(0 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{-1.0, 0.0}, {0.0, 0.0}})); + loader->AddRoad(1 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{0.0, 0.0}, {1.0, 0.0}})); + loader->AddRoad(2 /* featureId */, false /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, 0.0}, {1.9999, 0.0}})); + loader->AddRoad(3 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{1.9999, 0.0}, {3.0, 0.0}})); + loader->AddRoad(4 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, 0.0}, {1.0, -1.0}})); + loader->AddRoad(5 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, -1.0}, {1.0, 0.0}})); + loader->AddRoad(6 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, 0.0}, {1.0, 1.0}})); + loader->AddRoad(7 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, 1.0}, {1.0, 2.0}})); + + vector const joints = { + MakeJoint({{0, 1}, {1, 0}}), MakeJoint({{1, 1}, {2, 0}, {4, 0}, {5, 1}, {6, 0}}), + MakeJoint({{2, 1}, {3, 0}}), MakeJoint({{4, 1}, {5, 0}}), MakeJoint({{6, 1}, {7, 0}})}; + + traffic::TrafficCache const trafficCache; + unique_ptr graph = + make_unique(move(loader), CreateEstimator(trafficCache)); + graph->Import(joints); + return graph; +} + +UNIT_CLASS_TEST(RestrictionTest, CrossGraph_NoUTurn) +{ + Init(BuildCrossGraph()); + SetStarter(routing::IndexGraphStarter::FakeVertex(0, 0, m2::PointD(-1, 0)) /* start */, + routing::IndexGraphStarter::FakeVertex(7, 0, m2::PointD(1, 2)) /* finish */); + + 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}}; + TestRouteGeometry(*m_starter, AStarAlgorithm::Result::OK, expectedGeom); +} + +UNIT_CLASS_TEST(RestrictionTest, CrossGraph_UTurn) +{ + Init(BuildCrossGraph()); + SetStarter(routing::IndexGraphStarter::FakeVertex(0, 0, m2::PointD(-1, 0)) /* start */, + routing::IndexGraphStarter::FakeVertex(7, 0, m2::PointD(1, 2)) /* finish */); + + RestrictionVec restrictions = { + {Restriction::Type::No, {1 /* feature from */, 6 /* feature to */}}}; + vector const expectedGeom = {{-1.0, 0.0}, {0.0, 0.0}, {1.0, 0.0}, {1.0, -1.0}, + {1.0, 0.0}, {1.0, 1.0}, {1.0, 2.0}}; + + TestRestrictions(expectedGeom, AStarAlgorithm::Result::OK, + routing::IndexGraphStarter::FakeVertex(0, 0, m2::PointD(-1, 0)), /* start */ + routing::IndexGraphStarter::FakeVertex(7, 0, m2::PointD(1, 2)), /* finish */ + move(restrictions), *this); +} + +// Finish +// 3 * +// ^ +// | +// F4 +// | +// 2 * +// ^ ↖ +// | F1 +// | ↖ +// 1 | * +// F0 ↖ +// | F2 +// | ↖ +// 0 *<--F3---<--F3---*<--F5--* Start +// 0 1 2 3 +// Note. F0, F1 and F2 are one segment features. F3 is a two segments feature. +unique_ptr BuildTriangularGraph() +{ + unique_ptr loader = make_unique(); + loader->AddRoad(0 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{0.0, 0.0}, {0.0, 2.0}})); + loader->AddRoad(1 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, 1.0}, {0.0, 2.0}})); + loader->AddRoad(2 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{2.0, 0.0}, {1.0, 1.0}})); + loader->AddRoad(3 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{2.0, 0.0}, {1.0, 0.0}, {0.0, 0.0}})); + loader->AddRoad(4 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{0.0, 2.0}, {0.0, 3.0}})); + loader->AddRoad(5 /* featureId */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{3.0, 0.0}, {2.0, 0.0}})); + + vector const joints = { + MakeJoint({{2, 0}, {3, 0}, {5, 1}}), /* joint at point (2, 0) */ + MakeJoint({{3, 2}, {0, 0}}), /* joint at point (0, 0) */ + MakeJoint({{2, 1}, {1, 0}}), /* joint at point (1, 1) */ + MakeJoint({{0, 1}, {1, 1}, {4, 0}}), /* joint at point (0, 2) */ + MakeJoint({{5, 0}}), /* joint at point (3, 0) */ + MakeJoint({{4, 1}}) /* joint at point (0, 3) */ + }; + + traffic::TrafficCache const trafficCache; + unique_ptr graph = + make_unique(move(loader), CreateEstimator(trafficCache)); + graph->Import(joints); + return graph; +} + +// Route through triangular graph without any restrictions. +UNIT_CLASS_TEST(RestrictionTest, TriangularGraph) +{ + Init(BuildTriangularGraph()); + + vector const expectedGeom = {{3 /* x */, 0 /* y */}, {2, 0}, {1, 1}, {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 */, {}, + *this); +} + +// Route through triangular graph with restriction type no from feature 2 to feature 1. +UNIT_CLASS_TEST(RestrictionTest, TriangularGraph_RestrictionNoF2F1) +{ + Init(BuildTriangularGraph()); + RestrictionVec restrictions = { + {Restriction::Type::No, {2 /* feature from */, 1 /* feature to */}}}; + 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); +} + +UNIT_CLASS_TEST(RestrictionTest, TriangularGraph_RestrictionNoF5F2) +{ + Init(BuildTriangularGraph()); + RestrictionVec restrictions = { + {Restriction::Type::No, {5 /* feature from */, 2 /* feature to */}}}; + 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); +} + +UNIT_CLASS_TEST(RestrictionTest, TriangularGraph_RestrictionOnlyF5F3) +{ + Init(BuildTriangularGraph()); + RestrictionVec restrictions = { + {Restriction::Type::Only, {5 /* feature from */, 3 /* feature to */}}}; + 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); +} + +UNIT_CLASS_TEST(RestrictionTest, TriangularGraph_RestrictionNoF5F2RestrictionOnlyF5F3) +{ + Init(BuildTriangularGraph()); + RestrictionVec restrictions = { + {Restriction::Type::No, {5 /* feature from */, 2 /* feature to */}}, + {Restriction::Type::Only, {5 /* feature from */, 3 /* feature to */}}}; + 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); +} + +// Finish +// 3 * +// | +// F4 +// | +// 2 * +// | \ +// F0 F2 +// | \ +// 1 * * +// | \ +// F0 F2 +// | \ +// 0 *---F1--*--F1--*--F3---* Start +// 0 1 2 3 +// Note. All features are two setments and two-way. +unique_ptr BuildTwowayCornerGraph() +{ + unique_ptr loader = make_unique(); + loader->AddRoad(0 /* feature id */, false /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{0.0, 0.0}, {0.0, 1.0}, {0.0, 2.0}})); + loader->AddRoad(1 /* feature id */, false /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{2.0, 0.0}, {1.0, 0.0}, {0.0, 0.0}})); + loader->AddRoad(2 /* feature id */, false /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{2.0, 0.0}, {1.0, 1.0}, {0.0, 2.0}})); + loader->AddRoad(3 /* feature id */, false /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{3.0, 0.0}, {2.0, 0.0}})); + loader->AddRoad(4 /* feature id */, false /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{0.0, 2.0}, {0.0, 3.0}})); + + vector const joints = { + MakeJoint({{1 /* feature id */, 2 /* point id */}, {0, 0}}) + /* joint at point (0, 0) */, + MakeJoint({{1, 0}, {2, 0}, {3, 1}}), /* joint at point (2, 0) */ + MakeJoint({{2, 2}, {0, 2}, {4, 0}}), /* joint at point (0, 2) */ + MakeJoint({{4, 1}}), /* joint at point (0, 3) */ + MakeJoint({{3, 0}}), /* joint at point (3, 0) */ + }; + traffic::TrafficCache const trafficCache; + unique_ptr graph = + make_unique(move(loader), CreateEstimator(trafficCache)); + graph->Import(joints); + return graph; +} + +UNIT_CLASS_TEST(RestrictionTest, TwowayCornerGraph) +{ + Init(BuildTwowayCornerGraph()); + vector const expectedGeom = {{3 /* x */, 0 /* y */}, {2, 0}, {1, 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 */, {}, + *this); +} + +UNIT_CLASS_TEST(RestrictionTest, TwowayCornerGraph_RestrictionF3F2No) +{ + Init(BuildTwowayCornerGraph()); + RestrictionVec restrictions = { + {Restriction::Type::No, {3 /* feature from */, 2 /* feature to */}}}; + 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); +} + +UNIT_CLASS_TEST(RestrictionTest, TwowayCornerGraph_RestrictionF3F1Only) +{ + Init(BuildTwowayCornerGraph()); + RestrictionVec restrictions = { + {Restriction::Type::Only, {3 /* feature from */, 1 /* feature to */}}}; + 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); +} + +// Finish +// 3 * +// ^ +// | +// F11 +// | +// 2 *<---F5----*<---F6---* +// ^ ↖ ^ ↖ ^ +// | F7 | F8 | +// | ↖ F1 ↖ F2 +// | ↖ | ↖ | +// 1 F0 * * +// | ^ ↖ ^ +// | F1 F9 F2 +// | | ↖ | +// 0 *<----F4---*<---F3----*<--F10---* Start +// 0 1 2 3 +// Note. F1 and F2 are two segments features. The others are one segment ones. +unique_ptr BuildTwoSquaresGraph() +{ + unique_ptr loader = make_unique(); + loader->AddRoad(0 /* feature id */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{0.0, 0.0}, {0.0, 2.0}})); + loader->AddRoad(1 /* feature id */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, 0.0}, {1.0, 1.0}, {1.0, 2.0}})); + loader->AddRoad(2 /* feature id */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{2.0, 0.0}, {2.0, 1.0}, {2.0, 2.0}})); + loader->AddRoad(3 /* feature id */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{2.0, 0.0}, {1.0, 0.0}})); + loader->AddRoad(4 /* feature id */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, 0.0}, {0.0, 0.0}})); + loader->AddRoad(5 /* feature id */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, 2.0}, {0.0, 2.0}})); + loader->AddRoad(6 /* feature id */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{2.0, 2.0}, {1.0, 2.0}})); + loader->AddRoad(7 /* feature id */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, 1.0}, {0.0, 2.0}})); + loader->AddRoad(8 /* feature id */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{2.0, 1.0}, {1.0, 2.0}})); + loader->AddRoad(9 /* feature id */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{2.0, 0.0}, {1.0, 1.0}})); + loader->AddRoad(10 /* feature id */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{3.0, 0.0}, {2.0, 0.0}})); + loader->AddRoad(11 /* feature id */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{0.0, 2.0}, {0.0, 3.0}})); + + vector const joints = { + MakeJoint({{4 /* featureId */, 1 /* pointId */}, {0, 0}}), /* joint at point (0, 0) */ + MakeJoint({{0, 1}, {5, 1}, {7, 1}, {11, 0}}), /* joint at point (0, 2) */ + MakeJoint({{4, 0}, {1, 0}, {3, 1}}), /* joint at point (1, 0) */ + MakeJoint({{5, 0}, {1, 2}, {6, 1}, {8, 1}}), /* joint at point (1, 2) */ + MakeJoint({{3, 0}, {2, 0}, {9, 0}, {10, 1}}), /* joint at point (2, 0) */ + MakeJoint({{2, 2}, {6, 0}}), /* joint at point (2, 2) */ + MakeJoint({{1, 1}, {9, 1}, {7, 0}}), /* joint at point (1, 1) */ + MakeJoint({{2, 1}, {8, 0}}), /* joint at point (2, 1) */ + MakeJoint({{10, 0}}), /* joint at point (3, 0) */ + MakeJoint({{11, 1}}), /* joint at point (0, 3) */ + }; + + traffic::TrafficCache const trafficCache; + unique_ptr graph = + make_unique(move(loader), CreateEstimator(trafficCache)); + graph->Import(joints); + return graph; +} + +UNIT_CLASS_TEST(RestrictionTest, TwoSquaresGraph) +{ + Init(BuildTwoSquaresGraph()); + vector const expectedGeom = {{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 */, {}, + *this); +} + +UNIT_CLASS_TEST(RestrictionTest, TwoSquaresGraph_RestrictionF10F3Only) +{ + Init(BuildTwoSquaresGraph()); + RestrictionVec restrictions = { + {Restriction::Type::Only, {10 /* feature from */, 3 /* feature to */}}}; + + vector const expectedGeom = { + {3 /* x */, 0 /* y */}, {2, 0}, {1, 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); +} + +UNIT_CLASS_TEST(RestrictionTest, TwoSquaresGraph_RestrictionF10F3OnlyF3F4Only) +{ + Init(BuildTwoSquaresGraph()); + RestrictionVec restrictions = { + {Restriction::Type::Only, {3 /* feature from */, 4 /* feature to */}}, + {Restriction::Type::Only, {10 /* feature from */, 3 /* feature to */}}}; + + 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(10, 0, m2::PointD(3, 0)) /* start */, + routing::IndexGraphStarter::FakeVertex(11, 0, m2::PointD(0, 3)) /* finish */, + move(restrictions), *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 */}}}; + + vector const expectedGeom = { + {3 /* x */, 0 /* y */}, {2, 0}, {1, 1}, {1, 2}, {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); +} + +// 2 * +// | +// F6 +// |Finish +// 1 *-F4-*-F5-* +// | | +// F2 F3 +// | | +// 0 *---F1----*---F0---* Start +// 0 1 2 +// Note 1. All features are two-way. (It's possible to move along any direction of the features.) +// Note 2. Any feature contains of one segment. +unique_ptr BuildFlagGraph() +{ + unique_ptr loader = make_unique(); + loader->AddRoad(0 /* feature id */, false /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{2.0, 0.0}, {1.0, 0.0}})); + loader->AddRoad(1 /* feature id */, false /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, 0.0}, {0.0, 0.0}})); + loader->AddRoad(2 /* feature id */, false /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{0.0, 0.0}, {0.0, 1.0}})); + loader->AddRoad(3 /* feature id */, false /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, 0.0}, {1.0, 1.0}})); + loader->AddRoad(4 /* feature id */, false /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{0.0, 1.0}, {0.5, 1.0}})); + loader->AddRoad(5 /* feature id */, false /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{0.5, 1.0}, {1.0, 1.0}})); + loader->AddRoad(6 /* feature id */, false /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{0.5, 1.0}, {0.5, 2.0}})); + + vector const joints = { + MakeJoint({{1 /* feature id */, 1 /* point id */}, {2, 0}}), /* joint at point (0, 0) */ + MakeJoint({{2, 1}, {4, 0}}), /* joint at point (0, 1) */ + MakeJoint({{4, 1}, {5, 0}, {6, 0}}), /* joint at point (0.5, 1) */ + MakeJoint({{1, 0}, {3, 0}, {0, 1}}), /* joint at point (1, 0) */ + MakeJoint({{3, 1}, {5, 1}}), /* joint at point (1, 1) */ + MakeJoint({{6, 1}}), /* joint at point (0.5, 2) */ + MakeJoint({{0, 0}}), /* joint at point (2, 0) */ + }; + + traffic::TrafficCache const trafficCache; + unique_ptr graph = + make_unique(move(loader), CreateEstimator(trafficCache)); + graph->Import(joints); + return graph; +} + +// Route through flag graph without any restrictions. +UNIT_TEST(FlagGraph) +{ + unique_ptr graph = BuildFlagGraph(); + IndexGraphStarter starter( + *graph, routing::IndexGraphStarter::FakeVertex(0, 0, m2::PointD(2, 0)) /* start */, + routing::IndexGraphStarter::FakeVertex(6, 0, m2::PointD(0.5, 1)) /* finish */); + vector const expectedGeom = {{2 /* x */, 0 /* y */}, {1, 0}, {1, 1}, {0.5, 1}}; + TestRouteGeometry(starter, AStarAlgorithm::Result::OK, expectedGeom); +} + +// Route through flag graph with one restriciton (type no) from F0 to F3. +UNIT_CLASS_TEST(RestrictionTest, FlagGraph_RestrictionF0F3No) +{ + Init(BuildFlagGraph()); + RestrictionVec restrictions = { + {Restriction::Type::No, {0 /* feature from */, 3 /* feature to */}}}; + vector const expectedGeom = { + {2 /* x */, 0 /* y */}, {1, 0}, {0, 0}, {0, 1}, {0.5, 1}}; + + TestRestrictions(expectedGeom, AStarAlgorithm::Result::OK, + routing::IndexGraphStarter::FakeVertex(0, 0, m2::PointD(2, 0)) /* start */, + routing::IndexGraphStarter::FakeVertex(6, 0, m2::PointD(0.5, 1)) /* finish */, + move(restrictions), *this); +} + +// Route through flag graph with one restriciton (type only) from F0 to F1. +UNIT_CLASS_TEST(RestrictionTest, FlagGraph_RestrictionF0F1Only) +{ + Init(BuildFlagGraph()); + RestrictionVec restrictions = { + {Restriction::Type::No, {0 /* feature from */, 1 /* feature to */}}}; + vector const expectedGeom = {{2 /* x */, 0 /* y */}, {1, 0}, {1, 1}, {0.5, 1}}; + + TestRestrictions(expectedGeom, AStarAlgorithm::Result::OK, + routing::IndexGraphStarter::FakeVertex(0, 0, m2::PointD(2, 0)) /* start */, + routing::IndexGraphStarter::FakeVertex(6, 0, m2::PointD(0.5, 1)) /* finish */, + move(restrictions), *this); +} + +UNIT_CLASS_TEST(RestrictionTest, FlagGraph_PermutationsF1F3NoF7F8OnlyF8F4OnlyF4F6Only) +{ + Init(BuildFlagGraph()); + RestrictionVec restrictions = { + {Restriction::Type::No, {0 /* feature from */, 3 /* feature to */}}, + {Restriction::Type::Only, {0 /* feature from */, 1 /* feature to */}}, + {Restriction::Type::Only, {1 /* feature from */, 2 /* feature to */}}}; + + vector const expectedGeom = { + {2 /* x */, 0 /* y */}, {1, 0}, {0, 0}, {0, 1}, {0.5, 1}}; + TestRestrictions(expectedGeom, AStarAlgorithm::Result::OK, + routing::IndexGraphStarter::FakeVertex(0, 0, m2::PointD(2, 0)) /* start */, + routing::IndexGraphStarter::FakeVertex(6, 0, m2::PointD(0.5, 1)) /* finish */, + move(restrictions), *this); +} + +// 1 *-F4-*-F5-*---F6---* Finish +// | | +// F2 F3 +// | | +// 0 *---F1----*---F0---* Start +// 0 1 2 +// Note 1. All features except for F7 are two-way. +// Note 2. Any feature contains of one segment. +unique_ptr BuildPosterGraph() +{ + unique_ptr loader = make_unique(); + loader->AddRoad(0 /* feature id */, false /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{2.0, 0.0}, {1.0, 0.0}})); + loader->AddRoad(1 /* feature id */, false /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, 0.0}, {0.0, 0.0}})); + loader->AddRoad(2 /* feature id */, false /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{0.0, 0.0}, {0.0, 1.0}})); + loader->AddRoad(3 /* feature id */, false /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, 0.0}, {1.0, 1.0}})); + loader->AddRoad(4 /* feature id */, false /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{0.0, 1.0}, {0.5, 1.0}})); + loader->AddRoad(5 /* feature id */, false /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{0.5, 1.0}, {1.0, 1.0}})); + loader->AddRoad(6 /* feature id */, false /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, 1.0}, {2.0, 1.0}})); + + vector const joints = { + MakeJoint({{1 /* feature id */, 1 /* point id */}, {2, 0}}), /* joint at point (0, 0) */ + MakeJoint({{2, 1}, {4, 0}}), /* joint at point (0, 1) */ + MakeJoint({{4, 1}, {5, 0}}), /* joint at point (0.5, 1) */ + MakeJoint({{1, 0}, {3, 0}, {0, 1}}), /* joint at point (1, 0) */ + MakeJoint({{3, 1}, {5, 1}, {6, 0}}), /* joint at point (1, 1) */ + MakeJoint({{0, 0}}), /* joint at point (2, 0) */ + MakeJoint({{6, 1}}), /* joint at point (2, 1) */ + }; + + traffic::TrafficCache const trafficCache; + unique_ptr graph = + make_unique(move(loader), CreateEstimator(trafficCache)); + graph->Import(joints); + + return graph; +} + +// Route through poster graph without any restrictions. +UNIT_TEST(PosterGraph) +{ + unique_ptr graph = BuildPosterGraph(); + IndexGraphStarter starter( + *graph, routing::IndexGraphStarter::FakeVertex(0, 0, m2::PointD(2, 0)) /* start */, + routing::IndexGraphStarter::FakeVertex(6, 0, m2::PointD(2, 1)) /* finish */); + vector const expectedGeom = {{2 /* x */, 0 /* y */}, {1, 0}, {1, 1}, {2, 1}}; + + TestRouteGeometry(starter, AStarAlgorithm::Result::OK, expectedGeom); +} + +// Route through poster graph with restrictions F0-F3 (type no). +UNIT_CLASS_TEST(RestrictionTest, PosterGraph_RestrictionF0F3No) +{ + Init(BuildPosterGraph()); + RestrictionVec restrictions = { + {Restriction::Type::No, {0 /* feature from */, 3 /* feature to */}}}; + 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); +} + +// Route through poster graph with restrictions F0-F1 (type only). +UNIT_CLASS_TEST(RestrictionTest, PosterGraph_RestrictionF0F1Only) +{ + Init(BuildPosterGraph()); + + RestrictionVec restrictions = { + {Restriction::Type::Only, {0 /* feature from */, 1 /* feature to */}}}; + 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); +} + +// 1 *--F1-->* +// ↗ ↘ +// F1 F1 +// ↗ ↘ +// 0 Start *---F3--->*---F0--->-------F0----->*---F2-->* Finish +// -1 0 1 2 3 4 +// Note. F0 is a two segments feature. F1 is a three segment one. F2 and F3 are one segment +// features. +unique_ptr BuildTwoWayGraph() +{ + unique_ptr loader = make_unique(); + loader->AddRoad(0 /* feature id */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{0.0, 0.0}, {1.0, 0.0}, {3.0, 0}})); + loader->AddRoad(1 /* feature id */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{0.0, 0.0}, {1.0, 1.0}, {2.0, 1.0}, {3.0, 0.0}})); + loader->AddRoad(2 /* feature id */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{3.0, 0.0}, {4.0, 0.0}})); + loader->AddRoad(3 /* feature id */, true /* oneWay */, 1.0 /* speed */, + RoadGeometry::Points({{-1.0, 0.0}, {0.0, 0.0}})); + + vector const joints = { + MakeJoint( + {{0 /* feature id */, 0 /* point id */}, {1, 0}, {3, 1}}), /* joint at point (0, 0) */ + MakeJoint( + {{0 /* feature id */, 2 /* point id */}, {1, 3}, {2, 0}}), /* joint at point (3, 0) */ + MakeJoint({{3 /* feature id */, 0 /* point id */}}), /* joint at point (-1, 0) */ + MakeJoint({{2 /* feature id */, 1 /* point id */}}), /* joint at point (4, 0) */ + }; + + traffic::TrafficCache const trafficCache; + unique_ptr graph = + make_unique(move(loader), CreateEstimator(trafficCache)); + graph->Import(joints); + return graph; +} + +UNIT_TEST(TwoWayGraph) +{ + unique_ptr graph = BuildTwoWayGraph(); + IndexGraphStarter starter( + *graph, routing::IndexGraphStarter::FakeVertex(3, 0, m2::PointD(-1, 0)) /* start */, + routing::IndexGraphStarter::FakeVertex(2, 0, m2::PointD(4, 0)) /* finish */); + vector const expectedGeom = {{-1 /* x */, 0 /* y */}, {0, 0}, {1, 0}, {3, 0}, {4, 0}}; + + TestRouteGeometry(starter, AStarAlgorithm::Result::OK, expectedGeom); +} + +// 1 *---F4----* +// | | +// F2 F3 +// | | +// 0 *<--F5---*<--F1----*<--F0---* Start +// Finish +// 0 1 2 3 +// Note 1. F0, F1 and F5 are one-way features. F3, F2 and F4 are two-way features. +// Note 2. Any feature contains of one segment. +unique_ptr BuildSquaresGraph() +{ + unique_ptr loader = make_unique(); + loader->AddRoad(0 /* feature id */, true /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{3.0, 0.0}, {2.0, 0.0}})); + loader->AddRoad(1 /* feature id */, true /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{2.0, 0.0}, {1.0, 0.0}})); + loader->AddRoad(2 /* feature id */, false /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, 0.0}, {1.0, 1.0}})); + loader->AddRoad(3 /* feature id */, false /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{2.0, 0.0}, {2.0, 1.0}})); + loader->AddRoad(4 /* feature id */, false /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{2.0, 1.0}, {1.0, 1.0}})); + loader->AddRoad(5 /* feature id */, true /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, 0.0}, {0.0, 0.0}})); + + vector const joints = { + MakeJoint({{0 /* feature id */, 0 /* point id */}}), /* joint at point (3, 0) */ + MakeJoint({{0, 1}, {3, 0}, {1, 0}}), /* joint at point (2, 0) */ + MakeJoint({{3, 1}, {4, 0}}), /* joint at point (2, 1) */ + MakeJoint({{2, 1}, {4, 1}}), /* joint at point (1, 1) */ + MakeJoint({{1, 1}, {2, 0}, {5, 0}}), /* joint at point (1, 0) */ + MakeJoint({{5, 1}}) /* joint at point (0, 0) */ + }; + + traffic::TrafficCache const trafficCache; + unique_ptr graph = + make_unique(move(loader), CreateEstimator(trafficCache)); + graph->Import(joints); + return graph; +} + +UNIT_TEST(SquaresGraph) +{ + unique_ptr graph = BuildSquaresGraph(); + IndexGraphStarter starter( + *graph, routing::IndexGraphStarter::FakeVertex(0, 0, m2::PointD(3, 0)) /* start */, + routing::IndexGraphStarter::FakeVertex(5, 0, m2::PointD(0, 0)) /* finish */); + vector const expectedGeom = {{3 /* x */, 0 /* y */}, {2, 0}, {1, 0}, {0, 0}}; + TestRouteGeometry(starter, AStarAlgorithm::Result::OK, expectedGeom); +} + +// It's a test on correct working in case when because of adding restrictions +// start and finish could be match on blocked, moved or copied edges. +// See IndexGraphStarter constructor for a detailed description. +UNIT_CLASS_TEST(RestrictionTest, SquaresGraph_RestrictionF0F1OnlyF1F5Only) +{ + Init(BuildSquaresGraph()); + RestrictionVec restrictions = { + {Restriction::Type::Only, {0 /* feature from */, 1 /* feature to */}}, + {Restriction::Type::Only, {1 /* feature from */, 5 /* feature to */}}}; + vector const expectedGeom = {{3 /* x */, 0 /* y */}, {2, 0}, {1, 0}, {0, 0}}; + + TestRestrictions(expectedGeom, AStarAlgorithm::Result::OK, + routing::IndexGraphStarter::FakeVertex(0, 0, m2::PointD(3, 0)) /* start */, + routing::IndexGraphStarter::FakeVertex(5, 0, m2::PointD(0, 0)) /* finish */, + move(restrictions), *this); +} + +// 0 Start *--F0--->*---F1---*---F1---*---F1---*---F2-->* Finish +// 0 1 2 3 4 5 +// Note. F0 and F2 are one segment one-way features. F1 is a 3 segment two-way feature. +unique_ptr BuildLineGraph() +{ + unique_ptr loader = make_unique(); + loader->AddRoad(0 /* feature id */, true /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{0.0, 0.0}, {0.0, 1.0}})); + loader->AddRoad(1 /* feature id */, false /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{1.0, 0.0}, {2.0, 0.0}, {3.0, 0.0}, {3.0, 0.0}})); + loader->AddRoad(2 /* feature id */, true /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{4.0, 0.0}, {5.0, 0.0}})); + + vector const joints = { + MakeJoint({{0 /* feature id */, 0 /* point id */}}), /* joint at point (0, 0) */ + MakeJoint({{0, 1}, {1, 0}}), /* joint at point (1, 0) */ + MakeJoint({{1, 3}, {2, 0}}), /* joint at point (4, 0) */ + MakeJoint({{2, 1}}), /* joint at point (5, 0) */ + }; + + traffic::TrafficCache const trafficCache; + unique_ptr graph = + make_unique(move(loader), CreateEstimator(trafficCache)); + graph->Import(joints); + return graph; +} + +// This test checks that despite the fact uturn on F1 is prohibited (moving from F1 to F1 is +// prohibited) +// it's still possible to move from F1 to F1 in straight direction. +UNIT_CLASS_TEST(RestrictionTest, LineGraph_RestrictionF1F1No) +{ + Init(BuildLineGraph()); + RestrictionVec restrictions = { + {Restriction::Type::No, {1 /* feature from */, 1 /* feature to */}}}; + vector const expectedGeom = { + {0 /* x */, 0 /* y */}, {1, 0}, {2, 0}, {3, 0}, {4, 0}, {5, 0}}; + + TestRestrictions(expectedGeom, AStarAlgorithm::Result::OK, + routing::IndexGraphStarter::FakeVertex(0 /* feature id */, 0 /* seg id */, + m2::PointD(0, 0)) /* start */, + routing::IndexGraphStarter::FakeVertex(2, 0, m2::PointD(5, 0)) /* finish */, + move(restrictions), *this); +} + +// 2 *---F2-->* +// ^ +// F0 +// | +// 1 *---F1-->* Finish +// ^ +// F0 +// | +// 0 * +// 0 1 +// Start +unique_ptr BuildFGraph() +{ + unique_ptr loader = make_unique(); + loader->AddRoad(0 /* feature id */, true /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{0.0, 0.0}, {0.0, 1.0}, {0.0, 2.0}})); + loader->AddRoad(1 /* feature id */, true /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{0.0, 1.0}, {1.0, 1.0}})); + loader->AddRoad(2 /* feature id */, true /* one way */, 1.0 /* speed */, + RoadGeometry::Points({{0.0, 2.0}, {1.0, 2.0}})); + + vector const joints = { + MakeJoint({{0 /* feature id */, 0 /* point id */}}), /* joint at point (0, 0) */ + MakeJoint({{0, 1}, {1, 0}}), /* joint at point (0, 1) */ + MakeJoint({{0, 2}, {2, 0}}), /* joint at point (0, 2) */ + MakeJoint({{1, 1}}), /* joint at point (1, 1) */ + MakeJoint({{2, 1}}), /* joint at point (1, 2) */ + }; + + traffic::TrafficCache const trafficCache; + unique_ptr graph = + make_unique(move(loader), CreateEstimator(trafficCache)); + graph->Import(joints); + return graph; +} + +// This test checks that having a Only restriction from F0 to F2 it's still possible move +// from F0 to F1. +UNIT_CLASS_TEST(RestrictionTest, FGraph_RestrictionF0F2Only) +{ + Init(BuildFGraph()); + RestrictionVec restrictions = { + {Restriction::Type::Only, {0 /* feature from */, 2 /* feature to */}}}; + vector const expectedGeom = {{0 /* x */, 0 /* y */}, {0, 1}, {1, 1}}; + + TestRestrictions(expectedGeom, AStarAlgorithm::Result::OK, + routing::IndexGraphStarter::FakeVertex(0 /* feature id */, 0 /* seg id */, + m2::PointD(0, 0)) /* start */, + routing::IndexGraphStarter::FakeVertex(1, 0, m2::PointD(1, 1)) /* finish */, + move(restrictions), *this); +} +} // namespace routing_test diff --git a/routing/routing_tests/routing_tests.pro b/routing/routing_tests/routing_tests.pro index 49ee873ed0..f4c315d499 100644 --- a/routing/routing_tests/routing_tests.pro +++ b/routing/routing_tests/routing_tests.pro @@ -27,12 +27,14 @@ SOURCES += \ astar_router_test.cpp \ async_router_test.cpp \ cross_routing_tests.cpp \ + cumulative_restriction_test.cpp \ followed_polyline_test.cpp \ index_graph_test.cpp \ index_graph_tools.cpp \ nearest_edge_finder_tests.cpp \ online_cross_fetcher_test.cpp \ osrm_router_test.cpp \ + restriction_test.cpp \ road_graph_builder.cpp \ road_graph_nearest_edges_test.cpp \ route_tests.cpp \ diff --git a/routing/single_mwm_router.cpp b/routing/single_mwm_router.cpp index 288dcea1d9..190a5bcfce 100644 --- a/routing/single_mwm_router.cpp +++ b/routing/single_mwm_router.cpp @@ -10,6 +10,7 @@ #include "routing/index_graph_starter.hpp" #include "routing/index_road_graph.hpp" #include "routing/pedestrian_model.hpp" +#include "routing/restriction_loader.hpp" #include "routing/route.hpp" #include "routing/routing_helpers.hpp" #include "routing/turns_generator.hpp" @@ -190,6 +191,10 @@ 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); + if (restrictionLoader.HasRestrictions()) + graph.SetRestrictions(restrictionLoader.StealRestrictions()); + LOG(LINFO, (ROUTING_FILE_TAG, "section for", country, "loaded in", timer.ElapsedSeconds(), "seconds")); return true; From b3455075835cb5b31fe7e1d88390b4b415c81e1f Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Wed, 18 Jan 2017 15:46:43 +0300 Subject: [PATCH 2/8] Dynamic restriction bugfix and review fixes. --- routing/index_graph.cpp | 59 +++++++++++++------------- routing/index_graph_starter.cpp | 10 ----- routing/index_graph_starter.hpp | 12 +++++- routing/restriction_loader.hpp | 1 + routing/restrictions_serialization.cpp | 1 + routing/restrictions_serialization.hpp | 2 + 6 files changed, 44 insertions(+), 41 deletions(-) diff --git a/routing/index_graph.cpp b/routing/index_graph.cpp index f660d3940f..f1aaaf6ded 100644 --- a/routing/index_graph.cpp +++ b/routing/index_graph.cpp @@ -53,31 +53,33 @@ bool IsRestricted(RestrictionVec const & restrictions, vector const auto const lower = range.first; auto const upper = range.second; - // Checking if there's at least one restrictions of type Only from |featureIdFrom| and - // ending with |featureIdTo|. If yes, returns false. - if (lower != upper && lower->m_featureIds[1] == featureIdTo) + // Checking if there's restriction of type Only starting from |featureIdFrom|. If not returns false. + if (lower == upper) return false; - // Checking if there's at least one Only starting from |featureIdFrom|. - // If not, returns false. - if (lower == restrictions.cend() || lower->m_type != Restriction::Type::Only || - lower->m_featureIds[0] != featureIdFrom) + // 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) { - return false; - } + CHECK_EQUAL(i->m_featureIds.size(), 2, ("Only two link restrictions are support.")); - // 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. - CHECK_EQUAL(lower->m_featureIds.size(), 2, ("Only two link restrictions are support.")); - for (SegmentEdge const & e : edges) - { - if (e.GetTarget().GetFeatureId() == lower->m_featureIds[isOutgoing ? 1 /* to */ : 0 /* from */]) - return true; + // 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; } @@ -103,26 +105,25 @@ void IndexGraph::GetEdgeList(Segment const & segment, bool isOutgoing, vector rawEdges; if (jointId != Joint::kInvalidId) { m_jointIndex.ForEachPoint(jointId, [&](RoadPoint const & rp) { - GetNeighboringEdges(segment, rp, isOutgoing, edges); + GetNeighboringEdges(segment, rp, isOutgoing, rawEdges); }); } else { - GetNeighboringEdges(segment, roadPoint, isOutgoing, edges); + GetNeighboringEdges(segment, roadPoint, isOutgoing, rawEdges); } // Removing some edges according to restriction rules. - vector filteredEdges; - filteredEdges.reserve(edges.size()); - for (SegmentEdge const & e : edges) + edges.reserve(rawEdges.size()); + for (SegmentEdge const & e : rawEdges) { - if (!IsRestricted(m_restrictions, edges, segment, e.GetTarget(), isOutgoing)) - filteredEdges.push_back(e); + if (!IsRestricted(m_restrictions, rawEdges, segment, e.GetTarget(), isOutgoing)) + edges.push_back(e); } - edges.swap(filteredEdges); } void IndexGraph::Build(uint32_t numJoints) { m_jointIndex.Build(m_roadIndex, numJoints); } diff --git a/routing/index_graph_starter.cpp b/routing/index_graph_starter.cpp index 58e9d63053..0ba068c559 100644 --- a/routing/index_graph_starter.cpp +++ b/routing/index_graph_starter.cpp @@ -47,16 +47,6 @@ m2::PointD const & IndexGraphStarter::GetRoutePoint(vector const & segm return GetPoint(segments[pointIndex], true /* front */); } -void IndexGraphStarter::GetOutgoingEdgesList(TVertexType const & segment, vector & edges) -{ - GetEdgesList(segment, true /* isOutgoing */, edges); -} - -void IndexGraphStarter::GetIngoingEdgesList(TVertexType const & segment, vector & edges) -{ - GetEdgesList(segment, false /* isOutgoing */, edges); -} - void IndexGraphStarter::GetEdgesList(Segment const & segment, bool isOutgoing, vector & edges) { diff --git a/routing/index_graph_starter.hpp b/routing/index_graph_starter.hpp index cf5d415108..4ad31a298a 100644 --- a/routing/index_graph_starter.hpp +++ b/routing/index_graph_starter.hpp @@ -52,8 +52,16 @@ public: m2::PointD const & GetRoutePoint(vector const & route, size_t pointIndex); void GetEdgesList(Segment const & segment, bool isOutgoing, vector & edges); - void GetOutgoingEdgesList(TVertexType const & segment, vector & edges); - void GetIngoingEdgesList(TVertexType const & segment, vector & edges); + + void GetOutgoingEdgesList(TVertexType const & segment, vector & edges) + { + GetEdgesList(segment, true /* isOutgoing */, edges); + } + + void GetIngoingEdgesList(TVertexType const & segment, vector & edges) + { + GetEdgesList(segment, false /* isOutgoing */, edges); + } double HeuristicCostEstimate(TVertexType const & from, TVertexType const & to) { diff --git a/routing/restriction_loader.hpp b/routing/restriction_loader.hpp index 6e58134225..bae5c07aba 100644 --- a/routing/restriction_loader.hpp +++ b/routing/restriction_loader.hpp @@ -18,6 +18,7 @@ public: bool HasRestrictions() const { return !m_restrictions.empty(); } RestrictionVec && StealRestrictions() { return move(m_restrictions); } + private: unique_ptr m_reader; RestrictionHeader m_header; diff --git a/routing/restrictions_serialization.cpp b/routing/restrictions_serialization.cpp index 1a72524b68..a9efc8d6f3 100644 --- a/routing/restrictions_serialization.cpp +++ b/routing/restrictions_serialization.cpp @@ -42,6 +42,7 @@ string ToString(Restriction::Type const & type) } string DebugPrint(Restriction::Type const & type) { return ToString(type); } + string DebugPrint(Restriction const & restriction) { ostringstream out; diff --git a/routing/restrictions_serialization.hpp b/routing/restrictions_serialization.hpp index f0a75cb7df..dbba6417bc 100644 --- a/routing/restrictions_serialization.hpp +++ b/routing/restrictions_serialization.hpp @@ -37,6 +37,7 @@ struct Restriction }; Restriction(Type type, vector const & links) : m_featureIds(links), m_type(type) {} + bool IsValid() const; bool operator==(Restriction const & restriction) const; bool operator<(Restriction const & restriction) const; @@ -55,6 +56,7 @@ string DebugPrint(Restriction const & restriction); struct RestrictionHeader { RestrictionHeader() { Reset(); } + template void Serialize(Sink & sink) const { From e0bbd3afc92f191bcc901d7afb9072276cb07150 Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Thu, 19 Jan 2017 15:02:17 +0300 Subject: [PATCH 3/8] 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); From 3461daa69f3e102e20470cd8e2735c87bc30c7d2 Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Thu, 19 Jan 2017 16:09:07 +0300 Subject: [PATCH 4/8] Fixing cmake and xcode build. --- routing/CMakeLists.txt | 4 +-- routing/index_road_graph.cpp | 2 +- routing/routing_tests/CMakeLists.txt | 4 +++ .../routing/routing.xcodeproj/project.pbxproj | 34 +++++++++++++------ 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/routing/CMakeLists.txt b/routing/CMakeLists.txt index eeaa1a7edc..95cd367703 100644 --- a/routing/CMakeLists.txt +++ b/routing/CMakeLists.txt @@ -70,6 +70,8 @@ set( pedestrian_model.hpp restriction_loader.cpp restriction_loader.hpp + restrictions_serialization.cpp + restrictions_serialization.hpp road_graph.cpp road_graph.hpp road_graph_router.cpp @@ -92,8 +94,6 @@ set( routing_mapping.cpp routing_mapping.hpp routing_result_graph.hpp - routing_serialization.cpp - routing_serialization.hpp routing_session.cpp routing_session.hpp routing_settings.hpp diff --git a/routing/index_road_graph.cpp b/routing/index_road_graph.cpp index 6cfadc578c..c227049a4e 100644 --- a/routing/index_road_graph.cpp +++ b/routing/index_road_graph.cpp @@ -89,7 +89,7 @@ const Segment & IndexRoadGraph::GetSegment(Junction const & junction, bool isOut auto const & junctionToSegment = isOutgoing ? m_endToSegment : m_beginToSegment; auto it = junctionToSegment.find(junction); - CHECK(it != junctionToSegment.cend(), ("junctionToSegment doesn't contains", junction, ", isOutgoing =" + isOutgoing)); + CHECK(it != junctionToSegment.cend(), ("junctionToSegment doesn't contains", junction, ", isOutgoing =", isOutgoing)); return it->second; } } // namespace routing diff --git a/routing/routing_tests/CMakeLists.txt b/routing/routing_tests/CMakeLists.txt index ba0ae9da55..cbe5f9106e 100644 --- a/routing/routing_tests/CMakeLists.txt +++ b/routing/routing_tests/CMakeLists.txt @@ -9,10 +9,14 @@ set( astar_router_test.cpp async_router_test.cpp cross_routing_tests.cpp + cumulative_restriction_test.cpp followed_polyline_test.cpp + index_graph_tools.cpp + index_graph_tools.hpp nearest_edge_finder_tests.cpp online_cross_fetcher_test.cpp osrm_router_test.cpp + restriction_test.cpp road_graph_builder.cpp road_graph_builder.hpp road_graph_nearest_edges_test.cpp diff --git a/xcode/routing/routing.xcodeproj/project.pbxproj b/xcode/routing/routing.xcodeproj/project.pbxproj index d36a41eda4..5d7140792a 100644 --- a/xcode/routing/routing.xcodeproj/project.pbxproj +++ b/xcode/routing/routing.xcodeproj/project.pbxproj @@ -50,6 +50,12 @@ 56555E591D897D28009D786D /* testingmain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6742ACDE1C68A13F009CB89E /* testingmain.cpp */; }; 56826BD01DB51C4E00807C62 /* car_router.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56826BCE1DB51C4E00807C62 /* car_router.cpp */; }; 56826BD11DB51C4E00807C62 /* car_router.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56826BCF1DB51C4E00807C62 /* car_router.hpp */; }; + 56CA09E31E30E73B00D05C9A /* applying_traffic_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56CA09DE1E30E73B00D05C9A /* applying_traffic_test.cpp */; }; + 56CA09E41E30E73B00D05C9A /* cumulative_restriction_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56CA09DF1E30E73B00D05C9A /* cumulative_restriction_test.cpp */; }; + 56CA09E51E30E73B00D05C9A /* index_graph_tools.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56CA09E01E30E73B00D05C9A /* index_graph_tools.cpp */; }; + 56CA09E61E30E73B00D05C9A /* index_graph_tools.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56CA09E11E30E73B00D05C9A /* index_graph_tools.hpp */; }; + 56CA09E71E30E73B00D05C9A /* restriction_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 56CA09E21E30E73B00D05C9A /* restriction_test.cpp */; }; + 56CA09E91E30F19800D05C9A /* libtraffic.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 56CA09E81E30F19800D05C9A /* libtraffic.a */; }; 56EA2FD51D8FD8590083F01A /* routing_helpers.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56EA2FD41D8FD8590083F01A /* routing_helpers.hpp */; }; 56F0D7341D896A5300045886 /* libmap.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 67BD35DE1C69F198003AA26F /* libmap.a */; }; 56F0D7391D896A5300045886 /* libstorage.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 67BD35D41C69F155003AA26F /* libstorage.a */; }; @@ -141,7 +147,6 @@ 6742AD561C68C7D7009CB89E /* types.txt in Resources */ = {isa = PBXBuildFile; fileRef = 6742AD551C68C7C1009CB89E /* types.txt */; }; 6742AD5C1C68C7FA009CB89E /* drules_proto_clear.bin in Resources */ = {isa = PBXBuildFile; fileRef = 6742AD571C68C7F6009CB89E /* drules_proto_clear.bin */; }; 6742AD5D1C68C7FA009CB89E /* drules_proto_dark.bin in Resources */ = {isa = PBXBuildFile; fileRef = 6742AD581C68C7F6009CB89E /* drules_proto_dark.bin */; }; - 6742AD5E1C68C7FA009CB89E /* drules_proto_legacy.bin in Resources */ = {isa = PBXBuildFile; fileRef = 6742AD591C68C7F6009CB89E /* drules_proto_legacy.bin */; }; 6742AD5F1C68C7FA009CB89E /* drules_proto-bw.bin in Resources */ = {isa = PBXBuildFile; fileRef = 6742AD5A1C68C7F6009CB89E /* drules_proto-bw.bin */; }; 6742AD601C68C7FA009CB89E /* drules_proto.bin in Resources */ = {isa = PBXBuildFile; fileRef = 6742AD5B1C68C7F6009CB89E /* drules_proto.bin */; }; 6742AD621C68F747009CB89E /* sound-strings in Resources */ = {isa = PBXBuildFile; fileRef = 6742AD611C68F747009CB89E /* sound-strings */; }; @@ -223,8 +228,6 @@ 67BD36051C69F51C003AA26F /* WorldCoasts.mwm in Resources */ = {isa = PBXBuildFile; fileRef = 67BD36021C69F513003AA26F /* WorldCoasts.mwm */; }; 67C79BA11E2CEE1400C40034 /* restriction_loader.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 67C79B9F1E2CEE1400C40034 /* restriction_loader.cpp */; }; 67C79BA21E2CEE1400C40034 /* restriction_loader.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 67C79BA01E2CEE1400C40034 /* restriction_loader.hpp */; }; - 67C79BA51E2CEE3100C40034 /* routing_serialization.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 67C79BA31E2CEE3100C40034 /* routing_serialization.cpp */; }; - 67C79BA61E2CEE3100C40034 /* routing_serialization.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 67C79BA41E2CEE3100C40034 /* routing_serialization.hpp */; }; 67C7D4291B4EB48F00FE41AA /* car_model.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 67C7D4211B4EB48F00FE41AA /* car_model.cpp */; }; 67C7D42A1B4EB48F00FE41AA /* car_model.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 67C7D4221B4EB48F00FE41AA /* car_model.hpp */; }; 67C7D42B1B4EB48F00FE41AA /* pedestrian_model.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 67C7D4231B4EB48F00FE41AA /* pedestrian_model.cpp */; }; @@ -292,6 +295,12 @@ 563B91C41CC4F1DC00222BC1 /* bicycle_model.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = bicycle_model.hpp; sourceTree = ""; }; 56826BCE1DB51C4E00807C62 /* car_router.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = car_router.cpp; sourceTree = ""; }; 56826BCF1DB51C4E00807C62 /* car_router.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = car_router.hpp; sourceTree = ""; }; + 56CA09DE1E30E73B00D05C9A /* applying_traffic_test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = applying_traffic_test.cpp; sourceTree = ""; }; + 56CA09DF1E30E73B00D05C9A /* cumulative_restriction_test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cumulative_restriction_test.cpp; sourceTree = ""; }; + 56CA09E01E30E73B00D05C9A /* index_graph_tools.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = index_graph_tools.cpp; sourceTree = ""; }; + 56CA09E11E30E73B00D05C9A /* index_graph_tools.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = index_graph_tools.hpp; sourceTree = ""; }; + 56CA09E21E30E73B00D05C9A /* restriction_test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = restriction_test.cpp; sourceTree = ""; }; + 56CA09E81E30F19800D05C9A /* libtraffic.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libtraffic.a; path = "/Users/vladimirbykoyanko/src_github_master/omim/xcode/traffic/../../../omim-build/xcode/Debug/libtraffic.a"; sourceTree = ""; }; 56EA2FD41D8FD8590083F01A /* routing_helpers.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = routing_helpers.hpp; sourceTree = ""; }; 56F0D75F1D896A5300045886 /* routing_benchmarks.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = routing_benchmarks.app; sourceTree = BUILT_PRODUCTS_DIR; }; 670B84BE1A9381D900CE4492 /* cross_routing_context.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cross_routing_context.cpp; sourceTree = ""; }; @@ -415,8 +424,6 @@ 67BD36021C69F513003AA26F /* WorldCoasts.mwm */ = {isa = PBXFileReference; lastKnownFileType = file; path = WorldCoasts.mwm; sourceTree = ""; }; 67C79B9F1E2CEE1400C40034 /* restriction_loader.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = restriction_loader.cpp; sourceTree = ""; }; 67C79BA01E2CEE1400C40034 /* restriction_loader.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = restriction_loader.hpp; sourceTree = ""; }; - 67C79BA31E2CEE3100C40034 /* routing_serialization.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = routing_serialization.cpp; sourceTree = ""; }; - 67C79BA41E2CEE3100C40034 /* routing_serialization.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = routing_serialization.hpp; sourceTree = ""; }; 67C7D4211B4EB48F00FE41AA /* car_model.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = car_model.cpp; sourceTree = ""; }; 67C7D4221B4EB48F00FE41AA /* car_model.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = car_model.hpp; sourceTree = ""; }; 67C7D4231B4EB48F00FE41AA /* pedestrian_model.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pedestrian_model.cpp; sourceTree = ""; }; @@ -471,6 +478,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 56CA09E91E30F19800D05C9A /* libtraffic.a in Frameworks */, 3462FDAD1DC1E5BF00906FD7 /* libopening_hours.a in Frameworks */, 6742AD4D1C68AA59009CB89E /* librouting.a in Frameworks */, 6742AD401C68AA04009CB89E /* libosrm.a in Frameworks */, @@ -542,6 +550,7 @@ 56F0D7611D896DAF00045886 /* Frameworks */ = { isa = PBXGroup; children = ( + 56CA09E81E30F19800D05C9A /* libtraffic.a */, 3462FDAC1DC1E5BF00906FD7 /* libopening_hours.a */, ); name = Frameworks; @@ -561,6 +570,11 @@ 6742ACA01C68A07C009CB89E /* routing_tests */ = { isa = PBXGroup; children = ( + 56CA09DE1E30E73B00D05C9A /* applying_traffic_test.cpp */, + 56CA09DF1E30E73B00D05C9A /* cumulative_restriction_test.cpp */, + 56CA09E01E30E73B00D05C9A /* index_graph_tools.cpp */, + 56CA09E11E30E73B00D05C9A /* index_graph_tools.hpp */, + 56CA09E21E30E73B00D05C9A /* restriction_test.cpp */, 6742ACDE1C68A13F009CB89E /* testingmain.cpp */, 6742ACA61C68A0B1009CB89E /* astar_algorithm_test.cpp */, 6742ACA71C68A0B1009CB89E /* astar_progress_test.cpp */, @@ -685,8 +699,6 @@ 675343FA1A3F640D00A0A8C3 /* routing */ = { isa = PBXGroup; children = ( - 67C79BA31E2CEE3100C40034 /* routing_serialization.cpp */, - 67C79BA41E2CEE3100C40034 /* routing_serialization.hpp */, 67C79B9F1E2CEE1400C40034 /* restriction_loader.cpp */, 67C79BA01E2CEE1400C40034 /* restriction_loader.hpp */, 0C470E6F1E0D4EB1005B824D /* segment.hpp */, @@ -844,11 +856,11 @@ A1616E2C1B6B60AB003F078E /* router_delegate.hpp in Headers */, A17B42991BCFBD0E00A1EAE4 /* osrm_helpers.hpp in Headers */, 67C7D42E1B4EB48F00FE41AA /* turns_sound_settings.hpp in Headers */, - 67C79BA61E2CEE3100C40034 /* routing_serialization.hpp in Headers */, 56099E341CC9247E00A7772A /* bicycle_directions.hpp in Headers */, 670EE55E1B6001E7001E8064 /* routing_session.hpp in Headers */, 56099E291CC7C97D00A7772A /* loaded_path_segment.hpp in Headers */, 670EE55F1B6001E7001E8064 /* routing_settings.hpp in Headers */, + 56CA09E61E30E73B00D05C9A /* index_graph_tools.hpp in Headers */, 671F58BE1B874EC80032311E /* followed_polyline.hpp in Headers */, 67C7D42C1B4EB48F00FE41AA /* pedestrian_model.hpp in Headers */, 0C5FEC6A1DDE193F0017688C /* road_index.hpp in Headers */, @@ -1026,7 +1038,6 @@ 6742AD601C68C7FA009CB89E /* drules_proto.bin in Resources */, 6742AD621C68F747009CB89E /* sound-strings in Resources */, 6742AD5D1C68C7FA009CB89E /* drules_proto_dark.bin in Resources */, - 6742AD5E1C68C7FA009CB89E /* drules_proto_legacy.bin in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1094,6 +1105,7 @@ buildActionMask = 2147483647; files = ( 0C5FEC641DDE192A0017688C /* joint.cpp in Sources */, + 56CA09E71E30E73B00D05C9A /* restriction_test.cpp in Sources */, 0C5BC9D11E28FD4E0071BFDD /* index_road_graph.cpp in Sources */, 56826BD01DB51C4E00807C62 /* car_router.cpp in Sources */, 56099E2E1CC8FBDA00A7772A /* osrm_path_segment_factory.cpp in Sources */, @@ -1124,11 +1136,12 @@ 674A28B11B1605D2001A525C /* osrm_engine.cpp in Sources */, 0C08AA341DF83223004195DD /* index_graph_serialization.cpp in Sources */, 674F9BD41B0A580E00704FFA /* road_graph.cpp in Sources */, + 56CA09E51E30E73B00D05C9A /* index_graph_tools.cpp in Sources */, 0C0DF92A1DE898FF0055A22F /* routing_helpers.cpp in Sources */, - 67C79BA51E2CEE3100C40034 /* routing_serialization.cpp in Sources */, 67AB92E61B7B3E6E00AB5194 /* turns_tts_text.cpp in Sources */, 0C5FEC601DDE192A0017688C /* index_graph.cpp in Sources */, 0C5FEC6D1DDE19A40017688C /* index_graph_test.cpp in Sources */, + 56CA09E41E30E73B00D05C9A /* cumulative_restriction_test.cpp in Sources */, 6753441E1A3F644F00A0A8C3 /* turns.cpp in Sources */, 670B84C01A9381D900CE4492 /* cross_routing_context.cpp in Sources */, A120B3501B4A7C0A002F3808 /* routing_algorithm.cpp in Sources */, @@ -1136,6 +1149,7 @@ 0C5FEC5E1DDE192A0017688C /* geometry.cpp in Sources */, 674F9BD01B0A580E00704FFA /* online_cross_fetcher.cpp in Sources */, 670EE5751B664796001E8064 /* router.cpp in Sources */, + 56CA09E31E30E73B00D05C9A /* applying_traffic_test.cpp in Sources */, 0C5FEC621DDE192A0017688C /* joint_index.cpp in Sources */, 670C62131AC5A15700C38A8C /* routing_mapping.cpp in Sources */, 67C79BA11E2CEE1400C40034 /* restriction_loader.cpp in Sources */, From 9034270ae107781bb191d1e498ed3629ae38147d Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Thu, 19 Jan 2017 17:40:17 +0300 Subject: [PATCH 5/8] Review fixes --- .../generator_tests/restriction_test.cpp | 2 +- routing/geometry.hpp | 2 - routing/index_graph.cpp | 55 +++++++++++-------- routing/index_graph.hpp | 5 -- routing/restriction_loader.cpp | 28 ++++------ routing/restriction_loader.hpp | 4 +- routing/road_index.hpp | 16 +++--- routing/routing_tests/restriction_test.cpp | 12 ++-- 8 files changed, 58 insertions(+), 66 deletions(-) diff --git a/generator/generator_tests/restriction_test.cpp b/generator/generator_tests/restriction_test.cpp index 45dd0da2c4..e6b76a88f2 100644 --- a/generator/generator_tests/restriction_test.cpp +++ b/generator/generator_tests/restriction_test.cpp @@ -58,7 +58,7 @@ void LoadRestrictions(MwmValue const & mwmValue, RestrictionVec & restrictions) header.Deserialize(src); RestrictionVec restrictionsOnly; - RestrictionSerializer::Deserialize(header, restrictions /* restriction no */, restrictionsOnly, src); + RestrictionSerializer::Deserialize(header, restrictions, restrictionsOnly, src); restrictions.insert(restrictions.end(), restrictionsOnly.cbegin(), restrictionsOnly.cend()); } catch (Reader::OpenException const & e) diff --git a/routing/geometry.hpp b/routing/geometry.hpp index 1c9e7b8821..c172f4cf88 100644 --- a/routing/geometry.hpp +++ b/routing/geometry.hpp @@ -74,8 +74,6 @@ 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 2a2a51aeed..7677aa4cf3 100644 --- a/routing/index_graph.cpp +++ b/routing/index_graph.cpp @@ -3,6 +3,7 @@ #include "routing/restrictions_serialization.hpp" #include "base/assert.hpp" +#include "base/checked_cast.hpp" #include "base/exception.hpp" #include @@ -10,6 +11,7 @@ namespace { +using namespace base; using namespace routing; using namespace std; @@ -19,21 +21,30 @@ bool IsRestricted(RestrictionVec const & restrictions, Segment const & u, Segmen uint32_t const featureIdTo = isOutgoing ? v.GetFeatureId() : u.GetFeatureId(); // Looking for at least one restriction of type No from |featureIdFrom| to |featureIdTo|. - if (binary_search(restrictions.cbegin(), restrictions.cend(), - Restriction(Restriction::Type::No, {featureIdFrom, featureIdTo}))) + if (!binary_search(restrictions.cbegin(), restrictions.cend(), + Restriction(Restriction::Type::No, {featureIdFrom, featureIdTo}))) { - if (featureIdFrom != featureIdTo) - return true; - - // @TODO(bykoianko) According to current code if a feature id is marked as a feature with - // restrictricted U-turn it's restricted to make a U-turn on the both ends of the feature. - // Generally speaking it's wrong. In osm there's information about the end of the feature - // where the U-turn is restricted. It's necessary to pass the data to mwm and to use it here. - // Please see test LineGraph_RestrictionF1F1No for details. - return u.GetSegmentIdx() == v.GetSegmentIdx() && u.IsForward() != v.IsForward(); + return false; } - return false; + if (featureIdFrom != featureIdTo) + return true; + + // @TODO(bykoianko) According to current code if a feature id is marked as a feature with + // restrictricted U-turn it's restricted to make a U-turn on the both ends of the feature. + // Generally speaking it's wrong. In osm there's information about the end of the feature + // where the U-turn is restricted. It's necessary to pass the data to mwm and to use it here. + // Please see test LineGraph_RestrictionF1F1No for details. + // + // Another exapmle when it's necessary to be aware about feature end particepated in restriction is + // *---F1---* + // | | + // *--F3--A B--F4--* + // | | + // *---F2---* + // In case of restriction F1-A-F2 or F1-B-F2 of any type (No, Only) the important information + // is lost. + return u.GetSegmentIdx() == v.GetSegmentIdx() && u.IsForward() != v.IsForward(); } bool IsUTurn(Segment const & u, Segment const & v) @@ -57,24 +68,15 @@ void IndexGraph::GetEdgeList(Segment const & segment, bool isOutgoing, vector rawEdges; if (jointId != Joint::kInvalidId) { m_jointIndex.ForEachPoint(jointId, [&](RoadPoint const & rp) { - GetNeighboringEdges(segment, rp, isOutgoing, rawEdges); + GetNeighboringEdges(segment, rp, isOutgoing, edges); }); } else { - GetNeighboringEdges(segment, roadPoint, isOutgoing, rawEdges); - } - - // Removing some edges according to restriction rules. - edges.reserve(rawEdges.size()); - for (SegmentEdge const & e : rawEdges) - { - if (!IsRestricted(m_restrictions, segment, e.GetTarget(), isOutgoing)) - edges.push_back(e); + GetNeighboringEdges(segment, roadPoint, isOutgoing, edges); } } @@ -84,7 +86,7 @@ void IndexGraph::Import(vector const & joints) { m_roadIndex.Import(joints); CHECK_LESS_OR_EQUAL(joints.size(), numeric_limits::max(), ()); - Build(static_cast(joints.size())); + Build(checked_cast(joints.size())); } void IndexGraph::SetRestrictions(RestrictionVec && restrictions) @@ -124,6 +126,7 @@ void IndexGraph::GetNeighboringEdges(Segment const & from, RoadPoint const & rp, void IndexGraph::GetNeighboringEdge(Segment const & from, Segment const & to, bool isOutgoing, vector & edges) { + // Blocking U-turns on internal feature points. RoadPoint const rp = from.GetRoadPoint(isOutgoing); if (IsUTurn(from, to) && m_roadIndex.GetJointId(rp) == Joint::kInvalidId @@ -133,6 +136,10 @@ void IndexGraph::GetNeighboringEdge(Segment const & from, Segment const & to, bo return; } + // Blocking restriction edges. + if (IsRestricted(m_restrictions, from, to, isOutgoing)) + 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 b0e55d76c5..6c218b789e 100644 --- a/routing/index_graph.hpp +++ b/routing/index_graph.hpp @@ -49,11 +49,6 @@ public: m_roadIndex.PushFromSerializer(jointId, rp); } - bool IsValid() const - { - return m_geometry.IsValid() && m_estimator && m_roadIndex.GetSize() != 0 && m_jointIndex.GetNumPoints() != 0; - } - template void ForEachRoad(F && f) const { diff --git a/routing/restriction_loader.cpp b/routing/restriction_loader.cpp index 481fa5fb1d..f559566178 100644 --- a/routing/restriction_loader.cpp +++ b/routing/restriction_loader.cpp @@ -15,23 +15,23 @@ using namespace routing; /// \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) +Joint::Id GetCommonEndJoint(RoadJointIds const & r1, 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())) + + if (IsEqual(r1.GetJointId(0 /* point id */), r2.GetEndingJointId())) return r1.GetJointId(0); - if (IsEqual(r1.GetJointId(0 /* point id */), r2.GetJointId(0))) + if (IsEqual(r1.GetJointId(0 /* point id */), r2.GetJointId(0 /* point id */))) return r1.GetJointId(0); - if (IsEqual(r2.GetJointId(0 /* point id */), r1.GetLastJointId())) - return r2.GetJointId(0); + if (IsEqual(r1.GetEndingJointId(), r2.GetJointId(0 /* point id */))) + return r1.GetEndingJointId(); - Joint::Id const r1Last = r1.GetLastJointId(); - if (IsEqual(r1Last, r2.GetLastJointId())) - return r1Last; + if (IsEqual(r1.GetEndingJointId(), r2.GetEndingJointId())) + return r1.GetEndingJointId(); return Joint::kInvalidId; } @@ -53,7 +53,7 @@ RestrictionLoader::RestrictionLoader(MwmValue const & mwmValue, IndexGraph const RestrictionVec restrictionsOnly; RestrictionSerializer::Deserialize(m_header, m_restrictions /* restriction no */, restrictionsOnly, src); - ConvertRestrictionOnlyToNo(graph, restrictionsOnly, m_restrictions); + ConvertRestrictionsOnlyToNoAndSort(graph, restrictionsOnly, m_restrictions); } catch (Reader::OpenException const & e) { @@ -63,15 +63,9 @@ RestrictionLoader::RestrictionLoader(MwmValue const & mwmValue, IndexGraph const } } -void ConvertRestrictionOnlyToNo(IndexGraph const & graph, RestrictionVec const & restrictionsOnly, - RestrictionVec & restrictionsNo) +void ConvertRestrictionsOnlyToNoAndSort(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.")); diff --git a/routing/restriction_loader.hpp b/routing/restriction_loader.hpp index 5074a743cb..e41999424c 100644 --- a/routing/restriction_loader.hpp +++ b/routing/restriction_loader.hpp @@ -27,6 +27,6 @@ private: string const m_countryFileName; }; -void ConvertRestrictionOnlyToNo(IndexGraph const & graph, RestrictionVec const & restrictionsOnly, - RestrictionVec & restrictionsNo); +void ConvertRestrictionsOnlyToNoAndSort(IndexGraph const & graph, RestrictionVec const & restrictionsOnly, + RestrictionVec & restrictionsNo); } // namespace routing diff --git a/routing/road_index.hpp b/routing/road_index.hpp index e614fac36b..2f13c83330 100644 --- a/routing/road_index.hpp +++ b/routing/road_index.hpp @@ -29,15 +29,13 @@ public: return Joint::kInvalidId; } - Joint::Id GetLastJointId() const + Joint::Id GetEndingJointId() const { - Joint::Id lastJointId = Joint::kInvalidId; - for (Joint::Id const jointId : m_jointIds) - { - if (jointId != Joint::kInvalidId) - lastJointId = jointId; - } - return lastJointId; + if (m_jointIds.empty()) + return Joint::kInvalidId; + + ASSERT_NOT_EQUAL(m_jointIds.back(), Joint::kInvalidId, ()); + return m_jointIds.back(); } void AddJoint(uint32_t pointId, Joint::Id jointId) @@ -129,7 +127,7 @@ public: RoadJointIds const & GetRoad(uint32_t featureId) const { auto const & it = m_roads.find(featureId); - CHECK(it != m_roads.cend(), ("Feture id:", featureId)); + CHECK(it != m_roads.cend(), ("Feature id:", featureId)); return it->second; } diff --git a/routing/routing_tests/restriction_test.cpp b/routing/routing_tests/restriction_test.cpp index f29089e7ba..72519c6ef8 100644 --- a/routing/routing_tests/restriction_test.cpp +++ b/routing/routing_tests/restriction_test.cpp @@ -191,7 +191,7 @@ UNIT_CLASS_TEST(RestrictionTest, TriangularGraph_RestrictionOnlyF5F3) RestrictionVec restrictionsOnly = { {Restriction::Type::Only, {5 /* feature from */, 3 /* feature to */}}}; RestrictionVec restrictionsNo; - ConvertRestrictionOnlyToNo(*m_graph, restrictionsOnly, restrictionsNo); + ConvertRestrictionsOnlyToNoAndSort(*m_graph, restrictionsOnly, restrictionsNo); vector const expectedGeom = { {3 /* x */, 0 /* y */}, {2, 0}, {1, 0}, {0, 0}, {0, 2}, {0, 3}}; @@ -292,7 +292,7 @@ UNIT_CLASS_TEST(RestrictionTest, TwowayCornerGraph_RestrictionF3F1Only) RestrictionVec restrictionsOnly = { {Restriction::Type::Only, {3 /* feature from */, 1 /* feature to */}}}; RestrictionVec restrictionsNo; - ConvertRestrictionOnlyToNo(*m_graph, restrictionsOnly, restrictionsNo); + ConvertRestrictionsOnlyToNoAndSort(*m_graph, restrictionsOnly, restrictionsNo); vector const expectedGeom = { {3 /* x */, 0 /* y */}, {2, 0}, {1, 0}, {0, 0}, {0, 1}, {0, 2}, {0, 3}}; @@ -385,7 +385,7 @@ UNIT_CLASS_TEST(RestrictionTest, TwoSquaresGraph_RestrictionF10F3Only) RestrictionVec restrictionsOnly = { {Restriction::Type::Only, {10 /* feature from */, 3 /* feature to */}}}; RestrictionVec restrictionsNo; - ConvertRestrictionOnlyToNo(*m_graph, restrictionsOnly, restrictionsNo); + ConvertRestrictionsOnlyToNoAndSort(*m_graph, restrictionsOnly, restrictionsNo); vector const expectedGeom = { {3 /* x */, 0 /* y */}, {2, 0}, {1, 0}, {1, 1}, {0, 2}, {0, 3}}; @@ -403,7 +403,7 @@ UNIT_CLASS_TEST(RestrictionTest, TwoSquaresGraph_RestrictionF10F3OnlyF3F4Only) {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); + ConvertRestrictionsOnlyToNoAndSort(*m_graph, restrictionsOnly, restrictionsNo); vector const expectedGeom = { {3 /* x */, 0 /* y */}, {2, 0}, {1, 0}, {0, 0}, {0, 2}, {0, 3}}; @@ -421,7 +421,7 @@ UNIT_CLASS_TEST(RestrictionTest, TwoSquaresGraph_RestrictionF2F8NoRestrictionF9F {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); + ConvertRestrictionsOnlyToNoAndSort(*m_graph, restrictionsOnly, restrictionsNo); vector const expectedGeom = { {3 /* x */, 0 /* y */}, {2, 0}, {1, 1}, {0, 2}, {0, 3}}; @@ -614,7 +614,7 @@ UNIT_CLASS_TEST(RestrictionTest, PosterGraph_RestrictionF0F1Only) RestrictionVec restrictionsOnly = { {Restriction::Type::Only, {0 /* feature from */, 1 /* feature to */}}}; RestrictionVec restrictionsNo; - ConvertRestrictionOnlyToNo(*m_graph, restrictionsOnly, restrictionsNo); + ConvertRestrictionsOnlyToNoAndSort(*m_graph, restrictionsOnly, restrictionsNo); vector const expectedGeom = { {2 /* x */, 0 /* y */}, {1, 0}, {0, 0}, {0, 1}, {0.5, 1}, {1, 1}, {2, 1}}; From fb95d5b03e8e7a19c73cd27b2758e4d95fea9493 Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Thu, 19 Jan 2017 17:48:44 +0300 Subject: [PATCH 6/8] git-clang-format --- routing/index_graph.cpp | 18 +++++++++--------- routing/index_road_graph.cpp | 3 ++- routing/restriction_loader.cpp | 10 ++++++---- routing/restriction_loader.hpp | 3 ++- routing/restrictions_serialization.hpp | 11 ++++++----- routing/routing_tests/restriction_test.cpp | 8 ++++---- routing/single_mwm_router.cpp | 5 +++-- 7 files changed, 32 insertions(+), 26 deletions(-) diff --git a/routing/index_graph.cpp b/routing/index_graph.cpp index 7677aa4cf3..e373612ac6 100644 --- a/routing/index_graph.cpp +++ b/routing/index_graph.cpp @@ -15,7 +15,8 @@ using namespace base; using namespace routing; using namespace std; -bool IsRestricted(RestrictionVec const & restrictions, 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(); @@ -36,7 +37,8 @@ bool IsRestricted(RestrictionVec const & restrictions, Segment const & u, Segmen // where the U-turn is restricted. It's necessary to pass the data to mwm and to use it here. // Please see test LineGraph_RestrictionF1F1No for details. // - // Another exapmle when it's necessary to be aware about feature end particepated in restriction is + // Another exapmle when it's necessary to be aware about feature end particepated in restriction + // is // *---F1---* // | | // *--F3--A B--F4--* @@ -49,9 +51,8 @@ bool IsRestricted(RestrictionVec const & restrictions, Segment const & u, Segmen bool IsUTurn(Segment const & u, Segment const & v) { - return u.GetFeatureId() == v.GetFeatureId() - && u.GetSegmentIdx() == v.GetSegmentIdx() - && u.IsForward() != v.IsForward(); + return u.GetFeatureId() == v.GetFeatureId() && u.GetSegmentIdx() == v.GetSegmentIdx() && + u.IsForward() != v.IsForward(); } } // namespace @@ -128,10 +129,9 @@ void IndexGraph::GetNeighboringEdge(Segment const & from, Segment const & to, bo { // Blocking U-turns on internal feature points. RoadPoint const rp = from.GetRoadPoint(isOutgoing); - if (IsUTurn(from, to) - && m_roadIndex.GetJointId(rp) == Joint::kInvalidId - && rp.GetPointId() != 0 - && rp.GetPointId() + 1 != m_geometry.GetRoad(from.GetFeatureId()).GetPointsCount()) + if (IsUTurn(from, to) && m_roadIndex.GetJointId(rp) == Joint::kInvalidId && + rp.GetPointId() != 0 && + rp.GetPointId() + 1 != m_geometry.GetRoad(from.GetFeatureId()).GetPointsCount()) { return; } diff --git a/routing/index_road_graph.cpp b/routing/index_road_graph.cpp index c227049a4e..e3af2a1771 100644 --- a/routing/index_road_graph.cpp +++ b/routing/index_road_graph.cpp @@ -89,7 +89,8 @@ const Segment & IndexRoadGraph::GetSegment(Junction const & junction, bool isOut auto const & junctionToSegment = isOutgoing ? m_endToSegment : m_beginToSegment; auto it = junctionToSegment.find(junction); - CHECK(it != junctionToSegment.cend(), ("junctionToSegment doesn't contains", junction, ", isOutgoing =", isOutgoing)); + CHECK(it != junctionToSegment.cend(), + ("junctionToSegment doesn't contains", junction, ", isOutgoing =", isOutgoing)); return it->second; } } // namespace routing diff --git a/routing/restriction_loader.cpp b/routing/restriction_loader.cpp index f559566178..5f2e781758 100644 --- a/routing/restriction_loader.cpp +++ b/routing/restriction_loader.cpp @@ -52,7 +52,8 @@ RestrictionLoader::RestrictionLoader(MwmValue const & mwmValue, IndexGraph const m_header.Deserialize(src); RestrictionVec restrictionsOnly; - RestrictionSerializer::Deserialize(m_header, m_restrictions /* restriction no */, restrictionsOnly, src); + RestrictionSerializer::Deserialize(m_header, m_restrictions /* restriction no */, + restrictionsOnly, src); ConvertRestrictionsOnlyToNoAndSort(graph, restrictionsOnly, m_restrictions); } catch (Reader::OpenException const & e) @@ -63,7 +64,8 @@ RestrictionLoader::RestrictionLoader(MwmValue const & mwmValue, IndexGraph const } } -void ConvertRestrictionsOnlyToNoAndSort(IndexGraph const & graph, RestrictionVec const & restrictionsOnly, +void ConvertRestrictionsOnlyToNoAndSort(IndexGraph const & graph, + RestrictionVec const & restrictionsOnly, RestrictionVec & restrictionsNo) { for (Restriction const & o : restrictionsOnly) @@ -80,11 +82,11 @@ void ConvertRestrictionsOnlyToNoAndSort(IndexGraph const & graph, RestrictionVec // 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){ + 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()})); + Restriction(Restriction::Type::No, {o.m_featureIds[0 /* from */], rp.GetFeatureId()})); } }); } diff --git a/routing/restriction_loader.hpp b/routing/restriction_loader.hpp index e41999424c..6c4e6adbfa 100644 --- a/routing/restriction_loader.hpp +++ b/routing/restriction_loader.hpp @@ -27,6 +27,7 @@ private: string const m_countryFileName; }; -void ConvertRestrictionsOnlyToNoAndSort(IndexGraph const & graph, RestrictionVec const & restrictionsOnly, +void ConvertRestrictionsOnlyToNoAndSort(IndexGraph const & graph, + RestrictionVec const & restrictionsOnly, RestrictionVec & restrictionsNo); } // namespace routing diff --git a/routing/restrictions_serialization.hpp b/routing/restrictions_serialization.hpp index 43d9a24f49..235645e1f5 100644 --- a/routing/restrictions_serialization.hpp +++ b/routing/restrictions_serialization.hpp @@ -37,7 +37,6 @@ struct Restriction }; Restriction(Type type, vector const & links) : m_featureIds(links), m_type(type) {} - bool IsValid() const; bool operator==(Restriction const & restriction) const; bool operator<(Restriction const & restriction) const; @@ -105,11 +104,12 @@ public: } template - static void Deserialize(RestrictionHeader const & header, routing::RestrictionVec & restrictionsNo, + static void Deserialize(RestrictionHeader const & header, + routing::RestrictionVec & restrictionsNo, routing::RestrictionVec & restrictionsOnly, Source & src) { - DeserializeSingleType(routing::Restriction::Type::No, header.m_noRestrictionCount, restrictionsNo, - src); + DeserializeSingleType(routing::Restriction::Type::No, header.m_noRestrictionCount, + restrictionsNo, src); DeserializeSingleType(routing::Restriction::Type::Only, header.m_onlyRestrictionCount, restrictionsOnly, src); } @@ -183,7 +183,8 @@ private: LOG(LERROR, ("Decoded first link restriction feature id delta is zero.")); return false; } - restriction.m_featureIds[0] = prevFirstLinkFeatureId + base::checked_cast(biasedFirstFeatureId) - 1; + restriction.m_featureIds[0] = + prevFirstLinkFeatureId + base::checked_cast(biasedFirstFeatureId) - 1; for (size_t i = 1; i < numLinks; ++i) { auto const biasedDelta = coding::DeltaCoder::Decode(bits); diff --git a/routing/routing_tests/restriction_test.cpp b/routing/routing_tests/restriction_test.cpp index 72519c6ef8..04e50bf184 100644 --- a/routing/routing_tests/restriction_test.cpp +++ b/routing/routing_tests/restriction_test.cpp @@ -418,13 +418,13 @@ UNIT_CLASS_TEST(RestrictionTest, TwoSquaresGraph_RestrictionF2F8NoRestrictionF9F { Init(BuildTwoSquaresGraph()); RestrictionVec restrictionsNo = { - {Restriction::Type::No, {2 /* feature from */, 8 /* feature to */}}}; // Invalid restriction. + {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. + {Restriction::Type::Only, + {9 /* feature from */, 1 /* feature to */}}}; // Invalid restriction. ConvertRestrictionsOnlyToNoAndSort(*m_graph, restrictionsOnly, restrictionsNo); - vector const expectedGeom = { - {3 /* x */, 0 /* y */}, {2, 0}, {1, 1}, {0, 2}, {0, 3}}; + vector const expectedGeom = {{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 */, diff --git a/routing/single_mwm_router.cpp b/routing/single_mwm_router.cpp index 93365a5316..345d327113 100644 --- a/routing/single_mwm_router.cpp +++ b/routing/single_mwm_router.cpp @@ -208,8 +208,9 @@ 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); From 7616a0d2605a2739e1c2d937a084b25520e377e3 Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Fri, 20 Jan 2017 10:53:58 +0300 Subject: [PATCH 7/8] Review fixes. --- routing/geometry.hpp | 5 +++++ routing/index_graph.cpp | 9 ++++----- routing/index_graph.hpp | 3 +-- routing/restriction_loader.cpp | 5 +++-- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/routing/geometry.hpp b/routing/geometry.hpp index c172f4cf88..af7acd9f4b 100644 --- a/routing/geometry.hpp +++ b/routing/geometry.hpp @@ -42,6 +42,11 @@ public: // In such cases RoadGeometry is not valid. bool IsValid() const { return m_valid; } + bool IsEndPointId(uint32_t pointId) const + { + return pointId == 0 || pointId + 1 == GetPointsCount(); + } + private: Points m_points; double m_speed = 0.0; diff --git a/routing/index_graph.cpp b/routing/index_graph.cpp index e373612ac6..328ebdbda5 100644 --- a/routing/index_graph.cpp +++ b/routing/index_graph.cpp @@ -37,7 +37,7 @@ bool IsRestricted(RestrictionVec const & restrictions, Segment const & u, Segmen // where the U-turn is restricted. It's necessary to pass the data to mwm and to use it here. // Please see test LineGraph_RestrictionF1F1No for details. // - // Another exapmle when it's necessary to be aware about feature end particepated in restriction + // Another example when it's necessary to be aware about feature end participated in restriction // is // *---F1---* // | | @@ -129,9 +129,8 @@ void IndexGraph::GetNeighboringEdge(Segment const & from, Segment const & to, bo { // Blocking U-turns on internal feature points. RoadPoint const rp = from.GetRoadPoint(isOutgoing); - if (IsUTurn(from, to) && m_roadIndex.GetJointId(rp) == Joint::kInvalidId && - rp.GetPointId() != 0 && - rp.GetPointId() + 1 != m_geometry.GetRoad(from.GetFeatureId()).GetPointsCount()) + if (IsUTurn(from, to) && m_roadIndex.GetJointId(rp) == Joint::kInvalidId + && !m_geometry.GetRoad(from.GetFeatureId()).IsEndPointId(rp.GetPointId())) { return; } @@ -145,7 +144,7 @@ void IndexGraph::GetNeighboringEdge(Segment const & from, Segment const & to, bo edges.emplace_back(to, weight); } -double IndexGraph::GetPenalties(Segment const & u, Segment const & v) +double IndexGraph::GetPenalties(Segment const & u, Segment const & v) const { if (IsUTurn(u, v)) return GetEstimator().GetUTurnPenalty(); diff --git a/routing/index_graph.hpp b/routing/index_graph.hpp index 6c218b789e..ddcf96e688 100644 --- a/routing/index_graph.hpp +++ b/routing/index_graph.hpp @@ -67,13 +67,12 @@ private: vector & edges); void GetNeighboringEdge(Segment const & from, Segment const & to, bool isOutgoing, vector & edges); - double GetPenalties(Segment const & u, Segment const & v); + double GetPenalties(Segment const & u, Segment const & v) const; Geometry m_geometry; shared_ptr m_estimator; RoadIndex m_roadIndex; JointIndex m_jointIndex; - RestrictionVec m_restrictions; }; } // namespace routing diff --git a/routing/restriction_loader.cpp b/routing/restriction_loader.cpp index 5f2e781758..bee841182b 100644 --- a/routing/restriction_loader.cpp +++ b/routing/restriction_loader.cpp @@ -9,8 +9,8 @@ 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. +/// If not, returns Joint::kInvalidId. +/// \note It's possible that the both ends of |r1| and |r2| have 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 @@ -61,6 +61,7 @@ RestrictionLoader::RestrictionLoader(MwmValue const & mwmValue, IndexGraph const m_header.Reset(); LOG(LERROR, ("File", m_countryFileName, "Error while reading", RESTRICTIONS_FILE_TAG, "section.", e.Msg())); + throw; } } From 186fb3fa63305f790f20596cff833e2ce353cca5 Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Thu, 26 Jan 2017 12:01:09 +0300 Subject: [PATCH 8/8] Review fixes. --- routing/geometry.hpp | 1 + routing/index_graph.cpp | 16 +++++++--------- routing/index_road_graph.cpp | 4 ++-- routing/restriction_loader.cpp | 31 ++++++++++++++----------------- 4 files changed, 24 insertions(+), 28 deletions(-) diff --git a/routing/geometry.hpp b/routing/geometry.hpp index af7acd9f4b..818290e54f 100644 --- a/routing/geometry.hpp +++ b/routing/geometry.hpp @@ -44,6 +44,7 @@ public: bool IsEndPointId(uint32_t pointId) const { + ASSERT_LESS(pointId, m_points.size(), ()); return pointId == 0 || pointId + 1 == GetPointsCount(); } diff --git a/routing/index_graph.cpp b/routing/index_graph.cpp index 328ebdbda5..4ae83899a5 100644 --- a/routing/index_graph.cpp +++ b/routing/index_graph.cpp @@ -15,13 +15,18 @@ using namespace base; using namespace routing; using namespace std; +bool IsUTurn(Segment const & u, Segment const & v) +{ + return u.GetFeatureId() == v.GetFeatureId() && u.GetSegmentIdx() == v.GetSegmentIdx() && + u.IsForward() != v.IsForward(); +} + 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(); - // Looking for at least one restriction of type No from |featureIdFrom| to |featureIdTo|. if (!binary_search(restrictions.cbegin(), restrictions.cend(), Restriction(Restriction::Type::No, {featureIdFrom, featureIdTo}))) { @@ -46,13 +51,7 @@ bool IsRestricted(RestrictionVec const & restrictions, Segment const & u, Segmen // *---F2---* // In case of restriction F1-A-F2 or F1-B-F2 of any type (No, Only) the important information // is lost. - return u.GetSegmentIdx() == v.GetSegmentIdx() && u.IsForward() != v.IsForward(); -} - -bool IsUTurn(Segment const & u, Segment const & v) -{ - return u.GetFeatureId() == v.GetFeatureId() && u.GetSegmentIdx() == v.GetSegmentIdx() && - u.IsForward() != v.IsForward(); + return IsUTurn(u, v); } } // namespace @@ -135,7 +134,6 @@ void IndexGraph::GetNeighboringEdge(Segment const & from, Segment const & to, bo return; } - // Blocking restriction edges. if (IsRestricted(m_restrictions, from, to, isOutgoing)) return; diff --git a/routing/index_road_graph.cpp b/routing/index_road_graph.cpp index e3af2a1771..ab5d45b81d 100644 --- a/routing/index_road_graph.cpp +++ b/routing/index_road_graph.cpp @@ -88,9 +88,9 @@ const Segment & IndexRoadGraph::GetSegment(Junction const & junction, bool isOut { auto const & junctionToSegment = isOutgoing ? m_endToSegment : m_beginToSegment; - auto it = junctionToSegment.find(junction); + auto const it = junctionToSegment.find(junction); CHECK(it != junctionToSegment.cend(), - ("junctionToSegment doesn't contains", junction, ", isOutgoing =", isOutgoing)); + ("junctionToSegment doesn't contain", junction, ", isOutgoing =", isOutgoing)); return it->second; } } // namespace routing diff --git a/routing/restriction_loader.cpp b/routing/restriction_loader.cpp index bee841182b..44efd6aace 100644 --- a/routing/restriction_loader.cpp +++ b/routing/restriction_loader.cpp @@ -17,21 +17,16 @@ using namespace routing; /// point there has to be a joint. So the method is valid. Joint::Id GetCommonEndJoint(RoadJointIds const & r1, RoadJointIds const & r2) { - auto const IsEqual = [](Joint::Id j1, Joint::Id j2) { - return j1 != Joint::kInvalidId && j1 == j2; - }; + auto const & j11 = r1.GetJointId(0 /* point id */); + auto const & j12 = r1.GetEndingJointId(); + auto const & j21 = r2.GetJointId(0 /* point id */); + auto const & j22 = r2.GetEndingJointId(); - if (IsEqual(r1.GetJointId(0 /* point id */), r2.GetEndingJointId())) - return r1.GetJointId(0); + if (j11 == j21 || j11 == j22) + return j11; - if (IsEqual(r1.GetJointId(0 /* point id */), r2.GetJointId(0 /* point id */))) - return r1.GetJointId(0); - - if (IsEqual(r1.GetEndingJointId(), r2.GetJointId(0 /* point id */))) - return r1.GetEndingJointId(); - - if (IsEqual(r1.GetEndingJointId(), r2.GetEndingJointId())) - return r1.GetEndingJointId(); + if (j12 == j21 || j12 == j22) + return j12; return Joint::kInvalidId; } @@ -52,7 +47,7 @@ RestrictionLoader::RestrictionLoader(MwmValue const & mwmValue, IndexGraph const m_header.Deserialize(src); RestrictionVec restrictionsOnly; - RestrictionSerializer::Deserialize(m_header, m_restrictions /* restriction no */, + RestrictionSerializer::Deserialize(m_header, m_restrictions /* restriction No */, restrictionsOnly, src); ConvertRestrictionsOnlyToNoAndSort(graph, restrictionsOnly, m_restrictions); } @@ -71,7 +66,9 @@ void ConvertRestrictionsOnlyToNoAndSort(IndexGraph const & graph, { for (Restriction const & o : restrictionsOnly) { - CHECK_EQUAL(o.m_featureIds.size(), 2, ("Only two link restrictions are support.")); + if (o.m_featureIds.size() != 2) + continue; + if (!graph.IsRoad(o.m_featureIds[0]) || !graph.IsRoad(o.m_featureIds[1])) continue; @@ -86,8 +83,8 @@ void ConvertRestrictionsOnlyToNoAndSort(IndexGraph const & graph, 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()})); + restrictionsNo.emplace_back(Restriction::Type::No, + vector({o.m_featureIds[0 /* from */], rp.GetFeatureId()})); } }); }