diff --git a/coding/point_to_integer.hpp b/coding/point_to_integer.hpp index 068dd65193..afd46b90d6 100644 --- a/coding/point_to_integer.hpp +++ b/coding/point_to_integer.hpp @@ -7,8 +7,6 @@ #define POINT_COORD_BITS 30 -typedef m2::CellId<19> RectId; - m2::PointU PointD2PointU(double x, double y, uint32_t coordBits); inline m2::PointU PointD2PointU(m2::PointD const & pt, uint32_t coordBits) { diff --git a/indexer/cell_id.hpp b/indexer/cell_id.hpp index a0ef68a120..59ca845399 100644 --- a/indexer/cell_id.hpp +++ b/indexer/cell_id.hpp @@ -5,6 +5,10 @@ #include "base/assert.hpp" +using RectId = m2::CellId<19>; + +// 24 is enough to have cell size < 2.5m * 2.5m for world. +using LocalityCellId = m2::CellId<24>; template struct Bounds diff --git a/indexer/feature_covering.cpp b/indexer/feature_covering.cpp index 439b905379..9e8af7c47a 100644 --- a/indexer/feature_covering.cpp +++ b/indexer/feature_covering.cpp @@ -1,17 +1,16 @@ #include "indexer/feature_covering.hpp" -#include "indexer/cell_coverer.hpp" -#include "indexer/cell_id.hpp" #include "indexer/feature.hpp" #include "indexer/locality_object.hpp" -#include "indexer/scales.hpp" #include "geometry/covering_utils.hpp" +using namespace std; + namespace { - // This class should only be used with covering::CoverObject()! +template class FeatureIntersector { public: @@ -30,7 +29,7 @@ public: // 1. Here we don't need to differentiate between CELL_OBJECT_INTERSECT and OBJECT_INSIDE_CELL. // 2. We can return CELL_OBJECT_INTERSECT instead of CELL_INSIDE_OBJECT - it's just // a performance penalty. - covering::CellObjectIntersection operator() (RectId const & cell) const + covering::CellObjectIntersection operator()(m2::CellId const & cell) const { using namespace covering; @@ -91,12 +90,11 @@ public: return CELL_OBJECT_NO_INTERSECTION; } - typedef CellIdConverter CellIdConverterType; + using CellIdConverter = CellIdConverter>; m2::PointD ConvertPoint(m2::PointD const & p) { - m2::PointD const pt(CellIdConverterType::XToCellIdX(p.x), - CellIdConverterType::YToCellIdY(p.y)); + m2::PointD const pt(CellIdConverter::XToCellIdX(p.x), CellIdConverter::YToCellIdY(p.y)); m_rect.Add(pt); return pt; } @@ -112,7 +110,8 @@ public: } }; -void GetIntersection(FeatureType const & f, FeatureIntersector & fIsect) +template +void GetIntersection(FeatureType const & f, FeatureIntersector & fIsect) { // We need to cover feature for the best geometry, because it's indexed once for the // first top level scale. Do reset current cached geometry first. @@ -126,19 +125,22 @@ void GetIntersection(FeatureType const & f, FeatureIntersector & fIsect) f.GetLimitRect(scale).IsValid(), (f.DebugString(scale))); } -vector CoverIntersection(FeatureIntersector const & fIsect, int cellDepth, +template +vector CoverIntersection(FeatureIntersector const & fIsect, int cellDepth, uint64_t cellPenaltyArea) { if (fIsect.m_trg.empty() && fIsect.m_polyline.size() == 1) { m2::PointD const pt = fIsect.m_polyline[0]; return vector( - 1, RectId::FromXY(static_cast(pt.x), static_cast(pt.y), - RectId::DEPTH_LEVELS - 1).ToInt64(cellDepth)); + 1, m2::CellId::FromXY(static_cast(pt.x), + static_cast(pt.y), DEPTH_LEVELS - 1) + .ToInt64(cellDepth)); } - vector cells; - covering::CoverObject(fIsect, cellPenaltyArea, cells, cellDepth, RectId::Root()); + vector> cells; + covering::CoverObject(fIsect, cellPenaltyArea, cells, cellDepth, + m2::CellId::Root()); vector res(cells.size()); for (size_t i = 0; i < cells.size(); ++i) @@ -146,13 +148,13 @@ vector CoverIntersection(FeatureIntersector const & fIsect, int cellDep return res; } -} +} // namespace namespace covering { vector CoverFeature(FeatureType const & f, int cellDepth, uint64_t cellPenaltyArea) { - FeatureIntersector fIsect; + FeatureIntersector fIsect; GetIntersection(f, fIsect); return CoverIntersection(fIsect, cellDepth, cellPenaltyArea); } @@ -160,7 +162,7 @@ vector CoverFeature(FeatureType const & f, int cellDepth, uint64_t cell vector CoverLocality(indexer::LocalityObject const & o, int cellDepth, uint64_t cellPenaltyArea) { - FeatureIntersector fIsect; + FeatureIntersector fIsect; o.ForEachPoint(fIsect); o.ForEachTriangle(fIsect); return CoverIntersection(fIsect, cellDepth, cellPenaltyArea); @@ -192,91 +194,4 @@ Intervals SortAndMergeIntervals(Intervals const & v) SortAndMergeIntervals(v, res); return res; } - -void AppendLowerLevels(RectId id, int cellDepth, Intervals & intervals) -{ - int64_t idInt64 = id.ToInt64(cellDepth); - intervals.push_back(make_pair(idInt64, idInt64 + id.SubTreeSize(cellDepth))); - while (id.Level() > 0) - { - id = id.Parent(); - idInt64 = id.ToInt64(cellDepth); - intervals.push_back(make_pair(idInt64, idInt64 + 1)); - } -} - -void CoverViewportAndAppendLowerLevels(m2::RectD const & r, int cellDepth, Intervals & res) -{ - vector ids; - ids.reserve(SPLIT_RECT_CELLS_COUNT); - CoverRect(r, SPLIT_RECT_CELLS_COUNT, cellDepth, ids); - - Intervals intervals; - for (size_t i = 0; i < ids.size(); ++i) - AppendLowerLevels(ids[i], cellDepth, intervals); - - SortAndMergeIntervals(intervals, res); -} - -RectId GetRectIdAsIs(m2::RectD const & r) -{ - double const eps = MercatorBounds::GetCellID2PointAbsEpsilon(); - using TConverter = CellIdConverter; - - return TConverter::Cover2PointsWithCell( - MercatorBounds::ClampX(r.minX() + eps), - MercatorBounds::ClampY(r.minY() + eps), - MercatorBounds::ClampX(r.maxX() - eps), - MercatorBounds::ClampY(r.maxY() - eps)); -} - -int GetCodingDepth(int scale) -{ - int const delta = scales::GetUpperScale() - scale; - ASSERT_GREATER_OR_EQUAL ( delta, 0, () ); - - return (RectId::DEPTH_LEVELS - delta); -} - -Intervals const & CoveringGetter::Get(int scale) -{ - int const cellDepth = GetCodingDepth(scale); - int const ind = (cellDepth == RectId::DEPTH_LEVELS ? 0 : 1); - - if (m_res[ind].empty()) - { - switch (m_mode) - { - case ViewportWithLowLevels: - CoverViewportAndAppendLowerLevels(m_rect, cellDepth, m_res[ind]); - break; - - case LowLevelsOnly: - { - RectId id = GetRectIdAsIs(m_rect); - while (id.Level() >= cellDepth) - id = id.Parent(); - AppendLowerLevels(id, cellDepth, m_res[ind]); - - // Check for optimal result intervals. -#if 0 - size_t oldSize = m_res[ind].size(); - Intervals res; - SortAndMergeIntervals(m_res[ind], res); - if (res.size() != oldSize) - LOG(LINFO, ("Old =", oldSize, "; New =", res.size())); - res.swap(m_res[ind]); -#endif - break; - } - - case FullCover: - m_res[ind].push_back(Intervals::value_type(0, static_cast((1ULL << 63) - 1))); - break; - } - } - - return m_res[ind]; -} - } diff --git a/indexer/feature_covering.hpp b/indexer/feature_covering.hpp index 3cdca66957..624f13e3b6 100644 --- a/indexer/feature_covering.hpp +++ b/indexer/feature_covering.hpp @@ -1,9 +1,18 @@ #pragma once + +#include "indexer/cell_coverer.hpp" +#include "indexer/cell_id.hpp" +#include "indexer/scales.hpp" + +#include "geometry/mercator.hpp" #include "geometry/rect2d.hpp" #include "coding/point_to_integer.hpp" +#include "base/logging.hpp" + #include +#include #include class FeatureType; @@ -25,19 +34,56 @@ std::vector CoverFeature(FeatureType const & feature, int cellDepth, std::vector CoverLocality(indexer::LocalityObject const & o, int cellDepth, uint64_t cellPenaltyArea); -void AppendLowerLevels(RectId id, int cellDepth, Intervals & intervals); - -// Cover viewport with RectIds and append their RectIds as well. -void CoverViewportAndAppendLowerLevels(m2::RectD const & rect, int cellDepth, - Intervals & intervals); - // Given a vector of intervals [a, b), sort them and merge overlapping intervals. Intervals SortAndMergeIntervals(Intervals const & intervals); +void SortAndMergeIntervals(Intervals v, Intervals & res); -RectId GetRectIdAsIs(m2::RectD const & r); +template +m2::CellId GetRectIdAsIs(m2::RectD const & r) +{ + double const eps = MercatorBounds::GetCellID2PointAbsEpsilon(); + using Converter = CellIdConverter>; + + return Converter::Cover2PointsWithCell( + MercatorBounds::ClampX(r.minX() + eps), MercatorBounds::ClampY(r.minY() + eps), + MercatorBounds::ClampX(r.maxX() - eps), MercatorBounds::ClampY(r.maxY() - eps)); +} // Calculate cell coding depth according to max visual scale for mwm. -int GetCodingDepth(int scale); +template +int GetCodingDepth(int scale) +{ + int const delta = scales::GetUpperScale() - scale; + ASSERT_GREATER_OR_EQUAL(delta, 0, ()); + return DEPTH_LEVELS - delta; +} + +template +void AppendLowerLevels(m2::CellId id, int cellDepth, Intervals & intervals) +{ + int64_t idInt64 = id.ToInt64(cellDepth); + intervals.push_back(std::make_pair(idInt64, idInt64 + id.SubTreeSize(cellDepth))); + while (id.Level() > 0) + { + id = id.Parent(); + idInt64 = id.ToInt64(cellDepth); + intervals.push_back(make_pair(idInt64, idInt64 + 1)); + } +} + +template +void CoverViewportAndAppendLowerLevels(m2::RectD const & r, int cellDepth, Intervals & res) +{ + std::vector> ids; + ids.reserve(SPLIT_RECT_CELLS_COUNT); + CoverRect>(r, SPLIT_RECT_CELLS_COUNT, cellDepth, ids); + + Intervals intervals; + for (auto const & id : ids) + AppendLowerLevels(id, cellDepth, intervals); + + SortAndMergeIntervals(intervals, res); +} enum CoveringMode { @@ -56,6 +102,47 @@ class CoveringGetter public: CoveringGetter(m2::RectD const & r, CoveringMode mode) : m_rect(r), m_mode(mode) {} - Intervals const & Get(int scale); - }; + template + Intervals const & Get(int scale) + { + int const cellDepth = GetCodingDepth(scale); + int const ind = (cellDepth == DEPTH_LEVELS ? 0 : 1); + + if (m_res[ind].empty()) + { + switch (m_mode) + { + case ViewportWithLowLevels: + CoverViewportAndAppendLowerLevels(m_rect, cellDepth, m_res[ind]); + break; + + case LowLevelsOnly: + { + m2::CellId id = GetRectIdAsIs(m_rect); + while (id.Level() >= cellDepth) + id = id.Parent(); + AppendLowerLevels(id, cellDepth, m_res[ind]); + + // Check for optimal result intervals. +#if 0 + size_t oldSize = m_res[ind].size(); + Intervals res; + SortAndMergeIntervals(m_res[ind], res); + if (res.size() != oldSize) + LOG(LINFO, ("Old =", oldSize, "; New =", res.size())); + res.swap(m_res[ind]); +#endif + break; + } + + case FullCover: + m_res[ind].push_back( + Intervals::value_type(0, static_cast((uint64_t{1} << 63) - 1))); + break; + } + } + + return m_res[ind]; + } +}; } diff --git a/indexer/index.hpp b/indexer/index.hpp index d666fb8401..2de961d7f9 100644 --- a/indexer/index.hpp +++ b/indexer/index.hpp @@ -114,7 +114,7 @@ private: scale = lastScale; // Use last coding scale for covering (see index_builder.cpp). - covering::Intervals const & interval = cov.Get(lastScale); + covering::Intervals const & intervals = cov.Get(lastScale); // Prepare features reading. FeaturesVector const fv(pValue->m_cont, header, pValue->m_table.get()); @@ -125,7 +125,7 @@ private: CheckUniqueIndexes checkUnique(header.GetFormat() >= version::Format::v5); MwmId const & mwmID = handle.GetId(); - for (auto const & i : interval) + for (auto const & i : intervals) { index.ForEachInIntervalAndScale( [&](uint32_t index) @@ -186,14 +186,14 @@ private: scale = lastScale; // Use last coding scale for covering (see index_builder.cpp). - covering::Intervals const & interval = cov.Get(lastScale); + covering::Intervals const & intervals = cov.Get(lastScale); ScaleIndex const index(pValue->m_cont.GetReader(INDEX_FILE_TAG), pValue->m_factory); // Iterate through intervals. CheckUniqueIndexes checkUnique(header.GetFormat() >= version::Format::v5); MwmId const & mwmID = handle.GetId(); - for (auto const & i : interval) + for (auto const & i : intervals) { index.ForEachInIntervalAndScale( [&](uint32_t index) diff --git a/indexer/indexer_tests/scale_index_reading_tests.cpp b/indexer/indexer_tests/scale_index_reading_tests.cpp index ce5177ad1a..98c44c1d21 100644 --- a/indexer/indexer_tests/scale_index_reading_tests.cpp +++ b/indexer/indexer_tests/scale_index_reading_tests.cpp @@ -5,6 +5,7 @@ #include "indexer/indexer_tests_support/test_with_custom_mwms.hpp" +#include "indexer/cell_id.hpp" #include "indexer/data_factory.hpp" #include "indexer/data_header.hpp" #include "indexer/feature.hpp" @@ -49,7 +50,7 @@ public: covering::CoveringGetter covering(rect, covering::ViewportWithLowLevels); vector indices; - for (auto const & interval : covering.Get(scale)) + for (auto const & interval : covering.Get(scale)) { index.ForEachInIntervalAndScale([&](uint32_t index) { indices.push_back(index); }, interval.first, interval.second, scale); diff --git a/indexer/locality_index.hpp b/indexer/locality_index.hpp index 9acac6fcb3..d943729b61 100644 --- a/indexer/locality_index.hpp +++ b/indexer/locality_index.hpp @@ -32,7 +32,8 @@ 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) { diff --git a/indexer/locality_index_builder.hpp b/indexer/locality_index_builder.hpp index 3719cac9e8..12700e8b19 100644 --- a/indexer/locality_index_builder.hpp +++ b/indexer/locality_index_builder.hpp @@ -16,6 +16,7 @@ #include "defines.hpp" +#include #include #include @@ -35,8 +36,9 @@ void BuildLocalityIndex(TObjectsVector const & objects, TWriter & writer, 1024 * 1024 /* bufferBytes */, tmpFilePrefix + CELL2LOCALITY_TMP_EXT, out); objects.ForEach([&sorter](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 = covering::CoverLocality( + o, GetCodingDepth(scales::GetUpperScale()), + 250 /* cellPenaltyArea */); for (auto const & cell : cells) sorter.Add(CellValuePair(cell, o.GetStoredId())); }); @@ -48,7 +50,7 @@ void BuildLocalityIndex(TObjectsVector const & objects, TWriter & writer, { BuildIntervalIndex(cellsToValue.begin(), cellsToValue.end(), writer, - RectId::DEPTH_LEVELS * 2 + 1); + LocalityCellId::DEPTH_LEVELS * 2 + 1); } } } // namespace covering diff --git a/indexer/scale_index_builder.hpp b/indexer/scale_index_builder.hpp index 21442d4c12..5629dd25a9 100644 --- a/indexer/scale_index_builder.hpp +++ b/indexer/scale_index_builder.hpp @@ -37,7 +37,7 @@ public: , m_scalesIdx(0) , m_bucketsCount(header.GetLastScale() + 1) , m_displacement(manager) - , m_codingDepth(covering::GetCodingDepth(header.GetLastScale())) + , m_codingDepth(covering::GetCodingDepth(header.GetLastScale())) , m_featuresInBucket(featuresInBucket) , m_cellsInBucket(cellsInBucket) { diff --git a/search/mwm_context.cpp b/search/mwm_context.cpp index 4068f97b60..efcbdd55d5 100644 --- a/search/mwm_context.cpp +++ b/search/mwm_context.cpp @@ -1,11 +1,13 @@ #include "search/mwm_context.hpp" +#include "indexer/cell_id.hpp" + namespace search { void CoverRect(m2::RectD const & rect, int scale, covering::Intervals & result) { covering::CoveringGetter covering(rect, covering::ViewportWithLowLevels); - auto const & intervals = covering.Get(scale); + auto const & intervals = covering.Get(scale); result.insert(result.end(), intervals.begin(), intervals.end()); } diff --git a/search/street_vicinity_loader.cpp b/search/street_vicinity_loader.cpp index 28989355b3..497be99835 100644 --- a/search/street_vicinity_loader.cpp +++ b/search/street_vicinity_loader.cpp @@ -1,11 +1,11 @@ #include "search/street_vicinity_loader.hpp" +#include "indexer/cell_id.hpp" #include "indexer/feature_covering.hpp" #include "indexer/feature_decl.hpp" #include "indexer/index.hpp" #include "geometry/mercator.hpp" - #include "geometry/point2d.hpp" #include "base/math.hpp" @@ -58,7 +58,7 @@ void StreetVicinityLoader::LoadStreet(uint32_t featureId, Street & street) street.m_rect.Add(MercatorBounds::RectByCenterXYAndSizeInMeters(point, m_offsetMeters)); covering::CoveringGetter coveringGetter(street.m_rect, covering::ViewportWithLowLevels); - auto const & intervals = coveringGetter.Get(m_scale); + auto const & intervals = coveringGetter.Get(m_scale); m_context->ForEachIndex(intervals, m_scale, MakeBackInsertFunctor(street.m_features)); street.m_calculator = make_unique(points);