From 97856a84c4c93e43471aaf2ed7b6fb291b4e36c1 Mon Sep 17 00:00:00 2001 From: Maksim Andrianov Date: Tue, 4 Sep 2018 18:55:21 +0300 Subject: [PATCH] [generator] Improved regions --- generator/region_info_collector.hpp | 6 +-- generator/regions.cpp | 82 +++++++++++++++++------------ generator/regions.hpp | 3 +- 3 files changed, 54 insertions(+), 37 deletions(-) diff --git a/generator/region_info_collector.hpp b/generator/region_info_collector.hpp index 4eec64fedd..0983c2ab11 100644 --- a/generator/region_info_collector.hpp +++ b/generator/region_info_collector.hpp @@ -39,9 +39,9 @@ enum class PlaceType: uint8_t City = 9, Town = 10, Village = 11, - Suburb = 12, - Neighbourhood = 13, - Hamlet = 14, + Hamlet = 12, + Suburb = 13, + Neighbourhood = 14, Locality = 15, IsolatedDwelling = 16, }; diff --git a/generator/regions.cpp b/generator/regions.cpp index d3dc3df825..8a20816503 100644 --- a/generator/regions.cpp +++ b/generator/regions.cpp @@ -25,6 +25,7 @@ #include "3party/jansson/myjansson.hpp" #include "3party/ThreadPool/ThreadPool.h" #include "3party/boost/boost/math/special_functions/relative_difference.hpp" +#include "3party/boost/boost/range/adaptor/reversed.hpp" namespace generator { @@ -37,6 +38,11 @@ using MergeFunc = std::function; class JsonPolicy : public ToStringPolicyInterface { public: + JsonPolicy(bool extendedOutput = false) + : m_extendedOutput(extendedOutput) + { + } + std::string ToString(Node::PtrList const & nodePtrList) override { auto const & main = nodePtrList.front()->GetData(); @@ -50,13 +56,21 @@ public: ToJSONObject(*geometry, "coordinates", coordinates); auto address = my::NewJSONObject(); - for (auto const & p : nodePtrList) - ToJSONObject(*address, p->GetData().GetLabel(), p->GetData().GetName()); + for (auto const & p : boost::adaptors::reverse(nodePtrList)) + { + auto const label = p->GetData().GetLabel(); + ToJSONObject(*address, label, p->GetData().GetName()); + if (m_extendedOutput) + { + ToJSONObject(*address, label + "_i", p->GetData().GetId()); + ToJSONObject(*address, label + "_a", p->GetData().GetArea()); + ToJSONObject(*address, label + "_r", p->GetData().GetRank()); + } + } auto properties = my::NewJSONObject(); ToJSONObject(*properties, "name", main.GetName()); ToJSONObject(*properties, "rank", main.GetRank()); - ToJSONObject(*properties, "depth", nodePtrList.size()); ToJSONObject(*properties, "address", address); auto feature = my::NewJSONObject(); @@ -68,22 +82,10 @@ public: std::unique_ptr buffer(cstr); return buffer.get(); } -}; -inline void DebugDumpRegions(std::string const & name, RegionsBuilder::Regions const & regions) -{ - std::ofstream ofs(name, std::ofstream::out); - for (auto const & region : regions) - { - ofs << region.GetName() << "; " << region.GetArea() << "; [(" - << region.GetRect().min_corner().get<0>() << "," - << region.GetRect().min_corner().get<1>() << "), (" - << region.GetRect().max_corner().get<0>() << "," - << region.GetRect().max_corner().get<0>() << ")]; " - << region.GetPolygon()->outer().size() - << std::endl; - } -} +private: + bool m_extendedOutput; +}; // This function is for debugging only and can be used for statistics collection. size_t TreeSize(Node::Ptr node) @@ -280,10 +282,10 @@ Region::Region(FeatureBuilder1 const & fb, RegionData const & rd) m_regionData(rd), m_polygon(std::make_shared()) { + FillPolygon(fb); auto rect = fb.GetLimitRect(); m_rect = BoostRect({{rect.minX(), rect.minY()}, {rect.maxX(), rect.maxY()}}); - m_area = boost::geometry::area(m_rect); - FillPolygon(fb); + m_area = boost::geometry::area(*m_polygon); } std::string Region::GetName(int8_t lang) const @@ -352,10 +354,10 @@ bool Region::ContainsRect(Region const & smaller) const // This is used when calculating the rank. uint8_t Region::GetRank() const { + switch (m_regionData.m_adminLevel) { case AdminLevel::Two: - case AdminLevel::Three: case AdminLevel::Four: return static_cast(m_regionData.m_adminLevel); default: break; } @@ -364,16 +366,14 @@ uint8_t Region::GetRank() const { case PlaceType::City: case PlaceType::Town: - case PlaceType::Village: return static_cast(m_regionData.m_place); + case PlaceType::Village: + case PlaceType::Hamlet: return static_cast(m_regionData.m_place); default: break; } switch (m_regionData.m_adminLevel) { - case AdminLevel::Five: - case AdminLevel::Six: - case AdminLevel::Seven: - case AdminLevel::Eight: return static_cast(m_regionData.m_adminLevel); + case AdminLevel::Six: return static_cast(m_regionData.m_adminLevel); default: break; } @@ -381,7 +381,6 @@ uint8_t Region::GetRank() const { case PlaceType::Suburb: case PlaceType::Neighbourhood: - case PlaceType::Hamlet: case PlaceType::Locality: case PlaceType::IsolatedDwelling: return static_cast(m_regionData.m_place); default: break; @@ -537,7 +536,7 @@ Node::PtrList RegionsBuilder::MakeSelectedRegionsByCountry(Region const & countr auto const comp = [](const Region & l, const Region & r) { auto const lArea = l.GetArea(); - auto const rArea = l.GetArea(); + auto const rArea = r.GetArea(); return lArea != rArea ? lArea > rArea : l.GetRank() < r.GetRank(); }; std::sort(std::begin(regionsInCountry), std::end(regionsInCountry), comp); @@ -570,8 +569,18 @@ Node::Ptr RegionsBuilder::BuildCountryRegionTree(Region const & country, (currRegion.Contains(firstRegion) || currRegion.CalculateOverlapPercentage(firstRegion) > kAvaliableOverlapPercentage)) { - (*itFirstNode)->SetParent(*itCurr); - (*itCurr)->AddChild(*itFirstNode); + // In general, we assume that a region with the larger rank has the larger area. + // But sometimes it does not. In this case, we will make an inversion. + if (firstRegion.GetRank() < currRegion.GetRank()) + { + (*itCurr)->SetParent(*itFirstNode); + (*itFirstNode)->AddChild(*itCurr); + } + else + { + (*itFirstNode)->SetParent(*itCurr); + (*itCurr)->AddChild(*itFirstNode); + } // We want to free up memory. firstRegion.DeletePolygon(); nodes.pop_back(); @@ -620,11 +629,14 @@ bool GenerateRegions(feature::GenerateInfo const & genInfo) RegionInfoCollector regionsInfoCollector(collectorFilename); auto regions = ReadRegionsFromTmpMwm(genInfo, regionsInfoCollector); - auto kvBuilder = std::make_unique(std::move(regions)); + auto jsonPolicy = std::make_unique(genInfo.m_verbose); + auto kvBuilder = std::make_unique(std::move(regions), std::move(jsonPolicy)); auto const countryTrees = kvBuilder->GetCountryTrees(); auto const jsonlName = genInfo.GetIntermediateFileName(genInfo.m_fileName, ".jsonl"); std::ofstream ofs(jsonlName, std::ofstream::out); + std::set setIds; + size_t countIds = 0; for (auto const & countryName : kvBuilder->GetCountryNames()) { auto const keyRange = countryTrees.equal_range(countryName); @@ -641,11 +653,15 @@ bool GenerateRegions(feature::GenerateInfo const & genInfo) auto const idStringList = kvBuilder->ToIdStringList(mergedTree); for (auto const & s : idStringList) { - ofs << base::GeoObjectId(base::GeoObjectId::Type::OsmRelation, s.first).GetEncodedId() - << " " << s.second << std::endl; + auto const id = base::GeoObjectId(base::GeoObjectId::Type::OsmRelation, s.first).GetEncodedId(); + ofs << id << " " << s.second << std::endl; + ++countIds; + if (!setIds.insert(id).second) + LOG(LWARNING, ("Id alredy exists:", id, s.first)); } } + LOG(LINFO, (countIds, "total ids.", setIds.size(), "unique ids.")); LOG(LINFO, ("Finish generating regions.", timer.ElapsedSeconds(), "seconds.")); return true; } diff --git a/generator/regions.hpp b/generator/regions.hpp index 15c52b10b9..d039256ca0 100644 --- a/generator/regions.hpp +++ b/generator/regions.hpp @@ -36,7 +36,6 @@ struct Region explicit Region(FeatureBuilder1 const & fb, RegionData const & rd); - void FillPolygon(FeatureBuilder1 const & fb); void DeletePolygon(); std::string GetName(int8_t lang = StringUtf8Multilang::kDefaultCode) const; bool IsCountry() const; @@ -54,6 +53,8 @@ struct Region uint64_t GetId() const; private: + void FillPolygon(FeatureBuilder1 const & fb); + StringUtf8Multilang m_name; RegionData m_regionData; std::shared_ptr m_polygon;