From 709da7bd21b496c53abfe3296b686f1cf8d66122 Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Tue, 3 Dec 2019 12:33:04 +0300 Subject: [PATCH] [routing] Using CalcMinSquaredDistance() in EraseIfDeadEnd() to get the correct start segment. --- geometry/geometry_tests/polyline_tests.cpp | 2 +- geometry/point_with_altitude.hpp | 2 +- geometry/polyline2d.hpp | 20 ++++++++++---------- routing/index_router.cpp | 17 +++++++++++------ routing/index_router.hpp | 6 ++++-- 5 files changed, 27 insertions(+), 20 deletions(-) diff --git a/geometry/geometry_tests/polyline_tests.cpp b/geometry/geometry_tests/polyline_tests.cpp index 67ff33dd0f..ecb31cfbc5 100644 --- a/geometry/geometry_tests/polyline_tests.cpp +++ b/geometry/geometry_tests/polyline_tests.cpp @@ -15,7 +15,7 @@ double constexpr kEps = 1e-5; void TestClosest(std::vector const & points, m2::PointD const & point, double expectedSquaredDist, uint32_t expectedIndex) { - auto const closestByPoints = m2::CalcMinSquaredDistance(points, point); + auto const closestByPoints = m2::CalcMinSquaredDistance(points.begin(), points.end(), point); TEST_ALMOST_EQUAL_ABS(closestByPoints.first, expectedSquaredDist, kEps, ()); TEST_EQUAL(closestByPoints.second, expectedIndex, ()); diff --git a/geometry/point_with_altitude.hpp b/geometry/point_with_altitude.hpp index 97e840d9de..4a11e25c63 100644 --- a/geometry/point_with_altitude.hpp +++ b/geometry/point_with_altitude.hpp @@ -43,7 +43,7 @@ std::string DebugPrint(PointWithAltitude const & r); template m2::Point GetPoint(m2::Point const & point) { return point; } -m2::PointD GetPoint(PointWithAltitude const pwa) { return pwa.GetPoint(); } +inline m2::PointD GetPoint(PointWithAltitude const & pwa) { return pwa.GetPoint(); } inline PointWithAltitude MakePointWithAltitudeForTesting(m2::PointD const & point) { diff --git a/geometry/polyline2d.hpp b/geometry/polyline2d.hpp index e6c004d00f..c419c556c3 100644 --- a/geometry/polyline2d.hpp +++ b/geometry/polyline2d.hpp @@ -19,17 +19,17 @@ namespace m2 { /// \returns a pair of minimum squared distance from |point| to the closest segment and -/// a zero-based closest segment index in |points|. -template -std::pair CalcMinSquaredDistance(std::vector> const & points, - Point const & point) +/// a zero-based closest segment index in points in range [|beginIt|, |endIt|). +template +std::pair CalcMinSquaredDistance(It beginIt, It endIt, + m2::Point const & point) { - CHECK_GREATER(points.size(), 1, ()); + CHECK_GREATER(std::distance(beginIt, endIt), 1, ()); auto squaredClosestSegDist = std::numeric_limits::max(); - auto i = points.begin(); - auto closestSeg = points.begin(); - for (auto j = i + 1; j != points.end(); ++i, ++j) + auto i = beginIt; + auto closestSeg = beginIt; + for (auto j = i + 1; j != endIt; ++i, ++j) { m2::ParametrizedSegment> seg(geometry::GetPoint(*i), geometry::GetPoint(*j)); auto const squaredSegDist = seg.SquaredDistanceToPoint(point); @@ -41,7 +41,7 @@ std::pair CalcMinSquaredDistance(std::vector> const & } return std::make_pair(squaredClosestSegDist, - static_cast(std::distance(points.begin(), closestSeg))); + static_cast(std::distance(beginIt, closestSeg))); } template @@ -94,7 +94,7 @@ public: std::pair CalcMinSquaredDistance(m2::Point const & point) const { - return m2::CalcMinSquaredDistance(m_points, point); + return m2::CalcMinSquaredDistance(m_points.begin(), m_points.end(), point); } Rect GetLimitRect() const diff --git a/routing/index_router.cpp b/routing/index_router.cpp index 8f6bbc7de2..57f9eeff93 100644 --- a/routing/index_router.cpp +++ b/routing/index_router.cpp @@ -39,6 +39,7 @@ #include "geometry/mercator.hpp" #include "geometry/parametrized_segment.hpp" +#include "geometry/polyline2d.hpp" #include "geometry/segment2d.hpp" #include "base/assert.hpp" @@ -794,20 +795,24 @@ unique_ptr IndexRouter::MakeWorldGraph() move(transitGraphLoader), m_estimator); } -void IndexRouter::EraseIfDeadEnd(WorldGraph & worldGraph, +void IndexRouter::EraseIfDeadEnd(WorldGraph & worldGraph, m2::PointD const & point, vector & roads) const { // |deadEnds| cache is necessary to minimize number of calls a time consumption IsDeadEnd() method. set deadEnds; - base::EraseIf(roads, [&deadEnds, &worldGraph, this](auto const & fullRoadInfo) { + base::EraseIf(roads, [&deadEnds, &worldGraph, &point, this](auto const & fullRoadInfo) { CHECK_GREATER_OR_EQUAL(fullRoadInfo.m_roadInfo.m_junctions.size(), 2, ()); + auto const squaredDistAndIndex = m2::CalcMinSquaredDistance(fullRoadInfo.m_roadInfo.m_junctions.begin(), + fullRoadInfo.m_roadInfo.m_junctions.end(), + point); + auto const segmentId = squaredDistAndIndex.second; // Note. Checking if an edge goes to a dead end is a time consumption process. // So the number of checked edges should be minimized as possible. - // Below a heuristic is used. If a first segment of a feature is forward direction is a dead end - // all segments of the feature is considered as dead ends. + // Below a heuristic is used. If the closest to |point| segment of a feature + // in forward direction is a dead end all segments of the feature is considered as dead ends. auto const segment = GetSegmentByEdge(Edge::MakeReal(fullRoadInfo.m_featureId, true /* forward */, - 0 /* segment id */, + segmentId, fullRoadInfo.m_roadInfo.m_junctions[0], fullRoadInfo.m_roadInfo.m_junctions[1])); return IsDeadEndCached(segment, true /* isOutgoing */, false /* useRoutingOptions */, worldGraph, @@ -955,7 +960,7 @@ bool IndexRouter::FindBestEdges(m2::PointD const & point, // If to remove all fenced off by other features from |point| candidates at first, // only dead ends candidates may be left. And then the dead end candidates will be removed // as well as dead ends. It often happens near airports. - EraseIfDeadEnd(worldGraph, closestRoads); + EraseIfDeadEnd(worldGraph, point, closestRoads); // Sorting from the closest features to the further ones. The idea is the closer // a feature to a |point| the more chances that it crosses the segment diff --git a/routing/index_router.hpp b/routing/index_router.hpp index ef44ca3a12..bad5fd3c40 100644 --- a/routing/index_router.hpp +++ b/routing/index_router.hpp @@ -125,8 +125,10 @@ private: std::unique_ptr MakeWorldGraph(); /// \brief Removes all roads from |roads| which goes to dead ends and all road which - /// is not good according to |worldGraph|. For car routing it's roads with hwtag nocar. - void EraseIfDeadEnd(WorldGraph & worldGraph, + /// is not good according to |worldGraph|. For car routing there are roads with hwtag nocar as well. + /// \param point which is used to look for the closest segment in a road. The closest segment + /// is used then to check if it's a dead end. + void EraseIfDeadEnd(WorldGraph & worldGraph, m2::PointD const & point, std::vector & roads) const; /// \returns true if a segment (|point|, |edgeProjection.second|) crosses one of segments