diff --git a/openlr/CMakeLists.txt b/openlr/CMakeLists.txt index c9cb897ad7..025e80ed57 100644 --- a/openlr/CMakeLists.txt +++ b/openlr/CMakeLists.txt @@ -2,12 +2,15 @@ project(openlr) set( SRC + candidate_paths_getter.cpp + candidate_paths_getter.hpp candidate_points_getter.cpp candidate_points_getter.hpp decoded_path.cpp decoded_path.hpp graph.cpp graph.hpp + helpers.cpp helpers.hpp openlr_decoder.cpp openlr_decoder.hpp diff --git a/openlr/candidate_paths_getter.cpp b/openlr/candidate_paths_getter.cpp new file mode 100644 index 0000000000..21e9bb8f4e --- /dev/null +++ b/openlr/candidate_paths_getter.cpp @@ -0,0 +1,355 @@ +#include "openlr/candidate_paths_getter.hpp" + +#include "openlr/candidate_points_getter.hpp" +#include "openlr/graph.hpp" +#include "openlr/helpers.hpp" +#include "openlr/openlr_model.hpp" + +#include "routing/road_graph.hpp" + +#include "platform/location.hpp" + +#include "geometry/angles.hpp" + +#include +#include +#include +#include +#include + +using namespace std; +using namespace routing; + +namespace openlr +{ +namespace +{ +// TODO(mgsergio): Maybe add a penalty if this value deviates, not just throw it away. +int const kFRCThreshold = 3; + +int const kNumBuckets = 256; +double const kAnglesInBucket = 360.0 / kNumBuckets; + +m2::PointD PointAtSegmentM(m2::PointD const & p1, m2::PointD const & p2, double const distanceM) +{ + auto const v = p2 - p1; + auto const l = v.Length(); + auto const L = MercatorBounds::DistanceOnEarth(p1, p2); + auto const delta = distanceM * l / L; + return PointAtSegment(p1, p2, delta); +} + +uint32_t Bearing(m2::PointD const & a, m2::PointD const & b) +{ + auto const angle = location::AngleToBearing(my::RadToDeg(ang::AngleTo(a, b))); + CHECK_LESS_OR_EQUAL(angle, 360, ("Angle should be less than or equal to 360.")); + CHECK_GREATER_OR_EQUAL(angle, 0, ("Angle should be greater than or equal to 0")); + return my::clamp(angle / kAnglesInBucket, 0.0, 255.0); +} + +// This class is used to get correct points for further bearing calculations. +// Depending on |isLastPoint| it either calculates those points straightforwardly +// or reverses directions and then calculates. +class BearingPointsSelector +{ +public: + BearingPointsSelector(uint32_t const bearDistM, bool const isLastPoint) + : m_bearDistM(bearDistM), m_isLastPoint(isLastPoint) + { + } + + m2::PointD GetBearingStartPoint(Graph::Edge const & e) const + { + return m_isLastPoint ? e.GetEndPoint() : e.GetStartPoint(); + } + + m2::PointD GetBearingEndPoint(Graph::Edge const & e, uint32_t const distanceM) + { + if (distanceM < m_bearDistM && m_bearDistM <= distanceM + EdgeLength(e)) + { + auto const edgeLen = EdgeLength(e); + auto const edgeBearDist = min(m_bearDistM - distanceM, edgeLen); + ASSERT_LESS_OR_EQUAL(edgeBearDist, edgeLen, ()); + return m_isLastPoint ? PointAtSegmentM(e.GetEndPoint(), e.GetStartPoint(), + static_cast(edgeBearDist)) + : PointAtSegmentM(e.GetStartPoint(), e.GetEndPoint(), + static_cast(edgeBearDist)); + } + return m_isLastPoint ? e.GetStartPoint() : e.GetEndPoint(); + } + +private: + uint32_t m_bearDistM; + bool m_isLastPoint; +}; +} // namespace + +// CandidatePathsGetter::Link ---------------------------------------------------------------------- +bool CandidatePathsGetter::Link::operator<(Link const & o) const +{ + if (m_distanceM != o.m_distanceM) + return m_distanceM < o.m_distanceM; + + if (m_edge != o.m_edge) + return m_edge < o.m_edge; + + if (m_parent == o.m_parent) + return false; + + if (m_parent && o.m_parent) + return *m_parent < *o.m_parent; + + if (!m_parent) + return true; + + return false; +} + +Graph::Edge CandidatePathsGetter::Link::GetStartEdge() const +{ + auto * start = this; + while (start->m_parent) + start = start->m_parent.get(); + + return start->m_edge; +} + +bool CandidatePathsGetter::Link::IsJunctionInPath(routing::Junction const & j) const +{ + for (auto * l = this; l; l = l->m_parent.get()) + { + if (l->m_edge.GetEndJunction() == j) + { + LOG(LDEBUG, ("A loop detected, skipping...")); + return true; + } + } + + return false; +} + +// CandidatePathsGetter ---------------------------------------------------------------------------- +bool CandidatePathsGetter::GetLineCandidatesForPoints( + vector const & points, + vector> & lineCandidates) +{ + for (size_t i = 0; i < points.size(); ++i) + { + if (i != points.size() - 1 && points[i].m_distanceToNextPoint == 0) + { + LOG(LINFO, ("Distance to next point is zero. Skipping the whole segment")); + ++m_stats.m_dnpIsZero; + return false; + } + + lineCandidates.emplace_back(); + auto const isLastPoint = i == points.size() - 1; + auto const distanceToNextPoint = + (isLastPoint ? points[i - 1] : points[i]).m_distanceToNextPoint; + + vector pointCandidates; + m_pointsGetter.GetCandidatePoints(MercatorBounds::FromLatLon(points[i].m_latLon), + pointCandidates); + GetLineCandidates(points[i], isLastPoint, distanceToNextPoint, pointCandidates, + lineCandidates.back()); + + if (lineCandidates.back().empty()) + { + LOG(LINFO, ("No candidate lines found for point", points[i].m_latLon, "Giving up")); + ++m_stats.m_noCandidateFound; + return false; + } + } + + ASSERT_EQUAL(lineCandidates.size(), points.size(), ()); + + return true; +} + +void CandidatePathsGetter::GetStartLines(vector const & points, bool const isLastPoint, + Graph::EdgeVector & edges) +{ + ScopedTimer t(m_stats.m_startLinesTime); + + for (auto const & pc : points) + { + if (!isLastPoint) + m_graph.GetOutgoingEdges(Junction(pc, 0 /* altitude */), edges); + else + m_graph.GetIngoingEdges(Junction(pc, 0 /* altitude */), edges); + } + + // Same edges may start on different points if those points are close enough. + my::SortUnique(edges, less(), EdgesAreAlmostEqual); +} + +void CandidatePathsGetter::GetAllSuitablePaths(Graph::EdgeVector const & startLines, + bool const isLastPoint, uint32_t const bearDistM, + FunctionalRoadClass const frc, + vector & allPaths) +{ + ScopedTimer t(m_stats.m_allStatPathsTime); + + queue q; + + for (auto const & e : startLines) + { + auto const u = make_shared(nullptr /* parent */, e, 0 /* distanceM */); + q.push(u); + } + + while (!q.empty()) + { + auto const u = q.front(); + q.pop(); + + auto const & currentEdge = u->m_edge; + auto const currentEdgeLen = EdgeLength(currentEdge); + + // TODO(mgsergio): Maybe weak this constraint a bit. + if (u->m_distanceM + currentEdgeLen >= bearDistM) + { + allPaths.push_back(u); + continue; + } + + ASSERT_LESS(u->m_distanceM + currentEdgeLen, bearDistM, ()); + + Graph::EdgeVector edges; + if (!isLastPoint) + m_graph.GetOutgoingEdges(currentEdge.GetEndJunction(), edges); + else + m_graph.GetIngoingEdges(currentEdge.GetStartJunction(), edges); + + for (auto const & e : edges) + { + if (EdgesAreAlmostEqual(e.GetReverseEdge(), currentEdge)) + continue; + + ASSERT(currentEdge.HasRealPart(), ()); + + if (!PassesRestriction(e, frc, kFRCThreshold, m_infoGetter)) + continue; + + // TODO(mgsergio): Should we check form of way as well? + + if (u->IsJunctionInPath(e.GetEndJunction())) + continue; + + auto const p = make_shared(u, e, u->m_distanceM + currentEdgeLen); + q.push(p); + } + } +} + +void CandidatePathsGetter::GetBestCandidatePaths( + vector const & allPaths, bool const isLastPoint, uint32_t const requiredBearing, + uint32_t const bearDistM, m2::PointD const & startPoint, vector & candidates) +{ + ScopedTimer t(m_stats.m_bestCandidatePathsTime); + + set candidatePaths; + set fakeEndingsCandidatePaths; + + BearingPointsSelector pointsSelector(bearDistM, isLastPoint); + for (auto const & l : allPaths) + { + auto const bearStartPoint = pointsSelector.GetBearingStartPoint(l->GetStartEdge()); + auto const startPointsDistance = + static_cast(MercatorBounds::DistanceOnEarth(bearStartPoint, startPoint)); + + // Number of edges counting from the last one to check bearing on. Accorfing to OpenLR spec + // we have to check bearing on a point that is no longer than 25 meters traveling down the path. + // But sometimes we may skip the best place to stop and generate a candidate. So we check several + // edges before the last one to avoid such a situation. Number of iterations is taken + // by intuition. + // Example: + // o -------- o { Partners segment. } + // o ------- o --- o { Our candidate. } + // ^ 25m + // ^ This one may be better than + // ^ this one. + // So we want to check them all. + uint32_t traceBackIterationsLeft = 3; + for (auto part = l; part; part = part->m_parent) + { + if (traceBackIterationsLeft == 0) + break; + + --traceBackIterationsLeft; + + auto const bearEndPoint = + pointsSelector.GetBearingEndPoint(part->m_edge, part->m_distanceM); + + auto const bearing = Bearing(bearStartPoint, bearEndPoint); + auto const bearingDiff = AbsDifference(bearing, requiredBearing); + auto const pathDistDiff = AbsDifference(part->m_distanceM, bearDistM); + + // TODO(mgsergio): Check bearing is within tolerance. Add to canidates if it is. + + if (part->m_hasFake) + fakeEndingsCandidatePaths.emplace(part, bearingDiff, pathDistDiff, startPointsDistance); + else + candidatePaths.emplace(part, bearingDiff, pathDistDiff, startPointsDistance); + } + } + + ASSERT( + none_of(begin(candidatePaths), end(candidatePaths), mem_fn(&CandidatePath::HasFakeEndings)), + ()); + ASSERT(fakeEndingsCandidatePaths.empty() || + any_of(begin(fakeEndingsCandidatePaths), end(fakeEndingsCandidatePaths), + mem_fn(&CandidatePath::HasFakeEndings)), + ()); + + vector paths; + copy_n(begin(candidatePaths), min(static_cast(kMaxCandidates), candidatePaths.size()), + back_inserter(paths)); + + copy_n(begin(fakeEndingsCandidatePaths), + min(static_cast(kMaxFakeCandidates), fakeEndingsCandidatePaths.size()), + back_inserter(paths)); + + LOG(LDEBUG, ("List candidate paths...")); + for (auto const & path : paths) + { + LOG(LDEBUG, ("CP:", path.m_bearingDiff, path.m_pathDistanceDiff, path.m_startPointDistance)); + Graph::EdgeVector edges; + for (auto * p = path.m_path.get(); p; p = p->m_parent.get()) + edges.push_back(p->m_edge); + if (!isLastPoint) + reverse(begin(edges), end(edges)); + + candidates.emplace_back(move(edges)); + } +} + +void CandidatePathsGetter::GetLineCandidates(openlr::LocationReferencePoint const & p, + bool const isLastPoint, + uint32_t const distanceToNextPoint, + vector const & pointCandidates, + vector & candidates) +{ + ScopedTimer t(m_stats.m_lineCandidatesTime); + + uint32_t const kDefaultBearDistM = 25; + uint32_t const bearDistM = min(kDefaultBearDistM, distanceToNextPoint); + + LOG(LINFO, ("BearDist is", bearDistM)); + + Graph::EdgeVector startLines; + GetStartLines(pointCandidates, isLastPoint, startLines); + + LOG(LINFO, (startLines.size(), "start line candidates found for point (LatLon)", p.m_latLon)); + LOG(LDEBUG, ("Listing start lines:")); + for (auto const & e : startLines) + LOG(LDEBUG, (LogAs2GisPath(e))); + + auto const startPoint = MercatorBounds::FromLatLon(p.m_latLon); + + vector allPaths; + GetAllSuitablePaths(startLines, isLastPoint, bearDistM, p.m_functionalRoadClass, allPaths); + GetBestCandidatePaths(allPaths, isLastPoint, p.m_bearing, bearDistM, startPoint, candidates); + LOG(LDEBUG, (candidates.size(), "candidate paths found for point (LatLon)", p.m_latLon)); +} +} // namespace openlr diff --git a/openlr/candidate_paths_getter.hpp b/openlr/candidate_paths_getter.hpp new file mode 100644 index 0000000000..e59226bd7f --- /dev/null +++ b/openlr/candidate_paths_getter.hpp @@ -0,0 +1,130 @@ +#pragma once + +#include "openlr/graph.hpp" +#include "openlr/openlr_model.hpp" +#include "openlr/road_info_getter.hpp" +#include "openlr/stats.hpp" + +#include "geometry/point2d.hpp" + +#include +#include +#include +#include +#include + +namespace openlr +{ +class CandidatePointsGetter; + +class CandidatePathsGetter +{ +public: + CandidatePathsGetter(CandidatePointsGetter & pointsGetter, Graph & graph, + RoadInfoGetter & infoGetter, v2::Stats & stat) + : m_pointsGetter(pointsGetter), m_graph(graph), m_infoGetter(infoGetter), m_stats(stat) + { + } + + bool GetLineCandidatesForPoints(std::vector const & points, + std::vector> & lineCandidates); + +private: + struct Link; + using LinkPtr = std::shared_ptr; + + size_t static constexpr kMaxCandidates = 5; + size_t static constexpr kMaxFakeCandidates = 2; + + // TODO(mgsergio): Rename to Vertex. + struct Link + { + Link(LinkPtr const & parent, Graph::Edge const & edge, uint32_t const distanceM) + : m_parent(parent) + , m_edge(edge) + , m_distanceM(distanceM) + , m_hasFake((parent && parent->m_hasFake) || edge.IsFake()) + { + } + + bool operator<(Link const & o) const; + bool IsJunctionInPath(routing::Junction const & j) const; + + Graph::Edge GetStartEdge() const; + + LinkPtr const m_parent; + Graph::Edge const m_edge; + uint32_t const m_distanceM; + bool const m_hasFake; + }; + + struct CandidatePath + { + double static constexpr kBearingDiffFactor = 5; + double static constexpr kPathDistanceFactor = 1; + double static constexpr kPointDistanceFactor = 2; + + CandidatePath() = default; + + CandidatePath(LinkPtr const path, uint32_t const bearingDiff, uint32_t const pathDistanceDiff, + uint32_t const startPointDistance) + : m_path(path) + , m_bearingDiff(bearingDiff) + , m_pathDistanceDiff(pathDistanceDiff) + , m_startPointDistance(startPointDistance) + { + } + + bool operator<(CandidatePath const & o) const { return GetPenalty() < o.GetPenalty(); } + + double GetPenalty() const + { + return kBearingDiffFactor * m_bearingDiff + kPathDistanceFactor * m_pathDistanceDiff + + kPointDistanceFactor * m_startPointDistance; + } + + bool HasFakeEndings() const { return m_path && m_path->m_hasFake; } + + LinkPtr m_path = nullptr; + uint32_t m_bearingDiff = std::numeric_limits::max(); // Domain is roughly [0, 30] + uint32_t m_pathDistanceDiff = + std::numeric_limits::max(); // Domain is roughly [0, 25] + uint32_t m_startPointDistance = + std::numeric_limits::max(); // Domain is roughly [0, 50] + }; + + // Note: In all methods below if |isLastPoint| is true than algorithm should + // calculate all parameters (such as bearing, distance to next point, etc.) + // relative to the last point. + // o ----> o ----> o <---- o. + // 1 2 3 4 + // ^ isLastPoint = true. + // To calculate bearing for points 1 to 3 one have to go beardist from + // previous point to the next one (eg. from 1 to 2 and from 2 to 3). + // For point 4 one have to go from 4 to 3 reversing directions. And + // distance-to-next point is taken from point 3. You can learn more in + // TomTom OpenLR spec. + + void GetStartLines(std::vector const & points, bool const isLastPoint, + Graph::EdgeVector & edges); + + void GetAllSuitablePaths(Graph::EdgeVector const & startLines, bool const isLastPoint, + uint32_t const bearDistM, FunctionalRoadClass const frc, + std::vector & allPaths); + + void GetBestCandidatePaths(std::vector const & allPaths, bool const isLastPoint, + uint32_t const requiredBearing, uint32_t const bearDistM, + m2::PointD const & startPoint, + std::vector & candidates); + + void GetLineCandidates(openlr::LocationReferencePoint const & p, bool const isLastPoint, + uint32_t const distanceToNextPoint, + std::vector const & pointCandidates, + std::vector & candidates); + + CandidatePointsGetter & m_pointsGetter; + Graph & m_graph; + RoadInfoGetter & m_infoGetter; + v2::Stats & m_stats; +}; +} // namespace openlr diff --git a/openlr/helpers.cpp b/openlr/helpers.cpp new file mode 100644 index 0000000000..9343472e8b --- /dev/null +++ b/openlr/helpers.cpp @@ -0,0 +1,69 @@ +#include "openlr/helpers.hpp" + +#include "openlr/road_info_getter.hpp" + +#include "routing/features_road_graph.hpp" + +#include "geometry/mercator.hpp" + +#include "base/timer.hpp" + +#include +#include +#include + +namespace openlr +{ +bool PointsAreClose(m2::PointD const & p1, m2::PointD const & p2) +{ + double const kMwmRoadCrossingRadiusMeters = routing::GetRoadCrossingRadiusMeters(); + return MercatorBounds::DistanceOnEarth(p1, p2) < kMwmRoadCrossingRadiusMeters; +} + +// TODO(mgsergio): Try to use double instead of uint32_t and leave whait is better. +uint32_t EdgeLength(Graph::Edge const & e) +{ + return static_cast(MercatorBounds::DistanceOnEarth(e.GetStartPoint(), e.GetEndPoint())); +} + +bool EdgesAreAlmostEqual(Graph::Edge const & e1, Graph::Edge const & e2) +{ + // TODO(mgsergio): Do I need to check fields other than points? + return PointsAreClose(e1.GetStartPoint(), e2.GetStartPoint()) && + PointsAreClose(e1.GetEndPoint(), e2.GetEndPoint()); +} + +std::string LogAs2GisPath(Graph::EdgeVector const & path) +{ + CHECK(!path.empty(), ("Paths should not be empty")); + + std::ostringstream ost; + ost << "https://2gis.ru/moscow?queryState="; + + auto ll = MercatorBounds::ToLatLon(path.front().GetStartPoint()); + ost << "center%2F" << ll.lon << "%2C" << ll.lat << "%2F"; + ost << "zoom%2F" << 17 << "%2F"; + ost << "ruler%2Fpoints%2F"; + for (auto const & e : path) + { + ll = MercatorBounds::ToLatLon(e.GetStartPoint()); + ost << ll.lon << "%20" << ll.lat << "%2C"; + } + ll = MercatorBounds::ToLatLon(path.back().GetEndPoint()); + ost << ll.lon << "%20" << ll.lat; + + return ost.str(); +} + +std::string LogAs2GisPath(Graph::Edge const & e) { return LogAs2GisPath(Graph::EdgeVector({e})); } + +bool PassesRestriction(Graph::Edge const & e, FunctionalRoadClass const restriction, + int const frcThreshold, RoadInfoGetter & infoGetter) +{ + if (e.IsFake()) + return true; + + auto const frc = infoGetter.Get(e.GetFeatureId()).m_frc; + return static_cast(frc) <= static_cast(restriction) + frcThreshold; +} +} // namespace openlr diff --git a/openlr/helpers.hpp b/openlr/helpers.hpp index 9071b1d092..b784a3eab9 100644 --- a/openlr/helpers.hpp +++ b/openlr/helpers.hpp @@ -1,66 +1,28 @@ #pragma once #include "openlr/graph.hpp" +#include "openlr/openlr_model.hpp" -#include "routing/features_road_graph.hpp" - -#include "geometry/mercator.hpp" #include "geometry/point2d.hpp" #include "base/timer.hpp" -#include -#include #include namespace openlr { -inline bool PointsAreClose(m2::PointD const & p1, m2::PointD const & p2) -{ - double const kMwmRoadCrossingRadiusMeters = routing::GetRoadCrossingRadiusMeters(); - return MercatorBounds::DistanceOnEarth(p1, p2) < kMwmRoadCrossingRadiusMeters; -} +class RoadInfoGetter; + +bool PointsAreClose(m2::PointD const & p1, m2::PointD const & p2); // TODO(mgsergio): Try to use double instead of uint32_t and leave whait is better. -inline uint32_t EdgeLength(Graph::Edge const & e) -{ - return static_cast(MercatorBounds::DistanceOnEarth(e.GetStartPoint(), e.GetEndPoint())); -} +uint32_t EdgeLength(Graph::Edge const & e); -inline bool EdgesAraAlmostEqual(Graph::Edge const & e1, Graph::Edge const & e2) -{ - // TODO(mgsergio): Do I need to check fields other than points? - return PointsAreClose(e1.GetStartPoint(), e2.GetStartPoint()) && - PointsAreClose(e1.GetEndPoint(), e2.GetEndPoint()); -} +bool EdgesAreAlmostEqual(Graph::Edge const & e1, Graph::Edge const & e2); // TODO(mgsergio): Remove when unused. -inline std::string LogAs2GisPath(Graph::EdgeVector const & path) -{ - CHECK(!path.empty(), ("Paths should not be empty")); - - std::ostringstream ost; - ost << "https://2gis.ru/moscow?queryState="; - - auto ll = MercatorBounds::ToLatLon(path.front().GetStartPoint()); - ost << "center%2F" << ll.lon << "%2C" << ll.lat << "%2F"; - ost << "zoom%2F" << 17 <<"%2F"; - ost << "ruler%2Fpoints%2F"; - for (auto const & e : path) - { - ll = MercatorBounds::ToLatLon(e.GetStartPoint()); - ost << ll.lon << "%20" << ll.lat << "%2C"; - } - ll = MercatorBounds::ToLatLon(path.back().GetEndPoint()); - ost << ll.lon << "%20" << ll.lat; - - return ost.str(); -} - -inline std::string LogAs2GisPath(Graph::Edge const & e) -{ - return LogAs2GisPath(Graph::EdgeVector({e})); -} +std::string LogAs2GisPath(Graph::EdgeVector const & path); +std::string LogAs2GisPath(Graph::Edge const & e); template < typename T, typename U, @@ -80,4 +42,8 @@ public: private: std::chrono::milliseconds & m_ms; }; + +bool PassesRestriction(Graph::Edge const & e, FunctionalRoadClass const restriction, + int const frcThreshold, RoadInfoGetter & infoGetter); + } // namespace openlr diff --git a/openlr/router.cpp b/openlr/router.cpp index 3ebdc02c6d..0b45575725 100644 --- a/openlr/router.cpp +++ b/openlr/router.cpp @@ -1,5 +1,6 @@ #include "openlr/router.hpp" +#include "openlr/helpers.hpp" #include "openlr/road_info_getter.hpp" #include "routing/features_road_graph.hpp" @@ -425,16 +426,6 @@ bool Router::MayMoveToNextStage(Vertex const & u, double pi) const return NearNextStage(u, pi) && u.m_bearingChecked; } -bool Router::PassesRestriction(routing::Edge const & edge, - FunctionalRoadClass const restriction) const -{ - if (edge.IsFake()) - return true; - - auto const frc = m_roadInfoGetter.Get(edge.GetFeatureId()).m_frc; - return static_cast(frc) <= static_cast(restriction) + kFRCThreshold; -} - uint32_t Router::GetReverseBearing(Vertex const & u, Links const & links) const { m2::PointD const a = u.m_junction.GetPoint(); @@ -485,7 +476,7 @@ void Router::ForEachEdge(Vertex const & u, bool outgoing, FunctionalRoadClass re GetIngoingEdges(u.m_junction, edges); for (auto const & edge : edges) { - if (!PassesRestriction(edge, restriction)) + if (!PassesRestriction(edge, restriction, kFRCThreshold, m_roadInfoGetter)) continue; fn(edge); } @@ -545,7 +536,7 @@ void Router::ForEachNonFakeClosestEdge(Vertex const & u, FunctionalRoadClass con auto const & edge = p.first; if (edge.IsFake()) continue; - if (!PassesRestriction(edge, restriction)) + if (!PassesRestriction(edge, restriction, kFRCThreshold, m_roadInfoGetter)) continue; fn(edge); } diff --git a/openlr/router.hpp b/openlr/router.hpp index 9c617a57da..89ad635d4a 100644 --- a/openlr/router.hpp +++ b/openlr/router.hpp @@ -126,8 +126,6 @@ private: double GetWeight(Edge const & e) const { return GetWeight(e.m_raw); } - bool PassesRestriction(routing::Edge const & edge, FunctionalRoadClass const restriction) const; - uint32_t GetReverseBearing(Vertex const & u, Links const & links) const; template