Support maneuver relations (#4676)

This commit is contained in:
Daniel Patterson
2018-02-10 05:32:09 +11:00
committed by GitHub
parent 1aed13500d
commit 5531cace7f
46 changed files with 1474 additions and 89 deletions
+144
View File
@@ -566,6 +566,150 @@ std::vector<RouteStep> buildIntersections(std::vector<RouteStep> steps)
return removeNoTurnInstructions(std::move(steps));
}
void applyOverrides(const datafacade::BaseDataFacade &facade,
std::vector<RouteStep> &steps,
const LegGeometry &leg_geometry)
{
// Find overrides that match, and apply them
// The +/-1 here are to remove the depart and arrive steps, which
// we don't allow updates to
for (auto current_step_it = steps.begin(); current_step_it != steps.end(); ++current_step_it)
{
util::Log(logDEBUG) << "Searching for " << current_step_it->from_id << std::endl;
const auto overrides = facade.GetOverridesThatStartAt(current_step_it->from_id);
if (overrides.empty())
continue;
util::Log(logDEBUG) << "~~~~ GOT A HIT, checking the rest ~~~" << std::endl;
for (const extractor::ManeuverOverride &maneuver_relation : overrides)
{
util::Log(logDEBUG) << "Override sequence is ";
for (auto &n : maneuver_relation.node_sequence)
{
util::Log(logDEBUG) << n << " ";
}
util::Log(logDEBUG) << std::endl;
util::Log(logDEBUG) << "Override type is "
<< osrm::guidance::internalInstructionTypeToString(
maneuver_relation.override_type)
<< std::endl;
util::Log(logDEBUG) << "Override direction is "
<< osrm::guidance::instructionModifierToString(
maneuver_relation.direction)
<< std::endl;
util::Log(logDEBUG) << "Route sequence is ";
for (auto it = current_step_it; it != steps.end(); ++it)
{
util::Log(logDEBUG) << it->from_id << " ";
}
util::Log(logDEBUG) << std::endl;
auto search_iter = maneuver_relation.node_sequence.begin();
auto route_iter = current_step_it;
while (search_iter != maneuver_relation.node_sequence.end())
{
if (route_iter == steps.end())
break;
if (*search_iter == route_iter->from_id)
{
++search_iter;
++route_iter;
continue;
}
// Skip over duplicated EBNs in the step array
// EBNs are sometime duplicated because guidance code inserts
// "fake" steps that it later removes. This hasn't happened yet
// at this point, but we can safely just skip past the dupes.
if ((route_iter - 1)->from_id == route_iter->from_id)
{
++route_iter;
continue;
}
// If we get here, the values got out of sync so it's not
// a match.
break;
}
// We got a match, update using the instruction_node
if (search_iter == maneuver_relation.node_sequence.end())
{
util::Log(logDEBUG) << "Node sequence matched, looking for the step "
<< "that has the via node" << std::endl;
const auto via_node_coords =
facade.GetCoordinateOfNode(maneuver_relation.instruction_node);
// Find the step that has the instruction_node at the intersection point
auto step_to_update = std::find_if(
current_step_it,
route_iter,
[&leg_geometry, &via_node_coords](const auto &step) {
util::Log(logDEBUG) << "Leg geom from " << step.geometry_begin << " to "
<< step.geometry_end << std::endl;
// iterators over geometry of current step
auto begin = leg_geometry.locations.begin() + step.geometry_begin;
auto end = leg_geometry.locations.begin() + step.geometry_end;
auto via_match = std::find_if(begin, end, [&](const auto &location) {
return location == via_node_coords;
});
if (via_match != end)
{
util::Log(logDEBUG)
<< "Found geometry match at "
<< (std::distance(begin, end) - std::distance(via_match, end))
<< std::endl;
}
util::Log(logDEBUG)
<< ((*(leg_geometry.locations.begin() + step.geometry_begin) ==
via_node_coords)
? "true"
: "false")
<< std::endl;
return *(leg_geometry.locations.begin() + step.geometry_begin) ==
via_node_coords;
// return via_match != end;
});
// We found a step that had the intersection_node coordinate
// in its geometry
if (step_to_update != route_iter)
{
// Don't update the last step (it's an arrive instruction)
util::Log(logDEBUG) << "Updating step "
<< std::distance(steps.begin(), steps.end()) -
std::distance(step_to_update, steps.end())
<< std::endl;
if (maneuver_relation.override_type != osrm::guidance::TurnType::MaxTurnType)
{
util::Log(logDEBUG) << " instruction was "
<< osrm::guidance::internalInstructionTypeToString(
step_to_update->maneuver.instruction.type)
<< " now "
<< osrm::guidance::internalInstructionTypeToString(
maneuver_relation.override_type)
<< std::endl;
step_to_update->maneuver.instruction.type = maneuver_relation.override_type;
}
if (maneuver_relation.direction !=
osrm::guidance::DirectionModifier::MaxDirectionModifier)
{
util::Log(logDEBUG)
<< " direction was "
<< osrm::guidance::instructionModifierToString(
step_to_update->maneuver.instruction.direction_modifier)
<< " now " << osrm::guidance::instructionModifierToString(
maneuver_relation.direction)
<< std::endl;
step_to_update->maneuver.instruction.direction_modifier =
maneuver_relation.direction;
}
// step_to_update->is_overridden = true;
}
}
}
util::Log(logDEBUG) << "Done tweaking steps" << std::endl;
}
}
} // namespace guidance
} // namespace engine
} // namespace osrm
+105 -11
View File
@@ -31,6 +31,7 @@
#include <limits>
#include <sstream>
#include <string>
#include <tuple>
#include <unordered_map>
#include <tbb/blocked_range.h>
@@ -219,15 +220,18 @@ NBGToEBG EdgeBasedGraphFactory::InsertEdgeBasedNode(const NodeID node_u, const N
return NBGToEBG{node_u, node_v, nbe_to_ebn_mapping[edge_id_1], nbe_to_ebn_mapping[edge_id_2]};
}
void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
const std::string &turn_weight_penalties_filename,
const std::string &turn_duration_penalties_filename,
const std::string &turn_penalties_index_filename,
const std::string &cnbg_ebg_mapping_path,
const std::string &conditional_penalties_filename,
const RestrictionMap &node_restriction_map,
const ConditionalRestrictionMap &conditional_node_restriction_map,
const WayRestrictionMap &way_restriction_map)
void EdgeBasedGraphFactory::Run(
ScriptingEnvironment &scripting_environment,
const std::string &turn_weight_penalties_filename,
const std::string &turn_duration_penalties_filename,
const std::string &turn_penalties_index_filename,
const std::string &cnbg_ebg_mapping_path,
const std::string &conditional_penalties_filename,
const std::string &maneuver_overrides_filename,
const RestrictionMap &node_restriction_map,
const ConditionalRestrictionMap &conditional_node_restriction_map,
const WayRestrictionMap &way_restriction_map,
const std::vector<UnresolvedManeuverOverride> &unresolved_maneuver_overrides)
{
TIMER_START(renumber);
m_number_of_edge_based_nodes =
@@ -252,9 +256,11 @@ void EdgeBasedGraphFactory::Run(ScriptingEnvironment &scripting_environment,
turn_duration_penalties_filename,
turn_penalties_index_filename,
conditional_penalties_filename,
maneuver_overrides_filename,
node_restriction_map,
conditional_node_restriction_map,
way_restriction_map);
way_restriction_map,
unresolved_maneuver_overrides);
TIMER_STOP(generate_edges);
@@ -407,9 +413,11 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
const std::string &turn_duration_penalties_filename,
const std::string &turn_penalties_index_filename,
const std::string &conditional_penalties_filename,
const std::string &maneuver_overrides_filename,
const RestrictionMap &node_restriction_map,
const ConditionalRestrictionMap &conditional_restriction_map,
const WayRestrictionMap &way_restriction_map)
const WayRestrictionMap &way_restriction_map,
const std::vector<UnresolvedManeuverOverride> &unresolved_maneuver_overrides)
{
util::Log() << "Generating edge-expanded edges ";
@@ -434,6 +442,10 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
std::vector<TurnPenalty> turn_weight_penalties;
std::vector<TurnPenalty> turn_duration_penalties;
// Now, renumber all our maneuver overrides to use edge-based-nodes
std::vector<StorageManeuverOverride> storage_maneuver_overrides;
std::vector<NodeID> maneuver_override_sequences;
const auto weight_multiplier =
scripting_environment.GetProfileProperties().GetWeightMultiplier();
@@ -482,12 +494,16 @@ 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;
util::ConnectivityChecksum checksum;
};
using EdgesPipelineBufferPtr = std::shared_ptr<EdgesPipelineBuffer>;
m_connectivity_checksum = 0;
std::unordered_map<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.
NodeID current_node = 0;
@@ -847,6 +863,30 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
m_node_based_graph.GetTarget(outgoing_edge.edge),
m_number_of_edge_based_nodes);
/***************************/
const auto edgetarget =
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)
{
for (auto &turn : override.turn_sequence)
{
if (turn.from == incoming_edge.node &&
turn.via == intersection_node && turn.to == edgetarget)
{
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);
}
}
}
{ // scope to forget edge_with_data after
const auto edge_with_data_and_condition =
generate_edge(nbe_to_ebn_mapping[incoming_edge.edge],
@@ -997,6 +1037,13 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
// Copy via-way restrictions delayed data
delayed_data.insert(
delayed_data.end(), buffer->delayed_data.begin(), buffer->delayed_data.end());
std::for_each(buffer->turn_to_ebn_map.begin(),
buffer->turn_to_ebn_map.end(),
[&global_turn_to_ebn_map](const auto &p) {
// TODO: log conflicts here
global_turn_to_ebn_map.insert(p);
});
});
// Now, execute the pipeline. The value of "5" here was chosen by experimentation
@@ -1010,6 +1057,39 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
// NOTE: buffer.delayed_data and buffer.delayed_turn_data have the same index
std::for_each(delayed_data.begin(), delayed_data.end(), transfer_data);
// 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)
{
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;
std::vector<NodeID> node_sequence(unresolved_override.turn_sequence.size() + 1,
SPECIAL_NODEID);
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())
{
node_sequence[i] = v->second.first;
node_sequence[i + 1] = v->second.second;
}
}
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);
}
// Flush the turn_indexes_write_buffer if it's not empty
if (!turn_indexes_write_buffer.empty())
{
@@ -1018,6 +1098,20 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
turn_indexes_write_buffer.clear();
}
}
{
util::Log() << "Sorting and writing " << storage_maneuver_overrides.size()
<< " maneuver overrides...";
// Sort by `from_node`, so that later lookups can be done with a binary search.
std::sort(storage_maneuver_overrides.begin(),
storage_maneuver_overrides.end(),
[](const auto &a, const auto &b) { return a.start_node < b.start_node; });
// write conditional turn penalties into the restrictions file
storage::io::FileWriter writer(maneuver_overrides_filename,
storage::io::FileWriter::GenerateFingerprint);
extractor::serialization::write(
writer, storage_maneuver_overrides, maneuver_override_sequences);
}
util::Log() << "done.";
util::Log() << "Renumbering turns";
+277 -12
View File
@@ -141,6 +141,19 @@ void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environme
WriteEdges(file_out);
WriteMetadata(file_out);
/* Sort these so that searching is a bit faster later on */
{
util::UnbufferedLog log;
log << "Sorting used ways ... ";
TIMER_START(sort_ways);
tbb::parallel_sort(way_start_end_id_list.begin(),
way_start_end_id_list.end(),
FirstAndLastSegmentOfWayCompare());
TIMER_STOP(sort_ways);
log << "ok, after " << TIMER_SEC(sort_ways) << "s";
}
PrepareManeuverOverrides();
PrepareRestrictions();
WriteCharData(name_file_name);
}
@@ -651,20 +664,262 @@ void ExtractionContainers::WriteNodes(storage::io::FileWriter &file_out) const
util::Log() << "Processed " << max_internal_node_id << " nodes";
}
void ExtractionContainers::PrepareRestrictions()
void ExtractionContainers::PrepareManeuverOverrides()
{
std::unordered_map<OSMWayID, FirstAndLastSegmentOfWay> referenced_ways;
// prepare for extracting source/destination nodes for all maneuvers
{
util::UnbufferedLog log;
log << "Sorting used ways ... ";
TIMER_START(sort_ways);
tbb::parallel_sort(way_start_end_id_list.begin(),
way_start_end_id_list.end(),
FirstAndLastSegmentOfWayCompare());
TIMER_STOP(sort_ways);
log << "ok, after " << TIMER_SEC(sort_ways) << "s";
log << "Collecting start/end information on " << external_maneuver_overrides_list.size()
<< " maneuver overrides...";
TIMER_START(prepare_maneuver_overrides);
const auto mark_ids = [&](auto const &external_maneuver_override) {
FirstAndLastSegmentOfWay dummy_segment{
MAX_OSM_WAYID, MAX_OSM_NODEID, MAX_OSM_NODEID, MAX_OSM_NODEID, MAX_OSM_NODEID};
std::for_each(external_maneuver_override.via_ways.begin(),
external_maneuver_override.via_ways.end(),
[&referenced_ways, dummy_segment](const auto &element) {
referenced_ways[element] = dummy_segment;
});
};
// First, make an empty hashtable keyed by the ways referenced
// by the maneuver overrides
std::for_each(external_maneuver_overrides_list.begin(),
external_maneuver_overrides_list.end(),
mark_ids);
const auto set_ids = [&](auto const &start_end) {
auto itr = referenced_ways.find(start_end.way_id);
if (itr != referenced_ways.end())
itr->second = start_end;
};
// Then, populate the values in that hashtable for only the ways
// referenced
std::for_each(way_start_end_id_list.cbegin(), way_start_end_id_list.cend(), set_ids);
TIMER_STOP(prepare_maneuver_overrides);
log << "ok, after " << TIMER_SEC(prepare_maneuver_overrides) << "s";
}
auto const osm_node_to_internal_nbn = [&](auto const osm_node) {
auto internal = mapExternalToInternalNodeID(
used_node_id_list.begin(), used_node_id_list.end(), osm_node);
if (internal == SPECIAL_NODEID)
{
util::Log(logDEBUG) << "Maneuver override references invalid node: " << osm_node;
}
return internal;
};
// Given
// a -- b - ????????? - c -- d as via segment
// and either
// d -- e - ????????? - f -- g or
// h -- i - ????????? - j -- a
// return
// (d,e) or (j,a) as entry-segment
/**
* Here's what these properties represent on the node-based-graph
* way "ABCD" way "AB"
* -----------------------------------------------------------------
* ⬇ A first_segment_source_id
* ⬇ |
* ⬇︎ B first_segment_target_id A first_segment_source_id
* ⬇︎ | ⬇ | last_segment_source_id
* ⬇︎ | ⬇ |
* ⬇︎ | B first_segment_target_id
* ⬇︎ C last_segment_source_id last_segment_target_id
* ⬇︎ |
* ⬇︎ D last_segment_target_id
*
* Finds the point where two ways connect at the end, and returns the 3
* node-based nodes that describe the turn (the node just before, the
* node at the turn, and the next node after the turn)
**/
auto const find_turn_from_way_tofrom_nodes = [&](auto const &from_segment,
auto const &to_segment) {
if (from_segment.first_segment_source_id == to_segment.first_segment_source_id)
{
return NodeBasedTurn{osm_node_to_internal_nbn(from_segment.first_segment_target_id),
osm_node_to_internal_nbn(from_segment.first_segment_source_id),
osm_node_to_internal_nbn(to_segment.first_segment_target_id)};
}
else if (from_segment.first_segment_source_id == to_segment.last_segment_target_id)
{
return NodeBasedTurn{osm_node_to_internal_nbn(from_segment.first_segment_target_id),
osm_node_to_internal_nbn(from_segment.first_segment_source_id),
osm_node_to_internal_nbn(to_segment.last_segment_source_id)};
}
else if (from_segment.last_segment_target_id == to_segment.first_segment_source_id)
{
return NodeBasedTurn{osm_node_to_internal_nbn(from_segment.last_segment_source_id),
osm_node_to_internal_nbn(from_segment.last_segment_target_id),
osm_node_to_internal_nbn(to_segment.first_segment_target_id)};
}
else if (from_segment.last_segment_target_id == to_segment.last_segment_target_id)
{
return NodeBasedTurn{osm_node_to_internal_nbn(from_segment.last_segment_source_id),
osm_node_to_internal_nbn(from_segment.last_segment_target_id),
osm_node_to_internal_nbn(to_segment.last_segment_source_id)};
}
util::Log(logDEBUG) << "Maneuver override ways " << from_segment.way_id << " and "
<< to_segment.way_id << " are not connected";
return NodeBasedTurn{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
};
auto const get_turn_from_way_pair = [&](const OSMWayID &from_id, const OSMWayID &to_id) {
auto const from_segment_itr = referenced_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 = referenced_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};
}
auto result =
find_turn_from_way_tofrom_nodes(from_segment_itr->second, to_segment_itr->second);
return result;
};
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,
guidance::DirectionModifier::MaxDirectionModifier);
if (turn_string == "uturn")
{
result.first = guidance::TurnType::Turn;
result.second = guidance::DirectionModifier::UTurn;
}
else if (turn_string == "continue")
{
result.first = guidance::TurnType::Continue;
}
else if (turn_string == "turn")
{
result.first = guidance::TurnType::Turn;
}
else if (turn_string == "fork")
{
result.first = guidance::TurnType::Fork;
}
else if (turn_string == "suppress")
{
result.first = guidance::TurnType::Suppressed;
}
// Directions
if (direction_string == "left")
{
result.second = guidance::DirectionModifier::Left;
}
else if (direction_string == "slight_left")
{
result.second = guidance::DirectionModifier::SlightLeft;
}
else if (direction_string == "sharp_left")
{
result.second = guidance::DirectionModifier::SharpLeft;
}
else if (direction_string == "sharp_right")
{
result.second = guidance::DirectionModifier::SharpRight;
}
else if (direction_string == "slight_right")
{
result.second = guidance::DirectionModifier::SlightRight;
}
else if (direction_string == "right")
{
result.second = guidance::DirectionModifier::Right;
}
return result;
};
// Transform an InternalManeuverOverride (based on WayIDs) into an OSRM override (base on
// NodeIDs).
// 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)
{
// 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);
}
// 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);
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;
};
const auto transform_into_internal_types =
[&](const InputManeuverOverride &external_maneuver_override) {
UnresolvedManeuverOverride internal_maneuver_override;
if (transform(external_maneuver_override, internal_maneuver_override))
internal_maneuver_overrides.push_back(std::move(internal_maneuver_override));
};
// Transforming the overrides into the dedicated internal types
{
util::UnbufferedLog log;
log << "Collecting start/end information on " << external_maneuver_overrides_list.size()
<< " maneuver overrides...";
TIMER_START(transform);
std::for_each(external_maneuver_overrides_list.begin(),
external_maneuver_overrides_list.end(),
transform_into_internal_types);
TIMER_STOP(transform);
log << "ok, after " << TIMER_SEC(transform) << "s";
}
}
void ExtractionContainers::PrepareRestrictions()
{
// contain the start/end nodes of each way that is part of an restriction
std::unordered_map<OSMWayID, FirstAndLastSegmentOfWay> referenced_ways;
@@ -729,9 +984,16 @@ void ExtractionContainers::PrepareRestrictions()
// (d,e) or (j,a) as entry-segment
auto const find_node_restriction =
[&](auto const &segment, auto const &via_segment, auto const via_node) {
// In case of way-restrictions, via-node will be set to MAX_OSM_NODEID to signal that
// In case of way-restrictions, via-node will be set to MAX_OSM_NODEID to signal
// that
// the node is not present.
// connected at the front of the segment
// Turn restrictions are described as a restriction between the two segments closest
// to
// the shared via-node on the from and to ways. Graph compression will later
// renumber
// the from and to internal node IDs as nodes are plucked out of the node-based
// graph.
if (via_node == MAX_OSM_NODEID || segment.first_segment_source_id == via_node)
{
if (segment.first_segment_source_id == via_segment.first_segment_source_id)
@@ -770,7 +1032,8 @@ void ExtractionContainers::PrepareRestrictions()
return NodeRestriction{SPECIAL_NODEID, SPECIAL_NODEID, SPECIAL_NODEID};
};
// translate the turn from one segment onto another into a node restriction (the ways can only
// translate the turn from one segment onto another into a node restriction (the ways can
// only
// be connected at a single location)
auto const get_node_restriction_from_OSM_ids = [&](
auto const from_id, auto const to_id, const OSMNodeID via_node) {
@@ -792,7 +1055,8 @@ void ExtractionContainers::PrepareRestrictions()
// Transform an OSMRestriction (based on WayIDs) into an OSRM restriction (base on NodeIDs).
// Returns true on successful transformation, false in case of invalid references.
// Based on the auto type deduction, this transfor handles both conditional and unconditional
// Based on the auto type deduction, this transfor handles both conditional and
// unconditional
// turn restrictions.
const auto transform = [&](const auto &external_type, auto &internal_type) {
if (external_type.Type() == RestrictionType::WAY_RESTRICTION)
@@ -808,7 +1072,8 @@ void ExtractionContainers::PrepareRestrictions()
if (!from_restriction.Valid() || !to_restriction.Valid())
return false;
// point located at both via and segment is alway on `second`, to FSSF is the order we
// point located at both via and segment is alway on `second`, to FSSF is the order
// we
// need
WayRestriction way_restriction{from_restriction, to_restriction};
internal_type.node_or_way = std::move(way_restriction);
+31 -6
View File
@@ -7,6 +7,7 @@
#include "extractor/extraction_way.hpp"
#include "extractor/extractor_callbacks.hpp"
#include "extractor/files.hpp"
#include "extractor/maneuver_override_relation_parser.hpp"
#include "extractor/node_based_graph_factory.hpp"
#include "extractor/raster_source.hpp"
#include "extractor/restriction_filter.hpp"
@@ -202,7 +203,11 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
LaneDescriptionMap turn_lane_map;
std::vector<TurnRestriction> turn_restrictions;
std::vector<ConditionalTurnRestriction> conditional_turn_restrictions;
std::tie(turn_lane_map, turn_restrictions, conditional_turn_restrictions) =
std::vector<UnresolvedManeuverOverride> unresolved_maneuver_overrides;
std::tie(turn_lane_map,
turn_restrictions,
conditional_turn_restrictions,
unresolved_maneuver_overrides) =
ParseOSMData(scripting_environment, number_of_threads);
// Transform the node-based graph that OSM is based on into an edge-based graph
@@ -223,7 +228,8 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
NodeBasedGraphFactory node_based_graph_factory(config.GetPath(".osrm"),
scripting_environment,
turn_restrictions,
conditional_turn_restrictions);
conditional_turn_restrictions,
unresolved_maneuver_overrides);
util::Log() << "Find segregated edges in node-based graph ..." << std::flush;
TIMER_START(segregated);
@@ -290,6 +296,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
conditional_turn_restrictions,
segregated_edges,
name_table,
unresolved_maneuver_overrides,
turn_lane_map,
scripting_environment,
edge_based_nodes_container,
@@ -367,7 +374,8 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
std::tuple<LaneDescriptionMap,
std::vector<TurnRestriction>,
std::vector<ConditionalTurnRestriction>>
std::vector<ConditionalTurnRestriction>,
std::vector<UnresolvedManeuverOverride>>
Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
const unsigned number_of_threads)
{
@@ -432,6 +440,8 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
config.parse_conditionals,
restrictions);
const ManeuverOverrideRelationParser maneuver_override_parser;
// OSM data reader
using SharedBuffer = std::shared_ptr<osmium::memory::Buffer>;
struct ParsedBuffer
@@ -441,6 +451,7 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
std::vector<std::pair<const osmium::Way &, ExtractionWay>> resulting_ways;
std::vector<std::pair<const osmium::Relation &, ExtractionRelation>> resulting_relations;
std::vector<InputConditionalTurnRestriction> resulting_restrictions;
std::vector<InputManeuverOverride> resulting_maneuver_overrides;
};
ExtractionRelationContainer relations;
@@ -482,10 +493,12 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
parsed_buffer.buffer = buffer;
scripting_environment.ProcessElements(*buffer,
restriction_parser,
maneuver_override_parser,
relations,
parsed_buffer.resulting_nodes,
parsed_buffer.resulting_ways,
parsed_buffer.resulting_restrictions);
parsed_buffer.resulting_restrictions,
parsed_buffer.resulting_maneuver_overrides);
return parsed_buffer;
});
@@ -493,6 +506,7 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
unsigned number_of_nodes = 0;
unsigned number_of_ways = 0;
unsigned number_of_restrictions = 0;
unsigned number_of_maneuver_overrides = 0;
tbb::filter_t<ParsedBuffer, void> buffer_storage(
tbb::filter::serial_in_order, [&](const ParsedBuffer &parsed_buffer) {
@@ -513,6 +527,13 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
{
extractor_callbacks->ProcessRestriction(result);
}
number_of_maneuver_overrides = parsed_buffer.resulting_maneuver_overrides.size();
for (const auto &result : parsed_buffer.resulting_maneuver_overrides)
{
extractor_callbacks->ProcessManeuverOverride(result);
}
});
tbb::filter_t<SharedBuffer, std::shared_ptr<ExtractionRelationContainer>> buffer_relation_cache(
@@ -617,7 +638,8 @@ Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
return std::make_tuple(std::move(turn_lane_map),
std::move(extraction_containers.unconditional_turn_restrictions),
std::move(extraction_containers.conditional_turn_restrictions));
std::move(extraction_containers.conditional_turn_restrictions),
std::move(extraction_containers.internal_maneuver_overrides));
}
void Extractor::FindComponents(unsigned number_of_edge_based_nodes,
@@ -693,6 +715,7 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
const std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
const std::unordered_set<EdgeID> &segregated_edges,
const util::NameTable &name_table,
const std::vector<UnresolvedManeuverOverride> &maneuver_overrides,
const LaneDescriptionMap &turn_lane_map,
// for calculating turn penalties
ScriptingEnvironment &scripting_environment,
@@ -736,9 +759,11 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
config.GetPath(".osrm.turn_penalties_index").string(),
config.GetPath(".osrm.cnbg_to_ebg").string(),
config.GetPath(".osrm.restrictions").string(),
config.GetPath(".osrm.maneuver_overrides").string(),
via_node_restriction_map,
conditional_node_restriction_map,
via_way_restriction_map);
via_way_restriction_map,
maneuver_overrides);
return edge_based_graph_factory.GetNumberOfEdgeBasedNodes();
};
+5
View File
@@ -75,6 +75,11 @@ void ExtractorCallbacks::ProcessRestriction(const InputConditionalTurnRestrictio
// util::Log() << restriction.toString();
}
void ExtractorCallbacks::ProcessManeuverOverride(const InputManeuverOverride & override)
{
external_memory.external_maneuver_overrides_list.push_back(override);
}
/**
* Takes the geometry contained in the ```input_way``` and the tags computed
* by the lua profile inside ```parsed_way``` and computes all edge segments.
+3 -1
View File
@@ -26,6 +26,7 @@ void GraphCompressor::Compress(
ScriptingEnvironment &scripting_environment,
std::vector<TurnRestriction> &turn_restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides,
util::NodeBasedDynamicGraph &graph,
const std::vector<NodeBasedEdgeAnnotation> &node_data_container,
CompressedEdgeContainer &geometry_compressor)
@@ -33,7 +34,8 @@ void GraphCompressor::Compress(
const unsigned original_number_of_nodes = graph.GetNumberOfNodes();
const unsigned original_number_of_edges = graph.GetNumberOfEdges();
RestrictionCompressor restriction_compressor(turn_restrictions, conditional_turn_restrictions);
RestrictionCompressor restriction_compressor(
turn_restrictions, conditional_turn_restrictions, maneuver_overrides);
// we do not compress turn restrictions on degree two nodes. These nodes are usually used to
// indicated `directed` barriers
@@ -0,0 +1,126 @@
#include "extractor/maneuver_override_relation_parser.hpp"
#include "extractor/maneuver_override.hpp"
#include "util/log.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/regex.hpp>
#include <boost/optional/optional.hpp>
#include <boost/ref.hpp>
#include <boost/regex.hpp>
#include <osmium/osm.hpp>
#include <osmium/tags/regex_filter.hpp>
#include <algorithm>
#include <iterator>
namespace osrm
{
namespace extractor
{
ManeuverOverrideRelationParser::ManeuverOverrideRelationParser() {}
/**
* Parses the `type=maneuver` relation. Reads the fields, and puts data
* into an InputManeuverOverride object, if the relation is considered
* valid (i.e. has the minimum tags we expect).
*/
boost::optional<InputManeuverOverride>
ManeuverOverrideRelationParser::TryParse(const osmium::Relation &relation) const
{
osmium::tags::KeyFilter filter(false);
filter.add(true, "maneuver");
const osmium::TagList &tag_list = relation.tags();
osmium::tags::KeyFilter::iterator fi_begin(filter, tag_list.begin(), tag_list.end());
osmium::tags::KeyFilter::iterator fi_end(filter, tag_list.end(), tag_list.end());
// if it's not a maneuver, continue;
if (std::distance(fi_begin, fi_end) == 0)
{
return boost::none;
}
// we pretend every restriction is a conditional restriction. If we do not find any restriction,
// we can trim away the vector after parsing
InputManeuverOverride maneuver_override;
maneuver_override.maneuver = relation.tags().get_value_by_key("maneuver", "");
maneuver_override.direction = relation.tags().get_value_by_key("direction", "");
boost::optional<std::uint64_t> from = boost::none, via = boost::none, to = boost::none;
std::vector<std::uint64_t> via_ways;
for (const auto &member : relation.members())
{
const char *role = member.role();
if (strcmp("from", role) != 0 && strcmp("to", role) != 0 && strcmp("via", role) != 0)
{
continue;
}
switch (member.type())
{
case osmium::item_type::node:
{
// Make sure nodes appear only in the role if a via node
if (0 == strcmp("from", role) || 0 == strcmp("to", role))
{
continue;
}
BOOST_ASSERT(0 == strcmp("via", role));
via = static_cast<std::uint64_t>(member.ref());
// set via node id
break;
}
case osmium::item_type::way:
BOOST_ASSERT(0 == strcmp("from", role) || 0 == strcmp("to", role) ||
0 == strcmp("via", role));
if (0 == strcmp("from", role))
{
from = static_cast<std::uint64_t>(member.ref());
}
else if (0 == strcmp("to", role))
{
to = static_cast<std::uint64_t>(member.ref());
}
else if (0 == strcmp("via", role))
{
via_ways.push_back(static_cast<std::uint64_t>(member.ref()));
}
break;
case osmium::item_type::relation:
// not yet supported, but who knows what the future holds...
break;
default:
// shouldn't ever happen
break;
}
}
if (from && (via || via_ways.size() > 0) && to)
{
via_ways.insert(via_ways.begin(), *from);
via_ways.push_back(*to);
if (via)
{
maneuver_override.via_node = {*via};
}
for (const auto &n : via_ways)
{
maneuver_override.via_ways.push_back(OSMWayID{n});
}
}
else
{
return boost::none;
}
return maneuver_override;
}
}
}
+9 -3
View File
@@ -19,10 +19,14 @@ NodeBasedGraphFactory::NodeBasedGraphFactory(
const boost::filesystem::path &input_file,
ScriptingEnvironment &scripting_environment,
std::vector<TurnRestriction> &turn_restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions)
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides)
{
LoadDataFromFile(input_file);
Compress(scripting_environment, turn_restrictions, conditional_turn_restrictions);
Compress(scripting_environment,
turn_restrictions,
conditional_turn_restrictions,
maneuver_overrides);
CompressGeometry();
CompressAnnotationData();
}
@@ -84,7 +88,8 @@ void NodeBasedGraphFactory::LoadDataFromFile(const boost::filesystem::path &inpu
void NodeBasedGraphFactory::Compress(
ScriptingEnvironment &scripting_environment,
std::vector<TurnRestriction> &turn_restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions)
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides)
{
GraphCompressor graph_compressor;
graph_compressor.Compress(barriers,
@@ -92,6 +97,7 @@ void NodeBasedGraphFactory::Compress(
scripting_environment,
turn_restrictions,
conditional_turn_restrictions,
maneuver_overrides,
compressed_output_graph,
annotation_data,
compressed_edge_container);
+84 -1
View File
@@ -12,7 +12,8 @@ namespace extractor
RestrictionCompressor::RestrictionCompressor(
std::vector<TurnRestriction> &restrictions,
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions)
std::vector<ConditionalTurnRestriction> &conditional_turn_restrictions,
std::vector<UnresolvedManeuverOverride> &maneuver_overrides)
{
// add a node restriction ptr to the starts/ends maps, needs to be a reference!
auto index = [&](auto &element) {
@@ -40,10 +41,23 @@ RestrictionCompressor::RestrictionCompressor(
std::for_each(conditional_turn_restrictions.begin(),
conditional_turn_restrictions.end(),
index_starts_and_ends);
auto index_maneuver = [&](auto &maneuver) {
for (auto &turn : maneuver.turn_sequence)
{
maneuver_starts.insert(std::make_pair(turn.from, &turn));
maneuver_ends.insert(std::make_pair(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 startptrs and move them from via to from.
auto all_starts_range = starts.equal_range(via);
std::vector<NodeRestriction *> start_ptrs;
@@ -104,6 +118,75 @@ void RestrictionCompressor::Compress(const NodeID from, const NodeID via, const
const auto reinsert_end = [&](auto ptr) { ends.insert(std::make_pair(ptr->to, ptr)); };
std::for_each(end_ptrs.begin(), end_ptrs.end(), reinsert_end);
/**********************************************************************************************/
// 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(std::make_pair(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(std::make_pair(ptr->to, ptr));
};
std::for_each(mnv_end_ptrs.begin(), mnv_end_ptrs.end(), reinsert_end_mnvs);
}
} // namespace extractor
+8 -1
View File
@@ -7,6 +7,7 @@
#include "extractor/extraction_turn.hpp"
#include "extractor/extraction_way.hpp"
#include "extractor/internal_extractor_edge.hpp"
#include "extractor/maneuver_override_relation_parser.hpp"
#include "extractor/profile_properties.hpp"
#include "extractor/query_node.hpp"
#include "extractor/raster_source.hpp"
@@ -842,10 +843,12 @@ LuaScriptingContext &Sol2ScriptingEnvironment::GetSol2Context()
void Sol2ScriptingEnvironment::ProcessElements(
const osmium::memory::Buffer &buffer,
const RestrictionParser &restriction_parser,
const ManeuverOverrideRelationParser &maneuver_override_parser,
const ExtractionRelationContainer &relations,
std::vector<std::pair<const osmium::Node &, ExtractionNode>> &resulting_nodes,
std::vector<std::pair<const osmium::Way &, ExtractionWay>> &resulting_ways,
std::vector<InputConditionalTurnRestriction> &resulting_restrictions)
std::vector<InputConditionalTurnRestriction> &resulting_restrictions,
std::vector<InputManeuverOverride> &resulting_maneuver_overrides)
{
ExtractionNode result_node;
ExtractionWay result_way;
@@ -885,6 +888,10 @@ void Sol2ScriptingEnvironment::ProcessElements(
{
resulting_restrictions.push_back(*result_res);
}
else if (auto result_res = maneuver_override_parser.TryParse(relation))
{
resulting_maneuver_overrides.push_back(*result_res);
}
}
break;
default:
+28
View File
@@ -17,6 +17,7 @@
#include "extractor/edge_based_edge.hpp"
#include "extractor/edge_based_node.hpp"
#include "extractor/files.hpp"
#include "extractor/maneuver_override.hpp"
#include "extractor/packed_osm_ids.hpp"
#include "extractor/profile_properties.hpp"
#include "extractor/query_node.hpp"
@@ -440,6 +441,17 @@ void Storage::PopulateLayout(DataLayout &layout)
lane_tuple_count);
}
// load maneuver overrides
{
io::FileReader maneuver_overrides_file(config.GetPath(".osrm.maneuver_overrides"),
io::FileReader::VerifyFingerprint);
const auto number_of_overrides = maneuver_overrides_file.ReadElementCount64();
layout.SetBlockSize<extractor::StorageManeuverOverride>(DataLayout::MANEUVER_OVERRIDES,
number_of_overrides);
const auto number_of_nodes = maneuver_overrides_file.ReadElementCount64();
layout.SetBlockSize<NodeID>(DataLayout::MANEUVER_OVERRIDE_NODE_SEQUENCES, number_of_nodes);
}
{
// Loading MLD Data
if (boost::filesystem::exists(config.GetPath(".osrm.partition")))
@@ -1074,6 +1086,22 @@ void Storage::PopulateData(const DataLayout &layout, char *memory_ptr)
" in " + config.GetPath(".osrm.edges").string());
}
}
// load maneuver overrides
{
io::FileReader maneuver_overrides_file(config.GetPath(".osrm.maneuver_overrides"),
io::FileReader::VerifyFingerprint);
const auto number_of_overrides = maneuver_overrides_file.ReadElementCount64();
const auto number_of_nodes = maneuver_overrides_file.ReadElementCount64();
const auto maneuver_overrides_ptr =
layout.GetBlockPtr<extractor::StorageManeuverOverride, true>(
memory_ptr, DataLayout::MANEUVER_OVERRIDES);
maneuver_overrides_file.ReadInto(maneuver_overrides_ptr, number_of_overrides);
const auto maneuver_override_node_sequences_ptr = layout.GetBlockPtr<NodeID, true>(
memory_ptr, DataLayout::MANEUVER_OVERRIDE_NODE_SEQUENCES);
maneuver_overrides_file.ReadInto(maneuver_override_node_sequences_ptr, number_of_nodes);
}
}
}
}