diff --git a/features/car/stop_sign_penalties.feature b/features/car/stop_sign_penalties.feature new file mode 100644 index 000000000..1cccc30d8 --- /dev/null +++ b/features/car/stop_sign_penalties.feature @@ -0,0 +1,39 @@ +@routing @car @stop_sign +Feature: Car - Handle stop signs + + Background: + Given the profile "car" + + Scenario: Car - Encounters a stop sign + Given the node map + """ + a-1-b-2-c + + d-3-e-4-f + + g-h-i k-l-m + | | + j n + + """ + + And the ways + | nodes | highway | + | abc | primary | + | def | primary | + | ghi | primary | + | klm | primary | + | hj | primary | + | ln | primary | + + And the nodes + | node | highway | + | e | stop | + | l | stop | + + When I route I should get + | from | to | time | # | + | 1 | 2 | 11.1s | no turn with no stop sign | + | 3 | 4 | 13.1s | no turn with stop sign | + | g | j | 18.7s | turn with no stop sign | + | k | n | 20.7s | turn with stop sign | \ No newline at end of file diff --git a/features/support/hooks.js b/features/support/hooks.js index 01c2e6e89..4a0355545 100644 --- a/features/support/hooks.js +++ b/features/support/hooks.js @@ -51,7 +51,7 @@ module.exports = function () { .defer(rimraf, this.scenarioLogFile) .awaitAll(callback); // uncomment to get path to logfile - // console.log(' Writing logging output to ' + this.scenarioLogFile); + console.log(' Writing logging output to ' + this.scenarioLogFile); }); this.After((scenario, callback) => { diff --git a/include/extractor/edge_based_graph_factory.hpp b/include/extractor/edge_based_graph_factory.hpp index 9dc0cadf2..0ad5b16be 100644 --- a/include/extractor/edge_based_graph_factory.hpp +++ b/include/extractor/edge_based_graph_factory.hpp @@ -70,6 +70,7 @@ class EdgeBasedGraphFactory const CompressedEdgeContainer &compressed_edge_container, const std::unordered_set &barrier_nodes, const TrafficSignals &traffic_signals, + const StopSigns &stop_signs, const std::vector &coordinates, const NameTable &name_table, const std::unordered_set &segregated_edges, @@ -136,6 +137,8 @@ class EdgeBasedGraphFactory const std::unordered_set &m_barrier_nodes; const TrafficSignals &m_traffic_signals; + const StopSigns &m_stop_signs; + const CompressedEdgeContainer &m_compressed_edge_container; const NameTable &name_table; diff --git a/include/extractor/extraction_containers.hpp b/include/extractor/extraction_containers.hpp index 6f643aed0..03f24bec6 100644 --- a/include/extractor/extraction_containers.hpp +++ b/include/extractor/extraction_containers.hpp @@ -30,17 +30,24 @@ class ExtractionContainers using ReferencedWays = std::unordered_map; using ReferencedTrafficSignals = std::pair, std::unordered_multimap>; + using ReferencedStopSigns = + std::pair, std::unordered_multimap>; + // The relationship between way and nodes is lost during node preparation. // We identify the ways and nodes relevant to restrictions/overrides/signals prior to // node processing so that they can be referenced in the preparation phase. ReferencedWays IdentifyRestrictionWays(); ReferencedWays IdentifyManeuverOverrideWays(); ReferencedTrafficSignals IdentifyTrafficSignals(); + ReferencedStopSigns IdentifyStopSigns(); + void PrepareNodes(); void PrepareManeuverOverrides(const ReferencedWays &maneuver_override_ways); void PrepareRestrictions(const ReferencedWays &restriction_ways); void PrepareTrafficSignals(const ReferencedTrafficSignals &referenced_traffic_signals); + void PrepareStopSigns(const ReferencedStopSigns &referenced_stop_signs); + void PrepareEdges(ScriptingEnvironment &scripting_environment); void WriteCharData(const std::string &file_name); @@ -55,6 +62,8 @@ class ExtractionContainers using WayIDVector = std::vector; using WayNodeIDOffsets = std::vector; using InputTrafficSignal = std::pair; + using InputStopSign = std::pair; + using InputGiveWay = std::pair; std::vector barrier_nodes; NodeIDVector used_node_id_list; @@ -72,6 +81,13 @@ class ExtractionContainers std::vector external_traffic_signals; TrafficSignals internal_traffic_signals; + + std::vector external_stop_signs; + StopSigns internal_stop_signs; + + std::vector external_give_ways; + GiveWaySigns internal_give_ways; + std::vector used_edges; // List of restrictions (conditional and unconditional) before we transform them into the diff --git a/include/extractor/extraction_node.hpp b/include/extractor/extraction_node.hpp index 9a146d4d3..8872605db 100644 --- a/include/extractor/extraction_node.hpp +++ b/include/extractor/extraction_node.hpp @@ -2,22 +2,30 @@ #define EXTRACTION_NODE_HPP #include "traffic_lights.hpp" +#include namespace osrm { namespace extractor { + struct ExtractionNode { ExtractionNode() : traffic_lights(TrafficLightClass::NONE), barrier(false) {} void clear() { traffic_lights = TrafficLightClass::NONE; + stop_sign = StopSign::Direction::NONE; + give_way = GiveWay::Direction::NONE; barrier = false; } TrafficLightClass::Direction traffic_lights; bool barrier; + + + StopSign::Direction stop_sign; + GiveWay::Direction give_way; }; } // namespace extractor } // namespace osrm diff --git a/include/extractor/extraction_turn.hpp b/include/extractor/extraction_turn.hpp index 9e32712d3..9dfe163f8 100644 --- a/include/extractor/extraction_turn.hpp +++ b/include/extractor/extraction_turn.hpp @@ -51,6 +51,7 @@ struct ExtractionTurn int number_of_roads, bool is_u_turn, bool has_traffic_light, + bool has_stop_sign, bool is_left_hand_driving, bool source_restricted, TravelMode source_mode, @@ -75,7 +76,7 @@ struct ExtractionTurn const std::vector &roads_on_the_right, const std::vector &roads_on_the_left) : angle(180. - angle), number_of_roads(number_of_roads), is_u_turn(is_u_turn), - has_traffic_light(has_traffic_light), is_left_hand_driving(is_left_hand_driving), + has_traffic_light(has_traffic_light), has_stop_sign(has_stop_sign), is_left_hand_driving(is_left_hand_driving), source_restricted(source_restricted), source_mode(source_mode), source_is_motorway(source_is_motorway), source_is_link(source_is_link), @@ -100,6 +101,7 @@ struct ExtractionTurn const int number_of_roads; const bool is_u_turn; const bool has_traffic_light; + const bool has_stop_sign; const bool is_left_hand_driving; // source info diff --git a/include/extractor/extractor.hpp b/include/extractor/extractor.hpp index fb32af8a0..a2fc2d05c 100644 --- a/include/extractor/extractor.hpp +++ b/include/extractor/extractor.hpp @@ -67,6 +67,7 @@ class Extractor std::vector turn_restrictions; std::vector unresolved_maneuver_overrides; TrafficSignals traffic_signals; + StopSigns stop_signs; std::unordered_set barriers; std::vector osm_coordinates; extractor::PackedOSMIDs osm_node_ids; @@ -87,6 +88,7 @@ class Extractor const CompressedEdgeContainer &compressed_edge_container, const std::unordered_set &barrier_nodes, const TrafficSignals &traffic_signals, + const StopSigns &stop_signs, const RestrictionGraph &restriction_graph, const std::unordered_set &segregated_edges, const NameTable &name_table, diff --git a/include/extractor/graph_compressor.hpp b/include/extractor/graph_compressor.hpp index 1b6d8159a..3196cabfd 100644 --- a/include/extractor/graph_compressor.hpp +++ b/include/extractor/graph_compressor.hpp @@ -27,6 +27,7 @@ class GraphCompressor public: void Compress(const std::unordered_set &barrier_nodes, const TrafficSignals &traffic_signals, + const StopSigns &stop_signs, ScriptingEnvironment &scripting_environment, std::vector &turn_restrictions, std::vector &maneuver_overrides, diff --git a/include/extractor/node_based_graph_factory.hpp b/include/extractor/node_based_graph_factory.hpp index 7c0a70f2e..aca2aaa11 100644 --- a/include/extractor/node_based_graph_factory.hpp +++ b/include/extractor/node_based_graph_factory.hpp @@ -42,6 +42,8 @@ class NodeBasedGraphFactory std::vector &turn_restrictions, std::vector &maneuver_overrides, const TrafficSignals &traffic_signals, + const StopSigns &stop_signs, + std::unordered_set &&barriers, std::vector &&coordinates, extractor::PackedOSMIDs &&osm_node_ids, @@ -73,7 +75,8 @@ class NodeBasedGraphFactory void Compress(ScriptingEnvironment &scripting_environment, std::vector &turn_restrictions, std::vector &maneuver_overrides, - const TrafficSignals &traffic_signals); + const TrafficSignals &traffic_signals, + const StopSigns &stop_signs); // Most ways are bidirectional, making the geometry in forward and backward direction the same, // except for reversal. We make use of this fact by keeping only one representation of the diff --git a/include/extractor/stop_sign_class.hpp b/include/extractor/stop_sign_class.hpp new file mode 100644 index 000000000..e69de29bb diff --git a/include/extractor/traffic_lights.hpp b/include/extractor/traffic_lights.hpp index 0c8aa6d00..cf78509e9 100644 --- a/include/extractor/traffic_lights.hpp +++ b/include/extractor/traffic_lights.hpp @@ -1,6 +1,7 @@ #ifndef OSRM_EXTRACTOR_TRAFFIC_LIGHTS_DATA_HPP_ #define OSRM_EXTRACTOR_TRAFFIC_LIGHTS_DATA_HPP_ +#include namespace osrm { namespace extractor @@ -19,6 +20,36 @@ enum Direction }; } // namespace TrafficLightClass +// Stop Signs tagged on nodes can be present or not. In addition Stop Signs have +// an optional way direction they apply to. If the direction is unknown from the +// data we have to compute by checking the distance to the next intersection. +// +// Impl. detail: namespace + enum instead of enum class to make Luabind happy +namespace StopSign +{ +enum Direction : std::uint8_t +{ + NONE = 0, + DIRECTION_ALL = 1, + DIRECTION_FORWARD = 2, + DIRECTION_REVERSE = 3 +}; +} + +// Give Way is the complement to priority roads. Tagging is the same as Stop Signs. +// See explanation above. +namespace GiveWay +{ +enum Direction : std::uint8_t +{ + NONE = 0, + DIRECTION_ALL = 1, + DIRECTION_FORWARD = 2, + DIRECTION_REVERSE = 3 +}; +} + + } // namespace extractor } // namespace osrm diff --git a/include/extractor/traffic_signals.hpp b/include/extractor/traffic_signals.hpp index 36913092c..5e303ccb9 100644 --- a/include/extractor/traffic_signals.hpp +++ b/include/extractor/traffic_signals.hpp @@ -11,7 +11,8 @@ namespace osrm namespace extractor { -struct TrafficSignals +// TODO: better naming +struct RoadObjects { std::unordered_set bidirectional_nodes; std::unordered_set, boost::hash>> @@ -22,6 +23,14 @@ struct TrafficSignals return bidirectional_nodes.count(to) > 0 || unidirectional_segments.count({from, to}) > 0; } }; + +struct TrafficSignals final : public RoadObjects {}; + +// TODO: better naming ? +struct StopSigns final : public RoadObjects {}; +struct GiveWaySigns final : public RoadObjects {}; + + } // namespace extractor } // namespace osrm diff --git a/profiles/car.lua b/profiles/car.lua index 770805962..37f131807 100644 --- a/profiles/car.lua +++ b/profiles/car.lua @@ -7,6 +7,8 @@ Sequence = require('lib/sequence') Handlers = require("lib/way_handlers") Relations = require("lib/relations") TrafficSignal = require("lib/traffic_signal") +StopSign = require("lib/stop_sign") +GiveWay = require("lib/give_way") find_access_tag = require("lib/access").find_access_tag limit = require("lib/maxspeed").limit Utils = require("lib/utils") @@ -362,6 +364,12 @@ function process_node(profile, node, result, relations) -- check if node is a traffic light result.traffic_lights = TrafficSignal.get_value(node) + + -- check if node is stop sign + result.stop_sign = StopSign.get_value(node) + + -- check if node is a give way sign + result.give_way = GiveWay.get_value(node) end function process_way(profile, way, result, relations) @@ -472,6 +480,9 @@ function process_turn(profile, turn) if turn.has_traffic_light then turn.duration = profile.properties.traffic_light_penalty + elseif turn.has_stop_sign then + -- TODO: use another constant + turn.duration = profile.properties.traffic_light_penalty end if turn.number_of_roads > 2 or turn.source_mode ~= turn.target_mode or turn.is_u_turn then diff --git a/profiles/lib/give_way.lua b/profiles/lib/give_way.lua new file mode 100644 index 000000000..d8bb9863d --- /dev/null +++ b/profiles/lib/give_way.lua @@ -0,0 +1,23 @@ +local GiveWay = {} + +function GiveWay.get_value(node) + local tag = node:get_value_by_key("highway") + if "give_way" == tag then + local direction = node:get_value_by_key("direction") + if direction then + if "forward" == direction then + return give_way.direction_forward + end + if "backward" == direction then + return give_way.direction_reverse + end + end + -- return give_way.direction_all + return true + end + -- return give_way.none + return false +end + +return GiveWay + diff --git a/profiles/lib/stop_sign.lua b/profiles/lib/stop_sign.lua new file mode 100644 index 000000000..e805c5a39 --- /dev/null +++ b/profiles/lib/stop_sign.lua @@ -0,0 +1,21 @@ +local StopSign = {} + +function StopSign.get_value(node) + local tag = node:get_value_by_key("highway") + if "stop" == tag then + local direction = node:get_value_by_key("direction") + if direction then + if "forward" == direction then + return stop_sign.direction_forward + end + if "backward" == direction then + return stop_sign.direction_reverse + end + end + return stop_sign.direction_all + end + return stop_sign.none +end + +return StopSign + diff --git a/src/extractor/edge_based_graph_factory.cpp b/src/extractor/edge_based_graph_factory.cpp index a0a8561b7..862466a11 100644 --- a/src/extractor/edge_based_graph_factory.cpp +++ b/src/extractor/edge_based_graph_factory.cpp @@ -60,6 +60,7 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory( const CompressedEdgeContainer &compressed_edge_container, const std::unordered_set &barrier_nodes, const TrafficSignals &traffic_signals, + const StopSigns &stop_signs, const std::vector &coordinates, const NameTable &name_table, const std::unordered_set &segregated_edges, @@ -67,7 +68,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_signals(traffic_signals), m_compressed_edge_container(compressed_edge_container), + m_traffic_signals(traffic_signals), m_stop_signs(stop_signs), m_compressed_edge_container(compressed_edge_container), name_table(name_table), segregated_edges(segregated_edges), lane_description_map(lane_description_map) { @@ -643,6 +644,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( // 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_stop_sign = m_stop_signs.HasSignal(from_node, intersection_node); + std::cerr << "IS STOP SIGN " << is_stop_sign << std::endl; const auto is_uturn = guidance::getTurnDirection(turn_angle) == guidance::DirectionModifier::UTurn; @@ -652,6 +655,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( road_legs_on_the_right.size() + road_legs_on_the_left.size() + 2 - is_uturn, is_uturn, is_traffic_light, + is_stop_sign, m_edge_based_node_container.GetAnnotation(edge_data1.annotation_data) .is_left_hand_driving, // source info diff --git a/src/extractor/extraction_containers.cpp b/src/extractor/extraction_containers.cpp index 553968d6f..1738ecfb9 100644 --- a/src/extractor/extraction_containers.cpp +++ b/src/extractor/extraction_containers.cpp @@ -413,11 +413,14 @@ void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environme const auto restriction_ways = IdentifyRestrictionWays(); const auto maneuver_override_ways = IdentifyManeuverOverrideWays(); const auto traffic_signals = IdentifyTrafficSignals(); + const auto stop_signs = IdentifyStopSigns(); PrepareNodes(); PrepareEdges(scripting_environment); PrepareTrafficSignals(traffic_signals); + PrepareStopSigns(stop_signs); + PrepareManeuverOverrides(maneuver_override_ways); PrepareRestrictions(restriction_ways); WriteCharData(name_file_name); @@ -979,6 +982,54 @@ void ExtractionContainers::PrepareTrafficSignals( log << "ok, after " << TIMER_SEC(prepare_traffic_signals) << "s"; } +// TODO: copy-paste +void ExtractionContainers::PrepareStopSigns(const ReferencedStopSigns &referenced_stop_signs) { + const auto &bidirectional_signal_nodes = referenced_stop_signs.first; + const auto &unidirectional_signal_segments = referenced_stop_signs.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 bidirectional; + std::unordered_set, boost::hash>> + 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_stop_signs.bidirectional_nodes = std::move(bidirectional); + internal_stop_signs.unidirectional_segments = std::move(unidirectional); + + TIMER_STOP(prepare_traffic_signals); + log << "ok, after " << TIMER_SEC(prepare_traffic_signals) << "s"; +} + +// void ExtractionContainers::PrepareGiveWays(const ReferencedGiveWays &referenced_give_ways) { + +// } + + void ExtractionContainers::PrepareManeuverOverrides(const ReferencedWays &maneuver_override_ways) { auto const osm_node_to_internal_nbn = [&](auto const osm_node) { @@ -1159,6 +1210,95 @@ ExtractionContainers::ReferencedWays ExtractionContainers::IdentifyRestrictionWa return restriction_ways; } +// TODO: copy-paste +ExtractionContainers::ReferencedStopSigns ExtractionContainers::IdentifyStopSigns() +{ + util::UnbufferedLog log; + log << "Collecting traffic signal information on " << external_stop_signs.size() + << " signals..."; + TIMER_START(identify_traffic_signals); + + // Temporary store for nodes containing a unidirectional signal. + std::unordered_map 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 signal_segments; + + std::unordered_set bidirectional_signals; + + const auto mark_signals = [&](auto const &traffic_signal) { + if (traffic_signal.second == StopSign::DIRECTION_FORWARD || + traffic_signal.second == StopSign::DIRECTION_REVERSE) + { + unidirectional_signals.insert({traffic_signal.first, traffic_signal.second}); + } + else + { + BOOST_ASSERT(traffic_signal.second == StopSign::DIRECTION_ALL); + bidirectional_signals.insert(traffic_signal.first); + } + }; + std::for_each(external_stop_signs.begin(), external_stop_signs.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 == StopSign::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 == StopSign::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)}; +} + + ExtractionContainers::ReferencedTrafficSignals ExtractionContainers::IdentifyTrafficSignals() { util::UnbufferedLog log; diff --git a/src/extractor/extractor.cpp b/src/extractor/extractor.cpp index 687b35b53..14764dd2f 100644 --- a/src/extractor/extractor.cpp +++ b/src/extractor/extractor.cpp @@ -226,6 +226,8 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) parsed_osm_data.turn_restrictions, parsed_osm_data.unresolved_maneuver_overrides, parsed_osm_data.traffic_signals, + parsed_osm_data.stop_signs, + std::move(parsed_osm_data.barriers), std::move(parsed_osm_data.osm_coordinates), std::move(parsed_osm_data.osm_node_ids), @@ -283,6 +285,7 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) node_based_graph_factory.GetCompressedEdges(), barrier_nodes, parsed_osm_data.traffic_signals, + parsed_osm_data.stop_signs, restriction_graph, segregated_edges, name_table, @@ -649,6 +652,7 @@ Extractor::ParsedOSMData Extractor::ParseOSMData(ScriptingEnvironment &scripting std::move(extraction_containers.turn_restrictions), std::move(extraction_containers.internal_maneuver_overrides), std::move(extraction_containers.internal_traffic_signals), + std::move(extraction_containers.internal_stop_signs), std::move(extraction_containers.used_barrier_nodes), std::move(osm_coordinates), std::move(osm_node_ids), @@ -725,6 +729,7 @@ EdgeID Extractor::BuildEdgeExpandedGraph( const CompressedEdgeContainer &compressed_edge_container, const std::unordered_set &barrier_nodes, const TrafficSignals &traffic_signals, + const StopSigns &stop_signs, const RestrictionGraph &restriction_graph, const std::unordered_set &segregated_edges, const NameTable &name_table, @@ -746,6 +751,7 @@ EdgeID Extractor::BuildEdgeExpandedGraph( compressed_edge_container, barrier_nodes, traffic_signals, + stop_signs, coordinates, name_table, segregated_edges, diff --git a/src/extractor/extractor_callbacks.cpp b/src/extractor/extractor_callbacks.cpp index 7cecd763e..c6a0269b6 100644 --- a/src/extractor/extractor_callbacks.cpp +++ b/src/extractor/extractor_callbacks.cpp @@ -82,6 +82,15 @@ void ExtractorCallbacks::ProcessNode(const osmium::Node &input_node, { external_memory.external_traffic_signals.push_back({id, result_node.traffic_lights}); } + // if (result_node.give_way != GiveWay::Direction::NONE) + // { + // external_memory.external_give_ways.push_back({id, result_node.give_way}); + // } + if (result_node.stop_sign != StopSign::Direction::NONE) + { + std::cerr << "FOUND STOP SIGN\n"; + external_memory.external_stop_signs.push_back({id, result_node.stop_sign}); + } } void ExtractorCallbacks::ProcessRestriction(const InputTurnRestriction &restriction) diff --git a/src/extractor/graph_compressor.cpp b/src/extractor/graph_compressor.cpp index 517d3e8d7..e1ebbe317 100644 --- a/src/extractor/graph_compressor.cpp +++ b/src/extractor/graph_compressor.cpp @@ -23,6 +23,7 @@ static constexpr int SECOND_TO_DECISECOND = 10; void GraphCompressor::Compress(const std::unordered_set &barrier_nodes, const TrafficSignals &traffic_signals, + const StopSigns &stop_signs, ScriptingEnvironment &scripting_environment, std::vector &turn_restrictions, std::vector &maneuver_overrides, @@ -212,11 +213,15 @@ void GraphCompressor::Compress(const std::unordered_set &barrier_nodes, const bool has_forward_signal = traffic_signals.HasSignal(node_u, node_v); const bool has_reverse_signal = traffic_signals.HasSignal(node_w, node_v); + const bool has_forward_stop_sign = stop_signs.HasSignal(node_u, node_v); + const bool has_reverse_stop_sign = stop_signs.HasSignal(node_w, node_v); + + // TODO: can we have a case when we have both traffic signal and stop sign? how should we handle it? 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) + if (has_forward_signal || has_reverse_signal || has_forward_stop_sign || has_reverse_stop_sign) { // we cannot handle this as node penalty, if it depends on turn direction if (fwd_edge_data1.flags.restricted != fwd_edge_data2.flags.restricted) @@ -228,7 +233,8 @@ void GraphCompressor::Compress(const std::unordered_set &barrier_nodes, ExtractionTurn extraction_turn(0, 2, false, - true, + has_forward_signal || has_reverse_signal, + has_forward_stop_sign || has_reverse_stop_sign, false, false, TRAVEL_MODE_DRIVING, @@ -258,8 +264,11 @@ void GraphCompressor::Compress(const std::unordered_set &barrier_nodes, EdgeWeight &weight_penalty) { if (signal) { + std::cerr << "DUR = " << extraction_turn.duration << " WEIGHT = " << extraction_turn.weight << std::endl; duration_penalty = extraction_turn.duration * SECOND_TO_DECISECOND; weight_penalty = extraction_turn.weight * weight_multiplier; + + std::cerr << "DUR = " << duration_penalty << " WEIGHT = " << weight_penalty << std::endl; } }; @@ -269,6 +278,12 @@ void GraphCompressor::Compress(const std::unordered_set &barrier_nodes, update_direction_penalty(has_reverse_signal, reverse_node_duration_penalty, reverse_node_weight_penalty); + update_direction_penalty(has_forward_stop_sign, + forward_node_duration_penalty, + forward_node_weight_penalty); + update_direction_penalty(has_reverse_stop_sign, + reverse_node_duration_penalty, + reverse_node_weight_penalty); } // Get weights before graph is modified diff --git a/src/extractor/node_based_graph_factory.cpp b/src/extractor/node_based_graph_factory.cpp index 5edc44715..42a4dfeba 100644 --- a/src/extractor/node_based_graph_factory.cpp +++ b/src/extractor/node_based_graph_factory.cpp @@ -1,6 +1,7 @@ #include "extractor/node_based_graph_factory.hpp" #include "extractor/files.hpp" #include "extractor/graph_compressor.hpp" +#include "extractor/traffic_signals.hpp" #include "storage/io.hpp" #include "util/log.hpp" @@ -20,6 +21,7 @@ NodeBasedGraphFactory::NodeBasedGraphFactory( std::vector &turn_restrictions, std::vector &maneuver_overrides, const TrafficSignals &traffic_signals, + const StopSigns &stop_signs, std::unordered_set &&barriers, std::vector &&coordinates, extractor::PackedOSMIDs &&osm_node_ids, @@ -29,7 +31,7 @@ NodeBasedGraphFactory::NodeBasedGraphFactory( coordinates(std::move(coordinates)), osm_node_ids(std::move(osm_node_ids)) { BuildCompressedOutputGraph(edge_list); - Compress(scripting_environment, turn_restrictions, maneuver_overrides, traffic_signals); + Compress(scripting_environment, turn_restrictions, maneuver_overrides, traffic_signals, stop_signs); CompressGeometry(); CompressAnnotationData(); } @@ -74,11 +76,13 @@ void NodeBasedGraphFactory::BuildCompressedOutputGraph(const std::vector &turn_restrictions, std::vector &maneuver_overrides, - const TrafficSignals &traffic_signals) + const TrafficSignals &traffic_signals, + const StopSigns &stop_signs) { GraphCompressor graph_compressor; graph_compressor.Compress(barriers, traffic_signals, + stop_signs, scripting_environment, turn_restrictions, maneuver_overrides, diff --git a/src/extractor/scripting_environment_lua.cpp b/src/extractor/scripting_environment_lua.cpp index dca80fc44..d598ca1d5 100644 --- a/src/extractor/scripting_environment_lua.cpp +++ b/src/extractor/scripting_environment_lua.cpp @@ -294,6 +294,24 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context) extractor::TrafficLightClass::DIRECTION_FORWARD, "direction_reverse", extractor::TrafficLightClass::DIRECTION_REVERSE); + context.state.new_enum("stop_sign", + "none", + extractor::StopSign::NONE, + "direction_all", + extractor::StopSign::DIRECTION_ALL, + "direction_forward", + extractor::StopSign::DIRECTION_FORWARD, + "direction_reverse", + extractor::StopSign::DIRECTION_REVERSE); + context.state.new_enum("give_way", + "none", + extractor::GiveWay::NONE, + "direction_all", + extractor::GiveWay::DIRECTION_ALL, + "direction_forward", + extractor::GiveWay::DIRECTION_FORWARD, + "direction_reverse", + extractor::GiveWay::DIRECTION_REVERSE); context.state.new_usertype( "ResultNode", @@ -318,6 +336,18 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context) node.traffic_lights = val; } }), + "stop_sign", + sol::property([](const ExtractionNode &node) { return node.stop_sign; }, + [](ExtractionNode &node, const sol::object &obj) { + BOOST_ASSERT(obj.is()); + node.stop_sign = obj.as(); + }), + "give_way", + sol::property([](const ExtractionNode &node) { return node.give_way; }, + [](ExtractionNode &node, const sol::object &obj) { + BOOST_ASSERT(obj.is()); + node.give_way = obj.as(); + }), "barrier", &ExtractionNode::barrier); @@ -640,6 +670,8 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context) }), "has_traffic_light", &ExtractionTurn::has_traffic_light, + "has_stop_sign", + &ExtractionTurn::has_stop_sign, "weight", &ExtractionTurn::weight, "duration", @@ -765,7 +797,6 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context) &ExtractionTurn::has_traffic_light, "is_left_hand_driving", &ExtractionTurn::is_left_hand_driving, - "source_restricted", &ExtractionTurn::source_restricted, "source_mode", @@ -1125,15 +1156,23 @@ void Sol2ScriptingEnvironment::ProcessTurn(ExtractionTurn &turn) case 2: if (context.has_turn_penalty_function) { + std::cerr << "GOT TURN " << turn.has_stop_sign << " " << turn.has_traffic_light << std::endl; + context.turn_function(context.profile_table, std::ref(turn)); // Turn weight falls back to the duration value in deciseconds // or uses the extracted unit-less weight value - if (context.properties.fallback_to_duration) + if (context.properties.fallback_to_duration) { + std::cerr << "FALLBACK\n"; turn.weight = turn.duration; - else - // cap turn weight to max turn weight, which depend on weight precision + } + + else { + // cap turn weight to max turn weight, which depend on weight precision turn.weight = std::min(turn.weight, context.properties.GetMaxTurnWeight()); + std::cerr << "NO FALLBACK " << turn.weight << std::endl; + } + } break; @@ -1171,7 +1210,7 @@ void Sol2ScriptingEnvironment::ProcessTurn(ExtractionTurn &turn) } // Add traffic light penalty, back-compatibility of api_version=0 - if (turn.has_traffic_light) + if (turn.has_traffic_light || turn.has_stop_sign) turn.duration += context.properties.GetTrafficSignalPenalty(); // Turn weight falls back to the duration value in deciseconds diff --git a/taginfo.json b/taginfo.json index 358845d80..3107a5c61 100644 --- a/taginfo.json +++ b/taginfo.json @@ -125,6 +125,7 @@ {"key": "side_road", "value": "rotary", "description": "gets speed penalty"}, {"key": "route", "object_types": ["way"]}, {"key": "highway", "value": "traffic_signals", "object_types": ["node"]}, + {"key": "highway", "value": "stop", "object_types": ["node"]}, {"key": "highway", "value": "crossing", "object_types": ["node"]}, {"key": "access", "value": "yes"}, {"key": "access", "value": "motorcar"},