[generator:regions] Add country specifier

This commit is contained in:
Anatoly Serdtcev 2019-06-14 12:50:11 +03:00 committed by Maksim Andrianov
parent 63e08118fa
commit 68ecbc850f
6 changed files with 146 additions and 91 deletions

View file

@ -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

View 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

View 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

View file

@ -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));

View file

@ -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

View file

@ -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;