forked from organicmaps/organicmaps
[search] Search near my position for empty query.
This commit is contained in:
parent
c48b6ccd11
commit
b75ca70b25
6 changed files with 211 additions and 99 deletions
|
@ -174,10 +174,10 @@ static void OnSearchResultCallback(search::Results const & res, int queryId)
|
|||
else
|
||||
[self disableRadarMode];
|
||||
|
||||
// Refresh search results with new mode, but
|
||||
// do not search if text is not entered
|
||||
// Refresh search results with new mode.
|
||||
NSString * queryString = m_searchBar.text;
|
||||
if (queryString.length)
|
||||
// Search even with empty string.
|
||||
//if (queryString.length)
|
||||
{
|
||||
search::SearchParams params;
|
||||
[self fillSearchParams:params withText:queryString];
|
||||
|
@ -332,19 +332,20 @@ static void OnSearchResultCallback(search::Results const & res, int queryId)
|
|||
{
|
||||
++g_queryId;
|
||||
|
||||
if (searchText.length)
|
||||
// Search even with empty string.
|
||||
//if (searchText.length)
|
||||
{
|
||||
search::SearchParams params;
|
||||
[self fillSearchParams:params withText:searchText];
|
||||
m_framework->Search(params);
|
||||
}
|
||||
else
|
||||
{
|
||||
[g_lastSearchResults release];
|
||||
g_lastSearchResults = nil;
|
||||
// Clean the table
|
||||
[m_table reloadData];
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// [g_lastSearchResults release];
|
||||
// g_lastSearchResults = nil;
|
||||
// // Clean the table
|
||||
// [m_table reloadData];
|
||||
//}
|
||||
}
|
||||
|
||||
- (void)onCloseButton:(id)sender
|
||||
|
@ -553,10 +554,10 @@ static void OnSearchResultCallback(search::Results const & res, int queryId)
|
|||
|
||||
- (void)onGpsUpdate:(location::GpsInfo const &)info
|
||||
{
|
||||
// Refresh search results with newer location, but
|
||||
// do not search if text is not entered
|
||||
// Refresh search results with newer location.
|
||||
NSString * queryString = m_searchBar.text;
|
||||
if (queryString.length)
|
||||
// Search even with empty string.
|
||||
//if (queryString.length)
|
||||
{
|
||||
search::SearchParams params;
|
||||
[self fillSearchParams:params withText:queryString];
|
||||
|
|
|
@ -167,7 +167,9 @@ void SearchPanel::OnSearchTextChanged(QString const & str)
|
|||
++m_queryId;
|
||||
|
||||
QString const normalized = str.normalized(QString::NormalizationForm_KC);
|
||||
if (!normalized.isEmpty())
|
||||
|
||||
// search even with empty query
|
||||
//if (!normalized.isEmpty())
|
||||
{
|
||||
m_params.m_query = normalized.toUtf8().constData();
|
||||
m_params.m_callback = bind(&SearchPanel::SearchResultThreadFunc, this, _1, m_queryId);
|
||||
|
@ -181,11 +183,11 @@ void SearchPanel::OnSearchTextChanged(QString const & str)
|
|||
m_pClearButton->setFlat(true);
|
||||
m_pClearButton->setVisible(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// hide X button
|
||||
m_pClearButton->setVisible(false);
|
||||
}
|
||||
//else
|
||||
//{
|
||||
// // hide X button
|
||||
// m_pClearButton->setVisible(false);
|
||||
//}
|
||||
}
|
||||
|
||||
void SearchPanel::OnSearchPanelItemClicked(int row, int)
|
||||
|
@ -209,6 +211,7 @@ void SearchPanel::OnSearchPanelItemClicked(int row, int)
|
|||
void SearchPanel::showEvent(QShowEvent *)
|
||||
{
|
||||
connect(m_pDrawWidget, SIGNAL(ViewportChanged()), this, SLOT(OnViewportChanged()));
|
||||
OnSearchTextChanged(QString());
|
||||
}
|
||||
|
||||
void SearchPanel::hideEvent(QHideEvent *)
|
||||
|
|
|
@ -15,9 +15,9 @@ public:
|
|||
enum { MAX_SCORE = KeywordMatcher::MAX_SCORE
|
||||
* (NUM_LANG_PRIORITY_TIERS + 1) * (MAX_LANGS_IN_TIER + 1) };
|
||||
|
||||
explicit LangKeywordsScorer(vector<vector<int8_t> > const & languagePriorities,
|
||||
strings::UniString const * keywords, size_t keywordCount,
|
||||
strings::UniString const * pPrefix);
|
||||
LangKeywordsScorer(vector<vector<int8_t> > const & languagePriorities,
|
||||
strings::UniString const * keywords, size_t keywordCount,
|
||||
strings::UniString const * pPrefix);
|
||||
|
||||
uint32_t Score(int8_t lang, string const & name) const;
|
||||
uint32_t Score(int8_t lang, strings::UniString const & name) const;
|
||||
|
|
|
@ -96,17 +96,19 @@ namespace
|
|||
return MercatorBounds::MetresToXY(lon, lat, radius);
|
||||
}
|
||||
|
||||
enum { VIEWPORT_RECT = 0, NEARME_RECT = 1 };
|
||||
|
||||
/// Check rects for optimal search (avoid duplicating).
|
||||
void AnalizeRects(m2::RectD arrRects[2])
|
||||
{
|
||||
if (arrRects[1].IsRectInside(arrRects[0]))
|
||||
arrRects[0].MakeEmpty();
|
||||
if (arrRects[NEARME_RECT].IsRectInside(arrRects[VIEWPORT_RECT]))
|
||||
arrRects[VIEWPORT_RECT].MakeEmpty();
|
||||
else
|
||||
{
|
||||
if (arrRects[0].IsRectInside(arrRects[1]) &&
|
||||
scales::GetScaleLevel(arrRects[0]) + Query::m_scaleDepthSearch >= scales::GetUpperScale())
|
||||
if (arrRects[VIEWPORT_RECT].IsRectInside(arrRects[NEARME_RECT]) &&
|
||||
(scales::GetScaleLevel(arrRects[VIEWPORT_RECT]) + Query::m_scaleDepthSearch >= scales::GetUpperScale()))
|
||||
{
|
||||
arrRects[1].MakeEmpty();
|
||||
arrRects[NEARME_RECT].MakeEmpty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,7 +166,7 @@ void Engine::SearchAsync()
|
|||
{
|
||||
threads::MutexGuard updateGuard(m_updateMutex);
|
||||
params = m_params;
|
||||
arrRects[0] = m_viewport;
|
||||
arrRects[VIEWPORT_RECT] = m_viewport;
|
||||
}
|
||||
|
||||
// Initialize query.
|
||||
|
@ -173,16 +175,27 @@ void Engine::SearchAsync()
|
|||
{
|
||||
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())
|
||||
if (!params.m_query.empty())
|
||||
{
|
||||
worldSearch = false;
|
||||
arrRects[0].MakeEmpty();
|
||||
arrRects[NEARME_RECT] = GetViewportRect(params.m_lat, params.m_lon);
|
||||
|
||||
// Do not search in viewport for "NearMe" mode.
|
||||
if (params.IsNearMeMode())
|
||||
{
|
||||
worldSearch = false;
|
||||
arrRects[VIEWPORT_RECT].MakeEmpty();
|
||||
}
|
||||
else
|
||||
AnalizeRects(arrRects);
|
||||
}
|
||||
else
|
||||
AnalizeRects(arrRects);
|
||||
{
|
||||
// For empty query search in small viewport near position.
|
||||
arrRects[NEARME_RECT] = GetViewportRect(params.m_lat, params.m_lon, 2500);
|
||||
|
||||
worldSearch = false;
|
||||
arrRects[VIEWPORT_RECT].MakeEmpty();
|
||||
}
|
||||
}
|
||||
else
|
||||
m_pQuery->NullPosition();
|
||||
|
@ -196,7 +209,13 @@ void Engine::SearchAsync()
|
|||
|
||||
try
|
||||
{
|
||||
m_pQuery->Search(params.m_query, res);
|
||||
if (params.m_query.empty())
|
||||
{
|
||||
if (params.m_validPos)
|
||||
m_pQuery->SearchAllNearMe(res);
|
||||
}
|
||||
else
|
||||
m_pQuery->Search(params.m_query, res);
|
||||
}
|
||||
catch (Query::CancelException const &)
|
||||
{
|
||||
|
|
|
@ -181,45 +181,54 @@ namespace
|
|||
};
|
||||
}
|
||||
|
||||
void Query::InitSearch(string const & query)
|
||||
{
|
||||
m_cancel = false;
|
||||
m_rawQuery = query;
|
||||
m_uniQuery = NormalizeAndSimplifyString(m_rawQuery);
|
||||
m_tokens.clear();
|
||||
m_prefix.clear();
|
||||
}
|
||||
|
||||
void Query::InitKeywordsScorer()
|
||||
{
|
||||
vector<vector<int8_t> > langPriorities(4);
|
||||
langPriorities[0].push_back(m_currentLang);
|
||||
langPriorities[1].push_back(m_inputLang);
|
||||
langPriorities[2].push_back(StringUtf8Multilang::GetLangIndex("int_name"));
|
||||
langPriorities[2].push_back(StringUtf8Multilang::GetLangIndex("en"));
|
||||
langPriorities[3].push_back(StringUtf8Multilang::GetLangIndex("default"));
|
||||
m_pKeywordsScorer.reset(new LangKeywordsScorer(langPriorities,
|
||||
m_tokens.data(), m_tokens.size(), &m_prefix));
|
||||
}
|
||||
|
||||
void Query::Search(string const & query, Results & res, unsigned int resultsNeeded)
|
||||
{
|
||||
// Initialize.
|
||||
|
||||
InitSearch(query);
|
||||
|
||||
search::Delimiters delims;
|
||||
SplitUniString(m_uniQuery, MakeBackInsertFunctor(m_tokens), delims);
|
||||
|
||||
if (!m_tokens.empty() && !delims(strings::LastUniChar(m_rawQuery)))
|
||||
{
|
||||
m_cancel = false;
|
||||
m_rawQuery = query;
|
||||
m_uniQuery = NormalizeAndSimplifyString(m_rawQuery);
|
||||
m_tokens.clear();
|
||||
m_prefix.clear();
|
||||
m_prefix.swap(m_tokens.back());
|
||||
m_tokens.pop_back();
|
||||
}
|
||||
if (m_tokens.size() > 31)
|
||||
m_tokens.resize(31);
|
||||
|
||||
search::Delimiters delims;
|
||||
SplitUniString(m_uniQuery, MakeBackInsertFunctor(m_tokens), delims);
|
||||
InitKeywordsScorer();
|
||||
|
||||
if (!m_tokens.empty() && !delims(strings::LastUniChar(m_rawQuery)))
|
||||
{
|
||||
m_prefix.swap(m_tokens.back());
|
||||
m_tokens.pop_back();
|
||||
}
|
||||
if (m_tokens.size() > 31)
|
||||
m_tokens.resize(31);
|
||||
// Results queue's initialization.
|
||||
STATIC_ASSERT ( m_qCount == ARRAY_SIZE(g_arrCompare1) );
|
||||
STATIC_ASSERT ( m_qCount == ARRAY_SIZE(g_arrCompare2) );
|
||||
|
||||
vector<vector<int8_t> > langPriorities(4);
|
||||
langPriorities[0].push_back(m_currentLang);
|
||||
langPriorities[1].push_back(m_inputLang);
|
||||
langPriorities[2].push_back(StringUtf8Multilang::GetLangIndex("int_name"));
|
||||
langPriorities[2].push_back(StringUtf8Multilang::GetLangIndex("en"));
|
||||
langPriorities[3].push_back(StringUtf8Multilang::GetLangIndex("default"));
|
||||
m_pKeywordsScorer.reset(new LangKeywordsScorer(langPriorities,
|
||||
m_tokens.data(), m_tokens.size(), &m_prefix));
|
||||
|
||||
// Results queue's initialization.
|
||||
STATIC_ASSERT ( m_qCount == ARRAY_SIZE(g_arrCompare1) );
|
||||
STATIC_ASSERT ( m_qCount == ARRAY_SIZE(g_arrCompare2) );
|
||||
|
||||
for (size_t i = 0; i < m_qCount; ++i)
|
||||
{
|
||||
m_results[i] = QueueT(2 * resultsNeeded, QueueCompareT(g_arrCompare1[i]));
|
||||
m_results[i].reserve(2 * resultsNeeded);
|
||||
}
|
||||
for (size_t i = 0; i < m_qCount; ++i)
|
||||
{
|
||||
m_results[i] = QueueT(2 * resultsNeeded, QueueCompareT(g_arrCompare1[i]));
|
||||
m_results[i].reserve(2 * resultsNeeded);
|
||||
}
|
||||
|
||||
// Match (lat, lon).
|
||||
|
@ -279,7 +288,7 @@ namespace
|
|||
shared_ptr<value_type> m_val;
|
||||
|
||||
public:
|
||||
explicit IndexedValue(value_type * v) : m_val(v)
|
||||
IndexedValue(value_type * v) : m_val(v)
|
||||
{
|
||||
for (size_t i = 0; i < m_ind.size(); ++i)
|
||||
m_ind[i] = numeric_limits<size_t>::max();
|
||||
|
@ -328,6 +337,29 @@ namespace
|
|||
return (r1.GetID() < r2.GetID());
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void RemoveDuplicatingLinear(vector<T> & indV)
|
||||
{
|
||||
sort(indV.begin(), indV.end(), ProxyFunctor2<impl::PreResult2::LessLinearTypesF>());
|
||||
indV.erase(unique(indV.begin(), indV.end(),
|
||||
ProxyFunctor2<impl::PreResult2::EqualLinearTypesF>()),
|
||||
indV.end());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void AddPreResult2(impl::PreResult2 * p, vector<T> & indV)
|
||||
{
|
||||
if (p)
|
||||
{
|
||||
// do not insert duplicating results
|
||||
if (indV.end() == find_if(indV.begin(), indV.end(),
|
||||
ProxyFunctor1<impl::PreResult2::StrictEqualF>(p)))
|
||||
indV.push_back(p);
|
||||
else
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace impl
|
||||
|
@ -359,34 +391,56 @@ namespace impl
|
|||
|
||||
scoped_ptr<LockedFeaturesVector> m_pFV;
|
||||
|
||||
void LoadFeature(pair<size_t, uint32_t> const & id,
|
||||
FeatureType & f, string & name, string & country)
|
||||
{
|
||||
if (m_pFV.get() == 0 || m_pFV->GetID() != id.first)
|
||||
m_pFV.reset(new LockedFeaturesVector(*m_query.m_pIndex, id.first));
|
||||
|
||||
m_pFV->m_vector.Get(id.second, f);
|
||||
|
||||
uint32_t penalty;
|
||||
m_query.GetBestMatchName(f, penalty, name);
|
||||
|
||||
country = m_pFV->GetCountry();
|
||||
}
|
||||
|
||||
public:
|
||||
PreResult2Maker(Query & q) : m_query(q)
|
||||
{
|
||||
}
|
||||
|
||||
// For the best performance, impl::PreResult1 should be sorted by impl::PreResult1::GetID().
|
||||
impl::PreResult2 * operator() (impl::PreResult1 const & r)
|
||||
impl::PreResult2 * operator() (impl::PreResult1 const & res)
|
||||
{
|
||||
pair<size_t, uint32_t> const id = r.GetID();
|
||||
if (m_pFV.get() == 0 || m_pFV->GetID() != id.first)
|
||||
m_pFV.reset(new LockedFeaturesVector(*m_query.m_pIndex, id.first));
|
||||
|
||||
FeatureType feature;
|
||||
m_pFV->m_vector.Get(id.second, feature);
|
||||
string name, country;
|
||||
LoadFeature(res.GetID(), feature, name, country);
|
||||
|
||||
uint32_t penalty;
|
||||
string name;
|
||||
m_query.GetBestMatchName(feature, penalty, name);
|
||||
return new impl::PreResult2(feature, res, name, country);
|
||||
}
|
||||
|
||||
return new impl::PreResult2(feature, r, name, m_pFV->GetCountry());
|
||||
impl::PreResult2 * operator() (pair<size_t, uint32_t> const & id)
|
||||
{
|
||||
FeatureType feature;
|
||||
string name, country;
|
||||
LoadFeature(id, feature, name, country);
|
||||
|
||||
if (!name.empty() && !country.empty())
|
||||
{
|
||||
// this results will be with equal rank
|
||||
impl::PreResult1 res(0, 0, feature.GetLimitRect(FeatureType::WORST_GEOMETRY).Center(),
|
||||
0, m_query.m_position, m_query.GetViewport());
|
||||
return new impl::PreResult2(feature, res, name, country);
|
||||
}
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
void Query::FlushResults(Results & res)
|
||||
{
|
||||
typedef impl::PreResult2 ResultT;
|
||||
|
||||
vector<IndexedValue> indV;
|
||||
|
||||
{
|
||||
|
@ -403,27 +457,14 @@ void Query::FlushResults(Results & res)
|
|||
// make PreResult2 vector
|
||||
impl::PreResult2Maker maker(*this);
|
||||
for (PreResultSetT::const_iterator i = theSet.begin(); i != theSet.end(); ++i)
|
||||
{
|
||||
ResultT * res = maker(*i);
|
||||
if (res == 0) continue;
|
||||
|
||||
// do not insert duplicating results
|
||||
if (indV.end() == find_if(indV.begin(), indV.end(), ProxyFunctor1<ResultT::StrictEqualF>(res)))
|
||||
indV.push_back(IndexedValue(res));
|
||||
else
|
||||
delete res;
|
||||
}
|
||||
AddPreResult2(maker(*i), indV);
|
||||
}
|
||||
|
||||
// remove duplicating linear objects
|
||||
sort(indV.begin(), indV.end(), ProxyFunctor2<ResultT::LessLinearTypesF>());
|
||||
indV.erase(unique(indV.begin(), indV.end(),
|
||||
ProxyFunctor2<ResultT::EqualLinearTypesF>()),
|
||||
indV.end());
|
||||
RemoveDuplicatingLinear(indV);
|
||||
|
||||
for (size_t i = 0; i < m_qCount; ++i)
|
||||
{
|
||||
CompareT<ResultT, RefSmartPtr> comp(g_arrCompare2[i]);
|
||||
CompareT<impl::PreResult2, RefPointer> comp(g_arrCompare2[i]);
|
||||
|
||||
// sort by needed criteria
|
||||
sort(indV.begin(), indV.end(), comp);
|
||||
|
@ -750,4 +791,47 @@ m2::RectD const & Query::GetViewport() const
|
|||
}
|
||||
}
|
||||
|
||||
void Query::SearchAllNearMe(Results & res, unsigned int resultsNeeded)
|
||||
{
|
||||
InitSearch(string());
|
||||
InitKeywordsScorer();
|
||||
|
||||
size_t const ind = 1;
|
||||
ASSERT ( m_viewport[ind].IsValid(), () );
|
||||
|
||||
vector<impl::PreResult2*> indV;
|
||||
|
||||
impl::PreResult2Maker maker(*this);
|
||||
|
||||
// load results
|
||||
for (size_t i = 0; i < m_offsetsInViewport[ind].size(); ++i)
|
||||
{
|
||||
if (m_cancel) break;
|
||||
|
||||
for (size_t j = 0; j < m_offsetsInViewport[ind][i].size(); ++j)
|
||||
{
|
||||
if (m_cancel) break;
|
||||
|
||||
AddPreResult2(maker(make_pair(i, m_offsetsInViewport[ind][i][j])), indV);
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_cancel)
|
||||
{
|
||||
RemoveDuplicatingLinear(indV);
|
||||
|
||||
// sort by distance from m_position
|
||||
sort(indV.begin(), indV.end(),
|
||||
CompareT<impl::PreResult2, RefPointer>(&impl::PreResult2::LessDistance));
|
||||
|
||||
indV.resize(resultsNeeded);
|
||||
|
||||
// emit results
|
||||
for (size_t i = 0; i < indV.size(); ++i)
|
||||
res.AddResult(MakeResult(*(indV[i])));
|
||||
}
|
||||
|
||||
for_each(indV.begin(), indV.end(), DeleteFunctor());
|
||||
}
|
||||
|
||||
} // namespace search
|
||||
|
|
|
@ -61,6 +61,7 @@ public:
|
|||
inline void SetInputLanguage(int8_t lang) { m_inputLang = lang; }
|
||||
|
||||
void Search(string const & query, Results & res, unsigned int resultsNeeded = 10);
|
||||
void SearchAllNearMe(Results & res, unsigned int resultsNeeded = 30);
|
||||
|
||||
void ClearCache();
|
||||
|
||||
|
@ -73,6 +74,9 @@ private:
|
|||
friend class impl::BestNameFinder;
|
||||
friend class impl::PreResult2Maker;
|
||||
|
||||
void InitSearch(string const & query);
|
||||
void InitKeywordsScorer();
|
||||
|
||||
void UpdateViewportOffsets(size_t ind);
|
||||
void ClearCache(size_t ind);
|
||||
|
||||
|
@ -144,9 +148,10 @@ private:
|
|||
{
|
||||
template <class T> T const & operator() (T const & t) const { return t; }
|
||||
};
|
||||
struct RefSmartPtr
|
||||
struct RefPointer
|
||||
{
|
||||
template <class T> typename T::value_type const & operator() (T const & t) const { return *t; }
|
||||
template <class T> T const & operator() (T const * t) const { return *t; }
|
||||
};
|
||||
|
||||
typedef CompareT<impl::PreResult1, NothingRef> QueueCompareT;
|
||||
|
|
Loading…
Add table
Reference in a new issue