forked from organicmaps/organicmaps
[search] Take into account user’s edits.
This commit is contained in:
parent
d584749945
commit
b85fe49049
7 changed files with 158 additions and 102 deletions
|
@ -6,6 +6,8 @@
|
|||
#include "search_index_values.hpp"
|
||||
#include "search_trie.hpp"
|
||||
|
||||
#include "v2/mwm_context.hpp"
|
||||
|
||||
#include "indexer/feature.hpp"
|
||||
#include "indexer/feature_algo.hpp"
|
||||
#include "indexer/index.hpp"
|
||||
|
@ -50,13 +52,6 @@ unique_ptr<coding::CompressedBitVector> SortFeaturesAndBuildCBV(vector<uint64_t>
|
|||
return coding::CompressedBitVectorBuilder::FromBitPositions(move(features));
|
||||
}
|
||||
|
||||
void CoverRect(m2::RectD const & rect, int scale, covering::IntervalsT & result)
|
||||
{
|
||||
covering::CoveringGetter covering(rect, covering::ViewportWithLowLevels);
|
||||
auto const & intervals = covering.Get(scale);
|
||||
result.insert(result.end(), intervals.begin(), intervals.end());
|
||||
}
|
||||
|
||||
bool MatchFeatureByName(FeatureType const & ft, SearchQueryParams const & params)
|
||||
{
|
||||
bool matched = false;
|
||||
|
@ -147,27 +142,19 @@ unique_ptr<coding::CompressedBitVector> RetrieveAddressFeaturesImpl(
|
|||
// Retrieves from the geometry index corresponding to handle all
|
||||
// features from |coverage|.
|
||||
unique_ptr<coding::CompressedBitVector> RetrieveGeometryFeaturesImpl(
|
||||
MwmSet::MwmId const & id, MwmValue & value, my::Cancellable const & cancellable,
|
||||
v2::MwmContext const & context, my::Cancellable const & cancellable,
|
||||
covering::IntervalsT const & coverage, int scale)
|
||||
{
|
||||
// TODO(AlexZ): Also add created features.
|
||||
auto const deleted = Editor::Instance().GetFeaturesByStatus(id, Editor::FeatureStatus::Deleted);
|
||||
// TODO (@y, @m): remove this code as soon as geometry index will
|
||||
// have native support for bit vectors.
|
||||
vector<uint64_t> features;
|
||||
uint32_t counter = 0;
|
||||
auto const collector = [&](uint64_t featureId)
|
||||
vector<uint64_t> features;
|
||||
|
||||
context.ForEachIndex(coverage, scale, [&](uint64_t featureId)
|
||||
{
|
||||
if (binary_search(deleted.begin(), deleted.end(), static_cast<uint32_t>(featureId)))
|
||||
return;
|
||||
if ((++counter & 0xFF) == 0)
|
||||
BailIfCancelled(cancellable);
|
||||
features.push_back(featureId);
|
||||
};
|
||||
});
|
||||
|
||||
ScaleIndex<ModelReaderPtr> index(value.m_cont.GetReader(INDEX_FILE_TAG), value.m_factory);
|
||||
for (auto const & interval : coverage)
|
||||
index.ForEachInIntervalAndScale(collector, interval.first, interval.second, scale);
|
||||
return SortFeaturesAndBuildCBV(move(features));
|
||||
}
|
||||
|
||||
|
@ -295,10 +282,14 @@ public:
|
|||
if (m_prevScale < 0)
|
||||
{
|
||||
covering::IntervalsT coverage;
|
||||
CoverRect(currViewport, m_coverageScale, coverage);
|
||||
geometryFeatures =
|
||||
RetrieveGeometryFeaturesImpl(m_handle.GetId(), *m_handle.GetValue<MwmValue>(),
|
||||
cancellable, coverage, m_coverageScale);
|
||||
v2::CoverRect(currViewport, m_coverageScale, coverage);
|
||||
|
||||
/// @todo I didn't find a better solution for now to share MwmHandle.
|
||||
v2::MwmContext context(move(m_handle));
|
||||
geometryFeatures = RetrieveGeometryFeaturesImpl(context, cancellable,
|
||||
coverage, m_coverageScale);
|
||||
m_handle = move(context.m_handle);
|
||||
|
||||
for (auto const & interval : coverage)
|
||||
m_visited.Add(interval);
|
||||
}
|
||||
|
@ -313,10 +304,10 @@ public:
|
|||
m2::RectD d(a.LeftBottom(), c.LeftBottom());
|
||||
|
||||
covering::IntervalsT coverage;
|
||||
CoverRect(a, m_coverageScale, coverage);
|
||||
CoverRect(b, m_coverageScale, coverage);
|
||||
CoverRect(c, m_coverageScale, coverage);
|
||||
CoverRect(d, m_coverageScale, coverage);
|
||||
v2::CoverRect(a, m_coverageScale, coverage);
|
||||
v2::CoverRect(b, m_coverageScale, coverage);
|
||||
v2::CoverRect(c, m_coverageScale, coverage);
|
||||
v2::CoverRect(d, m_coverageScale, coverage);
|
||||
|
||||
my::SortUnique(coverage);
|
||||
coverage = covering::SortAndMergeIntervals(coverage);
|
||||
|
@ -331,9 +322,11 @@ public:
|
|||
for (auto const & interval : coverage)
|
||||
m_visited.SubtractFrom(interval, reducedCoverage);
|
||||
|
||||
geometryFeatures =
|
||||
RetrieveGeometryFeaturesImpl(m_handle.GetId(), *m_handle.GetValue<MwmValue>(),
|
||||
cancellable, reducedCoverage, m_coverageScale);
|
||||
/// @todo I didn't find a better solution for now to share MwmHandle.
|
||||
v2::MwmContext context(move(m_handle));
|
||||
geometryFeatures = RetrieveGeometryFeaturesImpl(context, cancellable,
|
||||
reducedCoverage, m_coverageScale);
|
||||
m_handle = move(context.m_handle);
|
||||
|
||||
for (auto const & interval : reducedCoverage)
|
||||
m_visited.Add(interval);
|
||||
|
@ -454,12 +447,12 @@ unique_ptr<coding::CompressedBitVector> Retrieval::RetrieveAddressFeatures(
|
|||
|
||||
// static
|
||||
unique_ptr<coding::CompressedBitVector> Retrieval::RetrieveGeometryFeatures(
|
||||
MwmSet::MwmId const & id, MwmValue & value, my::Cancellable const & cancellable,
|
||||
v2::MwmContext const & context, my::Cancellable const & cancellable,
|
||||
m2::RectD const & rect, int scale)
|
||||
{
|
||||
covering::IntervalsT coverage;
|
||||
CoverRect(rect, scale, coverage);
|
||||
return RetrieveGeometryFeaturesImpl(id, value, cancellable, coverage, scale);
|
||||
v2::CoverRect(rect, scale, coverage);
|
||||
return RetrieveGeometryFeaturesImpl(context, cancellable, coverage, scale);
|
||||
}
|
||||
|
||||
void Retrieval::Init(Index & index, vector<shared_ptr<MwmInfo>> const & infos,
|
||||
|
|
|
@ -23,6 +23,8 @@ class CompressedBitVector;
|
|||
|
||||
namespace search
|
||||
{
|
||||
namespace v2 { struct MwmContext; }
|
||||
|
||||
class Retrieval : public my::Cancellable
|
||||
{
|
||||
public:
|
||||
|
@ -112,7 +114,7 @@ public:
|
|||
|
||||
// Retrieves from the geometry index corresponding to |value| all features belonging to |rect|.
|
||||
WARN_UNUSED_RESULT static unique_ptr<coding::CompressedBitVector> RetrieveGeometryFeatures(
|
||||
MwmSet::MwmId const & id, MwmValue & value, my::Cancellable const & cancellable,
|
||||
v2::MwmContext const & context, my::Cancellable const & cancellable,
|
||||
m2::RectD const & rect, int scale);
|
||||
|
||||
// Initializes retrieval process, sets up internal state, takes all
|
||||
|
|
|
@ -46,78 +46,97 @@ void FeaturesLayerMatcher::OnQueryFinished()
|
|||
|
||||
uint32_t FeaturesLayerMatcher::GetMatchingStreet(uint32_t houseId)
|
||||
{
|
||||
auto entry = m_matchingStreetsCache.Get(houseId);
|
||||
if (!entry.second)
|
||||
return entry.first;
|
||||
|
||||
FeatureType houseFeature;
|
||||
GetByIndex(houseId, houseFeature);
|
||||
|
||||
entry.first = GetMatchingStreetImpl(houseId, houseFeature);
|
||||
return entry.first;
|
||||
FeatureType feature;
|
||||
return GetMatchingStreetImpl(houseId, feature);
|
||||
}
|
||||
|
||||
uint32_t FeaturesLayerMatcher::GetMatchingStreet(uint32_t houseId, FeatureType & houseFeature)
|
||||
{
|
||||
auto entry = m_matchingStreetsCache.Get(houseId);
|
||||
if (!entry.second)
|
||||
return entry.first;
|
||||
|
||||
entry.first = GetMatchingStreetImpl(houseId, houseFeature);
|
||||
return entry.first;
|
||||
return GetMatchingStreetImpl(houseId, houseFeature);
|
||||
}
|
||||
|
||||
FeaturesLayerMatcher::TStreets const &
|
||||
FeaturesLayerMatcher::GetNearbyStreets(uint32_t featureId)
|
||||
{
|
||||
auto entry = m_nearbyStreetsCache.Get(featureId);
|
||||
if (!entry.second)
|
||||
return entry.first;
|
||||
|
||||
FeatureType feature;
|
||||
GetByIndex(featureId, feature);
|
||||
|
||||
GetNearbyStreetsImpl(feature, entry.first);
|
||||
return entry.first;
|
||||
return GetNearbyStreetsImpl(featureId, feature);
|
||||
}
|
||||
|
||||
FeaturesLayerMatcher::TStreets const &
|
||||
FeaturesLayerMatcher::GetNearbyStreets(uint32_t featureId, FeatureType & feature)
|
||||
{
|
||||
return GetNearbyStreetsImpl(featureId, feature);
|
||||
}
|
||||
|
||||
FeaturesLayerMatcher::TStreets const &
|
||||
FeaturesLayerMatcher::GetNearbyStreetsImpl(uint32_t featureId, FeatureType & feature)
|
||||
{
|
||||
auto entry = m_nearbyStreetsCache.Get(featureId);
|
||||
if (!entry.second)
|
||||
return entry.first;
|
||||
|
||||
GetNearbyStreetsImpl(feature, entry.first);
|
||||
return entry.first;
|
||||
}
|
||||
if (!feature.GetID().IsValid())
|
||||
GetByIndex(featureId, feature);
|
||||
|
||||
void FeaturesLayerMatcher::GetNearbyStreetsImpl(FeatureType & feature, TStreets & streets)
|
||||
{
|
||||
auto & streets = entry.first;
|
||||
m_reverseGeocoder.GetNearbyStreets(feature, streets);
|
||||
for (size_t i = 0; i < streets.size(); ++i)
|
||||
{
|
||||
if (streets[i].m_distanceMeters > ReverseGeocoder::kLookupRadiusM)
|
||||
{
|
||||
streets.resize(i);
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return streets;
|
||||
}
|
||||
|
||||
uint32_t FeaturesLayerMatcher::GetMatchingStreetImpl(uint32_t houseId, FeatureType & houseFeature)
|
||||
{
|
||||
auto const & streets = GetNearbyStreets(houseId, houseFeature);
|
||||
// Check if this feature is modified - the logic will be different.
|
||||
string streetName;
|
||||
bool const edited = osm::Editor::Instance().GetEditedFeatureStreet(houseFeature.GetID(), streetName);
|
||||
|
||||
uint32_t index;
|
||||
if (m_houseToStreetTable->Get(houseId, index) && index < streets.size())
|
||||
return streets[index].m_id.m_index;
|
||||
// Check the cached result value.
|
||||
auto entry = m_matchingStreetsCache.Get(houseId);
|
||||
if (!edited && !entry.second)
|
||||
return entry.first;
|
||||
|
||||
// Load feature if needed.
|
||||
if (!houseFeature.GetID().IsValid())
|
||||
GetByIndex(houseId, houseFeature);
|
||||
|
||||
// Get nearby streets and calculate the resulting index.
|
||||
auto const & streets = GetNearbyStreets(houseId, houseFeature);
|
||||
uint32_t & result = entry.first;
|
||||
result = kInvalidId;
|
||||
|
||||
if (edited)
|
||||
{
|
||||
auto ret = find_if(streets.begin(), streets.end(), [&streetName](TStreet const & st)
|
||||
{
|
||||
return st.m_name == streetName;
|
||||
});
|
||||
if (ret != streets.end())
|
||||
result = ret->m_id.m_index;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint32_t index;
|
||||
if (m_houseToStreetTable->Get(houseId, index) && index < streets.size())
|
||||
result = streets[index].m_id.m_index;
|
||||
}
|
||||
|
||||
// If there is no saved street for feature, assume that it's a nearest street if it's too close.
|
||||
if (!streets.empty() && streets[0].m_distanceMeters < kMaxApproxStreetDistanceM)
|
||||
return streets[0].m_id.m_index;
|
||||
if (result == kInvalidId &&
|
||||
!streets.empty() &&
|
||||
streets[0].m_distanceMeters < kMaxApproxStreetDistanceM)
|
||||
{
|
||||
result = streets[0].m_id.m_index;
|
||||
}
|
||||
|
||||
return kInvalidId;
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace v2
|
||||
|
|
|
@ -325,11 +325,12 @@ private:
|
|||
uint32_t GetMatchingStreet(uint32_t houseId, FeatureType & houseFeature);
|
||||
uint32_t GetMatchingStreetImpl(uint32_t houseId, FeatureType & houseFeature);
|
||||
|
||||
using TStreets = vector<ReverseGeocoder::Street>;
|
||||
using TStreet = ReverseGeocoder::Street;
|
||||
using TStreets = vector<TStreet>;
|
||||
|
||||
TStreets const & GetNearbyStreets(uint32_t featureId);
|
||||
TStreets const & GetNearbyStreets(uint32_t featureId, FeatureType & feature);
|
||||
void GetNearbyStreetsImpl(FeatureType & feature, TStreets & streets);
|
||||
TStreets const & GetNearbyStreetsImpl(uint32_t featureId, FeatureType & feature);
|
||||
|
||||
inline void GetByIndex(uint32_t id, FeatureType & ft) const
|
||||
{
|
||||
|
|
|
@ -570,9 +570,8 @@ void Geocoder::GoImpl(vector<shared_ptr<MwmInfo>> & infos, bool inViewport)
|
|||
unique_ptr<coding::CompressedBitVector> viewportCBV;
|
||||
if (inViewport)
|
||||
{
|
||||
viewportCBV =
|
||||
Retrieval::RetrieveGeometryFeatures(m_context->GetId(), m_context->m_value, cancellable,
|
||||
m_params.m_viewport, m_params.m_scale);
|
||||
viewportCBV = Retrieval::RetrieveGeometryFeatures(*m_context, cancellable,
|
||||
m_params.m_viewport, m_params.m_scale);
|
||||
}
|
||||
|
||||
PrepareAddressFeatures();
|
||||
|
@ -1358,9 +1357,7 @@ coding::CompressedBitVector const * Geocoder::RetrieveGeometryFeatures(MwmContex
|
|||
return v.m_cbv.get();
|
||||
}
|
||||
|
||||
auto cbv = Retrieval::RetrieveGeometryFeatures(context.GetId(), context.m_value,
|
||||
static_cast<my::Cancellable const &>(*this), rect,
|
||||
m_params.m_scale);
|
||||
auto cbv = Retrieval::RetrieveGeometryFeatures(context, *this, rect, m_params.m_scale);
|
||||
|
||||
auto const * result = cbv.get();
|
||||
features.push_back({m2::Inflate(rect, kComparePoints, kComparePoints), move(cbv), id});
|
||||
|
|
|
@ -5,6 +5,14 @@ namespace search
|
|||
{
|
||||
namespace v2
|
||||
{
|
||||
|
||||
void CoverRect(m2::RectD const & rect, int scale, covering::IntervalsT & result)
|
||||
{
|
||||
covering::CoveringGetter covering(rect, covering::ViewportWithLowLevels);
|
||||
auto const & intervals = covering.Get(scale);
|
||||
result.insert(result.end(), intervals.begin(), intervals.end());
|
||||
}
|
||||
|
||||
MwmContext::MwmContext(MwmSet::MwmHandle handle)
|
||||
: m_handle(move(handle))
|
||||
, m_value(*m_handle.GetValue<MwmValue>())
|
||||
|
@ -13,5 +21,11 @@ MwmContext::MwmContext(MwmSet::MwmHandle handle)
|
|||
{
|
||||
}
|
||||
|
||||
void MwmContext::GetFeature(uint32_t index, FeatureType & ft) const
|
||||
{
|
||||
m_vector.GetByIndex(index, ft);
|
||||
ft.SetID(FeatureID(GetId(), index));
|
||||
}
|
||||
|
||||
} // namespace v2
|
||||
} // namespace search
|
||||
|
|
|
@ -12,9 +12,14 @@ namespace search
|
|||
{
|
||||
namespace v2
|
||||
{
|
||||
|
||||
void CoverRect(m2::RectD const & rect, int scale, covering::IntervalsT & result);
|
||||
|
||||
/// @todo Move this class into "index" library and make it more generic.
|
||||
/// Now it duplicates "Index" functionality.
|
||||
struct MwmContext
|
||||
{
|
||||
MwmContext(MwmSet::MwmHandle handle);
|
||||
explicit MwmContext(MwmSet::MwmHandle handle);
|
||||
|
||||
MwmSet::MwmHandle m_handle;
|
||||
MwmValue & m_value;
|
||||
|
@ -25,33 +30,58 @@ struct MwmContext
|
|||
inline string const & GetName() const { return GetInfo()->GetCountryName(); }
|
||||
inline shared_ptr<MwmInfo> const & GetInfo() const { return GetId().GetInfo(); }
|
||||
|
||||
template <class TFn> void ForEachFeature(m2::RectD const & rect, TFn && fn)
|
||||
template <class TFn> void ForEachIndex(covering::IntervalsT const & intervals,
|
||||
uint32_t scale, TFn && fn) const
|
||||
{
|
||||
feature::DataHeader const & header = m_value.GetHeader();
|
||||
covering::CoveringGetter covering(rect, covering::ViewportWithLowLevels);
|
||||
|
||||
uint32_t const scale = header.GetLastScale();
|
||||
covering::IntervalsT const & interval = covering.Get(scale);
|
||||
|
||||
CheckUniqueIndexes checkUnique(header.GetFormat() >= version::Format::v5);
|
||||
for (auto const & i : interval)
|
||||
ForEachIndexImpl(intervals, scale, [&](uint32_t index)
|
||||
{
|
||||
m_index.ForEachInIntervalAndScale([&](uint32_t index)
|
||||
{
|
||||
if (checkUnique(index))
|
||||
{
|
||||
FeatureType ft;
|
||||
GetFeature(index, ft);
|
||||
fn(ft);
|
||||
}
|
||||
}, i.first, i.second, scale);
|
||||
}
|
||||
if (GetEditedStatus(index) != osm::Editor::FeatureStatus::Deleted)
|
||||
fn(index);
|
||||
});
|
||||
}
|
||||
|
||||
inline void GetFeature(uint32_t index, FeatureType & ft) const
|
||||
template <class TFn> void ForEachFeature(m2::RectD const & rect, TFn && fn) const
|
||||
{
|
||||
m_vector.GetByIndex(index, ft);
|
||||
ft.SetID(FeatureID(GetId(), index));
|
||||
uint32_t const scale = m_value.GetHeader().GetLastScale();
|
||||
covering::IntervalsT intervals;
|
||||
CoverRect(rect, scale, intervals);
|
||||
|
||||
ForEachIndexImpl(intervals, scale,
|
||||
[&](uint32_t index)
|
||||
{
|
||||
FeatureType ft;
|
||||
|
||||
switch (GetEditedStatus(index))
|
||||
{
|
||||
case osm::Editor::FeatureStatus::Deleted: return;
|
||||
case osm::Editor::FeatureStatus::Modified:
|
||||
VERIFY(osm::Editor::Instance().GetEditedFeature(GetId(), index, ft), ());
|
||||
fn(ft);
|
||||
return;
|
||||
case osm::Editor::FeatureStatus::Created:
|
||||
CHECK(false, ("Created features index should be generated."));
|
||||
case osm::Editor::FeatureStatus::Untouched: break;
|
||||
}
|
||||
|
||||
GetFeature(index, ft);
|
||||
fn(ft);
|
||||
});
|
||||
}
|
||||
|
||||
void GetFeature(uint32_t index, FeatureType & ft) const;
|
||||
|
||||
private:
|
||||
osm::Editor::FeatureStatus GetEditedStatus(uint32_t index) const
|
||||
{
|
||||
return osm::Editor::Instance().GetFeatureStatus(GetId(), index);
|
||||
}
|
||||
|
||||
template <class TFn> void ForEachIndexImpl(covering::IntervalsT const & intervals,
|
||||
uint32_t scale, TFn && fn) const
|
||||
{
|
||||
CheckUniqueIndexes checkUnique(m_value.GetHeader().GetFormat() >= version::Format::v5);
|
||||
for (auto const & i : intervals)
|
||||
m_index.ForEachInIntervalAndScale([&] (uint32_t index) { fn(index); }, i.first, i.second, scale);
|
||||
}
|
||||
|
||||
DISALLOW_COPY_AND_MOVE(MwmContext);
|
||||
|
|
Loading…
Add table
Reference in a new issue