From de02ec02febb3da29fc0ed7a4019384a25c1b5d4 Mon Sep 17 00:00:00 2001 From: Mikhail Gorbushin Date: Thu, 4 Apr 2019 18:57:25 +0300 Subject: [PATCH] Stage 1. Preprocess data. --- generator/intermediate_data.hpp | 1 + generator/restriction_writer.cpp | 137 ++++++++++++++++++++++++++----- generator/restriction_writer.hpp | 27 ++++-- generator/translator_country.cpp | 2 +- 4 files changed, 137 insertions(+), 30 deletions(-) diff --git a/generator/intermediate_data.hpp b/generator/intermediate_data.hpp index c4e61d17be..86327fdd79 100644 --- a/generator/intermediate_data.hpp +++ b/generator/intermediate_data.hpp @@ -203,6 +203,7 @@ public: IntermediateDataReader(std::shared_ptr nodes, feature::GenerateInfo & info); + // TODO |GetNode()|, |lat|, |lon| is used as y, x in real. bool GetNode(Key id, double & lat, double & lon) const { return m_nodes->GetPoint(id, lat, lon); } bool GetWay(Key id, WayElement & e) { return m_ways.Read(id, e); } void LoadIndex(); diff --git a/generator/restriction_writer.cpp b/generator/restriction_writer.cpp index 5370a151b9..4d469394f5 100644 --- a/generator/restriction_writer.cpp +++ b/generator/restriction_writer.cpp @@ -1,10 +1,12 @@ #include "generator/restriction_writer.hpp" #include "generator/intermediate_elements.hpp" +#include "generator/osm_element.hpp" #include "generator/restriction_collector.hpp" #include "routing/restrictions_serialization.hpp" +#include "base/assert.hpp" #include "base/geo_object_id.hpp" #include "base/logging.hpp" @@ -45,15 +47,68 @@ bool TagToType(std::string const & tag, Restriction::Type & type) type = it->second; return true; } + +std::vector GetMembersByTag(RelationElement const & relationElement, + std::string const & tag) +{ + std::vector result; + for (auto const & member : relationElement.ways) + { + if (member.second == tag) + result.emplace_back(member); + } + + for (auto const & member : relationElement.nodes) + { + if (member.second == tag) + result.emplace_back(member); + } + + return result; +}; + +OsmElement::EntityType GetType(RelationElement const & relationElement, uint64_t osmId) +{ + for (auto const & member : relationElement.ways) + { + if (member.first == osmId) + return OsmElement::EntityType::Way; + } + + for (auto const & member : relationElement.nodes) + { + if (member.first == osmId) + return OsmElement::EntityType::Node; + } + + UNREACHABLE(); +}; } // namespace namespace routing { -RestrictionWriter::RestrictionWriter(std::string const & fullPath) +std::string const RestrictionWriter::kNodeString = "node"; +std::string const RestrictionWriter::kWayString = "way"; + +RestrictionWriter::RestrictionWriter(std::string const & fullPath, + generator::cache::IntermediateDataReader const & cache) + : m_cache(cache) { Open(fullPath); } +//static +RestrictionWriter::ViaType RestrictionWriter::ConvertFromString(std::string const & str) +{ + if (str == kNodeString) + return ViaType::Node; + else if (str == kWayString) + return ViaType::Way; + + CHECK(false, ("Bad via type in restrictons:", str)); + UNREACHABLE(); +} + void RestrictionWriter::Open(std::string const & fullPath) { LOG(LINFO, ("Saving road restrictions in osm id terms to", fullPath)); @@ -61,6 +116,8 @@ void RestrictionWriter::Open(std::string const & fullPath) if (!IsOpened()) LOG(LINFO, ("Cannot open file", fullPath)); + + m_stream << std::setprecision(20); } void RestrictionWriter::CollectRelation(RelationElement const & relationElement) @@ -74,29 +131,31 @@ void RestrictionWriter::CollectRelation(RelationElement const & relationElement) if (relationElement.GetType() != "restriction") return; - // Note. For the time being only line-point-line road restriction is supported. - if (relationElement.nodes.size() != 1 || relationElement.ways.size() != 2) - return; // Unsupported restriction. For example line-line-line. + auto const from = GetMembersByTag(relationElement, "from"); + auto const to = GetMembersByTag(relationElement, "to"); + auto const via = GetMembersByTag(relationElement, "via"); - // Extracting osm ids of lines and points of the restriction. - auto const findTag = [](std::vector> const & members, - std::string const & tag) { - auto const it = std::find_if( - members.cbegin(), members.cend(), - [&tag](std::pair const & p) { return p.second == tag; }); - return it; - }; - - auto const fromIt = findTag(relationElement.ways, "from"); - if (fromIt == relationElement.ways.cend()) + // TODO (@gmoryes) |from| and |to| can have size more than 1 in case of "no_entry", "no_exit" + if (from.size() != 1 || to.size() != 1 || via.empty()) return; - auto const toIt = findTag(relationElement.ways, "to"); - if (toIt == relationElement.ways.cend()) - return; + uint64_t const fromOsmId = from.back().first; + uint64_t const toOsmId = to.back().first; - if (findTag(relationElement.nodes, "via") == relationElement.nodes.cend()) - return; + // Either single node is marked as via or one or more ways are marked as via. + // https://wiki.openstreetmap.org/wiki/Relation:restriction#Members + if (via.size() != 1) + { + bool const allMembersAreWays = + std::all_of(via.begin(), via.end(), + [&](auto const & member) + { + return GetType(relationElement, member.first) == OsmElement::EntityType::Way; + }); + + if (!allMembersAreWays) + return; + } // Extracting type of restriction. auto const tagIt = relationElement.tags.find("restriction"); @@ -107,9 +166,43 @@ void RestrictionWriter::CollectRelation(RelationElement const & relationElement) if (!TagToType(tagIt->second, type)) return; - // Adding restriction. - m_stream << ToString(type) << "," << fromIt->first << ", " << toIt->first << '\n'; + auto const viaType = + GetType(relationElement, via.back().first) == OsmElement::EntityType::Node ? ViaType::Node + : ViaType::Way; + + m_stream << DebugPrint(type) << "," << DebugPrint(viaType) << ","; + + if (viaType == ViaType::Way) + { + m_stream << fromOsmId << ","; + for (auto const & viaMember : via) + m_stream << viaMember.first << ","; + } + else + { + double y = 0.0; + double x = 0.0; + uint64_t const viaNodeOsmId = via.back().first; + if (!m_cache.GetNode(viaNodeOsmId, y, x)) + return; + + m_stream << x << "," << y << ","; + m_stream << fromOsmId << ","; + } + + m_stream << toOsmId << '\n'; } bool RestrictionWriter::IsOpened() const { return m_stream && m_stream.is_open(); } + +std::string DebugPrint(RestrictionWriter::ViaType const & type) +{ + switch (type) + { + case RestrictionWriter::ViaType::Node: return RestrictionWriter::kNodeString; + case RestrictionWriter::ViaType::Way: return RestrictionWriter::kWayString; + case RestrictionWriter::ViaType::Max: CHECK(false, ()); + } + UNREACHABLE(); +} } // namespace routing diff --git a/generator/restriction_writer.hpp b/generator/restriction_writer.hpp index cb451fb7f9..f1e0668316 100644 --- a/generator/restriction_writer.hpp +++ b/generator/restriction_writer.hpp @@ -1,6 +1,7 @@ #pragma once #include "generator/collector_interface.hpp" +#include "generator/intermediate_data.hpp" #include #include @@ -12,20 +13,32 @@ namespace routing class RestrictionWriter : public generator::CollectorInterface { public: - RestrictionWriter(std::string const & fullPath); - // CollectorRelationsInterface overrides: - /// \brief Writes |relationElement| to |m_stream| if |relationElement| is a supported restriction. - /// See restriction_generator.hpp for the description of the format. - /// \note For the time being only line-point-line restrictions are processed. The other - /// restrictions are ignored. - // @TODO(bykoianko) It's necessary to process all kind of restrictions. + + enum class ViaType + { + Node, + Way, + }; + + static std::string const kNodeString; + static std::string const kWayString; + + RestrictionWriter(std::string const & fullPath, + generator::cache::IntermediateDataReader const & cache); + void CollectRelation(RelationElement const & relationElement) override; void Save() override {} + static ViaType ConvertFromString(std::string const & str); + private: void Open(std::string const & fullPath); bool IsOpened() const; std::ofstream m_stream; + generator::cache::IntermediateDataReader const & m_cache; }; + +std::string DebugPrint(RestrictionWriter::ViaType const & type); } // namespace routing + diff --git a/generator/translator_country.cpp b/generator/translator_country.cpp index a4d95eaaba..1007200ff6 100644 --- a/generator/translator_country.cpp +++ b/generator/translator_country.cpp @@ -85,7 +85,7 @@ TranslatorCountry::TranslatorCountry(std::shared_ptr emitter, // These are the four collector that collect additional information for the future building of routing section. AddCollector(std::make_shared(info.GetIntermediateFileName(MAXSPEEDS_FILENAME))); - AddCollector(std::make_shared(info.GetIntermediateFileName(RESTRICTIONS_FILENAME))); + AddCollector(std::make_shared(info.GetIntermediateFileName(RESTRICTIONS_FILENAME), cache)); AddCollector(std::make_shared(info.GetIntermediateFileName(ROAD_ACCESS_FILENAME))); AddCollector(std::make_shared(info.GetIntermediateFileName(CAMERAS_TO_WAYS_FILENAME)));