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:
@@ -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);
|
||||
}
|
||||
}
|
||||
{
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -13,11 +13,11 @@
|
||||
#include "extractor/name_table.hpp"
|
||||
#include "extractor/node_based_graph_factory.hpp"
|
||||
#include "extractor/node_restriction_map.hpp"
|
||||
#include "extractor/restriction_filter.hpp"
|
||||
#include "extractor/restriction_graph.hpp"
|
||||
#include "extractor/restriction_parser.hpp"
|
||||
#include "extractor/scripting_environment.hpp"
|
||||
#include "extractor/tarjan_scc.hpp"
|
||||
#include "extractor/turn_path_filter.hpp"
|
||||
#include "extractor/way_restriction_map.hpp"
|
||||
|
||||
#include "guidance/files.hpp"
|
||||
@@ -279,7 +279,9 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
edge_based_nodes_container =
|
||||
EdgeBasedNodeDataContainer({}, std::move(node_based_graph_factory.GetAnnotationData()));
|
||||
|
||||
turn_restrictions = removeInvalidRestrictions(std::move(turn_restrictions), node_based_graph);
|
||||
turn_restrictions = removeInvalidTurnPaths(std::move(turn_restrictions), node_based_graph);
|
||||
unresolved_maneuver_overrides =
|
||||
removeInvalidTurnPaths(std::move(unresolved_maneuver_overrides), node_based_graph);
|
||||
auto restriction_graph = constructRestrictionGraph(turn_restrictions);
|
||||
|
||||
const auto number_of_node_based_nodes = node_based_graph.GetNumberOfNodes();
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
#include "extractor/compressed_edge_container.hpp"
|
||||
#include "extractor/extraction_turn.hpp"
|
||||
#include "extractor/restriction.hpp"
|
||||
#include "extractor/restriction_compressor.hpp"
|
||||
#include "guidance/intersection.hpp"
|
||||
#include "extractor/turn_path_compressor.hpp"
|
||||
|
||||
#include "util/dynamic_graph.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
@@ -32,28 +31,34 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const unsigned original_number_of_nodes = graph.GetNumberOfNodes();
|
||||
const unsigned original_number_of_edges = graph.GetNumberOfEdges();
|
||||
|
||||
RestrictionCompressor restriction_compressor(turn_restrictions, maneuver_overrides);
|
||||
TurnPathCompressor turn_path_compressor(turn_restrictions, maneuver_overrides);
|
||||
|
||||
// Some degree two nodes are not compressed if they act as entry/exit points into a
|
||||
// restriction path.
|
||||
std::unordered_set<NodeID> restriction_via_nodes;
|
||||
std::unordered_set<NodeID> incompressible_via_nodes;
|
||||
|
||||
const auto remember_via_nodes = [&](const auto &restriction) {
|
||||
if (restriction.Type() == RestrictionType::NODE_RESTRICTION)
|
||||
if (restriction.turn_path.Type() == TurnPathType::VIA_NODE_TURN_PATH)
|
||||
{
|
||||
restriction_via_nodes.insert(restriction.AsNodeRestriction().via);
|
||||
incompressible_via_nodes.insert(restriction.turn_path.AsViaNodePath().via);
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(restriction.Type() == RestrictionType::WAY_RESTRICTION);
|
||||
const auto &way_restriction = restriction.AsWayRestriction();
|
||||
BOOST_ASSERT(restriction.turn_path.Type() == TurnPathType::VIA_WAY_TURN_PATH);
|
||||
const auto &way_restriction = restriction.turn_path.AsViaWayPath();
|
||||
// We do not compress the first and last via nodes so that we know how to enter/exit
|
||||
// a restriction path and apply the restrictions correctly.
|
||||
restriction_via_nodes.insert(way_restriction.via.front());
|
||||
restriction_via_nodes.insert(way_restriction.via.back());
|
||||
incompressible_via_nodes.insert(way_restriction.via.front());
|
||||
incompressible_via_nodes.insert(way_restriction.via.back());
|
||||
}
|
||||
};
|
||||
std::for_each(turn_restrictions.begin(), turn_restrictions.end(), remember_via_nodes);
|
||||
for (const auto &maneuver : maneuver_overrides)
|
||||
{
|
||||
// Only incompressible is where the instruction occurs.
|
||||
incompressible_via_nodes.insert(maneuver.instruction_node);
|
||||
}
|
||||
|
||||
{
|
||||
const auto weight_multiplier =
|
||||
scripting_environment.GetProfileProperties().GetWeightMultiplier();
|
||||
@@ -77,7 +82,7 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
}
|
||||
|
||||
// check if v is an entry/exit via node for a turn restriction
|
||||
if (restriction_via_nodes.count(node_v) > 0)
|
||||
if (incompressible_via_nodes.count(node_v) > 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -303,8 +308,8 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
graph.DeleteEdge(node_v, forward_e2);
|
||||
graph.DeleteEdge(node_v, reverse_e2);
|
||||
|
||||
// update any involved turn restrictions
|
||||
restriction_compressor.Compress(node_u, node_v, node_w);
|
||||
// update any involved turn relations
|
||||
turn_path_compressor.Compress(node_u, node_v, node_w);
|
||||
|
||||
// store compressed geometry in container
|
||||
geometry_compressor.CompressEdge(forward_e1,
|
||||
|
||||
@@ -119,9 +119,15 @@ ManeuverOverrideRelationParser::TryParse(const osmium::Relation &relation) const
|
||||
|
||||
if (valid_relation)
|
||||
{
|
||||
maneuver_override.via_ways.push_back(from);
|
||||
std::copy(via_ways.begin(), via_ways.end(), std::back_inserter(maneuver_override.via_ways));
|
||||
maneuver_override.via_ways.push_back(to);
|
||||
if (via_ways.empty())
|
||||
{
|
||||
maneuver_override.turn_path.node_or_way = InputViaNodePath{{from}, {via_node}, {to}};
|
||||
}
|
||||
else
|
||||
{
|
||||
maneuver_override.turn_path.node_or_way =
|
||||
InputViaWayPath{{from}, std::move(via_ways), {to}};
|
||||
}
|
||||
maneuver_override.via_node = via_node;
|
||||
}
|
||||
else
|
||||
|
||||
@@ -1,242 +0,0 @@
|
||||
#include "extractor/restriction_compressor.hpp"
|
||||
#include "extractor/restriction.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
RestrictionCompressor::RestrictionCompressor(
|
||||
std::vector<TurnRestriction> &restrictions,
|
||||
std::vector<UnresolvedManeuverOverride> &maneuver_overrides)
|
||||
{
|
||||
// add a turn restriction ptr to the starts/ends maps, needs to be a reference!
|
||||
auto index = [&](auto &element) {
|
||||
starts.insert({element.From(), &element});
|
||||
ends.insert({element.To(), &element});
|
||||
if (element.Type() == RestrictionType::WAY_RESTRICTION)
|
||||
{
|
||||
const auto &way_via = element.AsWayRestriction().via;
|
||||
BOOST_ASSERT(way_via.size() >= 2);
|
||||
// No need to track the first and last via nodes as they will not be compressed.
|
||||
for (const auto &via_node :
|
||||
boost::make_iterator_range(way_via.begin() + 1, way_via.end() - 1))
|
||||
{
|
||||
vias.insert({via_node, &element});
|
||||
}
|
||||
}
|
||||
};
|
||||
// !needs to be reference, so we can get the correct address
|
||||
const auto index_starts_ends_vias = [&](auto &restriction) { index(restriction); };
|
||||
|
||||
// add all restrictions as their respective start/via/end pointers
|
||||
std::for_each(restrictions.begin(), restrictions.end(), index_starts_ends_vias);
|
||||
|
||||
auto index_maneuver = [&](auto &maneuver) {
|
||||
for (auto &turn : maneuver.turn_sequence)
|
||||
{
|
||||
maneuver_starts.insert({turn.from, &turn});
|
||||
maneuver_ends.insert({turn.to, &turn});
|
||||
}
|
||||
};
|
||||
// !needs to be reference, so we can get the correct address
|
||||
std::for_each(maneuver_overrides.begin(), maneuver_overrides.end(), [&](auto &maneuver) {
|
||||
index_maneuver(maneuver);
|
||||
});
|
||||
}
|
||||
|
||||
void RestrictionCompressor::Compress(const NodeID from, const NodeID via, const NodeID to)
|
||||
{
|
||||
// handle turn restrictions
|
||||
// extract all start ptrs and move them from via to from.
|
||||
auto all_starts_range = starts.equal_range(via);
|
||||
std::vector<TurnRestriction *> start_ptrs;
|
||||
std::transform(all_starts_range.first,
|
||||
all_starts_range.second,
|
||||
std::back_inserter(start_ptrs),
|
||||
[](const auto pair) { return pair.second; });
|
||||
|
||||
const auto update_start = [&](auto ptr) {
|
||||
if (ptr->Type() == RestrictionType::NODE_RESTRICTION)
|
||||
{
|
||||
|
||||
// ____ | from - p.from | via - p.via | to - p.to | ____
|
||||
auto &node_ptr = ptr->AsNodeRestriction();
|
||||
BOOST_ASSERT(node_ptr.from == via);
|
||||
if (node_ptr.via == to)
|
||||
{
|
||||
node_ptr.from = from;
|
||||
}
|
||||
// ____ | to - p.from | via - p.via | from - p.to | ____
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(node_ptr.via == from);
|
||||
node_ptr.from = to;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(ptr->Type() == RestrictionType::WAY_RESTRICTION);
|
||||
auto &way_ptr = ptr->AsWayRestriction();
|
||||
// ____ | from - p.from | via - p.via[0] | to - p[1..],p.to | ____
|
||||
BOOST_ASSERT(way_ptr.from == via);
|
||||
if (way_ptr.via.front() == to)
|
||||
{
|
||||
way_ptr.from = from;
|
||||
}
|
||||
// ____ | to - p.from | via - p.via[0] | from - p[1,..],p.to | ____
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(way_ptr.via.front() == from);
|
||||
way_ptr.from = to;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::for_each(start_ptrs.begin(), start_ptrs.end(), update_start);
|
||||
|
||||
// update the ptrs in our mapping
|
||||
starts.erase(via);
|
||||
|
||||
const auto reinsert_start = [&](auto ptr) { starts.insert({ptr->From(), ptr}); };
|
||||
std::for_each(start_ptrs.begin(), start_ptrs.end(), reinsert_start);
|
||||
|
||||
// extract all end ptrs and move them from via to to
|
||||
auto all_ends_range = ends.equal_range(via);
|
||||
std::vector<TurnRestriction *> end_ptrs;
|
||||
std::transform(all_ends_range.first,
|
||||
all_ends_range.second,
|
||||
std::back_inserter(end_ptrs),
|
||||
[](const auto pair) { return pair.second; });
|
||||
|
||||
const auto update_end = [&](auto ptr) {
|
||||
if (ptr->Type() == RestrictionType::NODE_RESTRICTION)
|
||||
{
|
||||
auto &node_ptr = ptr->AsNodeRestriction();
|
||||
|
||||
BOOST_ASSERT(node_ptr.to == via);
|
||||
// p.from | ____ - p.via | from - p.to | via - ____ | to
|
||||
if (node_ptr.via == from)
|
||||
{
|
||||
node_ptr.to = to;
|
||||
}
|
||||
// p.from | ____ - p.via | to - p.to | via - ____ | from
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(node_ptr.via == to);
|
||||
node_ptr.to = from;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(ptr->Type() == RestrictionType::WAY_RESTRICTION);
|
||||
auto &way_ptr = ptr->AsWayRestriction();
|
||||
|
||||
BOOST_ASSERT(way_ptr.to == via);
|
||||
// p.from,p.via[..,n-1] | ____ - p.via[n] | from - p.to | via - ____ | to
|
||||
if (way_ptr.via.back() == from)
|
||||
{
|
||||
way_ptr.to = to;
|
||||
}
|
||||
// p.from,p.via[..,n-1] | ____ - p.via[n] | to - p.to | via - ____ | from
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(way_ptr.via.back() == to);
|
||||
way_ptr.to = from;
|
||||
}
|
||||
}
|
||||
};
|
||||
std::for_each(end_ptrs.begin(), end_ptrs.end(), update_end);
|
||||
|
||||
// update end ptrs in mapping
|
||||
ends.erase(via);
|
||||
|
||||
const auto reinsert_end = [&](auto ptr) { ends.insert({ptr->To(), ptr}); };
|
||||
std::for_each(end_ptrs.begin(), end_ptrs.end(), reinsert_end);
|
||||
|
||||
// remove compressed node from all via paths
|
||||
auto all_vias_range = vias.equal_range(via);
|
||||
|
||||
const auto update_via = [&](auto restriction_pair) {
|
||||
BOOST_ASSERT(restriction_pair.second->Type() == RestrictionType::WAY_RESTRICTION);
|
||||
auto &way_ptr = restriction_pair.second->AsWayRestriction();
|
||||
BOOST_ASSERT(std::find(way_ptr.via.begin(), way_ptr.via.end(), via) != way_ptr.via.end());
|
||||
way_ptr.via.erase(std::remove(way_ptr.via.begin(), way_ptr.via.end(), via),
|
||||
way_ptr.via.end());
|
||||
};
|
||||
std::for_each(all_vias_range.first, all_vias_range.second, update_via);
|
||||
|
||||
// update via ptrs in mapping
|
||||
vias.erase(via);
|
||||
|
||||
/**********************************************************************************************/
|
||||
|
||||
// handle maneuver overrides from nodes
|
||||
// extract all startptrs
|
||||
auto maneuver_starts_range = maneuver_starts.equal_range(via);
|
||||
std::vector<NodeBasedTurn *> mnv_start_ptrs;
|
||||
std::transform(maneuver_starts_range.first,
|
||||
maneuver_starts_range.second,
|
||||
std::back_inserter(mnv_start_ptrs),
|
||||
[](const auto pair) { return pair.second; });
|
||||
|
||||
// update from nodes of maneuver overrides
|
||||
const auto update_start_mnv = [&](auto ptr) {
|
||||
// ____ | from - p.from | via - p.via | to - p.to | ____
|
||||
BOOST_ASSERT(ptr->from == via);
|
||||
if (ptr->via == to)
|
||||
{
|
||||
ptr->from = from;
|
||||
}
|
||||
// ____ | to - p.from | via - p.via | from - p.to | ____
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(ptr->via == from);
|
||||
ptr->from = to;
|
||||
}
|
||||
};
|
||||
std::for_each(mnv_start_ptrs.begin(), mnv_start_ptrs.end(), update_start_mnv);
|
||||
|
||||
// update the ptrs in our mapping
|
||||
maneuver_starts.erase(via);
|
||||
const auto reinsert_start_mnv = [&](auto ptr) { maneuver_starts.insert({ptr->from, ptr}); };
|
||||
std::for_each(mnv_start_ptrs.begin(), mnv_start_ptrs.end(), reinsert_start_mnv);
|
||||
|
||||
/**********************************************************************************************/
|
||||
// handle maneuver override to nodes
|
||||
// extract all end ptrs and move them from via to to
|
||||
auto maneuver_ends_range = maneuver_ends.equal_range(via);
|
||||
std::vector<NodeBasedTurn *> mnv_end_ptrs;
|
||||
std::transform(maneuver_ends_range.first,
|
||||
maneuver_ends_range.second,
|
||||
std::back_inserter(mnv_end_ptrs),
|
||||
[](const auto pair) { return pair.second; });
|
||||
|
||||
const auto update_end_mnv = [&](auto ptr) {
|
||||
BOOST_ASSERT(ptr->to == via);
|
||||
// p.from | ____ - p.via | from - p.to | via - ____ | to
|
||||
if (ptr->via == from)
|
||||
{
|
||||
ptr->to = to;
|
||||
}
|
||||
// p.from | ____ - p.via | to - p.to | via - ____ | from
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(ptr->via == to);
|
||||
ptr->to = from;
|
||||
}
|
||||
};
|
||||
std::for_each(mnv_end_ptrs.begin(), mnv_end_ptrs.end(), update_end_mnv);
|
||||
|
||||
// update end ptrs in mapping
|
||||
maneuver_ends.erase(via);
|
||||
|
||||
const auto reinsert_end_mnvs = [&](auto ptr) { maneuver_ends.insert({ptr->to, ptr}); };
|
||||
std::for_each(mnv_end_ptrs.begin(), mnv_end_ptrs.end(), reinsert_end_mnvs);
|
||||
}
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
@@ -1,83 +0,0 @@
|
||||
#include "extractor/restriction_filter.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/timing_util.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
std::vector<TurnRestriction>
|
||||
removeInvalidRestrictions(std::vector<TurnRestriction> restrictions,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph)
|
||||
{
|
||||
util::UnbufferedLog log;
|
||||
log << "Removing invalid restrictions...";
|
||||
TIMER_START(remove_invalid_restrictions);
|
||||
|
||||
const auto is_valid_edge = [&node_based_graph](const auto from, const auto to) {
|
||||
const auto eid = node_based_graph.FindEdge(from, to);
|
||||
if (eid == SPECIAL_EDGEID)
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction has invalid edge: " << from << ", " << to;
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto &edge_data = node_based_graph.GetEdgeData(eid);
|
||||
if (edge_data.reversed)
|
||||
{
|
||||
util::Log(logDEBUG) << "Restriction has non-traversable edge: " << from << ", " << to;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const auto is_valid_node = [is_valid_edge](const auto &node_restriction) {
|
||||
return is_valid_edge(node_restriction.from, node_restriction.via) &&
|
||||
is_valid_edge(node_restriction.via, node_restriction.to);
|
||||
};
|
||||
|
||||
const auto is_valid_way = [is_valid_edge](const auto &way_restriction) {
|
||||
if (!is_valid_edge(way_restriction.from, way_restriction.via.front()))
|
||||
return false;
|
||||
|
||||
const auto invalid_it = std::adjacent_find(
|
||||
way_restriction.via.begin(),
|
||||
way_restriction.via.end(),
|
||||
[&](auto via_from, auto via_to) { return !is_valid_edge(via_from, via_to); });
|
||||
if (invalid_it != way_restriction.via.end())
|
||||
return false;
|
||||
|
||||
return is_valid_edge(way_restriction.via.back(), way_restriction.to);
|
||||
};
|
||||
|
||||
const auto is_invalid = [is_valid_way, is_valid_node](const auto &restriction) {
|
||||
if (restriction.Type() == RestrictionType::NODE_RESTRICTION)
|
||||
{
|
||||
return !is_valid_node(restriction.AsNodeRestriction());
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(restriction.Type() == RestrictionType::WAY_RESTRICTION);
|
||||
return !is_valid_way(restriction.AsWayRestriction());
|
||||
}
|
||||
};
|
||||
|
||||
const auto end_valid_restrictions =
|
||||
std::remove_if(restrictions.begin(), restrictions.end(), is_invalid);
|
||||
const auto num_removed = std::distance(end_valid_restrictions, restrictions.end());
|
||||
restrictions.erase(end_valid_restrictions, restrictions.end());
|
||||
|
||||
TIMER_STOP(remove_invalid_restrictions);
|
||||
log << "removed " << num_removed << " invalid restrictions, after "
|
||||
<< TIMER_SEC(remove_invalid_restrictions) << "s";
|
||||
|
||||
return restrictions;
|
||||
}
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
@@ -1,9 +1,10 @@
|
||||
#include "extractor/restriction_graph.hpp"
|
||||
#include "extractor/restriction.hpp"
|
||||
#include "extractor/turn_path.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/timing_util.hpp"
|
||||
#include <util/for_each_pair.hpp>
|
||||
|
||||
#include <boost/assign.hpp>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
|
||||
namespace osrm
|
||||
@@ -211,11 +212,11 @@ void buildGraph(RestrictionGraph &rg, const std::vector<TurnRestriction> &restri
|
||||
const auto run_builder = [&](const auto &restriction) {
|
||||
builder_type builder(rg);
|
||||
|
||||
builder.start(restriction.From(), restriction.FirstVia());
|
||||
if (restriction.Type() == RestrictionType::WAY_RESTRICTION)
|
||||
builder.start(restriction.turn_path.From(), restriction.turn_path.FirstVia());
|
||||
if (restriction.turn_path.Type() == TurnPathType::VIA_WAY_TURN_PATH)
|
||||
{
|
||||
const auto &way_restriction = restriction.AsWayRestriction();
|
||||
util::for_each_pair(way_restriction.via,
|
||||
const auto &via_way_path = restriction.turn_path.AsViaWayPath();
|
||||
util::for_each_pair(via_way_path.via,
|
||||
[&](NodeID from, NodeID to) { builder.next(from, to); });
|
||||
}
|
||||
builder.end(restriction);
|
||||
|
||||
@@ -232,7 +232,7 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
|
||||
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.
|
||||
// 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)
|
||||
@@ -243,12 +243,12 @@ RestrictionParser::TryParse(const osmium::Relation &relation) const
|
||||
if (is_node_restriction)
|
||||
{
|
||||
// template struct requires bracket for ID initialisation :(
|
||||
restriction.node_or_way = InputNodeRestriction{{from}, {via_node}, {to}};
|
||||
restriction.turn_path.node_or_way = InputViaNodePath{{from}, {via_node}, {to}};
|
||||
}
|
||||
else
|
||||
{
|
||||
// template struct requires bracket for ID initialisation :(
|
||||
restriction.node_or_way = InputWayRestriction{{from}, via_ways, {to}};
|
||||
restriction.turn_path.node_or_way = InputViaWayPath{{from}, via_ways, {to}};
|
||||
}
|
||||
restriction_containers.push_back(std::move(restriction));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
#include "extractor/turn_path_compressor.hpp"
|
||||
#include "extractor/maneuver_override.hpp"
|
||||
#include "extractor/restriction.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
TurnPathCompressor::TurnPathCompressor(std::vector<TurnRestriction> &restrictions,
|
||||
std::vector<UnresolvedManeuverOverride> &maneuver_overrides)
|
||||
{
|
||||
// Track all turn paths by their respective start/via/end nodes.
|
||||
auto index = [&](auto &element) {
|
||||
starts.insert({element.From(), &element});
|
||||
ends.insert({element.To(), &element});
|
||||
if (element.Type() == TurnPathType::VIA_WAY_TURN_PATH)
|
||||
{
|
||||
// Some of the via nodes can not be compressed so don't need tracking
|
||||
// (e.g. first and last via node of a restriction, instruction node of maneuver).
|
||||
// However, for the sake of simplicity we'll track them all.
|
||||
for (const auto &via_node : element.AsViaWayPath().via)
|
||||
{
|
||||
vias.insert({via_node, &element});
|
||||
}
|
||||
}
|
||||
};
|
||||
// We need to pass a reference to the index as we will mutate the turn path during compression.
|
||||
const auto index_starts_ends_vias = [&](auto &relation) { index(relation.turn_path); };
|
||||
|
||||
std::for_each(restrictions.begin(), restrictions.end(), index_starts_ends_vias);
|
||||
std::for_each(maneuver_overrides.begin(), maneuver_overrides.end(), index_starts_ends_vias);
|
||||
}
|
||||
|
||||
void TurnPathCompressor::Compress(const NodeID from, const NodeID via, const NodeID to)
|
||||
{
|
||||
// handle turn restrictions
|
||||
// extract all start ptrs and move them from via to from.
|
||||
auto all_starts_range = starts.equal_range(via);
|
||||
std::vector<TurnPath *> start_ptrs;
|
||||
std::transform(all_starts_range.first,
|
||||
all_starts_range.second,
|
||||
std::back_inserter(start_ptrs),
|
||||
[](const auto pair) { return pair.second; });
|
||||
|
||||
const auto update_start = [&](auto ptr) {
|
||||
if (ptr->Type() == TurnPathType::VIA_NODE_TURN_PATH)
|
||||
{
|
||||
|
||||
// ____ | from - p.from | via - p.via | to - p.to | ____
|
||||
auto &node_ptr = ptr->AsViaNodePath();
|
||||
BOOST_ASSERT(node_ptr.from == via);
|
||||
if (node_ptr.via == to)
|
||||
{
|
||||
node_ptr.from = from;
|
||||
}
|
||||
// ____ | to - p.from | via - p.via | from - p.to | ____
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(node_ptr.via == from);
|
||||
node_ptr.from = to;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(ptr->Type() == TurnPathType::VIA_WAY_TURN_PATH);
|
||||
auto &way_ptr = ptr->AsViaWayPath();
|
||||
// ____ | from - p.from | via - p.via[0] | to - p[1..],p.to | ____
|
||||
BOOST_ASSERT(way_ptr.from == via);
|
||||
if (way_ptr.via.front() == to)
|
||||
{
|
||||
way_ptr.from = from;
|
||||
}
|
||||
// ____ | to - p.from | via - p.via[0] | from - p[1,..],p.to | ____
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(way_ptr.via.front() == from);
|
||||
way_ptr.from = to;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::for_each(start_ptrs.begin(), start_ptrs.end(), update_start);
|
||||
|
||||
// update the ptrs in our mapping
|
||||
starts.erase(via);
|
||||
|
||||
const auto reinsert_start = [&](auto ptr) { starts.insert({ptr->From(), ptr}); };
|
||||
std::for_each(start_ptrs.begin(), start_ptrs.end(), reinsert_start);
|
||||
|
||||
// extract all end ptrs and move them from via to to
|
||||
auto all_ends_range = ends.equal_range(via);
|
||||
std::vector<TurnPath *> end_ptrs;
|
||||
std::transform(all_ends_range.first,
|
||||
all_ends_range.second,
|
||||
std::back_inserter(end_ptrs),
|
||||
[](const auto pair) { return pair.second; });
|
||||
|
||||
const auto update_end = [&](auto ptr) {
|
||||
if (ptr->Type() == TurnPathType::VIA_NODE_TURN_PATH)
|
||||
{
|
||||
auto &node_ptr = ptr->AsViaNodePath();
|
||||
|
||||
BOOST_ASSERT(node_ptr.to == via);
|
||||
// p.from | ____ - p.via | from - p.to | via - ____ | to
|
||||
if (node_ptr.via == from)
|
||||
{
|
||||
node_ptr.to = to;
|
||||
}
|
||||
// p.from | ____ - p.via | to - p.to | via - ____ | from
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(node_ptr.via == to);
|
||||
node_ptr.to = from;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(ptr->Type() == TurnPathType::VIA_WAY_TURN_PATH);
|
||||
auto &way_ptr = ptr->AsViaWayPath();
|
||||
|
||||
BOOST_ASSERT(way_ptr.to == via);
|
||||
// p.from,p.via[..,n-1] | ____ - p.via[n] | from - p.to | via - ____ | to
|
||||
if (way_ptr.via.back() == from)
|
||||
{
|
||||
way_ptr.to = to;
|
||||
}
|
||||
// p.from,p.via[..,n-1] | ____ - p.via[n] | to - p.to | via - ____ | from
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(way_ptr.via.back() == to);
|
||||
way_ptr.to = from;
|
||||
}
|
||||
}
|
||||
};
|
||||
std::for_each(end_ptrs.begin(), end_ptrs.end(), update_end);
|
||||
|
||||
// update end ptrs in mapping
|
||||
ends.erase(via);
|
||||
|
||||
const auto reinsert_end = [&](auto ptr) { ends.insert({ptr->To(), ptr}); };
|
||||
std::for_each(end_ptrs.begin(), end_ptrs.end(), reinsert_end);
|
||||
|
||||
// remove compressed node from all via paths
|
||||
auto all_vias_range = vias.equal_range(via);
|
||||
|
||||
const auto update_via = [&](auto restriction_pair) {
|
||||
BOOST_ASSERT(restriction_pair.second->Type() == TurnPathType::VIA_WAY_TURN_PATH);
|
||||
auto &way_ptr = restriction_pair.second->AsViaWayPath();
|
||||
BOOST_ASSERT(std::find(way_ptr.via.begin(), way_ptr.via.end(), via) != way_ptr.via.end());
|
||||
way_ptr.via.erase(std::remove(way_ptr.via.begin(), way_ptr.via.end(), via),
|
||||
way_ptr.via.end());
|
||||
};
|
||||
std::for_each(all_vias_range.first, all_vias_range.second, update_via);
|
||||
|
||||
// update via ptrs in mapping
|
||||
vias.erase(via);
|
||||
}
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
@@ -0,0 +1,88 @@
|
||||
#include "extractor/turn_path_filter.hpp"
|
||||
#include "extractor/maneuver_override.hpp"
|
||||
#include "util/node_based_graph.hpp"
|
||||
#include "util/timing_util.hpp"
|
||||
#include "util/typedefs.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
namespace osrm
|
||||
{
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
template <typename T>
|
||||
std::vector<T> removeInvalidTurnPaths(std::vector<T> turn_relations,
|
||||
const util::NodeBasedDynamicGraph &node_based_graph)
|
||||
{
|
||||
util::UnbufferedLog log;
|
||||
log << "Removing invalid " << T::Name() << "s...";
|
||||
TIMER_START(remove_invalid_turn_paths);
|
||||
|
||||
const auto is_valid_edge = [&node_based_graph](const auto from, const auto to) {
|
||||
const auto eid = node_based_graph.FindEdge(from, to);
|
||||
if (eid == SPECIAL_EDGEID)
|
||||
{
|
||||
util::Log(logDEBUG) << T::Name() << " has invalid edge: " << from << ", " << to;
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto &edge_data = node_based_graph.GetEdgeData(eid);
|
||||
if (edge_data.reversed)
|
||||
{
|
||||
util::Log(logDEBUG) << T::Name() << " has non-traversable edge: " << from << ", " << to;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
const auto is_valid_node = [is_valid_edge](const auto &via_node_path) {
|
||||
return is_valid_edge(via_node_path.from, via_node_path.via) &&
|
||||
is_valid_edge(via_node_path.via, via_node_path.to);
|
||||
};
|
||||
|
||||
const auto is_valid_way = [is_valid_edge](const auto &via_way_path) {
|
||||
if (!is_valid_edge(via_way_path.from, via_way_path.via.front()))
|
||||
return false;
|
||||
|
||||
const auto invalid_it = std::adjacent_find(
|
||||
via_way_path.via.begin(), via_way_path.via.end(), [&](auto via_from, auto via_to) {
|
||||
return !is_valid_edge(via_from, via_to);
|
||||
});
|
||||
if (invalid_it != via_way_path.via.end())
|
||||
return false;
|
||||
|
||||
return is_valid_edge(via_way_path.via.back(), via_way_path.to);
|
||||
};
|
||||
|
||||
const auto is_invalid = [is_valid_way, is_valid_node](const auto &turn_relation) {
|
||||
if (turn_relation.turn_path.Type() == TurnPathType::VIA_NODE_TURN_PATH)
|
||||
{
|
||||
return !is_valid_node(turn_relation.turn_path.AsViaNodePath());
|
||||
}
|
||||
|
||||
BOOST_ASSERT(turn_relation.turn_path.Type() == TurnPathType::VIA_WAY_TURN_PATH);
|
||||
return !is_valid_way(turn_relation.turn_path.AsViaWayPath());
|
||||
};
|
||||
|
||||
const auto end_valid_relations =
|
||||
std::remove_if(turn_relations.begin(), turn_relations.end(), is_invalid);
|
||||
const auto num_removed = std::distance(end_valid_relations, turn_relations.end());
|
||||
turn_relations.erase(end_valid_relations, turn_relations.end());
|
||||
|
||||
TIMER_STOP(remove_invalid_turn_paths);
|
||||
log << "removed " << num_removed << " invalid " << T::Name() << "s, after "
|
||||
<< TIMER_SEC(remove_invalid_turn_paths) << "s";
|
||||
|
||||
return turn_relations;
|
||||
}
|
||||
|
||||
template std::vector<TurnRestriction> removeInvalidTurnPaths<>(std::vector<TurnRestriction>,
|
||||
const util::NodeBasedDynamicGraph &);
|
||||
template std::vector<UnresolvedManeuverOverride>
|
||||
removeInvalidTurnPaths<>(std::vector<UnresolvedManeuverOverride>,
|
||||
const util::NodeBasedDynamicGraph &);
|
||||
|
||||
} // namespace extractor
|
||||
} // namespace osrm
|
||||
Reference in New Issue
Block a user