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:
Michael Bell
2022-08-24 16:19:24 +01:00
committed by GitHub
parent 8e74b7af9d
commit a98074a051
24 changed files with 1224 additions and 1045 deletions
+94 -47
View File
@@ -10,24 +10,19 @@
#include "storage/io.hpp"
#include "util/assert.hpp"
#include "util/bearing.hpp"
#include "util/connectivity_checksum.hpp"
#include "util/coordinate.hpp"
#include "util/coordinate_calculation.hpp"
#include "util/exception.hpp"
#include "util/integer_range.hpp"
#include "util/log.hpp"
#include "util/percent.hpp"
#include "util/timing_util.hpp"
#include <boost/assert.hpp>
#include <boost/crc.hpp>
#include <boost/functional/hash.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <algorithm>
#include <cmath>
#include <iomanip>
#include <limits>
#include <sstream>
#include <string>
@@ -451,6 +446,17 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
{
util::Log() << "Generating edge-expanded edges ";
// Keep a set of all maneuver turns so we can identify them as
// we generate the edge-expansion.
std::unordered_set<NodeBasedTurn> unresolved_turns;
for (const auto &manuevers : unresolved_maneuver_overrides)
{
for (const auto &turn : manuevers.Turns())
{
unresolved_turns.insert(turn);
}
}
std::size_t node_based_edge_counter = 0;
SuffixTable street_name_suffix_table(scripting_environment);
@@ -514,7 +520,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
std::vector<EdgeWithData> delayed_data; // may need this
std::vector<Conditional> conditionals;
std::unordered_map<NodeBasedTurn, std::pair<NodeID, NodeID>> turn_to_ebn_map;
std::unordered_multimap<NodeBasedTurn, std::pair<NodeID, NodeID>> turn_to_ebn_map;
util::ConnectivityChecksum checksum;
};
@@ -522,7 +528,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
m_connectivity_checksum = 0;
std::unordered_map<NodeBasedTurn, std::pair<NodeID, NodeID>> global_turn_to_ebn_map;
std::unordered_multimap<NodeBasedTurn, std::pair<NodeID, NodeID>> global_turn_to_ebn_map;
// going over all nodes (which form the center of an intersection), we compute all possible
// turns along these intersections.
@@ -894,24 +900,16 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
const auto outgoing_edge_target =
m_node_based_graph.GetTarget(outgoing_edge.edge);
// TODO: this loop is not optimized - once we have a few
// overrides available, we should index this for faster
// lookups
for (auto &override : unresolved_maneuver_overrides)
const auto turn_nodes = NodeBasedTurn{
incoming_edge.node, intersection_node, outgoing_edge_target};
const auto is_maneuver_turn = unresolved_turns.count(turn_nodes) > 0;
if (is_maneuver_turn)
{
for (auto &turn : override.turn_sequence)
{
if (turn.from == incoming_edge.node &&
turn.via == intersection_node &&
turn.to == outgoing_edge_target)
{
const auto &ebn_from =
nbe_to_ebn_mapping[incoming_edge.edge];
const auto &ebn_to = target_id;
buffer->turn_to_ebn_map[turn] =
std::make_pair(ebn_from, ebn_to);
}
}
const auto &ebn_from = nbe_to_ebn_mapping[incoming_edge.edge];
const auto &ebn_to = target_id;
buffer->turn_to_ebn_map.insert(
{turn_nodes, std::make_pair(ebn_from, ebn_to)});
}
{ // scope to forget edge_with_data after
@@ -1025,6 +1023,16 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
m_coordinates[intersection_node],
restriction->condition}});
}
// We also need to track maneuvers that traverse duplicate
// edges
if (is_maneuver_turn)
{
const auto &ebn_from = from_id;
const auto &ebn_to = via_target_id;
buffer->turn_to_ebn_map.insert(
{turn_nodes, std::make_pair(ebn_from, ebn_to)});
}
}
else
{
@@ -1053,6 +1061,16 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
edge_geometries);
buffer->delayed_data.push_back(edge_with_data);
// We also need to track maneuvers that traverse duplicate
// edges
if (is_maneuver_turn)
{
const auto &ebn_from = from_id;
const auto &ebn_to = via_target_id;
buffer->turn_to_ebn_map.insert(
{turn_nodes, std::make_pair(ebn_from, ebn_to)});
}
}
}
}
@@ -1107,35 +1125,64 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
// Now, replace node-based-node ID values in the `node_sequence` with
// the edge-based-node values we found and stored in the `turn_to_ebn_map`
for (auto &unresolved_override : unresolved_maneuver_overrides)
for (const auto &unresolved_override : unresolved_maneuver_overrides)
{
StorageManeuverOverride storage_override;
storage_override.instruction_node = unresolved_override.instruction_node;
storage_override.override_type = unresolved_override.override_type;
storage_override.direction = unresolved_override.direction;
// There can be multiple edge-based-node sequences for a node-based-turn sequence
// due to duplicate edges in the restriction graph.
std::vector<std::vector<NodeID>> node_sequences;
std::vector<NodeID> node_sequence(unresolved_override.turn_sequence.size() + 1,
SPECIAL_NODEID);
const auto &turns = unresolved_override.Turns();
for (std::int64_t i = unresolved_override.turn_sequence.size() - 1; i >= 0; --i)
{
const auto v = global_turn_to_ebn_map.find(unresolved_override.turn_sequence[i]);
if (v != global_turn_to_ebn_map.end())
BOOST_ASSERT(!turns.empty());
// Populate the node sequences with the first turn values.
const auto first_turn_edges = global_turn_to_ebn_map.equal_range(turns[0]);
std::transform(
first_turn_edges.first,
first_turn_edges.second,
std::back_inserter(node_sequences),
[](const auto turn_edges) {
return std::vector<NodeID>{turn_edges.second.first, turn_edges.second.second};
});
std::for_each(std::next(turns.begin()), turns.end(), [&](const auto &turn) {
std::vector<std::vector<NodeID>> next_node_sequences;
const auto next_turn_edges = global_turn_to_ebn_map.equal_range(turn);
for (auto &node_sequence : node_sequences)
{
node_sequence[i] = v->second.first;
node_sequence[i + 1] = v->second.second;
const auto found_it = std::find_if(
next_turn_edges.first, next_turn_edges.second, [&](const auto &turn_edges) {
const auto pre_turn_edge = turn_edges.second.first;
return (node_sequence.back() == pre_turn_edge);
});
if (found_it != next_turn_edges.second)
{
const auto post_turn_edge = found_it->second.second;
node_sequence.push_back(post_turn_edge);
next_node_sequences.push_back(std::move(node_sequence));
}
}
node_sequences = std::move(next_node_sequences);
});
for (const auto &node_sequence : node_sequences)
{
StorageManeuverOverride storage_override;
storage_override.instruction_node = unresolved_override.instruction_node;
storage_override.override_type = unresolved_override.override_type;
storage_override.direction = unresolved_override.direction;
storage_override.node_sequence_offset_begin = maneuver_override_sequences.size();
storage_override.node_sequence_offset_end =
maneuver_override_sequences.size() + node_sequence.size();
storage_override.start_node = node_sequence.front();
maneuver_override_sequences.insert(
maneuver_override_sequences.end(), node_sequence.begin(), node_sequence.end());
storage_maneuver_overrides.push_back(storage_override);
}
storage_override.node_sequence_offset_begin = maneuver_override_sequences.size();
storage_override.node_sequence_offset_end =
maneuver_override_sequences.size() + node_sequence.size();
storage_override.start_node = node_sequence.front();
maneuver_override_sequences.insert(
maneuver_override_sequences.end(), node_sequence.begin(), node_sequence.end());
storage_maneuver_overrides.push_back(storage_override);
}
}
{