Repo created
This commit is contained in:
parent
4af19165ec
commit
68073add76
12458 changed files with 12350765 additions and 2 deletions
348
libs/search/result.cpp
Normal file
348
libs/search/result.cpp
Normal file
|
|
@ -0,0 +1,348 @@
|
|||
#include "search/result.hpp"
|
||||
|
||||
#include "search/common.hpp"
|
||||
#include "search/geometry_utils.hpp"
|
||||
|
||||
#include "indexer/classificator.hpp"
|
||||
#include "indexer/feature_utils.hpp"
|
||||
|
||||
#include "platform/localization.hpp"
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
|
||||
#include "base/string_utils.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace search
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
void Result::FromFeature(FeatureID const & id, uint32_t mainType, uint32_t matchedType, Details const & details)
|
||||
{
|
||||
m_id = id;
|
||||
ASSERT(m_id.IsValid(), ());
|
||||
|
||||
m_mainType = mainType;
|
||||
m_matchedType = matchedType;
|
||||
m_details = details;
|
||||
m_resultType = Type::Feature;
|
||||
}
|
||||
|
||||
Result::Result(string str, string && suggest)
|
||||
: m_resultType(Type::PureSuggest)
|
||||
, m_str(std::move(str))
|
||||
, m_suggestionStr(std::move(suggest))
|
||||
{}
|
||||
|
||||
Result::Result(Result && res, string && suggest)
|
||||
: m_id(std::move(res.m_id))
|
||||
, m_center(res.m_center)
|
||||
, m_str(std::move(res.m_str))
|
||||
, m_address(std::move(res.m_address))
|
||||
, m_matchedType(res.m_matchedType)
|
||||
, m_suggestionStr(std::move(suggest))
|
||||
, m_hightlightRanges(std::move(res.m_hightlightRanges))
|
||||
{
|
||||
m_resultType = m_id.IsValid() ? Type::SuggestFromFeature : Type::PureSuggest;
|
||||
}
|
||||
|
||||
bool Result::IsSuggest() const
|
||||
{
|
||||
return m_resultType == Type::SuggestFromFeature || m_resultType == Type::PureSuggest;
|
||||
}
|
||||
|
||||
bool Result::HasPoint() const
|
||||
{
|
||||
return m_resultType != Type::PureSuggest;
|
||||
}
|
||||
|
||||
FeatureID const & Result::GetFeatureID() const
|
||||
{
|
||||
ASSERT_EQUAL(m_resultType, Type::Feature, ());
|
||||
return m_id;
|
||||
}
|
||||
|
||||
uint32_t Result::GetFeatureType() const
|
||||
{
|
||||
ASSERT_EQUAL(m_resultType, Type::Feature, ());
|
||||
return m_mainType;
|
||||
}
|
||||
|
||||
bool Result::IsSameType(uint32_t type) const
|
||||
{
|
||||
uint8_t const level = ftype::GetLevel(type);
|
||||
for (uint32_t t : {m_mainType, m_matchedType})
|
||||
{
|
||||
ftype::TruncValue(t, level);
|
||||
if (t == type)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string GetLocalizedTypeName(uint32_t type)
|
||||
{
|
||||
return platform::GetLocalizedTypeName(classif().GetReadableObjectName(type));
|
||||
}
|
||||
|
||||
std::string Result::GetLocalizedFeatureType() const
|
||||
{
|
||||
switch (m_resultType)
|
||||
{
|
||||
case Type::Feature: return GetLocalizedTypeName(m_mainType);
|
||||
case Type::Postcode: return platform::GetLocalizedString("postal_code");
|
||||
default: return {};
|
||||
}
|
||||
}
|
||||
|
||||
std::string Result::GetFeatureDescription() const
|
||||
{
|
||||
std::string res = GetLocalizedFeatureType();
|
||||
if (res.empty())
|
||||
return res;
|
||||
|
||||
auto const append = [&res](std::string_view sv)
|
||||
{
|
||||
if (!res.empty())
|
||||
res += feature::kFieldsSeparator;
|
||||
res += sv;
|
||||
};
|
||||
|
||||
// Clear, because GetLocalizedFeatureType will be shown as main title.
|
||||
if (m_str.empty())
|
||||
res.clear();
|
||||
|
||||
if (m_mainType != m_matchedType && m_matchedType != 0)
|
||||
append(GetLocalizedTypeName(m_matchedType));
|
||||
|
||||
if (!GetDescription().empty())
|
||||
append(GetDescription());
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
m2::PointD Result::GetFeatureCenter() const
|
||||
{
|
||||
ASSERT(HasPoint(), ());
|
||||
return m_center;
|
||||
}
|
||||
|
||||
string const & Result::GetSuggestionString() const
|
||||
{
|
||||
ASSERT(IsSuggest(), ());
|
||||
return m_suggestionStr;
|
||||
}
|
||||
|
||||
bool Result::IsEqualSuggest(Result const & r) const
|
||||
{
|
||||
return m_suggestionStr == r.m_suggestionStr;
|
||||
}
|
||||
|
||||
bool Result::IsEqualFeature(Result const & r) const
|
||||
{
|
||||
/// @todo Compare TruncValue(m_matchedType) ?
|
||||
if (m_resultType != r.m_resultType || m_matchedType != r.m_matchedType)
|
||||
return false;
|
||||
|
||||
ASSERT_EQUAL(m_resultType, Result::Type::Feature, ());
|
||||
ASSERT(m_id.IsValid() && r.m_id.IsValid(), ());
|
||||
|
||||
/// @todo Investigate why it is happens here?
|
||||
if (m_id == r.m_id)
|
||||
return true;
|
||||
|
||||
if (m_str != r.m_str)
|
||||
return false;
|
||||
|
||||
if (m_id.IsWorld() != r.m_id.IsWorld())
|
||||
{
|
||||
// Filter logically duplicating results from World.mwm and Country.mwm (like cities).
|
||||
return PointDistance(m_center, r.m_center) < 500.0;
|
||||
}
|
||||
|
||||
// Filter stops (bus/tram), see BA_LasHeras test.
|
||||
if (ftypes::IsPublicTransportStopChecker::Instance()(m_matchedType))
|
||||
return PointDistance(m_center, r.m_center) < 150.0;
|
||||
|
||||
/// @todo Keep this check until RemoveDuplicatingLinear will be fixed.
|
||||
// Filter same streets (with 'same logical street distance' threshold).
|
||||
if (ftypes::IsWayChecker::Instance().GetSearchRank(m_matchedType) != ftypes::IsWayChecker::Default)
|
||||
return PointDistance(m_center, r.m_center) < 2000.0;
|
||||
|
||||
// Filter real duplicates when say area park is present in 2 MWMs, or OSM data duplicates.
|
||||
return m_address == r.m_address && PointDistance(m_center, r.m_center) < 10.0;
|
||||
}
|
||||
|
||||
void Result::AddHighlightRange(pair<uint16_t, uint16_t> const & range)
|
||||
{
|
||||
m_hightlightRanges.push_back(range);
|
||||
}
|
||||
|
||||
void Result::AddDescHighlightRange(pair<uint16_t, uint16_t> const & range)
|
||||
{
|
||||
m_descHightlightRanges.push_back(range);
|
||||
}
|
||||
|
||||
pair<uint16_t, uint16_t> const & Result::GetHighlightRange(size_t idx) const
|
||||
{
|
||||
ASSERT(idx < m_hightlightRanges.size(), ());
|
||||
return m_hightlightRanges[idx];
|
||||
}
|
||||
pair<uint16_t, uint16_t> const & Result::GetDescHighlightRange(size_t idx) const
|
||||
{
|
||||
ASSERT(idx < m_descHightlightRanges.size(), ());
|
||||
return m_descHightlightRanges[idx];
|
||||
}
|
||||
|
||||
void Result::PrependCity(string_view city)
|
||||
{
|
||||
// It is expected that if |m_address| is not empty,
|
||||
// it starts with the region name. Avoid duplication
|
||||
// in the case where this region name coincides with
|
||||
// the city name and prepend otherwise.
|
||||
strings::SimpleTokenizer tok(m_address, ",");
|
||||
if (tok && *tok != city)
|
||||
m_address = std::string(city) + ", " + m_address;
|
||||
}
|
||||
|
||||
string Result::ToStringForStats() const
|
||||
{
|
||||
string readableType;
|
||||
if (GetResultType() == Type::Feature)
|
||||
readableType = classif().GetReadableObjectName(m_matchedType);
|
||||
|
||||
string s;
|
||||
s.append(GetString());
|
||||
s.append("|");
|
||||
s.append(readableType);
|
||||
s.append("|");
|
||||
s.append(IsSuggest() ? "1" : "0");
|
||||
s.append("|");
|
||||
s.append(to_string(mercator::YToLat(m_center.y)));
|
||||
s.append("|");
|
||||
s.append(to_string(mercator::XToLon(m_center.x)));
|
||||
return s;
|
||||
}
|
||||
|
||||
string DebugPrint(Result::Type type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Result::Type::Feature: return "Feature";
|
||||
case Result::Type::LatLon: return "LatLon";
|
||||
case Result::Type::PureSuggest: return "PureSuggest";
|
||||
case Result::Type::SuggestFromFeature: return "SuggestFromFeature";
|
||||
case Result::Type::Postcode: return "Postcode";
|
||||
}
|
||||
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
string DebugPrint(Result const & result)
|
||||
{
|
||||
string readableType;
|
||||
if (result.GetResultType() == Result::Type::Feature)
|
||||
readableType = classif().GetReadableObjectName(result.GetFeatureType());
|
||||
|
||||
ostringstream os;
|
||||
os << "Result [";
|
||||
os << "name: " << result.GetString();
|
||||
os << ", type: " << readableType;
|
||||
os << ", info: " << DebugPrint(result.GetRankingInfo());
|
||||
|
||||
#ifdef SEARCH_USE_PROVENANCE
|
||||
if (!result.m_provenance.empty())
|
||||
os << ", provenance: " << ::DebugPrint(result.m_provenance);
|
||||
#endif
|
||||
|
||||
os << "]";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
// Results -----------------------------------------------------------------------------------------
|
||||
Results::Results()
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
|
||||
bool Results::AddResult(Result && result)
|
||||
{
|
||||
// Find first feature result.
|
||||
auto it = find_if(m_results.begin(), m_results.end(),
|
||||
[](Result const & r) { return r.GetResultType() == Result::Type::Feature; });
|
||||
|
||||
if (result.IsSuggest())
|
||||
{
|
||||
if (static_cast<size_t>(std::distance(m_results.begin(), it)) >= kMaxNumSuggests)
|
||||
return false;
|
||||
|
||||
for (auto i = m_results.begin(); i != it; ++i)
|
||||
if (result.IsEqualSuggest(*i))
|
||||
return false;
|
||||
InsertResult(it, std::move(result));
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; it != m_results.end(); ++it)
|
||||
if (result.IsEqualFeature(*it))
|
||||
return false;
|
||||
InsertResult(m_results.end(), std::move(result));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Results::AddResultNoChecks(Result && result)
|
||||
{
|
||||
InsertResult(m_results.end(), std::move(result));
|
||||
}
|
||||
|
||||
void Results::AddBookmarkResult(bookmarks::Result const & result)
|
||||
{
|
||||
m_bookmarksResults.push_back(result);
|
||||
}
|
||||
|
||||
void Results::Clear()
|
||||
{
|
||||
m_results.clear();
|
||||
m_bookmarksResults.clear();
|
||||
m_status = Status::None;
|
||||
}
|
||||
|
||||
size_t Results::GetSuggestsCount() const
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
// Suggests always go first, so we need to compute length of prefix
|
||||
// of suggests.
|
||||
while (i < m_results.size() && m_results[i].IsSuggest())
|
||||
++i;
|
||||
return i;
|
||||
}
|
||||
|
||||
bookmarks::Results const & Results::GetBookmarksResults() const
|
||||
{
|
||||
return m_bookmarksResults;
|
||||
}
|
||||
|
||||
void Results::InsertResult(vector<Result>::iterator where, Result && result)
|
||||
{
|
||||
ASSERT_LESS(m_results.size(), numeric_limits<int32_t>::max(), ());
|
||||
|
||||
for (auto it = where; it != m_results.end(); ++it)
|
||||
{
|
||||
auto & r = *it;
|
||||
auto const position = r.GetPositionInResults();
|
||||
r.SetPositionInResults(position + 1);
|
||||
}
|
||||
|
||||
result.SetPositionInResults(static_cast<int32_t>(distance(m_results.begin(), where)));
|
||||
m_results.insert(where, std::move(result));
|
||||
}
|
||||
|
||||
string DebugPrint(search::Results const & results)
|
||||
{
|
||||
return DebugPrintSequence(results.begin(), results.end());
|
||||
}
|
||||
} // namespace search
|
||||
Loading…
Add table
Add a link
Reference in a new issue