forked from organicmaps/organicmaps-tmp
[generator:regions] Add country specifier
This commit is contained in:
parent
63e08118fa
commit
68ecbc850f
6 changed files with 146 additions and 91 deletions
|
@ -148,6 +148,8 @@ set(SRC
|
|||
region_meta.hpp
|
||||
regions/collector_region_info.cpp
|
||||
regions/collector_region_info.hpp
|
||||
regions/country_specifier.cpp
|
||||
regions/country_specifier.hpp
|
||||
regions/level_region.hpp
|
||||
regions/node.cpp
|
||||
regions/node.hpp
|
||||
|
|
89
generator/regions/country_specifier.cpp
Normal file
89
generator/regions/country_specifier.cpp
Normal file
|
@ -0,0 +1,89 @@
|
|||
#include "generator/regions/country_specifier.hpp"
|
||||
|
||||
namespace generator
|
||||
{
|
||||
namespace regions
|
||||
{
|
||||
PlaceLevel CountrySpecifier::GetLevel(Region const & region) const
|
||||
{
|
||||
auto const placeLevel = GetLevel(region.GetPlaceType());
|
||||
if (placeLevel != PlaceLevel::Unknown)
|
||||
return placeLevel;
|
||||
|
||||
if (region.GetAdminLevel() == AdminLevel::Two)
|
||||
return PlaceLevel::Country;
|
||||
|
||||
return PlaceLevel::Unknown;
|
||||
}
|
||||
|
||||
PlaceLevel CountrySpecifier::GetLevel(PlaceType placeType) const
|
||||
{
|
||||
switch (placeType)
|
||||
{
|
||||
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:
|
||||
return PlaceLevel::Suburb;
|
||||
case PlaceType::Quarter:
|
||||
case PlaceType::Neighbourhood:
|
||||
return PlaceLevel::Sublocality;
|
||||
case PlaceType::IsolatedDwelling:
|
||||
return PlaceLevel::Sublocality;
|
||||
case PlaceType::Unknown:
|
||||
break;
|
||||
}
|
||||
|
||||
return PlaceLevel::Unknown;
|
||||
}
|
||||
|
||||
int CountrySpecifier::RelateByWeight(LevelRegion const & l, LevelRegion const & r) const
|
||||
{
|
||||
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;
|
||||
}
|
||||
} // namespace regions
|
||||
} // namespace generator
|
25
generator/regions/country_specifier.hpp
Normal file
25
generator/regions/country_specifier.hpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "generator/regions/collector_region_info.hpp"
|
||||
#include "generator/regions/level_region.hpp"
|
||||
#include "generator/regions/region.hpp"
|
||||
|
||||
namespace generator
|
||||
{
|
||||
namespace regions
|
||||
{
|
||||
class CountrySpecifier
|
||||
{
|
||||
public:
|
||||
virtual ~CountrySpecifier() = default;
|
||||
|
||||
virtual PlaceLevel GetLevel(Region const & region) const;
|
||||
// Return -1 - |l| is under place of |r|, 0 - undefined relation, 1 - |r| is under place of |l|.
|
||||
// Non-transitive.
|
||||
virtual int RelateByWeight(LevelRegion const & l, LevelRegion const & r) const;
|
||||
|
||||
protected:
|
||||
PlaceLevel GetLevel(PlaceType placeType) const;
|
||||
};
|
||||
} // namespace regions
|
||||
} // namespace generator
|
|
@ -142,8 +142,7 @@ private:
|
|||
auto region = Region(fb, collector.Get(id));
|
||||
|
||||
auto const & name = region.GetName();
|
||||
auto const level = RegionsBuilder::GetLevel(region);
|
||||
if (name.empty() || level == PlaceLevel::Unknown)
|
||||
if (name.empty())
|
||||
return;
|
||||
|
||||
regions.emplace_back(std::move(region));
|
||||
|
|
|
@ -69,13 +69,16 @@ RegionsBuilder::StringsList RegionsBuilder::GetCountryNames() const
|
|||
}
|
||||
|
||||
Node::PtrList RegionsBuilder::MakeSelectedRegionsByCountry(Region const & outer,
|
||||
Regions const & allRegions)
|
||||
Regions const & allRegions, CountrySpecifier const & countrySpecifier)
|
||||
{
|
||||
std::vector<LevelRegion> regionsInCountry{{PlaceLevel::Country, outer}};
|
||||
for (auto const & region : allRegions)
|
||||
{
|
||||
if (outer.ContainsRect(region))
|
||||
regionsInCountry.emplace_back(GetLevel(region), region);
|
||||
{
|
||||
auto const level = countrySpecifier.GetLevel(region);
|
||||
regionsInCountry.emplace_back(level, region);
|
||||
}
|
||||
}
|
||||
|
||||
auto const comp = [](LevelRegion const & l, LevelRegion const & r) {
|
||||
|
@ -94,9 +97,9 @@ Node::PtrList RegionsBuilder::MakeSelectedRegionsByCountry(Region const & outer,
|
|||
}
|
||||
|
||||
Node::Ptr RegionsBuilder::BuildCountryRegionTree(Region const & outer,
|
||||
Regions const & allRegions)
|
||||
Regions const & allRegions, CountrySpecifier const & countrySpecifier)
|
||||
{
|
||||
auto nodes = MakeSelectedRegionsByCountry(outer, allRegions);
|
||||
auto nodes = MakeSelectedRegionsByCountry(outer, allRegions, countrySpecifier);
|
||||
while (nodes.size() > 1)
|
||||
{
|
||||
auto itFirstNode = std::rbegin(nodes);
|
||||
|
@ -109,7 +112,7 @@ Node::Ptr RegionsBuilder::BuildCountryRegionTree(Region const & outer,
|
|||
if (!currRegion.ContainsRect(firstRegion) && !currRegion.Contains(firstRegion.GetCenter()))
|
||||
continue;
|
||||
|
||||
auto const c = Compare(currRegion, firstRegion);
|
||||
auto const c = Compare(currRegion, firstRegion, countrySpecifier);
|
||||
if (c == 1)
|
||||
{
|
||||
(*itFirstNode)->SetParent(*itCurr);
|
||||
|
@ -125,7 +128,8 @@ Node::Ptr RegionsBuilder::BuildCountryRegionTree(Region const & outer,
|
|||
}
|
||||
|
||||
// static
|
||||
int RegionsBuilder::Compare(LevelRegion const & l, LevelRegion const & r)
|
||||
int RegionsBuilder::Compare(LevelRegion const & l, LevelRegion const & r,
|
||||
CountrySpecifier const & countrySpecifier)
|
||||
{
|
||||
if (IsAreaLess(r, l) && l.Contains(r))
|
||||
return 1;
|
||||
|
@ -150,7 +154,7 @@ int RegionsBuilder::Compare(LevelRegion const & l, LevelRegion const & r)
|
|||
return -1;
|
||||
}
|
||||
|
||||
return RelateByWeight(l, r);
|
||||
return countrySpecifier.RelateByWeight(l, r);
|
||||
}
|
||||
|
||||
// static
|
||||
|
@ -160,60 +164,24 @@ bool RegionsBuilder::IsAreaLess(Region const & l, Region const & r)
|
|||
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())
|
||||
{
|
||||
auto countrySpecifier = GetCountrySpecifier(countryName);
|
||||
|
||||
Regions outers;
|
||||
auto const & countries = GetCountriesOuters();
|
||||
auto const pred = [&](Region const & country) { return countryName == country.GetName(); };
|
||||
std::copy_if(std::begin(countries), std::end(countries), std::back_inserter(outers), pred);
|
||||
auto countryTrees = BuildCountryRegionTrees(outers);
|
||||
auto countryTrees = BuildCountryRegionTrees(outers, *countrySpecifier);
|
||||
|
||||
fn(countryName, countryTrees);
|
||||
}
|
||||
}
|
||||
|
||||
Node::PtrList RegionsBuilder::BuildCountryRegionTrees(Regions const & outers)
|
||||
Node::PtrList RegionsBuilder::BuildCountryRegionTrees(Regions const & outers,
|
||||
CountrySpecifier const & countrySpecifier)
|
||||
{
|
||||
std::vector<std::future<Node::Ptr>> buildingTasks;
|
||||
{
|
||||
|
@ -221,7 +189,8 @@ Node::PtrList RegionsBuilder::BuildCountryRegionTrees(Regions const & outers)
|
|||
for (auto const & outer : outers)
|
||||
{
|
||||
auto result = threadPool.Submit(
|
||||
&RegionsBuilder::BuildCountryRegionTree, std::cref(outer), std::cref(m_regionsInAreaOrder));
|
||||
&RegionsBuilder::BuildCountryRegionTree,
|
||||
std::cref(outer), std::cref(m_regionsInAreaOrder), std::cref(countrySpecifier));
|
||||
buildingTasks.emplace_back(std::move(result));
|
||||
}
|
||||
}
|
||||
|
@ -232,40 +201,9 @@ Node::PtrList RegionsBuilder::BuildCountryRegionTrees(Regions const & outers)
|
|||
return trees;
|
||||
}
|
||||
|
||||
// static
|
||||
PlaceLevel RegionsBuilder::GetLevel(Region const & region)
|
||||
std::unique_ptr<CountrySpecifier> RegionsBuilder::GetCountrySpecifier(std::string const & countryName)
|
||||
{
|
||||
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:
|
||||
return PlaceLevel::Suburb;
|
||||
case PlaceType::Quarter:
|
||||
case PlaceType::Neighbourhood:
|
||||
return PlaceLevel::Sublocality;
|
||||
case PlaceType::IsolatedDwelling:
|
||||
return PlaceLevel::Sublocality;
|
||||
case PlaceType::Unknown:
|
||||
break;
|
||||
}
|
||||
|
||||
if (region.GetAdminLevel() == AdminLevel::Two)
|
||||
return PlaceLevel::Country;
|
||||
|
||||
return PlaceLevel::Unknown;
|
||||
return std::make_unique<CountrySpecifier>();
|
||||
}
|
||||
} // namespace regions
|
||||
} // namespace generator
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "generator/regions/country_specifier.hpp"
|
||||
#include "generator/regions/node.hpp"
|
||||
#include "generator/regions/region.hpp"
|
||||
#include "generator/regions/to_string_policy.hpp"
|
||||
|
@ -29,21 +30,22 @@ public:
|
|||
StringsList GetCountryNames() const;
|
||||
void ForEachCountry(CountryFn fn);
|
||||
|
||||
static PlaceLevel GetLevel(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);
|
||||
Node::PtrList BuildCountryRegionTrees(Regions const & outers,
|
||||
CountrySpecifier const & countrySpecifier);
|
||||
static Node::Ptr BuildCountryRegionTree(Region const & outer, Regions const & allRegions,
|
||||
CountrySpecifier const & countrySpecifier);
|
||||
static Node::PtrList MakeSelectedRegionsByCountry(Region const & outer,
|
||||
Regions const & allRegions);
|
||||
Regions const & allRegions, CountrySpecifier const & countrySpecifier);
|
||||
// Return: 0 - no relation, 1 - |l| contains |r|, -1 - |r| contains |l|.
|
||||
static int Compare(LevelRegion const & l, LevelRegion const & r);
|
||||
static int Compare(LevelRegion const & l, LevelRegion const & r,
|
||||
CountrySpecifier const & countrySpecifier);
|
||||
static bool IsAreaLess(Region const & l, Region const & r);
|
||||
static int RelateByWeight(LevelRegion const & l, LevelRegion const & r);
|
||||
std::unique_ptr<CountrySpecifier> GetCountrySpecifier(std::string const & countryName);
|
||||
|
||||
Regions m_countriesOuters;
|
||||
Regions m_regionsInAreaOrder;
|
||||
|
|
Loading…
Add table
Reference in a new issue