#include "openlr/score_candidate_points_getter.hpp" #include "openlr/helpers.hpp" #include "routing/road_graph.hpp" #include "routing/routing_helpers.hpp" #include "storage/country_info_getter.hpp" #include "indexer/feature.hpp" #include "indexer/scales.hpp" #include "geometry/mercator.hpp" #include "base/assert.hpp" #include "base/stl_helpers.hpp" #include #include #include using namespace routing; namespace { // Ends of segments and intermediate points of segments are considered only within this radius. double const kRadius = 30.0; } // namespace namespace openlr { void ScoreCandidatePointsGetter::GetJunctionPointCandidates(m2::PointD const & p, bool isLastPoint, ScoreEdgeVec & edgeCandidates) { ScorePointVec pointCandidates; auto const selectCandidates = [&p, &pointCandidates, this](FeatureType & ft) { ft.ParseGeometry(FeatureType::BEST_GEOMETRY); ft.ForEachPoint( [&p, &pointCandidates, this](m2::PointD const & candidate) { if (MercatorBounds::DistanceOnEarth(p, candidate) < kRadius) pointCandidates.emplace_back(GetScoreByDistance(p, candidate), candidate); }, scales::GetUpperScale()); }; m_dataSource.ForEachInRect(selectCandidates, MercatorBounds::RectByCenterXYAndSizeInMeters(p, kRadius), scales::GetUpperScale()); base::SortUnique(pointCandidates); std::reverse(pointCandidates.begin(), pointCandidates.end()); pointCandidates.resize(std::min(m_maxJunctionCandidates, pointCandidates.size())); for (auto const & pc : pointCandidates) { Graph::EdgeVector edges; if (!isLastPoint) m_graph.GetOutgoingEdges(Junction(pc.m_point, 0 /* altitude */), edges); else m_graph.GetIngoingEdges(Junction(pc.m_point, 0 /* altitude */), edges); for (auto const & e : edges) edgeCandidates.emplace_back(pc.m_score, e); } } void ScoreCandidatePointsGetter::EnrichWithProjectionPoints(m2::PointD const & p, ScoreEdgeVec & edgeCandidates) { m_graph.ResetFakes(); vector> vicinities; m_graph.FindClosestEdges(p, static_cast(m_maxProjectionCandidates), vicinities); for (auto const & v : vicinities) { auto const & edge = v.first; auto const & proj = v.second; CHECK(edge.HasRealPart(), ()); CHECK(!edge.IsFake(), ()); if (MercatorBounds::DistanceOnEarth(p, proj.GetPoint()) >= kRadius) continue; edgeCandidates.emplace_back(GetScoreByDistance(p, proj.GetPoint()), edge); } } bool ScoreCandidatePointsGetter::IsJunction(m2::PointD const & p) { Graph::EdgeVector outgoing; m_graph.GetRegularOutgoingEdges(Junction(p, 0 /* altitude */), outgoing); Graph::EdgeVector ingoing; m_graph.GetRegularIngoingEdges(Junction(p, 0 /* altitude */), ingoing); // Note. At mwm borders the size of |ids| may be bigger than two in case of straight // road because of road feature duplication at borders. std::set> ids; for (auto const & e : outgoing) ids.insert(std::make_pair(e.GetFeatureId().m_index, e.GetSegId())); for (auto const & e : ingoing) ids.insert(std::make_pair(e.GetFeatureId().m_index, e.GetSegId())); // Size of |ids| is number of different pairs of (feature id, segment id) starting from // |p| plus going to |p|. The size 0, 1 or 2 is considered |p| is not a junction of roads. // If the size is 3 or more it means |p| is an intersection of 3 or more roads. return ids.size() >= 3; } Score ScoreCandidatePointsGetter::GetScoreByDistance(m2::PointD const & point, m2::PointD const & candidate) { // Maximum possible score for the distance between an openlr segment ends and an osm segments. Score constexpr kMaxScoreForDist = 70; // If the distance between an openlr segments end and an osm segments end is less or equal // |kMaxScoreDistM| the point gets |kMaxScoreForDist| score. double constexpr kMaxScoreDistM = 5.0; // According to the standard openlr edge should be started from a junction. Despite the fact // that openlr and osm are based on different graphs, the score of junction should be increased. double const junctionFactor = IsJunction(candidate) ? 1.1 : 1.0; double const distM = MercatorBounds::DistanceOnEarth(point, candidate); double const score = distM <= kMaxScoreDistM ? kMaxScoreForDist * junctionFactor : static_cast(kMaxScoreForDist) * junctionFactor / (1.0 + distM - kMaxScoreDistM); CHECK_GREATER_OR_EQUAL(score, 0.0, ()); CHECK_LESS_OR_EQUAL(score, static_cast(kMaxScoreForDist) * junctionFactor, ()); return static_cast(score); } } // namespace openlr