From 3b06c903f7538d2388a9d9932596cced8a8bdc38 Mon Sep 17 00:00:00 2001 From: Alex Zolotarev Date: Tue, 17 May 2011 20:55:33 +0200 Subject: [PATCH] Knee-search v0.2, limited to viewport only --- indexer/feature.hpp | 5 +++ map/framework.cpp | 36 +++++------------- map/framework.hpp | 3 +- map/map.pro | 2 + map/search_processor.cpp | 79 ++++++++++++++++++++++++++++++++++++++++ map/search_processor.hpp | 65 +++++++++++++++++++++++++++++++++ qt/mainwindow.cpp | 37 +++++++++++-------- qt/mainwindow.hpp | 7 +++- 8 files changed, 190 insertions(+), 44 deletions(-) create mode 100644 map/search_processor.cpp create mode 100644 map/search_processor.hpp diff --git a/indexer/feature.hpp b/indexer/feature.hpp index 6849a5e1ab..6aba11de76 100644 --- a/indexer/feature.hpp +++ b/indexer/feature.hpp @@ -202,6 +202,11 @@ public: return m_Params.layer; } + inline bool HasName() const + { + return Header() & feature::HEADER_HAS_NAME; + } + template inline bool ForEachNameRef(T & functor) const { diff --git a/map/framework.cpp b/map/framework.cpp index c5e13ea773..d5426912a7 100644 --- a/map/framework.cpp +++ b/map/framework.cpp @@ -6,6 +6,7 @@ #include "feature_vec_model.hpp" #include "benchmark_provider.hpp" #include "languages.hpp" +#include "search_processor.hpp" #include "../indexer/feature_visibility.hpp" #include "../indexer/feature.hpp" @@ -257,7 +258,6 @@ namespace fwork return true; } - } template @@ -387,7 +387,7 @@ void FrameWork::AddRedrawCommandSure() // set language priorities languages::CodesT langCodes; languages::GetCurrentSettings(langCodes); - StringUtf8Multilang::SetPreferableLanguages(langCodes); + languages::SaveSettings(langCodes); } template @@ -1058,37 +1058,21 @@ void FrameWork::AddRedrawCommandSure() UpdateNow(); } - class SearchProcessor - { - string const & m_text; - SearchCallbackT & m_callback; - - public: - SearchProcessor(string const & textToSearch, SearchCallbackT & callback) - : m_text(textToSearch), m_callback(callback) {} - bool operator() (FeatureType const & f) const - { - // @TODO search for all languages - string name; - f.GetName(name); - if (!name.empty() && name.find(m_text) != string::npos) - { - m_callback(name, f.GetLimitRect(-1)); - } - return true; - } - }; - template void FrameWork::Search(string const & text, SearchCallbackT callback) const { threads::MutexGuard lock(m_modelSyn); - SearchProcessor doClass(text, callback); - m_model.ForEachFeatureWithScale(m2::RectD(MercatorBounds::minX, + search::Query query(text); + search::Processor doClass(query); + m_model.ForEachFeature(m_navigator.Screen().GlobalRect() + /*m2::RectD(MercatorBounds::minX, MercatorBounds::minY, MercatorBounds::maxX, - MercatorBounds::maxY), doClass, 9); + MercatorBounds::maxY)*/, doClass); + query.ForEachResultRef(callback); + // empty name indicates last element + callback(search::Result(string(), m2::RectD())); } template class FrameWork; diff --git a/map/framework.hpp b/map/framework.hpp index 0be701d484..3058dccec2 100644 --- a/map/framework.hpp +++ b/map/framework.hpp @@ -7,6 +7,7 @@ #include "window_handle.hpp" #include "location_state.hpp" #include "navigator.hpp" +#include "search_processor.hpp" #include "../defines.hpp" @@ -51,7 +52,7 @@ class redraw_operation_cancelled {}; struct BenchmarkRectProvider; -typedef boost::function SearchCallbackT; +typedef boost::function SearchCallbackT; namespace fwork { diff --git a/map/map.pro b/map/map.pro index 2fc51c278a..7810392aca 100644 --- a/map/map.pro +++ b/map/map.pro @@ -25,6 +25,7 @@ HEADERS += \ location_state.hpp \ benchmark_provider.hpp \ languages.hpp \ + search_processor.hpp \ SOURCES += \ feature_vec_model.cpp \ @@ -39,6 +40,7 @@ SOURCES += \ location_state.cpp \ benchmark_provider.cpp \ languages.cpp \ + search_processor.cpp \ !iphone*:!bada* { HEADERS += qgl_render_context.hpp diff --git a/map/search_processor.cpp b/map/search_processor.cpp new file mode 100644 index 0000000000..34501f1844 --- /dev/null +++ b/map/search_processor.cpp @@ -0,0 +1,79 @@ +#include "search_processor.hpp" + +#include "../indexer/feature.hpp" +#include "../indexer/classificator.hpp" + +#include "../base/utf8_string.hpp" +#include "../base/logging.hpp" + +#include "../std/bind.hpp" + +namespace search +{ + int Score(string const & key, string const & word) + { + size_t const offset = word.find(key); + switch (offset) + { + case 0: // best match - from the beginning + if (word.size() == key.size()) + return 1000; // full match + else + return 100; // partial match + break; + case string::npos: // no match + return -1; + break; + default: // match in the middle of the string + return key.size() * 2; // how many symbols matched + } + } + + Query::Query(string const & line) + { + utf8_string::Split(line, m_tokens); + } + + bool Query::operator()(char lang, string const & utf8s) + { + vector words; + utf8_string::Split(utf8s, words); + int score = -1; + for (size_t i = 0; i < m_tokens.size(); ++i) + { + for (size_t j = 0; j < words.size(); ++j) + { + score += Score(m_tokens[i], words[j]); + } + } + if (score > 0) + { + m_queue.push(make_pair(score, Result(utf8s, m_currFeature->GetLimitRect(-1)))); + return false; + } + return true; + } + + void Query::Match(FeatureType const & f) + { + m_currFeature = &f; + f.ForEachNameRef(*this); + } + + ////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////// + + Processor::Processor(Query & query) + : m_query(query) + { + } + + bool Processor::operator() (FeatureType const & f) const + { + // filter out features without any name + if (f.HasName()) + m_query.Match(f); + return true; + } + +} diff --git a/map/search_processor.hpp b/map/search_processor.hpp new file mode 100644 index 0000000000..7106ad7e30 --- /dev/null +++ b/map/search_processor.hpp @@ -0,0 +1,65 @@ +#pragma once + +#include "../geometry/rect2d.hpp" + +#include "../std/string.hpp" +#include "../std/vector.hpp" +#include "../std/queue.hpp" + +class FeatureType; + +namespace search +{ + struct Result + { + Result(string const & name, m2::RectD const & rect) + : m_name(name), m_rect(rect) {} + string m_name; + m2::RectD m_rect; + }; + + typedef pair elem_type; + struct QueueComparer + { + // custom comparison for priority_queue + bool operator() (elem_type const & e1, elem_type const & e2) const + { + return e1.first < e2.first; + } + }; + + class Query + { + vector m_tokens; + /// custom comparison, holds found features + priority_queue, QueueComparer> m_queue; + + // @TODO refactor and remove + FeatureType const * m_currFeature; + + public: + Query(string const & line); + + bool operator()(char lang, string const & utf8s); + + void Match(FeatureType const & f); + template void ForEachResultRef(T & f) + { + while (!m_queue.empty()) + { + f(m_queue.top().second); + m_queue.pop(); + } + } + }; + + class Processor + { + /// mutable here because indexer stores const ref to functor + mutable Query & m_query; + + public: + Processor(Query & query); + bool operator() (FeatureType const & f) const; + }; +} diff --git a/qt/mainwindow.cpp b/qt/mainwindow.cpp index 19acd4f724..bbf66fb56d 100644 --- a/qt/mainwindow.cpp +++ b/qt/mainwindow.cpp @@ -6,6 +6,7 @@ #include "../defines.hpp" +#include "../map/search_processor.hpp" #include "../map/settings.hpp" #include @@ -349,27 +350,31 @@ void MainWindow::OnSearchTextChanged(QString const & str) QTableWidget * table = static_cast(m_Docks[3]->widget()); table->clear(); table->setRowCount(0); - m_pDrawWidget->Search(str.toUtf8().constData(), - boost::bind(&MainWindow::OnSearchResult, this, _1, _2)); + if (!str.isEmpty()) + m_pDrawWidget->Search(str.toUtf8().constData(), + boost::bind(&MainWindow::OnSearchResult, this, _1)); } -void MainWindow::OnSearchResult(string const & name, m2::RectD const & rect) +void MainWindow::OnSearchResult(search::Result const & result) { - QTableWidget * table = static_cast(m_Docks[3]->widget()); + if (result.m_name.empty()) // last element + { + if (!m_Docks[3]->isVisible()) + m_Docks[3]->show(); + } + else + { + QTableWidget * table = static_cast(m_Docks[3]->widget()); - int const rowCount = table->rowCount(); - if (rowCount > 100) - return; + int const rowCount = table->rowCount(); - table->setRowCount(rowCount + 1); - QTableWidgetItem * item = new QTableWidgetItem(QString::fromUtf8(name.c_str())); - item->setData(Qt::UserRole, QRectF(QPointF(rect.minX(), rect.maxY()), - QPointF(rect.maxX(), rect.minY()))); - item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); - table->setItem(rowCount, 0, item); - - if (!m_Docks[3]->isVisible()) - m_Docks[3]->show(); + table->setRowCount(rowCount + 1); + QTableWidgetItem * item = new QTableWidgetItem(QString::fromUtf8(result.m_name.c_str())); + item->setData(Qt::UserRole, QRectF(QPointF(result.m_rect.minX(), result.m_rect.maxY()), + QPointF(result.m_rect.maxX(), result.m_rect.minY()))); + item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + table->setItem(rowCount, 0, item); + } } void MainWindow::OnSearchPanelShortcutPressed() diff --git a/qt/mainwindow.hpp b/qt/mainwindow.hpp index 0635a409e7..6ad9fbd9fc 100644 --- a/qt/mainwindow.hpp +++ b/qt/mainwindow.hpp @@ -6,6 +6,11 @@ class QDockWidget; +namespace search +{ + class Result; +} + namespace qt { class DrawWidget; @@ -38,7 +43,7 @@ namespace qt private: void OnLocationFound(); - void OnSearchResult(string const & name, m2::RectD const & rect); + void OnSearchResult(search::Result const & result); protected: #ifdef DEBUG // code removed for desktop releases