[generator:regions] Add administrative place

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

View file

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

View file

@ -23,10 +23,17 @@ uint8_t const CollectorRegionInfo::kVersion = 0;
PlaceType EncodePlaceType(std::string const & place)
{
static std::map<std::string, PlaceType> 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}

View file

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

View file

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

View file

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

View file

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