diff options
Diffstat (limited to 'search/nested_rects_cache.cpp')
-rw-r--r-- | search/nested_rects_cache.cpp | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/search/nested_rects_cache.cpp b/search/nested_rects_cache.cpp new file mode 100644 index 0000000000..07c5ae68ce --- /dev/null +++ b/search/nested_rects_cache.cpp @@ -0,0 +1,102 @@ +#include "search/nested_rects_cache.hpp" + +#include "search/ranking_info.hpp" + +#include "indexer/index.hpp" + +#include "geometry/mercator.hpp" +#include "geometry/rect2d.hpp" + +#include "base/assert.hpp" +#include "base/stl_add.hpp" + +#include "std/algorithm.hpp" + +namespace search +{ +namespace +{ +double const kPositionToleranceMeters = 15.0; +} // namespace + +NestedRectsCache::NestedRectsCache(Index & index) + : m_index(index), m_scale(0), m_position(0, 0), m_valid(false) +{ +} + +void NestedRectsCache::SetPosition(m2::PointD const & position, int scale) +{ + double distance = MercatorBounds::DistanceOnEarth(position, m_position); + if (distance < kPositionToleranceMeters && scale == m_scale && m_valid) + return; + m_position = position; + m_scale = scale; + Update(); +} + +double NestedRectsCache::GetDistanceToFeatureMeters(FeatureID const & id) const +{ + if (!m_valid) + return RankingInfo::kMaxDistMeters; + + size_t bucket = 0; + for (; bucket != RECT_SCALE_COUNT; ++bucket) + { + if (binary_search(m_features[bucket].begin(), m_features[bucket].end(), id)) + break; + } + auto const scale = static_cast<RectScale>(bucket); + + if (scale != RECT_SCALE_COUNT) + return GetRadiusMeters(scale); + + if (auto const & info = id.m_mwmId.GetInfo()) + { + auto const & rect = info->m_limitRect; + return max(MercatorBounds::DistanceOnEarth(rect.Center(), m_position), GetRadiusMeters(scale)); + } + + return RankingInfo::kMaxDistMeters; +} + +void NestedRectsCache::Clear() +{ + for (int scale = 0; scale != RECT_SCALE_COUNT; ++scale) + { + m_features[scale].clear(); + m_features[scale].shrink_to_fit(); + } + m_valid = false; +} + +// static +double NestedRectsCache::GetRadiusMeters(RectScale scale) +{ + switch (scale) + { + case RECT_SCALE_TINY: return 100.0; + case RECT_SCALE_SMALL: return 300.0; + case RECT_SCALE_MEDIUM: return 1000.0; + case RECT_SCALE_LARGE: return 2500.0; + case RECT_SCALE_COUNT: return 5000.0; + } +} + +void NestedRectsCache::Update() +{ + for (int scale = 0; scale != RECT_SCALE_COUNT; ++scale) + { + auto & features = m_features[scale]; + + features.clear(); + m2::RectD const rect = MercatorBounds::RectByCenterXYAndSizeInMeters( + m_position, GetRadiusMeters(static_cast<RectScale>(scale))); + auto addId = MakeBackInsertFunctor(features); + m_index.ForEachFeatureIDInRect(addId, rect, m_scale); + sort(features.begin(), features.end()); + } + + m_valid = true; +} + +} // namespace search |