From 88f2db2e930cd599669953aa1d351365274395d8 Mon Sep 17 00:00:00 2001 From: vng Date: Wed, 15 Feb 2012 15:58:33 +0300 Subject: [PATCH] [search] Do search in viewport-rect and NearMe-rect in default mode. Don't search in World in "NearMe" mode. --- iphone/Maps/Classes/SearchVC.mm | 9 +- map/framework.cpp | 4 +- map/framework.hpp | 2 +- search/search_engine.cpp | 79 ++++++++++-------- search/search_engine.hpp | 6 +- search/search_query.cpp | 141 +++++++++++++++++++------------- search/search_query.hpp | 26 ++++-- 7 files changed, 162 insertions(+), 105 deletions(-) diff --git a/iphone/Maps/Classes/SearchVC.mm b/iphone/Maps/Classes/SearchVC.mm index e18a1461de..0ff486081b 100644 --- a/iphone/Maps/Classes/SearchVC.mm +++ b/iphone/Maps/Classes/SearchVC.mm @@ -120,19 +120,18 @@ static void OnSearchResultCallback(search::Results const & res, int queryId) m_framework = framework; m_locationManager = lm; - // get current location if needed - bool radarMode = false; - Settings::Get(RADAR_MODE_SETTINGS_KEY, radarMode); + // get current location CLLocation * l = m_locationManager.lastLocation; double lat, lon; - if (radarMode && [SearchVC isLocationValid:l]) + bool const hasPt = [SearchVC isLocationValid:l]; + if (hasPt) { lat = l.coordinate.latitude; lon = l.coordinate.longitude; } - m_framework->PrepareSearch(radarMode, lat, lon); + m_framework->PrepareSearch(hasPt, lat, lon); } return self; } diff --git a/map/framework.cpp b/map/framework.cpp index bef181da6d..4916b39408 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -682,9 +682,9 @@ search::Engine * Framework::GetSearchEngine() return m_pSearchEngine.get(); } -void Framework::PrepareSearch(bool nearMe, double lat, double lon) +void Framework::PrepareSearch(bool hasPt, double lat, double lon) { - GetSearchEngine()->PrepareSearch(GetCurrentViewport(), nearMe, lat, lon); + GetSearchEngine()->PrepareSearch(GetCurrentViewport(), hasPt, lat, lon); } void Framework::Search(search::SearchParams const & params) diff --git a/map/framework.hpp b/map/framework.hpp index 98b8b1e59d..dba690a43b 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -142,7 +142,7 @@ private: inline m2::RectD GetCurrentViewport() const { return m_navigator.Screen().ClipRect(); } search::Engine * GetSearchEngine(); public: - void PrepareSearch(bool nearMe, double lat = 0.0, double lon = 0.0); + void PrepareSearch(bool hasPt, double lat = 0.0, double lon = 0.0); void Search(search::SearchParams const & params); bool GetCurrentPosition(double & lat, double & lon); diff --git a/search/search_engine.cpp b/search/search_engine.cpp index c7aa7ac5cd..47f70ac5bb 100644 --- a/search/search_engine.cpp +++ b/search/search_engine.cpp @@ -7,6 +7,7 @@ #include "../indexer/categories_holder.hpp" #include "../indexer/search_string_utils.hpp" #include "../indexer/mercator.hpp" +#include "../indexer/scales.hpp" #include "../platform/platform.hpp" @@ -94,14 +95,30 @@ namespace { return MercatorBounds::MetresToXY(lon, lat, radius); } + + /// Check rects for optimal search (avoid duplicating). + void AnalizeRects(m2::RectD arrRects[2]) + { + if (arrRects[1].IsRectInside(arrRects[0])) + arrRects[0].MakeEmpty(); + else + { + if (arrRects[0].IsRectInside(arrRects[1]) && + scales::GetScaleLevel(arrRects[0]) + Query::m_scaleDepthSearch >= scales::GetUpperScale()) + { + arrRects[1].MakeEmpty(); + } + } + } } -void Engine::PrepareSearch(m2::RectD const & viewport, bool nearMe, - double lat, double lon) +void Engine::PrepareSearch(m2::RectD const & viewport, + bool hasPt, double lat, double lon) { - // bind does copy of viewport - m2::RectD const r = (nearMe ? GetViewportRect(lat, lon) : viewport); - GetPlatform().RunAsync(bind(&Engine::SetViewportAsync, this, r)); + m2::RectD const nearby = (hasPt ? GetViewportRect(lat, lon) : m2::RectD()); + + // bind does copy of all rects + GetPlatform().RunAsync(bind(&Engine::SetViewportAsync, this, viewport, nearby)); } void Engine::Search(SearchParams const & params, m2::RectD const & viewport) @@ -118,7 +135,7 @@ void Engine::Search(SearchParams const & params, m2::RectD const & viewport) p.RunAsync(bind(&Engine::SearchAsync, this)); } -void Engine::SetViewportAsync(m2::RectD const & viewport) +void Engine::SetViewportAsync(m2::RectD const & viewport, m2::RectD const & nearby) { // First of all - cancel previous query. m_pQuery->DoCancel(); @@ -126,7 +143,10 @@ void Engine::SetViewportAsync(m2::RectD const & viewport) // Enter to run new search. threads::MutexGuard searchGuard(m_searchMutex); - m_pQuery->SetViewport(viewport); + m2::RectD arrRects[] = { viewport, nearby }; + AnalizeRects(arrRects); + + m_pQuery->SetViewport(arrRects, ARRAY_SIZE(arrRects)); } void Engine::SearchAsync() @@ -139,52 +159,47 @@ void Engine::SearchAsync() // Get current search params. SearchParams params; - m2::RectD viewport; + m2::RectD arrRects[2]; { threads::MutexGuard updateGuard(m_updateMutex); params = m_params; - viewport = m_viewport; + arrRects[0] = m_viewport; } // Initialize query. - bool const nearMe = params.IsNearMeMode(); - if (nearMe) - m_pQuery->SetViewport(GetViewportRect(params.m_lat, params.m_lon)); - else - m_pQuery->SetViewport(viewport); - + bool worldSearch = true; if (params.m_validPos) + { m_pQuery->SetPosition(GetViewportXY(params.m_lat, params.m_lon)); + + arrRects[1] = GetViewportRect(params.m_lat, params.m_lon); + + // Do not search in viewport for "NearMe" mode. + if (params.IsNearMeMode()) + { + worldSearch = false; + arrRects[0].MakeEmpty(); + } + else + AnalizeRects(arrRects); + } else m_pQuery->NullPosition(); - unsigned int const resultsNeeded = 10; + m_pQuery->SetViewport(arrRects, 2); + m_pQuery->SetSearchInWorld(worldSearch); + Results res; - // Run first search with needed params. try { - m_pQuery->Search(params.m_query, res, resultsNeeded); + m_pQuery->Search(params.m_query, res); } catch (Query::CancelException const &) { } - // If not enough results, run second search with "Near Me" viewport. - if (!m_pQuery->IsCanceled() && !nearMe && params.m_validPos && (res.Count() < resultsNeeded)) - { - m_pQuery->SetViewport(GetViewportRect(params.m_lat, params.m_lon)); - - try - { - m_pQuery->Search(params.m_query, res, resultsNeeded); - } - catch (Query::CancelException const &) - { - } - } - // Emit results in any way, even if search was canceled. params.m_callback(res); } diff --git a/search/search_engine.hpp b/search/search_engine.hpp index e136dc1465..8c0abc0357 100644 --- a/search/search_engine.hpp +++ b/search/search_engine.hpp @@ -36,14 +36,14 @@ public: string const & lang); ~Engine(); - void PrepareSearch(m2::RectD const & viewport, bool nearMe, - double lat, double lon); + void PrepareSearch(m2::RectD const & viewport, + bool hasPt, double lat, double lon); void Search(SearchParams const & params, m2::RectD const & viewport); string GetCountryFile(m2::PointD const & pt) const; private: - void SetViewportAsync(m2::RectD const & viewport); + void SetViewportAsync(m2::RectD const & viewport, m2::RectD const & nearby); void SearchAsync(); threads::Mutex m_searchMutex, m_updateMutex; diff --git a/search/search_query.cpp b/search/search_query.cpp index 3f9718c1d8..ed86e66d40 100644 --- a/search/search_query.cpp +++ b/search/search_query.cpp @@ -35,10 +35,11 @@ Query::Query(Index const * pIndex, m_pStringsToSuggest(pStringsToSuggest), m_pInfoGetter(pInfoGetter), m_currentLang(StringUtf8Multilang::GetLangIndex("en")), - m_viewport(m2::RectD::GetEmptyRect()), m_viewportExtended(m2::RectD::GetEmptyRect()), - m_position(empty_pos_value, empty_pos_value), - m_bOffsetsCacheIsValid(false) + m_position(empty_pos_value, empty_pos_value) { + // m_viewport, m_viewportExtended are initialized as empty rects + + ASSERT ( m_pIndex, () ); } Query::~Query() @@ -47,9 +48,9 @@ Query::~Query() namespace { - inline bool IsEqual(m2::RectD const & r1, m2::RectD const & r2, double eps) + inline bool IsEqualMercator(m2::RectD const & r1, m2::RectD const & r2, double epsMeters) { - eps = eps * MercatorBounds::degreeInMetres; + double const eps = epsMeters * MercatorBounds::degreeInMetres; m2::RectD r = r1; r.Inflate(eps, eps); @@ -63,17 +64,26 @@ namespace } } -void Query::SetViewport(m2::RectD const & viewport) +void Query::SetViewport(m2::RectD viewport[], size_t count) { - // Check if viewports are equal. - // 10.0 - is 10 meters - if (!m_bOffsetsCacheIsValid || !IsEqual(m_viewport, viewport, 10.0)) - { - m_viewport = viewport; - m_viewportExtended = m_viewport; - m_viewportExtended.Scale(3); + ASSERT_LESS_OR_EQUAL(count, m_rectsCount, ()); - UpdateViewportOffsets(); + for (size_t i = 0; i < count; ++i) + { + if (viewport[i].IsValid()) + { + // Check if viewports are equal (10 meters). + if (!m_viewport[i].IsValid() || !IsEqualMercator(m_viewport[i], viewport[i], 10.0)) + { + m_viewport[i] = viewport[i]; + m_viewportExtended[i] = m_viewport[i]; + m_viewportExtended[i].Scale(3); + + UpdateViewportOffsets(i); + } + } + else + ClearCache(i); } } @@ -84,25 +94,32 @@ void Query::SetPreferredLanguage(string const & lang) void Query::ClearCache() { - m_offsetsInViewport.clear(); - m_bOffsetsCacheIsValid = false; + for (size_t i = 0; i < m_rectsCount; ++i) + ClearCache(i); } -void Query::UpdateViewportOffsets() +void Query::ClearCache(size_t ind) { - m_offsetsInViewport.clear(); + m_offsetsInViewport[ind].clear(); + m_viewport[ind].MakeEmpty(); + m_viewportExtended[ind].MakeEmpty(); +} + +void Query::UpdateViewportOffsets(size_t ind) +{ + m_offsetsInViewport[ind].clear(); vector mwmInfo; m_pIndex->GetMwmInfo(mwmInfo); - m_offsetsInViewport.resize(mwmInfo.size()); + m_offsetsInViewport[ind].resize(mwmInfo.size()); - int const viewScale = scales::GetScaleLevel(m_viewport); - covering::CoveringGetter cov(m_viewport, 0); + int const viewScale = scales::GetScaleLevel(m_viewport[ind]); + covering::CoveringGetter cov(m_viewport[ind], 0); for (MwmSet::MwmId mwmId = 0; mwmId < mwmInfo.size(); ++mwmId) { // Search only mwms that intersect with viewport (world always does). - if (m_viewportExtended.IsIntersect(mwmInfo[mwmId].m_limitRect)) + if (m_viewportExtended[ind].IsIntersect(mwmInfo[mwmId].m_limitRect)) { Index::MwmLock mwmLock(*m_pIndex, mwmId); if (MwmValue * pMwm = mwmLock.GetValue()) @@ -111,7 +128,7 @@ void Query::UpdateViewportOffsets() if (header.GetType() == feature::DataHeader::country) { pair const scaleR = header.GetScaleRange(); - int const scale = min(max(viewScale + 7, scaleR.first), scaleR.second); + int const scale = min(max(viewScale + m_scaleDepthSearch, scaleR.first), scaleR.second); covering::IntervalsT const & interval = cov.Get(header.GetLastScale()); @@ -120,23 +137,21 @@ void Query::UpdateViewportOffsets() for (size_t i = 0; i < interval.size(); ++i) { - index.ForEachInIntervalAndScale(MakeBackInsertFunctor(m_offsetsInViewport[mwmId]), + index.ForEachInIntervalAndScale(MakeBackInsertFunctor(m_offsetsInViewport[ind][mwmId]), interval[i].first, interval[i].second, scale); } - sort(m_offsetsInViewport[mwmId].begin(), m_offsetsInViewport[mwmId].end()); + sort(m_offsetsInViewport[ind][mwmId].begin(), m_offsetsInViewport[ind][mwmId].end()); } } } } - m_bOffsetsCacheIsValid = true; - #ifdef DEBUG size_t offsetsCached = 0; for (MwmSet::MwmId mwmId = 0; mwmId < mwmInfo.size(); ++mwmId) - offsetsCached += m_offsetsInViewport[mwmId].size(); + offsetsCached += m_offsetsInViewport[ind][mwmId].size(); LOG(LDEBUG, ("For search in viewport cached ", "mwms:", mwmInfo.size(), @@ -210,7 +225,7 @@ void Query::Search(string const & query, Results & res, unsigned int resultsNeed if (search::MatchLatLon(m_rawQuery, lat, lon, latPrec, lonPrec)) { //double const precision = 5.0 * max(0.0001, min(latPrec, lonPrec)); // Min 55 meters - res.AddResult(impl::PreResult2(m_viewport, m_position, lat, lon). + res.AddResult(impl::PreResult2(GetViewport(), m_position, lat, lon). GenerateFinalResult(m_pInfoGetter, m_pCategories, m_currentLang)); } } @@ -387,21 +402,21 @@ void Query::FlushResults(Results & res) { typedef impl::PreResult2 ResultT; - /* - #ifdef DEBUG - { - impl::PreResult2Maker maker(*this); - LOG(LDEBUG, ("Dump features for rank:")); - for (QueueT::const_iterator i = m_results[0].begin(); i != m_results[0].end(); ++i) - { - ResultT * res = maker(*i); - LOG(LDEBUG, (*res)); - delete res; - } - LOG(LDEBUG, ("------------------------")); - } - #endif - */ +/* +#ifdef DEBUG + { + impl::PreResult2Maker maker(*this); + LOG(LDEBUG, ("Dump features for rank:")); + for (QueueT::const_iterator i = m_results[0].begin(); i != m_results[0].end(); ++i) + { + ResultT * res = maker(*i); + LOG(LDEBUG, (*res)); + delete res; + } + LOG(LDEBUG, ("------------------------")); + } +#endif +*/ vector indV; @@ -490,7 +505,7 @@ namespace void Query::AddResultFromTrie(TrieValueT const & val, size_t mwmID) { - impl::PreResult1 res(val.m_featureId, val.m_rank, val.m_pt, mwmID, m_position, m_viewport); + impl::PreResult1 res(val.m_featureId, val.m_rank, val.m_pt, mwmID, m_position, GetViewport()); for (size_t i = 0; i < m_qCount; ++i) { @@ -584,9 +599,6 @@ public: void Query::SearchFeatures() { - if (!m_pIndex) - return; - vector > tokens(m_tokens.size()); // Add normal tokens. @@ -609,7 +621,11 @@ void Query::SearchFeatures() langs.insert(StringUtf8Multilang::GetLangIndex("en")); langs.insert(StringUtf8Multilang::GetLangIndex("default")); - SearchFeatures(tokens, mwmInfo, langs, true); + for (size_t i = 0; i < m_rectsCount; ++i) + { + if (m_viewportExtended[i].IsValid()) + SearchFeatures(tokens, mwmInfo, langs, i); + } } namespace @@ -639,13 +655,12 @@ namespace void Query::SearchFeatures(vector > const & tokens, vector const & mwmInfo, unordered_set const & langs, - bool onlyInViewport) + size_t ind) { for (MwmSet::MwmId mwmId = 0; mwmId < mwmInfo.size(); ++mwmId) { // Search only mwms that intersect with viewport (world always does). - if (!onlyInViewport || - m_viewportExtended.IsIntersect(mwmInfo[mwmId].m_limitRect)) + if (m_viewportExtended[ind].IsIntersect(mwmInfo[mwmId].m_limitRect)) { Index::MwmLock mwmLock(*m_pIndex, mwmId); if (MwmValue * pMwm = mwmLock.GetValue()) @@ -653,8 +668,12 @@ void Query::SearchFeatures(vector > const & tokens, if (pMwm->m_cont.IsReaderExist(SEARCH_INDEX_FILE_TAG)) { feature::DataHeader const & header = pMwm->GetHeader(); - serial::CodingParams cp(GetCPForTrie(header.GetDefCodingParams())); + bool const isWorld = (header.GetType() == feature::DataHeader::world); + if (isWorld && !m_worldSearch) + continue; + + serial::CodingParams cp(GetCPForTrie(header.GetDefCodingParams())); scoped_ptr pTrieRoot(::trie::reader::ReadTrie( pMwm->m_cont.GetReader(SEARCH_INDEX_FILE_TAG), trie::ValueReader(cp), @@ -679,8 +698,6 @@ void Query::SearchFeatures(vector > const & tokens, } ASSERT_NOT_EQUAL(pCategoriesRoot, 0, ()); - bool const isWorld = (header.GetType() == feature::DataHeader::world); - impl::FeatureLoader emitter(*this, mwmId); // Iterate through first language edges. @@ -694,7 +711,8 @@ void Query::SearchFeatures(vector > const & tokens, MatchFeaturesInTrie(tokens, m_prefix, TrieRootPrefix(*pLangRoot, edge), TrieRootPrefix(*pCategoriesRoot, categoriesEdge), - FeaturesFilter(m_offsetsInViewport[mwmId], isWorld, m_cancel), emitter); + FeaturesFilter(m_offsetsInViewport[ind][mwmId], isWorld, m_cancel), + emitter); LOG(LDEBUG, ("Lang:", StringUtf8Multilang::GetLangByCode(static_cast(edge[0])), @@ -746,4 +764,15 @@ void Query::MatchForSuggestions(strings::UniString const & token, Results & res) } } +m2::RectD const & Query::GetViewport() const +{ + if (m_viewport[0].IsValid()) + return m_viewport[0]; + else + { + ASSERT ( m_viewport[1].IsValid(), () ); + return m_viewport[1]; + } +} + } // namespace search diff --git a/search/search_query.hpp b/search/search_query.hpp index 620b2919af..1e539f30a0 100644 --- a/search/search_query.hpp +++ b/search/search_query.hpp @@ -38,6 +38,8 @@ namespace impl class Query { public: + static int const m_scaleDepthSearch = 7; + // Vector of pairs (string_to_suggest, min_prefix_length_to_suggest). typedef vector > StringsToSuggestVectorT; @@ -47,12 +49,14 @@ public: storage::CountryInfoGetter const * pInfoGetter); ~Query(); - void SetViewport(m2::RectD const & viewport); + void SetViewport(m2::RectD viewport[], size_t count); static const int empty_pos_value = -1000; inline void SetPosition(m2::PointD const & pos) { m_position = pos; } inline void NullPosition() { m_position = m2::PointD(empty_pos_value, empty_pos_value); } + inline void SetSearchInWorld(bool b) { m_worldSearch = b; } + void SetPreferredLanguage(string const & lang); void Search(string const & query, Results & res, unsigned int resultsNeeded = 10); @@ -68,7 +72,8 @@ private: friend class impl::BestNameFinder; friend class impl::PreResult2Maker; - void UpdateViewportOffsets(); + void UpdateViewportOffsets(size_t ind); + void ClearCache(size_t ind); typedef trie::ValueReader::ValueType TrieValueT; void AddResultFromTrie(TrieValueT const & val, size_t mwmID); @@ -79,7 +84,7 @@ private: void SearchFeatures(vector > const & tokens, vector const & mwmInfo, unordered_set const & langs, - bool onlyInViewport); + size_t ind); void SuggestStrings(Results & res); void MatchForSuggestions(strings::UniString const & token, Results & res); @@ -99,13 +104,22 @@ private: buffer_vector m_tokens; strings::UniString m_prefix; - m2::RectD m_viewport, m_viewportExtended; + /// @todo OMG, this static integral constant does't link ??? + //static size_t const m_rectsCount = 2; + enum { m_rectsCount = 2 }; + + m2::RectD m_viewport[m_rectsCount]; + m2::RectD m_viewportExtended[m_rectsCount]; + bool m_worldSearch; + + /// @return Rect for viewport-distance calculation. + m2::RectD const & GetViewport() const; + m2::PointD m_position; scoped_ptr m_pKeywordsScorer; - bool m_bOffsetsCacheIsValid; - vector > m_offsetsInViewport; + vector > m_offsetsInViewport[m_rectsCount]; template class CompareT {