From 63e08118faf1b8cb04dd67f54bb48e3edc7f4cbe Mon Sep 17 00:00:00 2001 From: Anatoly Serdtcev Date: Fri, 14 Jun 2019 12:50:11 +0300 Subject: [PATCH] [generator:regions] Add administrative place --- generator/generator_tests/regions_tests.cpp | 12 +- generator/regions/collector_region_info.cpp | 7 + generator/regions/collector_region_info.hpp | 22 +-- generator/regions/region.cpp | 2 + generator/regions/regions_builder.cpp | 143 +++++++++++++------- generator/regions/regions_builder.hpp | 7 +- 6 files changed, 129 insertions(+), 64 deletions(-) diff --git a/generator/generator_tests/regions_tests.cpp b/generator/generator_tests/regions_tests.cpp index 647832e794..2061e95f9f 100644 --- a/generator/generator_tests/regions_tests.cpp +++ b/generator/generator_tests/regions_tests.cpp @@ -50,12 +50,12 @@ std::string MakeCollectorData() CollectorRegionInfo collector(filename); collector.CollectFeature(kEmptyFeature, CreateOsmRelation(1 /* id */, "2" /* adminLevel */)); collector.CollectFeature(kEmptyFeature, CreateOsmRelation(2 /* id */, "2" /* adminLevel */)); - collector.CollectFeature(kEmptyFeature, CreateOsmRelation(3 /* id */, "4" /* adminLevel */)); - collector.CollectFeature(kEmptyFeature, CreateOsmRelation(4 /* id */, "4" /* adminLevel */)); - collector.CollectFeature(kEmptyFeature, CreateOsmRelation(5 /* id */, "4" /* adminLevel */)); - collector.CollectFeature(kEmptyFeature, CreateOsmRelation(6 /* id */, "6" /* adminLevel */)); - collector.CollectFeature(kEmptyFeature, CreateOsmRelation(7 /* id */, "6" /* adminLevel */)); - collector.CollectFeature(kEmptyFeature, CreateOsmRelation(8 /* id */, "4" /* adminLevel */)); + collector.CollectFeature(kEmptyFeature, CreateOsmRelation(3 /* id */, "4" /* adminLevel */, "state")); + collector.CollectFeature(kEmptyFeature, CreateOsmRelation(4 /* id */, "4" /* adminLevel */, "state")); + collector.CollectFeature(kEmptyFeature, CreateOsmRelation(5 /* id */, "4" /* adminLevel */, "state")); + collector.CollectFeature(kEmptyFeature, CreateOsmRelation(6 /* id */, "6" /* adminLevel */, "district")); + collector.CollectFeature(kEmptyFeature, CreateOsmRelation(7 /* id */, "6" /* adminLevel */, "district")); + collector.CollectFeature(kEmptyFeature, CreateOsmRelation(8 /* id */, "4" /* adminLevel */, "state")); collector.Save(); return filename; } diff --git a/generator/regions/collector_region_info.cpp b/generator/regions/collector_region_info.cpp index 4a6c470c3c..94361bd5f2 100644 --- a/generator/regions/collector_region_info.cpp +++ b/generator/regions/collector_region_info.cpp @@ -23,10 +23,17 @@ uint8_t const CollectorRegionInfo::kVersion = 0; PlaceType EncodePlaceType(std::string const & place) { static std::map const m = { + {"country", PlaceType::Country}, + {"state", PlaceType::State}, + {"province", PlaceType::Province}, + {"district", PlaceType::District}, + {"county", PlaceType::County}, + {"municipality", PlaceType::Municipality}, {"city", PlaceType::City}, {"town", PlaceType::Town}, {"village", PlaceType::Village}, {"suburb", PlaceType::Suburb}, + {"quarter", PlaceType::Quarter}, {"neighbourhood", PlaceType::Neighbourhood}, {"hamlet", PlaceType::Hamlet}, {"isolated_dwelling", PlaceType::IsolatedDwelling} diff --git a/generator/regions/collector_region_info.hpp b/generator/regions/collector_region_info.hpp index 42edd19d4f..001c52cfd5 100644 --- a/generator/regions/collector_region_info.hpp +++ b/generator/regions/collector_region_info.hpp @@ -26,7 +26,6 @@ namespace regions enum class AdminLevel : uint8_t { Unknown = 0, - One = 1, Two = 2, Three = 3, Four = 4, @@ -44,13 +43,20 @@ enum class AdminLevel : uint8_t enum class PlaceType: uint8_t { Unknown = 0, - City = 9, - Town = 10, - Village = 11, - Hamlet = 12, - Suburb = 13, - Neighbourhood = 14, - IsolatedDwelling = 15, + Country = 1, + State = 2, + Province = 3, + District = 4, + County = 5, + Municipality = 6, + City = 7, + Town = 8, + Village = 9, + Hamlet = 10, + Suburb = 11, + Quarter = 12, + Neighbourhood = 13, + IsolatedDwelling = 14, }; PlaceType EncodePlaceType(std::string const & place); diff --git a/generator/regions/region.cpp b/generator/regions/region.cpp index 4d6267fb89..85406b59cf 100644 --- a/generator/regions/region.cpp +++ b/generator/regions/region.cpp @@ -72,10 +72,12 @@ double Region::GetRadiusByPlaceType(PlaceType place) return 0.0067; case PlaceType::Suburb: return 0.016; + case PlaceType::Quarter: case PlaceType::Neighbourhood: case PlaceType::IsolatedDwelling: return 0.0035; case PlaceType::Unknown: + default: UNREACHABLE(); } UNREACHABLE(); diff --git a/generator/regions/regions_builder.cpp b/generator/regions/regions_builder.cpp index 3db728cb95..6278c6a567 100644 --- a/generator/regions/regions_builder.cpp +++ b/generator/regions/regions_builder.cpp @@ -105,10 +105,12 @@ Node::Ptr RegionsBuilder::BuildCountryRegionTree(Region const & outer, for (; itCurr != std::rend(nodes); ++itCurr) { auto const & currRegion = (*itCurr)->GetData(); - if (currRegion.Contains(firstRegion) || - (GetWeight(firstRegion) < GetWeight(currRegion) && - currRegion.Contains(firstRegion.GetCenter()) && - currRegion.CalculateOverlapPercentage(firstRegion) > 50.0)) + + if (!currRegion.ContainsRect(firstRegion) && !currRegion.Contains(firstRegion.GetCenter())) + continue; + + auto const c = Compare(currRegion, firstRegion); + if (c == 1) { (*itFirstNode)->SetParent(*itCurr); (*itCurr)->AddChild(*itFirstNode); @@ -122,6 +124,81 @@ Node::Ptr RegionsBuilder::BuildCountryRegionTree(Region const & outer, return nodes.front(); } +// static +int RegionsBuilder::Compare(LevelRegion const & l, LevelRegion const & r) +{ + if (IsAreaLess(r, l) && l.Contains(r)) + return 1; + if (IsAreaLess(l, r) && r.Contains(l)) + return -1; + + if (l.CalculateOverlapPercentage(r) < 50.0) + return 0; + + auto const lArea = l.GetArea(); + auto const rArea = r.GetArea(); + if (0.5 * lArea >= rArea) + { + LOG(LDEBUG, ("Region", l.GetId(), GetRegionNotation(l), "contains partly", + r.GetId(), GetRegionNotation(r))); + return 1; + } + if (0.5 * rArea >= lArea) + { + LOG(LDEBUG, ("Region", r.GetId(), GetRegionNotation(r), "contains partly", + l.GetId(), GetRegionNotation(l))); + return -1; + } + + return RelateByWeight(l, r); +} + +// static +bool RegionsBuilder::IsAreaLess(Region const & l, Region const & r) +{ + constexpr auto lAreaRation = 1. + kAreaRelativeErrorPercent / 100.; + return lAreaRation * l.GetArea() < r.GetArea(); +} + +// static +int RegionsBuilder::RelateByWeight(LevelRegion const & l, LevelRegion const & r) +{ + if (l.GetLevel() != PlaceLevel::Unknown && r.GetLevel() != PlaceLevel::Unknown) + { + if (l.GetLevel() > r.GetLevel()) + return -1; + if (l.GetLevel() < r.GetLevel()) + return 1; + } + + auto const lPlaceType = l.GetPlaceType(); + auto const rPlaceType = r.GetPlaceType(); + if (lPlaceType != PlaceType::Unknown && rPlaceType != PlaceType::Unknown) + { + if (lPlaceType > rPlaceType) + return -1; + if (lPlaceType < rPlaceType) + return 1; + // Check by admin level (administrative city (district + city) > city). + } + + auto const lAdminLevel = l.GetAdminLevel(); + auto const rAdminLevel = r.GetAdminLevel(); + if (lAdminLevel != AdminLevel::Unknown && rAdminLevel != AdminLevel::Unknown) + { + if (lAdminLevel > rAdminLevel) + return -1; + if (lAdminLevel < rAdminLevel) + return 1; + } + if (lAdminLevel != AdminLevel::Unknown) + return 1; + if (rAdminLevel != AdminLevel::Unknown) + return -1; + + return 0; +} + void RegionsBuilder::ForEachCountry(CountryFn fn) { for (auto const & countryName : GetCountryNames()) @@ -160,67 +237,35 @@ PlaceLevel RegionsBuilder::GetLevel(Region const & region) { switch (region.GetPlaceType()) { + case PlaceType::Country: + return PlaceLevel::Country; + case PlaceType::State: + case PlaceType::Province: + return PlaceLevel::Region; + case PlaceType::District: + case PlaceType::County: + case PlaceType::Municipality: + return PlaceLevel::Subregion; case PlaceType::City: case PlaceType::Town: case PlaceType::Village: case PlaceType::Hamlet: return PlaceLevel::Locality; case PlaceType::Suburb: - case PlaceType::Neighbourhood: return PlaceLevel::Suburb; + case PlaceType::Quarter: + case PlaceType::Neighbourhood: + return PlaceLevel::Sublocality; case PlaceType::IsolatedDwelling: return PlaceLevel::Sublocality; case PlaceType::Unknown: break; } - switch (region.GetAdminLevel()) - { - case AdminLevel::Two: + if (region.GetAdminLevel() == AdminLevel::Two) return PlaceLevel::Country; - case AdminLevel::Four: - return PlaceLevel::Region; - case AdminLevel::Six: - return PlaceLevel::Subregion; - default: - break; - } return PlaceLevel::Unknown; } - -// static -size_t RegionsBuilder::GetWeight(Region const & region) -{ - switch (region.GetPlaceType()) - { - case PlaceType::City: - case PlaceType::Town: - case PlaceType::Village: - case PlaceType::Hamlet: - return 3; - case PlaceType::Suburb: - case PlaceType::Neighbourhood: - return 2; - case PlaceType::IsolatedDwelling: - return 1; - case PlaceType::Unknown: - break; - } - - switch (region.GetAdminLevel()) - { - case AdminLevel::Two: - return 6; - case AdminLevel::Four: - return 5; - case AdminLevel::Six: - return 4; - default: - break; - } - - return 0; -} } // namespace regions } // namespace generator diff --git a/generator/regions/regions_builder.hpp b/generator/regions/regions_builder.hpp index 3a77bfceab..d945bfeb39 100644 --- a/generator/regions/regions_builder.hpp +++ b/generator/regions/regions_builder.hpp @@ -30,15 +30,20 @@ public: void ForEachCountry(CountryFn fn); static PlaceLevel GetLevel(Region const & region); - static size_t GetWeight(Region const & region); private: + static constexpr double kAreaRelativeErrorPercent = 0.1; + Regions FormRegionsInAreaOrder(Regions && regions); Regions ExtractCountriesOuters(Regions & regions); Node::PtrList BuildCountryRegionTrees(Regions const & outers); static Node::Ptr BuildCountryRegionTree(Region const & outer, Regions const & allRegions); static Node::PtrList MakeSelectedRegionsByCountry(Region const & outer, Regions const & allRegions); + // Return: 0 - no relation, 1 - |l| contains |r|, -1 - |r| contains |l|. + static int Compare(LevelRegion const & l, LevelRegion const & r); + static bool IsAreaLess(Region const & l, Region const & r); + static int RelateByWeight(LevelRegion const & l, LevelRegion const & r); Regions m_countriesOuters; Regions m_regionsInAreaOrder;