Improvements to maneuver override processing (#6215)
This change unblocks the osrm-extract debug build, which is currently failing on a maneuver override assertion. The processing of maneuver overrides currently has three issues - It assumes the via node(s) can't be compressed (the failing assertion) - It can't handle via-paths containing incompressible nodes - It doesn't interop with turn restriction on the same path Turn restrictions and maneuver overrides both use the same from-via-to path representation. Therefore, we can fix these issues by consolidating their structures and reusing the path representation for turn restrictions, which already is robust to the above issues. This also simplifies some of the codebase by removing maneuver override specific path processing. There are ~100 maneuver overrides in the OSM database, so the impact on processing and routing will be minimal.
This commit is contained in:
@@ -152,6 +152,228 @@ std::tuple<OSMNodeID, OSMNodeID, OSMNodeID> find_turn_nodes(const oe::NodesOfWay
|
||||
}
|
||||
return std::make_tuple(SPECIAL_OSM_NODEID, SPECIAL_OSM_NODEID, SPECIAL_OSM_NODEID);
|
||||
}
|
||||
|
||||
// Via-node paths describe a relation between the two segments closest
|
||||
// to the shared via-node on the from and to ways.
|
||||
// from: [a, b, c, d, e]
|
||||
// to: [f, g, h, i, j]
|
||||
//
|
||||
// The via node establishes the orientation of the from/to intersection when choosing the
|
||||
// segments.
|
||||
// via | node path
|
||||
// a=f | b,a,g
|
||||
// a=j | b,a,i
|
||||
// e=f | d,e,g
|
||||
// e=j | d,e,i
|
||||
oe::ViaNodePath find_via_node_path(const std::string &turn_relation_type,
|
||||
const oe::NodesOfWay &from_segment,
|
||||
const oe::NodesOfWay &to_segment,
|
||||
const OSMNodeID via_node,
|
||||
const std::function<NodeID(OSMNodeID)> &to_internal_node)
|
||||
{
|
||||
|
||||
OSMNodeID from, via, to;
|
||||
std::tie(from, via, to) = find_turn_nodes(from_segment, to_segment, via_node);
|
||||
if (via == SPECIAL_OSM_NODEID)
|
||||
{
|
||||
// unconnected
|
||||
osrm::util::Log(logDEBUG) << turn_relation_type
|
||||
<< " references unconnected way: " << from_segment.way_id;
|
||||
return oe::ViaNodePath{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
}
|
||||
return oe::ViaNodePath{to_internal_node(from), to_internal_node(via), to_internal_node(to)};
|
||||
}
|
||||
|
||||
// Via way paths are comprised of:
|
||||
// 1. The segment in the from way that intersects with the via ways
|
||||
// 2. All segments that make up the via path
|
||||
// 3. The segment in the to way that intersects with the via path.
|
||||
//
|
||||
// from: [a, b, c, d, e]
|
||||
// via: [[f, g, h, i, j], [k, l], [m, n, o]]
|
||||
// to: [p, q, r, s]
|
||||
//
|
||||
// First establish the orientation of the from/via intersection by finding which end
|
||||
// nodes both ways share. From this we can select the from segment.
|
||||
//
|
||||
// intersect | from segment | next_connection
|
||||
// a=f | b,a | f
|
||||
// a=j | b,a | j
|
||||
// e=f | e,d | f
|
||||
// e=j | e,d | j
|
||||
//
|
||||
// Use the next connection to inform the orientation of the first via
|
||||
// way and the intersection between first and second via ways.
|
||||
//
|
||||
// next_connection | intersect | via result | next_next_connection
|
||||
// f | j=k | [f,g,h,i,j] | k
|
||||
// f | j=l | [f,g,h,i,j] | l
|
||||
// j | f=k | [j,i,h,g,f] | k
|
||||
// j | f=l | [j,i,h,g,f] | l
|
||||
//
|
||||
// This is continued for the remaining via ways, appending to the via result
|
||||
//
|
||||
// The final via/to intersection also uses the next_connection information in a similar fashion.
|
||||
//
|
||||
// next_connection | intersect | to_segment
|
||||
// m | o=p | p,q
|
||||
// m | o=s | s,r
|
||||
// o | m=p | p,q
|
||||
// o | m=s | s,r
|
||||
//
|
||||
// The final result is a list of nodes that represent a valid from->via->to path through the
|
||||
// ways.
|
||||
//
|
||||
// E.g. if intersection nodes are a=j, f=l, k=o, m=s
|
||||
// the result will be {e [d,c,b,a,i,h,g,f,k,n,m] r}
|
||||
oe::ViaWayPath find_via_way_path(const std::string &turn_relation_type,
|
||||
const oe::NodesOfWay &from_way,
|
||||
const std::vector<oe::NodesOfWay> &via_ways,
|
||||
const oe::NodesOfWay &to_way,
|
||||
const std::function<NodeID(OSMNodeID)> &to_internal_node)
|
||||
{
|
||||
BOOST_ASSERT(!via_ways.empty());
|
||||
|
||||
oe::ViaWayPath way_path;
|
||||
|
||||
// Find the orientation of the connected ways starting with the from-via intersection.
|
||||
OSMNodeID from, via;
|
||||
std::tie(from, via, std::ignore) =
|
||||
find_turn_nodes(from_way, via_ways.front(), SPECIAL_OSM_NODEID);
|
||||
if (via == SPECIAL_OSM_NODEID)
|
||||
{
|
||||
osrm::util::Log(logDEBUG) << turn_relation_type
|
||||
<< " has unconnected from and via ways: " << from_way.way_id
|
||||
<< ", " << via_ways.front().way_id;
|
||||
return oe::ViaWayPath{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
way_path.from = to_internal_node(from);
|
||||
way_path.via.push_back(to_internal_node(via));
|
||||
|
||||
// Use the connection node from the previous intersection to inform our conversion of
|
||||
// via ways into internal nodes.
|
||||
OSMNodeID next_connection = via;
|
||||
for (const auto &via_way : via_ways)
|
||||
{
|
||||
if (next_connection == via_way.first_segment_source_id())
|
||||
{
|
||||
std::transform(std::next(via_way.node_ids.begin()),
|
||||
via_way.node_ids.end(),
|
||||
std::back_inserter(way_path.via),
|
||||
to_internal_node);
|
||||
next_connection = via_way.last_segment_target_id();
|
||||
}
|
||||
else if (next_connection == via_way.last_segment_target_id())
|
||||
{
|
||||
std::transform(std::next(via_way.node_ids.rbegin()),
|
||||
via_way.node_ids.rend(),
|
||||
std::back_inserter(way_path.via),
|
||||
to_internal_node);
|
||||
next_connection = via_way.first_segment_source_id();
|
||||
}
|
||||
else
|
||||
{
|
||||
osrm::util::Log(logDEBUG)
|
||||
<< turn_relation_type << " has unconnected via way: " << via_way.way_id
|
||||
<< " to node " << next_connection;
|
||||
return oe::ViaWayPath{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
}
|
||||
|
||||
// Add the final to node after the via-to intersection.
|
||||
if (next_connection == to_way.first_segment_source_id())
|
||||
{
|
||||
way_path.to = to_internal_node(to_way.first_segment_target_id());
|
||||
}
|
||||
else if (next_connection == to_way.last_segment_target_id())
|
||||
{
|
||||
way_path.to = to_internal_node(to_way.last_segment_source_id());
|
||||
}
|
||||
else
|
||||
{
|
||||
osrm::util::Log(logDEBUG) << turn_relation_type
|
||||
<< " has unconnected via and to ways: " << via_ways.back().way_id
|
||||
<< ", " << to_way.way_id;
|
||||
return oe::ViaWayPath{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
return way_path;
|
||||
}
|
||||
|
||||
// Check if we were able to resolve all the involved OSM elements before translating to an
|
||||
// internal via-way turn path
|
||||
oe::ViaWayPath
|
||||
get_via_way_path_from_OSM_ids(const std::string &turn_relation_type,
|
||||
const std::unordered_map<OSMWayID, oe::NodesOfWay> &referenced_ways,
|
||||
const OSMWayID from_id,
|
||||
const OSMWayID to_id,
|
||||
const std::vector<OSMWayID> &via_ids,
|
||||
const std::function<NodeID(OSMNodeID)> &to_internal_node)
|
||||
{
|
||||
auto const from_way_itr = referenced_ways.find(from_id);
|
||||
if (from_way_itr->second.way_id != from_id)
|
||||
{
|
||||
osrm::util::Log(logDEBUG) << turn_relation_type
|
||||
<< " references invalid from way: " << from_id;
|
||||
return oe::ViaWayPath{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
|
||||
std::vector<oe::NodesOfWay> via_ways;
|
||||
for (const auto &via_id : via_ids)
|
||||
{
|
||||
auto const via_segment_itr = referenced_ways.find(via_id);
|
||||
if (via_segment_itr->second.way_id != via_id)
|
||||
{
|
||||
osrm::util::Log(logDEBUG)
|
||||
<< turn_relation_type << " references invalid via way: " << via_id;
|
||||
return oe::ViaWayPath{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
via_ways.push_back(via_segment_itr->second);
|
||||
}
|
||||
|
||||
auto const to_way_itr = referenced_ways.find(to_id);
|
||||
if (to_way_itr->second.way_id != to_id)
|
||||
{
|
||||
osrm::util::Log(logDEBUG) << turn_relation_type << " references invalid to way: " << to_id;
|
||||
return oe::ViaWayPath{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
|
||||
return find_via_way_path(
|
||||
turn_relation_type, from_way_itr->second, via_ways, to_way_itr->second, to_internal_node);
|
||||
}
|
||||
|
||||
// Check if we were able to resolve all the involved OSM elements before translating to an
|
||||
// internal via-node turn path
|
||||
oe::ViaNodePath
|
||||
get_via_node_path_from_OSM_ids(const std::string &turn_relation_type,
|
||||
const std::unordered_map<OSMWayID, oe::NodesOfWay> &referenced_ways,
|
||||
const OSMWayID from_id,
|
||||
const OSMWayID to_id,
|
||||
const OSMNodeID via_node,
|
||||
const std::function<NodeID(OSMNodeID)> &to_internal_node)
|
||||
{
|
||||
|
||||
auto const from_segment_itr = referenced_ways.find(from_id);
|
||||
|
||||
if (from_segment_itr->second.way_id != from_id)
|
||||
{
|
||||
osrm::util::Log(logDEBUG) << turn_relation_type << " references invalid way: " << from_id;
|
||||
return oe::ViaNodePath{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
}
|
||||
|
||||
auto const to_segment_itr = referenced_ways.find(to_id);
|
||||
if (to_segment_itr->second.way_id != to_id)
|
||||
{
|
||||
osrm::util::Log(logDEBUG) << turn_relation_type << " references invalid way: " << to_id;
|
||||
return oe::ViaNodePath{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
}
|
||||
|
||||
return find_via_node_path(turn_relation_type,
|
||||
from_segment_itr->second,
|
||||
to_segment_itr->second,
|
||||
via_node,
|
||||
to_internal_node);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace osrm
|
||||
@@ -177,10 +399,10 @@ ExtractionContainers::ExtractionContainers()
|
||||
* Processes the collected data and serializes it.
|
||||
* At this point nodes are still referenced by their OSM id.
|
||||
*
|
||||
* - map start-end nodes of ways to ways used in restrictions to compute compressed
|
||||
* trippe representation
|
||||
* - filter nodes list to nodes that are referenced by ways
|
||||
* - merge edges with nodes to include location of start/end points and serialize
|
||||
* - Identify nodes of ways used in restrictions and maneuver overrides
|
||||
* - Filter nodes list to nodes that are referenced by ways
|
||||
* - Prepare edges and compute routing properties
|
||||
* - Prepare and validate restrictions and maneuver overrides
|
||||
*
|
||||
*/
|
||||
void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environment,
|
||||
@@ -723,11 +945,17 @@ ExtractionContainers::ReferencedWays ExtractionContainers::IdentifyManeuverOverr
|
||||
|
||||
const auto mark_ids = [&](auto const &external_maneuver_override) {
|
||||
NodesOfWay dummy_segment{MAX_OSM_WAYID, {MAX_OSM_NODEID, MAX_OSM_NODEID}};
|
||||
std::for_each(external_maneuver_override.via_ways.begin(),
|
||||
external_maneuver_override.via_ways.end(),
|
||||
[&maneuver_override_ways, dummy_segment](const auto &element) {
|
||||
maneuver_override_ways[element] = dummy_segment;
|
||||
});
|
||||
const auto &turn_path = external_maneuver_override.turn_path;
|
||||
maneuver_override_ways[turn_path.From()] = dummy_segment;
|
||||
maneuver_override_ways[turn_path.To()] = dummy_segment;
|
||||
if (external_maneuver_override.turn_path.Type() == TurnPathType::VIA_WAY_TURN_PATH)
|
||||
{
|
||||
const auto &way = turn_path.AsViaWayPath();
|
||||
for (const auto &via : way.via)
|
||||
{
|
||||
maneuver_override_ways[via] = dummy_segment;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// First, make an empty hashtable keyed by the ways referenced
|
||||
@@ -767,36 +995,6 @@ void ExtractionContainers::PrepareManeuverOverrides(const ReferencedWays &maneuv
|
||||
return internal;
|
||||
};
|
||||
|
||||
auto const get_turn_from_way_pair = [&](const OSMWayID &from_id, const OSMWayID &to_id) {
|
||||
auto const from_segment_itr = maneuver_override_ways.find(from_id);
|
||||
if (from_segment_itr->second.way_id != from_id)
|
||||
{
|
||||
util::Log(logDEBUG) << "Override references invalid way: " << from_id;
|
||||
return NodeBasedTurn{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
}
|
||||
|
||||
auto const to_segment_itr = maneuver_override_ways.find(to_id);
|
||||
if (to_segment_itr->second.way_id != to_id)
|
||||
{
|
||||
util::Log(logDEBUG) << "Override references invalid way: " << to_id;
|
||||
return NodeBasedTurn{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
}
|
||||
|
||||
OSMNodeID from, via, to;
|
||||
std::tie(from, via, to) =
|
||||
find_turn_nodes(from_segment_itr->second, to_segment_itr->second, SPECIAL_OSM_NODEID);
|
||||
if (via == SPECIAL_OSM_NODEID)
|
||||
{
|
||||
// unconnected
|
||||
util::Log(logDEBUG) << "Maneuver override ways " << from_segment_itr->second.way_id
|
||||
<< " and " << to_segment_itr->second.way_id << " are not connected";
|
||||
return NodeBasedTurn{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
}
|
||||
return NodeBasedTurn{osm_node_to_internal_nbn(from),
|
||||
osm_node_to_internal_nbn(via),
|
||||
osm_node_to_internal_nbn(to)};
|
||||
};
|
||||
|
||||
const auto strings_to_turn_type_and_direction = [](const std::string &turn_string,
|
||||
const std::string &direction_string) {
|
||||
auto result = std::make_pair(guidance::TurnType::MaxTurnType,
|
||||
@@ -862,44 +1060,36 @@ void ExtractionContainers::PrepareManeuverOverrides(const ReferencedWays &maneuv
|
||||
// Returns true on successful transformation, false in case of invalid references.
|
||||
// Later, the UnresolvedManeuverOverride will be converted into a final ManeuverOverride
|
||||
// once the edge-based-node IDs are generated by the edge-based-graph-factory
|
||||
const auto transform = [&](const auto &external, auto &internal) {
|
||||
// Create a stub override
|
||||
auto maneuver_override =
|
||||
UnresolvedManeuverOverride{{},
|
||||
osm_node_to_internal_nbn(external.via_node),
|
||||
guidance::TurnType::Invalid,
|
||||
guidance::DirectionModifier::MaxDirectionModifier};
|
||||
|
||||
// Convert Way IDs into node-based-node IDs
|
||||
// We iterate from back to front here because the first node in the node_sequence
|
||||
// must eventually be a source node, but all the others must be targets.
|
||||
// the get_internal_pairs_from_ways returns (source,target), so if we
|
||||
// iterate backwards, we will end up with source,target,target,target,target
|
||||
// in a sequence, which is what we want
|
||||
for (auto i = 0ul; i < external.via_ways.size() - 1; ++i)
|
||||
const auto transform = [&](const auto &external_type, auto &internal_type) {
|
||||
if (external_type.turn_path.Type() == TurnPathType::VIA_WAY_TURN_PATH)
|
||||
{
|
||||
// returns the two far ends of the referenced ways
|
||||
auto turn = get_turn_from_way_pair(external.via_ways[i], external.via_ways[i + 1]);
|
||||
|
||||
maneuver_override.turn_sequence.push_back(turn);
|
||||
auto const &external = external_type.turn_path.AsViaWayPath();
|
||||
internal_type.turn_path.node_or_way =
|
||||
get_via_way_path_from_OSM_ids(internal_type.Name(),
|
||||
maneuver_override_ways,
|
||||
external.from,
|
||||
external.to,
|
||||
external.via,
|
||||
osm_node_to_internal_nbn);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(external_type.turn_path.Type() == TurnPathType::VIA_NODE_TURN_PATH);
|
||||
auto const &external = external_type.turn_path.AsViaNodePath();
|
||||
internal_type.turn_path.node_or_way =
|
||||
get_via_node_path_from_OSM_ids(internal_type.Name(),
|
||||
maneuver_override_ways,
|
||||
external.from,
|
||||
external.to,
|
||||
external.via,
|
||||
osm_node_to_internal_nbn);
|
||||
}
|
||||
|
||||
// check if we were able to resolve all the involved ways
|
||||
// auto maneuver_override =
|
||||
// get_maneuver_override_from_OSM_ids(external.from, external.to,
|
||||
// external.via_node);
|
||||
internal_type.instruction_node = osm_node_to_internal_nbn(external_type.via_node),
|
||||
std::tie(internal_type.override_type, internal_type.direction) =
|
||||
strings_to_turn_type_and_direction(external_type.maneuver, external_type.direction);
|
||||
|
||||
std::tie(maneuver_override.override_type, maneuver_override.direction) =
|
||||
strings_to_turn_type_and_direction(external.maneuver, external.direction);
|
||||
|
||||
if (!maneuver_override.Valid())
|
||||
{
|
||||
util::Log(logDEBUG) << "Override is invalid";
|
||||
return false;
|
||||
}
|
||||
|
||||
internal = std::move(maneuver_override);
|
||||
return true;
|
||||
return internal_type.Valid();
|
||||
};
|
||||
|
||||
const auto transform_into_internal_types =
|
||||
@@ -925,7 +1115,7 @@ void ExtractionContainers::PrepareManeuverOverrides(const ReferencedWays &maneuv
|
||||
|
||||
ExtractionContainers::ReferencedWays ExtractionContainers::IdentifyRestrictionWays()
|
||||
{
|
||||
// Contains the nodes of each way that is part of an restriction
|
||||
// Contains the nodes of each way that is part of a restriction
|
||||
ReferencedWays restriction_ways;
|
||||
|
||||
// Prepare for extracting nodes for all restrictions
|
||||
@@ -937,23 +1127,17 @@ ExtractionContainers::ReferencedWays ExtractionContainers::IdentifyRestrictionWa
|
||||
// nodes of these ways.
|
||||
const auto mark_ids = [&](auto const &turn_restriction) {
|
||||
NodesOfWay dummy_segment{MAX_OSM_WAYID, {MAX_OSM_NODEID, MAX_OSM_NODEID}};
|
||||
if (turn_restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
||||
const auto &turn_path = turn_restriction.turn_path;
|
||||
restriction_ways[turn_path.From()] = dummy_segment;
|
||||
restriction_ways[turn_path.To()] = dummy_segment;
|
||||
if (turn_path.Type() == TurnPathType::VIA_WAY_TURN_PATH)
|
||||
{
|
||||
const auto &way = turn_restriction.AsWayRestriction();
|
||||
restriction_ways[way.from] = dummy_segment;
|
||||
restriction_ways[way.to] = dummy_segment;
|
||||
for (const auto &v : way.via)
|
||||
const auto &way = turn_path.AsViaWayPath();
|
||||
for (const auto &via : way.via)
|
||||
{
|
||||
restriction_ways[v] = dummy_segment;
|
||||
restriction_ways[via] = dummy_segment;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(turn_restriction.Type() == RestrictionType::NODE_RESTRICTION);
|
||||
const auto &node = turn_restriction.AsNodeRestriction();
|
||||
restriction_ways[node.from] = dummy_segment;
|
||||
restriction_ways[node.to] = dummy_segment;
|
||||
}
|
||||
};
|
||||
|
||||
std::for_each(restrictions_list.begin(), restrictions_list.end(), mark_ids);
|
||||
@@ -992,234 +1176,41 @@ void ExtractionContainers::PrepareRestrictions(const ReferencedWays &restriction
|
||||
return internal;
|
||||
};
|
||||
|
||||
// Way restrictions are comprised of:
|
||||
// 1. The segment in the from way that intersects with the via path
|
||||
// 2. All segments that make up the via path
|
||||
// 3. The segment in the to way that intersects with the via path.
|
||||
//
|
||||
// from: [a, b, c, d, e]
|
||||
// via: [[f, g, h, i, j], [k, l], [m, n, o]]
|
||||
// to: [p, q, r, s]
|
||||
//
|
||||
// First establish the orientation of the from/via intersection by finding which end
|
||||
// nodes both ways share. From this we can select the from segment.
|
||||
//
|
||||
// intersect | from segment | next_connection
|
||||
// a=f | b,a | f
|
||||
// a=j | b,a | j
|
||||
// e=f | e,d | f
|
||||
// e=j | e,d | j
|
||||
//
|
||||
// Use the next connection to inform the orientation of the first via
|
||||
// way and the intersection between first and second via ways.
|
||||
//
|
||||
// next_connection | intersect | via result | next_next_connection
|
||||
// f | j=k | [f,g,h,i,j] | k
|
||||
// f | j=l | [f,g,h,i,j] | l
|
||||
// j | f=k | [j,i,h,g,f] | k
|
||||
// j | f=l | [j,i,h,g,f] | l
|
||||
//
|
||||
// This is continued for the remaining via ways, appending to the via result
|
||||
//
|
||||
// The final via/to intersection also uses the next_connection information in a similar fashion.
|
||||
//
|
||||
// next_connection | intersect | to_segment
|
||||
// m | o=p | p,q
|
||||
// m | o=s | s,r
|
||||
// o | m=p | p,q
|
||||
// o | m=s | s,r
|
||||
//
|
||||
// The final result is a list of nodes that represent a valid from->via->to path through the
|
||||
// ways.
|
||||
//
|
||||
// E.g. if intersection nodes are a=j, f=l, k=o, m=s
|
||||
// the result will be {e [d,c,b,a,i,h,g,f,k,n,m] r}
|
||||
auto const find_way_restriction = [&](const NodesOfWay &from_way,
|
||||
const std::vector<NodesOfWay> &via_ways,
|
||||
const NodesOfWay &to_way) {
|
||||
BOOST_ASSERT(!via_ways.empty());
|
||||
|
||||
WayRestriction restriction;
|
||||
|
||||
// Find the orientation of the connected ways starting with the from-via intersection.
|
||||
OSMNodeID from, via;
|
||||
std::tie(from, via, std::ignore) =
|
||||
find_turn_nodes(from_way, via_ways.front(), SPECIAL_OSM_NODEID);
|
||||
if (via == SPECIAL_OSM_NODEID)
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction has unconnected from and via ways: "
|
||||
<< from_way.way_id << ", " << via_ways.front().way_id;
|
||||
return WayRestriction{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
restriction.from = to_internal(from);
|
||||
restriction.via.push_back(to_internal(via));
|
||||
|
||||
// Use the connection node from the previous intersection to inform our conversion of
|
||||
// via ways into internal nodes.
|
||||
OSMNodeID next_connection = via;
|
||||
for (const auto &via_way : via_ways)
|
||||
{
|
||||
if (next_connection == via_way.first_segment_source_id())
|
||||
{
|
||||
std::transform(std::next(via_way.node_ids.begin()),
|
||||
via_way.node_ids.end(),
|
||||
std::back_inserter(restriction.via),
|
||||
to_internal);
|
||||
next_connection = via_way.last_segment_target_id();
|
||||
}
|
||||
else if (next_connection == via_way.last_segment_target_id())
|
||||
{
|
||||
std::transform(std::next(via_way.node_ids.rbegin()),
|
||||
via_way.node_ids.rend(),
|
||||
std::back_inserter(restriction.via),
|
||||
to_internal);
|
||||
next_connection = via_way.first_segment_source_id();
|
||||
}
|
||||
else
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction has unconnected via way: " << via_way.way_id
|
||||
<< " to node " << next_connection;
|
||||
return WayRestriction{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
}
|
||||
|
||||
// Add the final to node after the via-to intersection.
|
||||
if (next_connection == to_way.first_segment_source_id())
|
||||
{
|
||||
restriction.to = to_internal(to_way.first_segment_target_id());
|
||||
}
|
||||
else if (next_connection == to_way.last_segment_target_id())
|
||||
{
|
||||
restriction.to = to_internal(to_way.last_segment_source_id());
|
||||
}
|
||||
else
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction has unconnected via and to ways: "
|
||||
<< via_ways.back().way_id << ", " << to_way.way_id;
|
||||
return WayRestriction{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
return restriction;
|
||||
};
|
||||
|
||||
// Check if we were able to resolve all the involved OSM elements before translating to an
|
||||
// internal restriction
|
||||
auto const get_way_restriction_from_OSM_ids =
|
||||
[&](auto const from_id, auto const to_id, const std::vector<OSMWayID> &via_ids) {
|
||||
auto const from_way_itr = restriction_ways.find(from_id);
|
||||
if (from_way_itr->second.way_id != from_id)
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction references invalid from way: " << from_id;
|
||||
return WayRestriction{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
|
||||
std::vector<NodesOfWay> via_ways;
|
||||
for (const auto &via_id : via_ids)
|
||||
{
|
||||
auto const via_segment_itr = restriction_ways.find(via_id);
|
||||
if (via_segment_itr->second.way_id != via_id)
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction references invalid via way: " << via_id;
|
||||
return WayRestriction{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
via_ways.push_back(via_segment_itr->second);
|
||||
}
|
||||
|
||||
auto const to_way_itr = restriction_ways.find(to_id);
|
||||
if (to_way_itr->second.way_id != to_id)
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction references invalid to way: " << to_id;
|
||||
return WayRestriction{SPECIAL_NODEID, {}, SPECIAL_NODEID};
|
||||
}
|
||||
|
||||
return find_way_restriction(from_way_itr->second, via_ways, to_way_itr->second);
|
||||
};
|
||||
|
||||
// Node restrictions are described as a restriction between the two segments closest
|
||||
// to the shared via-node on the from and to ways.
|
||||
// from: [a, b, c, d, e]
|
||||
// to: [f, g, h, i, j]
|
||||
//
|
||||
// The via node establishes the orientation of the from/to intersection when choosing the
|
||||
// segments.
|
||||
// via | node restriction
|
||||
// a=f | b,a,g
|
||||
// a=j | b,a,i
|
||||
// e=f | d,e,g
|
||||
// e=j | d,e,i
|
||||
auto const find_node_restriction =
|
||||
[&](auto const &from_segment, auto const &to_segment, auto const via_node) {
|
||||
OSMNodeID from, via, to;
|
||||
std::tie(from, via, to) = find_turn_nodes(from_segment, to_segment, via_node);
|
||||
if (via == SPECIAL_OSM_NODEID)
|
||||
{
|
||||
// unconnected
|
||||
util::Log(logDEBUG)
|
||||
<< "Restriction references unconnected way: " << from_segment.way_id;
|
||||
return NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
}
|
||||
return NodeRestriction{to_internal(from), to_internal(via), to_internal(to)};
|
||||
};
|
||||
|
||||
// Check if we were able to resolve all the involved OSM elements before translating to an
|
||||
// internal restriction
|
||||
auto const get_node_restriction_from_OSM_ids = [&](auto const from_id,
|
||||
auto const to_id,
|
||||
const OSMNodeID via_node) {
|
||||
auto const from_segment_itr = restriction_ways.find(from_id);
|
||||
|
||||
if (from_segment_itr->second.way_id != from_id)
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction references invalid way: " << from_id;
|
||||
return NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
}
|
||||
|
||||
auto const to_segment_itr = restriction_ways.find(to_id);
|
||||
if (to_segment_itr->second.way_id != to_id)
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction references invalid way: " << to_id;
|
||||
return NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
|
||||
}
|
||||
|
||||
return find_node_restriction(from_segment_itr->second, to_segment_itr->second, via_node);
|
||||
};
|
||||
|
||||
// Transform an OSMRestriction (based on WayIDs) into an OSRM restriction (base on NodeIDs).
|
||||
// Returns true on successful transformation, false in case of invalid references.
|
||||
const auto transform = [&](const auto &external_type, auto &internal_type) {
|
||||
if (external_type.Type() == RestrictionType::WAY_RESTRICTION)
|
||||
if (external_type.turn_path.Type() == TurnPathType::VIA_WAY_TURN_PATH)
|
||||
{
|
||||
auto const &external = external_type.AsWayRestriction();
|
||||
auto const restriction =
|
||||
get_way_restriction_from_OSM_ids(external.from, external.to, external.via);
|
||||
|
||||
if (!restriction.Valid())
|
||||
return false;
|
||||
|
||||
internal_type.node_or_way = restriction;
|
||||
return true;
|
||||
auto const &external = external_type.turn_path.AsViaWayPath();
|
||||
internal_type.turn_path.node_or_way =
|
||||
get_via_way_path_from_OSM_ids(internal_type.Name(),
|
||||
restriction_ways,
|
||||
external.from,
|
||||
external.to,
|
||||
external.via,
|
||||
to_internal);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(external_type.Type() == RestrictionType::NODE_RESTRICTION);
|
||||
auto const &external = external_type.AsNodeRestriction();
|
||||
|
||||
auto restriction =
|
||||
get_node_restriction_from_OSM_ids(external.from, external.to, external.via);
|
||||
|
||||
if (!restriction.Valid())
|
||||
return false;
|
||||
|
||||
internal_type.node_or_way = restriction;
|
||||
return true;
|
||||
BOOST_ASSERT(external_type.turn_path.Type() == TurnPathType::VIA_NODE_TURN_PATH);
|
||||
auto const &external = external_type.turn_path.AsViaNodePath();
|
||||
internal_type.turn_path.node_or_way =
|
||||
get_via_node_path_from_OSM_ids(internal_type.Name(),
|
||||
restriction_ways,
|
||||
external.from,
|
||||
external.to,
|
||||
external.via,
|
||||
to_internal);
|
||||
}
|
||||
internal_type.is_only = external_type.is_only;
|
||||
internal_type.condition = std::move(external_type.condition);
|
||||
return internal_type.Valid();
|
||||
};
|
||||
|
||||
const auto transform_into_internal_types = [&](InputTurnRestriction &external_restriction) {
|
||||
TurnRestriction restriction;
|
||||
if (transform(external_restriction, restriction))
|
||||
{
|
||||
restriction.is_only = external_restriction.is_only;
|
||||
restriction.condition = std::move(external_restriction.condition);
|
||||
turn_restrictions.push_back(std::move(restriction));
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user