From 808ea9e32638ab6fbb4ffc7cf37c75eef08a7539 Mon Sep 17 00:00:00 2001 From: Maksim Andrianov Date: Tue, 2 Jul 2019 17:12:05 +0300 Subject: [PATCH] Optimization step 'generate_features': Added affilations. --- generator/affiliation.cpp | 62 ++++++++++++++++++++++++++++++++ generator/affiliation.hpp | 48 +++++++++++++++++++++++++ generator/borders.cpp | 59 +++++++++++++++++++++--------- generator/borders.hpp | 75 +++++++++++++++++++++++++++++++++++---- 4 files changed, 221 insertions(+), 23 deletions(-) create mode 100644 generator/affiliation.cpp create mode 100644 generator/affiliation.hpp diff --git a/generator/affiliation.cpp b/generator/affiliation.cpp new file mode 100644 index 0000000000..a21ab6540b --- /dev/null +++ b/generator/affiliation.cpp @@ -0,0 +1,62 @@ +#include "generator/affiliation.hpp" + +namespace feature +{ +CountriesFilesAffiliation::CountriesFilesAffiliation(std::string const & borderPath, bool isMwmsForWholeWorld) + : m_countries(borders::PackedBorders::GetOrCreate(borderPath)) + , m_isMwmsForWholeWorld(isMwmsForWholeWorld) +{ +} + +std::vector CountriesFilesAffiliation::GetAffiliations(FeatureBuilder const & fb) const +{ + std::vector countries; + std::vector> countriesContainer; + m_countries.ForEachInRect(fb.GetLimitRect(), [&](auto const & countryPolygons) { + countriesContainer.emplace_back(countryPolygons); + }); + + if (m_isMwmsForWholeWorld && countriesContainer.size() == 1) + { + borders::CountryPolygons const & countryPolygons= countriesContainer.front(); + countries.emplace_back(countryPolygons.GetName()); + return countries; + } + + if (!countriesContainer.empty()) + { + for (borders::CountryPolygons const & countryPolygons : countriesContainer) + { + auto const need = fb.ForAnyGeometryPoint([&](auto const & point) { + return countryPolygons.Contains(point); + }); + + if (need) + countries.emplace_back(countryPolygons.GetName()); + } + return countries; + } + + return countries; +} + +bool CountriesFilesAffiliation::HasRegionByName(std::string const & name) const +{ + return m_countries.HasRegionByName(name); +} + +OneFileAffiliation::OneFileAffiliation(std::string const & filename) + : m_filename(filename) +{ +} + +std::vector OneFileAffiliation::GetAffiliations(FeatureBuilder const &) const +{ + return {m_filename}; +} + +bool OneFileAffiliation::HasRegionByName(std::string const & name) const +{ + return name == m_filename; +} +} // namespace feature diff --git a/generator/affiliation.hpp b/generator/affiliation.hpp new file mode 100644 index 0000000000..dcd7ebc22b --- /dev/null +++ b/generator/affiliation.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include "generator/borders.hpp" +#include "generator/feature_builder.hpp" + +#include +#include + +namespace feature +{ +class AffiliationInterface +{ +public: + virtual ~AffiliationInterface() = default; + + virtual std::vector GetAffiliations(FeatureBuilder const & fb) const = 0; + virtual bool HasRegionByName(std::string const & name) const = 0; +}; + +class CountriesFilesAffiliation : public AffiliationInterface +{ +public: + CountriesFilesAffiliation(std::string const & borderPath, bool isMwmsForWholeWorld); + + // AffiliationInterface overrides: + std::vector GetAffiliations(FeatureBuilder const & fb) const override; + + bool HasRegionByName(std::string const & name) const override; + +private: + borders::CountriesContainer const & m_countries; + bool m_isMwmsForWholeWorld; +}; + +class OneFileAffiliation : public AffiliationInterface +{ +public: + OneFileAffiliation(std::string const & filename); + + // AffiliationInterface overrides: + std::vector GetAffiliations(FeatureBuilder const &) const override; + + bool HasRegionByName(std::string const & name) const override; + +private: + std::string m_filename; +}; +} // namespace feature diff --git a/generator/borders.cpp b/generator/borders.cpp index 526cffe01a..fea17c9a10 100644 --- a/generator/borders.cpp +++ b/generator/borders.cpp @@ -16,6 +16,7 @@ #include "geometry/parametrized_segment.hpp" #include "geometry/simplification.hpp" +#include "base/assert.hpp" #include "base/exception.hpp" #include "base/file_name_utils.hpp" #include "base/logging.hpp" @@ -29,6 +30,7 @@ #include #include "base/assert.hpp" +#include "base/string_utils.hpp" #include "defines.hpp" @@ -38,25 +40,20 @@ namespace { class PolygonLoader { - CountryPolygons m_polygons; - m2::RectD m_rect; - - CountriesContainer & m_countries; - public: - explicit PolygonLoader(CountriesContainer & countries) : m_countries(countries) {} + explicit PolygonLoader(m4::Tree & countries) : m_countries(countries) {} void operator()(std::string const & name, std::vector const & borders) { - if (m_polygons.m_name.empty()) - m_polygons.m_name = name; - + RegionsContainer regions; for (m2::RegionD const & border : borders) { m2::RectD const rect(border.GetRect()); m_rect.Add(rect); - m_polygons.m_regions.Add(border, rect); + regions.Add(border, rect); } + + m_polygons = CountryPolygons(name, regions); } void Finish() @@ -64,18 +61,23 @@ public: if (!m_polygons.IsEmpty()) { ASSERT_NOT_EQUAL(m_rect, m2::RectD::GetEmptyRect(), ()); - m_countries.Add(m_polygons, m_rect); + m_countries.Add(std::move(m_polygons), std::move(m_rect)); } m_polygons.Clear(); m_rect.MakeEmpty(); } + +private: + m4::Tree & m_countries; + CountryPolygons m_polygons; + m2::RectD m_rect; }; template void ForEachCountry(std::string const & baseDir, ToDo & toDo) { - std::string const bordersDir = baseDir + BORDERS_DIR; + std::string const bordersDir = base::JoinPath(baseDir, BORDERS_DIR); CHECK(Platform::IsFileExistsByFullPath(bordersDir), ("Cannot read borders directory", bordersDir)); @@ -221,16 +223,21 @@ bool GetBordersRect(std::string const & baseDir, std::string const & country, bool LoadCountriesList(std::string const & baseDir, CountriesContainer & countries) { - countries.Clear(); - + m4::Tree regionsTree; LOG(LINFO, ("Loading countries.")); - PolygonLoader loader(countries); + PolygonLoader loader(regionsTree); ForEachCountry(baseDir, loader); - LOG(LINFO, ("Countries loaded:", countries.GetSize())); + LOG(LINFO, ("Countries loaded:", regionsTree.GetSize())); - return !countries.IsEmpty(); + if (!regionsTree.IsEmpty()) + { + countries = CountriesContainer(regionsTree); + return true; + } + + return false; } void GeneratePackedBorders(std::string const & baseDir) @@ -287,4 +294,22 @@ void UnpackBorders(std::string const & baseDir, std::string const & targetDir) DumpBorderToPolyFile(targetDir, mwmName, polygons); } } + +// static +std::mutex PackedBorders::m_mutex; +// static +std::unordered_map PackedBorders::m_countries; + +// static +CountriesContainer const & PackedBorders::GetOrCreate(std::string const & name) +{ + std::lock_guard lock(m_mutex); + if (m_countries.count(name) != 0) + return m_countries[name]; + + CountriesContainer countries; + CHECK(LoadCountriesList(name, countries), ("Error loading country polygons files.")); + m_countries.emplace(name, countries); + return m_countries[name]; +} } // namespace borders diff --git a/generator/borders.hpp b/generator/borders.hpp index 8be11528b9..970def0a4c 100644 --- a/generator/borders.hpp +++ b/generator/borders.hpp @@ -11,7 +11,10 @@ #include +#include +#include #include +#include #include #define BORDERS_DIR "borders/" @@ -39,24 +42,74 @@ namespace borders using Region = m2::RegionD; using RegionsContainer = m4::Tree; -struct CountryPolygons +class CountryPolygons { - CountryPolygons(std::string const & name = "") : m_name(name), m_index(-1) {} +public: + CountryPolygons() = default; + explicit CountryPolygons( std::string const & name, RegionsContainer const & regions) + : m_name(name) + , m_regions(regions) + { + } + CountryPolygons(CountryPolygons && other) = default; + CountryPolygons(CountryPolygons const & other) = default; + + CountryPolygons & operator=(CountryPolygons && other) = default; + CountryPolygons & operator=(CountryPolygons const & other) = default; + + std::string const & GetName() const { return m_name; } bool IsEmpty() const { return m_regions.IsEmpty(); } void Clear() { m_regions.Clear(); m_name.clear(); - m_index = -1; } - RegionsContainer m_regions; + bool Contains(m2::PointD const & point) const + { + return m_regions.ForAnyInRect(m2::RectD(point, point), [&](auto const & rgn) { + return rgn.Contains(point); + }); + } + +private: std::string m_name; - mutable int m_index; + RegionsContainer m_regions; }; -using CountriesContainer = m4::Tree; +class CountriesContainer +{ +public: + CountriesContainer() = default; + explicit CountriesContainer(m4::Tree const & tree) + : m_regionsTree(tree) + { + tree.ForEach([&](auto const & region) { + m_regions.emplace(region.GetName(), region); + }); + } + + template + void ForEachInRect(m2::RectD const & rect, ToDo && toDo) const + { + m_regionsTree.ForEachInRect(rect, std::forward(toDo)); + } + + bool HasRegionByName(std::string const & name) const + { + return m_regions.count(name) != 0; + } + + CountryPolygons const & GetRegionByName(std::string const & name) const + { + return m_regions.at(name); + } + +private: + m4::Tree m_regionsTree; + std::unordered_map m_regions; +}; /// @return false if borderFile can't be opened bool LoadBorders(std::string const & borderFile, std::vector & outBorders); @@ -86,4 +139,14 @@ std::vector ReadPolygonsOfOneBorder(Source & src) void DumpBorderToPolyFile(std::string const & filePath, storage::CountryId const & mwmName, std::vector const & polygons); void UnpackBorders(std::string const & baseDir, std::string const & targetDir); + +class PackedBorders +{ +public: + static CountriesContainer const & GetOrCreate(std::string const & name); + +private: + static std::mutex m_mutex; + static std::unordered_map m_countries; +}; } // namespace borders