diff options
author | Arsentiy Milchakov <milcars@mapswithme.com> | 2018-06-19 14:16:22 +0300 |
---|---|---|
committer | Vlad Mihaylenko <vxmihaylenko@gmail.com> | 2018-06-19 19:27:18 +0300 |
commit | c701d2d7be6e0890d5cd2518942ba45b9aaae3f6 (patch) | |
tree | dc1801ac95460808d2e63578a619ed8825572109 /storage | |
parent | 360fdd2db0e107450029fbca6957019c95c57c52 (diff) |
[storage][lightweight] added lightweight country info reader.
Diffstat (limited to 'storage')
-rw-r--r-- | storage/CMakeLists.txt | 2 | ||||
-rw-r--r-- | storage/country_info_getter.cpp | 90 | ||||
-rw-r--r-- | storage/country_info_getter.hpp | 75 | ||||
-rw-r--r-- | storage/country_info_reader_light.cpp | 78 | ||||
-rw-r--r-- | storage/country_info_reader_light.hpp | 36 | ||||
-rw-r--r-- | storage/storage_integration_tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | storage/storage_integration_tests/lightweight_matching_tests.cpp | 58 |
7 files changed, 263 insertions, 77 deletions
diff --git a/storage/CMakeLists.txt b/storage/CMakeLists.txt index 6f0c13478f..43249852a5 100644 --- a/storage/CMakeLists.txt +++ b/storage/CMakeLists.txt @@ -13,6 +13,8 @@ set( country_info_getter.hpp country_name_getter.cpp country_name_getter.hpp + country_info_reader_light.cpp + country_info_reader_light.hpp country_parent_getter.cpp country_parent_getter.hpp country_polygon.hpp diff --git a/storage/country_info_getter.cpp b/storage/country_info_getter.cpp index 2dadcf3149..4da112944d 100644 --- a/storage/country_info_getter.cpp +++ b/storage/country_info_getter.cpp @@ -50,13 +50,59 @@ private: }; } // namespace -// CountryInfoGetter ------------------------------------------------------------------------------- -TCountryId CountryInfoGetter::GetRegionCountryId(m2::PointD const & pt) const +// CountryInfoGetterBase --------------------------------------------------------------------------------- +TCountryId CountryInfoGetterBase::GetRegionCountryId(m2::PointD const & pt) const { TRegionId const id = FindFirstCountry(pt); return id != kInvalidId ? m_countries[id].m_countryId : kInvalidCountryId; } +bool CountryInfoGetterBase::IsBelongToRegions(m2::PointD const & pt, + TRegionIdSet const & regions) const +{ + for (auto const & id : regions) + { + if (m_countries[id].m_rect.IsPointInside(pt) && IsBelongToRegionImpl(id, pt)) + return true; + } + return false; +} + +bool CountryInfoGetterBase::IsBelongToRegions(TCountryId const & countryId, + TRegionIdSet const & regions) const +{ + for (auto const & id : regions) + { + if (m_countries[id].m_countryId == countryId) + return true; + } + return false; +} + +void CountryInfoGetterBase::RegionIdsToCountryIds(TRegionIdSet const & regions, + TCountriesVec & countries) const +{ + for (auto const & id : regions) + countries.push_back(m_countries[id].m_countryId); +} + +CountryInfoGetterBase::TRegionId CountryInfoGetterBase::FindFirstCountry(m2::PointD const & pt) const +{ + for (size_t id = 0; id < m_countries.size(); ++id) + { + if (m_countries[id].m_rect.IsPointInside(pt) && IsBelongToRegionImpl(id, pt)) + return id; + } + + ms::LatLon const latLon = MercatorBounds::ToLatLon(pt); + alohalytics::LogEvent(m_isSingleMwm + ? "Small mwm case. CountryInfoGetter could not find any mwm by point." + : "Big mwm case. CountryInfoGetter could not find any mwm by point.", + alohalytics::Location::FromLatLon(latLon.lat, latLon.lon)); + return kInvalidId; +} + +// CountryInfoGetter ------------------------------------------------------------------------------- vector<TCountryId> CountryInfoGetter::GetRegionsCountryIdByRect(m2::RectD const & rect, bool rough) const { size_t constexpr kAverageSize = 10; @@ -149,52 +195,12 @@ void CountryInfoGetter::GetMatchedRegions(string const & affiliation, TRegionIdS regions.push_back(i); } } - -bool CountryInfoGetter::IsBelongToRegions(m2::PointD const & pt, TRegionIdSet const & regions) const -{ - for (auto const & id : regions) - { - if (m_countries[id].m_rect.IsPointInside(pt) && IsBelongToRegionImpl(id, pt)) - return true; - } - return false; -} - -bool CountryInfoGetter::IsBelongToRegions(TCountryId const & countryId, TRegionIdSet const & regions) const -{ - for (auto const & id : regions) - { - if (m_countries[id].m_countryId == countryId) - return true; - } - return false; -} - -void CountryInfoGetter::RegionIdsToCountryIds(TRegionIdSet const & regions, TCountriesVec & countries) const -{ - for (auto const & id : regions) - countries.push_back(m_countries[id].m_countryId); -} void CountryInfoGetter::InitAffiliationsInfo(TMappingAffiliations const * affiliations) { m_affiliations = affiliations; } -CountryInfoGetter::TRegionId CountryInfoGetter::FindFirstCountry(m2::PointD const & pt) const -{ - for (size_t id = 0; id < m_countries.size(); ++id) - { - if (m_countries[id].m_rect.IsPointInside(pt) && IsBelongToRegionImpl(id, pt)) - return id; - } - - ms::LatLon const latLon = MercatorBounds::ToLatLon(pt); - alohalytics::LogEvent(m_isSingleMwm ? "Small mwm case. CountryInfoGetter could not find any mwm by point." - : "Big mwm case. CountryInfoGetter could not find any mwm by point.", - alohalytics::Location::FromLatLon(latLon.lat, latLon.lon)); - return kInvalidId; -} template <typename ToDo> void CountryInfoGetter::ForEachCountry(string const & prefix, ToDo && toDo) const diff --git a/storage/country_info_getter.hpp b/storage/country_info_getter.hpp index a53af3fed1..c3b1069d91 100644 --- a/storage/country_info_getter.hpp +++ b/storage/country_info_getter.hpp @@ -20,25 +20,57 @@ namespace storage { -// This class allows users to get information about country by point -// or by name. -// -// *NOTE* This class is thread-safe. -class CountryInfoGetter +class CountryInfoGetterBase { public: // Identifier of a region (index in m_countries array). using TRegionId = size_t; using TRegionIdSet = std::vector<TRegionId>; - CountryInfoGetter(bool isSingleMwm) : m_isSingleMwm(isSingleMwm) {} - virtual ~CountryInfoGetter() = default; + CountryInfoGetterBase(bool isSingleMwm) : m_isSingleMwm(isSingleMwm) {} + virtual ~CountryInfoGetterBase() = default; // Returns country file name without an extension for a country |pt| // belongs to. If there is no such country, returns an empty // string. TCountryId GetRegionCountryId(m2::PointD const & pt) const; + // Returns true when |pt| belongs to at least one of the specified + // |regions|. + bool IsBelongToRegions(m2::PointD const & pt, TRegionIdSet const & regions) const; + + // Returns true if there're at least one region with id equals to + // |countryId|. + bool IsBelongToRegions(TCountryId const & countryId, TRegionIdSet const & regions) const; + + void RegionIdsToCountryIds(TRegionIdSet const & regions, TCountriesVec & countries) const; + +protected: + // Returns identifier of a first country containing |pt|. + TRegionId FindFirstCountry(m2::PointD const & pt) const; + + // Returns true when |pt| belongs to a country identified by |id|. + virtual bool IsBelongToRegionImpl(size_t id, m2::PointD const & pt) const = 0; + + // @TODO(bykoianko): consider to get rid of m_countryIndex. + // The possibility should be considered. + // List of all known countries. + std::vector<CountryDef> m_countries; + // m_isSingleMwm == true if the system is currently working with single (small) mwms + // and false otherwise. + // @TODO(bykoianko) Init m_isSingleMwm correctly. + bool m_isSingleMwm; +}; + +// This class allows users to get information about country by point +// or by name. +// +// *NOTE* This class is thread-safe. +class CountryInfoGetter : public CountryInfoGetterBase +{ +public: + CountryInfoGetter(bool isSingleMwm) : CountryInfoGetterBase(isSingleMwm) {} + // Returns vector of countries file names without an extension for // countries belong to |rect|. |rough| provides fast rough result // or a slower but more precise one. @@ -73,27 +105,13 @@ public: // Returns identifiers for all regions matching to correspondent |affiliation|. virtual void GetMatchedRegions(string const & affiliation, TRegionIdSet & regions) const; - // Returns true when |pt| belongs to at least one of the specified - // |regions|. - bool IsBelongToRegions(m2::PointD const & pt, TRegionIdSet const & regions) const; - - // Returns true if there're at least one region with id equals to - // |countryId|. - bool IsBelongToRegions(TCountryId const & countryId, TRegionIdSet const & regions) const; - - void RegionIdsToCountryIds(TRegionIdSet const & regions, TCountriesVec & countries) const; - // Clears regions cache. inline void ClearCaches() const { ClearCachesImpl(); } void InitAffiliationsInfo(TMappingAffiliations const * affiliations); protected: - CountryInfoGetter() = default; - - // Returns identifier of a first country containing |pt|. - TRegionId FindFirstCountry(m2::PointD const & pt) const; - + CountryInfoGetter() : CountryInfoGetterBase(true) {}; // Invokes |toDo| on each country whose name starts with |prefix|. template <typename ToDo> void ForEachCountry(string const & prefix, ToDo && toDo) const; @@ -101,19 +119,11 @@ protected: // Clears regions cache. virtual void ClearCachesImpl() const = 0; - // Returns true when |pt| belongs to a country identified by |id|. - virtual bool IsBelongToRegionImpl(size_t id, m2::PointD const & pt) const = 0; - // Returns true when |rect| intersects a country identified by |id|. virtual bool IsIntersectedByRegionImpl(size_t id, m2::RectD const & rect) const = 0; // Returns true when the distance from |pt| to country identified by |id| less then |distance|. virtual bool IsCloseEnough(size_t id, m2::PointD const & pt, double distance) = 0; - - // @TODO(bykoianko): consider to get rid of m_countryIndex. - // The possibility should be considered. - // List of all known countries. - std::vector<CountryDef> m_countries; // Maps all leaf country id (file names) to their indices in m_countries. std::unordered_map<TCountryId, TRegionId> m_countryIndex; @@ -121,11 +131,6 @@ protected: // Maps country file name without an extension to a country info. std::map<std::string, CountryInfo> m_id2info; - - // m_isSingleMwm == true if the system is currently working with single (small) mwms - // and false otherwise. - // @TODO(bykoianko) Init m_isSingleMwm correctly. - bool m_isSingleMwm; }; // This class reads info about countries from polygons file and diff --git a/storage/country_info_reader_light.cpp b/storage/country_info_reader_light.cpp new file mode 100644 index 0000000000..eb395d1369 --- /dev/null +++ b/storage/country_info_reader_light.cpp @@ -0,0 +1,78 @@ +#include "storage/country_info_reader_light.hpp" + +#include "storage/country_decl.hpp" +#include "storage/country_polygon.hpp" + +#include "platform/platform.hpp" +#include "platform/preferred_languages.hpp" + +#include "coding/file_name_utils.hpp" +#include "coding/file_reader.hpp" +#include "coding/geometry_coding.hpp" +#include "coding/read_write_utils.hpp" + +#include "geometry/region2d.hpp" + +#include "base/logging.hpp" +#include "base/string_utils.hpp" + +#include <chrono> +#include <string> +#include <utility> +#include <vector> + +namespace lightweight +{ +CountryInfoReader::CountryInfoReader() + : CountryInfoGetterBase(true) +{ + try + { + m_reader = std::make_unique<FilesContainerR>(GetPlatform().GetReader(PACKED_POLYGONS_FILE)); + ReaderSource<ModelReaderPtr> src(m_reader->GetReader(PACKED_POLYGONS_INFO_TAG)); + rw::Read(src, m_countries); + } + catch (FileReader::Exception const & exception) + { + LOG(LERROR, + ("Exception while reading file:", PACKED_POLYGONS_FILE, "reason:", exception.what())); + + m_reader.reset(); + m_countries.clear(); + } + + m_nameGetter.SetLocale(languages::GetCurrentTwine()); +} + +bool CountryInfoReader::IsBelongToRegionImpl(size_t id, m2::PointD const & pt) const +{ + // Load regions from file. + ReaderSource<ModelReaderPtr> src(m_reader->GetReader(strings::to_string(id))); + + uint32_t const count = ReadVarUint<uint32_t>(src); + std::vector<m2::RegionD> regions; + + for (size_t i = 0; i < count; ++i) + { + std::vector<m2::PointD> points; + serial::LoadOuterPath(src, serial::GeometryCodingParams(), points); + regions.emplace_back(move(points)); + } + + for (auto const & region : regions) + { + if (region.Contains(pt)) + return true; + } + + return false; +} + +CountryInfoReader::Info CountryInfoReader::GetMwmInfo(m2::PointD const & pt) const +{ + Info info; + info.m_id = GetRegionCountryId(pt); + info.m_name = m_nameGetter(info.m_id); + return info; +} +} // namespace lightweight diff --git a/storage/country_info_reader_light.hpp b/storage/country_info_reader_light.hpp new file mode 100644 index 0000000000..a171b26be8 --- /dev/null +++ b/storage/country_info_reader_light.hpp @@ -0,0 +1,36 @@ +#pragma once + +#include "storage/index.hpp" +#include "storage/country_info_getter.hpp" +#include "storage/country_name_getter.hpp" + +#include "coding/file_container.hpp" + +#include "geometry/point2d.hpp" + +#include <cstdint> +#include <memory> + +namespace lightweight +{ +// Protected inheritance for test purposes only. +class CountryInfoReader : protected storage::CountryInfoGetterBase +{ +public: + struct Info + { + storage::TCountryId m_id; + std::string m_name; + }; + + CountryInfoReader(); + Info GetMwmInfo(m2::PointD const & pt) const; + +protected: + bool IsBelongToRegionImpl(size_t id, m2::PointD const & pt) const override; + +private: + std::unique_ptr<FilesContainerR> m_reader; + storage::CountryNameGetter m_nameGetter; +}; +} // namespace lightweight diff --git a/storage/storage_integration_tests/CMakeLists.txt b/storage/storage_integration_tests/CMakeLists.txt index 59eb9320fc..6d0ccda436 100644 --- a/storage/storage_integration_tests/CMakeLists.txt +++ b/storage/storage_integration_tests/CMakeLists.txt @@ -5,6 +5,7 @@ add_definitions("-DOMIM_UNIT_TEST_WITH_QT_EVENT_LOOP") set( SRC + lightweight_matching_tests.cpp migrate_tests.cpp storage_3levels_tests.cpp storage_downloading_tests.cpp diff --git a/storage/storage_integration_tests/lightweight_matching_tests.cpp b/storage/storage_integration_tests/lightweight_matching_tests.cpp new file mode 100644 index 0000000000..3ed2aa0135 --- /dev/null +++ b/storage/storage_integration_tests/lightweight_matching_tests.cpp @@ -0,0 +1,58 @@ +#include "testing/testing.hpp" + +#include "storage/country_info_reader_light.hpp" +#include "storage/index.hpp" + +#include "geometry/mercator.hpp" +#include "geometry/point2d.hpp" + +#include <utility> +#include <vector> + +using namespace lightweight; + +namespace +{ +double constexpr kStepInMercator = 1; // 1 mercator ~= 9602.84 meters + +struct PointAndCountry +{ + PointAndCountry(m2::PointD && pt, storage::TCountryId && country) + : m_pt(std::move(pt)) + , m_country(std::move(country)) + { + } + + m2::PointD m_pt; + storage::TCountryId m_country; +}; + +UNIT_CLASS_TEST(CountryInfoReader, LightweightMatching) +{ + auto const reader = storage::CountryInfoReader::CreateCountryInfoReader(GetPlatform()); + + LOG(LINFO, ("Generating dataset...")); + std::vector<PointAndCountry> dataset; + for (auto x = MercatorBounds::minX; x <= MercatorBounds::maxX; x += kStepInMercator) + { + for (auto y = MercatorBounds::minY; y <= MercatorBounds::maxY; y += kStepInMercator) + { + m2::PointD pt(x, y); + dataset.emplace_back(std::move(pt), reader->GetRegionCountryId(pt)); + } + } + + { + m2::PointD ptFrom = {MercatorBounds::minX, MercatorBounds::minY}; + m2::PointD ptTo = {MercatorBounds::minX + kStepInMercator, MercatorBounds::minY}; + auto const stepSizeInMeters = MercatorBounds::DistanceOnEarth(ptFrom, ptTo); + LOG(LINFO, ("The dataset is generated. Dataset size:", dataset.size(), + ". The step is:", stepSizeInMeters, "meters")); + } + + for (auto const & sample : dataset) + { + TEST_EQUAL(GetRegionCountryId(sample.m_pt), sample.m_country, (sample.m_pt)); + } +} +} // namespace |