Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'search/locality_finder.cpp')
-rw-r--r--search/locality_finder.cpp246
1 files changed, 128 insertions, 118 deletions
diff --git a/search/locality_finder.cpp b/search/locality_finder.cpp
index 92bc5251a5..5774b267a4 100644
--- a/search/locality_finder.cpp
+++ b/search/locality_finder.cpp
@@ -1,5 +1,7 @@
#include "search/locality_finder.hpp"
+#include "search/categories_cache.hpp"
+#include "search/cbv.hpp"
#include "search/dummy_rank_table.hpp"
#include "search/mwm_context.hpp"
@@ -16,20 +18,55 @@ namespace search
namespace
{
double const kMaxCityRadiusMeters = 30000.0;
-double const kInflateRectMercator = 0.001;
+
+struct Filter
+{
+public:
+ virtual ~Filter() = default;
+ virtual bool IsGood(uint32_t id) const = 0;
+};
+
+class CityFilter : public Filter
+{
+public:
+ CityFilter(RankTable const & ranks) : m_ranks(ranks) {}
+
+ // Filter overrides:
+ bool IsGood(uint32_t id) const override { return m_ranks.Get(id) != 0; }
+
+private:
+ RankTable const & m_ranks;
+};
+
+class VillageFilter : public Filter
+{
+public:
+ VillageFilter(MwmContext const & ctx, VillagesCache & villages) : m_cbv(villages.Get(ctx)) {}
+
+ // Filter overrides:
+ bool IsGood(uint32_t id) const override { return m_cbv.HasBit(id); }
+
+private:
+ CBV m_cbv;
+};
class DoLoader
{
public:
- DoLoader(MwmContext const & ctx, LocalityFinder::Cache & cache, RankTable const & ranks,
- int8_t lang)
- : m_ctx(ctx), m_cache(cache), m_ranks(ranks), m_lang(lang)
+ DoLoader(MwmContext const & ctx, Filter const & filter, int8_t lang,
+ m4::Tree<LocalityFinder::Item> & localities,
+ map<MwmSet::MwmId, unordered_set<uint32_t>> & loadedIds)
+ : m_ctx(ctx), m_filter(filter), m_lang(lang), m_localities(localities), m_loadedIds(loadedIds)
{
}
void operator()(uint32_t id) const
{
- if (m_ranks.Get(id) == 0)
+ auto const & mwmId = m_ctx.GetId();
+ if (m_loadedIds[mwmId].count(id) != 0)
+ return;
+
+ if (!m_filter.IsGood(id))
return;
FeatureType ft;
@@ -43,77 +80,53 @@ public:
switch (IsLocalityChecker::Instance().GetType(ft))
{
case CITY:
- case TOWN: break;
+ case TOWN:
+ case VILLAGE:
+ break;
default: // cache only cities and towns at this moment
return;
}
- if (m_cache.m_loadedIds.count(id) > 0)
- return;
-
uint32_t const population = ftypes::GetPopulation(ft);
if (population == 0)
return;
+ auto const center = ft.GetCenter();
double const radius = ftypes::GetRadiusByPopulation(population);
- m2::RectD const rect = MercatorBounds::RectByCenterXYAndSizeInMeters(ft.GetCenter(), radius);
- if (!rect.IsIntersect(m_cache.m_rect))
- return;
+ m2::RectD const rect = MercatorBounds::RectByCenterXYAndSizeInMeters(center, radius);
// read item
string name;
if (!ft.GetName(m_lang, name) && !ft.GetName(0, name))
return;
- LocalityItem item(name, population, id);
- m_cache.m_tree.Add(item, rect);
- m_cache.m_loadedIds.insert(id);
+ LocalityFinder::Item item(name, center, population);
+ m_localities.Add(item, rect);
+ m_loadedIds[mwmId].insert(id);
}
private:
MwmContext const & m_ctx;
- LocalityFinder::Cache & m_cache;
- RankTable const & m_ranks;
+ Filter const & m_filter;
int8_t const m_lang;
-};
-
-class DoSelectLocality
-{
-public:
- DoSelectLocality(string & name, m2::PointD const & pt)
- : m_name(name), m_pt(pt), m_bestScore(numeric_limits<double>::max())
- {
- }
-
- void operator()(m2::RectD const & rect, LocalityItem const & item)
- {
- // TODO (@y, @m): replace this naive score by p-values on
- // multivariate Gaussian.
- double const distanceMeters = MercatorBounds::DistanceOnEarth(rect.Center(), m_pt);
- double const score =
- ftypes::GetPopulationByRadius(distanceMeters) / static_cast<double>(item.m_population);
- if (score < m_bestScore)
- {
- m_bestScore = score;
- m_name = item.m_name;
- }
- }
-private:
- string & m_name;
- m2::PointD m_pt;
- double m_bestScore;
+ m4::Tree<LocalityFinder::Item> & m_localities;
+ map<MwmSet::MwmId, unordered_set<uint32_t>> & m_loadedIds;
};
} // namespace
-// LocalityItem ------------------------------------------------------------------------------------
-LocalityItem::LocalityItem(string const & name, uint32_t population, uint32_t id)
- : m_name(name), m_population(population), m_id(id)
+// LocalityFinder::Item
+// ------------------------------------------------------------------------------------
+LocalityFinder::Item::Item(string const & name, m2::PointD const & center, uint32_t population)
+ : m_name(name), m_center(center), m_population(population)
{
}
// LocalityFinder ----------------------------------------------------------------------------------
-LocalityFinder::LocalityFinder(Index const & index) : m_index(index), m_lang(0) {}
+LocalityFinder::LocalityFinder(Index const & index, VillagesCache & villagesCache)
+ : m_index(index), m_villagesCache(villagesCache), m_lang(0)
+{
+}
void LocalityFinder::SetLanguage(int8_t lang)
{
@@ -124,101 +137,98 @@ void LocalityFinder::SetLanguage(int8_t lang)
m_lang = lang;
}
-void LocalityFinder::UpdateCache(Cache & cache, m2::PointD const & pt)
+void LocalityFinder::GetLocality(m2::PointD const & pt, string & name)
{
- m2::RectD rect = MercatorBounds::RectByCenterXYAndSizeInMeters(pt, kMaxCityRadiusMeters);
- if (cache.m_rect.IsRectInside(rect))
- return;
+ m2::RectD const rect = MercatorBounds::RectByCenterXYAndSizeInMeters(pt, kMaxCityRadiusMeters);
- rect.Add(cache.m_rect);
- rect.Inflate(kInflateRectMercator, kInflateRectMercator);
+ bool covered = false;
+ m_coverage.ForEachInRect(rect, [&covered](bool) { covered = true; });
+ if (!covered)
+ LoadVicinity(pt);
- if (!m_worldId.IsAlive())
- {
- m_worldId.Reset();
- m_ranks.reset();
-
- vector<shared_ptr<MwmInfo>> mwmsInfo;
- m_index.GetMwmsInfo(mwmsInfo);
- for (auto const & info : mwmsInfo)
- {
- MwmSet::MwmId id(info);
- Index::MwmHandle handle = m_index.GetMwmHandleById(id);
- MwmValue const * value = handle.GetValue<MwmValue>();
- if (handle.IsAlive() && value->GetHeader().GetType() == feature::DataHeader::world)
- {
- m_worldId = id;
- m_ranks = RankTable::Load(value->m_cont);
- break;
- }
- }
-
- if (!m_ranks)
- m_ranks = make_unique<DummyRankTable>();
- }
-
- ASSERT(m_ranks.get(), ());
-
- Index::MwmHandle handle = m_index.GetMwmHandleById(m_worldId);
- if (!handle.IsAlive())
- return;
+ m_localities.ForEachInRect(rect, LocalitySelector(name, pt));
+}
- cache.m_rect = rect;
- MwmContext ctx(move(handle));
- ctx.ForEachIndex(rect, DoLoader(ctx, cache, *m_ranks, m_lang));
+void LocalityFinder::ClearCache()
+{
+ m_ranks.reset();
+ m_coverage.Clear();
+ m_localities.Clear();
+ m_loadedIds.clear();
}
-void LocalityFinder::GetLocality(m2::PointD const & pt, string & name)
+void LocalityFinder::LoadVicinity(m2::PointD const & pt)
{
- Cache * working = nullptr;
+ m2::RectD const drect =
+ MercatorBounds::RectByCenterXYAndSizeInMeters(pt, 2 * kMaxCityRadiusMeters);
- // Find suitable cache that includes needed point.
- for (auto & cache : m_caches)
+ vector<shared_ptr<MwmInfo>> mwmsInfo;
+ m_index.GetMwmsInfo(mwmsInfo);
+ for (auto const & info : mwmsInfo)
{
- if (cache.m_rect.IsPointInside(pt))
+ MwmSet::MwmId id(info);
+ Index::MwmHandle handle = m_index.GetMwmHandleById(id);
+
+ if (!handle.IsAlive())
+ continue;
+
+ MwmValue const & value = *handle.GetValue<MwmValue>();
+ auto const & header = value.GetHeader();
+ switch (header.GetType())
+ {
+ case feature::DataHeader::world:
{
- working = &cache;
+ if (!m_ranks)
+ m_ranks = RankTable::Load(value.m_cont);
+ if (!m_ranks)
+ m_ranks = make_unique<DummyRankTable>();
+
+ MwmContext ctx(move(handle));
+ ctx.ForEachIndex(drect,
+ DoLoader(ctx, CityFilter(*m_ranks), m_lang, m_localities, m_loadedIds));
break;
}
+ case feature::DataHeader::country:
+ if (header.GetBounds().IsPointInside(pt))
+ {
+ MwmContext ctx(move(handle));
+ ctx.ForEachIndex(drect, DoLoader(ctx, VillageFilter(ctx, m_villagesCache), m_lang,
+ m_localities, m_loadedIds));
+ }
+ break;
+ case feature::DataHeader::worldcoasts: break;
+ }
}
- if (working == nullptr)
- {
- // Find most unused cache.
- working =
- &*min_element(begin(m_caches), end(m_caches), my::LessBy(&LocalityFinder::Cache::m_usage));
- working->Clear();
- }
-
- UpdateCache(*working, pt);
- working->GetLocality(pt, name);
+ m_coverage.Add(true, m2::RectD(pt, pt));
}
-void LocalityFinder::ClearCache()
+// LocalitySelector --------------------------------------------------------------------------------
+LocalitySelector::LocalitySelector(string & name, m2::PointD const & pt)
+ : m_name(name), m_pt(pt), m_bestScore(numeric_limits<double>::max())
{
- for (auto & cache : m_caches)
- cache.Clear();
}
-// LocalityFinder::Cache ---------------------------------------------------------------------------
-void LocalityFinder::Cache::Clear()
+void LocalitySelector::operator()(LocalityFinder::Item const & item)
{
- m_usage = 0;
- m_tree.Clear();
- m_loadedIds.clear();
- m_rect.MakeEmpty();
-}
+ // TODO (@y, @m): replace this naive score by p-values on
+ // multivariate Gaussian.
+ double const distance = MercatorBounds::DistanceOnEarth(item.m_center, m_pt);
-void LocalityFinder::Cache::GetLocality(m2::PointD const & pt, string & name)
-{
- ++m_usage;
- m_tree.ForEachInRectEx(m2::RectD(pt, pt), DoSelectLocality(name, pt));
+ double const score =
+ ftypes::GetPopulationByRadius(distance) / static_cast<double>(item.m_population);
+ if (score < m_bestScore)
+ {
+ m_bestScore = score;
+ m_name = item.m_name;
+ }
}
-string DebugPrint(LocalityItem const & item)
+string DebugPrint(LocalityFinder::Item const & item)
{
stringstream ss;
- ss << "Name = " << item.m_name << "Population = " << item.m_population << "ID = " << item.m_id;
+ ss << "Name = " << item.m_name << ", Center = " << DebugPrint(item.m_center)
+ << ", Population = " << item.m_population;
return ss.str();
}
} // namespace search