Пример #1
0
/**
 * 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));
}
Пример #2
0
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);
}
Пример #3
0
/**
 * 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;
}