diff --git a/generator/CMakeLists.txt b/generator/CMakeLists.txt index fd208f5d14..1837bced70 100644 --- a/generator/CMakeLists.txt +++ b/generator/CMakeLists.txt @@ -35,6 +35,7 @@ set( cities_ids_builder.hpp city_roads_generator.cpp city_roads_generator.hpp + cluster_finder.hpp coastlines_generator.cpp coastlines_generator.hpp collection_base.hpp diff --git a/generator/cluster_finder.hpp b/generator/cluster_finder.hpp new file mode 100644 index 0000000000..77268fbef7 --- /dev/null +++ b/generator/cluster_finder.hpp @@ -0,0 +1,105 @@ +#pragma once + +#include "geometry/mercator.hpp" +#include "geometry/rect2d.hpp" +#include "geometry/tree4d.hpp" + +#include +#include +#include +#include +#include + +namespace generator +{ +// The class ClustersFinder finds clusters of objects for which IsSameFunc will return the true. +// RadiusFunc should return the same radius for all objects in one cluster. +template class Container, typename Alloc = std::allocator> +class ClustersFinder +{ +public: + using RadiusFunc = std::function; + using IsSameFunc = std::function; + + ClustersFinder(Container && container, RadiusFunc const & radiusFunc, + IsSameFunc const & isSameFunc) + : m_container(std::move(container)), m_radiusFunc(radiusFunc), m_isSameFunc(isSameFunc) + { + for (auto const & e : m_container) + m_tree.Add(&e); + } + + std::vector> Find() const + { + std::vector> clusters; + std::set unviewed; + for (auto const & e : m_container) + unviewed.insert(&e); + + while (!unviewed.empty()) + { + auto const it = *std::cbegin(unviewed); + clusters.emplace_back(FindOneCluster(it, unviewed)); + } + return clusters; + } + +private: + using ConstIterator = T const *; + + struct TraitsDef + { + m2::RectD const LimitRect(ConstIterator const & it) const { return GetLimitRect(*it); } + }; + + std::vector FindOneCluster(ConstIterator const & it, std::set & unviewed) const + { + 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 & candidate) { + if (unviewed.count(candidate) == 0 || !m_isSameFunc(*it, *candidate)) + return; + + unviewed.erase(candidate); + queue.emplace(candidate); + cluster.emplace_back(*candidate); + }); + } + + return cluster; + } + + m2::RectD GetBboxFor(ConstIterator const & it) const + { + m2::RectD bbox; + auto const dist = m_radiusFunc(*it); + GetLimitRect(*it).ForEachCorner([&](auto const & p) { + bbox.Add(mercator::RectByCenterXYAndSizeInMeters(p, dist)); + }); + + return bbox; + } + + Container m_container; + RadiusFunc m_radiusFunc; + IsSameFunc m_isSameFunc; + m4::Tree m_tree; +}; + +template class Container, typename Alloc = std::allocator> +std::vector> GetClusters( + Container && container, + typename ClustersFinder::RadiusFunc const & radiusFunc, + typename ClustersFinder::IsSameFunc const & isSameFunc) +{ + return ClustersFinder(std::forward>(container), + radiusFunc, isSameFunc).Find(); +} +} // namespace generator diff --git a/generator/generator_tests/cluster_finder_tests.cpp b/generator/generator_tests/cluster_finder_tests.cpp index b94918d1bd..173d0f2e75 100644 --- a/generator/generator_tests/cluster_finder_tests.cpp +++ b/generator/generator_tests/cluster_finder_tests.cpp @@ -1,6 +1,6 @@ #include "testing/testing.hpp" -#include "generator/place_processor.hpp" +#include "generator/cluster_finder.hpp" #include "geometry/mercator.hpp" #include "geometry/point2d.hpp" diff --git a/generator/place_processor.cpp b/generator/place_processor.cpp index ffb1f0e724..e436e25a98 100644 --- a/generator/place_processor.cpp +++ b/generator/place_processor.cpp @@ -1,5 +1,6 @@ #include "generator/place_processor.hpp" +#include "generator/cluster_finder.hpp" #include "generator/feature_maker_base.hpp" #include "generator/type_helper.hpp" diff --git a/generator/place_processor.hpp b/generator/place_processor.hpp index 197e9dee8a..0b0b36343d 100644 --- a/generator/place_processor.hpp +++ b/generator/place_processor.hpp @@ -3,15 +3,12 @@ #include "generator/cities_boundaries_builder.hpp" #include "generator/feature_builder.hpp" -#include "geometry/mercator.hpp" -#include "geometry/tree4d.hpp" +#include "geometry/rect2d.hpp" #include "base/geo_object_id.hpp" #include #include -#include -#include #include #include #include @@ -19,96 +16,6 @@ namespace generator { -// The class ClustersFinder finds clusters of objects for which IsSameFunc will return the true. -// RadiusFunc should return the same radius for all objects in one cluster. -template class Container, typename Alloc = std::allocator> -class ClustersFinder -{ -public: - using RadiusFunc = std::function; - using IsSameFunc = std::function; - using ConstIterator = T const *; - - ClustersFinder(Container && container, RadiusFunc const & radiusFunc, - IsSameFunc const & isSameFunc) - : m_container(std::move(container)), m_radiusFunc(radiusFunc), m_isSameFunc(isSameFunc) - { - for (auto const & e : m_container) - m_tree.Add(&e); - } - - std::vector> Find() const - { - std::vector> clusters; - std::set unviewed; - for (auto const & e : m_container) - unviewed.insert(&e); - - while (!unviewed.empty()) - { - auto const it = *std::cbegin(unviewed); - clusters.emplace_back(FindOneCluster(it, unviewed)); - } - return clusters; - } - -private: - struct TraitsDef - { - m2::RectD const LimitRect(ConstIterator const & it) const { return GetLimitRect(*it); } - }; - - std::vector FindOneCluster(ConstIterator const & it, std::set & unviewed) const - { - 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 & candidate) { - if (unviewed.count(candidate) == 0 || !m_isSameFunc(*it, *candidate)) - return; - - unviewed.erase(candidate); - queue.emplace(candidate); - cluster.emplace_back(*candidate); - }); - } - - return cluster; - } - - m2::RectD GetBboxFor(ConstIterator const & it) const - { - m2::RectD bbox; - auto const dist = m_radiusFunc(*it); - GetLimitRect(*it).ForEachCorner([&](auto const & p) { - bbox.Add(mercator::RectByCenterXYAndSizeInMeters(p, dist)); - }); - - return bbox; - } - - Container m_container; - RadiusFunc m_radiusFunc; - IsSameFunc m_isSameFunc; - m4::Tree m_tree; -}; - -template class Container, typename Alloc = std::allocator> -std::vector> GetClusters( - Container && container, - typename ClustersFinder::RadiusFunc const & radiusFunc, - typename ClustersFinder::IsSameFunc const & isSameFunc) -{ - return ClustersFinder(std::forward>(container), - radiusFunc, isSameFunc).Find(); -} - bool NeedProcessPlace(feature::FeatureBuilder const & fb); // This structure encapsulates work with elements of different types.