Complete support for no_entry and no_exit turn restrictions (#5988)
The internal representation of turn restrictions expects only one `from` way and only one `to` way. `no_entry` and `no_exit` turn restrictions can have multiple `from` and `to` ways respectively. This means they are not fully supported by OSRM's restriction parser. We complete support for these turn restriction types by parsing all ways and converting a valid restriction with multiple `from`/`to` members into multiple internal restrictions.
This commit is contained in:
parent
b4b1aea567
commit
3cfd0e8334
@ -36,6 +36,7 @@
|
||||
- CHANGED: Docker build, enabled arm64 build layer [#6172](https://github.com/Project-OSRM/osrm-backend/pull/6172)
|
||||
- CHANGED: Docker build, enabled apt-get update/install caching in separate layer for build phase [#6175](https://github.com/Project-OSRM/osrm-backend/pull/6175)
|
||||
- Routing:
|
||||
- FIXED: Completed support for no_entry and no_exit turn restrictions. [#5988](https://github.com/Project-OSRM/osrm-backend/pull/5988)
|
||||
- ADDED: Add support for non-round-trips with a single fixed endpoint. [#6050](https://github.com/Project-OSRM/osrm-backend/pull/6050)
|
||||
|
||||
# 5.26.0
|
||||
|
@ -1008,3 +1008,123 @@ Feature: Car - Turn restrictions
|
||||
| from | to | route |
|
||||
| d | x | bd,abc,xa,xa |
|
||||
| d | z | bd,abc,cz,cz |
|
||||
|
||||
|
||||
Scenario: Multiple restricted entrances
|
||||
Given the node map
|
||||
"""
|
||||
b
|
||||
|
|
||||
a----e----c
|
||||
|
|
||||
d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ae |
|
||||
| be |
|
||||
| ce |
|
||||
| de |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | ae,be | ed | e | no_entry |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | d | ae,ce,ce,de,de |
|
||||
| b | d | be,ce,ce,de,de |
|
||||
| c | d | ce,de,de |
|
||||
|
||||
|
||||
Scenario: Multiple restricted exits
|
||||
Given the node map
|
||||
"""
|
||||
b
|
||||
|
|
||||
a----e----c
|
||||
|
|
||||
d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ae |
|
||||
| be |
|
||||
| ce |
|
||||
| de |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | ae | ce,de | e | no_exit |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | b | ae,be,be |
|
||||
| a | c | ae,be,be,ce,ce |
|
||||
| a | d | ae,be,be,de,de |
|
||||
|
||||
|
||||
Scenario: Invalid restricted entrances/exits
|
||||
Given the node map
|
||||
"""
|
||||
b
|
||||
|
|
||||
a----e----c
|
||||
|
|
||||
d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ae |
|
||||
| be |
|
||||
| ce |
|
||||
| de |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | ae | ce,de | e | no_entry |
|
||||
| restriction | ae,be | ed | e | no_exit |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | b | ae,be,be |
|
||||
| a | c | ae,ce,ce |
|
||||
| a | d | ae,de,de |
|
||||
| b | d | be,de,de |
|
||||
| c | d | ce,de,de |
|
||||
|
||||
|
||||
Scenario: Invalid multi from/to restrictions
|
||||
Given the node map
|
||||
"""
|
||||
b
|
||||
|
|
||||
a----e----c
|
||||
|
|
||||
d
|
||||
"""
|
||||
|
||||
And the ways
|
||||
| nodes |
|
||||
| ae |
|
||||
| be |
|
||||
| ce |
|
||||
| de |
|
||||
|
||||
And the relations
|
||||
| type | way:from | way:to | node:via | restriction |
|
||||
| restriction | ae,de | ce,de | e | no_right_turn |
|
||||
| restriction | ae,be | ce,de | e | no_straight_on |
|
||||
| restriction | ae,be | be,ce | e | only_left_turn |
|
||||
| restriction | ae,be | ce,de | e | only_straight_on |
|
||||
|
||||
When I route I should get
|
||||
| from | to | route |
|
||||
| a | b | ae,be,be |
|
||||
| a | c | ae,ce,ce |
|
||||
| a | d | ae,de,de |
|
||||
| b | d | be,de,de |
|
||||
| c | d | ce,de,de |
|
||||
|
@ -44,7 +44,7 @@ class RestrictionParser
|
||||
RestrictionParser(bool use_turn_restrictions,
|
||||
bool parse_conditionals,
|
||||
std::vector<std::string> &restrictions);
|
||||
boost::optional<InputTurnRestriction> TryParse(const osmium::Relation &relation) const;
|
||||
std::vector<InputTurnRestriction> TryParse(const osmium::Relation &relation) const;
|
||||
|
||||
private:
|
||||
bool ShouldIgnoreRestriction(const std::string &except_tag_string) const;
|
||||
|
@ -50,13 +50,13 @@ RestrictionParser::RestrictionParser(bool use_turn_restrictions_,
|
||||
* 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<InputTurnRestriction>
|
||||
std::vector<InputTurnRestriction>
|
||||
RestrictionParser::TryParse(const osmium::Relation &relation) const
|
||||
{
|
||||
// return if turn restrictions should be ignored
|
||||
if (!use_turn_restrictions)
|
||||
{
|
||||
return boost::none;
|
||||
return {};
|
||||
}
|
||||
|
||||
osmium::tags::KeyFilter filter(false);
|
||||
@ -85,17 +85,19 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
|
||||
// if it's not a restriction, continue;
|
||||
if (std::distance(fi_begin, fi_end) == 0)
|
||||
{
|
||||
return boost::none;
|
||||
return {};
|
||||
}
|
||||
|
||||
// check if the restriction should be ignored
|
||||
const char *except = relation.get_value_by_key("except");
|
||||
if (except != nullptr && ShouldIgnoreRestriction(except))
|
||||
{
|
||||
return boost::none;
|
||||
return {};
|
||||
}
|
||||
|
||||
bool is_only_restriction = false;
|
||||
bool is_multi_from = false;
|
||||
bool is_multi_to = false;
|
||||
|
||||
for (; fi_begin != fi_end; ++fi_begin)
|
||||
{
|
||||
@ -111,21 +113,26 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
|
||||
else if (value.find("no_") == 0 && !boost::algorithm::ends_with(value, "_on_red"))
|
||||
{
|
||||
is_only_restriction = false;
|
||||
if (boost::algorithm::starts_with(value, "no_exit"))
|
||||
{
|
||||
is_multi_to = true;
|
||||
}
|
||||
else if (boost::algorithm::starts_with(value, "no_entry"))
|
||||
{
|
||||
is_multi_from = true;
|
||||
}
|
||||
}
|
||||
else // unrecognized value type
|
||||
{
|
||||
return boost::none;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
InputTurnRestriction restriction_container;
|
||||
restriction_container.is_only = is_only_restriction;
|
||||
|
||||
constexpr auto INVALID_OSM_ID = std::numeric_limits<std::uint64_t>::max();
|
||||
auto from = INVALID_OSM_ID;
|
||||
std::vector<OSMWayID> from_ways;
|
||||
auto via_node = INVALID_OSM_ID;
|
||||
std::vector<OSMWayID> via_ways;
|
||||
auto to = INVALID_OSM_ID;
|
||||
std::vector<OSMWayID> to_ways;
|
||||
bool is_node_restriction = true;
|
||||
|
||||
for (const auto &member : relation.members())
|
||||
@ -157,11 +164,11 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
|
||||
0 == strcmp("via", role));
|
||||
if (0 == strcmp("from", role))
|
||||
{
|
||||
from = static_cast<std::uint64_t>(member.ref());
|
||||
from_ways.push_back({static_cast<std::uint64_t>(member.ref())});
|
||||
}
|
||||
else if (0 == strcmp("to", role))
|
||||
{
|
||||
to = static_cast<std::uint64_t>(member.ref());
|
||||
to_ways.push_back({static_cast<std::uint64_t>(member.ref())});
|
||||
}
|
||||
else if (0 == strcmp("via", role))
|
||||
{
|
||||
@ -178,6 +185,7 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<util::OpeningHours> condition;
|
||||
// parse conditional tags
|
||||
if (parse_conditionals)
|
||||
{
|
||||
@ -199,33 +207,55 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
|
||||
std::vector<util::OpeningHours> hours = util::ParseOpeningHours(p.condition);
|
||||
// found unrecognized condition, continue
|
||||
if (hours.empty())
|
||||
return boost::none;
|
||||
return {};
|
||||
|
||||
restriction_container.condition = std::move(hours);
|
||||
condition = std::move(hours);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (from != INVALID_OSM_ID && (via_node != INVALID_OSM_ID || !via_ways.empty()) &&
|
||||
to != INVALID_OSM_ID)
|
||||
std::vector<InputTurnRestriction> restriction_containers;
|
||||
if (!from_ways.empty() && (via_node != INVALID_OSM_ID || !via_ways.empty()) && !to_ways.empty())
|
||||
{
|
||||
if (from_ways.size() > 1 && !is_multi_from)
|
||||
{
|
||||
util::Log(logDEBUG) << "Parsed restriction " << relation.id()
|
||||
<< " unexpectedly contains " << from_ways.size()
|
||||
<< " from ways, skipping...";
|
||||
return {};
|
||||
}
|
||||
if (to_ways.size() > 1 && !is_multi_to)
|
||||
{
|
||||
util::Log(logDEBUG) << "Parsed restriction " << relation.id()
|
||||
<< " unexpectedly contains " << to_ways.size()
|
||||
<< " to ways, skipping...";
|
||||
return {};
|
||||
}
|
||||
// Internally restrictions are represented with one 'from' and one 'to' way.
|
||||
// Therefore we need to convert a multi from/to restriction into multiple restrictions.
|
||||
for (const auto &from : from_ways)
|
||||
{
|
||||
for (const auto &to : to_ways)
|
||||
{
|
||||
InputTurnRestriction restriction;
|
||||
restriction.is_only = is_only_restriction;
|
||||
restriction.condition = condition;
|
||||
if (is_node_restriction)
|
||||
{
|
||||
// template struct requires bracket for ID initialisation :(
|
||||
restriction_container.node_or_way = InputNodeRestriction{{from}, {via_node}, {to}};
|
||||
restriction.node_or_way = InputNodeRestriction{{from}, {via_node}, {to}};
|
||||
}
|
||||
else
|
||||
{
|
||||
// template struct requires bracket for ID initialisation :(
|
||||
restriction_container.node_or_way = InputWayRestriction{{from}, via_ways, {to}};
|
||||
restriction.node_or_way = InputWayRestriction{{from}, via_ways, {to}};
|
||||
}
|
||||
return restriction_container;
|
||||
restriction_containers.push_back(std::move(restriction));
|
||||
}
|
||||
else
|
||||
{
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
return restriction_containers;
|
||||
}
|
||||
|
||||
bool RestrictionParser::ShouldIgnoreRestriction(const std::string &except_tag_string) const
|
||||
{
|
||||
|
@ -909,13 +909,15 @@ void Sol2ScriptingEnvironment::ProcessElements(
|
||||
case osmium::item_type::relation:
|
||||
{
|
||||
const auto &relation = static_cast<const osmium::Relation &>(*entity);
|
||||
if (auto result_res = restriction_parser.TryParse(relation))
|
||||
auto results = restriction_parser.TryParse(relation);
|
||||
if (!results.empty())
|
||||
{
|
||||
resulting_restrictions.push_back(*result_res);
|
||||
std::move(
|
||||
results.begin(), results.end(), std::back_inserter(resulting_restrictions));
|
||||
}
|
||||
else if (auto result_res = maneuver_override_parser.TryParse(relation))
|
||||
{
|
||||
resulting_maneuver_overrides.push_back(*result_res);
|
||||
resulting_maneuver_overrides.push_back(std::move(*result_res));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
Loading…
Reference in New Issue
Block a user