From 2af95203c4245d359bb5695aaf0a5bab5bb1dd9b Mon Sep 17 00:00:00 2001 From: vng Date: Tue, 25 Oct 2011 16:57:51 +0300 Subject: [PATCH] Add file name (id) -> region name conversion routine. --- storage/country.cpp | 72 ++++++++++++++++++--- storage/country.hpp | 2 + storage/country_info.cpp | 41 ++++++++++-- storage/country_info.hpp | 11 ++-- storage/storage_tests/country_info_test.cpp | 21 +++++- 5 files changed, 125 insertions(+), 22 deletions(-) diff --git a/storage/country.cpp b/storage/country.cpp index f0328c2613..3a3969ea6c 100644 --- a/storage/country.cpp +++ b/storage/country.cpp @@ -72,7 +72,8 @@ int64_t Country::Price() const //////////////////////////////////////////////////////////////////////// -void LoadGroupImpl(int depth, json_t * group, CountriesContainerT & container) +template +void LoadGroupImpl(int depth, json_t * group, ToDo & toDo) { for (size_t i = 0; i < json_array_size(group); ++i) { @@ -92,21 +93,17 @@ void LoadGroupImpl(int depth, json_t * group, CountriesContainerT & container) json_t * jPrice = json_object_get(j, "p"); json_int_t price = jPrice ? json_integer_value(jPrice) : INVALID_PRICE; - Country country(name, flag ? flag : ""); - if (size) - country.AddFile(CountryFile(file, size, price)); - container.AddAtDepth(depth, country); + toDo(name, file, flag ? flag : "", size, price, depth); json_t * children = json_object_get(j, "g"); if (children) - LoadGroupImpl(depth + 1, children, container); + LoadGroupImpl(depth + 1, children, toDo); } } -int64_t LoadCountries(string const & jsonBuffer, CountriesContainerT & countries) +template +int64_t LoadCountriesImpl(string const & jsonBuffer, ToDo & toDo) { - countries.Clear(); - int64_t version = -1; try @@ -116,7 +113,7 @@ int64_t LoadCountries(string const & jsonBuffer, CountriesContainerT & countries json_t * children = json_object_get(root, "g"); if (!children) MYTHROW(my::Json::Exception, ("Root country doesn't have any groups")); - LoadGroupImpl(0, children, countries); + LoadGroupImpl(0, children, toDo); } catch (my::Json::Exception const & e) { @@ -127,6 +124,61 @@ int64_t LoadCountries(string const & jsonBuffer, CountriesContainerT & countries return version; } +namespace +{ + class DoStoreCountries + { + CountriesContainerT & m_cont; + public: + DoStoreCountries(CountriesContainerT & cont) : m_cont(cont) {} + + void operator() (string const & name, string const & file, string const & flag, + uint32_t size, int64_t price, int depth) + { + Country country(name, flag); + if (size) + country.AddFile(CountryFile(file, size, price)); + m_cont.AddAtDepth(depth, country); + } + }; + + class DoStoreNames + { + map & m_id2name; + public: + DoStoreNames(map & id2name) : m_id2name(id2name) {} + + void operator() (string name, string const & file, string const &, + uint32_t size, int64_t, int) + { + // if 'file' is empty - it's equal to name + if (size && !file.empty()) + { + size_t const i = file.find_first_of('_'); + if (i != string::npos) + name = file.substr(0, i) + '_' + name; + + if (name != file) + m_id2name[file] = name; + } + } + }; +} + +int64_t LoadCountries(string const & jsonBuffer, CountriesContainerT & countries) +{ + countries.Clear(); + DoStoreCountries doStore(countries); + return LoadCountriesImpl(jsonBuffer, doStore); +} + +void LoadCountryNames(string const & jsonBuffer, map & id2name) +{ + ASSERT ( id2name.empty(), () ); + DoStoreNames doStore(id2name); + LoadCountriesImpl(jsonBuffer, doStore); +} + template void SaveImpl(T const & v, json_t * jParent) { diff --git a/storage/country.hpp b/storage/country.hpp index 2a484183da..6e94e400ec 100644 --- a/storage/country.hpp +++ b/storage/country.hpp @@ -70,5 +70,7 @@ namespace storage /// @return version of country file or -1 if error was encountered int64_t LoadCountries(string const & jsonBuffer, CountriesContainerT & countries); + void LoadCountryNames(string const & jsonBuffer, map & id2name); + bool SaveCountries(int64_t version, CountriesContainerT const & countries, string & jsonBuffer); } diff --git a/storage/country_info.cpp b/storage/country_info.cpp index a73d3b3968..c808057f50 100644 --- a/storage/country_info.cpp +++ b/storage/country_info.cpp @@ -1,4 +1,5 @@ #include "country_info.hpp" +#include "country.hpp" #include "../indexer/geometry_serialization.hpp" @@ -11,15 +12,19 @@ namespace storage { - CountryInfoGetter::CountryInfoGetter(ModelReaderPtr reader) - : m_reader(reader) + CountryInfoGetter::CountryInfoGetter(ModelReaderPtr polyR, ModelReaderPtr countryR) + : m_reader(polyR) { ReaderSource src(m_reader.GetReader(PACKED_POLYGONS_INFO_TAG)); rw::Read(src, m_countries); + + string buffer; + countryR.ReadAsString(buffer); + LoadCountryNames(buffer, m_id2name); } template - void CountryInfoGetter::ForEachCountry(m2::PointD const & pt, ToDo & toDo) + void CountryInfoGetter::ForEachCountry(m2::PointD const & pt, ToDo & toDo) const { for (size_t i = 0; i < m_countries.size(); ++i) if (m_countries[i].m_rect.IsPointInside(pt)) @@ -48,16 +53,38 @@ namespace storage return true; } - string CountryInfoGetter::GetRegionName(m2::PointD const & pt) + string CountryInfoGetter::GetRegionName(m2::PointD const & pt) const { GetByPoint doGet(*this, pt); ForEachCountry(pt, doGet); if (doGet.m_res != -1) - { - return m_countries[doGet.m_res].m_name; - } + return GetRegionName(m_countries[doGet.m_res].m_name); return string(); } + + string CountryInfoGetter::GetRegionName(string const & id) const + { + string name; + + map::const_iterator i = m_id2name.find(id); + if (i != m_id2name.end()) + name = i->second; + else + name = id; + + /// @todo Correct replace '_' with ", " in name. + if (id.find_first_of('_') != string::npos) + { + // I don't know how to do it best for UTF8, but this variant will work + // correctly for now (utf8-names of compound countries are equal to ascii-names). + + size_t const i = name.find_first_of('_'); + ASSERT_NOT_EQUAL ( i, string::npos, () ); + name = name.substr(0, i) + ", " + name.substr(i+1); + } + + return name; + } } diff --git a/storage/country_info.hpp b/storage/country_info.hpp index 60151aa566..45f0c6180b 100644 --- a/storage/country_info.hpp +++ b/storage/country_info.hpp @@ -9,10 +9,12 @@ namespace storage class CountryInfoGetter { FilesContainerR m_reader; + vector m_countries; + map m_id2name; template - void ForEachCountry(m2::PointD const & pt, ToDo & toDo); + void ForEachCountry(m2::PointD const & pt, ToDo & toDo) const; class GetByPoint { @@ -22,14 +24,15 @@ namespace storage public: size_t m_res; - GetByPoint(CountryInfoGetter & info, m2::PointD const & pt) + GetByPoint(CountryInfoGetter const & info, m2::PointD const & pt) : m_info(info), m_pt(pt), m_res(-1) {} bool operator() (size_t id); }; public: - CountryInfoGetter(ModelReaderPtr reader); + CountryInfoGetter(ModelReaderPtr polyR, ModelReaderPtr countryR); - string GetRegionName(m2::PointD const & pt); + string GetRegionName(m2::PointD const & pt) const; + string GetRegionName(string const & id) const; }; } diff --git a/storage/storage_tests/country_info_test.cpp b/storage/storage_tests/country_info_test.cpp index 8bd10dc497..4904eb41d4 100644 --- a/storage/storage_tests/country_info_test.cpp +++ b/storage/storage_tests/country_info_test.cpp @@ -1,6 +1,7 @@ #include "../../testing/testing.hpp" #include "../country_info.hpp" +#include "../country.hpp" #include "../../indexer/mercator.hpp" @@ -9,10 +10,28 @@ UNIT_TEST(CountryInfo_GetByPoint_Smoke) { - storage::CountryInfoGetter getter(GetPlatform().GetReader(PACKED_POLYGONS_FILE)); + Platform & pl = GetPlatform(); + + storage::CountryInfoGetter getter(pl.GetReader(PACKED_POLYGONS_FILE), + pl.GetReader(COUNTRIES_FILE)); // Minsk TEST_EQUAL(getter.GetRegionName( m2::PointD(MercatorBounds::LonToX(27.5618818), MercatorBounds::LatToY(53.9022651))), "Belarus", ()); } + +UNIT_TEST(CountryInfo_ValidName_Smoke) +{ + string buffer; + ReaderPtr(GetPlatform().GetReader(COUNTRIES_FILE)).ReadAsString(buffer); + + map id2name; + storage::LoadCountryNames(buffer, id2name); + + TEST(id2name.count("Germany_Baden-Wurttemberg") == 1, ()); + TEST(id2name.count("France_Paris & Ile-de-France") == 1, ()); + + TEST(id2name.count("Russia_Far Eastern") == 0, ()); + TEST(id2name.count("UK_Northern Ireland") == 0, ()); +}