diff --git a/pedestrian_routing_tests/pedestrian_routing_tests.cpp b/pedestrian_routing_tests/pedestrian_routing_tests.cpp index bdc33a0ff5..1921f03bf1 100644 --- a/pedestrian_routing_tests/pedestrian_routing_tests.cpp +++ b/pedestrian_routing_tests/pedestrian_routing_tests.cpp @@ -94,7 +94,9 @@ unique_ptr CreatePedestrianAStarTestRouter(Index & index, stor auto UKGetter = [&](m2::PointD const & pt) { return cig.GetRegionCountryId(pt); }; unique_ptr vehicleModelFactory(new SimplifiedPedestrianModelFactory()); unique_ptr algorithm(new routing::AStarRoutingAlgorithm()); - unique_ptr router(new routing::RoadGraphRouter("test-astar-pedestrian", index, UKGetter, move(vehicleModelFactory), move(algorithm), nullptr)); + unique_ptr router(new routing::RoadGraphRouter("test-astar-pedestrian", index, UKGetter, + true /* onewayAsBidirectional */, + move(vehicleModelFactory), move(algorithm), nullptr)); return router; } @@ -103,7 +105,9 @@ unique_ptr CreatePedestrianAStarBidirectionalTestRouter(Index auto UKGetter = [&](m2::PointD const & pt) { return cig.GetRegionCountryId(pt); }; unique_ptr vehicleModelFactory(new SimplifiedPedestrianModelFactory()); unique_ptr algorithm(new routing::AStarBidirectionalRoutingAlgorithm()); - unique_ptr router(new routing::RoadGraphRouter("test-astar-bidirectional-pedestrian", index, UKGetter, move(vehicleModelFactory), move(algorithm), nullptr)); + unique_ptr router(new routing::RoadGraphRouter("test-astar-bidirectional-pedestrian", index, UKGetter, + true /* onewayAsBidirectional */, + move(vehicleModelFactory), move(algorithm), nullptr)); return router; } @@ -120,7 +124,7 @@ m2::PointD GetPointOnEdge(routing::Edge & e, double posAlong) void GetNearestPedestrianEdges(Index & index, m2::PointD const & pt, vector> & edges) { unique_ptr vehicleModelFactory(new SimplifiedPedestrianModelFactory()); - routing::FeaturesRoadGraph roadGraph(index, move(vehicleModelFactory)); + routing::FeaturesRoadGraph roadGraph(index, true /* onewayAsBidirectional */, move(vehicleModelFactory)); roadGraph.FindClosestEdges(pt, 1 /*count*/, edges); } diff --git a/routing/bicycle_model.hpp b/routing/bicycle_model.hpp index 2c420ccd83..2a7fdaa4fa 100644 --- a/routing/bicycle_model.hpp +++ b/routing/bicycle_model.hpp @@ -17,7 +17,6 @@ public: /// @name Overrides from VehicleModel. //@{ double GetSpeed(FeatureType const & f) const override; - bool IsOneWay(FeatureType const &) const override { return false; } //@} private: diff --git a/routing/features_road_graph.cpp b/routing/features_road_graph.cpp index 65e5b039bc..1fa3793f48 100644 --- a/routing/features_road_graph.cpp +++ b/routing/features_road_graph.cpp @@ -101,9 +101,9 @@ void FeaturesRoadGraph::RoadInfoCache::Clear() m_cache.clear(); } - -FeaturesRoadGraph::FeaturesRoadGraph(Index & index, unique_ptr && vehicleModelFactory) - : m_index(index), +FeaturesRoadGraph::FeaturesRoadGraph(Index const & index, bool onewayAsBidirectional, + unique_ptr && vehicleModelFactory) + : m_index(index), m_onewayAsBidirectional(onewayAsBidirectional), m_vehicleModel(move(vehicleModelFactory)) { } @@ -114,7 +114,7 @@ class CrossFeaturesLoader { public: CrossFeaturesLoader(FeaturesRoadGraph const & graph, - IRoadGraph::CrossEdgesLoader & edgesLoader) + IRoadGraph::ICrossEdgesLoader & edgesLoader) : m_graph(graph), m_edgesLoader(edgesLoader) {} @@ -136,7 +136,7 @@ public: private: FeaturesRoadGraph const & m_graph; - IRoadGraph::CrossEdgesLoader & m_edgesLoader; + IRoadGraph::ICrossEdgesLoader & m_edgesLoader; }; IRoadGraph::RoadInfo FeaturesRoadGraph::GetRoadInfo(FeatureID const & featureId) const @@ -159,7 +159,7 @@ double FeaturesRoadGraph::GetMaxSpeedKMPH() const } void FeaturesRoadGraph::ForEachFeatureClosestToCross(m2::PointD const & cross, - CrossEdgesLoader & edgesLoader) const + ICrossEdgesLoader & edgesLoader) const { CrossFeaturesLoader featuresLoader(*this, edgesLoader); m2::RectD const rect = MercatorBounds::RectByCenterXYAndSizeInMeters(cross, kMwmRoadCrossingRadiusMeters); @@ -230,6 +230,11 @@ void FeaturesRoadGraph::GetJunctionTypes(Junction const & junction, feature::Typ m_index.ForEachInRect(f, rect, GetStreetReadScale()); } +bool FeaturesRoadGraph::ConsiderOnewayFeaturesAsBidirectional() const +{ + return m_onewayAsBidirectional; +}; + void FeaturesRoadGraph::ClearState() { m_cache.Clear(); diff --git a/routing/features_road_graph.hpp b/routing/features_road_graph.hpp index ae0576647c..016358e1db 100644 --- a/routing/features_road_graph.hpp +++ b/routing/features_road_graph.hpp @@ -56,7 +56,8 @@ private: }; public: - FeaturesRoadGraph(Index & index, unique_ptr && vehicleModelFactory); + FeaturesRoadGraph(Index const & index, bool onewayAsBidirectional, + unique_ptr && vehicleModelFactory); static uint32_t GetStreetReadScale(); @@ -65,11 +66,12 @@ public: double GetSpeedKMPH(FeatureID const & featureId) const override; double GetMaxSpeedKMPH() const override; void ForEachFeatureClosestToCross(m2::PointD const & cross, - CrossEdgesLoader & edgesLoader) const override; + ICrossEdgesLoader & edgesLoader) const override; void FindClosestEdges(m2::PointD const & point, uint32_t count, vector> & vicinities) const override; void GetFeatureTypes(FeatureID const & featureId, feature::TypesHolder & types) const override; void GetJunctionTypes(Junction const & junction, feature::TypesHolder & types) const override; + bool ConsiderOnewayFeaturesAsBidirectional() const override; void ClearState() override; private: @@ -89,7 +91,8 @@ private: void LockFeatureMwm(FeatureID const & featureId) const; - Index & m_index; + Index const & m_index; + bool const m_onewayAsBidirectional; mutable RoadInfoCache m_cache; mutable CrossCountryVehicleModel m_vehicleModel; mutable map m_mwmLocks; diff --git a/routing/road_graph.cpp b/routing/road_graph.cpp index c0a314ca23..36ff80188e 100644 --- a/routing/road_graph.cpp +++ b/routing/road_graph.cpp @@ -61,6 +61,18 @@ vector::const_iterator FindEdgeContainingPoint(vector const & edges, return find_if(edges.begin(), edges.end(), liesOnEdgeFn); } +/// \brief Reverses |edges| starting from index |beginIdx| and upto the end of |v|. +void ReverseEdges(size_t beginIdx, IRoadGraph::TEdgeVector & edges) +{ + if (beginIdx > edges.size()) + { + ASSERT(false, ()); + return; + } + + for (size_t i = beginIdx; i < edges.size(); ++i) + edges[i] = edges[i].GetReverseEdge(); +} } // namespace // Junction -------------------------------------------------------------------- @@ -154,14 +166,38 @@ IRoadGraph::RoadInfo::RoadInfo(bool bidirectional, double speedKMPH, initializer : m_points(points), m_speedKMPH(speedKMPH), m_bidirectional(bidirectional) {} -// IRoadGraph::CrossEdgesLoader ------------------------------------------------ - -IRoadGraph::CrossEdgesLoader::CrossEdgesLoader(m2::PointD const & cross, TEdgeVector & outgoingEdges) - : m_cross(cross), m_outgoingEdges(outgoingEdges) +// IRoadGraph::CrossOutgoingLoader --------------------------------------------- +void IRoadGraph::CrossOutgoingLoader::LoadEdge(FeatureID const & featureId, RoadInfo const & roadInfo) { + size_t const numPoints = roadInfo.m_points.size(); + + for (size_t i = 0; i < numPoints; ++i) + { + m2::PointD const & p = roadInfo.m_points[i]; + + if (!PointsAlmostEqualAbs(m_cross, p)) + continue; + + if (i > 0 && (roadInfo.m_bidirectional || m_onewayAsBidirectional)) + { + // p + // o------------>o + + m_edges.emplace_back(featureId, false /* forward */, i - 1, p, roadInfo.m_points[i - 1]); + } + + if (i < numPoints - 1) + { + // p + // o------------>o + + m_edges.emplace_back(featureId, true /* forward */, i, p, roadInfo.m_points[i + 1]); + } + } } -void IRoadGraph::CrossEdgesLoader::operator()(FeatureID const & featureId, RoadInfo const & roadInfo) +// IRoadGraph::CrossIngoingLoader ---------------------------------------------- +void IRoadGraph::CrossIngoingLoader::LoadEdge(FeatureID const & featureId, RoadInfo const & roadInfo) { size_t const numPoints = roadInfo.m_points.size(); @@ -177,51 +213,71 @@ void IRoadGraph::CrossEdgesLoader::operator()(FeatureID const & featureId, RoadI // p // o------------>o - m_outgoingEdges.emplace_back(featureId, false /* forward */, i - 1, p, roadInfo.m_points[i - 1]); + m_edges.emplace_back(featureId, true /* forward */, i - 1, roadInfo.m_points[i - 1], p); } - if (i < numPoints - 1) + if (i < numPoints - 1 && (roadInfo.m_bidirectional || m_onewayAsBidirectional)) { // p // o------------>o - m_outgoingEdges.emplace_back(featureId, true /* forward */, i, p, roadInfo.m_points[i + 1]); + m_edges.emplace_back(featureId, false /* forward */, i, roadInfo.m_points[i + 1], p); } } } // IRoadGraph ------------------------------------------------------------------ - void IRoadGraph::GetOutgoingEdges(Junction const & junction, TEdgeVector & edges) const { - auto const itr = m_outgoingEdges.find(junction); - if (itr != m_outgoingEdges.end()) - { - edges.reserve(edges.size() + itr->second.size()); - edges.insert(edges.end(), itr->second.begin(), itr->second.end()); - } - else - { - GetRegularOutgoingEdges(junction, edges); - } + GetFakeOutgoingEdges(junction, edges); + GetRegularOutgoingEdges(junction, edges); } void IRoadGraph::GetIngoingEdges(Junction const & junction, TEdgeVector & edges) const { - size_t const wasSize = edges.size(); + GetFakeIngoingEdges(junction, edges); + GetRegularIngoingEdges(junction, edges); +} - GetOutgoingEdges(junction, edges); +void IRoadGraph::LoadOutgoingEdges(m2::PointD const & cross, TEdgeVector & edges) const +{ + CrossOutgoingLoader loader(cross, ConsiderOnewayFeaturesAsBidirectional(), edges); + ForEachFeatureClosestToCross(cross, loader); +} - size_t const size = edges.size(); - for (size_t i = wasSize; i < size; ++i) - edges[i] = edges[i].GetReverseEdge(); +void IRoadGraph::LoadIngoingEdges(m2::PointD const & cross, TEdgeVector & edges) const +{ + CrossIngoingLoader loader(cross, ConsiderOnewayFeaturesAsBidirectional(), edges); + ForEachFeatureClosestToCross(cross, loader); } void IRoadGraph::GetRegularOutgoingEdges(Junction const & junction, TEdgeVector & edges) const { m2::PointD const cross = junction.GetPoint(); - CrossEdgesLoader loader(cross, edges); - ForEachFeatureClosestToCross(cross, loader); + LoadOutgoingEdges(cross, edges); +} + +void IRoadGraph::GetRegularIngoingEdges(Junction const & junction, TEdgeVector & edges) const +{ + m2::PointD const cross = junction.GetPoint(); + LoadIngoingEdges(cross, edges); +} + +void IRoadGraph::GetFakeOutgoingEdges(Junction const & junction, TEdgeVector & edges) const +{ + auto const itr = m_outgoingEdges.find(junction); + if (itr == m_outgoingEdges.cend()) + return; + + edges.reserve(edges.size() + itr->second.size()); + edges.insert(edges.end(), itr->second.begin(), itr->second.end()); +} + +void IRoadGraph::GetFakeIngoingEdges(Junction const & junction, TEdgeVector & edges) const +{ + size_t const wasSize = edges.size(); + GetFakeOutgoingEdges(junction, edges); + ReverseEdges(wasSize, edges); } void IRoadGraph::ResetFakes() diff --git a/routing/road_graph.hpp b/routing/road_graph.hpp index 982c98ff6c..8c26f8a867 100644 --- a/routing/road_graph.hpp +++ b/routing/road_graph.hpp @@ -99,17 +99,44 @@ public: }; /// This class is responsible for loading edges in a cross. - /// It loades only outgoing edges. - class CrossEdgesLoader + class ICrossEdgesLoader { public: - CrossEdgesLoader(m2::PointD const & cross, TEdgeVector & outgoingEdges); + ICrossEdgesLoader(m2::PointD const & cross, bool onewayAsBidirectional, TEdgeVector & edges) + : m_cross(cross), m_onewayAsBidirectional(onewayAsBidirectional), m_edges(edges) {} + virtual ~ICrossEdgesLoader() = default; - void operator()(FeatureID const & featureId, RoadInfo const & roadInfo); + void operator()(FeatureID const & featureId, RoadInfo const & roadInfo) + { + LoadEdge(featureId, roadInfo); + } private: + virtual void LoadEdge(FeatureID const & featureId, RoadInfo const & roadInfo) = 0; + + protected: m2::PointD const m_cross; - TEdgeVector & m_outgoingEdges; + bool const m_onewayAsBidirectional; + TEdgeVector & m_edges; + }; + + class CrossOutgoingLoader : public ICrossEdgesLoader + { + public: + CrossOutgoingLoader(m2::PointD const & cross, bool onewayAsBidirectional, TEdgeVector & edges) + : ICrossEdgesLoader(cross, onewayAsBidirectional, edges) {} + + // ICrossEdgesLoader overrides: + virtual void LoadEdge(FeatureID const & featureId, RoadInfo const & roadInfo) override; + }; + + class CrossIngoingLoader : public ICrossEdgesLoader + { + public: + CrossIngoingLoader(m2::PointD const & cross, bool onewayAsBidirectional, TEdgeVector & edges) + : ICrossEdgesLoader(cross, onewayAsBidirectional, edges) {} + // ICrossEdgesLoader overrides: + virtual void LoadEdge(FeatureID const & featureId, RoadInfo const & roadInfo) override; }; virtual ~IRoadGraph() = default; @@ -141,7 +168,7 @@ public: /// Calls edgesLoader on each feature which is close to cross. virtual void ForEachFeatureClosestToCross(m2::PointD const & cross, - CrossEdgesLoader & edgesLoader) const = 0; + ICrossEdgesLoader & edgesLoader) const = 0; /// Finds the closest edges to the point. /// @return Array of pairs of Edge and projection point on the Edge. If there is no the closest edges @@ -158,12 +185,22 @@ public: /// @return Types for specified junction virtual void GetJunctionTypes(Junction const & junction, feature::TypesHolder & types) const = 0; + virtual bool ConsiderOnewayFeaturesAsBidirectional() const = 0; + /// Clear all temporary buffers. virtual void ClearState() {} private: - /// Finds all outgoing regular (non-fake) edges for junction. + /// \brief Finds all outgoing regular (non-fake) edges for junction. void GetRegularOutgoingEdges(Junction const & junction, TEdgeVector & edges) const; + /// \brief Finds all ingoing regular (non-fake) edges for junction. + void GetRegularIngoingEdges(Junction const & junction, TEdgeVector & edges) const; + void LoadOutgoingEdges(m2::PointD const & cross, TEdgeVector & edges) const; + void LoadIngoingEdges(m2::PointD const & cross, TEdgeVector & edges) const; + /// \brief Finds all outgoing fake edges for junction. + void GetFakeOutgoingEdges(Junction const & junction, TEdgeVector & edges) const; + /// \brief Finds all ingoing fake edges for junction. + void GetFakeIngoingEdges(Junction const & junction, TEdgeVector & edges) const; /// Determines if the edge has been split by fake edges and if yes returns these fake edges. bool HasBeenSplitToFakes(Edge const & edge, vector & fakeEdges) const; @@ -171,5 +208,4 @@ private: // Map of outgoing edges for junction map m_outgoingEdges; }; - } // namespace routing diff --git a/routing/road_graph_router.cpp b/routing/road_graph_router.cpp index 0cab63e835..cc3be95ee3 100644 --- a/routing/road_graph_router.cpp +++ b/routing/road_graph_router.cpp @@ -130,8 +130,9 @@ void FindClosestEdges(IRoadGraph const & graph, m2::PointD const & point, RoadGraphRouter::~RoadGraphRouter() {} -RoadGraphRouter::RoadGraphRouter(string const & name, Index & index, +RoadGraphRouter::RoadGraphRouter(string const & name, Index const & index, TCountryFileFn const & countryFileFn, + bool onewayAsBidirectional, unique_ptr && vehicleModelFactory, unique_ptr && algorithm, unique_ptr && directionsEngine) @@ -139,7 +140,7 @@ RoadGraphRouter::RoadGraphRouter(string const & name, Index & index, , m_countryFileFn(countryFileFn) , m_index(index) , m_algorithm(move(algorithm)) - , m_roadGraph(make_unique(index, move(vehicleModelFactory))) + , m_roadGraph(make_unique(index, onewayAsBidirectional, move(vehicleModelFactory))) , m_directionsEngine(move(directionsEngine)) { } @@ -259,6 +260,7 @@ unique_ptr CreatePedestrianAStarRouter(Index & index, TCountryFileFn co unique_ptr algorithm(new AStarRoutingAlgorithm()); unique_ptr directionsEngine(new PedestrianDirectionsEngine()); unique_ptr router(new RoadGraphRouter("astar-pedestrian", index, countryFileFn, + true /* onewayAsBidirectional */, move(vehicleModelFactory), move(algorithm), move(directionsEngine))); return router; @@ -270,7 +272,8 @@ unique_ptr CreatePedestrianAStarBidirectionalRouter(Index & index, TCou unique_ptr algorithm(new AStarBidirectionalRoutingAlgorithm()); unique_ptr directionsEngine(new PedestrianDirectionsEngine()); unique_ptr router(new RoadGraphRouter("astar-bidirectional-pedestrian", index, - countryFileFn, move(vehicleModelFactory), + countryFileFn, true /* onewayAsBidirectional */, + move(vehicleModelFactory), move(algorithm), move(directionsEngine))); return router; } @@ -280,7 +283,8 @@ unique_ptr CreateBicycleAStarBidirectionalRouter(Index & index, TCountr unique_ptr vehicleModelFactory(new BicycleModelFactory()); unique_ptr algorithm(new AStarBidirectionalRoutingAlgorithm()); unique_ptr directionsEngine(new BicycleDirectionsEngine(index)); - unique_ptr router(new RoadGraphRouter("astar-bidirectional-bicycle", index, countryFileFn, move(vehicleModelFactory), + unique_ptr router(new RoadGraphRouter("astar-bidirectional-bicycle", index, countryFileFn, + false /* onewayAsBidirectional */, move(vehicleModelFactory), move(algorithm), move(directionsEngine))); return router; } diff --git a/routing/road_graph_router.hpp b/routing/road_graph_router.hpp index 17127bb124..ca6eba45c3 100644 --- a/routing/road_graph_router.hpp +++ b/routing/road_graph_router.hpp @@ -23,8 +23,9 @@ namespace routing class RoadGraphRouter : public IRouter { public: - RoadGraphRouter(string const & name, Index & index, + RoadGraphRouter(string const & name, Index const & index, TCountryFileFn const & countryFileFn, + bool onewayAsBidirectional, unique_ptr && vehicleModelFactory, unique_ptr && algorithm, unique_ptr && directionsEngine); @@ -47,7 +48,7 @@ private: string const m_name; TCountryFileFn const m_countryFileFn; - Index & m_index; + Index const & m_index; unique_ptr const m_algorithm; unique_ptr const m_roadGraph; unique_ptr const m_directionsEngine; diff --git a/routing/routing_tests/road_graph_builder.cpp b/routing/routing_tests/road_graph_builder.cpp index 00f8f55d95..2de44978ca 100644 --- a/routing/routing_tests/road_graph_builder.cpp +++ b/routing/routing_tests/road_graph_builder.cpp @@ -84,7 +84,7 @@ double RoadGraphMockSource::GetMaxSpeedKMPH() const } void RoadGraphMockSource::ForEachFeatureClosestToCross(m2::PointD const & /* cross */, - CrossEdgesLoader & edgesLoader) const + ICrossEdgesLoader & edgesLoader) const { for (size_t roadId = 0; roadId < m_roads.size(); ++roadId) edgesLoader(MakeTestFeatureID(roadId), m_roads[roadId]); @@ -110,6 +110,8 @@ void RoadGraphMockSource::GetJunctionTypes(Junction const & junction, feature::T UNUSED_VALUE(types); } +bool RoadGraphMockSource::ConsiderOnewayFeaturesAsBidirectional() const { return true; } + FeatureID MakeTestFeatureID(uint32_t offset) { static TestValidFeatureIDProvider instance; diff --git a/routing/routing_tests/road_graph_builder.hpp b/routing/routing_tests/road_graph_builder.hpp index 9501c9f4ed..4fbad32f70 100644 --- a/routing/routing_tests/road_graph_builder.hpp +++ b/routing/routing_tests/road_graph_builder.hpp @@ -17,11 +17,12 @@ public: double GetSpeedKMPH(FeatureID const & featureId) const override; double GetMaxSpeedKMPH() const override; void ForEachFeatureClosestToCross(m2::PointD const & cross, - CrossEdgesLoader & edgeLoader) const override; + ICrossEdgesLoader & edgeLoader) const override; void FindClosestEdges(m2::PointD const & point, uint32_t count, vector> & vicinities) const override; void GetFeatureTypes(FeatureID const & featureId, feature::TypesHolder & types) const override; void GetJunctionTypes(routing::Junction const & junction, feature::TypesHolder & types) const override; + bool ConsiderOnewayFeaturesAsBidirectional() const override; private: vector m_roads; diff --git a/routing/vehicle_model.hpp b/routing/vehicle_model.hpp index 17b7d91fe8..a9778ed934 100644 --- a/routing/vehicle_model.hpp +++ b/routing/vehicle_model.hpp @@ -64,6 +64,11 @@ public: //@} double GetSpeed(feature::TypesHolder const & types) const; + /// \returns true if |types| is a oneway feature. + /// \note According to OSM tag "oneway" could have value "-1". That means it's a oneway feature + /// with reversed geometry. In that case while map generation the geometry of such features + /// is reversed (the order of points is changed) so in vehicle model all oneway feature + /// could be considered as features with forward geometry. bool IsOneWay(feature::TypesHolder const & types) const; bool IsRoad(FeatureType const & f) const;