Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'routing/routing_tests')
-rw-r--r--routing/routing_tests/index_graph_test.cpp71
-rw-r--r--routing/routing_tests/index_graph_tools.cpp84
-rw-r--r--routing/routing_tests/index_graph_tools.hpp46
-rw-r--r--routing/routing_tests/restriction_test.cpp622
-rw-r--r--routing/routing_tests/routing_tests.pro3
5 files changed, 765 insertions, 61 deletions
diff --git a/routing/routing_tests/index_graph_test.cpp b/routing/routing_tests/index_graph_test.cpp
index 3458b7cd8e..da2ff816cf 100644
--- a/routing/routing_tests/index_graph_test.cpp
+++ b/routing/routing_tests/index_graph_test.cpp
@@ -1,5 +1,7 @@
#include "testing/testing.hpp"
+#include "routing/routing_tests/index_graph_tools.hpp"
+
#include "routing/base/astar_algorithm.hpp"
#include "routing/car_model.hpp"
#include "routing/edge_estimator.hpp"
@@ -18,75 +20,20 @@
namespace
{
using namespace routing;
-
-class TestGeometryLoader final : public GeometryLoader
-{
-public:
- // GeometryLoader overrides:
- void Load(uint32_t featureId, RoadGeometry & road) const override;
-
- void AddRoad(uint32_t featureId, bool oneWay, RoadGeometry::Points const & points);
-
-private:
- unordered_map<uint32_t, RoadGeometry> m_roads;
-};
-
-void TestGeometryLoader::Load(uint32_t featureId, RoadGeometry & road) const
-{
- auto it = m_roads.find(featureId);
- if (it == m_roads.cend())
- return;
-
- road = it->second;
-}
-
-void TestGeometryLoader::AddRoad(uint32_t featureId, bool oneWay,
- RoadGeometry::Points const & points)
-{
- auto it = m_roads.find(featureId);
- if (it != m_roads.end())
- {
- ASSERT(false, ("Already contains feature", featureId));
- return;
- }
-
- m_roads[featureId] = RoadGeometry(oneWay, 1.0 /* speed */, points);
-}
-
-Joint MakeJoint(vector<RoadPoint> const & points)
-{
- Joint joint;
- for (auto const & point : points)
- joint.AddPoint(point);
-
- return joint;
-}
-
-shared_ptr<EdgeEstimator> CreateEstimator()
-{
- return EdgeEstimator::CreateForCar(*make_shared<CarModelFactory>()->GetVehicleModel());
-}
+using namespace routing_test;
void TestRoute(IndexGraph const & graph, RoadPoint const & start, RoadPoint const & finish,
size_t expectedLength, vector<RoadPoint> const * expectedRoute = nullptr)
{
- LOG(LINFO, ("Test route", start.GetFeatureId(), ",", start.GetPointId(), "=>",
- finish.GetFeatureId(), ",", finish.GetPointId()));
-
- AStarAlgorithm<IndexGraphStarter> algorithm;
- RoutingResult<Joint::Id> routingResult;
-
+ vector<RoadPoint> route;
IndexGraphStarter starter(graph, start, finish);
- auto const resultCode = algorithm.FindPath(starter, starter.GetStartJoint(),
- starter.GetFinishJoint(), routingResult, {}, {});
- TEST_EQUAL(resultCode, AStarAlgorithm<IndexGraphStarter>::Result::OK, ());
+ AStarAlgorithm<IndexGraphStarter>::Result const resultCode = CalculateRoute(starter, route);
- vector<RoadPoint> roadPoints;
- starter.RedressRoute(routingResult.path, roadPoints);
- TEST_EQUAL(roadPoints.size(), expectedLength, ());
+ TEST_EQUAL(resultCode, AStarAlgorithm<IndexGraphStarter>::Result::OK, ());
+ TEST_EQUAL(route.size(), expectedLength, ());
if (expectedRoute != nullptr)
- TEST_EQUAL(roadPoints, *expectedRoute, ());
+ TEST_EQUAL(route, *expectedRoute, ());
}
void TestEdges(IndexGraph const & graph, Joint::Id jointId,
@@ -244,6 +191,7 @@ UNIT_TEST(FindPathManhattan)
street.emplace_back(static_cast<double>(i), static_cast<double>(j));
avenue.emplace_back(static_cast<double>(j), static_cast<double>(i));
}
+
loader->AddRoad(i, false, street);
loader->AddRoad(i + kCitySize, false, avenue);
}
@@ -256,6 +204,7 @@ UNIT_TEST(FindPathManhattan)
for (uint32_t j = 0; j < kCitySize; ++j)
joints.emplace_back(MakeJoint({{i, j}, {j + kCitySize, i}}));
}
+
graph.Import(joints);
for (uint32_t startY = 0; startY < kCitySize; ++startY)
diff --git a/routing/routing_tests/index_graph_tools.cpp b/routing/routing_tests/index_graph_tools.cpp
new file mode 100644
index 0000000000..eba158a256
--- /dev/null
+++ b/routing/routing_tests/index_graph_tools.cpp
@@ -0,0 +1,84 @@
+#include "routing/routing_tests/index_graph_tools.hpp"
+
+#include "testing/testing.hpp"
+
+#include "routing/car_model.hpp"
+
+namespace routing_test
+{
+using namespace routing;
+
+void TestGeometryLoader::Load(uint32_t featureId, RoadGeometry & road) const
+{
+ auto it = m_roads.find(featureId);
+ if (it == m_roads.cend())
+ return;
+
+ road = it->second;
+}
+
+void TestGeometryLoader::AddRoad(uint32_t featureId, bool oneWay,
+ RoadGeometry::Points const & points)
+{
+ auto it = m_roads.find(featureId);
+ if (it != m_roads.end())
+ {
+ ASSERT(false, ("Already contains feature", featureId));
+ return;
+ }
+
+ m_roads[featureId] = RoadGeometry(oneWay, 1.0 /* speed */, points);
+}
+
+Joint MakeJoint(vector<RoadPoint> const & points)
+{
+ Joint joint;
+ for (auto const & point : points)
+ joint.AddPoint(point);
+
+ return joint;
+}
+
+shared_ptr<EdgeEstimator> CreateEstimator()
+{
+ return EdgeEstimator::CreateForCar(*make_shared<CarModelFactory>()->GetVehicleModel());
+}
+
+AStarAlgorithm<IndexGraphStarter>::Result CalculateRoute(IndexGraphStarter const & starter,
+ vector<RoadPoint> & roadPoints)
+{
+ AStarAlgorithm<IndexGraphStarter> algorithm;
+ RoutingResult<Joint::Id> routingResult;
+ AStarAlgorithm<IndexGraphStarter>::Result const resultCode = algorithm.FindPath(
+ starter, starter.GetStartJoint(), starter.GetFinishJoint(), routingResult, {}, {});
+
+ starter.RedressRoute(routingResult.path, roadPoints);
+ return resultCode;
+}
+
+void TestRouteSegments(IndexGraphStarter const & starter,
+ AStarAlgorithm<IndexGraphStarter>::Result expectedRouteResult,
+ vector<RoadPoint> const & expectedRoute)
+{
+ vector<RoadPoint> route;
+ AStarAlgorithm<IndexGraphStarter>::Result const resultCode = CalculateRoute(starter, route);
+ TEST_EQUAL(resultCode, expectedRouteResult, ());
+ TEST_EQUAL(route, expectedRoute, ());
+}
+
+void TestRouteGeometry(IndexGraphStarter const & starter,
+ AStarAlgorithm<IndexGraphStarter>::Result expectedRouteResult,
+ vector<m2::PointD> const & expectedRouteGeom)
+{
+ vector<RoadPoint> route;
+ AStarAlgorithm<IndexGraphStarter>::Result const resultCode = CalculateRoute(starter, route);
+ TEST_EQUAL(resultCode, expectedRouteResult, ());
+ TEST_EQUAL(route.size(), expectedRouteGeom.size(), ());
+ for (size_t i = 0; i < route.size(); ++i)
+ {
+ RoadGeometry roadGeom = starter.GetGraph().GetRoad(route[i].GetFeatureId());
+ CHECK_LESS(route[i].GetPointId(), roadGeom.GetPointsCount(), ());
+ TEST_EQUAL(expectedRouteGeom[i], roadGeom.GetPoint(route[i].GetPointId()), ());
+ }
+}
+} // namespace routing_test
diff --git a/routing/routing_tests/index_graph_tools.hpp b/routing/routing_tests/index_graph_tools.hpp
new file mode 100644
index 0000000000..7a5482430f
--- /dev/null
+++ b/routing/routing_tests/index_graph_tools.hpp
@@ -0,0 +1,46 @@
+#pragma once
+
+#include "routing/edge_estimator.hpp"
+#include "routing/index_graph.hpp"
+#include "routing/index_graph_starter.hpp"
+#include "routing/road_point.hpp"
+
+#include "routing/base/astar_algorithm.hpp"
+
+#include "geometry/point2d.hpp"
+
+#include "std/algorithm.hpp"
+#include "std/shared_ptr.hpp"
+#include "std/unique_ptr.hpp"
+#include "std/unordered_map.hpp"
+#include "std/vector.hpp"
+
+namespace routing_test
+{
+class TestGeometryLoader final : public routing::GeometryLoader
+{
+public:
+ // GeometryLoader overrides:
+ void Load(uint32_t featureId, routing::RoadGeometry & road) const override;
+
+ void AddRoad(uint32_t featureId, bool oneWay, routing::RoadGeometry::Points const & points);
+
+private:
+ unordered_map<uint32_t, routing::RoadGeometry> m_roads;
+};
+
+routing::Joint MakeJoint(vector<routing::RoadPoint> const & points);
+
+shared_ptr<routing::EdgeEstimator> CreateEstimator();
+
+routing::AStarAlgorithm<routing::IndexGraphStarter>::Result CalculateRoute(
+ routing::IndexGraphStarter const & graph, vector<routing::RoadPoint> & roadPoints);
+
+void TestRouteSegments(routing::IndexGraphStarter const & starter,
+ routing::AStarAlgorithm<routing::IndexGraphStarter>::Result expectedRouteResult,
+ vector<routing::RoadPoint> const & expectedRoute);
+
+void TestRouteGeometry(routing::IndexGraphStarter const & starter,
+ routing::AStarAlgorithm<routing::IndexGraphStarter>::Result expectedRouteResult,
+ vector<m2::PointD> const & expectedRouteGeom);
+} // 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..895481763e
--- /dev/null
+++ b/routing/routing_tests/restriction_test.cpp
@@ -0,0 +1,622 @@
+#include "testing/testing.hpp"
+
+#include "routing/routing_tests/index_graph_tools.hpp"
+
+#include "routing/car_model.hpp"
+
+#include "routing/geometry.hpp"
+#include "geometry/point2d.hpp"
+
+#include "std/unique_ptr.hpp"
+#include "std/vector.hpp"
+
+namespace
+{
+using namespace routing;
+using namespace routing_test;
+
+void TestRoutes(vector<RoadPoint> const & starts,
+ vector<RoadPoint> const & finishes,
+ vector<vector<RoadPoint>> const & expectedRoutes,
+ IndexGraph & graph)
+{
+ CHECK_EQUAL(starts.size(), expectedRoutes.size(), ());
+ CHECK_EQUAL(finishes.size(), expectedRoutes.size(), ());
+
+ for (size_t i = 0; i < expectedRoutes.size(); ++i)
+ {
+ IndexGraphStarter starter(graph, starts[i], finishes[i]);
+ TestRouteSegments(starter, AStarAlgorithm<IndexGraphStarter>::Result::OK, expectedRoutes[i]);
+ }
+}
+
+void EdgeTest(Joint::Id vertex, size_t expectedIntgoingNum, size_t expectedOutgoingNum,
+ IndexGraph & graph)
+{
+ vector<IndexGraphStarter::TEdgeType> ingoing;
+ graph.GetEdgesList(vertex, false /* is outgoing */, ingoing);
+ TEST_EQUAL(ingoing.size(), expectedIntgoingNum, ());
+
+ vector<IndexGraphStarter::TEdgeType> outgoing;
+ graph.GetEdgesList(vertex, true /* is outgoing */, outgoing);
+ TEST_EQUAL(outgoing.size(), expectedOutgoingNum, ());
+}
+
+// Finish
+// 2 *
+// ^ ↖
+// | F1
+// | ↖
+// 1 | *
+// F0 ↖
+// | F2
+// | ↖
+// 0 *<--F3---<--F3---* Start
+// 0 1 2
+// Note. F0, F1 and F2 are one segment features. F3 is a two segments feature.
+unique_ptr<IndexGraph> BuildTriangularGraph()
+{
+ auto const loader = []()
+ {
+ unique_ptr<TestGeometryLoader> loader = make_unique<TestGeometryLoader>();
+ loader->AddRoad(0 /* featureId */, true /* oneWay */, buffer_vector<m2::PointD, 32>(
+ {{0.0, 0.0}, {0.0, 2.0}}));
+ loader->AddRoad(1 /* featureId */, true /* oneWay */, buffer_vector<m2::PointD, 32>(
+ {{1.0, 1.0}, {0.0, 2.0}}));
+ loader->AddRoad(2 /* featureId */, true /* oneWay */, buffer_vector<m2::PointD, 32>(
+ {{0.0, 2.0}, {1.0, 1.0}}));
+ loader->AddRoad(3 /* featureId */, true /* oneWay */, buffer_vector<m2::PointD, 32>(
+ {{2.0, 0.0}, {1.0, 0.0}, {0.0, 0.0}}));
+ return loader;
+ };
+
+ vector<Joint> const joints = {MakeJoint({{2, 0}, {3, 0}}), /* 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}}) /* joint at point (0, 2) */
+ };
+
+ unique_ptr<IndexGraph> graph = make_unique<IndexGraph>(loader(), CreateEstimator());
+ graph->Import(joints);
+ return graph;
+}
+
+// Route through triangular graph without any restrictions.
+UNIT_TEST(TriangularGraph)
+{
+ unique_ptr<IndexGraph> graph = BuildTriangularGraph();
+ IndexGraphStarter starter(*graph, RoadPoint(2, 0) /* start */, RoadPoint(1, 1) /* finish */);
+ vector<RoadPoint> const expectedRoute = {{2 /* feature id */, 0 /* seg id */},
+ {2, 1}, {1, 1}};
+ TestRouteSegments(starter, AStarAlgorithm<IndexGraphStarter>::Result::OK, expectedRoute);
+}
+
+// Route through triangular graph with feature 2 disabled.
+UNIT_TEST(TriangularGraph_DisableF2)
+{
+ unique_ptr<IndexGraph> graph = BuildTriangularGraph();
+ graph->DisableEdge(graph->GetJointIdForTesting({2 /* feature id */, 0 /* point id */}),
+ graph->GetJointIdForTesting({2, 1}));
+
+ IndexGraphStarter starter(*graph, RoadPoint(2, 0) /* start */, RoadPoint(1, 1) /* finish */);
+ vector<RoadPoint> const expectedRouteOneEdgeRemoved = {{3 /* feature id */, 0 /* seg id */},
+ {3, 1}, {3, 2}, {0, 1}};
+ TestRouteSegments(starter, AStarAlgorithm<IndexGraphStarter>::Result::OK,
+ expectedRouteOneEdgeRemoved);
+}
+
+// Route through triangular graph with restriction type no from feature 2 to feature 1.
+UNIT_TEST(TriangularGraph_RestrictionNoF2F1)
+{
+ unique_ptr<IndexGraph> graph = BuildTriangularGraph();
+ graph->ApplyRestrictionNo({2 /* feature id */, 1 /* seg id */}, {1, 0},
+ graph->GetJointIdForTesting({1, 0}));
+
+ IndexGraphStarter starter(*graph, RoadPoint(2, 0) /* start */, RoadPoint(1, 1) /* finish */);
+ vector<RoadPoint> const expectedRouteRestrictionF2F1No = {{3 /* feature id */, 0 /* seg id */},
+ {3, 1}, {3, 2}, {0, 1}};
+ TestRouteSegments(starter, AStarAlgorithm<IndexGraphStarter>::Result::OK,
+ expectedRouteRestrictionF2F1No);
+}
+
+// Finish
+// 2 *
+// ^ ↖
+// | ↖
+// | ↖
+// 1 | Fake adding one link feature
+// F0 ↖
+// | ↖
+// | ↖
+// 0 *<--F1---<--F1--* Start
+// 0 1 2
+// Note. F1 is a two setments feature. The others are one setment ones.
+unique_ptr<IndexGraph> BuildCornerGraph()
+{
+ auto const loader = []()
+ {
+ unique_ptr<TestGeometryLoader> loader = make_unique<TestGeometryLoader>();
+ loader->AddRoad(0 /* feature id */, true /* oneWay */, buffer_vector<m2::PointD, 32>(
+ {{0.0, 0.0}, {0.0, 2.0}}));
+ loader->AddRoad(1 /* feature id */, true /* oneWay */, buffer_vector<m2::PointD, 32>(
+ {{2.0, 0.0}, {1.0, 0.0}, {0.0, 0.0}}));
+ return loader;
+ };
+
+ vector<Joint> const joints =
+ {MakeJoint({{1 /* feature id */, 2 /* point id */}, {0, 0}}), /* joint at point (0, 0) */};
+
+ unique_ptr<IndexGraph> graph = make_unique<IndexGraph>(loader(), CreateEstimator());
+ graph->Import(joints);
+ graph->InsertJoint({1 /* feature id */, 0 /* point id */}); // Start joint.
+ graph->InsertJoint({0 /* feature id */, 1 /* point id */}); // Finish joint.
+ return graph;
+}
+
+// Route through corner graph without any restrictions.
+UNIT_TEST(CornerGraph)
+{
+ unique_ptr<IndexGraph> graph = BuildCornerGraph();
+
+ // Route along F1 and F0.
+ IndexGraphStarter starter(*graph, RoadPoint(1, 0) /* start */, RoadPoint(0, 1) /* finish */);
+ vector<RoadPoint> const expectedRoute = {{1 /* feature id */, 0 /* point id */},
+ {1, 1}, {1, 2}, {0, 1}};
+ TestRouteSegments(starter, AStarAlgorithm<IndexGraphStarter>::Result::OK, expectedRoute);
+}
+
+// Generate geometry based on feature 1 of corner graph.
+UNIT_TEST(CornerGraph_CreateFakeFeature1Geometry)
+{
+ unique_ptr<IndexGraph> graph = BuildCornerGraph();
+
+ vector<vector<RoadPoint>> oneEdgeConnectionPaths;
+ graph->GetConnectionPaths(graph->GetJointIdForTesting({1 /* feature id */, 0 /* point id */}),
+ graph->GetJointIdForTesting({1, 2}), oneEdgeConnectionPaths);
+ TEST_EQUAL(oneEdgeConnectionPaths.size(), 1, ());
+
+ vector<RoadPoint> const expectedDirectOrder = {{1, 0}, {1, 1}, {1, 2}};
+ TEST_EQUAL(oneEdgeConnectionPaths[0], expectedDirectOrder, ());
+ RoadGeometry geometryDirect;
+ graph->CreateFakeFeatureGeometry(oneEdgeConnectionPaths[0], geometryDirect);
+ RoadGeometry expectedGeomentryDirect(true /* one way */, 1.0 /* speed */,
+ buffer_vector<m2::PointD, 32>({{2.0, 0.0}, {1.0, 0.0},
+ {0.0, 0.0}}));
+ TEST_EQUAL(geometryDirect, expectedGeomentryDirect, ());
+}
+
+// Generate geometry based on reversed feature 1 of corner graph.
+UNIT_TEST(CornerGraph_CreateFakeReversedFeature1Geometry)
+{
+ unique_ptr<IndexGraph> graph = BuildCornerGraph();
+
+ vector<vector<RoadPoint>> oneEdgeConnectionPaths;
+ graph->GetConnectionPaths(graph->GetJointIdForTesting({1 /* feature id */, 2 /* point id */}),
+ graph->GetJointIdForTesting({1, 0}), oneEdgeConnectionPaths);
+ TEST_EQUAL(oneEdgeConnectionPaths.size(), 1, ());
+
+ vector<RoadPoint> const expectedBackOrder = {{1, 2}, {1, 1}, {1, 0}};
+ TEST_EQUAL(oneEdgeConnectionPaths[0], expectedBackOrder, ());
+ RoadGeometry geometryBack;
+ graph->CreateFakeFeatureGeometry(oneEdgeConnectionPaths[0], geometryBack);
+ RoadGeometry expectedGeomentryBack(true /* one way */, 1.0 /* speed */,
+ buffer_vector<m2::PointD, 32>({{0.0, 0.0}, {1.0, 0.0},
+ {2.0, 0.0}}));
+ TEST_EQUAL(geometryBack, expectedGeomentryBack, ());
+}
+
+// Route through corner graph with adding a fake edge.
+UNIT_TEST(CornerGraph_AddFakeFeature)
+{
+ RoadPoint const kStart(1, 0);
+ RoadPoint const kFinish(0, 1);
+ unique_ptr<IndexGraph> graph = BuildCornerGraph();
+
+ graph->AddFakeFeature(graph->GetJointIdForTesting(kStart), graph->GetJointIdForTesting(kFinish),
+ {kStart, kFinish} /* geometrySource */);
+
+ IndexGraphStarter starter(*graph, kStart, kFinish);
+ vector<RoadPoint> const expectedRouteByFakeFeature = {{IndexGraph::kStartFakeFeatureIds, 0 /* seg id */},
+ {IndexGraph::kStartFakeFeatureIds, 1 /* seg id */}};
+ TestRouteSegments(starter, AStarAlgorithm<IndexGraphStarter>::Result::OK, expectedRouteByFakeFeature);
+}
+
+// Finish 2 Finish 1 Finish 0
+// 2 *<---F5----*<---F6---*
+// ^ ↖ ^ ↖ ^
+// | Fake-1 | Fake-0 |
+// | ↖ F1 ↖ F2
+// | ↖ | ↖ |
+// 1 F0 * *
+// | ^ ↖ ^
+// | F1 Fake-2 F2
+// | | ↖ |
+// 0 *<----F4---*<---F3----* Start
+// 0 1 2
+// Note. F1 and F2 are two segments features. The others are one segment ones.
+unique_ptr<IndexGraph> BuildTwoSquaresGraph()
+{
+ auto const loader = []()
+ {
+ unique_ptr<TestGeometryLoader> loader = make_unique<TestGeometryLoader>();
+ loader->AddRoad(0 /* feature id */, true /* oneWay */, buffer_vector<m2::PointD, 32>(
+ {{0.0, 0.0}, {0.0, 2.0}}));
+ loader->AddRoad(1 /* feature id */, true /* oneWay */, buffer_vector<m2::PointD, 32>(
+ {{1.0, 0.0}, {1.0, 1.0}, {1.0, 2.0}}));
+ loader->AddRoad(2 /* feature id */, true /* oneWay */, buffer_vector<m2::PointD, 32>(
+ {{2.0, 0.0}, {2.0, 1.0}, {2.0, 2.0}}));
+ loader->AddRoad(3 /* feature id */, true /* oneWay */, buffer_vector<m2::PointD, 32>(
+ {{2.0, 0.0}, {1.0, 0.0}}));
+ loader->AddRoad(4 /* feature id */, true /* oneWay */, buffer_vector<m2::PointD, 32>(
+ {{1.0, 0.0}, {0.0, 0.0}}));
+ loader->AddRoad(5 /* feature id */, true /* oneWay */, buffer_vector<m2::PointD, 32>(
+ {{1.0, 2.0}, {0.0, 2.0}}));
+ loader->AddRoad(6 /* feature id */, true /* oneWay */, buffer_vector<m2::PointD, 32>(
+ {{2.0, 2.0}, {1.0, 2.0}}));
+ return loader;
+ };
+
+ vector<Joint> const joints = {
+ MakeJoint({{4 /* featureId */, 1 /* pointId */}, {0, 0}}), /* joint at point (0, 0) */
+ MakeJoint({{0, 1}, {5, 1}}), /* joint at point (0, 2) */
+ MakeJoint({{4, 0}, {1, 0}, {3, 1}}), /* joint at point (1, 0) */
+ MakeJoint({{5, 0}, {1, 2}, {6, 1}}), /* joint at point (1, 2) */
+ MakeJoint({{3, 0}, {2, 0}}), /* joint at point (2, 0) */
+ MakeJoint({{2, 2}, {6, 0}}), /* joint at point (2, 2) */
+ };
+
+ unique_ptr<IndexGraph> graph = make_unique<IndexGraph>(loader(), CreateEstimator());
+ graph->Import(joints);
+ return graph;
+}
+
+// Route through two squares graph without any restrictions.
+UNIT_TEST(TwoSquaresGraph)
+{
+ unique_ptr<IndexGraph> graph = BuildTwoSquaresGraph();
+
+ vector<RoadPoint> const starts = {{2 /* feature id */, 0 /* point id */}, {2, 0}, {2, 0}};
+ vector<RoadPoint> const finishes = {{6 /* feature id */, 0 /* point id */}, {6, 1}, {5, 1}};
+ vector<RoadPoint> const expectedRoute0 = {{2 /* feature id */, 0 /* point id */},
+ {2, 1}, {2, 2}};
+ vector<RoadPoint> const expectedRoute1 = {{2 /* feature id */, 0 /* point id */},
+ {2, 1}, {2, 2}, {6, 1}};
+ vector<RoadPoint> const expectedRoute2 = {{2 /* feature id */, 0 /* point id */},
+ {2, 1}, {2, 2}, {6, 1}, {5, 1}};
+
+ TestRoutes(starts, finishes, {expectedRoute0, expectedRoute1, expectedRoute2}, *graph);
+}
+
+// Route through two squares graph with adding a Fake-0 edge.
+UNIT_TEST(TwoSquaresGraph_AddFakeFeatureZero)
+{
+ unique_ptr<IndexGraph> graph = BuildTwoSquaresGraph();
+ graph->AddFakeFeature(graph->InsertJoint({2 /* feature id */, 1 /* point id */}),
+ graph->GetJointIdForTesting({6 /* feature id */, 1 /* point id */}),
+ {{2, 1}, {6, 1}} /* geometrySource */);
+
+ vector<RoadPoint> const starts = {{2 /* feature id */, 0 /* point id */}, {2, 0}, {2, 0}};
+ vector<RoadPoint> const finishes = {{6 /* feature id */, 0 /* point id */}, {6, 1}, {5, 1}};
+ vector<RoadPoint> const expectedRoute0 = {{2 /* feature id */, 0 /* point id */},
+ {2, 1}, {2, 2}};
+ vector<RoadPoint> const expectedRoute1 = {{2 /* feature id */, 0 /* point id */},
+ {2, 1}, {IndexGraph::kStartFakeFeatureIds, 1}};
+ vector<RoadPoint> const expectedRoute2 = {{2 /* feature id */, 0 /* point id */},
+ {2, 1}, {IndexGraph::kStartFakeFeatureIds, 1}, {5, 1}};
+
+ TestRoutes(starts, finishes, {expectedRoute0, expectedRoute1, expectedRoute2}, *graph);
+}
+
+// Route through two squares graph with adding a Fake-0, Fake-1 and Fake-2 edge.
+UNIT_TEST(TwoSquaresGraph_AddFakeFeatureZeroOneTwo)
+{
+ unique_ptr<IndexGraph> graph = BuildTwoSquaresGraph();
+ // Adding features: Fake 0, Fake 1 and Fake 2.
+ graph->AddFakeFeature(graph->InsertJoint({2 /* feature id */, 1 /* point id */}),
+ graph->GetJointIdForTesting({6 /* feature id */, 1 /* point id */}),
+ {{2, 1}, {6, 1}} /* geometrySource */);
+ graph->AddFakeFeature(graph->InsertJoint({1 /* feature id */, 1 /* point id */}),
+ graph->GetJointIdForTesting({5 /* feature id */, 1 /* point id */}),
+ {{1, 1}, {5, 1}} /* geometrySource */);
+ graph->AddFakeFeature(graph->GetJointIdForTesting({2 /* feature id */, 0 /* point id */}),
+ graph->GetJointIdForTesting({1 /* feature id */, 1 /* point id */}),
+ {{2, 0}, {1, 1}} /* geometrySource */);
+
+ vector<RoadPoint> const starts = {{2 /* feature id */, 0 /* point id */}, {2, 0}, {2, 0}};
+ vector<RoadPoint> const finishes = {{6 /* feature id */, 0 /* point id */}, {6, 1}, {5, 1}};
+ vector<RoadPoint> const expectedRoute0 = {{2 /* feature id */, 0 /* point id */},
+ {2, 1}, {2, 2}};
+ vector<RoadPoint> const expectedRoute1 = {{2 /* feature id */, 0 /* point id */},
+ {2, 1}, {IndexGraph::kStartFakeFeatureIds, 1}};
+ vector<RoadPoint> const expectedRoute2 = {{IndexGraph::kStartFakeFeatureIds + 2 /* Fake 2 */, 0},
+ {IndexGraph::kStartFakeFeatureIds + 2 /* Fake 2 */, 1},
+ {IndexGraph::kStartFakeFeatureIds + 1 /* Fake 1 */, 1}};
+ TestRoutes(starts, finishes, {expectedRoute0, expectedRoute1, expectedRoute2}, *graph);
+
+ // Disabling Fake-2 feature.
+ graph->DisableEdge(graph->GetJointIdForTesting({IndexGraph::kStartFakeFeatureIds + 2 /* Fake 2 */, 0}),
+ graph->GetJointIdForTesting({IndexGraph::kStartFakeFeatureIds + 2 /* Fake 2 */, 1}));
+ vector<RoadPoint> const expectedRoute2Disable2 = {{2 /* feature id */, 0 /* point id */},
+ {2, 1}, {IndexGraph::kStartFakeFeatureIds, 1}, {5, 1}};
+ TestRoutes(starts, finishes, {expectedRoute0, expectedRoute1, expectedRoute2Disable2}, *graph);
+}
+
+// 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<IndexGraph> BuildFlagGraph()
+{
+ auto const loader = []()
+ {
+ unique_ptr<TestGeometryLoader> loader = make_unique<TestGeometryLoader>();
+ loader->AddRoad(0 /* feature id */, false /* one way */, buffer_vector<m2::PointD, 32>(
+ {{2.0, 0.0}, {1.0, 0.0}}));
+ loader->AddRoad(1 /* feature id */, false /* one way */, buffer_vector<m2::PointD, 32>(
+ {{1.0, 0.0}, {0.0, 0.0}}));
+ loader->AddRoad(2 /* feature id */, false /* one way */, buffer_vector<m2::PointD, 32>(
+ {{0.0, 0.0}, {0.0, 1.0}}));
+ loader->AddRoad(3 /* feature id */, false /* one way */, buffer_vector<m2::PointD, 32>(
+ {{1.0, 0.0}, {1.0, 1.0}}));
+ loader->AddRoad(4 /* feature id */, false /* one way */, buffer_vector<m2::PointD, 32>(
+ {{0.0, 1.0}, {0.5, 1.0}}));
+ loader->AddRoad(5 /* feature id */, false /* one way */, buffer_vector<m2::PointD, 32>(
+ {{0.5, 1.0}, {1.0, 1.0}}));
+ return loader;
+ };
+
+ vector<Joint> 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}}), /* joint at point (1, 1) */
+ };
+
+ unique_ptr<IndexGraph> graph = make_unique<IndexGraph>(loader(), CreateEstimator());
+ graph->Import(joints);
+ // Note. It's necessary to insert start joint because the edge F0 is used
+ // for creating restrictions.
+ graph->InsertJoint({0 /* feature id */, 0 /* point id */}); // start
+ return graph;
+}
+
+// @TODO(bykoianko) It's necessary to implement put several no restriction on the same junction
+// ingoing edges of the same jucntion. For example test with flag graph with two restriction
+// type no from F0 to F3 and form F0 to F1.
+
+// Route through flag graph without any restrictions.
+UNIT_TEST(FlagGraph)
+{
+ unique_ptr<IndexGraph> graph = BuildFlagGraph();
+ IndexGraphStarter starter(*graph, RoadPoint(0, 0) /* start */, RoadPoint(5, 0) /* finish */);
+ vector<m2::PointD> const expectedGeom = {{2 /* x */, 0 /* y */},
+ {1, 0}, {1, 1}, {0.5, 1}};
+ TestRouteGeometry(starter, AStarAlgorithm<IndexGraphStarter>::Result::OK, expectedGeom);
+}
+
+// Route through flag graph with one restriciton (type no) from F0 to F3.
+UNIT_TEST(FlagGraph_RestrictionF0F3No)
+{
+ unique_ptr<IndexGraph> graph = BuildFlagGraph();
+ Joint::Id const restictionCenterId = graph->GetJointIdForTesting({0, 1});
+
+ // Testing outgoing and ingoing edge number near restriction joint.
+ EdgeTest(restictionCenterId, 3 /* expectedIntgoingNum */, 3 /* expectedOutgoingNum */, *graph);
+ graph->ApplyRestrictionNo({0 /* feature id */, 1 /* point id */}, {3 /* feature id */, 0 /* point id */},
+ restictionCenterId);
+ EdgeTest(restictionCenterId, 2 /* expectedIntgoingNum */, 3 /* expectedOutgoingNum */, *graph);
+
+ // Testing route building after adding the restriction.
+ IndexGraphStarter starter(*graph, RoadPoint(0, 0) /* start */, RoadPoint(5, 0) /* finish */);
+ vector<m2::PointD> const expectedGeom = {{2 /* x */, 0 /* y */},
+ {1, 0}, {0, 0}, {0, 1}, {0.5, 1}};
+ TestRouteGeometry(starter, AStarAlgorithm<IndexGraphStarter>::Result::OK, expectedGeom);
+}
+
+// Route through flag graph with one restriciton (type only) from F0 to F1.
+UNIT_TEST(FlagGraph_RestrictionF0F1Only)
+{
+ unique_ptr<IndexGraph> graph = BuildFlagGraph();
+ Joint::Id const restictionCenterId = graph->GetJointIdForTesting({0, 1});
+ graph->ApplyRestrictionOnly({0 /* feature id */, 1 /* point id */}, {1 /* feature id */, 0 /* point id */},
+ restictionCenterId);
+
+ IndexGraphStarter starter(*graph, RoadPoint(0, 0) /* start */, RoadPoint(5, 0) /* finish */);
+ vector<RoadPoint> const expectedRoute = {{IndexGraph::kStartFakeFeatureIds, 0 /* point id */},
+ {IndexGraph::kStartFakeFeatureIds, 1},
+ {IndexGraph::kStartFakeFeatureIds, 2},
+ {2 /* feature id */, 1 /* point id */},
+ {4, 1}};
+ TestRouteSegments(starter, AStarAlgorithm<IndexGraphStarter>::Result::OK, expectedRoute);
+}
+
+// 1 *-F4-*-F5-*---F6---* Finish
+// | |
+// 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<IndexGraph> BuildPosterGraph()
+{
+ auto loader = []()
+ {
+ unique_ptr<TestGeometryLoader> loader = make_unique<TestGeometryLoader>();
+ loader->AddRoad(0 /* feature id */, false /* one way */, buffer_vector<m2::PointD, 32>(
+ {{2.0, 0.0}, {1.0, 0.0}}));
+ loader->AddRoad(1 /* feature id */, false /* one way */, buffer_vector<m2::PointD, 32>(
+ {{1.0, 0.0}, {0.0, 0.0}}));
+ loader->AddRoad(2 /* feature id */, false /* one way */, buffer_vector<m2::PointD, 32>(
+ {{0.0, 0.0}, {0.0, 1.0}}));
+ loader->AddRoad(3 /* feature id */, false /* one way */, buffer_vector<m2::PointD, 32>(
+ {{1.0, 0.0}, {1.0, 1.0}}));
+ loader->AddRoad(4 /* feature id */, false /* one way */, buffer_vector<m2::PointD, 32>(
+ {{0.0, 1.0}, {0.5, 1.0}}));
+ loader->AddRoad(5 /* feature id */, false /* one way */, buffer_vector<m2::PointD, 32>(
+ {{0.5, 1.0}, {1.0, 1.0}}));
+ loader->AddRoad(6 /* feature id */, false /* one way */, buffer_vector<m2::PointD, 32>(
+ {{1.0, 1.0}, {2.0, 1.0}}));
+ return loader;
+ };
+
+ vector<Joint> 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) */
+ };
+
+ unique_ptr<IndexGraph> graph = make_unique<IndexGraph>(loader(), CreateEstimator());
+ graph->Import(joints);
+ // Note. It's necessary to insert start and finish joints because the edge F0 is used
+ // for creating restrictions.
+ graph->InsertJoint({0 /* feature id */, 0 /* point id */}); // start
+ graph->InsertJoint({6 /* feature id */, 1 /* point id */}); // finish
+
+ return graph;
+}
+
+// Route through poster graph without any restrictions.
+UNIT_TEST(PosterGraph)
+{
+ unique_ptr<IndexGraph> graph = BuildPosterGraph();
+ IndexGraphStarter starter(*graph, RoadPoint(0, 0) /* start */, RoadPoint(6, 1) /* finish */);
+ vector<m2::PointD> const expectedGeom = {{2 /* x */, 0 /* y */},
+ {1, 0}, {1, 1}, {2, 1}};
+
+ TestRouteGeometry(starter, AStarAlgorithm<IndexGraphStarter>::Result::OK, expectedGeom);
+}
+
+// Route through poster graph with restrictions F0-F3 (type no).
+UNIT_TEST(PosterGraph_RestrictionF0F3No)
+{
+ unique_ptr<IndexGraph> graph = BuildPosterGraph();
+ Joint::Id const restictionCenterId = graph->GetJointIdForTesting({0, 1});
+
+ graph->ApplyRestrictionNo({0 /* feature id */, 1 /* point id */}, {3 /* feature id */, 0 /* point id */},
+ restictionCenterId);
+
+ IndexGraphStarter starter(*graph, RoadPoint(0, 0) /* start */, RoadPoint(6, 1) /* finish */);
+ vector<m2::PointD> const expectedGeom = {{2 /* x */, 0 /* y */},
+ {1, 0}, {0, 0}, {0, 1}, {0.5, 1}, {1, 1}, {2, 1}};
+ TestRouteGeometry(starter, AStarAlgorithm<IndexGraphStarter>::Result::OK, expectedGeom);
+}
+
+// Route through poster graph with restrictions F0-F1 (type only).
+UNIT_TEST(PosterGraph_RestrictionF0F1Only)
+{
+ unique_ptr<IndexGraph> graph = BuildPosterGraph();
+ Joint::Id const restictionCenterId = graph->GetJointIdForTesting({0, 1});
+
+ graph->ApplyRestrictionOnly({0 /* feature id */, 1 /* point id */}, {1 /* feature id */, 0 /* point id */},
+ restictionCenterId);
+
+ IndexGraphStarter starter(*graph, RoadPoint(0, 0) /* start */, RoadPoint(6, 1) /* finish */);
+ vector<m2::PointD> const expectedGeom = {{2 /* x */, 0 /* y */},
+ {1, 0}, {0, 0}, {0, 1}, {0.5, 1}, {1, 1}, {2, 1}};
+ TestRouteGeometry(starter, AStarAlgorithm<IndexGraphStarter>::Result::OK, expectedGeom);
+}
+
+// 1 *--F1-->*
+// ↗ ↘
+// F1 F1
+// ↗ ↘
+// Start 0 *---F0--->-------F0----->* Finish
+// 0 1 2 3
+// Start
+// Note. F0 is a two setments feature. F1 is a three segment one.
+unique_ptr<IndexGraph> BuildTwoWayGraph()
+{
+ auto const loader = []()
+ {
+ unique_ptr<TestGeometryLoader> loader = make_unique<TestGeometryLoader>();
+ loader->AddRoad(0 /* feature id */, true /* oneWay */, buffer_vector<m2::PointD, 32>(
+ {{0.0, 0.0}, {1.0, 0.0}, {3.0, 0}}));
+ loader->AddRoad(1 /* feature id */, true /* oneWay */, buffer_vector<m2::PointD, 32>(
+ {{0.0, 0.0}, {1.0, 1.0}, {2.0, 1.0}, {3.0, 0.0}}));
+ return loader;
+ };
+
+ vector<Joint> const joints = {
+ MakeJoint({{0 /* feature id */, 0 /* point id */}, {1, 0}}), /* joint at point (0, 0) */
+ MakeJoint({{0 /* feature id */, 2 /* point id */}, {1, 3}})};
+
+ unique_ptr<IndexGraph> graph = make_unique<IndexGraph>(loader(), CreateEstimator());
+ graph->Import(joints);
+ return graph;
+}
+
+UNIT_TEST(TwoWay_GetSingleFeaturePaths)
+{
+ unique_ptr<IndexGraph> graph = BuildTwoWayGraph();
+ vector<RoadPoint> singleFeaturePath;
+
+ // Full feature 0.
+ graph->GetSingleFeaturePaths({0 /* feature id */, 0 /* point id */}, {0, 2}, singleFeaturePath);
+ vector<RoadPoint> const expectedF0 = {{0 /* feature id */, 0 /* point id */}, {0, 1}, {0, 2}};
+ TEST_EQUAL(singleFeaturePath, expectedF0, ());
+
+ // Full feature 1.
+ graph->GetSingleFeaturePaths({1 /* feature id */, 0 /* point id */}, {1, 3}, singleFeaturePath);
+ vector<RoadPoint> const expectedF1 = {{1 /* feature id */, 0 /* point id */}, {1, 1},
+ {1, 2}, {1, 3}};
+ TEST_EQUAL(singleFeaturePath, expectedF1, ());
+
+ // Full feature 1 in reversed order.
+ graph->GetSingleFeaturePaths({1 /* feature id */, 3 /* point id */}, {1, 0}, singleFeaturePath);
+ vector<RoadPoint> const expectedReversedF1 = {{1 /* feature id */, 3 /* point id */}, {1, 2},
+ {1, 1}, {1, 0}};
+ TEST_EQUAL(singleFeaturePath, expectedReversedF1, ());
+
+ // Part of feature 0.
+ graph->GetSingleFeaturePaths({0 /* feature id */, 1 /* point id */}, {0, 2}, singleFeaturePath);
+ vector<RoadPoint> const expectedPartF0 = {{0 /* feature id */, 1 /* point id */}, {0, 2}};
+ TEST_EQUAL(singleFeaturePath, expectedPartF0, ());
+
+ // Part of feature 1 in reversed order.
+ graph->GetSingleFeaturePaths({1 /* feature id */, 2 /* point id */}, {1, 1}, singleFeaturePath);
+ vector<RoadPoint> const expectedPartF1 = {{1 /* feature id */, 2 /* point id */}, {1, 1}};
+ TEST_EQUAL(singleFeaturePath, expectedPartF1, ());
+
+ // Single point test.
+ graph->GetSingleFeaturePaths({0 /* feature id */, 0 /* point id */}, {0, 0}, singleFeaturePath);
+ vector<RoadPoint> const expectedSinglePoint = {{0 /* feature id */, 0 /* point id */}};
+ TEST_EQUAL(singleFeaturePath, expectedSinglePoint, ());
+}
+
+UNIT_TEST(TwoWay_GetConnectionPaths)
+{
+ unique_ptr<IndexGraph> graph = BuildTwoWayGraph();
+ vector<vector<RoadPoint>> connectionPaths;
+
+ graph->GetConnectionPaths(graph->GetJointIdForTesting({1 /* feature id */, 0 /* point id */}),
+ graph->GetJointIdForTesting({0, 2}), connectionPaths);
+ vector<vector<RoadPoint>> const expectedConnectionPaths = {
+ {{0, 0}, {0, 1}, {0, 2}}, // feature 0
+ {{1, 0}, {1, 1}, {1, 2}, {1, 3}}, // feature 1
+ };
+ sort(connectionPaths.begin(), connectionPaths.end());
+ TEST_EQUAL(connectionPaths, expectedConnectionPaths, ());
+}
+
+UNIT_TEST(TwoWay_GetShortestConnectionPath)
+{
+ unique_ptr<IndexGraph> graph = BuildTwoWayGraph();
+ vector<RoadPoint> shortestPath;
+
+ graph->GetShortestConnectionPath(graph->GetJointIdForTesting({0 /* feature id */, 0 /* point id */}),
+ graph->GetJointIdForTesting({1, 3}), shortestPath);
+ vector<RoadPoint> const expectedShortestPath = {
+ {0, 0}, {0, 1}, {0, 2}, // feature 0
+ };
+ TEST_EQUAL(shortestPath, expectedShortestPath, ());
+}
+} // namespace
diff --git a/routing/routing_tests/routing_tests.pro b/routing/routing_tests/routing_tests.pro
index 100399f067..b170fc5d4f 100644
--- a/routing/routing_tests/routing_tests.pro
+++ b/routing/routing_tests/routing_tests.pro
@@ -28,6 +28,7 @@ SOURCES += \
cross_routing_tests.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 \
@@ -40,6 +41,8 @@ SOURCES += \
turns_sound_test.cpp \
turns_tts_text_tests.cpp \
vehicle_model_test.cpp \
+ restriction_test.cpp \
HEADERS += \
+ index_graph_tools.hpp \
road_graph_builder.hpp \