#include "generator/hierarchy_entry.hpp" #include "indexer/feature_utils.hpp" #include "indexer/ftypes_matcher.hpp" #include "coding/string_utf8_multilang.hpp" #include "base/assert.hpp" #include "base/string_utils.hpp" #include "base/stl_helpers.hpp" #include #include #include #include #include "3party/jansson/myjansson.hpp" namespace { // GetRussianName returns a Russian feature name if it's possible. // Otherwise, GetRussianName function returns a name that GetReadableName returns. std::string GetRussianName(StringUtf8Multilang const & str) { auto const deviceLang = StringUtf8Multilang::GetLangIndex("ru"); std::string result; feature::GetReadableName({} /* regionData */, str, deviceLang, false /* allowTranslit */, result); for (auto const & ch : {';', '\n', '\t'}) std::replace(std::begin(result), std::end(result), ch, ','); return result; } } // namespace namespace generator { bool operator==(HierarchyEntry const & lhs, HierarchyEntry const & rhs) { return base::AlmostEqualAbs(lhs.m_center, rhs.m_center, 1e-7) && (std::tie(lhs.m_id, lhs.m_parentId, lhs.m_depth, lhs.m_name, lhs.m_country, lhs.m_type) == std::tie(rhs.m_id, rhs.m_parentId, rhs.m_depth, rhs.m_name, rhs.m_country, rhs.m_type)); } std::string DebugPrint(HierarchyEntry const & entry) { auto obj = base::NewJSONObject(); ToJSONObject(*obj, "id", DebugPrint(entry.m_id)); if (entry.m_parentId) ToJSONObject(*obj, "parentId", DebugPrint(*entry.m_parentId)); ToJSONObject(*obj, "depth", entry.m_depth); ToJSONObject(*obj, "type", classif().GetReadableObjectName(entry.m_type)); ToJSONObject(*obj, "name", entry.m_name); ToJSONObject(*obj, "country", entry.m_country); auto center = base::NewJSONObject(); ToJSONObject(*center, "x", entry.m_center.x); ToJSONObject(*center, "y", entry.m_center.y); ToJSONObject(*obj, "center", center); return DumpToString(obj); } namespace hierarchy { uint32_t GetMainType(FeatureParams::Types const & types) { auto const & airportChecker = ftypes::IsAirportChecker::Instance(); auto it = base::FindIf(types, airportChecker); if (it != std::cend(types)) return *it; auto const & attractChecker = ftypes::AttractionsChecker::Instance(); auto const type = attractChecker.GetBestType(types); if (type != ftype::GetEmptyValue()) return type; auto const & eatChecker = ftypes::IsEatChecker::Instance(); it = base::FindIf(types, eatChecker); if (it != std::cend(types)) return *it; auto const & buildingPartChecker = ftypes::IsBuildingPartChecker::Instance(); it = base::FindIf(types, buildingPartChecker); return it != std::cend(types) ? *it : ftype::GetEmptyValue(); } std::string GetName(StringUtf8Multilang const & str) { return GetRussianName(str); } std::string HierarchyEntryToCsvString(HierarchyEntry const & entry, char delim) { return strings::JoinStrings(HierarchyEntryToCsvRow(entry), delim); } coding::CSVReader::Row HierarchyEntryToCsvRow(HierarchyEntry const & entry) { coding::CSVReader::Row row; row.emplace_back(entry.m_id.ToString()); std::string parentId; if (entry.m_parentId) parentId = (*entry.m_parentId).ToString(); row.emplace_back(parentId); row.emplace_back(strings::to_string(entry.m_depth)); row.emplace_back(strings::to_string_dac(entry.m_center.x, 7)); row.emplace_back(strings::to_string_dac(entry.m_center.y, 7)); row.emplace_back(strings::to_string(classif().GetReadableObjectName(entry.m_type))); row.emplace_back(strings::to_string(entry.m_name)); row.emplace_back(strings::to_string(entry.m_country)); return row; } HierarchyEntry HierarchyEntryFromCsvRow(coding::CSVReader::Row const & row) { CHECK_EQUAL(row.size(), 8, (row)); auto const & id = row[0]; auto const & parentId = row[1]; auto const & depth = row[2]; auto const & x = row[3]; auto const & y = row[4]; auto const & type = row[5]; auto const & name = row[6]; auto const & country = row[7]; HierarchyEntry entry; entry.m_id = CompositeId(id); if (!parentId.empty()) entry.m_parentId = CompositeId(parentId); VERIFY(strings::to_size_t(depth, entry.m_depth), (row)); VERIFY(strings::to_double(x, entry.m_center.x), (row)); VERIFY(strings::to_double(y, entry.m_center.y), (row)); entry.m_type = classif().GetTypeByReadableObjectName(type); entry.m_name = name; entry.m_country = country; return entry; } tree_node::types::Ptrs LoadHierachy(std::string const & filename) { std::unordered_map> nodes; for (auto const & row : coding::CSVRunner( coding::CSVReader(filename, false /* hasHeader */, kCsvDelimiter))) { auto entry = HierarchyEntryFromCsvRow(row); auto const id = entry.m_id; nodes.emplace(id, tree_node::MakeTreeNode(std::move(entry))); } for (auto const & pair : nodes) { auto const & node = pair.second; auto const parentIdOpt = node->GetData().m_parentId; if (parentIdOpt) { auto const it = nodes.find(*parentIdOpt); CHECK(it != std::cend(nodes), (*it)); tree_node::Link(node, it->second); } } std::vector> trees; base::Transform(nodes, std::back_inserter(trees), base::RetrieveSecond()); base::EraseIf(trees, [](auto const & node) { return node->HasParent(); }); return trees; } } // namespace hierarchy } // namespace generator