#pragma once #include "indexer/cell_coverer.hpp" #include "indexer/cell_id.hpp" #include "indexer/scales.hpp" #include "geometry/cellid.hpp" #include "geometry/mercator.hpp" #include "geometry/rect2d.hpp" #include "base/logging.hpp" #include #include #include #include class FeatureType; namespace indexer { class LocalityObject; } // namespace indexer namespace covering { typedef std::pair Interval; typedef std::vector Intervals; // Cover feature with RectIds and return their integer representations. std::vector CoverFeature(FeatureType const & feature, 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); void SortAndMergeIntervals(Intervals v, Intervals & res); 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. 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, ToDo const & toDo) { int64_t idInt64 = id.ToInt64(cellDepth); toDo(std::make_pair(idInt64, idInt64 + id.SubTreeSize(cellDepth))); while (id.Level() > 0) { id = id.Parent(); idInt64 = id.ToInt64(cellDepth); toDo(std::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](Interval const & interval) { intervals.push_back(interval); }); } SortAndMergeIntervals(intervals, res); } enum CoveringMode { ViewportWithLowLevels = 0, LowLevelsOnly, FullCover, Spiral }; class CoveringGetter { Intervals m_res[2]; m2::RectD const & m_rect; CoveringMode m_mode; public: CoveringGetter(m2::RectD const & r, CoveringMode mode) : m_rect(r), m_mode(mode) {} 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, [this, ind](Interval const & interval) { m_res[ind].push_back(interval); }); // 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; case Spiral: { std::vector> ids; CoverSpiral>(m_rect, cellDepth, ids); std::set uniqueIds; auto insertInterval = [this, ind, &uniqueIds](Interval const & interval) { if (uniqueIds.insert(interval).second) m_res[ind].push_back(interval); }; for (auto const & id : ids) AppendLowerLevels(id, cellDepth, insertInterval); } } } return m_res[ind]; } }; }