/** * Tries to parse a relation as a turn restriction. This can fail for a number of * reasons. The return type is a boost::optional<T>. * * Some restrictions can also be ignored: See the ```get_restrictions``` function * in the corresponding profile. We use it for both namespacing restrictions, as in * restriction:motorcar as well as whitelisting if its in except:motorcar. */ boost::optional<InputRestrictionContainer> RestrictionParser::TryParse(const osmium::Relation &relation) const { // return if turn restrictions should be ignored if (!use_turn_restrictions) { return {}; } osmium::tags::KeyFilter filter(false); filter.add(true, "restriction"); // Not only use restriction= but also e.g. restriction:motorcar= for (const auto &namespaced : restrictions) filter.add(true, "restriction:" + namespaced); 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 restriction, continue; if (std::distance(fi_begin, fi_end) == 0) { return {}; } // check if the restriction should be ignored const char *except = relation.get_value_by_key("except"); if (except != nullptr && ShouldIgnoreRestriction(except)) { return {}; } bool is_only_restriction = false; for (; fi_begin != fi_end; ++fi_begin) { const std::string key(fi_begin->key()); const std::string value(fi_begin->value()); // documented OSM restriction tags start either with only_* or no_*; // check and return on these values, and ignore unrecognized values if (value.find("only_") == 0) { is_only_restriction = true; } else if (value.find("no_") == 0) { is_only_restriction = false; } else // unrecognized value type { return {}; } } InputRestrictionContainer restriction_container(is_only_restriction); 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 restriction_container.restriction.via.node = 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)) { restriction_container.restriction.from.way = member.ref(); } else if (0 == strcmp("to", role)) { restriction_container.restriction.to.way = member.ref(); } // else if (0 == strcmp("via", role)) // { // not yet suppported // restriction_container.restriction.via.way = 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; } } return boost::make_optional(std::move(restriction_container)); }
mapbox::util::optional<InputRestrictionContainer> RestrictionParser::TryParse(const osmium::Relation &relation) const { // return if turn restrictions should be ignored if (!use_turn_restrictions) { return mapbox::util::optional<InputRestrictionContainer>(); } osmium::tags::KeyPrefixFilter filter(false); filter.add(true, "restriction"); const osmium::TagList &tag_list = relation.tags(); osmium::tags::KeyPrefixFilter::iterator fi_begin(filter, tag_list.begin(), tag_list.end()); osmium::tags::KeyPrefixFilter::iterator fi_end(filter, tag_list.end(), tag_list.end()); // if it's a restriction, continue; if (std::distance(fi_begin, fi_end) == 0) { return mapbox::util::optional<InputRestrictionContainer>(); } // check if the restriction should be ignored const char *except = relation.get_value_by_key("except"); if (except != nullptr && ShouldIgnoreRestriction(except)) { return mapbox::util::optional<InputRestrictionContainer>(); } bool is_only_restriction = false; for (auto iter = fi_begin; iter != fi_end; ++iter) { if (std::string("restriction") == iter->key() || std::string("restriction::hgv") == iter->key()) { const std::string restriction_value(iter->value()); if (restriction_value.find("only_") == 0) { is_only_restriction = true; } } } InputRestrictionContainer restriction_container(is_only_restriction); 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 restriction_container.restriction.via.node = 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)) { restriction_container.restriction.from.way = member.ref(); } else if (0 == strcmp("to", role)) { restriction_container.restriction.to.way = member.ref(); } // else if (0 == strcmp("via", role)) // { // not yet suppported // restriction_container.restriction.via.way = 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; } } return mapbox::util::optional<InputRestrictionContainer>(restriction_container); }
/** * Tries to parse a relation as a turn restriction. This can fail for a number of * reasons. The return type is a boost::optional<T>. * * Some restrictions can also be ignored: See the ```get_restrictions``` function * in the corresponding profile. We use it for both namespacing restrictions, as in * restriction:motorcar as well as whitelisting if its in except:motorcar. */ std::vector<InputRestrictionContainer> RestrictionParser::TryParse(const osmium::Relation &relation) const { std::vector<InputRestrictionContainer> parsed_restrictions; // return if turn restrictions should be ignored if (!use_turn_restrictions) { return {}; } osmium::tags::KeyFilter filter(false); filter.add(true, "restriction"); if (parse_conditionals) { filter.add(true, "restriction:conditional"); for (const auto &namespaced : restrictions) { filter.add(true, "restriction:" + namespaced + ":conditional"); } } // Not only use restriction= but also e.g. restriction:motorcar= // Include restriction:{mode}:conditional if flagged for (const auto &namespaced : restrictions) { filter.add(true, "restriction:" + namespaced); } 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 restriction, continue; if (std::distance(fi_begin, fi_end) == 0) { return {}; } // check if the restriction should be ignored const char *except = relation.get_value_by_key("except"); if (except != nullptr && ShouldIgnoreRestriction(except)) { return {}; } bool is_only_restriction = false; for (; fi_begin != fi_end; ++fi_begin) { const std::string key(fi_begin->key()); const std::string value(fi_begin->value()); // documented OSM restriction tags start either with only_* or no_*; // check and return on these values, and ignore unrecognized values if (value.find("only_") == 0) { is_only_restriction = true; } else if (value.find("no_") == 0) { is_only_restriction = false; } else // unrecognized value type { return {}; } } InputRestrictionContainer restriction_container(is_only_restriction); 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 restriction_container.restriction.via.node = 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)) { restriction_container.restriction.from.way = member.ref(); } else if (0 == strcmp("to", role)) { restriction_container.restriction.to.way = member.ref(); } // else if (0 == strcmp("via", role)) // { // not yet suppported // restriction_container.restriction.via.way = 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; } } // parse conditional tags if (parse_conditionals) { 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()); for (; fi_begin != fi_end; ++fi_begin) { const std::string key(fi_begin->key()); const std::string value(fi_begin->value()); // Parse condition and add independent value/condition pairs const auto &parsed = osrm::util::ParseConditionalRestrictions(value); if (parsed.empty()) continue; for (const auto &p : parsed) { std::vector<util::OpeningHours> hours = util::ParseOpeningHours(p.condition); // found unrecognized condition, continue if (hours.empty()) return {}; restriction_container.restriction.condition = std::move(hours); } } } // push back a copy of turn restriction if (restriction_container.restriction.via.node != SPECIAL_NODEID && restriction_container.restriction.from.node != SPECIAL_NODEID && restriction_container.restriction.to.node != SPECIAL_NODEID) parsed_restrictions.push_back(restriction_container); return parsed_restrictions; }