diff --git a/defines.hpp b/defines.hpp index a7280af864..c9043c3b18 100644 --- a/defines.hpp +++ b/defines.hpp @@ -50,7 +50,8 @@ #define UGC_FILE_TAG "ugc" #define LOCALITY_DATA_FILE_TAG "locdata" -#define LOCALITY_INDEX_FILE_TAG "locidx" +#define GEO_OBJECTS_INDEX_FILE_TAG "locidx" +#define REGIONS_INDEX_FILE_TAG "regidx" #define BORDERS_FILE_TAG "borders" #define READY_FILE_EXTENSION ".ready" diff --git a/generator/generator_tool/generator_tool.cpp b/generator/generator_tool/generator_tool.cpp index ae28923e7f..ac45ecc491 100644 --- a/generator/generator_tool/generator_tool.cpp +++ b/generator/generator_tool/generator_tool.cpp @@ -285,7 +285,7 @@ int main(int argc, char ** argv) LOG(LINFO, ("Saving locality index to", outFile)); - if (!indexer::BuildLocalityIndexFromDataFile(locDataFile, outFile)) + if (!indexer::BuildGeoObjectsIndexFromDataFile(locDataFile, outFile)) { LOG(LCRITICAL, ("Error generating locality index.")); return -1; diff --git a/indexer/cell_id.hpp b/indexer/cell_id.hpp index 8d25e23edc..81c64c0349 100644 --- a/indexer/cell_id.hpp +++ b/indexer/cell_id.hpp @@ -12,7 +12,10 @@ using RectId = m2::CellId<19>; // 24 is enough to have cell size < 2.5m * 2.5m for world. -using LocalityCellId = m2::CellId<24>; +constexpr int kGeoObjectsDepthLevels = 24; + +// Cell size < 40m * 40m for world is good for regions. +constexpr int kRegionsDepthLevels = 20; template class CellIdConverter diff --git a/indexer/feature_covering.cpp b/indexer/feature_covering.cpp index 01dc620006..c20900b1a2 100644 --- a/indexer/feature_covering.cpp +++ b/indexer/feature_covering.cpp @@ -148,6 +148,16 @@ vector CoverIntersection(FeatureIntersector const & fIsec return res; } + +template +vector CoverLocality(indexer::LocalityObject const & o, int cellDepth, + uint64_t cellPenaltyArea) +{ + FeatureIntersector fIsect; + o.ForEachPoint(fIsect); + o.ForEachTriangle(fIsect); + return CoverIntersection(fIsect, cellDepth, cellPenaltyArea); +} } // namespace namespace covering @@ -159,13 +169,16 @@ vector CoverFeature(FeatureType const & f, int cellDepth, uint64_t cell return CoverIntersection(fIsect, cellDepth, cellPenaltyArea); } -vector CoverLocality(indexer::LocalityObject const & o, int cellDepth, - uint64_t cellPenaltyArea) +vector CoverGeoObject(indexer::LocalityObject const & o, int cellDepth, + uint64_t cellPenaltyArea) { - FeatureIntersector fIsect; - o.ForEachPoint(fIsect); - o.ForEachTriangle(fIsect); - return CoverIntersection(fIsect, cellDepth, cellPenaltyArea); + return CoverLocality(o, cellDepth, cellPenaltyArea); +} + +vector CoverRegion(indexer::LocalityObject const & o, int cellDepth, + uint64_t cellPenaltyArea) +{ + return CoverLocality(o, cellDepth, cellPenaltyArea); } void SortAndMergeIntervals(Intervals v, Intervals & res) diff --git a/indexer/feature_covering.hpp b/indexer/feature_covering.hpp index b933613c00..202b911666 100644 --- a/indexer/feature_covering.hpp +++ b/indexer/feature_covering.hpp @@ -31,8 +31,11 @@ typedef std::vector Intervals; std::vector CoverFeature(FeatureType const & feature, int cellDepth, uint64_t cellPenaltyArea); -std::vector CoverLocality(indexer::LocalityObject const & o, int cellDepth, - uint64_t cellPenaltyArea); +std::vector CoverGeoObject(indexer::LocalityObject const & o, int cellDepth, + uint64_t cellPenaltyArea); + +std::vector CoverRegion(indexer::LocalityObject const & o, int cellDepth, + uint64_t cellPenaltyArea); // Given a vector of intervals [a, b), sort them and merge overlapping intervals. Intervals SortAndMergeIntervals(Intervals const & intervals); diff --git a/indexer/indexer_tests/locality_index_test.cpp b/indexer/indexer_tests/locality_index_test.cpp index ce840831e6..291b8ba342 100644 --- a/indexer/indexer_tests/locality_index_test.cpp +++ b/indexer/indexer_tests/locality_index_test.cpp @@ -35,6 +35,18 @@ struct LocalityObjectVector vector m_objects; }; +template +void BuildGeoObjectsIndex(ObjectsVector const & objects, Writer & writer, + string const & tmpFilePrefix) +{ + auto coverLocality = [](indexer::LocalityObject const & o, int cellDepth, + uint64_t cellPenaltyArea) { + return covering::CoverGeoObject(o, cellDepth, cellPenaltyArea); + }; + return covering::BuildLocalityIndex( + objects, writer, coverLocality, tmpFilePrefix); +} + using Ids = set; using RankedIds = vector; @@ -67,10 +79,10 @@ UNIT_TEST(BuildLocalityIndexTest) vector localityIndex; MemWriter> writer(localityIndex); - covering::BuildLocalityIndex(objects, writer, "tmp"); + BuildGeoObjectsIndex(objects, writer, "tmp"); MemReader reader(localityIndex.data(), localityIndex.size()); - indexer::LocalityIndex index(reader); + indexer::GeoObjectsIndex index(reader); TEST_EQUAL(GetIds(index, m2::RectD{-0.5, -0.5, 0.5, 0.5}), (Ids{1}), ()); TEST_EQUAL(GetIds(index, m2::RectD{0.5, -0.5, 1.5, 1.5}), (Ids{2, 3}), ()); @@ -88,10 +100,10 @@ UNIT_TEST(LocalityIndexRankTest) vector localityIndex; MemWriter> writer(localityIndex); - covering::BuildLocalityIndex(objects, writer, "tmp"); + BuildGeoObjectsIndex(objects, writer, "tmp"); MemReader reader(localityIndex.data(), localityIndex.size()); - indexer::LocalityIndex index(reader); + indexer::GeoObjectsIndex index(reader); TEST_EQUAL(GetRankedIds(index, m2::PointD{1, 0} /* center */, m2::PointD{4, 0} /* border */, 4 /* topSize */), (vector{1, 2, 3, 4}), ()); @@ -120,10 +132,10 @@ UNIT_TEST(LocalityIndexTopSizeTest) vector localityIndex; MemWriter> writer(localityIndex); - covering::BuildLocalityIndex(objects, writer, "tmp"); + BuildGeoObjectsIndex(objects, writer, "tmp"); MemReader reader(localityIndex.data(), localityIndex.size()); - indexer::LocalityIndex index(reader); + indexer::GeoObjectsIndex index(reader); TEST_EQUAL(GetRankedIds(index, m2::PointD{1, 0} /* center */, m2::PointD{0, 0} /* border */, 4 /* topSize */) .size(), diff --git a/indexer/locality_index.hpp b/indexer/locality_index.hpp index 327bf04c34..18a58b743e 100644 --- a/indexer/locality_index.hpp +++ b/indexer/locality_index.hpp @@ -20,7 +20,7 @@ namespace indexer // Geometry index which stores osm::Id as object identifier. // Used for geocoder server, stores only POIs and buildings which have address information. // Based on IntervalIndex. -template +template class LocalityIndex { public: @@ -34,8 +34,7 @@ public: void ForEachInRect(ProcessObject const & processObject, m2::RectD const & rect) const { covering::CoveringGetter cov(rect, covering::CoveringMode::ViewportWithLowLevels); - covering::Intervals const & intervals = - cov.Get(scales::GetUpperScale()); + covering::Intervals const & intervals = cov.Get(scales::GetUpperScale()); for (auto const & i : intervals) { @@ -55,8 +54,7 @@ public: auto const rect = MercatorBounds::RectByCenterXYAndSizeInMeters(center, sizeM); covering::CoveringGetter cov(rect, covering::CoveringMode::Spiral); - covering::Intervals const & intervals = - cov.Get(scales::GetUpperScale()); + covering::Intervals const & intervals = cov.Get(scales::GetUpperScale()); std::set objects; auto process = [topSize, &objects, &processObject](uint64_t storedId) { @@ -75,4 +73,10 @@ public: private: std::unique_ptr> m_intervalIndex; }; + +template +using GeoObjectsIndex = LocalityIndex; + +template +using RegionsIndex = LocalityIndex; } // namespace indexer diff --git a/indexer/locality_index_builder.cpp b/indexer/locality_index_builder.cpp index 784676cdef..163665edc3 100644 --- a/indexer/locality_index_builder.cpp +++ b/indexer/locality_index_builder.cpp @@ -13,13 +13,13 @@ namespace indexer { namespace { -template +template class LocalityVector { DISALLOW_COPY(LocalityVector); public: - LocalityVector(ReaderT const & reader) : m_recordReader(reader, 256 /* expectedRecordSize */) {} + LocalityVector(Reader const & reader) : m_recordReader(reader, 256 /* expectedRecordSize */) {} template void ForEach(ToDo && toDo) const @@ -55,9 +55,12 @@ private: FilesContainerR m_cont; LocalityVector m_vector; }; -} // namespace -bool BuildLocalityIndexFromDataFile(string const & dataFile, string const & outFileName) +template +bool BuildLocalityIndexFromDataFile(string const & dataFile, + covering::CoverLocality const & coverLocality, + string const & outFileName, + string const & localityIndexFileTag) { try { @@ -66,11 +69,12 @@ bool BuildLocalityIndexFromDataFile(string const & dataFile, string const & outF LocalityVectorReader localities(dataFile); FileWriter writer(idxFileName); - covering::BuildLocalityIndex(localities.GetVector(), writer, outFileName); + covering::BuildLocalityIndex, FileWriter, DEPTH_LEVELS>( + localities.GetVector(), writer, coverLocality, outFileName); } FilesContainerW(outFileName, FileWriter::OP_WRITE_TRUNCATE) - .Write(idxFileName, LOCALITY_INDEX_FILE_TAG); + .Write(idxFileName, localityIndexFileTag); FileWriter::DeleteFileX(idxFileName); } catch (Reader::Exception const & e) @@ -85,4 +89,25 @@ bool BuildLocalityIndexFromDataFile(string const & dataFile, string const & outF } return true; } +} // namespace + +bool BuildGeoObjectsIndexFromDataFile(string const & dataFile, string const & outFileName) +{ + auto coverObject = [](indexer::LocalityObject const & o, int cellDepth, + uint64_t cellPenaltyArea) { + return covering::CoverGeoObject(o, cellDepth, cellPenaltyArea); + }; + return BuildLocalityIndexFromDataFile(dataFile, coverObject, outFileName, + GEO_OBJECTS_INDEX_FILE_TAG); +} + +bool BuildRegionsIndexFromDataFile(string const & dataFile, string const & outFileName) +{ + auto coverRegion = [](indexer::LocalityObject const & o, int cellDepth, + uint64_t cellPenaltyArea) { + return covering::CoverRegion(o, cellDepth, cellPenaltyArea); + }; + return BuildLocalityIndexFromDataFile(dataFile, coverRegion, outFileName, + REGIONS_INDEX_FILE_TAG); +} } // namespace indexer diff --git a/indexer/locality_index_builder.hpp b/indexer/locality_index_builder.hpp index 12700e8b19..d766c40dad 100644 --- a/indexer/locality_index_builder.hpp +++ b/indexer/locality_index_builder.hpp @@ -17,14 +17,18 @@ #include "defines.hpp" #include +#include #include #include namespace covering { -template -void BuildLocalityIndex(TObjectsVector const & objects, TWriter & writer, - string const & tmpFilePrefix) +using CoverLocality = std::function(indexer::LocalityObject const & o, + int cellDepth, uint64_t cellPenaltyArea)>; + +template +void BuildLocalityIndex(ObjectsVector const & objects, Writer & writer, + CoverLocality const & coverLocality, string const & tmpFilePrefix) { string const cellsToValueFile = tmpFilePrefix + CELL2LOCALITY_SORTED_EXT + ".all"; MY_SCOPE_GUARD(cellsToValueFileGuard, bind(&FileWriter::DeleteFileX, cellsToValueFile)); @@ -34,11 +38,10 @@ void BuildLocalityIndex(TObjectsVector const & objects, TWriter & writer, WriterFunctor out(cellsToValueWriter); FileSorter, WriterFunctor> sorter( 1024 * 1024 /* bufferBytes */, tmpFilePrefix + CELL2LOCALITY_TMP_EXT, out); - objects.ForEach([&sorter](indexer::LocalityObject const & o) { + objects.ForEach([&sorter, &coverLocality](indexer::LocalityObject const & o) { // @todo(t.yan): adjust cellPenaltyArea for whole world locality index. - std::vector const cells = covering::CoverLocality( - o, GetCodingDepth(scales::GetUpperScale()), - 250 /* cellPenaltyArea */); + std::vector const cells = coverLocality( + o, GetCodingDepth(scales::GetUpperScale()), 250 /* cellPenaltyArea */); for (auto const & cell : cells) sorter.Add(CellValuePair(cell, o.GetStoredId())); }); @@ -49,13 +52,18 @@ void BuildLocalityIndex(TObjectsVector const & objects, TWriter & writer, DDVector, FileReader, uint64_t> cellsToValue(reader); { - BuildIntervalIndex(cellsToValue.begin(), cellsToValue.end(), writer, - LocalityCellId::DEPTH_LEVELS * 2 + 1); + BuildIntervalIndex(cellsToValue.begin(), cellsToValue.end(), writer, DEPTH_LEVELS * 2 + 1); } } } // namespace covering namespace indexer { -bool BuildLocalityIndexFromDataFile(std::string const & dataFile, std::string const & tmpFile); +// Builds indexer::GeoObjectsIndex for reverse geocoder with |kGeoObjectsDepthLevels| depth levels +// and saves it to |GEO_OBJECTS_INDEX_FILE_TAG| of |out|. +bool BuildGeoObjectsIndexFromDataFile(std::string const & dataFile, std::string const & out); + +// Builds indexer::RegionsIndex for reverse geocoder with |kRegionsDepthLevels| depth levels and +// saves it to |REGIONS_INDEX_FILE_TAG| of |out|. +bool BuildRegionsIndexFromDataFile(std::string const & dataFile, std::string const & out); } // namespace indexer