#pragma once #include "generator/osm_element.hpp" #include "base/logging.hpp" #include "base/stl_helpers.hpp" #include "base/string_utils.hpp" #include #include #include #include #include #include #include class WaysParserHelper { public: WaysParserHelper(std::map & ways) : m_ways(ways) {} void ParseStream(std::istream & input) { std::string oneLine; while (std::getline(input, oneLine, '\n')) { // String format: <>. auto pos = oneLine.find(';'); if (pos != std::string::npos) { uint64_t wayId; CHECK(strings::to_uint64(oneLine.substr(0, pos), wayId),()); m_ways[wayId] = oneLine.substr(pos + 1, oneLine.length() - pos - 1); } } } private: std::map & m_ways; }; class CapitalsParserHelper { public: CapitalsParserHelper(std::set & capitals) : m_capitals(capitals) {} void ParseStream(std::istream & input) { std::string oneLine; while (std::getline(input, oneLine, '\n')) { // String format: <>. // First ';'. auto pos = oneLine.find(";"); if (pos != std::string::npos) { // Second ';'. pos = oneLine.find(";", pos + 1); if (pos != std::string::npos) { uint64_t nodeId; // Third ';'. auto endPos = oneLine.find(";", pos + 1); if (endPos != std::string::npos) { if (strings::to_uint64(oneLine.substr(pos + 1, endPos - pos - 1), nodeId)) m_capitals.insert(nodeId); } } } } } private: std::set & m_capitals; }; class TagAdmixer { public: TagAdmixer(std::string const & waysFile, std::string const & capitalsFile) : m_ferryTag("route", "ferry") { try { std::ifstream reader(waysFile); WaysParserHelper parser(m_ways); parser.ParseStream(reader); } catch (std::ifstream::failure const &) { LOG(LWARNING, ("Can't read the world level ways file! Generating world without roads. Path:", waysFile)); return; } try { std::ifstream reader(capitalsFile); CapitalsParserHelper parser(m_capitals); parser.ParseStream(reader); } catch (std::ifstream::failure const &) { LOG(LWARNING, ("Can't read the world level capitals file! Generating world without towns admixing. Path:", capitalsFile)); return; } } void operator()(OsmElement & element) { if (element.type == OsmElement::EntityType::Way && m_ways.find(element.id) != m_ways.end()) { // Exclude ferry routes. if (find(element.Tags().begin(), element.Tags().end(), m_ferryTag) == element.Tags().end()) element.AddTag("highway", m_ways[element.id]); } else if (element.type == OsmElement::EntityType::Node && m_capitals.find(element.id) != m_capitals.end()) { // Our goal here - to make some capitals visible in World map. // The simplest way is to upgrade population to 45000, // according to our visibility rules in mapcss files. element.UpdateTag("population", [] (std::string & v) { uint64_t n; if (!strings::to_uint64(v, n) || n < 45000) v = "45000"; }); } } private: std::map m_ways; std::set m_capitals; OsmElement::Tag const m_ferryTag; }; class TagReplacer { std::map> m_entries; public: TagReplacer(std::string const & filePath) { std::ifstream stream(filePath); OsmElement::Tag tag; std::vector values; std::string line; while (std::getline(stream, line)) { if (line.empty()) continue; strings::SimpleTokenizer iter(line, " \t=,:"); if (!iter) continue; tag.key = *iter; ++iter; if (!iter) continue; tag.value = *iter; values.clear(); while (++iter) values.push_back(*iter); if (values.size() >= 2 && values.size() % 2 == 0) m_entries[tag].swap(values); } } void operator()(OsmElement & element) { for (auto & tag : element.m_tags) { auto it = m_entries.find(tag); if (it != m_entries.end()) { auto const & v = it->second; tag.key = v[0]; tag.value = v[1]; for (size_t i = 2; i < v.size(); i += 2) element.AddTag(v[i], v[i + 1]); } } } }; class OsmTagMixer { std::map, std::vector> m_elements; public: OsmTagMixer(std::string const & filePath) { std::ifstream stream(filePath); std::vector values; std::vector tags; std::string line; while (std::getline(stream, line)) { if (line.empty() || line.front() == '#') continue; strings::ParseCSVRow(line, ',', values); if (values.size() < 3) continue; OsmElement::EntityType entityType = OsmElement::StringToEntityType(values[0]); uint64_t id; if (entityType == OsmElement::EntityType::Unknown || !strings::to_uint64(values[1], id)) continue; for (size_t i = 2; i < values.size(); ++i) { auto p = values[i].find('='); if (p != std::string::npos) tags.push_back(OsmElement::Tag(values[i].substr(0, p), values[i].substr(p + 1))); } if (!tags.empty()) { std::pair elementPair = {entityType, id}; m_elements[elementPair].swap(tags); } } } void operator()(OsmElement & element) { std::pair elementId = {element.type, element.id}; auto elements = m_elements.find(elementId); if (elements != m_elements.end()) { for (OsmElement::Tag tag : elements->second) element.UpdateTag(tag.key, [&tag](std::string & v) { v = tag.value; }); } } };