#include "extractor/maneuver_override_relation_parser.hpp" #include "extractor/maneuver_override.hpp" #include "util/log.hpp" #include #include #include #include #include #include #include #include #include #include namespace osrm { namespace extractor { ManeuverOverrideRelationParser::ManeuverOverrideRelationParser() {} /** * Parses the `type=maneuver` relation. Reads the fields, and puts data * into an InputManeuverOverride object, if the relation is considered * valid (i.e. has the minimum tags we expect). */ boost::optional ManeuverOverrideRelationParser::TryParse(const osmium::Relation &relation) const { osmium::tags::KeyFilter filter(false); filter.add(true, "maneuver"); const osmium::TagList &tag_list = relation.tags(); osmium::tags::KeyFilter::iterator fi_begin(filter, tag_list.begin(), tag_list.end()); osmium::tags::KeyFilter::iterator fi_end(filter, tag_list.end(), tag_list.end()); // if it's not a maneuver, continue; if (std::distance(fi_begin, fi_end) == 0) { return boost::none; } // we pretend every restriction is a conditional restriction. If we do not find any restriction, // we can trim away the vector after parsing InputManeuverOverride maneuver_override; maneuver_override.maneuver = relation.tags().get_value_by_key("maneuver", ""); maneuver_override.direction = relation.tags().get_value_by_key("direction", ""); bool valid_relation = true; OSMNodeID via_node = SPECIAL_OSM_NODEID; OSMWayID from = SPECIAL_OSM_WAYID, to = SPECIAL_OSM_WAYID; std::vector via_ways; for (const auto &member : relation.members()) { const char *role = member.role(); if (strcmp("from", role) != 0 && strcmp("to", role) != 0 && strcmp("via", role) != 0) { continue; } switch (member.type()) { case osmium::item_type::node: { // Make sure nodes appear only in the role if a via node if (0 == strcmp("from", role) || 0 == strcmp("to", role)) { continue; } BOOST_ASSERT(0 == strcmp("via", role)); // set via node id valid_relation &= via_node == SPECIAL_OSM_NODEID; via_node = OSMNodeID{static_cast(member.ref())}; break; } case osmium::item_type::way: BOOST_ASSERT(0 == strcmp("from", role) || 0 == strcmp("to", role) || 0 == strcmp("via", role)); if (0 == strcmp("from", role)) { valid_relation &= from == SPECIAL_OSM_WAYID; from = OSMWayID{static_cast(member.ref())}; } else if (0 == strcmp("to", role)) { valid_relation &= to == SPECIAL_OSM_WAYID; to = OSMWayID{static_cast(member.ref())}; } else if (0 == strcmp("via", role)) { via_ways.push_back(OSMWayID{static_cast(member.ref())}); } break; case osmium::item_type::relation: // not yet supported, but who knows what the future holds... break; default: // shouldn't ever happen break; } } // Check required roles valid_relation &= from != SPECIAL_OSM_WAYID; valid_relation &= to != SPECIAL_OSM_WAYID; valid_relation &= via_node != SPECIAL_OSM_NODEID; if (valid_relation) { maneuver_override.via_ways.push_back(from); std::copy(via_ways.begin(), via_ways.end(), std::back_inserter(maneuver_override.via_ways)); maneuver_override.via_ways.push_back(to); maneuver_override.via_node = via_node; } else { return boost::none; } return maneuver_override; } } }