diff --git a/generator/CMakeLists.txt b/generator/CMakeLists.txt index 4f036a0db7..714b65e094 100644 --- a/generator/CMakeLists.txt +++ b/generator/CMakeLists.txt @@ -150,9 +150,13 @@ set( regions/country_specifier.cpp regions/country_specifier.hpp regions/level_region.hpp + regions/locality_point_integrator.cpp + regions/locality_point_integrator.hpp regions/node.cpp regions/node.hpp regions/place_point.hpp + regions/place_points_integrator.cpp + regions/place_points_integrator.hpp regions/region.cpp regions/region.hpp regions/region_base.cpp @@ -165,8 +169,6 @@ set( regions/regions.hpp regions/regions_builder.cpp regions/regions_builder.hpp - regions/regions_fixer.cpp - regions/regions_fixer.hpp regions/specs/rus.cpp regions/specs/rus.hpp relation_tags.cpp diff --git a/generator/generator_tests/regions_tests.cpp b/generator/generator_tests/regions_tests.cpp index 62ee8f11e5..d04e1a6f20 100644 --- a/generator/generator_tests/regions_tests.cpp +++ b/generator/generator_tests/regions_tests.cpp @@ -57,24 +57,23 @@ struct TagValue { std::string m_key; std::string m_value; +}; - TagValue(std::string key, std::string value = {}) - : m_key{std::move(key)}, m_value{std::move(value)} - { - } - +struct Tag +{ TagValue operator=(std::string const & value) const { - CHECK(m_value.empty(), ()); - return {m_key, value}; + return {m_name, value}; } + + std::string m_name; }; struct OsmElementData { uint64_t m_id; std::vector m_tags; - std::vector m_polygon; + std::vector m_polygon; std::vector m_members; }; @@ -114,14 +113,18 @@ void BuildTestData(std::vector const & testData, RegionsBuilder: CHECK(elementData.m_polygon.size() == 1 || elementData.m_polygon.size() == 2, ()); if (elementData.m_polygon.size() == 1) { - fb.SetCenter(elementData.m_polygon[0]); + fb.SetCenter({double{elementData.m_polygon[0].x}, double{elementData.m_polygon[0].y}}); } else if (elementData.m_polygon.size() == 2) { auto const & p1 = elementData.m_polygon[0]; auto const & p2 = elementData.m_polygon[1]; vector poly = { - {p1.x, p1.y}, {p1.x, p2.y}, {p2.x, p2.y}, {p2.x, p1.y}, {p1.x, p1.x}}; + {double{p1.x}, double{p1.y}}, + {double{p1.x}, double{p2.y}}, + {double{p2.x}, double{p2.y}}, + {double{p2.x}, double{p1.y}}, + {double{p1.x}, double{p1.x}}}; fb.AddPolygon(poly); fb.SetHoles({}); fb.SetArea(); @@ -143,7 +146,7 @@ void BuildTestData(std::vector const & testData, RegionsBuilder: } } -std::string ToLabelingString(vector const & path) +std::string ToLabelingString(vector const & path, bool withGeometry) { CHECK(!path.empty(), ()); std::stringstream stream; @@ -153,12 +156,28 @@ std::string ToLabelingString(vector const & path) stream << (*i)->GetData().GetName(); ++i; for (; i != path.end(); ++i) - stream << ", " << GetLabel((*i)->GetData().GetLevel()) << ": " << (*i)->GetData().GetName(); + { + auto const & region = (*i)->GetData(); + stream << ", " << GetLabel(region.GetLevel()) << ": " << region.GetName(); + + if (withGeometry) + { + stream << " ["; + + auto const & rect = region.GetRect(); + stream << std::fixed << std::setprecision(0); + stream << "(" << rect.min_corner().get<0>() << ", " << rect.min_corner().get<1>() << "), "; + stream << "(" << rect.max_corner().get<0>() << ", " << rect.max_corner().get<1>() << ")"; + + stream << "]"; + } + } return stream.str(); } -std::vector GenerateTestRegions(std::vector const & testData) +std::vector GenerateTestRegions(std::vector const & testData, + bool withGeometry = false) { classificator::Load(); @@ -170,13 +189,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::move(placePointsMap)); 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(ToLabelingString(path)); + kvRegions.push_back(ToLabelingString(path, withGeometry)); }); } }); @@ -387,58 +406,152 @@ UNIT_TEST(RegionsBuilderTest_GetCountryTrees) TEST(NameExists(bankOfNames, "Country_1Country_1_Region_5Country_1_Region_5_Subregion_7"), ()); } + +// City generation tests --------------------------------------------------------------------------- +UNIT_TEST(RegionsBuilderTest_GenerateCityPointRegionByAround) +{ + Tag const admin{"admin_level"}; + Tag const place{"place"}; + Tag const name{"name"}; + TagValue const ba{"boundary", "administrative"}; + + auto regions = GenerateTestRegions( + { + {1, {name = u8"Nederland", admin = "2", ba}, {{0, 0}, {50, 50}}}, + {2, {name = u8"Nederland", admin = "3", ba}, {{10, 10}, {20, 20}}}, + {3, {name = u8"Noord-Holland", admin = "4", ba}, {{12, 12}, {18, 18}}}, + {6, {name = u8"Amsterdam", place = "city", admin = "2"}, {{15, 15}}}, + }, + true /* withGeometry */); + + TEST(HasName(regions, u8"Nederland, locality: Amsterdam [(15, 15), (15, 15)]"), ()); +} + +UNIT_TEST(RegionsBuilderTest_GenerateCityPointRegionByNameMatching) +{ + Tag const admin{"admin_level"}; + Tag const place{"place"}; + Tag const name{"name"}; + TagValue const ba{"boundary", "administrative"}; + + auto regions = GenerateTestRegions( + { + {1, {name = u8"Nederland", admin = "2", ba}, {{0, 0}, {50, 50}}}, + {2, {name = u8"Nederland", admin = "3", ba}, {{10, 10}, {20, 20}}}, + {3, {name = u8"Noord-Holland", admin = "4", ba}, {{12, 12}, {18, 18}}}, + {4, {name = u8"Amsterdam", admin = "8", ba}, {{14, 14}, {17, 17}}}, + {5, {name = u8"Amsterdam", admin = "10", ba}, {{14, 14}, {16, 16}}}, + {6, {name = u8"Amsterdam", place = "city", admin = "2"}, {{15, 15}}}, + }, + true /* withGeometry */); + + TEST(HasName(regions, u8"Nederland, locality: Amsterdam [(14, 14), (16, 16)]"), ()); +} + +UNIT_TEST(RegionsBuilderTest_GenerateCityPointRegionByEnglishNameMatching) +{ + Tag const admin{"admin_level"}; + Tag const place{"place"}; + Tag const name{"name"}; + TagValue const ba{"boundary", "administrative"}; + + auto regions = GenerateTestRegions( + { + {1, {name = u8"België / Belgique / Belgien", admin = "2", ba}, {{0, 0}, {50, 50}}}, + {3, {name = u8"Ville de Bruxelles - Stad Brussel", admin = "8", ba}, {{12, 12}, {18, 18}}}, + {4, {name = u8"Bruxelles / Brussel", {"name:en", "Brussels"}, admin = "9", ba}, {{12, 12}, {17, 17}}}, + {5, {name = u8"Bruxelles - Brussel", {"name:en", "Brussels"}, place = "city"}, {{15, 15}}}, + }, + true /* withGeometry */); + + TEST(HasName(regions, u8"België / Belgique / Belgien, locality: Bruxelles - Brussel [(12, 12), (17, 17)]"), ()); +} + +UNIT_TEST(RegionsBuilderTest_GenerateCityPointRegionByNameMatchingWithCityPrefix) +{ + Tag const admin{"admin_level"}; + Tag const place{"place"}; + Tag const name{"name"}; + TagValue const ba{"boundary", "administrative"}; + + auto regions = GenerateTestRegions( + { + {1, {name = u8"United Kingdom", admin = "2", ba}, {{0, 0}, {50, 50}}}, + {3, {name = u8"Scotland", admin = "4", ba}, {{12, 12}, {18, 18}}}, + {4, {name = u8"City of Edinburgh", admin = "6", ba}, {{12, 12}, {17, 17}}}, + {5, {name = u8"Edinburgh", place = "city"}, {{15, 15}}}, + }, + true /* withGeometry */); + + TEST(HasName(regions, u8"United Kingdom, locality: Edinburgh [(12, 12), (17, 17)]"), ()); +} + +UNIT_TEST(RegionsBuilderTest_GenerateCityPointRegionByNameMatchingWithCityPostfix) +{ + Tag const admin{"admin_level"}; + Tag const place{"place"}; + Tag const name{"name"}; + TagValue const ba{"boundary", "administrative"}; + + auto regions = GenerateTestRegions( + { + {1, {name = u8"United Kingdom", admin = "2", ba}, {{0, 0}, {50, 50}}}, + {3, {name = u8"Scotland", admin = "4", ba}, {{12, 12}, {18, 18}}}, + {4, {name = u8"Edinburgh (city)", admin = "6", ba}, {{12, 12}, {17, 17}}}, + {5, {name = u8"Edinburgh", place = "city"}, {{15, 15}}}, + }, + true /* withGeometry */); + + TEST(HasName(regions, u8"United Kingdom, locality: Edinburgh [(12, 12), (17, 17)]"), ()); +} + // Russia regions tests ---------------------------------------------------------------------------- UNIT_TEST(RegionsBuilderTest_GenerateRusCitySuburb) { - TagValue const admin{"admin_level"}; - TagValue const place{"place"}; - TagValue const name{"name"}; + Tag const admin{"admin_level"}; + Tag const place{"place"}; + Tag const name{"name"}; TagValue const ba{"boundary", "administrative"}; auto regions = GenerateTestRegions({ - {1, {name = u8"Россия", admin = "2", ba}, {{0, 0}, {50, 50}}}, - {2, {name = u8"Сибирский федеральный округ", admin = "3", ba}, {{10, 10}, {20, 20}}}, - {3, {name = u8"Омская область", admin = "4", ba}, {{12, 12}, {18, 18}}}, - {4, {name = u8"Омск", place = "city"}, {{14, 14}, {16, 16}}}, - {5, - {name = u8"городской округ Омск", admin = "6", ba}, - {{14, 14}, {16, 16}}, - {{6, NodeEntry, "admin_centre"}}}, - {6, {name = u8"Омск", place = "city"}, {{14.5, 14.5}}}, - {7, {name = u8"Кировский административный округ", admin = "9", ba}, {{14, 14}, {15, 15}}}, + {1, {name = u8"Россия", admin = "2", ba}, {{0, 0}, {50, 50}}}, + {2, {name = u8"Сибирский федеральный округ", admin = "3", ba}, {{10, 10}, {20, 20}}}, + {3, {name = u8"Омская область", admin = "4", ba}, {{12, 12}, {18, 18}}}, + {4, {name = u8"Омск", place = "city"}, {{14, 14}, {16, 16}}}, + {5, {name = u8"городской округ Омск", admin = "6", ba}, {{14, 14}, {16, 16}}, + {{6, NodeEntry, "admin_centre"}}}, + {6, {name = u8"Омск", place = "city"}, {{15, 15}}}, + {7, {name = u8"Кировский административный округ", admin = "9", ba}, {{14, 14}, {15, 15}}}, }); - /* - TEST(HasName(regions, u8"Россия, region: Омская область, subregion: городской округ Омск, " - u8"locality: Омск"), - ()); - TEST(HasName(regions, u8"Россия, region: Омская область, subregion: городской округ Омск, " - u8"locality: Омск, suburb: Кировский административный округ"), - ()); + TEST(HasName(regions, u8"Россия, region: Омская область, subregion: городской округ Омск, " + u8"locality: Омск"), + ()); + /* FIXME: + TEST(HasName(regions, u8"Россия, region: Омская область, subregion: городской округ Омск, " + u8"locality: Омск, suburb: Кировский административный округ"), + ()); */ } UNIT_TEST(RegionsBuilderTest_GenerateRusMoscowSuburb) { - TagValue const admin{"admin_level"}; - TagValue const place{"place"}; - TagValue const name{"name"}; + Tag const admin{"admin_level"}; + Tag const place{"place"}; + Tag const name{"name"}; TagValue const ba{"boundary", "administrative"}; auto regions = GenerateTestRegions({ - {1, {name = u8"Россия", admin = "2", ba}, {{0, 0}, {50, 50}}}, - {2, {name = u8"Центральный федеральный округ", admin = "3", ba}, {{10, 10}, {20, 20}}}, - {3, {name = u8"Москва", admin = "4", ba}, {{12, 12}, {18, 18}}}, - {4, {name = u8"Москва", place = "city"}, {{12, 12}, {17, 17}}}, - {5, {name = u8"Западный административный округ", admin = "5", ba}, {{14, 14}, {16, 16}}}, - {6, - {name = u8"район Раменки", admin = "8", ba}, - {{14, 14}, {15, 15}}, - {{7, NodeEntry, "label"}}}, - {7, {name = u8"Раменки", place = "suburb"}, {{14.5, 14.5}}}, // label - {8, {name = u8"Тропарёво", place = "suburb"}, {{15.1, 15.1}}}, // no label - {9, {name = u8"Воробъёвы горы", place = "suburb"}, {{14.5, 14.5}, {14.6, 14.6}}}, - {10, {name = u8"Центр", place = "suburb"}, {{15, 15}, {15.5, 15.5}}}, + {1, {name = u8"Россия", admin = "2", ba}, {{0, 0}, {50, 50}}}, + {2, {name = u8"Центральный федеральный округ", admin = "3", ba}, {{10, 10}, {20, 20}}}, + {3, {name = u8"Москва", admin = "4", ba}, {{12, 12}, {20, 20}}}, + {4, {name = u8"Москва", place = "city"}, {{12, 12}, {19, 19}}}, + {5, {name = u8"Западный административный округ", admin = "5", ba}, {{12, 12}, {18, 18}}}, + {6, {name = u8"район Раменки", admin = "8", ba}, {{12, 12}, {15, 15}}, {{7, NodeEntry, "label"}}}, + {7, {name = u8"Раменки", place = "suburb"}, {{13, 13}}}, // label + {8, {name = u8"Тропарёво", place = "suburb"}, {{16, 16}}}, // no label + {9, {name = u8"Воробъёвы горы", place = "suburb"}, {{12, 12}, {14, 14}}}, + {10, {name = u8"Центр", place = "suburb"}, {{15, 15}, {16, 16}}}, }); TEST(HasName(regions, u8"Россия, region: Москва"), ()); @@ -463,9 +576,9 @@ UNIT_TEST(RegionsBuilderTest_GenerateRusMoscowSuburb) UNIT_TEST(RegionsBuilderTest_GenerateRusSPetersburgSuburb) { - TagValue const admin{"admin_level"}; - TagValue const place{"place"}; - TagValue const name{"name"}; + Tag const admin{"admin_level"}; + Tag const place{"place"}; + Tag const name{"name"}; TagValue const ba{"boundary", "administrative"}; auto regions = GenerateTestRegions({ diff --git a/generator/regions/collector_region_info.cpp b/generator/regions/collector_region_info.cpp index a3445f3a8a..afd8653712 100644 --- a/generator/regions/collector_region_info.cpp +++ b/generator/regions/collector_region_info.cpp @@ -32,17 +32,56 @@ PlaceType EncodePlaceType(std::string const & place) {"city", PlaceType::City}, {"town", PlaceType::Town}, {"village", PlaceType::Village}, + {"hamlet", PlaceType::Hamlet}, + {"isolated_dwelling", PlaceType::IsolatedDwelling}, {"suburb", PlaceType::Suburb}, {"quarter", PlaceType::Quarter}, {"neighbourhood", PlaceType::Neighbourhood}, - {"hamlet", PlaceType::Hamlet}, - {"isolated_dwelling", PlaceType::IsolatedDwelling} }; auto const it = m.find(place); return it == m.end() ? PlaceType::Unknown : it->second; } +char const * StringifyPlaceType(PlaceType placeType) +{ + switch (placeType) + { + case PlaceType::Country: + return "country"; + case PlaceType::State: + return "state"; + case PlaceType::Province: + return "province"; + case PlaceType::District: + return "district"; + case PlaceType::County: + return "county"; + case PlaceType::Municipality: + return "municipality"; + case PlaceType::City: + return "city"; + case PlaceType::Town: + return "town"; + case PlaceType::Village: + return "village"; + case PlaceType::Hamlet: + return "hamlet"; + case PlaceType::IsolatedDwelling: + return "isolated_dwelling"; + case PlaceType::Suburb: + return "suburb"; + case PlaceType::Quarter: + return "quarter"; + case PlaceType::Neighbourhood: + return "neighbourhood"; + case PlaceType::Unknown: + return "unknown"; + }; + + UNREACHABLE(); +} + char const * GetLabel(PlaceLevel level) { switch (level) diff --git a/generator/regions/collector_region_info.hpp b/generator/regions/collector_region_info.hpp index e602e5de58..88368eece5 100644 --- a/generator/regions/collector_region_info.hpp +++ b/generator/regions/collector_region_info.hpp @@ -60,13 +60,14 @@ enum class PlaceType: uint8_t Town = 8, Village = 9, Hamlet = 10, - Suburb = 11, - Quarter = 12, - Neighbourhood = 13, - IsolatedDwelling = 14, + IsolatedDwelling = 11, + Suburb = 12, + Quarter = 13, + Neighbourhood = 14, }; PlaceType EncodePlaceType(std::string const & place); +char const * StringifyPlaceType(PlaceType placeType); enum class PlaceLevel : uint8_t { diff --git a/generator/regions/country_specifier.cpp b/generator/regions/country_specifier.cpp index 555ac0c526..e92aabfd57 100644 --- a/generator/regions/country_specifier.cpp +++ b/generator/regions/country_specifier.cpp @@ -23,7 +23,8 @@ PlaceLevel CountrySpecifier::GetLevel(Region const & region) const return PlaceLevel::Unknown; } -PlaceLevel CountrySpecifier::GetLevel(PlaceType placeType) const +// static +PlaceLevel CountrySpecifier::GetLevel(PlaceType placeType) { switch (placeType) { @@ -40,13 +41,13 @@ PlaceLevel CountrySpecifier::GetLevel(PlaceType placeType) const case PlaceType::Town: case PlaceType::Village: case PlaceType::Hamlet: + case PlaceType::IsolatedDwelling: 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; diff --git a/generator/regions/country_specifier.hpp b/generator/regions/country_specifier.hpp index c24bb88cec..d3a1be6f53 100644 --- a/generator/regions/country_specifier.hpp +++ b/generator/regions/country_specifier.hpp @@ -21,8 +21,7 @@ public: // Non-transitive. virtual int RelateByWeight(LevelRegion const & l, LevelRegion const & r) const; -protected: - PlaceLevel GetLevel(PlaceType placeType) const; + static PlaceLevel GetLevel(PlaceType placeType); }; } // namespace regions } // namespace generator diff --git a/generator/regions/locality_point_integrator.cpp b/generator/regions/locality_point_integrator.cpp new file mode 100644 index 0000000000..718ab92ca6 --- /dev/null +++ b/generator/regions/locality_point_integrator.cpp @@ -0,0 +1,221 @@ +#include "generator/regions/locality_point_integrator.hpp" + +#include "generator/regions/collector_region_info.hpp" +#include "generator/regions/regions_builder.hpp" + +#include "base/string_utils.hpp" + +#include +#include + +#include + +namespace generator +{ +namespace regions +{ +LocalityPointIntegrator::LocalityPointIntegrator(PlacePoint const & localityPoint, + CountrySpecifier const & countrySpecifier) + : m_localityRegion{MakeAroundRegion(localityPoint, countrySpecifier)} + , m_countrySpecifier{countrySpecifier} +{ + CHECK(countrySpecifier.GetLevel(localityPoint.GetPlaceType()) == PlaceLevel::Locality, ()); +} + +bool LocalityPointIntegrator::IntegrateInto(Node::Ptr & tree) +{ + auto & region = tree->GetData(); + + if (HasIntegratingLocalityName(region)) + { + // Match any locality type (city/town/village). + if (region.GetLevel() == PlaceLevel::Locality) + { + EnlargeRegion(region); + return true; + } + + if (IsSuitableForLocalityRegionize(region)) + RegionizeBy(region); + } + + // Find deepest region for integration. + for (auto & subtree : tree->GetChildren()) + { + auto const & subregion = subtree->GetData(); + if (!subregion.Contains(m_localityRegion.GetCenter())) + continue; + + if (IntegrateInto(subtree)) + return true; + } + + if (0 < RegionsBuilder::CompareAffiliation(region, m_localityRegion, m_countrySpecifier)) + { + InsertInto(tree); + return true; + } + + return false; +} + +bool LocalityPointIntegrator::HasIntegratingLocalityName(LevelRegion const & region) const +{ + auto const & regionName = region.GetName(); + auto const & localityName = m_localityRegion.GetName(); + if (regionName == localityName) + return true; + + if (strings::StartsWith(regionName, "City of") && regionName == "City of " + localityName) + return true; + if (strings::EndsWith(regionName, "(city)") && regionName == localityName + " (city)") + return true; + + auto const & regionEnglishName = region.GetName(StringUtf8Multilang::kEnglishCode); + if (!regionEnglishName.empty()) + { + auto const & localityEnglishName = m_localityRegion.GetName(StringUtf8Multilang::kEnglishCode); + if (regionEnglishName == localityEnglishName) + return true; + } + + return false; +} + +bool LocalityPointIntegrator::IsSuitableForLocalityRegionize(LevelRegion const & region) const +{ + auto const adminLevel = region.GetAdminLevel(); + if (adminLevel != AdminLevel::Unknown && adminLevel < AdminLevel::Three) + return false; + + auto const regionPlaceType = region.GetPlaceType(); + if (regionPlaceType != PlaceType::Unknown && regionPlaceType >= PlaceType::City) + return false; + + return true; +} + +void LocalityPointIntegrator::EnlargeRegion(LevelRegion & region) +{ + LOG(LDEBUG, ("Enclose", + StringifyPlaceType(m_localityRegion.GetPlaceType()), "place point", + m_localityRegion.GetId(), "(", GetRegionNotation(m_localityRegion), ")", + "into", region.GetId(), "(", GetRegionNotation(region), ")")); + if (!region.GetLabel()) + region.SetLabel(*m_localityRegion.GetLabel()); +} + +void LocalityPointIntegrator::RegionizeBy(LevelRegion const & region) +{ + m_localityRegion.SetPolygon(region.GetPolygon()); + m_regionizedByRegion = region; +} + +void LocalityPointIntegrator::InsertInto(Node::Ptr & node) +{ + if (m_regionizedByRegion) + { + LOG(LDEBUG, ("Regionize", + StringifyPlaceType(m_localityRegion.GetPlaceType()), "place point", + m_localityRegion.GetId(), "(", GetRegionNotation(m_localityRegion), ")", + "by", m_regionizedByRegion->GetId(), + "(", GetRegionNotation(*m_regionizedByRegion), ")")); + } + else + { + auto const & region = node->GetData(); + LOG(LDEBUG, ("Insert around", + StringifyPlaceType(m_localityRegion.GetPlaceType()), "place point", + m_localityRegion.GetId(), "(", GetRegionNotation(m_localityRegion), ")", + "into", region.GetId(), "(", GetRegionNotation(region), ")")); + + EmboundBy(region); + } + + RegionsBuilder::InsertIntoSubtree(node, std::move(m_localityRegion), m_countrySpecifier); +} + +void LocalityPointIntegrator::EmboundBy(LevelRegion const & region) +{ + auto const & regionPolygon = *region.GetPolygon(); + auto const & localityPolygon = *m_localityRegion.GetPolygon(); + auto intersection = boost::geometry::model::multi_polygon{}; + boost::geometry::intersection(regionPolygon, localityPolygon, intersection); + // Select one with label point. + for (auto & polygon : intersection) + { + if (!boost::geometry::covered_by(m_localityRegion.GetCenter(), polygon)) + continue; + + // Skip error in boost::geometry::intersection(): there are A and B when + // intersection(A, B) != null and intersection(A, intersection(A, B)) == null. + auto checkPolygon = boost::geometry::model::multi_polygon{}; + boost::geometry::intersection(regionPolygon, polygon, checkPolygon); + if (checkPolygon.empty()) + continue; + + m_localityRegion.SetPolygon(std::make_shared(std::move(polygon))); + return; + } + + LOG(LWARNING, ("Failed to embound", + StringifyPlaceType(m_localityRegion.GetPlaceType()), "place", + m_localityRegion.GetId(), "(", GetRegionNotation(m_localityRegion), ")", + "by", region.GetId(), "(", GetRegionNotation(region), ")")); +} + +// static +LevelRegion LocalityPointIntegrator::MakeAroundRegion(PlacePoint const & localityPoint, + CountrySpecifier const & countrySpecifier) +{ + auto const placeType = localityPoint.GetPlaceType(); + auto const radius = GetRadiusByPlaceType(placeType); + auto polygon = MakePolygonWithRadius(localityPoint.GetPosition(), radius); + auto region = LevelRegion{ + PlaceLevel::Locality, + {localityPoint.GetMultilangName(), localityPoint.GetRegionData(), std::move(polygon)}}; + region.SetLabel(localityPoint); + return region; +} + +// static +double LocalityPointIntegrator::GetRadiusByPlaceType(PlaceType place) +{ + // Based on average radiuses of OSM place polygons. + switch (place) + { + case PlaceType::City: + return 0.078; + case PlaceType::Town: + return 0.033; + case PlaceType::Village: + return 0.013; + case PlaceType::Hamlet: + return 0.0067; + case PlaceType::IsolatedDwelling: + return 0.0035; + default: + UNREACHABLE(); + } + UNREACHABLE(); +} + +// static +std::shared_ptr LocalityPointIntegrator::MakePolygonWithRadius( + BoostPoint const & point, double radius, size_t numPoints) +{ + boost::geometry::strategy::buffer::point_circle point_strategy(numPoints); + boost::geometry::strategy::buffer::distance_symmetric distance_strategy(radius); + + static boost::geometry::strategy::buffer::join_round const join_strategy; + static boost::geometry::strategy::buffer::end_round const end_strategy; + static boost::geometry::strategy::buffer::side_straight const side_strategy; + + boost::geometry::model::multi_polygon result; + boost::geometry::buffer(point, result, distance_strategy, side_strategy, join_strategy, + end_strategy, point_strategy); + CHECK_EQUAL(result.size(), 1, ()); + return std::make_shared(std::move(result.front())); +} +} // namespace regions +} // namespace generator diff --git a/generator/regions/locality_point_integrator.hpp b/generator/regions/locality_point_integrator.hpp new file mode 100644 index 0000000000..2c38ebbfc6 --- /dev/null +++ b/generator/regions/locality_point_integrator.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include "generator/boost_helpers.hpp" +#include "generator/regions/country_specifier.hpp" +#include "generator/regions/level_region.hpp" +#include "generator/regions/node.hpp" +#include "generator/regions/place_point.hpp" + +#include + +namespace generator +{ +namespace regions +{ +// LocalityPointIntegrator inserts place point (city/town/village) into region tree +// as region with around boundary or boundary from administrative region (by name matching). +class LocalityPointIntegrator +{ +public: + LocalityPointIntegrator(PlacePoint const & localityPoint, + CountrySpecifier const & countrySpecifier); + + bool IntegrateInto(Node::Ptr & tree); + +private: + bool IsSuitableForLocalityRegionize(LevelRegion const & region) const; + bool HasIntegratingLocalityName(LevelRegion const & region) const; + void EnlargeRegion(LevelRegion & region); + void RegionizeBy(LevelRegion const & region); + void InsertInto(Node::Ptr & node); + void EmboundBy(LevelRegion const & region); + static LevelRegion MakeAroundRegion(PlacePoint const & localityPoint, + CountrySpecifier const & countrySpecifier); + // This function uses heuristics and assigns a radius according to the tag place. + // The radius will be returned in mercator units. + static double GetRadiusByPlaceType(PlaceType place); + static std::shared_ptr MakePolygonWithRadius( + BoostPoint const & point, double radius, size_t numPoints = 16); + + LevelRegion m_localityRegion; + CountrySpecifier const & m_countrySpecifier; + boost::optional m_regionizedByRegion; +}; +} // namespace regions +} // namespace generator diff --git a/generator/regions/place_points_integrator.cpp b/generator/regions/place_points_integrator.cpp new file mode 100644 index 0000000000..d1c17f4c4c --- /dev/null +++ b/generator/regions/place_points_integrator.cpp @@ -0,0 +1,63 @@ +#include "generator/regions/place_points_integrator.hpp" + +#include "generator/regions/locality_point_integrator.hpp" + +namespace generator +{ +namespace regions +{ +PlacePointsIntegrator::PlacePointsIntegrator(PlacePointsMap const & placePoints, + CountrySpecifier const & countrySpecifier) + : m_placePoints(placePoints) + , m_countrySpecifier{countrySpecifier} +{ } + +void PlacePointsIntegrator::ApplyTo(Node::PtrList & outers) +{ + ApplyLocalityPointsTo(outers); +} + +void PlacePointsIntegrator::ApplyLocalityPointsTo(Node::PtrList & outers) +{ + // Intergrate from biggest to smallest location types for intersections of nested localities. + auto localityTypes = {PlaceType::City, PlaceType::Town, + PlaceType::Village, PlaceType::Hamlet, PlaceType::IsolatedDwelling}; + for (auto type : localityTypes) + { + for (auto const & placePoint : m_placePoints) + { + auto const & place = placePoint.second; + if (place.GetPlaceType() == type) + ApplyLocalityPointTo(place, outers); + } + } +} + +void PlacePointsIntegrator::ApplyLocalityPointTo(PlacePoint const & localityPoint, + Node::PtrList & outers) +{ + for (auto & tree : outers) + { + auto & countryRegion = tree->GetData(); + if (countryRegion.Contains(localityPoint)) + { + IntegrateLocalityPointInto(localityPoint, tree); + return; + } + } +} + +void PlacePointsIntegrator::IntegrateLocalityPointInto( + PlacePoint const & localityPoint, Node::Ptr & tree) +{ + auto localityIntegrator = LocalityPointIntegrator{localityPoint, m_countrySpecifier}; + if (!localityIntegrator.IntegrateInto(tree)) + { + LOG(LWARNING, ("Can't integrate the", + StringifyPlaceType(localityPoint.GetPlaceType()), "place", + localityPoint.GetId(), "(", GetRegionNotation(localityPoint), ")", + "into", GetRegionNotation(tree->GetData()))); + } +} +} // namespace regions +} // namespace generator diff --git a/generator/regions/place_points_integrator.hpp b/generator/regions/place_points_integrator.hpp new file mode 100644 index 0000000000..15d3d3bd3a --- /dev/null +++ b/generator/regions/place_points_integrator.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "generator/regions/country_specifier.hpp" +#include "generator/regions/node.hpp" +#include "generator/regions/place_point.hpp" + +namespace generator +{ +namespace regions +{ +class PlacePointsIntegrator +{ +public: + PlacePointsIntegrator(PlacePointsMap const & placePoints, + CountrySpecifier const & countrySpecifier); + + void ApplyTo(Node::PtrList & outers); + +private: + void ApplyLocalityPointsTo(Node::PtrList & outers); + void ApplyLocalityPointTo(PlacePoint const & localityPoint, Node::PtrList & outers); + void IntegrateLocalityPointInto(PlacePoint const & localityPoint, Node::Ptr & tree); + + PlacePointsMap const & m_placePoints; + CountrySpecifier const & m_countrySpecifier; +}; +} // namespace regions +} // namespace generator diff --git a/generator/regions/region.cpp b/generator/regions/region.cpp index 6daee9b04d..e8c83149ca 100644 --- a/generator/regions/region.cpp +++ b/generator/regions/region.cpp @@ -19,22 +19,6 @@ namespace generator { namespace regions { -BoostPolygon MakePolygonWithRadius(BoostPoint const & point, double radius, size_t numPoints = 16) -{ - boost::geometry::strategy::buffer::point_circle point_strategy(numPoints); - boost::geometry::strategy::buffer::distance_symmetric distance_strategy(radius); - - static boost::geometry::strategy::buffer::join_round const join_strategy; - static boost::geometry::strategy::buffer::end_round const end_strategy; - static boost::geometry::strategy::buffer::side_straight const side_strategy; - - boost::geometry::model::multi_polygon result; - boost::geometry::buffer(point, result, distance_strategy, side_strategy, join_strategy, - end_strategy, point_strategy); - CHECK_EQUAL(result.size(), 1, ()); - return std::move(result.front()); -} - Region::Region(FeatureBuilder const & fb, RegionDataProxy const & rd) : RegionWithName(fb.GetParams().name) , RegionWithData(rd) @@ -43,19 +27,15 @@ Region::Region(FeatureBuilder const & fb, RegionDataProxy const & rd) FillPolygon(fb); boost::geometry::envelope(*m_polygon, m_rect); m_area = boost::geometry::area(*m_polygon); + CHECK_GREATER_OR_EQUAL(m_area, 0.0, ()); } -Region::Region(PlacePoint const & place) - : RegionWithName(place.GetMultilangName()) - , RegionWithData(place.GetRegionData()) - , m_polygon(std::make_shared()) +Region::Region(StringUtf8Multilang const & name, RegionDataProxy const & rd, + std::shared_ptr const & polygon) + : RegionWithName(name) + , RegionWithData(rd) { - 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); + SetPolygon(polygon); } std::string Region::GetTranslatedOrTransliteratedName(LanguageCode languageCode) const @@ -70,9 +50,9 @@ std::string Region::GetTranslatedOrTransliteratedName(LanguageCode languageCode) std::string Region::GetName(int8_t lang) const { if (m_placeLabel) - return m_placeLabel->GetName(); + return m_placeLabel->GetName(lang); - return RegionWithName::GetName(); + return RegionWithName::GetName(lang); } base::GeoObjectId Region::GetId() const @@ -102,32 +82,17 @@ boost::optional Region::GetIsoCode() const return RegionWithData::GetIsoCode(); } +boost::optional const & Region::GetLabel() const noexcept +{ + return m_placeLabel; +} + void Region::SetLabel(PlacePoint const & place) { CHECK(!m_placeLabel, ()); m_placeLabel = place; } -// static -double Region::GetRadiusByPlaceType(PlaceType place) -{ - // Based on average radiuses of OSM place polygons. - switch (place) - { - case PlaceType::City: return 0.078; - case PlaceType::Town: return 0.033; - case PlaceType::Village: return 0.013; - case PlaceType::Hamlet: 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(); -} - void Region::FillPolygon(FeatureBuilder const & fb) { CHECK(m_polygon, ()); @@ -136,6 +101,15 @@ void Region::FillPolygon(FeatureBuilder const & fb) bool Region::IsLocality() const { return GetPlaceType() >= PlaceType::City; } +void Region::SetPolygon(std::shared_ptr const & polygon) +{ + m_polygon = polygon; + m_rect = {}; + boost::geometry::envelope(*m_polygon, m_rect); + m_area = boost::geometry::area(*m_polygon); + CHECK_GREATER_OR_EQUAL(m_area, 0.0, ()); +} + bool Region::Contains(Region const & smaller) const { CHECK(m_polygon, ()); @@ -191,16 +165,5 @@ bool Region::Contains(BoostPoint const & point) const return boost::geometry::covered_by(point, m_rect) && boost::geometry::covered_by(point, *m_polygon); } - -std::string GetRegionNotation(Region const & region) -{ - auto notation = region.GetTranslatedOrTransliteratedName(StringUtf8Multilang::GetLangIndex("en")); - if (notation.empty()) - return region.GetName(); - - if (notation != region.GetName()) - notation += " / " + region.GetName(); - return notation; -} } // namespace regions } // namespace generator diff --git a/generator/regions/region.hpp b/generator/regions/region.hpp index 843a1d9643..c161e371db 100644 --- a/generator/regions/region.hpp +++ b/generator/regions/region.hpp @@ -23,8 +23,8 @@ 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); + Region(StringUtf8Multilang const & name, RegionDataProxy const & rd, + std::shared_ptr const & polygon); // See RegionWithName::GetTranslatedOrTransliteratedName(). std::string GetTranslatedOrTransliteratedName(LanguageCode languageCode) const; @@ -36,6 +36,7 @@ public: boost::optional GetIsoCode() const; using RegionWithData::GetLabelOsmId; + boost::optional const & GetLabel() const noexcept; void SetLabel(PlacePoint const & place); bool Contains(Region const & smaller) const; @@ -47,10 +48,8 @@ public: bool IsLocality() const; BoostRect const & GetRect() const { return m_rect; } std::shared_ptr const & GetPolygon() const noexcept { return m_polygon; } + void SetPolygon(std::shared_ptr const & polygon); double GetArea() const { return m_area; } - // This function uses heuristics and assigns a radius according to the tag place. - // The radius will be returned in mercator units. - static double GetRadiusByPlaceType(PlaceType place); private: void FillPolygon(feature::FeatureBuilder const & fb); @@ -60,7 +59,5 @@ private: BoostRect m_rect; double m_area; }; - -std::string GetRegionNotation(Region const & region); } // namespace regions } // namespace generator diff --git a/generator/regions/region_base.hpp b/generator/regions/region_base.hpp index f828e6e89e..3604b054bc 100644 --- a/generator/regions/region_base.hpp +++ b/generator/regions/region_base.hpp @@ -60,5 +60,17 @@ public: protected: RegionDataProxy m_regionData; }; + +template +std::string GetRegionNotation(Place const & place) +{ + auto notation = place.GetTranslatedOrTransliteratedName(StringUtf8Multilang::GetLangIndex("en")); + if (notation.empty()) + return place.GetName(); + + if (notation != place.GetName()) + notation += " / " + place.GetName(); + return notation; +} } // namespace regions } // namespace generator diff --git a/generator/regions/regions_builder.cpp b/generator/regions/regions_builder.cpp index de8cfb448f..cf12f74816 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/place_points_integrator.hpp" #include "generator/regions/specs/rus.hpp" #include "base/assert.hpp" @@ -27,10 +28,10 @@ RegionsBuilder::RegionsBuilder(Regions && regions, PlacePointsMap && placePoints ASSERT(m_threadsCount != 0, ()); MoveLabelPlacePoints(placePointsMap, regions); - FixRegionsWithPlacePointApproximation(placePointsMap, regions); m_regionsInAreaOrder = FormRegionsInAreaOrder(std::move(regions)); m_countriesOuters = ExtractCountriesOuters(m_regionsInAreaOrder); + m_placePointsMap = std::move(placePointsMap); } void RegionsBuilder::MoveLabelPlacePoints(PlacePointsMap & placePointsMap, Regions & regions) @@ -96,10 +97,9 @@ RegionsBuilder::StringsList RegionsBuilder::GetCountryNames() const } Node::Ptr RegionsBuilder::BuildCountryRegionTree( - Region const & outer, Regions const & regionsInAreaOrder, - CountrySpecifier const & countrySpecifier) const + Region const & outer, CountrySpecifier const & countrySpecifier) const { - auto nodes = MakeCountryNodesInAreaOrder(outer, regionsInAreaOrder, countrySpecifier); + auto nodes = MakeCountryNodesInAreaOrder(outer, m_regionsInAreaOrder, countrySpecifier); for (auto i = std::crbegin(nodes), end = std::crend(nodes); i != end; ++i) { @@ -162,10 +162,10 @@ Node::Ptr RegionsBuilder::ChooseParent( if (i == forItem) continue; - auto const c = Compare(candidateRegion, region, countrySpecifier); + auto const c = CompareAffiliation(candidateRegion, region, countrySpecifier); if (c == 1) { - if (parent && 0 <= Compare(candidateRegion, parent->GetData(), countrySpecifier)) + if (parent && 0 <= CompareAffiliation(candidateRegion, parent->GetData(), countrySpecifier)) continue; parent = candidate; @@ -190,7 +190,46 @@ std::vector::const_reverse_iterator RegionsBuilder::FindAreaLowerBoun } // static -int RegionsBuilder::Compare(LevelRegion const & l, LevelRegion const & r, +void RegionsBuilder::InsertIntoSubtree(Node::Ptr & subtree, LevelRegion && region, + CountrySpecifier const & countrySpecifier) +{ + auto newNode = std::make_shared(std::move(region)); + InsertIntoSubtree(subtree, std::move(newNode), countrySpecifier); +} + +// static +void RegionsBuilder::InsertIntoSubtree(Node::Ptr & subtree, Node::Ptr && newNode, + CountrySpecifier const & countrySpecifier) +{ + CHECK(0 < CompareAffiliation(subtree->GetData(), newNode->GetData(), countrySpecifier), ()); + + auto & children = subtree->GetChildren(); + auto childIt = children.begin(); + while (childIt != children.end()) + { + auto & child = *childIt; + auto const c = CompareAffiliation(child->GetData(), newNode->GetData(), countrySpecifier); + if (c > 0) + return InsertIntoSubtree(child, std::move(newNode), countrySpecifier); + + if (c < 0) + { + child->SetParent(newNode); + newNode->AddChild(child); + childIt = children.erase(childIt); + continue; + } + + ASSERT(c == 0, ()); + ++childIt; + } + + newNode->SetParent(subtree); + subtree->AddChild(newNode); +} + +// static +int RegionsBuilder::CompareAffiliation(LevelRegion const & l, LevelRegion const & r, CountrySpecifier const & countrySpecifier) { if (IsAreaLessRely(r, l) && l.Contains(r)) @@ -235,9 +274,7 @@ void RegionsBuilder::ForEachCountry(CountryFn fn) for (auto const & countryName : GetCountryNames()) { - auto result = threadPool.Submit([this, countryName](){ - return BuildCountry(countryName); - }); + auto result = threadPool.Submit([this, countryName]() { return BuildCountry(countryName); }); buildingTasks.emplace_back(std::move(result)); } } @@ -253,14 +290,19 @@ void RegionsBuilder::ForEachCountry(CountryFn fn) Node::PtrList RegionsBuilder::BuildCountry(std::string const & countryName) const { - 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 countrySpecifier = GetCountrySpecifier(countryName); auto countryTrees = BuildCountryRegionTrees(outers, *countrySpecifier); + PlacePointsIntegrator pointsIntegrator{m_placePointsMap, *countrySpecifier}; + LOG(LINFO, ("Start integrate place points for", countryName)); + pointsIntegrator.ApplyTo(countryTrees); + LOG(LINFO, ("Finish integrate place points for", countryName)); + countrySpecifier->AdjustRegionsLevel(countryTrees); return countryTrees; @@ -272,7 +314,7 @@ Node::PtrList RegionsBuilder::BuildCountryRegionTrees( Node::PtrList trees; for (auto const & outer : outers) { - auto tree = BuildCountryRegionTree(outer, m_regionsInAreaOrder, countrySpecifier); + auto tree = BuildCountryRegionTree(outer, countrySpecifier); trees.push_back(std::move(tree)); } diff --git a/generator/regions/regions_builder.hpp b/generator/regions/regions_builder.hpp index dbe47bfa6c..f508ed0da3 100644 --- a/generator/regions/regions_builder.hpp +++ b/generator/regions/regions_builder.hpp @@ -1,6 +1,7 @@ #pragma once #include "generator/regions/country_specifier.hpp" +#include "generator/regions/level_region.hpp" #include "generator/regions/node.hpp" #include "generator/regions/region.hpp" @@ -30,6 +31,12 @@ public: StringsList GetCountryNames() const; void ForEachCountry(CountryFn fn); + static void InsertIntoSubtree(Node::Ptr & subtree, LevelRegion && region, + CountrySpecifier const & countrySpecifier); + // Return: 0 - no relation, 1 - |l| contains |r|, -1 - |r| contains |l|. + static int CompareAffiliation(LevelRegion const & l, LevelRegion const & r, + CountrySpecifier const & countrySpecifier); + private: static constexpr double kAreaRelativeErrorPercent = 0.1; @@ -39,7 +46,7 @@ private: Node::PtrList BuildCountry(std::string const & countryName) const; Node::PtrList BuildCountryRegionTrees(Regions const & outers, CountrySpecifier const & countrySpecifier) const; - Node::Ptr BuildCountryRegionTree(Region const & outer, Regions const & regionsInAreaOrder, + Node::Ptr BuildCountryRegionTree(Region const & outer, CountrySpecifier const & countrySpecifier) const; std::vector MakeCountryNodesInAreaOrder( Region const & countryOuter, Regions const & regionsInAreaOrder, @@ -50,14 +57,14 @@ private: std::vector::const_reverse_iterator FindAreaLowerBoundRely( std::vector const & nodesInAreaOrder, std::vector::const_reverse_iterator forItem) const; - // Return: 0 - no relation, 1 - |l| contains |r|, -1 - |r| contains |l|. - static int Compare(LevelRegion const & l, LevelRegion const & r, - CountrySpecifier const & countrySpecifier); - static bool IsAreaLessRely(Region const & l, Region const & r); std::unique_ptr GetCountrySpecifier(std::string const & countryName) const; + static void InsertIntoSubtree(Node::Ptr & subtree, Node::Ptr && newNode, + CountrySpecifier const & countrySpecifier); + static bool IsAreaLessRely(Region const & l, Region const & r); Regions m_countriesOuters; Regions m_regionsInAreaOrder; + PlacePointsMap m_placePointsMap; size_t m_threadsCount; }; } // namespace regions diff --git a/generator/regions/regions_fixer.cpp b/generator/regions/regions_fixer.cpp deleted file mode 100644 index 2327567c4f..0000000000 --- a/generator/regions/regions_fixer.cpp +++ /dev/null @@ -1,113 +0,0 @@ -#include "generator/regions/regions_fixer.hpp" - -#include "base/logging.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -namespace generator -{ -namespace regions -{ -namespace -{ -class RegionLocalityChecker -{ -public: - RegionLocalityChecker() = default; - explicit RegionLocalityChecker(RegionsBuilder::Regions const & regions) - { - for (auto const & region : regions) - { - auto const name = region.GetName(); - if (region.IsLocality() && !name.empty()) - m_nameRegionMap.emplace(std::move(name), region); - } - } - - bool PlaceExistsAsRegion(PlacePoint const & place) - { - auto const placeType = place.GetPlaceType(); - auto const range = m_nameRegionMap.equal_range(place.GetName()); - for (auto it = range.first; it != range.second; ++it) - { - Region const & region = it->second; - if (placeType == region.GetPlaceType() && region.Contains(place)) - return true; - } - - return false; - } - -private: - std::multimap> m_nameRegionMap; -}; - -class RegionsFixerWithPlacePointApproximation -{ -public: - explicit RegionsFixerWithPlacePointApproximation(RegionsBuilder::Regions && regions, - PlacePointsMap const & placePointsMap) - : m_regions(std::move(regions)), m_placePointsMap(placePointsMap) {} - - - RegionsBuilder::Regions && GetFixedRegions() - { - RegionLocalityChecker regionsChecker(m_regions); - RegionsBuilder::Regions approximatedRegions; - size_t countOfFixedRegions = 0; - for (auto const & placeKeyValue : m_placePointsMap) - { - auto const & place = placeKeyValue.second; - if (IsApproximable(place) && !regionsChecker.PlaceExistsAsRegion(place)) - { - approximatedRegions.push_back(Region(place)); - ++countOfFixedRegions; - } - } - - LOG(LINFO, ("Place boundaries restored by approximation:", countOfFixedRegions)); - std::move(std::begin(approximatedRegions), std::end(approximatedRegions), - std::back_inserter(m_regions)); - return std::move(m_regions); - } - -private: - bool IsApproximable(PlacePoint const & place) - { - switch (place.GetPlaceType()) - { - case PlaceType::City: - case PlaceType::Town: - case PlaceType::Village: - case PlaceType::Hamlet: - case PlaceType::IsolatedDwelling: - return true; - default: - break; - } - - return false; - } - - RegionsBuilder::Regions m_regions; - PlacePointsMap const & m_placePointsMap; -}; -} // namespace - -void FixRegionsWithPlacePointApproximation(PlacePointsMap const & placePointsMap, - RegionsBuilder::Regions & regions) -{ - RegionsFixerWithPlacePointApproximation fixer(std::move(regions), placePointsMap); - regions = fixer.GetFixedRegions(); -} -} // namespace regions -} // namespace generator diff --git a/generator/regions/regions_fixer.hpp b/generator/regions/regions_fixer.hpp deleted file mode 100644 index 8452c0ecde..0000000000 --- a/generator/regions/regions_fixer.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "generator/regions/place_point.hpp" -#include "generator/regions/regions_builder.hpp" - -#include "base/geo_object_id.hpp" - -#include - -namespace generator -{ -namespace regions -{ -// This function will build a boundary from point based on place. -void FixRegionsWithPlacePointApproximation(PlacePointsMap const & placePointsMap, - RegionsBuilder::Regions & regions); -} // namespace regions -} // namespace generator