forked from organicmaps/organicmaps
[search] Implemented intersection of POI and STREET layers.
This commit is contained in:
parent
6e6279c4d3
commit
2adf4dc9df
13 changed files with 266 additions and 28 deletions
|
@ -47,6 +47,7 @@ HEADERS += \
|
|||
v2/geocoder.hpp \
|
||||
v2/search_model.hpp \
|
||||
v2/search_query_v2.hpp \
|
||||
v2/street_vicinity_loader.hpp \
|
||||
|
||||
SOURCES += \
|
||||
approximate_string_match.cpp \
|
||||
|
@ -77,3 +78,4 @@ SOURCES += \
|
|||
v2/geocoder.cpp \
|
||||
v2/search_model.cpp \
|
||||
v2/search_query_v2.cpp \
|
||||
v2/street_vicinity_loader.cpp \
|
||||
|
|
|
@ -54,7 +54,10 @@ UNIT_TEST(SearchQueryV2_Smoke)
|
|||
m2::RectD viewport(m2::PointD(-1.0, -1.0), m2::PointD(1.0, 1.0));
|
||||
|
||||
Cleanup(map);
|
||||
MY_SCOPE_GUARD(cleanup, [&]() { Cleanup(map); });
|
||||
MY_SCOPE_GUARD(cleanup, [&]()
|
||||
{
|
||||
Cleanup(map);
|
||||
});
|
||||
|
||||
vector<storage::CountryDef> countries;
|
||||
countries.emplace_back(map.GetCountryName(), viewport);
|
||||
|
@ -69,6 +72,9 @@ UNIT_TEST(SearchQueryV2_Smoke)
|
|||
auto const quantumTeleport2 =
|
||||
make_shared<TestPOI>(m2::PointD(10, 10), "Quantum teleport 2", "en");
|
||||
auto const quantumCafe = make_shared<TestPOI>(m2::PointD(-0.0002, -0.0002), "Quantum cafe", "en");
|
||||
auto const faynmannStreet = make_shared<TestStreet>(
|
||||
vector<m2::PointD>{m2::PointD(9.999, 9.999), m2::PointD(10, 10), m2::PointD(10.001, 10.001)},
|
||||
"Faynmann street", "en");
|
||||
|
||||
{
|
||||
TestMwmBuilder builder(map, feature::DataHeader::country);
|
||||
|
@ -78,6 +84,7 @@ UNIT_TEST(SearchQueryV2_Smoke)
|
|||
builder.Add(*quantumTeleport1);
|
||||
builder.Add(*quantumTeleport2);
|
||||
builder.Add(*quantumCafe);
|
||||
builder.Add(*faynmannStreet);
|
||||
}
|
||||
|
||||
auto const regResult = engine.RegisterMap(map);
|
||||
|
@ -114,4 +121,13 @@ UNIT_TEST(SearchQueryV2_Smoke)
|
|||
request.Wait();
|
||||
TEST_EQUAL(0, request.Results().size(), ());
|
||||
}
|
||||
|
||||
{
|
||||
TestSearchRequest request(engine, "teleport faynmann street", "en", search::SearchParams::ALL,
|
||||
viewport);
|
||||
request.Wait();
|
||||
vector<shared_ptr<MatchingRule>> rules = {
|
||||
make_shared<ExactMatch>(regResult.first, quantumTeleport2)};
|
||||
TEST(MatchResults(engine, rules, request.Results()), ());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ namespace search
|
|||
{
|
||||
namespace tests_support
|
||||
{
|
||||
TestFeature::TestFeature(string const & name, string const & lang) : m_name(name), m_lang(lang) {}
|
||||
|
||||
TestFeature::TestFeature(m2::PointD const & center, string const & name, string const & lang)
|
||||
: m_center(center), m_name(name), m_lang(lang)
|
||||
{
|
||||
|
@ -33,6 +35,7 @@ bool TestFeature::Matches(FeatureType const & feature) const
|
|||
return feature.GetName(langIndex, name) && m_name == name;
|
||||
}
|
||||
|
||||
// TestPOI -----------------------------------------------------------------------------------------
|
||||
TestPOI::TestPOI(m2::PointD const & center, string const & name, string const & lang)
|
||||
: TestFeature(center, name, lang)
|
||||
{
|
||||
|
@ -52,6 +55,7 @@ string TestPOI::ToString() const
|
|||
return os.str();
|
||||
}
|
||||
|
||||
// TestCity ----------------------------------------------------------------------------------------
|
||||
TestCity::TestCity(m2::PointD const & center, string const & name, string const & lang,
|
||||
uint8_t rank)
|
||||
: TestFeature(center, name, lang), m_rank(rank)
|
||||
|
@ -73,6 +77,31 @@ string TestCity::ToString() const
|
|||
return os.str();
|
||||
}
|
||||
|
||||
// TestStreet --------------------------------------------------------------------------------------
|
||||
TestStreet::TestStreet(vector<m2::PointD> const & points, string const & name, string const & lang)
|
||||
: TestFeature(name, lang), m_points(points)
|
||||
{
|
||||
}
|
||||
|
||||
void TestStreet::Serialize(FeatureBuilder1 & fb) const
|
||||
{
|
||||
CHECK(fb.AddName(m_lang, m_name), ("Can't set feature name:", m_name, "(", m_lang, ")"));
|
||||
|
||||
auto const & classificator = classif();
|
||||
fb.SetType(classificator.GetTypeByPath({"highway", "living_street"}));
|
||||
|
||||
for (auto const & point : m_points)
|
||||
fb.AddPoint(point);
|
||||
fb.SetLinear(false /* reverseGeometry */);
|
||||
}
|
||||
|
||||
string TestStreet::ToString() const
|
||||
{
|
||||
ostringstream os;
|
||||
os << "TestStreet [" << m_name << ", " << m_lang << ", " << ::DebugPrint(m_points) << "]";
|
||||
return os.str();
|
||||
}
|
||||
|
||||
string DebugPrint(TestFeature const & feature) { return feature.ToString(); }
|
||||
} // namespace tests_support
|
||||
} // namespace search
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "geometry/point2d.hpp"
|
||||
|
||||
#include "std/string.hpp"
|
||||
#include "std/vector.hpp"
|
||||
|
||||
class FeatureBuilder1;
|
||||
class FeatureType;
|
||||
|
@ -21,6 +22,7 @@ public:
|
|||
virtual string ToString() const = 0;
|
||||
|
||||
protected:
|
||||
TestFeature(string const & name, string const & lang);
|
||||
TestFeature(m2::PointD const & center, string const & name, string const & lang);
|
||||
|
||||
m2::PointD const m_center;
|
||||
|
@ -51,6 +53,19 @@ private:
|
|||
uint8_t const m_rank;
|
||||
};
|
||||
|
||||
class TestStreet : public TestFeature
|
||||
{
|
||||
public:
|
||||
TestStreet(vector<m2::PointD> const & points, string const & name, string const & lang);
|
||||
|
||||
// TestFeature overrides:
|
||||
void Serialize(FeatureBuilder1 & fb) const override;
|
||||
string ToString() const override;
|
||||
|
||||
private:
|
||||
vector<m2::PointD> m_points;
|
||||
};
|
||||
|
||||
string DebugPrint(TestFeature const & feature);
|
||||
} // namespace tests_support
|
||||
} // namespace search
|
||||
|
|
|
@ -12,7 +12,7 @@ FeaturesLayer::FeaturesLayer() { Clear(); }
|
|||
|
||||
void FeaturesLayer::Clear()
|
||||
{
|
||||
m_features.clear();
|
||||
m_sortedFeatures.clear();
|
||||
m_startToken = 0;
|
||||
m_endToken = 0;
|
||||
m_type = SearchModel::SEARCH_TYPE_COUNT;
|
||||
|
@ -21,7 +21,7 @@ void FeaturesLayer::Clear()
|
|||
string DebugPrint(FeaturesLayer const & layer)
|
||||
{
|
||||
ostringstream os;
|
||||
os << "FeaturesLayer [ m_features: " << ::DebugPrint(layer.m_features)
|
||||
os << "FeaturesLayer [ m_sortedFeatures: " << ::DebugPrint(layer.m_sortedFeatures)
|
||||
<< ", m_startToken: " << layer.m_startToken << ", m_endToken: " << layer.m_endToken
|
||||
<< ", m_type: " << DebugPrint(layer.m_type) << " ]";
|
||||
return os.str();
|
||||
|
|
|
@ -17,7 +17,7 @@ struct FeaturesLayer
|
|||
|
||||
void Clear();
|
||||
|
||||
vector<uint32_t> m_features;
|
||||
vector<uint32_t> m_sortedFeatures;
|
||||
size_t m_startToken;
|
||||
size_t m_endToken;
|
||||
SearchModel::SearchType m_type;
|
||||
|
|
|
@ -4,8 +4,13 @@ namespace search
|
|||
{
|
||||
namespace v2
|
||||
{
|
||||
FeaturesLayerMatcher::FeaturesLayerMatcher(FeaturesVector const & featuresVector)
|
||||
: m_featuresVector(featuresVector)
|
||||
namespace
|
||||
{
|
||||
static double constexpr kDefaultRadiusMeters = 200;
|
||||
} // namespace
|
||||
|
||||
FeaturesLayerMatcher::FeaturesLayerMatcher(MwmValue & value, FeaturesVector const & featuresVector)
|
||||
: m_featuresVector(featuresVector), m_loader(value, featuresVector, kDefaultRadiusMeters)
|
||||
{
|
||||
}
|
||||
} // namespace v2
|
||||
|
|
|
@ -2,11 +2,13 @@
|
|||
|
||||
#include "search/v2/features_layer.hpp"
|
||||
#include "search/v2/search_model.hpp"
|
||||
#include "search/v2/street_vicinity_loader.hpp"
|
||||
|
||||
#include "indexer/feature.hpp"
|
||||
#include "indexer/feature_algo.hpp"
|
||||
#include "indexer/features_vector.hpp"
|
||||
#include "indexer/ftypes_matcher.hpp"
|
||||
#include "indexer/scales.hpp"
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
#include "geometry/point2d.hpp"
|
||||
|
@ -14,8 +16,11 @@
|
|||
|
||||
#include "base/macros.hpp"
|
||||
|
||||
#include "std/algorithm.hpp"
|
||||
#include "std/vector.hpp"
|
||||
|
||||
class MwmValue;
|
||||
|
||||
namespace search
|
||||
{
|
||||
namespace v2
|
||||
|
@ -23,24 +28,24 @@ namespace v2
|
|||
class FeaturesLayerMatcher
|
||||
{
|
||||
public:
|
||||
FeaturesLayerMatcher(FeaturesVector const & featuresVector);
|
||||
FeaturesLayerMatcher(MwmValue & value, FeaturesVector const & featuresVector);
|
||||
|
||||
template <typename TFn>
|
||||
void Match(FeaturesLayer const & child, FeaturesLayer const & parent, TFn && fn) const
|
||||
void Match(FeaturesLayer const & child, FeaturesLayer const & parent, TFn && fn)
|
||||
{
|
||||
if (child.m_type >= parent.m_type)
|
||||
return;
|
||||
if (child.m_type == SearchModel::SEARCH_TYPE_BUILDING &&
|
||||
parent.m_type == SearchModel::SEARCH_TYPE_STREET)
|
||||
if (parent.m_type == SearchModel::SEARCH_TYPE_STREET)
|
||||
{
|
||||
// TODO (y@): match buildings with streets.
|
||||
if (child.m_type == SearchModel::SEARCH_TYPE_POI)
|
||||
MatchPOIsWithStreets(child, parent, forward<TFn>(fn));
|
||||
else if (child.m_type == SearchModel::SEARCH_TYPE_BUILDING)
|
||||
MatchBuildingsWithStreets(child, parent, forward<TFn>(fn));
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO (y@): match POI with streets separately.
|
||||
|
||||
vector<m2::PointD> childCenters;
|
||||
for (uint32_t featureId : child.m_features)
|
||||
for (uint32_t featureId : child.m_sortedFeatures)
|
||||
{
|
||||
FeatureType ft;
|
||||
m_featuresVector.GetByIndex(featureId, ft);
|
||||
|
@ -48,7 +53,7 @@ public:
|
|||
}
|
||||
|
||||
vector<m2::RectD> parentRects;
|
||||
for (uint32_t featureId : parent.m_features)
|
||||
for (uint32_t featureId : parent.m_sortedFeatures)
|
||||
{
|
||||
FeatureType feature;
|
||||
m_featuresVector.GetByIndex(featureId, feature);
|
||||
|
@ -57,9 +62,9 @@ public:
|
|||
parentRects.push_back(MercatorBounds::RectByCenterXYAndSizeInMeters(center, radius));
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < parent.m_features.size(); ++j)
|
||||
for (size_t j = 0; j < parent.m_sortedFeatures.size(); ++j)
|
||||
{
|
||||
for (size_t i = 0; i < child.m_features.size(); ++i)
|
||||
for (size_t i = 0; i < child.m_sortedFeatures.size(); ++i)
|
||||
{
|
||||
if (parentRects[j].IsPointInside(childCenters[i]))
|
||||
fn(i, j);
|
||||
|
@ -68,7 +73,42 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
template <typename TFn>
|
||||
void MatchPOIsWithStreets(FeaturesLayer const & child, FeaturesLayer const & parent, TFn && fn)
|
||||
{
|
||||
ASSERT_EQUAL(child.m_type, SearchModel::SEARCH_TYPE_POI, ());
|
||||
ASSERT_EQUAL(parent.m_type, SearchModel::SEARCH_TYPE_STREET, ());
|
||||
|
||||
for (size_t j = 0; j < parent.m_sortedFeatures.size(); ++j)
|
||||
{
|
||||
auto match = [&](uint32_t poiId)
|
||||
{
|
||||
auto const it =
|
||||
lower_bound(child.m_sortedFeatures.begin(), child.m_sortedFeatures.end(), poiId);
|
||||
if (it != child.m_sortedFeatures.end() && *it == poiId)
|
||||
{
|
||||
size_t i = distance(child.m_sortedFeatures.begin(), it);
|
||||
fn(i, j);
|
||||
}
|
||||
};
|
||||
|
||||
m_loader.ForEachInVicinity(parent.m_sortedFeatures[j], scales::GetUpperScale(), match);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename TFn>
|
||||
void MatchBuildingsWithStreets(FeaturesLayer const & child, FeaturesLayer const & parent,
|
||||
TFn && fn)
|
||||
{
|
||||
ASSERT_EQUAL(child.m_type, SearchModel::SEARCH_TYPE_BUILDING, ());
|
||||
ASSERT_EQUAL(parent.m_type, SearchModel::SEARCH_TYPE_STREET, ());
|
||||
|
||||
// TODO (@y): implement this
|
||||
NOTIMPLEMENTED();
|
||||
}
|
||||
|
||||
FeaturesVector const & m_featuresVector;
|
||||
StreetVicinityLoader m_loader;
|
||||
};
|
||||
} // namespace v2
|
||||
} // namespace search
|
||||
|
|
|
@ -8,8 +8,9 @@ namespace search
|
|||
{
|
||||
namespace v2
|
||||
{
|
||||
FeaturesLayerPathFinder::FeaturesLayerPathFinder(FeaturesVector const & featuresVector)
|
||||
: m_matcher(featuresVector)
|
||||
FeaturesLayerPathFinder::FeaturesLayerPathFinder(MwmValue & value,
|
||||
FeaturesVector const & featuresVector)
|
||||
: m_matcher(value, featuresVector)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -23,7 +24,7 @@ void FeaturesLayerPathFinder::BuildGraph(vector<FeaturesLayer *> const & layers)
|
|||
auto & parent = (*layers[i + 1]);
|
||||
auto addEdges = [&](uint32_t from, uint32_t to)
|
||||
{
|
||||
m_graph[parent.m_features[to]].push_back(child.m_features[from]);
|
||||
m_graph[parent.m_sortedFeatures[to]].push_back(child.m_sortedFeatures[from]);
|
||||
};
|
||||
m_matcher.Match(child, parent, addEdges);
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "std/vector.hpp"
|
||||
|
||||
class FeaturesVector;
|
||||
class MwmValue;
|
||||
|
||||
namespace search
|
||||
{
|
||||
|
@ -20,7 +21,7 @@ public:
|
|||
using TAdjList = vector<uint32_t>;
|
||||
using TLayerGraph = unordered_map<uint32_t, TAdjList>;
|
||||
|
||||
FeaturesLayerPathFinder(FeaturesVector const & featuresVector);
|
||||
FeaturesLayerPathFinder(MwmValue & value, FeaturesVector const & featuresVector);
|
||||
|
||||
template <typename TFn>
|
||||
void ForEachReachableVertex(vector<FeaturesLayer *> const & layers, TFn && fn)
|
||||
|
@ -31,10 +32,10 @@ public:
|
|||
BuildGraph(layers);
|
||||
|
||||
m_visited.clear();
|
||||
for (uint32_t featureId : (*layers.back()).m_features)
|
||||
for (uint32_t featureId : (*layers.back()).m_sortedFeatures)
|
||||
Dfs(featureId);
|
||||
|
||||
for (uint32_t featureId : (*layers.front()).m_features)
|
||||
for (uint32_t featureId : (*layers.front()).m_sortedFeatures)
|
||||
{
|
||||
if (m_visited.count(featureId) != 0)
|
||||
fn(featureId);
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "search/search_string_utils.hpp"
|
||||
|
||||
#include "indexer/feature_decl.hpp"
|
||||
#include "indexer/feature_impl.hpp"
|
||||
#include "indexer/index.hpp"
|
||||
|
||||
#include "coding/multilang_utf8_string.hpp"
|
||||
|
@ -25,6 +26,30 @@ namespace search
|
|||
{
|
||||
namespace v2
|
||||
{
|
||||
namespace
|
||||
{
|
||||
void JoinQueryTokens(SearchQueryParams const & params, size_t curToken, size_t endToken,
|
||||
string const & sep, string & res)
|
||||
{
|
||||
ASSERT_LESS_OR_EQUAL(curToken, endToken, ());
|
||||
for (size_t i = curToken; i < endToken; ++i)
|
||||
{
|
||||
if (i < params.m_tokens.size())
|
||||
{
|
||||
res.append(strings::ToUtf8(params.m_tokens[i].front()));
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT_EQUAL(i, params.m_tokens.size(), ());
|
||||
res.append(strings::ToUtf8(params.m_prefixTokens.front()));
|
||||
}
|
||||
|
||||
if (i + 1 != endToken)
|
||||
res.append(sep);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
Geocoder::Geocoder(Index & index)
|
||||
: m_index(index)
|
||||
, m_numTokens(0)
|
||||
|
@ -79,7 +104,7 @@ void Geocoder::Go(vector<FeatureID> & results)
|
|||
});
|
||||
|
||||
m_loader.reset(new Index::FeaturesLoaderGuard(m_index, m_mwmId));
|
||||
m_finder.reset(new FeaturesLayerPathFinder(m_loader->GetFeaturesVector()));
|
||||
m_finder.reset(new FeaturesLayerPathFinder(*m_value, m_loader->GetFeaturesVector()));
|
||||
m_cache.clear();
|
||||
|
||||
DoGeocoding(0 /* curToken */);
|
||||
|
@ -172,7 +197,8 @@ void Geocoder::DoGeocoding(size_t curToken)
|
|||
// DoGeocoding(). This may lead to use-after-free.
|
||||
auto & layer = m_layers.back();
|
||||
|
||||
layer.m_features.swap(clusters[i]);
|
||||
layer.m_sortedFeatures.swap(clusters[i]);
|
||||
ASSERT(is_sorted(layer.m_sortedFeatures.begin(), layer.m_sortedFeatures.end()), ());
|
||||
layer.m_type = static_cast<SearchModel::SearchType>(i);
|
||||
if (IsLayerSequenceSane())
|
||||
DoGeocoding(curToken + n);
|
||||
|
@ -213,9 +239,11 @@ bool Geocoder::IsLayerSequenceSane() const
|
|||
|
||||
bool Geocoder::LooksLikeHouseNumber(size_t curToken, size_t endToken) const
|
||||
{
|
||||
// TODO (@y): implement this.
|
||||
// NOTIMPLEMENTED();
|
||||
return false;
|
||||
string res;
|
||||
JoinQueryTokens(m_params, curToken, endToken, " " /* sep */, res);
|
||||
|
||||
// TODO (@y): we need to implement a better check here.
|
||||
return feature::IsHouseNumber(res);
|
||||
}
|
||||
|
||||
void Geocoder::FindPaths()
|
||||
|
|
50
search/v2/street_vicinity_loader.cpp
Normal file
50
search/v2/street_vicinity_loader.cpp
Normal file
|
@ -0,0 +1,50 @@
|
|||
#include "search/v2/street_vicinity_loader.hpp"
|
||||
|
||||
#include "indexer/feature.hpp"
|
||||
#include "indexer/feature_decl.hpp"
|
||||
#include "indexer/features_vector.hpp"
|
||||
#include "indexer/index.hpp"
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
|
||||
namespace search
|
||||
{
|
||||
namespace
|
||||
{
|
||||
m2::RectD GetStreetLimitRect(FeatureType const & feature, double offsetMeters)
|
||||
{
|
||||
m2::RectD rect;
|
||||
if (feature.GetFeatureType() != feature::GEOM_LINE)
|
||||
return rect;
|
||||
|
||||
auto expandRect = [&rect, &offsetMeters](m2::PointD const & point)
|
||||
{
|
||||
rect.Add(MercatorBounds::RectByCenterXYAndSizeInMeters(point, offsetMeters));
|
||||
};
|
||||
feature.ForEachPoint(expandRect, FeatureType::BEST_GEOMETRY);
|
||||
return rect;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
StreetVicinityLoader::StreetVicinityLoader(MwmValue & value, FeaturesVector const & featuresVector,
|
||||
double offsetMeters)
|
||||
: m_index(value.m_cont.GetReader(INDEX_FILE_TAG), value.m_factory)
|
||||
, m_scaleRange(value.GetHeader().GetScaleRange())
|
||||
, m_featuresVector(featuresVector)
|
||||
, m_offsetMeters(offsetMeters)
|
||||
{
|
||||
}
|
||||
|
||||
m2::RectD StreetVicinityLoader::GetLimitRect(uint32_t featureId)
|
||||
{
|
||||
auto it = m_cache.find(featureId);
|
||||
if (it != m_cache.end())
|
||||
return it->second;
|
||||
|
||||
FeatureType feature;
|
||||
m_featuresVector.GetByIndex(featureId, feature);
|
||||
m2::RectD rect = GetStreetLimitRect(feature, m_offsetMeters);
|
||||
m_cache[featureId] = rect;
|
||||
return rect;
|
||||
}
|
||||
} // namespace search
|
51
search/v2/street_vicinity_loader.hpp
Normal file
51
search/v2/street_vicinity_loader.hpp
Normal file
|
@ -0,0 +1,51 @@
|
|||
#pragma once
|
||||
|
||||
#include "indexer/feature_covering.hpp"
|
||||
#include "indexer/scale_index.hpp"
|
||||
|
||||
#include "coding/reader.hpp"
|
||||
|
||||
#include "geometry/rect2d.hpp"
|
||||
|
||||
#include "std/unordered_map.hpp"
|
||||
|
||||
class MwmValue;
|
||||
class FeaturesVector;
|
||||
|
||||
namespace search
|
||||
{
|
||||
class StreetVicinityLoader
|
||||
{
|
||||
public:
|
||||
StreetVicinityLoader(MwmValue & value, FeaturesVector const & featuresVector,
|
||||
double offsetMeters);
|
||||
|
||||
template <typename TFn>
|
||||
void ForEachInVicinity(uint32_t featureId, int scale, TFn const & fn)
|
||||
{
|
||||
m2::RectD const rect = GetLimitRect(featureId);
|
||||
if (rect.IsEmptyInterior())
|
||||
return;
|
||||
|
||||
scale = min(max(scale, m_scaleRange.first), m_scaleRange.second);
|
||||
covering::CoveringGetter coveringGetter(rect, covering::ViewportWithLowLevels);
|
||||
auto const & intervals = coveringGetter.Get(scale);
|
||||
for (auto const & interval : intervals)
|
||||
m_index.ForEachInIntervalAndScale(fn, interval.first, interval.second, scale);
|
||||
}
|
||||
|
||||
inline void ClearCache() { m_cache.clear(); }
|
||||
|
||||
private:
|
||||
m2::RectD GetLimitRect(uint32_t featureId);
|
||||
|
||||
ScaleIndex<ModelReaderPtr> m_index;
|
||||
pair<int, int> m_scaleRange;
|
||||
|
||||
FeaturesVector const & m_featuresVector;
|
||||
|
||||
double const m_offsetMeters;
|
||||
|
||||
unordered_map<uint32_t, m2::RectD> m_cache;
|
||||
};
|
||||
} // namespace search
|
Loading…
Add table
Reference in a new issue