From 3b26b2e7cb1df023f5d205f7472e73ab3e321fd8 Mon Sep 17 00:00:00 2001 From: Maksim Andrianov Date: Thu, 29 Aug 2019 19:34:51 +0300 Subject: [PATCH] [generator] Added ClustersFinder. --- .../final_processor_intermediate_mwm.cpp | 2 +- generator/place_processor.cpp | 53 +++++------- generator/place_processor.hpp | 82 +++++++++++++++++++ 3 files changed, 105 insertions(+), 32 deletions(-) diff --git a/generator/final_processor_intermediate_mwm.cpp b/generator/final_processor_intermediate_mwm.cpp index 7926b204ea..2fb8b6e2f0 100644 --- a/generator/final_processor_intermediate_mwm.cpp +++ b/generator/final_processor_intermediate_mwm.cpp @@ -235,7 +235,7 @@ private: { for (auto const & id : fbWithIds.second) { - if (cities.count(id) != 0) + if (cities.count(id) == 0) continue; auto static const kPromoType = classif().GetTypeByPath({"sponsored", "promo_catalog"}); diff --git a/generator/place_processor.cpp b/generator/place_processor.cpp index b954e6a875..d9f2895c09 100644 --- a/generator/place_processor.cpp +++ b/generator/place_processor.cpp @@ -81,19 +81,15 @@ bool IsTheSamePlace(T const & left, T const & right) return dist <= GetThresholdM(localityL); } -template -Iterator FindGroupOfTheSamePlaces(Iterator start, Iterator end) +std::vector> FindClusters(std::vector && places) { - CHECK(start != end, ()); - auto next = start; - while (++next != end) - { - if (!IsTheSamePlace(*next, *start)) - return next; - - start = next; - } - return end; + auto func = [](FeaturePlace const & fp) { + auto const & localityChecker = ftypes::IsLocalityChecker::Instance(); + auto const locality = localityChecker.GetType(GetPlaceType(fp.GetFb())); + return GetThresholdM(locality); + }; + ClustersFinder f(std::move(places), func, IsTheSamePlace); + return f.Find(); } } // namespace @@ -131,6 +127,11 @@ m2::RectD const & FeaturePlace::GetLimitRect() const return m_limitRect; } +base::GeoObjectId FeaturePlace::GetMostGenericOsmId() const +{ + return GetFb().GetMostGenericOsmId(); +} + uint8_t FeaturePlace::GetRank() const { return GetFb().GetRank(); @@ -194,19 +195,11 @@ std::vector PlaceProcessor::ProcessPlaces() places.reserve(nameToGeoObjectIdToFeaturePlaces.second.size()); for (auto const & geoObjectIdToFeaturePlaces : nameToGeoObjectIdToFeaturePlaces.second) places.emplace_back(geoObjectIdToFeaturePlaces.second); - // Firstly, objects are geometrically sorted. - std::sort(std::begin(places), std::end(places), [](auto const & l, auto const & r) { - auto const & rectL = l.GetLimitRect(); - auto const & rectR = r.GetLimitRect(); - return rectL.Center() < rectR.Center(); - }); - // Secondly, a group of similar places is searched for, then a better place is searched in - // this group. - auto start = std::begin(places); - while (start != std::cend(places)) + + auto const clusters = FindClusters(std::move(places)); + for (auto const & cluster : clusters) { - auto end = FindGroupOfTheSamePlaces(start, std::end(places)); - auto best = std::max_element(start, end, IsWorsePlace); + auto best = std::max_element(std::cbegin(cluster), std::cend(cluster), IsWorsePlace); auto bestFb = best->GetFb(); auto const & localityChecker = ftypes::IsLocalityChecker::Instance(); if (bestFb.IsArea() && localityChecker.GetType(GetPlaceType(bestFb)) != ftypes::NONE) @@ -215,17 +208,15 @@ std::vector PlaceProcessor::ProcessPlaces() TransformAreaToPoint(bestFb); } std::vector ids; - ids.reserve(static_cast(std::distance(start, end))); - std::transform(start, end, std::back_inserter(ids), [](auto const & place) { - return place.GetMostGenericOsmId(); - }); + ids.reserve(cluster.size()); + std::transform(std::cbegin(cluster), std::cend(cluster), std::back_inserter(ids), + [](auto const & place) { return place.GetMostGenericOsmId(); }); finalPlaces.emplace_back(std::move(bestFb), std::move(ids)); if (m_boundariesTable) - FillTable(start, end, best); - - start = end; + FillTable(std::cbegin(cluster), std::cend(cluster), best); } } + return finalPlaces; } diff --git a/generator/place_processor.hpp b/generator/place_processor.hpp index 32271128aa..4dbdf48517 100644 --- a/generator/place_processor.hpp +++ b/generator/place_processor.hpp @@ -3,15 +3,96 @@ #include "generator/cities_boundaries_builder.hpp" #include "generator/feature_builder.hpp" +#include "geometry/mercator.hpp" +#include "geometry/tree4d.hpp" + #include "base/geo_object_id.hpp" +#include #include +#include +#include #include #include #include namespace generator { +template class Container, typename Alloc = std::allocator> +class ClustersFinder +{ +public: + using DistanceFunc = std::function; + using IsSameFunc = std::function; + using ConstIterator = T const *; + + ClustersFinder(Container && container, DistanceFunc distanceFunc, IsSameFunc isSameFunc) + : m_container(std::move(container)), m_distanseFunc(distanceFunc), m_isSameFunc(isSameFunc) + { + for (auto const & e : m_container) + m_tree.Add(&e); + } + + std::vector> Find() + { + std::vector> clusters; + std::set unviewed; + for (auto const & e : m_container) + unviewed.insert(&e); + + while (!unviewed.empty()) + clusters.emplace_back(FindOneCluster(*std::cbegin(unviewed), unviewed)); + + return clusters; + } + +private: + struct TraitsDef + { + m2::RectD const LimitRect(ConstIterator const & it) const { return it->GetLimitRect(); } + }; + + std::vector FindOneCluster(ConstIterator const & it, std::set & unviewed) + { + std::vector cluster{*it}; + std::queue queue; + queue.emplace(it); + unviewed.erase(it); + while (!queue.empty()) + { + auto const current = queue.front(); + queue.pop(); + auto const queryBbox = GetBboxFor(current); + m_tree.ForEachInRect(queryBbox, [&](auto const & conditate) { + if (current == conditate || unviewed.count(conditate) == 0 || !m_isSameFunc(*current, *conditate)) + return; + + unviewed.erase(conditate); + queue.emplace(conditate); + cluster.emplace_back(*conditate); + }); + } + + return cluster; + } + + m2::RectD GetBboxFor(ConstIterator const & it) + { + m2::RectD bbox; + it->GetLimitRect().ForEachCorner([&](auto const & p) { + auto const dist = m_distanseFunc(*it); + bbox.Add(MercatorBounds::RectByCenterXYAndSizeInMeters(p, dist)); + }); + + return bbox; + } + + Container m_container; + DistanceFunc m_distanseFunc; + IsSameFunc m_isSameFunc; + m4::Tree m_tree; +}; + bool NeedProcessPlace(feature::FeatureBuilder const & fb); // This structure encapsulates work with elements of different types. @@ -25,6 +106,7 @@ public: feature::FeatureBuilder const & GetFb() const; FeaturesBuilders const & GetFbs() const; m2::RectD const & GetLimitRect() const; + base::GeoObjectId GetMostGenericOsmId() const; uint8_t GetRank() const; std::string GetName() const; m2::PointD GetKeyPoint() const;