Support OSM traffic signal directions (#6153)
Currently OSRM parses traffic signal nodes without consideration for the direction in which the signal applies. This can lead to duplicated routing penalties, especially when a forward and backward signal are in close proximity on a way. This commit adds support for directed signals to the extraction and graph creation. Signal penalties are only applied in the direction specified by the OSM tag. We add the assignment of traffic directions to the lua scripts, maintaining backwards compatibility with the existing boolean traffic states. As part of the changes to the internal structures used for tracking traffic signals during extraction, we stop serialising/deserialising signals to the `.osrm` file. The traffic signals are only used by `osrm-extract` so whilst this is a data format change, it will not break any existing user processes.
This commit is contained in:
@@ -59,7 +59,7 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory(
|
||||
EdgeBasedNodeDataContainer &node_data_container,
|
||||
const CompressedEdgeContainer &compressed_edge_container,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const std::unordered_set<NodeID> &traffic_lights,
|
||||
const TrafficSignals &traffic_signals,
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const NameTable &name_table,
|
||||
const std::unordered_set<EdgeID> &segregated_edges,
|
||||
@@ -67,7 +67,7 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory(
|
||||
: m_edge_based_node_container(node_data_container), m_connectivity_checksum(0),
|
||||
m_number_of_edge_based_nodes(0), m_coordinates(coordinates),
|
||||
m_node_based_graph(node_based_graph), m_barrier_nodes(barrier_nodes),
|
||||
m_traffic_lights(traffic_lights), m_compressed_edge_container(compressed_edge_container),
|
||||
m_traffic_signals(traffic_signals), m_compressed_edge_container(compressed_edge_container),
|
||||
name_table(name_table), segregated_edges(segregated_edges),
|
||||
lane_description_map(lane_description_map)
|
||||
{
|
||||
@@ -623,8 +623,26 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
BOOST_ASSERT(!edge_data1.reversed);
|
||||
BOOST_ASSERT(!edge_data2.reversed);
|
||||
|
||||
// We write out the mapping between the edge-expanded edges and the original nodes.
|
||||
// Since each edge represents a possible maneuver, external programs can use this to
|
||||
// quickly perform updates to edge weights in order to penalize certain turns.
|
||||
|
||||
// If this edge is 'trivial' -- where the compressed edge corresponds exactly to an
|
||||
// original OSM segment -- we can pull the turn's preceding node ID directly with
|
||||
// `node_along_road_entering`;
|
||||
// otherwise, we need to look up the node immediately preceding the turn from the
|
||||
// compressed edge container.
|
||||
const bool isTrivial = m_compressed_edge_container.IsTrivial(node_based_edge_from);
|
||||
|
||||
const auto &from_node =
|
||||
isTrivial ? node_along_road_entering
|
||||
: m_compressed_edge_container.GetLastEdgeSourceID(node_based_edge_from);
|
||||
|
||||
// compute weight and duration penalties
|
||||
const auto is_traffic_light = m_traffic_lights.count(intersection_node);
|
||||
// In theory we shouldn't get a directed traffic light on a turn, as it indicates that
|
||||
// the traffic signal direction was potentially ambiguously annotated on the junction
|
||||
// node But we'll check anyway.
|
||||
const auto is_traffic_light = m_traffic_signals.HasSignal(from_node, intersection_node);
|
||||
const auto is_uturn =
|
||||
guidance::getTurnDirection(turn_angle) == guidance::DirectionModifier::UTurn;
|
||||
|
||||
@@ -690,20 +708,6 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges(
|
||||
true,
|
||||
false};
|
||||
|
||||
// We write out the mapping between the edge-expanded edges and the original nodes.
|
||||
// Since each edge represents a possible maneuver, external programs can use this to
|
||||
// quickly perform updates to edge weights in order to penalize certain turns.
|
||||
|
||||
// If this edge is 'trivial' -- where the compressed edge corresponds exactly to an
|
||||
// original OSM segment -- we can pull the turn's preceding node ID directly with
|
||||
// `node_along_road_entering`;
|
||||
// otherwise, we need to look up the node immediately preceding the turn from the
|
||||
// compressed edge container.
|
||||
const bool isTrivial = m_compressed_edge_container.IsTrivial(node_based_edge_from);
|
||||
|
||||
const auto &from_node =
|
||||
isTrivial ? node_along_road_entering
|
||||
: m_compressed_edge_container.GetLastEdgeSourceID(node_based_edge_from);
|
||||
const auto &to_node =
|
||||
m_compressed_edge_container.GetFirstEdgeTargetID(node_based_edge_to);
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "util/exception.hpp"
|
||||
#include "util/exception_utils.hpp"
|
||||
#include "util/for_each_indexed.hpp"
|
||||
#include "util/for_each_pair.hpp"
|
||||
#include "util/log.hpp"
|
||||
#include "util/timing_util.hpp"
|
||||
|
||||
@@ -413,6 +414,7 @@ void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environme
|
||||
|
||||
const auto restriction_ways = IdentifyRestrictionWays();
|
||||
const auto maneuver_override_ways = IdentifyManeuverOverrideWays();
|
||||
const auto traffic_signals = IdentifyTrafficSignals();
|
||||
|
||||
PrepareNodes();
|
||||
WriteNodes(writer);
|
||||
@@ -422,6 +424,7 @@ void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environme
|
||||
WriteEdges(writer);
|
||||
WriteMetadata(writer);
|
||||
|
||||
PrepareTrafficSignals(traffic_signals);
|
||||
PrepareManeuverOverrides(maneuver_override_ways);
|
||||
PrepareRestrictions(restriction_ways);
|
||||
WriteCharData(name_file_name);
|
||||
@@ -911,25 +914,6 @@ void ExtractionContainers::WriteNodes(storage::tar::FileWriter &writer) const
|
||||
log << "ok, after " << TIMER_SEC(write_nodes) << "s";
|
||||
}
|
||||
|
||||
{
|
||||
util::UnbufferedLog log;
|
||||
log << "Writing traffic light nodes ... ";
|
||||
TIMER_START(write_nodes);
|
||||
std::vector<NodeID> internal_traffic_signals;
|
||||
for (const auto osm_id : traffic_signals)
|
||||
{
|
||||
const auto node_id = mapExternalToInternalNodeID(
|
||||
used_node_id_list.begin(), used_node_id_list.end(), osm_id);
|
||||
if (node_id != SPECIAL_NODEID)
|
||||
{
|
||||
internal_traffic_signals.push_back(node_id);
|
||||
}
|
||||
}
|
||||
storage::serialization::write(
|
||||
writer, "/extractor/traffic_lights", internal_traffic_signals);
|
||||
log << "ok, after " << TIMER_SEC(write_nodes) << "s";
|
||||
}
|
||||
|
||||
util::Log() << "Processed " << max_internal_node_id << " nodes";
|
||||
}
|
||||
|
||||
@@ -983,6 +967,50 @@ ExtractionContainers::ReferencedWays ExtractionContainers::IdentifyManeuverOverr
|
||||
return maneuver_override_ways;
|
||||
}
|
||||
|
||||
void ExtractionContainers::PrepareTrafficSignals(
|
||||
const ExtractionContainers::ReferencedTrafficSignals &referenced_traffic_signals)
|
||||
{
|
||||
const auto &bidirectional_signal_nodes = referenced_traffic_signals.first;
|
||||
const auto &unidirectional_signal_segments = referenced_traffic_signals.second;
|
||||
|
||||
util::UnbufferedLog log;
|
||||
log << "Preparing traffic light signals for " << bidirectional_signal_nodes.size()
|
||||
<< " bidirectional, " << unidirectional_signal_segments.size()
|
||||
<< " unidirectional nodes ...";
|
||||
TIMER_START(prepare_traffic_signals);
|
||||
|
||||
std::unordered_set<NodeID> bidirectional;
|
||||
std::unordered_set<std::pair<NodeID, NodeID>, boost::hash<std::pair<NodeID, NodeID>>>
|
||||
unidirectional;
|
||||
|
||||
for (const auto &osm_node : bidirectional_signal_nodes)
|
||||
{
|
||||
const auto node_id = mapExternalToInternalNodeID(
|
||||
used_node_id_list.begin(), used_node_id_list.end(), osm_node);
|
||||
if (node_id != SPECIAL_NODEID)
|
||||
{
|
||||
bidirectional.insert(node_id);
|
||||
}
|
||||
}
|
||||
for (const auto &to_from : unidirectional_signal_segments)
|
||||
{
|
||||
const auto to_node_id = mapExternalToInternalNodeID(
|
||||
used_node_id_list.begin(), used_node_id_list.end(), to_from.first);
|
||||
const auto from_node_id = mapExternalToInternalNodeID(
|
||||
used_node_id_list.begin(), used_node_id_list.end(), to_from.second);
|
||||
if (from_node_id != SPECIAL_NODEID && to_node_id != SPECIAL_NODEID)
|
||||
{
|
||||
unidirectional.insert({from_node_id, to_node_id});
|
||||
}
|
||||
}
|
||||
|
||||
internal_traffic_signals.bidirectional_nodes = std::move(bidirectional);
|
||||
internal_traffic_signals.unidirectional_segments = std::move(unidirectional);
|
||||
|
||||
TIMER_STOP(prepare_traffic_signals);
|
||||
log << "ok, after " << TIMER_SEC(prepare_traffic_signals) << "s";
|
||||
}
|
||||
|
||||
void ExtractionContainers::PrepareManeuverOverrides(const ReferencedWays &maneuver_override_ways)
|
||||
{
|
||||
auto const osm_node_to_internal_nbn = [&](auto const osm_node) {
|
||||
@@ -1163,6 +1191,93 @@ ExtractionContainers::ReferencedWays ExtractionContainers::IdentifyRestrictionWa
|
||||
return restriction_ways;
|
||||
}
|
||||
|
||||
ExtractionContainers::ReferencedTrafficSignals ExtractionContainers::IdentifyTrafficSignals()
|
||||
{
|
||||
util::UnbufferedLog log;
|
||||
log << "Collecting traffic signal information on " << external_traffic_signals.size()
|
||||
<< " signals...";
|
||||
TIMER_START(identify_traffic_signals);
|
||||
|
||||
// Temporary store for nodes containing a unidirectional signal.
|
||||
std::unordered_map<OSMNodeID, TrafficLightClass::Direction> unidirectional_signals;
|
||||
|
||||
// For each node that has a unidirectional traffic signal, we store the node(s)
|
||||
// that lead up to the signal.
|
||||
std::unordered_multimap<OSMNodeID, OSMNodeID> signal_segments;
|
||||
|
||||
std::unordered_set<OSMNodeID> bidirectional_signals;
|
||||
|
||||
const auto mark_signals = [&](auto const &traffic_signal) {
|
||||
if (traffic_signal.second == TrafficLightClass::DIRECTION_FORWARD ||
|
||||
traffic_signal.second == TrafficLightClass::DIRECTION_REVERSE)
|
||||
{
|
||||
unidirectional_signals.insert({traffic_signal.first, traffic_signal.second});
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(traffic_signal.second == TrafficLightClass::DIRECTION_ALL);
|
||||
bidirectional_signals.insert(traffic_signal.first);
|
||||
}
|
||||
};
|
||||
std::for_each(external_traffic_signals.begin(), external_traffic_signals.end(), mark_signals);
|
||||
|
||||
// Extract all the segments that lead up to unidirectional traffic signals.
|
||||
const auto set_segments = [&](const size_t way_list_idx, auto const & /*unused*/) {
|
||||
const auto node_start_offset =
|
||||
used_node_id_list.begin() + way_node_id_offsets[way_list_idx];
|
||||
const auto node_end_offset =
|
||||
used_node_id_list.begin() + way_node_id_offsets[way_list_idx + 1];
|
||||
|
||||
for (auto node_it = node_start_offset; node_it < node_end_offset; node_it++)
|
||||
{
|
||||
const auto sig = unidirectional_signals.find(*node_it);
|
||||
if (sig != unidirectional_signals.end())
|
||||
{
|
||||
if (sig->second == TrafficLightClass::DIRECTION_FORWARD)
|
||||
{
|
||||
if (node_it != node_start_offset)
|
||||
{
|
||||
// Previous node leads to signal
|
||||
signal_segments.insert({*node_it, *(node_it - 1)});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
BOOST_ASSERT(sig->second == TrafficLightClass::DIRECTION_REVERSE);
|
||||
if (node_it + 1 != node_end_offset)
|
||||
{
|
||||
// Next node leads to signal
|
||||
signal_segments.insert({*node_it, *(node_it + 1)});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
util::for_each_indexed(ways_list.cbegin(), ways_list.cend(), set_segments);
|
||||
|
||||
util::for_each_pair(
|
||||
signal_segments, [](const auto pair_a, const auto pair_b) {
|
||||
if (pair_a.first == pair_b.first)
|
||||
{
|
||||
// If a node is appearing multiple times in this map, then it's ambiguous.
|
||||
// The node is an intersection and the traffic direction is being use for multiple
|
||||
// ways. We can't be certain of the original intent. See:
|
||||
// https://wiki.openstreetmap.org/wiki/Key:traffic_signals:direction
|
||||
|
||||
// OSRM will include the signal for all intersecting ways in the specified
|
||||
// direction, but let's flag this as a concern.
|
||||
util::Log(logWARNING)
|
||||
<< "OSM node " << pair_a.first
|
||||
<< " has a unidirectional traffic signal ambiguously applied to multiple ways";
|
||||
}
|
||||
});
|
||||
|
||||
TIMER_STOP(identify_traffic_signals);
|
||||
log << "ok, after " << TIMER_SEC(identify_traffic_signals) << "s";
|
||||
|
||||
return {std::move(bidirectional_signals), std::move(signal_segments)};
|
||||
}
|
||||
|
||||
void ExtractionContainers::PrepareRestrictions(const ReferencedWays &restriction_ways)
|
||||
{
|
||||
|
||||
|
||||
+14
-10
@@ -75,7 +75,7 @@ void SetClassNames(const std::vector<std::string> &class_names,
|
||||
if (!class_names.empty())
|
||||
{
|
||||
// add class names that were never used explicitly on a way
|
||||
// this makes sure we can correctly validate unkown class names later
|
||||
// this makes sure we can correctly validate unknown class names later
|
||||
for (const auto &name : class_names)
|
||||
{
|
||||
if (!isValidClassName(name))
|
||||
@@ -207,7 +207,8 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
LaneDescriptionMap turn_lane_map;
|
||||
std::vector<TurnRestriction> turn_restrictions;
|
||||
std::vector<UnresolvedManeuverOverride> unresolved_maneuver_overrides;
|
||||
std::tie(turn_lane_map, turn_restrictions, unresolved_maneuver_overrides) =
|
||||
TrafficSignals traffic_signals;
|
||||
std::tie(turn_lane_map, turn_restrictions, unresolved_maneuver_overrides, traffic_signals) =
|
||||
ParseOSMData(scripting_environment, number_of_threads);
|
||||
|
||||
// Transform the node-based graph that OSM is based on into an edge-based graph
|
||||
@@ -229,7 +230,8 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
NodeBasedGraphFactory node_based_graph_factory(config.GetPath(".osrm"),
|
||||
scripting_environment,
|
||||
turn_restrictions,
|
||||
unresolved_maneuver_overrides);
|
||||
unresolved_maneuver_overrides,
|
||||
traffic_signals);
|
||||
|
||||
NameTable name_table;
|
||||
files::readNames(config.GetPath(".osrm.names"), name_table);
|
||||
@@ -264,7 +266,6 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
node_based_graph_factory.GetCompressedEdges().PrintStatistics();
|
||||
|
||||
const auto &barrier_nodes = node_based_graph_factory.GetBarriers();
|
||||
const auto &traffic_signals = node_based_graph_factory.GetTrafficSignals();
|
||||
// stealing the annotation data from the node-based graph
|
||||
edge_based_nodes_container =
|
||||
EdgeBasedNodeDataContainer({}, std::move(node_based_graph_factory.GetAnnotationData()));
|
||||
@@ -360,10 +361,12 @@ int Extractor::run(ScriptingEnvironment &scripting_environment)
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::
|
||||
tuple<LaneDescriptionMap, std::vector<TurnRestriction>, std::vector<UnresolvedManeuverOverride>>
|
||||
Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
||||
const unsigned number_of_threads)
|
||||
std::tuple<LaneDescriptionMap,
|
||||
std::vector<TurnRestriction>,
|
||||
std::vector<UnresolvedManeuverOverride>,
|
||||
TrafficSignals>
|
||||
Extractor::ParseOSMData(ScriptingEnvironment &scripting_environment,
|
||||
const unsigned number_of_threads)
|
||||
{
|
||||
TIMER_START(extracting);
|
||||
|
||||
@@ -628,7 +631,8 @@ std::
|
||||
|
||||
return std::make_tuple(std::move(turn_lane_map),
|
||||
std::move(extraction_containers.turn_restrictions),
|
||||
std::move(extraction_containers.internal_maneuver_overrides));
|
||||
std::move(extraction_containers.internal_maneuver_overrides),
|
||||
std::move(extraction_containers.internal_traffic_signals));
|
||||
}
|
||||
|
||||
void Extractor::FindComponents(unsigned number_of_edge_based_nodes,
|
||||
@@ -699,7 +703,7 @@ EdgeID Extractor::BuildEdgeExpandedGraph(
|
||||
const std::vector<util::Coordinate> &coordinates,
|
||||
const CompressedEdgeContainer &compressed_edge_container,
|
||||
const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const std::unordered_set<NodeID> &traffic_signals,
|
||||
const TrafficSignals &traffic_signals,
|
||||
const RestrictionGraph &restriction_graph,
|
||||
const std::unordered_set<EdgeID> &segregated_edges,
|
||||
const NameTable &name_table,
|
||||
|
||||
@@ -78,9 +78,9 @@ void ExtractorCallbacks::ProcessNode(const osmium::Node &input_node,
|
||||
{
|
||||
external_memory.barrier_nodes.push_back(id);
|
||||
}
|
||||
if (result_node.traffic_lights)
|
||||
if (result_node.traffic_lights != TrafficLightClass::NONE)
|
||||
{
|
||||
external_memory.traffic_signals.push_back(id);
|
||||
external_memory.external_traffic_signals.push_back({id, result_node.traffic_lights});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,10 @@ namespace osrm
|
||||
namespace extractor
|
||||
{
|
||||
|
||||
static constexpr int SECOND_TO_DECISECOND = 10;
|
||||
|
||||
void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
const std::unordered_set<NodeID> &traffic_signals,
|
||||
const TrafficSignals &traffic_signals,
|
||||
ScriptingEnvironment &scripting_environment,
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
std::vector<UnresolvedManeuverOverride> &maneuver_overrides,
|
||||
@@ -207,16 +209,20 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
rev_edge_data2.annotation_data, rev_edge_data1.annotation_data);
|
||||
|
||||
// Add node penalty when compress edge crosses a traffic signal
|
||||
const bool has_node_penalty = traffic_signals.find(node_v) != traffic_signals.end();
|
||||
EdgeDuration node_duration_penalty = MAXIMAL_EDGE_DURATION;
|
||||
EdgeWeight node_weight_penalty = INVALID_EDGE_WEIGHT;
|
||||
if (has_node_penalty)
|
||||
const bool has_forward_signal = traffic_signals.HasSignal(node_u, node_v);
|
||||
const bool has_reverse_signal = traffic_signals.HasSignal(node_w, node_v);
|
||||
|
||||
EdgeDuration forward_node_duration_penalty = MAXIMAL_EDGE_DURATION;
|
||||
EdgeWeight forward_node_weight_penalty = INVALID_EDGE_WEIGHT;
|
||||
EdgeDuration reverse_node_duration_penalty = MAXIMAL_EDGE_DURATION;
|
||||
EdgeWeight reverse_node_weight_penalty = INVALID_EDGE_WEIGHT;
|
||||
if (has_forward_signal || has_reverse_signal)
|
||||
{
|
||||
// we cannot handle this as node penalty, if it depends on turn direction
|
||||
if (fwd_edge_data1.flags.restricted != fwd_edge_data2.flags.restricted)
|
||||
continue;
|
||||
|
||||
// generate an artifical turn for the turn penalty generation
|
||||
// generate an artificial turn for the turn penalty generation
|
||||
std::vector<ExtractionTurnLeg> roads_on_the_right;
|
||||
std::vector<ExtractionTurnLeg> roads_on_the_left;
|
||||
ExtractionTurn extraction_turn(0,
|
||||
@@ -245,8 +251,24 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
roads_on_the_right,
|
||||
roads_on_the_left);
|
||||
scripting_environment.ProcessTurn(extraction_turn);
|
||||
node_duration_penalty = extraction_turn.duration * 10;
|
||||
node_weight_penalty = extraction_turn.weight * weight_multiplier;
|
||||
|
||||
auto update_direction_penalty =
|
||||
[&extraction_turn, weight_multiplier](bool signal,
|
||||
EdgeDuration &duration_penalty,
|
||||
EdgeWeight &weight_penalty) {
|
||||
if (signal)
|
||||
{
|
||||
duration_penalty = extraction_turn.duration * SECOND_TO_DECISECOND;
|
||||
weight_penalty = extraction_turn.weight * weight_multiplier;
|
||||
}
|
||||
};
|
||||
|
||||
update_direction_penalty(has_forward_signal,
|
||||
forward_node_duration_penalty,
|
||||
forward_node_weight_penalty);
|
||||
update_direction_penalty(has_reverse_signal,
|
||||
reverse_node_duration_penalty,
|
||||
reverse_node_weight_penalty);
|
||||
}
|
||||
|
||||
// Get weights before graph is modified
|
||||
@@ -278,27 +300,37 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
BOOST_ASSERT(0 != reverse_weight1);
|
||||
BOOST_ASSERT(0 != reverse_weight2);
|
||||
|
||||
// add weight of e2's to e1
|
||||
graph.GetEdgeData(forward_e1).weight += forward_weight2;
|
||||
graph.GetEdgeData(reverse_e1).weight += reverse_weight2;
|
||||
auto apply_e2_to_e1 = [&graph](EdgeID edge,
|
||||
EdgeWeight weight,
|
||||
EdgeDuration duration,
|
||||
EdgeDistance distance,
|
||||
EdgeDuration &duration_penalty,
|
||||
EdgeWeight &weight_penalty) {
|
||||
auto &edge_data = graph.GetEdgeData(edge);
|
||||
edge_data.weight += weight;
|
||||
edge_data.duration += duration;
|
||||
edge_data.distance += distance;
|
||||
if (weight_penalty != INVALID_EDGE_WEIGHT &&
|
||||
duration_penalty != MAXIMAL_EDGE_DURATION)
|
||||
{
|
||||
edge_data.weight += weight_penalty;
|
||||
edge_data.duration += duration_penalty;
|
||||
// Note: no penalties for distances
|
||||
}
|
||||
};
|
||||
|
||||
// add duration of e2's to e1
|
||||
graph.GetEdgeData(forward_e1).duration += forward_duration2;
|
||||
graph.GetEdgeData(reverse_e1).duration += reverse_duration2;
|
||||
|
||||
// add distance of e2's to e1
|
||||
graph.GetEdgeData(forward_e1).distance += forward_distance2;
|
||||
graph.GetEdgeData(reverse_e1).distance += reverse_distance2;
|
||||
|
||||
if (node_weight_penalty != INVALID_EDGE_WEIGHT &&
|
||||
node_duration_penalty != MAXIMAL_EDGE_DURATION)
|
||||
{
|
||||
graph.GetEdgeData(forward_e1).weight += node_weight_penalty;
|
||||
graph.GetEdgeData(reverse_e1).weight += node_weight_penalty;
|
||||
graph.GetEdgeData(forward_e1).duration += node_duration_penalty;
|
||||
graph.GetEdgeData(reverse_e1).duration += node_duration_penalty;
|
||||
// Note: no penalties for distances
|
||||
}
|
||||
apply_e2_to_e1(forward_e1,
|
||||
forward_weight2,
|
||||
forward_duration2,
|
||||
forward_distance2,
|
||||
forward_node_weight_penalty,
|
||||
forward_node_duration_penalty);
|
||||
apply_e2_to_e1(reverse_e1,
|
||||
reverse_weight2,
|
||||
reverse_duration2,
|
||||
reverse_distance2,
|
||||
reverse_node_weight_penalty,
|
||||
reverse_node_duration_penalty);
|
||||
|
||||
// extend e1's to targets of e2's
|
||||
graph.SetTarget(forward_e1, node_w);
|
||||
@@ -311,6 +343,25 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
// update any involved turn relations
|
||||
turn_path_compressor.Compress(node_u, node_v, node_w);
|
||||
|
||||
// Forward and reversed compressed edge lengths need to match.
|
||||
// Set a dummy empty penalty weight if opposite value exists.
|
||||
auto set_dummy_penalty = [](EdgeWeight &weight_penalty,
|
||||
EdgeDuration &duration_penalty,
|
||||
EdgeWeight &other_weight_penalty) {
|
||||
if (weight_penalty == INVALID_EDGE_WEIGHT &&
|
||||
other_weight_penalty != INVALID_EDGE_WEIGHT)
|
||||
{
|
||||
weight_penalty = 0;
|
||||
duration_penalty = 0;
|
||||
}
|
||||
};
|
||||
set_dummy_penalty(forward_node_weight_penalty,
|
||||
forward_node_duration_penalty,
|
||||
reverse_node_weight_penalty);
|
||||
set_dummy_penalty(reverse_node_weight_penalty,
|
||||
reverse_node_duration_penalty,
|
||||
forward_node_weight_penalty);
|
||||
|
||||
// store compressed geometry in container
|
||||
geometry_compressor.CompressEdge(forward_e1,
|
||||
forward_e2,
|
||||
@@ -320,8 +371,8 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
forward_weight2,
|
||||
forward_duration1,
|
||||
forward_duration2,
|
||||
node_weight_penalty,
|
||||
node_duration_penalty);
|
||||
forward_node_weight_penalty,
|
||||
forward_node_duration_penalty);
|
||||
geometry_compressor.CompressEdge(reverse_e1,
|
||||
reverse_e2,
|
||||
node_v,
|
||||
@@ -330,8 +381,8 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes,
|
||||
reverse_weight2,
|
||||
reverse_duration1,
|
||||
reverse_duration2,
|
||||
node_weight_penalty,
|
||||
node_duration_penalty);
|
||||
reverse_node_weight_penalty,
|
||||
reverse_node_duration_penalty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,10 +19,11 @@ NodeBasedGraphFactory::NodeBasedGraphFactory(
|
||||
const boost::filesystem::path &input_file,
|
||||
ScriptingEnvironment &scripting_environment,
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
std::vector<UnresolvedManeuverOverride> &maneuver_overrides)
|
||||
std::vector<UnresolvedManeuverOverride> &maneuver_overrides,
|
||||
const TrafficSignals &traffic_signals)
|
||||
{
|
||||
LoadDataFromFile(input_file);
|
||||
Compress(scripting_environment, turn_restrictions, maneuver_overrides);
|
||||
Compress(scripting_environment, turn_restrictions, maneuver_overrides, traffic_signals);
|
||||
CompressGeometry();
|
||||
CompressAnnotationData();
|
||||
}
|
||||
@@ -31,16 +32,10 @@ NodeBasedGraphFactory::NodeBasedGraphFactory(
|
||||
void NodeBasedGraphFactory::LoadDataFromFile(const boost::filesystem::path &input_file)
|
||||
{
|
||||
auto barriers_iter = inserter(barriers, end(barriers));
|
||||
auto traffic_signals_iter = inserter(traffic_signals, end(traffic_signals));
|
||||
std::vector<NodeBasedEdge> edge_list;
|
||||
|
||||
files::readRawNBGraph(input_file,
|
||||
barriers_iter,
|
||||
traffic_signals_iter,
|
||||
coordinates,
|
||||
osm_node_ids,
|
||||
edge_list,
|
||||
annotation_data);
|
||||
files::readRawNBGraph(
|
||||
input_file, barriers_iter, coordinates, osm_node_ids, edge_list, annotation_data);
|
||||
|
||||
const auto number_of_node_based_nodes = coordinates.size();
|
||||
if (edge_list.empty())
|
||||
@@ -80,7 +75,8 @@ void NodeBasedGraphFactory::LoadDataFromFile(const boost::filesystem::path &inpu
|
||||
|
||||
void NodeBasedGraphFactory::Compress(ScriptingEnvironment &scripting_environment,
|
||||
std::vector<TurnRestriction> &turn_restrictions,
|
||||
std::vector<UnresolvedManeuverOverride> &maneuver_overrides)
|
||||
std::vector<UnresolvedManeuverOverride> &maneuver_overrides,
|
||||
const TrafficSignals &traffic_signals)
|
||||
{
|
||||
GraphCompressor graph_compressor;
|
||||
graph_compressor.Compress(barriers,
|
||||
|
||||
@@ -285,11 +285,41 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context)
|
||||
return get_location_tag(context, node.location(), key);
|
||||
});
|
||||
|
||||
context.state.new_usertype<ExtractionNode>("ResultNode",
|
||||
"traffic_lights",
|
||||
&ExtractionNode::traffic_lights,
|
||||
"barrier",
|
||||
&ExtractionNode::barrier);
|
||||
context.state.new_enum("traffic_lights",
|
||||
"none",
|
||||
extractor::TrafficLightClass::NONE,
|
||||
"direction_all",
|
||||
extractor::TrafficLightClass::DIRECTION_ALL,
|
||||
"direction_forward",
|
||||
extractor::TrafficLightClass::DIRECTION_FORWARD,
|
||||
"direction_reverse",
|
||||
extractor::TrafficLightClass::DIRECTION_REVERSE);
|
||||
|
||||
context.state.new_usertype<ExtractionNode>(
|
||||
"ResultNode",
|
||||
"traffic_lights",
|
||||
sol::property([](const ExtractionNode &node) { return node.traffic_lights; },
|
||||
[](ExtractionNode &node, const sol::object &obj) {
|
||||
if (obj.is<bool>())
|
||||
{
|
||||
// The old approach of assigning a boolean traffic light
|
||||
// state to the node is converted to the class enum
|
||||
// TODO: Make a breaking API change and remove this option.
|
||||
bool val = obj.as<bool>();
|
||||
node.traffic_lights = (val) ? TrafficLightClass::DIRECTION_ALL
|
||||
: TrafficLightClass::NONE;
|
||||
return;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(obj.is<TrafficLightClass::Direction>());
|
||||
{
|
||||
TrafficLightClass::Direction val =
|
||||
obj.as<TrafficLightClass::Direction>();
|
||||
node.traffic_lights = val;
|
||||
}
|
||||
}),
|
||||
"barrier",
|
||||
&ExtractionNode::barrier);
|
||||
|
||||
context.state.new_usertype<RoadClassification>(
|
||||
"RoadClassification",
|
||||
|
||||
@@ -44,7 +44,7 @@ std::size_t loadGraph(const std::string &path,
|
||||
auto nop = boost::make_function_output_iterator([](auto) {});
|
||||
|
||||
extractor::files::readRawNBGraph(
|
||||
path, nop, nop, coordinate_list, osm_node_ids, edge_list, annotation_data);
|
||||
path, nop, coordinate_list, osm_node_ids, edge_list, annotation_data);
|
||||
|
||||
// Building a node-based graph
|
||||
for (const auto &input_edge : edge_list)
|
||||
|
||||
Reference in New Issue
Block a user