From 74d68e730b4ebf81681b6f03543ea993ec253ace Mon Sep 17 00:00:00 2001 From: Anatoly Serdtcev Date: Thu, 20 Jun 2019 18:39:59 +0300 Subject: [PATCH] [generator:regions] Add place label nodes --- generator/generator_tests/regions_tests.cpp | 39 +++++++-------- generator/regions/collector_region_info.cpp | 31 +++++++----- generator/regions/collector_region_info.hpp | 1 + generator/regions/region.cpp | 54 +++++++++++++++++++++ generator/regions/region.hpp | 18 +++++-- generator/regions/region_base.cpp | 5 ++ generator/regions/region_base.hpp | 2 + generator/regions/region_info.cpp | 10 ++++ generator/regions/region_info.hpp | 1 + generator/regions/regions.cpp | 18 ++----- generator/regions/regions_builder.cpp | 23 ++++++++- generator/regions/regions_builder.hpp | 4 +- 12 files changed, 154 insertions(+), 52 deletions(-) diff --git a/generator/generator_tests/regions_tests.cpp b/generator/generator_tests/regions_tests.cpp index b44ff35b23..72dbb1b377 100644 --- a/generator/generator_tests/regions_tests.cpp +++ b/generator/generator_tests/regions_tests.cpp @@ -144,25 +144,20 @@ void BuildTestData(std::vector const & testData, } } -class ToLabelingStringPolicy : public ToStringPolicyInterface +std::string ToLabelingString(vector const & path) { -public: - // ToStringPolicyInterface overrides: - std::string ToString(vector const & path) const override - { - CHECK(!path.empty(), ()); - std::stringstream stream; - auto i = path.begin(); - auto const & countryName = (*i)->GetData().GetName(); - CHECK(!countryName.empty(), ()); - stream << (*i)->GetData().GetName(); - ++i; - for (; i != path.end(); ++i) - stream << ", " << GetLabel((*i)->GetData().GetLevel()) << ": " << (*i)->GetData().GetName(); + CHECK(!path.empty(), ()); + std::stringstream stream; + auto i = path.begin(); + auto const & countryName = (*i)->GetData().GetName(); + CHECK(!countryName.empty(), ()); + stream << (*i)->GetData().GetName(); + ++i; + for (; i != path.end(); ++i) + stream << ", " << GetLabel((*i)->GetData().GetLevel()) << ": " << (*i)->GetData().GetName(); - return stream.str(); - } -}; + return stream.str(); +} std::vector GenerateTestRegions(std::vector const & testData) { @@ -176,13 +171,13 @@ std::vector GenerateTestRegions(std::vector const & RegionInfo collector(filename); BuildTestData(testData, regions, placePointsMap, collector); - RegionsBuilder builder(std::move(regions)); + RegionsBuilder builder(std::move(regions), {}); std::vector kvRegions; builder.ForEachCountry([&](std::string const & name, Node::PtrList const & outers) { for (auto const & tree : outers) { ForEachLevelPath(tree, [&] (std::vector const & path) { - kvRegions.push_back(ToLabelingStringPolicy{}.ToString(path)); + kvRegions.push_back(ToLabelingString(path)); }); } }); @@ -344,7 +339,7 @@ UNIT_TEST(RegionsBuilderTest_GetCountryNames) { auto const filename = MakeCollectorData(); RegionInfo collector(filename); - RegionsBuilder builder(MakeTestDataSet1(collector)); + RegionsBuilder builder(MakeTestDataSet1(collector), {} /* placePointsMap */); auto const & countryNames = builder.GetCountryNames(); TEST_EQUAL(countryNames.size(), 2, ()); TEST(std::count(std::begin(countryNames), std::end(countryNames), "Country_1"), ()); @@ -355,7 +350,7 @@ UNIT_TEST(RegionsBuilderTest_GetCountries) { auto const filename = MakeCollectorData(); RegionInfo collector(filename); - RegionsBuilder builder(MakeTestDataSet1(collector)); + RegionsBuilder builder(MakeTestDataSet1(collector), {} /* placePointsMap */); auto const & countries = builder.GetCountriesOuters(); TEST_EQUAL(countries.size(), 3, ()); TEST_EQUAL(std::count_if(std::begin(countries), std::end(countries), @@ -371,7 +366,7 @@ UNIT_TEST(RegionsBuilderTest_GetCountryTrees) auto const filename = MakeCollectorData(); RegionInfo collector(filename); std::vector bankOfNames; - RegionsBuilder builder(MakeTestDataSet1(collector)); + RegionsBuilder builder(MakeTestDataSet1(collector), {} /* placePointsMap */); builder.ForEachCountry([&](std::string const & name, Node::PtrList const & outers) { for (auto const & tree : outers) { diff --git a/generator/regions/collector_region_info.cpp b/generator/regions/collector_region_info.cpp index 8cc35311f6..efe3a26a3f 100644 --- a/generator/regions/collector_region_info.cpp +++ b/generator/regions/collector_region_info.cpp @@ -97,22 +97,29 @@ void CollectorRegionInfo::FillRegionData(base::GeoObjectId const & osmId, OsmEle { rd.m_osmId = osmId; rd.m_place = EncodePlaceType(el.GetTag("place")); - auto const al = el.GetTag("admin_level"); - if (al.empty()) - return; - try + auto const al = el.GetTag("admin_level"); + if (!al.empty()) { - auto const adminLevel = std::stoi(al); - // Administrative level is in the range [1 ... 12]. - // https://wiki.openstreetmap.org/wiki/Tag:boundary=administrative - rd.m_adminLevel = (adminLevel >= 1 && adminLevel <= 12) ? - static_cast(adminLevel) : AdminLevel::Unknown; + try + { + auto const adminLevel = std::stoi(al); + // Administrative level is in the range [1 ... 12]. + // https://wiki.openstreetmap.org/wiki/Tag:boundary=administrative + rd.m_adminLevel = (adminLevel >= 1 && adminLevel <= 12) ? + static_cast(adminLevel) : AdminLevel::Unknown; + } + catch (std::exception const & e) // std::invalid_argument, std::out_of_range + { + LOG(LWARNING, (e.what())); + rd.m_adminLevel = AdminLevel::Unknown; + } } - catch (std::exception const & e) // std::invalid_argument, std::out_of_range + + for (auto const & member : el.Members()) { - LOG(::base::LWARNING, (e.what())); - rd.m_adminLevel = AdminLevel::Unknown; + if (member.m_role == "label" && member.m_type == OsmElement::EntityType::Node) + rd.m_labelOsmId = base::MakeOsmNode(member.m_ref); } } diff --git a/generator/regions/collector_region_info.hpp b/generator/regions/collector_region_info.hpp index 0133b16900..380fd43f7c 100644 --- a/generator/regions/collector_region_info.hpp +++ b/generator/regions/collector_region_info.hpp @@ -103,6 +103,7 @@ struct RegionData base::GeoObjectId m_osmId; AdminLevel m_adminLevel = AdminLevel::Unknown; PlaceType m_place = PlaceType::Unknown; + base::GeoObjectId m_labelOsmId; }; using MapRegionData = std::unordered_map; diff --git a/generator/regions/region.cpp b/generator/regions/region.cpp index 85406b59cf..64ffa84340 100644 --- a/generator/regions/region.cpp +++ b/generator/regions/region.cpp @@ -50,12 +50,63 @@ Region::Region(PlacePoint const & place) , RegionWithData(place.GetRegionData()) , m_polygon(std::make_shared()) { + CHECK_NOT_EQUAL(place.GetPlaceType(), PlaceType::Unknown, ()); + auto const radius = GetRadiusByPlaceType(place.GetPlaceType()); *m_polygon = MakePolygonWithRadius(place.GetPosition(), radius); boost::geometry::envelope(*m_polygon, m_rect); m_area = boost::geometry::area(*m_polygon); } +std::string Region::GetEnglishOrTransliteratedName() const +{ + if (m_placeLabel) + return m_placeLabel->GetEnglishOrTransliteratedName(); + + return RegionWithName::GetEnglishOrTransliteratedName(); +} + +std::string Region::GetName(int8_t lang) const +{ + if (m_placeLabel) + return m_placeLabel->GetName(); + + return RegionWithName::GetName(); +} + +base::GeoObjectId Region::GetId() const +{ + if (m_placeLabel) + return m_placeLabel->GetId(); + + return RegionWithData::GetId(); +} + +PlaceType Region::GetPlaceType() const +{ + if (m_placeLabel) + return m_placeLabel->GetPlaceType(); + + return RegionWithData::GetPlaceType(); +} + +boost::optional Region::GetIsoCode() const +{ + if (m_placeLabel) + { + if (auto && isoCode = m_placeLabel->GetIsoCode()) + return isoCode; + } + + return RegionWithData::GetIsoCode(); +} + +void Region::SetLabel(PlacePoint const & place) +{ + CHECK(!m_placeLabel, ()); + m_placeLabel = place; +} + // static double Region::GetRadiusByPlaceType(PlaceType place) { @@ -127,6 +178,9 @@ bool Region::ContainsRect(Region const & smaller) const BoostPoint Region::GetCenter() const { + if (m_placeLabel) + return m_placeLabel->GetPosition(); + BoostPoint p; boost::geometry::centroid(m_rect, p); return p; diff --git a/generator/regions/region.hpp b/generator/regions/region.hpp index 507ccc7341..1b0f4c95a2 100644 --- a/generator/regions/region.hpp +++ b/generator/regions/region.hpp @@ -2,6 +2,7 @@ #include "generator/feature_builder.hpp" #include "generator/regions/region_base.hpp" +#include "generator/regions/place_point.hpp" #include @@ -16,17 +17,27 @@ class RegionDataProxy; namespace regions { -class PlacePoint; - // This is a helper class that is needed to represent the region. // With this view, further processing is simplified. -class Region : public RegionWithName, public RegionWithData +class Region : protected RegionWithName, protected RegionWithData { public: explicit Region(feature::FeatureBuilder const & fb, RegionDataProxy const & rd); // Build a region and its boundary based on the heuristic. explicit Region(PlacePoint const & place); + // See RegionWithName::GetEnglishOrTransliteratedName(). + std::string GetEnglishOrTransliteratedName() const; + std::string GetName(int8_t lang = StringUtf8Multilang::kDefaultCode) const; + + base::GeoObjectId GetId() const; + using RegionWithData::GetAdminLevel; + PlaceType GetPlaceType() const; + boost::optional GetIsoCode() const; + + using RegionWithData::GetLabelOsmId; + void SetLabel(PlacePoint const & place); + bool Contains(Region const & smaller) const; bool ContainsRect(Region const & smaller) const; bool Contains(PlacePoint const & place) const; @@ -44,6 +55,7 @@ public: private: void FillPolygon(feature::FeatureBuilder const & fb); + boost::optional m_placeLabel; std::shared_ptr m_polygon; BoostRect m_rect; double m_area; diff --git a/generator/regions/region_base.cpp b/generator/regions/region_base.cpp index 90e1fafb61..981f32d189 100644 --- a/generator/regions/region_base.cpp +++ b/generator/regions/region_base.cpp @@ -63,5 +63,10 @@ boost::optional RegionWithData::GetIsoCode() const { return m_regionData.GetIsoCodeAlpha2(); } + +boost::optional RegionWithData::GetLabelOsmId() const +{ + return m_regionData.GetLabelOsmId(); +} } // namespace regions } // namespace generator diff --git a/generator/regions/region_base.hpp b/generator/regions/region_base.hpp index bc7f1c8f6f..2dc0b4dd2d 100644 --- a/generator/regions/region_base.hpp +++ b/generator/regions/region_base.hpp @@ -50,6 +50,8 @@ public: base::GeoObjectId GetId() const; boost::optional GetIsoCode() const; + boost::optional GetLabelOsmId() const; + AdminLevel GetAdminLevel() const { return m_regionData.GetAdminLevel(); } PlaceType GetPlaceType() const { return m_regionData.GetPlaceType(); } diff --git a/generator/regions/region_info.cpp b/generator/regions/region_info.cpp index 7db844230f..4a96969e9d 100644 --- a/generator/regions/region_info.cpp +++ b/generator/regions/region_info.cpp @@ -114,6 +114,16 @@ PlaceType BaseRegionDataProxy::GetPlaceType() const return regionData->second.m_place; } +template +boost::optional BaseRegionDataProxy::GetLabelOsmId() const +{ + auto const & labelId = GetMapRegionData().at(m_osmId).m_labelOsmId; + if (!labelId.GetEncodedId()) + return {}; + + return labelId; +} + template boost::optional BaseRegionDataProxy::GetIsoCodeAlpha2() const { diff --git a/generator/regions/region_info.hpp b/generator/regions/region_info.hpp index 71525b2af8..acdf6ecdfc 100644 --- a/generator/regions/region_info.hpp +++ b/generator/regions/region_info.hpp @@ -69,6 +69,7 @@ public: base::GeoObjectId const & GetOsmId() const; AdminLevel GetAdminLevel() const; PlaceType GetPlaceType() const; + boost::optional GetLabelOsmId() const; boost::optional GetIsoCodeAlpha2() const; boost::optional GetIsoCodeAlpha3() const; diff --git a/generator/regions/regions.cpp b/generator/regions/regions.cpp index 56412c7764..7b5ab3c0e3 100644 --- a/generator/regions/regions.cpp +++ b/generator/regions/regions.cpp @@ -62,10 +62,12 @@ public: auto timer = base::Timer{}; Transliteration::Instance().Init(GetPlatform().ResourcesDir()); - RegionsBuilder::Regions regions = ReadAndFixData(); - RegionsBuilder builder{std::move(regions), threadsCount}; - GenerateRegions(builder); + RegionsBuilder::Regions regions; + PlacePointsMap placePointsMap; + std::tie(regions, placePointsMap) = ReadDatasetFromTmpMwm(m_pathInRegionsTmpMwm, m_regionsInfoCollector); + RegionsBuilder builder{std::move(regions), std::move(placePointsMap), threadsCount}; + GenerateRegions(builder); LOG(LINFO, ("Finish generating regions.", timer.ElapsedSeconds(), "seconds.")); } @@ -222,16 +224,6 @@ private: return std::make_tuple(std::move(regions), std::move(placePointsMap)); } - RegionsBuilder::Regions ReadAndFixData() - { - RegionsBuilder::Regions regions; - PlacePointsMap placePointsMap; - std::tie(regions, placePointsMap) = - ReadDatasetFromTmpMwm(m_pathInRegionsTmpMwm, m_regionsInfoCollector); - FixRegionsWithPlacePointApproximation(placePointsMap, regions); - return regions; - } - void RepackTmpMwm() { feature::FeaturesCollector featuresCollector{m_pathOutRepackedRegionsTmpMwm}; diff --git a/generator/regions/regions_builder.cpp b/generator/regions/regions_builder.cpp index b9f375d23f..26325bd47b 100644 --- a/generator/regions/regions_builder.cpp +++ b/generator/regions/regions_builder.cpp @@ -1,5 +1,6 @@ #include "generator/regions/regions_builder.hpp" +#include "generator/regions/regions_fixer.hpp" #include "generator/regions/specs/rus.hpp" #include "base/assert.hpp" @@ -20,15 +21,35 @@ namespace generator { namespace regions { -RegionsBuilder::RegionsBuilder(Regions && regions, size_t threadsCount) +RegionsBuilder::RegionsBuilder(Regions && regions, PlacePointsMap && placePointsMap, + size_t threadsCount) : m_threadsCount(threadsCount) { ASSERT(m_threadsCount != 0, ()); + MoveLabelPlacePoints(placePointsMap, regions); + FixRegionsWithPlacePointApproximation(placePointsMap, regions); + m_regionsInAreaOrder = FormRegionsInAreaOrder(std::move(regions)); m_countriesOuters = ExtractCountriesOuters(m_regionsInAreaOrder); } +void RegionsBuilder::MoveLabelPlacePoints(PlacePointsMap & placePointsMap, Regions & regions) +{ + for (auto & region : regions) + { + if (auto labelOsmId = region.GetLabelOsmId()) + { + auto label = placePointsMap.find(*labelOsmId); + if (label != placePointsMap.end()) + { + region.SetLabel(label->second); + placePointsMap.erase(label); + } + } + } +} + RegionsBuilder::Regions RegionsBuilder::FormRegionsInAreaOrder(Regions && regions) { auto const cmp = [](Region const & l, Region const & r) { return l.GetArea() > r.GetArea(); }; diff --git a/generator/regions/regions_builder.hpp b/generator/regions/regions_builder.hpp index 8fd146660e..fcd536204a 100644 --- a/generator/regions/regions_builder.hpp +++ b/generator/regions/regions_builder.hpp @@ -23,7 +23,8 @@ public: using StringsList = std::vector; using CountryFn = std::function; - explicit RegionsBuilder(Regions && regions, size_t threadsCount = 1); + explicit RegionsBuilder(Regions && regions, PlacePointsMap && placePointsMap, + size_t threadsCount = 1); Regions const & GetCountriesOuters() const; StringsList GetCountryNames() const; @@ -32,6 +33,7 @@ public: private: static constexpr double kAreaRelativeErrorPercent = 0.1; + void MoveLabelPlacePoints(PlacePointsMap & placePointsMap, Regions & regions); Regions FormRegionsInAreaOrder(Regions && regions); Regions ExtractCountriesOuters(Regions & regions); Node::PtrList BuildCountryRegionTrees(Regions const & outers,