diff --git a/generator/generator_tests_support/test_mwm_builder.cpp b/generator/generator_tests_support/test_mwm_builder.cpp index cef3de94b0..c398bfd126 100644 --- a/generator/generator_tests_support/test_mwm_builder.cpp +++ b/generator/generator_tests_support/test_mwm_builder.cpp @@ -150,7 +150,10 @@ void TestMwmBuilder::Finish() CHECK(indexer::BuildIndexFromDataFile(path, path), ("Can't build geometry index.")); - CHECK(BuildPostcodesSection(path), ("Can't build postcodes section.")); + // We do not have boundaryPostcodesFilename because we do not have osm elements stage. + CHECK(BuildPostcodesSection(m_file.GetDirectory(), m_file.GetCountryName(), + "" /* boundaryPostcodesFilename */), + ("Can't build postcodes section.")); CHECK(indexer::BuildSearchIndexFromDataFile(m_file.GetDirectory(), m_file.GetCountryName(), true /* forceRebuild */, 1 /* threadsCount */), diff --git a/generator/generator_tool/generator_tool.cpp b/generator/generator_tool/generator_tool.cpp index 4ab04e316b..ed3b398ff4 100644 --- a/generator/generator_tool/generator_tool.cpp +++ b/generator/generator_tool/generator_tool.cpp @@ -345,7 +345,9 @@ MAIN_WITH_ERROR_HANDLING([](int argc, char ** argv) if (!feature::BuildOffsetsTable(datFile)) continue; - if (!BuildPostcodesSection(datFile)) + auto const boundaryPostcodesFilename = + genInfo.GetIntermediateFileName(BOUNDARY_POSTCODE_TMP_FILENAME); + if (!BuildPostcodesSection(path, country, boundaryPostcodesFilename)) LOG(LCRITICAL, ("Error generating postcodes section.")); if (mapType == MapType::Country) diff --git a/generator/postcodes_section_builder.cpp b/generator/postcodes_section_builder.cpp index cccc8d8ee0..73523b89ff 100644 --- a/generator/postcodes_section_builder.cpp +++ b/generator/postcodes_section_builder.cpp @@ -2,8 +2,9 @@ #include "generator/gen_mwm_info.hpp" -#include "indexer/feature_meta.hpp" +#include "indexer/feature_algo.hpp" #include "indexer/feature_processor.hpp" +#include "indexer/ftypes_matcher.hpp" #include "indexer/postcodes.hpp" #include "platform/platform.hpp" @@ -11,40 +12,97 @@ #include "coding/files_container.hpp" #include "coding/reader.hpp" +#include "geometry/point2d.hpp" +#include "geometry/region2d.hpp" +#include "geometry/tree4d.hpp" + #include "base/checked_cast.hpp" +#include "base/file_name_utils.hpp" #include +#include #include #include "defines.hpp" namespace generator { -bool BuildPostcodesSection(std::string const & mwmFile) +bool BuildPostcodesSection(std::string const & path, std::string const & country, + std::string const & boundaryPostcodesFilename) { LOG(LINFO, ("Building the Postcodes section")); - FileReader reader(mwmFile + TEMP_ADDR_FILENAME); - ReaderSource src(reader); std::vector addrs; - while (src.Size() > 0) { - addrs.push_back({}); - addrs.back().Deserialize(src); + auto const addrFile = base::JoinPath(path, country + DATA_FILE_EXTENSION + TEMP_ADDR_FILENAME); + FileReader reader(addrFile); + ReaderSource src(reader); + while (src.Size() > 0) + { + addrs.push_back({}); + addrs.back().Deserialize(src); + } } auto const featuresCount = base::checked_cast(addrs.size()); + std::vector> boundaryPostcodes; + m4::Tree boundariesTree; + + // May be empty for tests because TestMwmBuilder cannot collect data from osm elements. + if (!boundaryPostcodesFilename.empty()) + { + FileReader reader(boundaryPostcodesFilename); + ReaderSource src(reader); + + while (src.Size() > 0) + { + std::string postcode; + utils::ReadString(src, postcode); + std::vector geometry; + rw::ReadVectorOfPOD(src, geometry); + boundaryPostcodes.emplace_back(std::move(postcode), std::move(geometry)); + boundariesTree.Add(boundaryPostcodes.size() - 1, boundaryPostcodes.back().second.GetRect()); + } + } + indexer::PostcodesBuilder builder; bool havePostcodes = false; - feature::ForEachFromDat(mwmFile, [&](FeatureType const & f, uint32_t featureId) { + auto const mwmFile = base::JoinPath(path, country + DATA_FILE_EXTENSION); + feature::ForEachFromDat(mwmFile, [&](FeatureType & f, uint32_t featureId) { CHECK_LESS(featureId, featuresCount, ()); auto const postcode = addrs[featureId].Get(feature::AddressData::Type::Postcode); - if (postcode.empty()) + if (!postcode.empty()) + { + havePostcodes = true; + builder.Put(featureId, postcode); + return; + } + + if (!ftypes::IsAddressObjectChecker::Instance()(f)) return; - havePostcodes = true; - builder.Put(featureId, postcode); + std::string name; + f.GetReadableName(name); + + auto const houseNumber = f.GetHouseNumber(); + + // We do not save postcodes for unnamed features without house number to reduce amount of data. + // For example with this filter we have +100Kb for Turkey_Marmara Region_Istanbul.mwm, without + // filter we have +3Mb because of huge amount of unnamed houses without number. + if (name.empty() && houseNumber.empty()) + return; + + auto const center = feature::GetCenter(f); + boundariesTree.ForAnyInRect(m2::RectD(center, center), [&](size_t i) { + CHECK_LESS(i, boundaryPostcodes.size(), ()); + if (!boundaryPostcodes[i].second.Contains(center)) + return false; + + havePostcodes = true; + builder.Put(featureId, boundaryPostcodes[i].first); + return true; + }); }); if (!havePostcodes) diff --git a/generator/postcodes_section_builder.hpp b/generator/postcodes_section_builder.hpp index 6ab0b8bb82..2537d7640b 100644 --- a/generator/postcodes_section_builder.hpp +++ b/generator/postcodes_section_builder.hpp @@ -4,5 +4,6 @@ namespace generator { -bool BuildPostcodesSection(std::string const & mwmFile); +bool BuildPostcodesSection(std::string const & path, std::string const & country, + std::string const & boundaryPostcodesFilename); } // namespace generator