diff --git a/CHANGELOG.md b/CHANGELOG.md index fddc909d92c..3f36b733ab0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Unreleased - Changes from 5.27.1 - Features + - ADDED: Add generic support for obstacles [#7130](https://github.com/Project-OSRM/osrm-backend/pull/7130) - ADDED: Route pedestrians over highway=platform [#6993](https://github.com/Project-OSRM/osrm-backend/pull/6993) - REMOVED: Remove all core-CH left-overs [#6920](https://github.com/Project-OSRM/osrm-backend/pull/6920) - ADDED: Add support for a keepalive_timeout flag. [#6674](https://github.com/Project-OSRM/osrm-backend/pull/6674) diff --git a/docs/profiles.md b/docs/profiles.md index c66eb81c299..b6c29056899 100644 --- a/docs/profiles.md +++ b/docs/profiles.md @@ -1,7 +1,7 @@ # OSRM profiles OSRM supports "profiles". Profiles representing routing behavior for different transport modes like car, bike and foot. You can also create profiles for variations like a fastest/shortest car profile or fastest/safest/greenest bicycles profile. - A profile describes whether or not it's possible to route along a particular type of way, whether we can pass a particular node, and how quickly we'll be traveling when we do. This feeds into the way the routing graph is created and thus influences the output routes. +A profile describes whether or not it's possible to route along a particular type of way, whether we can pass a particular node, and how quickly we'll be traveling when we do. This feeds into the way the routing graph is created and thus influences the output routes. ## Available profiles Out-of-the-box OSRM comes with profiles for car, bicycle and foot. You can easily modify these or create new ones if you like. @@ -116,7 +116,7 @@ suffix_list | Set | List of name suffixes relation_types | Sequence | Determines which relations should be cached for processing in this profile. It contains relations types ### process_node(profile, node, result, relations) -Process an OSM node to determine whether this node is a barrier or can be passed and whether passing it incurs a delay. +Process an OSM node to determine whether this node is an obstacle, if it can be passed at all and whether passing it incurs a delay. Argument | Description ---------|------------------------------------------------------- @@ -126,12 +126,177 @@ result | The output that you will modify. relations| Storage of relations to access relations, where `node` is a member. The following attributes can be set on `result`: +(Note: for new code use the `obstacle_map`. Attribute | Type | Notes ----------------|---------|--------------------------------------------------------- barrier | Boolean | Is it an impassable barrier? traffic_lights | Boolean | Is it a traffic light (incurs delay in `process_turn`)? +### Obstacle +A user type that represents an obstacle on the road or a place where you can turn +around. + +This may be a completely impassable obstacle like a barrier, a temporary obstacle like a +traffic light or a stop sign, or an obstacle that just slows you down like a +traffic_calming. The obstacle may be present in both directions or in one direction +only. + +This also represents a good turning point like a mini_roundabout, turning_loop, or +turning_circle. + +An object of this type is immutable once constructed. + +```lua +local obs = Obstacle.new( + obstacle_type.traffic_signals, + obstacle_direction.forward, + 2.5, + 0 +) +assert(obs.duration == 2.5) +``` + +Member | Mode | Type | Notes +----------|-----------|--------------------|---------------------------------- +type | read-only | obstacle_type | eg. `obstacle_type.barrier` +direction | read-only | obstacle_direction | eg. `obstacle_direction.forward` +duration | read-only | float | The expected delay in seconds +weight | read-only | float | The weight + +#### obstacle_type +An enum with the following keys: + +Keys | +----------------| +none | +barrier | +traffic_signals | +stop | +give_way | +crossing | +traffic_calming | +mini_roundabout | +turning_loop | +turning_circle | + +#### obstacle_direction +An enum with the following keys: + +Keys | +---------| +none | +forward | +backward | +both | + +### obstacle_map +A global user type. It stores obstacles. + +The canonical workflow is: to store obstacles in `process_node()` and retrieve them in +`process_turn()`. + +Note: In the course of processing, between the `process_node()` stage and the +`process_turn()` stage, the extractor switches from using OSM nodes to using +internal nodes. Both types have different ids. You can only store OSM nodes and only +retrieve internal nodes. This implies that, in `process_node()`, you cannot retrieve an +obstacle you have just stored. + +#### obstacle_map:add(node, obstacle) +Call this function inside `process_node()` to register an obstacle on a node. You can +register as many different obstacles as you wish on any given node. It is your +responsibility to register the same obstacle only once. + +In a following step -- likely in `process_turn()` -- you can retrieve all obstacles +registered at any given node. This function works with OSM nodes. + +Argument | Type | Notes +---------|----------|-------------------------------------------- +node | OSMNode | The same node as passed to `process_node`. +obstacle | Obstacle | The obstacle + +Usage example: + +```lua +function process_node(profile, node, result, relations) + ... + obstacle_map:add(node, + Obstacle.new( + obstacle_type.traffic_signal, + obstacle_direction.forward, + 2, 0)) +end +``` + +#### obstacle_map:any(from, to, type) +Return true if there are any obstacles at node `to` when coming from node +`from` and having the type `type`. + +You will likely call this function inside `process_turn()`. +Note that this works only with internal nodes, not with OSM nodes. + +```lua +bool obstacle_map:any(to) +bool obstacle_map:any(from, to) +bool obstacle_map:any(from, to, type) +``` + +Argument | Type | Notes +---------|---------------|------------------------------------------------------------------------------------- +from | Node | The leading node. Optional. +to | Node | The node with the obstacle. +type | obstacle_type | The obstacle type. Defaults to all types. May be a bitwise-or combination of types. +returns | bool | True if there are any obstacles satisfiying the given criteria. + +Usage examples: + +```lua +function process_turn(profile, turn) + if obstacle_map:any(turn.via) then + ... + end + if obstacle_map:any(turn.from, turn.via, obstacle_type.traffic_signal) then + turn.duration = turn.duration + 2 + end +end +``` + +#### obstacle_map:get(from, to, type) +This function retrieves all registered obstacles at node `to` when coming from the node +`from` and having the type `type`. + +You will likely call this function inside `process_turn()`. +Note that this works only with internal nodes, not with OSM nodes. + +```lua +obstacle_map:get(to) +obstacle_map:get(from, to) +obstacle_map:get(from, to, type) +``` + +Argument | Type | Notes +---------|---------------|------------------------------------------------------------------------------------- +from | Node | The leading node. Optional. +to | Node | The node with the obstacle. +type | obstacle_type | The obstacle type. Defaults to all types. May be a bitwise-or combination of types. +returns | table | A table of `Obstacle`s. + +Usage examples: + +```lua +function process_turn(profile, turn) + for _, obs in pairs(obstacle_map:get(turn.via)) do + if obs.type == obstacle_type.barrier then + turn.duration = turn.duration + obs.duration + end + end + for _, obs in pairs(obstacle_map:get( + turn.from, turn.via, obstacle_type.traffic_signal)) do + turn.duration = turn.duration + obs.duration + end +end +``` + ### process_way(profile, way, result, relations) Given an OpenStreetMap way, the `process_way` function will either return nothing (meaning we are not going to route over this way at all), or it will set up a result hash. @@ -233,14 +398,24 @@ target_highway_turn_classification | Read | Integer | target_access_turn_classification | Read | Integer | Classification based on access tag defined by user during setup. (default when not set: 0, allowed classification values are: 0-15)) target_speed | Read | Integer | Speed on this target road in km/h target_priority_class | Read | Enum | The type of road priority class of the target. Defined in `include/extractor/road_classification.hpp` +from | Read | NodeID | The leading node +via | Read | NodeID | The intersection node +to | Read | NodeID | The trailing node +source_road | Read | ExtractionTurnLeg | The incoming road +target_road | Read | ExtractionTurnLeg | The outgoing road roads_on_the_right | Read | Vector<ExtractionTurnLeg> | Vector with information about other roads on the right of the turn that are also connected at the intersection roads_on_the_left | Read | Vector<ExtractionTurnLeg> | Vector with information about other roads on the left of the turn that are also connected at the intersection. If turn is a u turn, this is empty. weight | Read/write | Float | Penalty to be applied for this turn (routing weight) duration | Read/write | Float | Penalty to be applied for this turn (duration in deciseconds) -#### `roads_on_the_right` and `roads_on_the_left` -The information of `roads_on_the_right` and `roads_on_the_left` that can be read are as follows: +#### `from`, `via`, and `to` +Use these node IDs to retrieve obstacles. See: `obstacle_map:get`. + +#### `source_road`, `target_road`, `roads_on_the_right`, and `roads_on_the_left` + +The information of `source_road`, `target_road`, `roads_on_the_right`, and +`roads_on_the_left` that can be read are as follows: Attribute | Read/write? | Type | Notes --------------------- | ------------- | --------- | ------------------------------------------------------ @@ -252,6 +427,7 @@ number_of_lanes | Read | Integer | How many lanes does th highway_turn_classification | Read | Integer | Classification based on highway tag defined by user during setup. (default when not set: 0, allowed classification values are: 0-15) access_turn_classification | Read | Integer | Classification based on access tag defined by user during setup. (default when not set: 0, allowed classification values are: 0-15) speed | Read | Integer | Speed on this road in km/h +distance | Read | Double | The length of the road edge priority_class | Read | Enum | The type of road priority class of the leg. Defined in `include/extractor/road_classification.hpp` is_incoming | Read | Boolean | Is the road an incoming road of the intersection is_outgoing | Read | Boolean | Is the road an outgoing road of the intersection diff --git a/docs/src/content.js b/docs/src/content.js index 6e7844e1a29..c3eaf359d36 100644 --- a/docs/src/content.js +++ b/docs/src/content.js @@ -11,6 +11,4 @@ var fs = require('fs'); */ module.exports = '# HTTP API\n' + - fs.readFileSync('./content/http.md', 'utf8') + '\n'+ - '# libosrm C++ API\n' + - fs.readFileSync('./content/libosrm.md', 'utf8') + '\n'; + fs.readFileSync('./content/http.md', 'utf8') + '\n'; diff --git a/features/car/obstacle_penalties.feature b/features/car/obstacle_penalties.feature new file mode 100644 index 00000000000..1b733933004 --- /dev/null +++ b/features/car/obstacle_penalties.feature @@ -0,0 +1,227 @@ +@routing @car @obstacle +Feature: Car - Handle obstacle penalties + + Background: + Given the profile "car" + + Scenario: Car - Give-Way signs + Given the node map + """ + a-b-c d-e-f g-h-i j-k-l m-n-o + + """ + + And the ways + | nodes | highway | + | abc | primary | + | def | primary | + | ghi | primary | + | jkl | primary | + | mno | primary | + + And the nodes + | node | highway | direction | + | e | give_way | | + | h | give_way | forward | + | k | give_way | backward | + | n | give_way | both | + + When I route I should get + | from | to | time | # | + | a | c | 11s | | + | c | a | 11s | | + | d | f | 12s | give-way sign | + | f | d | 12s | give-way sign | + | g | i | 12s | give-way sign | + | i | g | 11s | | + | j | l | 11s | | + | l | j | 12s | give-way sign | + | m | o | 12s | give-way sign | + | o | m | 12s | give-way sign | + + + Scenario: Car - Stop signs + Given the node map + """ + a-b-c d-e-f g-h-i j-k-l m-n-o + + """ + + And the ways + | nodes | highway | + | abc | primary | + | def | primary | + | ghi | primary | + | jkl | primary | + | mno | primary | + + And the nodes + | node | highway | direction | + | e | stop | | + | h | stop | forward | + | k | stop | backward | + | n | stop | both | + + When I route I should get + | from | to | time | # | + | a | c | 11s | | + | c | a | 11s | | + | d | f | 13s | stop sign | + | f | d | 13s | stop sign | + | g | i | 13s | stop sign | + | i | g | 11s | | + | j | l | 11s | | + | l | j | 13s | stop sign | + | m | o | 13s | stop sign | + | o | m | 13s | stop sign | + + + Scenario: Car - Stop sign on intersection node + Given the node map + """ + a f k + b-c-d h-g-i l-m-n + e j o + + """ + + And the ways + | nodes | highway | + | bcd | primary | + | ace | secondary | + | hgi | primary | + | fgj | secondary | + | lmn | primary | + | kmo | secondary | + + And the nodes + | node | highway | stop | + | g | stop | | + | m | stop | minor | + + + When I route I should get + + # No road has stop signs + | from | to | time | # | + | a | b | 14s +-1 | turn | + | a | e | 13s +-1 | no turn | + | a | d | 17s +-1 | turn | + | e | d | 14s +-1 | turn | + | e | a | 13s +-1 | no turn | + | e | b | 17s +-1 | turn | + | d | a | 14s +-1 | turn | + | d | b | 11s +-1 | no turn | + | d | e | 17s +-1 | turn | + | b | e | 14s +-1 | turn | + | b | d | 11s +-1 | no turn | + | b | a | 17s +-1 | turn | + + # All roads have stop signs - 2s penalty + | f | h | 16s +-1 | turn with stop | + | f | j | 15s +-1 | no turn with stop | + | f | i | 19s +-1 | turn with stop | + | j | i | 16s +-1 | turn with stop | + | j | f | 15s +-1 | no turn with stop | + | j | h | 19s +-1 | turn with stop | + | i | f | 16s +-1 | turn with stop | + | i | h | 13s +-1 | no turn with stop | + | i | j | 19s +-1 | turn with stop | + | h | j | 16s +-1 | turn with stop | + | h | i | 13s +-1 | no turn with stop | + | h | f | 19s +-1 | turn with stop | + + # Minor roads have stop signs - 2s penalty + | k | l | 16s +-1 | turn with minor stop | + | k | o | 15s +-1 | no turn with minor stop | + | k | n | 19s +-1 | turn with minor stop | + | o | n | 16s +-1 | turn with minor stop | + | o | k | 15s +-1 | no turn with minor stop | + | o | l | 19s +-1 | turn with minor stop | + | n | k | 14s +-1 | turn | + | n | l | 11s +-1 | no turn | + | n | o | 17s +-1 | turn | + | l | o | 14s +-1 | turn | + | l | n | 11s +-1 | no turn | + | l | k | 17s +-1 | turn | + + + Scenario: Car - Infer stop sign direction + Given a grid size of 5 meters + + Given the node map + """ + a---------sb + + c---------td + + e---------uf + + g---------vh + + """ + + And the ways + | nodes | highway | + | asb | primary | + | ctd | primary | + | euf | primary | + | gvh | primary | + + And the nodes + | node | highway | direction | + | s | stop | | + | t | stop | forward | + | u | stop | backward | + | v | stop | both | + + When I route I should get + | from | to | time | # | + | a | b | 3.5s | stop | + | b | a | 1.5s | | + | c | d | 3.5s | stop | + | d | c | 1.5s | | + | e | f | 1.5s | | + | f | e | 3.5s | stop | + | g | h | 3.5s | stop | + | h | g | 3.5s | stop | + + + Scenario: Car - Infer stop sign direction 2 + Given a grid size of 5 meters + + Given the node map + """ + + d + | + a---------sbt---------c + | + e + + """ + + And the ways + | nodes | highway | + | asbtc | primary | + | dbe | primary | + + And the nodes + | node | highway | + | s | stop | + | t | stop | + + When I route I should get + | from | to | time | # | + | a | d | 9s +- 1 | stop | + | a | c | 5s +- 1 | stop | + | a | e | 6s +- 1 | stop | + | c | e | 9s +- 1 | stop | + | c | a | 5s +- 1 | stop | + | c | d | 6s +- 1 | stop | + | d | c | 7s +- 1 | | + | d | e | 1s +- 1 | | + | d | a | 4s +- 1 | | + | e | a | 7s +- 1 | | + | e | d | 1s +- 1 | | + | e | c | 4s +- 1 | | diff --git a/features/car/traffic_light_penalties.feature b/features/car/traffic_light_penalties.feature index 2a5ded5f02e..5311599b6df 100644 --- a/features/car/traffic_light_penalties.feature +++ b/features/car/traffic_light_penalties.feature @@ -81,7 +81,7 @@ Feature: Car - Handle traffic lights Given the profile file "car" initialized with """ profile.properties.weight_name = 'distance' - profile.properties.traffic_light_penalty = 100000 + profile.properties.traffic_signal_penalty = 1000 """ Given the node map @@ -107,8 +107,8 @@ Feature: Car - Handle traffic lights | b | traffic_signals | When I route I should get - | from | to | time | distances | weight | # | - | 1 | 2 | 100033.2s | 599.9m,0m | 599.8 | goes via the expensive traffic signal | + | from | to | time | distances | weight | # | + | 1 | 2 | 1033.2s | 599.9m,0m | 599.8 | goes via the expensive traffic signal | @@ -243,7 +243,7 @@ Feature: Car - Handle traffic lights | a | c | abc,abc | _ibE_ibE?gJ?eJ | - Scenario: Traffic Signal Geometry - reverse signal + Scenario: Traffic Signal Geometry - backward signal Given the query options | overview | full | | geometries | polyline | @@ -259,7 +259,7 @@ Feature: Car - Handle traffic lights And the nodes | node | highway | traffic_signals:direction | - | b | traffic_signals | reverse | + | b | traffic_signals | backward | When I route I should get | from | to | route | geometry | diff --git a/features/car/turning_loop.feature b/features/car/turning_loop.feature new file mode 100644 index 00000000000..1c4d8bb0d54 --- /dev/null +++ b/features/car/turning_loop.feature @@ -0,0 +1,32 @@ +@routing @car @turning_loop +Feature: Car - Handle turning loop + + Background: + Given the profile "car" + + Scenario: Car - Must turn around at the first good opportunity + Given the node map + """ + a-b-c-d-e-f-g + """ + + And the ways + | nodes | highway | + | ab | primary | + | bc | primary | + | cd | primary | + | de | primary | + | ef | primary | + | fg | primary | + + And the nodes + | node | highway | + | b | turning_loop | + | d | turning_circle | + | f | mini_roundabout | + + When I route I should get + | waypoints | bearings | route | turns | + | a,a | 90,10 270,10 | ab,ab,ab | depart,continue uturn,arrive | + | c,a | 90,10 270,10 | cd,cd,ab | depart,continue uturn,arrive | + | e,a | 90,10 270,10 | ef,ef,ab | depart,continue uturn,arrive | diff --git a/include/extractor/edge_based_graph_factory.hpp b/include/extractor/edge_based_graph_factory.hpp index 56aec7392c7..dd5454f519a 100644 --- a/include/extractor/edge_based_graph_factory.hpp +++ b/include/extractor/edge_based_graph_factory.hpp @@ -23,7 +23,6 @@ #include "util/typedefs.hpp" #include "storage/io.hpp" -#include "traffic_signals.hpp" #include <cstdint> #include <string> @@ -60,8 +59,6 @@ class EdgeBasedGraphFactory explicit EdgeBasedGraphFactory(const util::NodeBasedDynamicGraph &node_based_graph, EdgeBasedNodeDataContainer &node_data_container, const CompressedEdgeContainer &compressed_edge_container, - const std::unordered_set<NodeID> &barrier_nodes, - const TrafficSignals &traffic_signals, const std::vector<util::Coordinate> &coordinates, const NameTable &name_table, const std::unordered_set<EdgeID> &segregated_edges, @@ -126,8 +123,6 @@ class EdgeBasedGraphFactory const std::vector<util::Coordinate> &m_coordinates; const util::NodeBasedDynamicGraph &m_node_based_graph; - const std::unordered_set<NodeID> &m_barrier_nodes; - const TrafficSignals &m_traffic_signals; 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 1711e7cb241..60b9cf64656 100644 --- a/include/extractor/extraction_containers.hpp +++ b/include/extractor/extraction_containers.hpp @@ -8,8 +8,6 @@ #include "extractor/scripting_environment.hpp" #include "storage/tar_fwd.hpp" -#include "traffic_lights.hpp" -#include "traffic_signals.hpp" #include <unordered_map> #include <unordered_set> @@ -26,19 +24,15 @@ namespace osrm::extractor class ExtractionContainers { using ReferencedWays = std::unordered_map<OSMWayID, NodesOfWay>; - using ReferencedTrafficSignals = - std::pair<std::unordered_set<OSMNodeID>, std::unordered_multimap<OSMNodeID, OSMNodeID>>; // The relationship between way and nodes is lost during node preparation. - // We identify the ways and nodes relevant to restrictions/overrides/signals prior to + // We identify the ways and nodes relevant to restrictions/overrides/obstacles prior to // node processing so that they can be referenced in the preparation phase. ReferencedWays IdentifyRestrictionWays(); ReferencedWays IdentifyManeuverOverrideWays(); - ReferencedTrafficSignals IdentifyTrafficSignals(); void PrepareNodes(); void PrepareManeuverOverrides(const ReferencedWays &maneuver_override_ways); void PrepareRestrictions(const ReferencedWays &restriction_ways); - void PrepareTrafficSignals(const ReferencedTrafficSignals &referenced_traffic_signals); void PrepareEdges(ScriptingEnvironment &scripting_environment); void WriteCharData(const std::string &file_name); @@ -52,9 +46,7 @@ class ExtractionContainers using NameOffsets = std::vector<size_t>; using WayIDVector = std::vector<OSMWayID>; using WayNodeIDOffsets = std::vector<size_t>; - using InputTrafficSignal = std::pair<OSMNodeID, TrafficLightClass::Direction>; - std::vector<OSMNodeID> barrier_nodes; NodeIDVector used_node_id_list; NodeVector all_nodes_list; EdgeVector all_edges_list; @@ -67,9 +59,6 @@ class ExtractionContainers unsigned max_internal_node_id; - std::vector<InputTrafficSignal> external_traffic_signals; - TrafficSignals internal_traffic_signals; - std::vector<NodeBasedEdge> used_edges; // List of restrictions (conditional and unconditional) before we transform them into the @@ -81,7 +70,6 @@ class ExtractionContainers std::vector<InputManeuverOverride> external_maneuver_overrides_list; std::vector<UnresolvedManeuverOverride> internal_maneuver_overrides; - std::unordered_set<NodeID> used_barrier_nodes; NodeVector used_nodes; ExtractionContainers(); diff --git a/include/extractor/extraction_node.hpp b/include/extractor/extraction_node.hpp index ad46e9bcefc..189e37c7e3b 100644 --- a/include/extractor/extraction_node.hpp +++ b/include/extractor/extraction_node.hpp @@ -1,21 +1,17 @@ #ifndef EXTRACTION_NODE_HPP #define EXTRACTION_NODE_HPP -#include "traffic_lights.hpp" +#include <osmium/osm/node.hpp> namespace osrm::extractor { struct ExtractionNode { - ExtractionNode() : traffic_lights(TrafficLightClass::NONE), barrier(false) {} - void clear() - { - traffic_lights = TrafficLightClass::NONE; - barrier = false; - } - TrafficLightClass::Direction traffic_lights; - bool barrier; + ExtractionNode() {} + + // the current node + const osmium::Node *node; }; } // namespace osrm::extractor diff --git a/include/extractor/extraction_turn.hpp b/include/extractor/extraction_turn.hpp index 4dafd823cb9..a779c920ed0 100644 --- a/include/extractor/extraction_turn.hpp +++ b/include/extractor/extraction_turn.hpp @@ -1,8 +1,10 @@ #ifndef OSRM_EXTRACTION_TURN_HPP #define OSRM_EXTRACTION_TURN_HPP +#include "extractor/graph_compressor.hpp" #include "extractor/road_classification.hpp" #include "extractor/travel_mode.hpp" +#include "util/typedefs.hpp" #include <boost/numeric/conversion/cast.hpp> @@ -13,6 +15,8 @@ namespace osrm::extractor struct ExtractionTurnLeg { + using EdgeData = util::NodeBasedDynamicGraph::EdgeData; + ExtractionTurnLeg(bool is_restricted, bool is_motorway, bool is_link, @@ -20,17 +24,34 @@ struct ExtractionTurnLeg int highway_turn_classification, int access_turn_classification, int speed, + double distance, RoadPriorityClass::Enum priority_class, bool is_incoming, bool is_outgoing) : is_restricted(is_restricted), is_motorway(is_motorway), is_link(is_link), number_of_lanes(number_of_lanes), highway_turn_classification(highway_turn_classification), - access_turn_classification(access_turn_classification), speed(speed), + access_turn_classification(access_turn_classification), speed(speed), distance(distance), priority_class(priority_class), is_incoming(is_incoming), is_outgoing(is_outgoing) { } + ExtractionTurnLeg(EdgeData edge_data, bool is_incoming, bool is_outgoing) + : ExtractionTurnLeg(edge_data.flags.restricted, + edge_data.flags.road_classification.IsMotorwayClass(), + edge_data.flags.road_classification.IsLinkClass(), + edge_data.flags.road_classification.GetNumberOfLanes(), + edge_data.flags.highway_turn_classification, + edge_data.flags.access_turn_classification, + 36.0 * from_alias<double>(edge_data.distance) / + from_alias<double>(edge_data.duration), + from_alias<double>(edge_data.distance), + edge_data.flags.road_classification.GetPriority(), + is_incoming, + is_outgoing) + { + } + bool is_restricted; bool is_motorway; bool is_link; @@ -38,11 +59,25 @@ struct ExtractionTurnLeg int highway_turn_classification; int access_turn_classification; int speed; + double distance; RoadPriorityClass::Enum priority_class; bool is_incoming; bool is_outgoing; }; +// Structure reflected into LUA scripting +// +// This structure backs the `turn` parameter in the LUA `process_turn` function. +// That function is called: +// +// 1. from graph_compressor.cpp when compressing nodes with obstacles. A fake turn with +// just one incoming and one outgoing edge will be generated. `number_of_roads` will +// be 2. The returned penalties will be added to the compressed edge. +// +// 2. from edge_based_graph_factory.cpp during generation of edge-expanded edges. In +// this stage real turns will be modelled. The returned penalties will be added to +// the edge-expanded edge. + struct ExtractionTurn { ExtractionTurn(double angle, @@ -50,6 +85,7 @@ struct ExtractionTurn bool is_u_turn, bool has_traffic_light, bool is_left_hand_driving, + bool source_restricted, TravelMode source_mode, bool source_is_motorway, @@ -70,8 +106,13 @@ struct ExtractionTurn int target_speed, RoadPriorityClass::Enum target_priority_class, + const ExtractionTurnLeg &source_road, + const ExtractionTurnLeg &target_road, const std::vector<ExtractionTurnLeg> &roads_on_the_right, - const std::vector<ExtractionTurnLeg> &roads_on_the_left) + const std::vector<ExtractionTurnLeg> &roads_on_the_left, + const NodeID from, + const NodeID via, + const NodeID to) : 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), @@ -89,11 +130,60 @@ struct ExtractionTurn target_access_turn_classification(target_access_turn_classification), target_speed(target_speed), target_priority_class(target_priority_class), - roads_on_the_right(roads_on_the_right), roads_on_the_left(roads_on_the_left), weight(0.), - duration(0.) + from(from), via(via), to(to), + + source_road(source_road), target_road(target_road), + roads_on_the_right(roads_on_the_right), roads_on_the_left(roads_on_the_left), + weight(0.), duration(0.) { } + + // to construct a "fake" turn while compressing obstacle nodes + // in graph_compressor.cpp + ExtractionTurn(NodeID from, + NodeID via, + NodeID to, + const ExtractionTurnLeg::EdgeData &source_edge, + const ExtractionTurnLeg::EdgeData &target_edge, + const std::vector<ExtractionTurnLeg> &roads_on_the_right, + const std::vector<ExtractionTurnLeg> &roads_on_the_left) + : ExtractionTurn{0, + 2, + false, + true, + false, + // source + false, + TRAVEL_MODE_DRIVING, + false, + false, + 1, + 0, + 0, + 0, + 0, + // target + false, + TRAVEL_MODE_DRIVING, + false, + false, + 1, + 0, + 0, + 0, + 0, + // other + ExtractionTurnLeg{source_edge, true, false}, + ExtractionTurnLeg{target_edge, false, true}, + roads_on_the_right, + roads_on_the_left, + from, + via, + to} + { + } + const double angle; const int number_of_roads; const bool is_u_turn; @@ -122,6 +212,12 @@ struct ExtractionTurn const int target_speed; const RoadPriorityClass::Enum target_priority_class; + const NodeID from; + const NodeID via; + const NodeID to; + + const ExtractionTurnLeg source_road; + const ExtractionTurnLeg target_road; const std::vector<ExtractionTurnLeg> roads_on_the_right; const std::vector<ExtractionTurnLeg> roads_on_the_left; diff --git a/include/extractor/extractor.hpp b/include/extractor/extractor.hpp index 1d36418aab2..4d30eb7e4b1 100644 --- a/include/extractor/extractor.hpp +++ b/include/extractor/extractor.hpp @@ -43,7 +43,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "util/guidance/turn_lanes.hpp" #include "restriction_graph.hpp" -#include "traffic_signals.hpp" #include "util/typedefs.hpp" namespace osrm::extractor @@ -64,8 +63,6 @@ class Extractor LaneDescriptionMap turn_lane_map; std::vector<TurnRestriction> turn_restrictions; std::vector<UnresolvedManeuverOverride> unresolved_maneuver_overrides; - TrafficSignals traffic_signals; - std::unordered_set<NodeID> barriers; std::vector<util::Coordinate> osm_coordinates; extractor::PackedOSMIDs osm_node_ids; std::vector<NodeBasedEdge> edge_list; @@ -83,8 +80,6 @@ class Extractor const util::NodeBasedDynamicGraph &node_based_graph, const std::vector<util::Coordinate> &coordinates, const CompressedEdgeContainer &compressed_edge_container, - const std::unordered_set<NodeID> &barrier_nodes, - const TrafficSignals &traffic_signals, const RestrictionGraph &restriction_graph, const std::unordered_set<EdgeID> &segregated_edges, const NameTable &name_table, @@ -112,7 +107,6 @@ class Extractor const EdgeBasedNodeDataContainer &edge_based_node_container, const std::vector<util::Coordinate> &node_coordinates, const CompressedEdgeContainer &compressed_edge_container, - const std::unordered_set<NodeID> &barrier_nodes, const RestrictionGraph &restriction_graph, const NameTable &name_table, LaneDescriptionMap lane_description_map, diff --git a/include/extractor/extractor_callbacks.hpp b/include/extractor/extractor_callbacks.hpp index 83672f54977..9a493e27409 100644 --- a/include/extractor/extractor_callbacks.hpp +++ b/include/extractor/extractor_callbacks.hpp @@ -43,13 +43,13 @@ class ExtractorCallbacks using MapVal = unsigned; using StringMap = std::unordered_map<MapKey, MapVal>; StringMap string_map; - ExtractionContainers &external_memory; std::unordered_map<std::string, ClassData> &classes_map; LaneDescriptionMap &lane_description_map; bool fallback_to_duration; bool force_split_edges; public: + ExtractionContainers &external_memory; using ClassesMap = std::unordered_map<std::string, ClassData>; explicit ExtractorCallbacks(ExtractionContainers &extraction_containers, diff --git a/include/extractor/graph_compressor.hpp b/include/extractor/graph_compressor.hpp index 0e9a1070570..3af6662779d 100644 --- a/include/extractor/graph_compressor.hpp +++ b/include/extractor/graph_compressor.hpp @@ -2,10 +2,8 @@ #define GEOMETRY_COMPRESSOR_HPP #include "extractor/scripting_environment.hpp" -#include "util/typedefs.hpp" - -#include "traffic_signals.hpp" #include "util/node_based_graph.hpp" +#include "util/typedefs.hpp" #include <unordered_set> #include <vector> @@ -19,12 +17,10 @@ struct UnresolvedManeuverOverride; class GraphCompressor { + public: using EdgeData = util::NodeBasedDynamicGraph::EdgeData; - public: - void Compress(const std::unordered_set<NodeID> &barrier_nodes, - TrafficSignals &traffic_signals, - ScriptingEnvironment &scripting_environment, + void Compress(ScriptingEnvironment &scripting_environment, std::vector<TurnRestriction> &turn_restrictions, std::vector<UnresolvedManeuverOverride> &maneuver_overrides, util::NodeBasedDynamicGraph &graph, diff --git a/include/extractor/intersection/intersection_analysis.hpp b/include/extractor/intersection/intersection_analysis.hpp index 9e0878df5d7..6765b5b52d5 100644 --- a/include/extractor/intersection/intersection_analysis.hpp +++ b/include/extractor/intersection/intersection_analysis.hpp @@ -6,6 +6,7 @@ #include "extractor/intersection/intersection_view.hpp" #include "extractor/intersection/mergable_road_detector.hpp" #include "extractor/node_restriction_map.hpp" +#include "extractor/obstacles.hpp" #include "extractor/turn_lane_types.hpp" #include "util/coordinate.hpp" @@ -26,7 +27,7 @@ IntersectionEdges getOutgoingEdges(const util::NodeBasedDynamicGraph &graph, bool isTurnAllowed(const util::NodeBasedDynamicGraph &graph, const EdgeBasedNodeDataContainer &node_data_container, const RestrictionMap &restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const ObstacleMap &obstacle_nodes, const IntersectionEdgeGeometries &geometries, const TurnLanesIndexedArray &turn_lanes_data, const IntersectionEdge &from, @@ -46,14 +47,14 @@ getIntersectionGeometries(const util::NodeBasedDynamicGraph &graph, IntersectionView convertToIntersectionView(const util::NodeBasedDynamicGraph &graph, const EdgeBasedNodeDataContainer &node_data_container, const RestrictionMap &restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const ObstacleMap &obstacle_nodes, const IntersectionEdgeGeometries &edge_geometries, const TurnLanesIndexedArray &turn_lanes_data, const IntersectionEdge &incoming_edge, const IntersectionEdges &outgoing_edges, const std::unordered_set<EdgeID> &merged_edges); -// Check for restrictions/barriers and generate a list of valid and invalid turns present at +// Check for restrictions/obstacles and generate a list of valid and invalid turns present at // the node reached from `incoming_edge`. The resulting candidates have to be analyzed // for their actual instructions later on. template <bool USE_CLOSE_COORDINATE> @@ -62,7 +63,7 @@ IntersectionView getConnectedRoads(const util::NodeBasedDynamicGraph &graph, const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const ObstacleMap &obstacle_nodes, const TurnLanesIndexedArray &turn_lanes_data, const IntersectionEdge &incoming_edge); @@ -70,15 +71,15 @@ IntersectionView getConnectedRoadsForEdgeGeometries(const util::NodeBasedDynamicGraph &graph, const EdgeBasedNodeDataContainer &node_data_container, const RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const ObstacleMap &obstacle_nodes, const TurnLanesIndexedArray &turn_lanes_data, const IntersectionEdge &incoming_edge, const IntersectionEdgeGeometries &edge_geometries, const std::unordered_set<EdgeID> &merged_edge_ids); -// Graph Compression cannot compress every setting. For example any barrier/traffic light cannot +// Graph Compression cannot compress every setting. For example nodes with obstacles cannot // be compressed. As a result, a simple road of the form `a ----- b` might end up as having an -// intermediate intersection, if there is a traffic light in between. If we want to look farther +// intermediate intersection, if there is an obstacle in between. If we want to look farther // down a road, finding the next actual decision requires the look at multiple intersections. // Here we follow the road until we either reach a dead end or find the next intersection with // more than a single next road. This function skips over degree two nodes to find correct input diff --git a/include/extractor/intersection/intersection_view.hpp b/include/extractor/intersection/intersection_view.hpp index 4eb60585602..6cb721b1275 100644 --- a/include/extractor/intersection/intersection_view.hpp +++ b/include/extractor/intersection/intersection_view.hpp @@ -166,7 +166,7 @@ template <typename Self> struct EnableIntersectionOps } // Can this be skipped over? - auto isTrafficSignalOrBarrier() const { return self()->size() == 2; } + auto isObstacle() const { return self()->size() == 2; } // Checks if there is at least one road available (except UTurn road) on which to continue. auto isDeadEnd() const diff --git a/include/extractor/intersection/mergable_road_detector.hpp b/include/extractor/intersection/mergable_road_detector.hpp index 1f02afb5675..2686196a264 100644 --- a/include/extractor/intersection/mergable_road_detector.hpp +++ b/include/extractor/intersection/mergable_road_detector.hpp @@ -6,6 +6,7 @@ #include "extractor/intersection/have_identical_names.hpp" #include "extractor/name_table.hpp" #include "extractor/node_restriction_map.hpp" +#include "extractor/obstacles.hpp" #include "extractor/turn_lane_types.hpp" #include "guidance/intersection.hpp" @@ -47,7 +48,7 @@ class MergableRoadDetector const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const ObstacleMap &obstacle_nodes, const TurnLanesIndexedArray &turn_lanes_data, const extractor::NameTable &name_table, const SuffixTable &street_name_suffix_table); @@ -164,7 +165,7 @@ class MergableRoadDetector const std::vector<util::Coordinate> &node_coordinates; const extractor::CompressedEdgeContainer &compressed_geometries; const RestrictionMap &node_restriction_map; - const std::unordered_set<NodeID> &barrier_nodes; + const ObstacleMap &obstacle_nodes; const TurnLanesIndexedArray &turn_lanes_data; // name detection diff --git a/include/extractor/intersection/node_based_graph_walker.hpp b/include/extractor/intersection/node_based_graph_walker.hpp index f3915ee9f1e..bafd662121f 100644 --- a/include/extractor/intersection/node_based_graph_walker.hpp +++ b/include/extractor/intersection/node_based_graph_walker.hpp @@ -30,7 +30,7 @@ class NodeBasedGraphWalker const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const ObstacleMap &obstacle_nodes, const TurnLanesIndexedArray &turn_lanes_data); /* @@ -53,7 +53,7 @@ class NodeBasedGraphWalker const std::vector<util::Coordinate> &node_coordinates; const extractor::CompressedEdgeContainer &compressed_geometries; const RestrictionMap &node_restriction_map; - const std::unordered_set<NodeID> &barrier_nodes; + const ObstacleMap &obstacle_nodes; const TurnLanesIndexedArray &turn_lanes_data; }; @@ -160,7 +160,7 @@ struct IntersectionFinderAccumulator const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const ObstacleMap &obstacle_nodes, const TurnLanesIndexedArray &turn_lanes_data); // true if the path has traversed enough distance bool terminate(); @@ -182,7 +182,7 @@ struct IntersectionFinderAccumulator const std::vector<util::Coordinate> &node_coordinates; const extractor::CompressedEdgeContainer &compressed_geometries; const RestrictionMap &node_restriction_map; - const std::unordered_set<NodeID> &barrier_nodes; + const ObstacleMap &obstacle_nodes; const TurnLanesIndexedArray &turn_lanes_data; }; @@ -223,7 +223,7 @@ NodeBasedGraphWalker::TraverseRoad(NodeID current_node_id, node_coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, {current_node_id, current_edge_id}); @@ -252,7 +252,7 @@ NodeBasedGraphWalker::TraverseRoad(NodeID current_node_id, return {}; } -struct SkipTrafficSignalBarrierRoadSelector +struct SkipObstacleRoadSelector { std::optional<EdgeID> operator()(const NodeID, const EdgeID, @@ -260,7 +260,7 @@ struct SkipTrafficSignalBarrierRoadSelector const util::NodeBasedDynamicGraph &, const EdgeBasedNodeDataContainer &) const { - if (intersection.isTrafficSignalOrBarrier()) + if (intersection.isObstacle()) { return std::make_optional(intersection[1].eid); } diff --git a/include/extractor/node_based_edge.hpp b/include/extractor/node_based_edge.hpp index 2abb98b205c..d98e2283e64 100644 --- a/include/extractor/node_based_edge.hpp +++ b/include/extractor/node_based_edge.hpp @@ -48,6 +48,8 @@ struct NodeBasedEdgeClassification { } + bool IsRestricted() const { return restricted; } + bool operator==(const NodeBasedEdgeClassification &other) const { return (road_classification == other.road_classification) && (forward == other.forward) && diff --git a/include/extractor/node_based_graph_factory.hpp b/include/extractor/node_based_graph_factory.hpp index 79b4b45cd34..8c08e78bd33 100644 --- a/include/extractor/node_based_graph_factory.hpp +++ b/include/extractor/node_based_graph_factory.hpp @@ -8,7 +8,6 @@ #include "extractor/packed_osm_ids.hpp" #include "extractor/scripting_environment.hpp" -#include "traffic_signals.hpp" #include "util/coordinate.hpp" #include "util/node_based_graph.hpp" @@ -23,7 +22,7 @@ namespace osrm::extractor // edge-based graph and is also the basic concept for annotating paths. All information from ways // that is transferred into the API response is connected to the edges of the node-based graph. // -// The input to the graph creation is the set of edges, traffic signals, barriers, meta-data,... +// The input to the graph creation is the set of edges, obstacles, meta-data,... // which is generated during extraction and stored within the extraction containers. class NodeBasedGraphFactory { @@ -35,15 +34,12 @@ class NodeBasedGraphFactory NodeBasedGraphFactory(ScriptingEnvironment &scripting_environment, std::vector<TurnRestriction> &turn_restrictions, std::vector<UnresolvedManeuverOverride> &maneuver_overrides, - TrafficSignals &traffic_signals, - std::unordered_set<NodeID> &&barriers, std::vector<util::Coordinate> &&coordinates, extractor::PackedOSMIDs &&osm_node_ids, const std::vector<NodeBasedEdge> &edge_list, std::vector<NodeBasedEdgeAnnotation> &&annotation_data); auto const &GetGraph() const { return compressed_output_graph; } - auto const &GetBarriers() const { return barriers; } auto const &GetCompressedEdges() const { return compressed_edge_container; } auto const &GetCoordinates() const { return coordinates; } auto const &GetAnnotationData() const { return annotation_data; } @@ -66,8 +62,7 @@ class NodeBasedGraphFactory // edges into a single representative form void Compress(ScriptingEnvironment &scripting_environment, std::vector<TurnRestriction> &turn_restrictions, - std::vector<UnresolvedManeuverOverride> &maneuver_overrides, - TrafficSignals &traffic_signals); + std::vector<UnresolvedManeuverOverride> &maneuver_overrides); // 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 @@ -87,8 +82,6 @@ class NodeBasedGraphFactory std::vector<NodeBasedEdgeAnnotation> annotation_data; // General Information about the graph, not used outside of extractor - std::unordered_set<NodeID> barriers; - std::vector<util::Coordinate> coordinates; // data to keep in sync with the node-based graph diff --git a/include/extractor/obstacles.hpp b/include/extractor/obstacles.hpp new file mode 100644 index 00000000000..b2ca3039172 --- /dev/null +++ b/include/extractor/obstacles.hpp @@ -0,0 +1,211 @@ +/* + +Copyright (c) 2025, Project OSRM contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#ifndef OSRM_EXTRACTOR_OBSTACLES_DATA_HPP_ +#define OSRM_EXTRACTOR_OBSTACLES_DATA_HPP_ + +#include "util/typedefs.hpp" + +#include <osmium/osm/node.hpp> +#include <tbb/concurrent_vector.h> + +#include <ranges> +#include <string> +#include <unordered_map> +#include <vector> + +namespace osrm::extractor +{ +// A class that represents an obstacle on the road or a place where you can turn around. +// +// This may be a completely impassable obstacle like a barrier, a temporary obstacle +// like a traffic light or a stop sign, or an obstacle that just slows you down like a +// traffic calming bump. The obstacle may be present in both directions or in one +// direction only. +// +// This also represents a good turning point like a mini_roundabout, turning_loop, or +// turning_circle. +// +// Note: A better name would have been 'WayPoint', but that name is ambiguous in the +// OSRM-context. +// +struct Obstacle +{ + // The type of an obstacle + // Note: must be kept in sync with the initializer_list in obstacles.cpp + enum class Type : uint16_t + { + None = 0x0000, + Barrier = 0x0001, + TrafficSignals = 0x0002, + Stop = 0x0004, + GiveWay = 0x0008, + Crossing = 0x0010, + TrafficCalming = 0x0020, + MiniRoundabout = 0x0040, + TurningLoop = 0x0080, + TurningCircle = 0x0100, + StopMinor = 0x0200, + + Turning = MiniRoundabout | TurningLoop | TurningCircle, + Incompressible = Barrier | Turning, + All = 0xFFFF + }; + + static const std::initializer_list<std::pair<std::string_view, Type>> + enum_type_initializer_list; + + // The directions in which an obstacle applies. + // Note: must be kept in sync with the initializer_list in obstacles.cpp + enum class Direction : uint8_t + { + None = 0x0, + Forward = 0x1, + Backward = 0x2, + Both = 0x3 + }; + + static const std::initializer_list<std::pair<std::string_view, Direction>> + enum_direction_initializer_list; + + // use overloading instead of default arguments for sol::constructors + Obstacle(Type t_type) : type{t_type} {}; + Obstacle(Type t_type, Direction t_direction) : type{t_type}, direction{t_direction} {}; + Obstacle(Type t_type, Direction t_direction, float t_duration_penalty, float t_weight_penalty) + : type{t_type}, direction{t_direction}, duration{t_duration_penalty}, + weight{t_weight_penalty} {}; + + Type type; + Direction direction{Direction::None}; + float duration{0}; // in seconds + float weight{0}; // unit: profile.weight_multiplier +}; + +// A class that holds all known nodes with obstacles. +// +// This class holds all obstacles, bidirectional and unidirectional ones. For +// unidirectional obstacle nodes it also stores the node leading to it. +// +// Notes: +// +// Before fixupNodes() it uses the external node id (aka. OSMNodeID). +// After fixupNodes() it uses the internal node id (aka. NodeID). +// +class ObstacleMap +{ + using NodeIDVector = std::vector<OSMNodeID>; + using WayNodeIDOffsets = std::vector<size_t>; + + using OsmFromToObstacle = std::tuple<OSMNodeID, OSMNodeID, Obstacle>; + using FromToObstacle = std::tuple<NodeID, NodeID, Obstacle>; + + public: + ObstacleMap() = default; + + // Insert an obstacle using the OSM node id. + // + // This function is thread-safe. + void emplace(OSMNodeID osm_node_id, const Obstacle &obstacle) + { + osm_obstacles.emplace_back(SPECIAL_OSM_NODEID, osm_node_id, obstacle); + }; + + // Insert an obstacle using internal node ids. + // + // The obstacle is at 'to'. For bidirectional obstacles set 'from' to SPECIAL_NODEID. + // Convenient for testing. + void emplace(NodeID from, NodeID to, const Obstacle &obstacle) + { + obstacles.emplace(to, std::make_tuple(from, to, obstacle)); + }; + + // get all obstacles at node 'to' when coming from node 'from' + // pass SPECIAL_NODEID as 'from' to get all obstacles at 'to' + // 'type' can be a bitwise-or combination of Obstacle::Type + std::vector<Obstacle> + get(NodeID from, NodeID to, Obstacle::Type type = Obstacle::Type::All) const + { + std::vector<Obstacle> result; + + auto [begin, end] = obstacles.equal_range(to); + for (auto &[key, value] : std::ranges::subrange(begin, end)) + { + auto &[from_id, to_id, obstacle] = value; + if ((from_id == SPECIAL_NODEID || from_id == from) && + (static_cast<uint16_t>(obstacle.type) & static_cast<uint16_t>(type))) + { + result.push_back(obstacle); + } + } + return result; // vector has move semantics + } + + std::vector<Obstacle> get(NodeID to) const + { + return get(SPECIAL_NODEID, to, Obstacle::Type::All); + } + + // is there any obstacle at node 'to'? + // inexpensive general test + bool any(NodeID to) const { return obstacles.contains(to); } + + // is there any obstacle of type 'type' at node 'to' when coming from node 'from'? + // pass SPECIAL_NODEID as 'from' to query all obstacles at 'to' + // 'type' can be a bitwise-or combination of Obstacle::Type + bool any(NodeID from, NodeID to, Obstacle::Type type = Obstacle::Type::All) const + { + return any(to) && !get(from, to, type).empty(); + } + + // Preprocess the obstacles + // + // For all unidirectional obstacles find the node that leads up to them. This + // function must be called while the vector 'node_ids' is still unsorted / + // uncompressed. + void preProcess(const NodeIDVector &, const WayNodeIDOffsets &); + + // Convert all external OSMNodeIDs into internal NodeIDs. + // + // This function must be called when the vector 'node_ids' is already sorted and + // compressed. Call this function once only. + void fixupNodes(const NodeIDVector &); + + // Replace a leading node that is going to be deleted during graph + // compression with the leading node of the leading node. + void compress(NodeID from, NodeID delendus, NodeID to); + + private: + // obstacles according to external id + tbb::concurrent_vector<OsmFromToObstacle> osm_obstacles; + + // obstacles according to internal id, with a leading node if unidirectional + // bidirectional obstacles are stored with a leading node id == SPECIAL_NODE_ID + std::unordered_multimap<NodeID, FromToObstacle> obstacles; +}; + +} // namespace osrm::extractor +#endif // OSRM_EXTRACTOR_OBSTACLES_DATA_HPP_ diff --git a/include/extractor/road_classification.hpp b/include/extractor/road_classification.hpp index 679e1d1f6ca..875e9036dad 100644 --- a/include/extractor/road_classification.hpp +++ b/include/extractor/road_classification.hpp @@ -99,7 +99,7 @@ class RoadClassification std::uint8_t GetNumberOfLanes() const { return number_of_lanes; } void SetNumberOfLanes(const std::uint8_t new_value) { number_of_lanes = new_value; } - std::uint32_t GetPriority() const { return static_cast<std::uint32_t>(road_priority_class); } + RoadPriorityClass::Enum GetPriority() const { return road_priority_class; } RoadPriorityClass::Enum GetClass() const { return road_priority_class; } void SetClass(const RoadPriorityClass::Enum new_value) { road_priority_class = new_value; } diff --git a/include/extractor/scripting_environment.hpp b/include/extractor/scripting_environment.hpp index 2a11afc33d1..662aea23527 100644 --- a/include/extractor/scripting_environment.hpp +++ b/include/extractor/scripting_environment.hpp @@ -3,6 +3,7 @@ #include "extractor/internal_extractor_edge.hpp" #include "extractor/maneuver_override.hpp" +#include "extractor/obstacles.hpp" #include "extractor/profile_properties.hpp" #include "extractor/restriction.hpp" @@ -72,6 +73,8 @@ class ScriptingEnvironment std::vector<InputManeuverOverride> &resulting_maneuver_overrides) = 0; virtual bool HasLocationDependentData() const = 0; + + ObstacleMap m_obstacle_map; // The obstacle map shared by all threads. }; } // namespace extractor } // namespace osrm diff --git a/include/extractor/traffic_lights.hpp b/include/extractor/traffic_lights.hpp deleted file mode 100644 index 1bb54bd91c3..00000000000 --- a/include/extractor/traffic_lights.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef OSRM_EXTRACTOR_TRAFFIC_LIGHTS_DATA_HPP_ -#define OSRM_EXTRACTOR_TRAFFIC_LIGHTS_DATA_HPP_ - -namespace osrm::extractor::TrafficLightClass -{ -// The traffic light annotation is extracted from node tags. -// The directions in which the traffic light applies are relative to the way containing the node. -enum Direction -{ - NONE = 0, - DIRECTION_ALL = 1, - DIRECTION_FORWARD = 2, - DIRECTION_REVERSE = 3 -}; -} // namespace osrm::extractor::TrafficLightClass - -#endif // OSRM_EXTRACTOR_TRAFFIC_LIGHTS_DATA_HPP_ diff --git a/include/extractor/traffic_signals.hpp b/include/extractor/traffic_signals.hpp deleted file mode 100644 index af0d3daeb19..00000000000 --- a/include/extractor/traffic_signals.hpp +++ /dev/null @@ -1,40 +0,0 @@ -#ifndef OSRM_EXTRACTOR_TRAFFIC_SIGNALS_HPP -#define OSRM_EXTRACTOR_TRAFFIC_SIGNALS_HPP - -#include "util/std_hash.hpp" -#include "util/typedefs.hpp" - -#include <unordered_set> -#include <utility> - -namespace osrm::extractor -{ - -struct TrafficSignals -{ - std::unordered_set<NodeID> bidirectional_nodes; - std::unordered_set<std::pair<NodeID, NodeID>> unidirectional_segments; - - inline bool HasSignal(NodeID from, NodeID to) const - { - return bidirectional_nodes.contains(to) || unidirectional_segments.contains({from, to}); - } - - void Compress(NodeID from, NodeID via, NodeID to) - { - bidirectional_nodes.erase(via); - if (unidirectional_segments.contains({via, to})) - { - unidirectional_segments.erase({via, to}); - unidirectional_segments.insert({from, to}); - } - if (unidirectional_segments.contains({via, from})) - { - unidirectional_segments.erase({via, from}); - unidirectional_segments.insert({to, from}); - } - } -}; -} // namespace osrm::extractor - -#endif // OSRM_EXTRACTOR_TRAFFIC_SIGNALS_HPP diff --git a/include/extractor/turn_path_compressor.hpp b/include/extractor/turn_path_compressor.hpp index 4a6bbea8987..e4e7f4da175 100644 --- a/include/extractor/turn_path_compressor.hpp +++ b/include/extractor/turn_path_compressor.hpp @@ -16,7 +16,7 @@ struct UnresolvedManeuverOverride; // OSRM stores turn paths as node -> [node] -> node instead of way -> node -> way (or // way->[way]->way) as it is done in OSM. These paths need to match the state of graph // compression which we perform in the graph compressor that removes certain degree two nodes from -// the graph (all but the ones with penalties/barriers, as of the state of writing). +// the graph (all but the ones with obstacles, as of the state of writing). // Since this graph compression is performed after creating the turn paths in the extraction // phase, we need to update the involved nodes whenever one of the nodes is compressed. // diff --git a/include/guidance/driveway_handler.hpp b/include/guidance/driveway_handler.hpp index a33cab9a863..81cc9a0daeb 100644 --- a/include/guidance/driveway_handler.hpp +++ b/include/guidance/driveway_handler.hpp @@ -15,7 +15,7 @@ class DrivewayHandler final : public IntersectionHandler const std::vector<util::Coordinate> &coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const extractor::RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, const extractor::NameTable &name_table, const extractor::SuffixTable &street_name_suffix_table); diff --git a/include/guidance/guidance_processing.hpp b/include/guidance/guidance_processing.hpp index e0aea1d5423..a95554120ac 100644 --- a/include/guidance/guidance_processing.hpp +++ b/include/guidance/guidance_processing.hpp @@ -7,6 +7,7 @@ #include "extractor/name_table.hpp" #include "extractor/node_data_container.hpp" #include "extractor/node_restriction_map.hpp" +#include "extractor/obstacles.hpp" #include "extractor/suffix_table.hpp" #include "extractor/turn_lane_types.hpp" #include "extractor/way_restriction_map.hpp" @@ -29,7 +30,7 @@ void annotateTurns(const util::NodeBasedDynamicGraph &node_based_graph, const extractor::EdgeBasedNodeDataContainer &edge_based_node_container, const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_edge_container, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::RestrictionMap &node_restriction_map, const extractor::WayRestrictionMap &way_restriction_map, const extractor::NameTable &name_table, diff --git a/include/guidance/intersection_handler.hpp b/include/guidance/intersection_handler.hpp index 2f657ee05ed..9cd130634fc 100644 --- a/include/guidance/intersection_handler.hpp +++ b/include/guidance/intersection_handler.hpp @@ -32,7 +32,7 @@ class IntersectionHandler const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const extractor::RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, const extractor::NameTable &name_table, const extractor::SuffixTable &street_name_suffix_table); @@ -53,7 +53,7 @@ class IntersectionHandler const std::vector<util::Coordinate> &node_coordinates; const extractor::CompressedEdgeContainer &compressed_geometries; const extractor::RestrictionMap &node_restriction_map; - const std::unordered_set<NodeID> &barrier_nodes; + const extractor::ObstacleMap &obstacle_nodes; const extractor::TurnLanesIndexedArray &turn_lanes_data; const extractor::NameTable &name_table; const extractor::SuffixTable &street_name_suffix_table; @@ -114,8 +114,8 @@ class IntersectionHandler NodeID node; // < node at this intersection }; - // Skips over artificial intersections i.e. traffic lights, barriers etc. - // Returns the next non-artificial intersection and its node in the node based + // Skips over a string of edges that could not be compressed because of obstacles. + // Returns the next intersection and its node in the node based // graph if an intersection could be found or none otherwise. // // a ... tl ... b .. c diff --git a/include/guidance/motorway_handler.hpp b/include/guidance/motorway_handler.hpp index 8f399156de1..bda5ffc71ce 100644 --- a/include/guidance/motorway_handler.hpp +++ b/include/guidance/motorway_handler.hpp @@ -23,7 +23,7 @@ class MotorwayHandler final : public IntersectionHandler const std::vector<util::Coordinate> &coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const extractor::RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, const extractor::NameTable &name_table, const extractor::SuffixTable &street_name_suffix_table); diff --git a/include/guidance/roundabout_handler.hpp b/include/guidance/roundabout_handler.hpp index 29fda3786f7..150f182226e 100644 --- a/include/guidance/roundabout_handler.hpp +++ b/include/guidance/roundabout_handler.hpp @@ -41,7 +41,7 @@ class RoundaboutHandler final : public IntersectionHandler const std::vector<util::Coordinate> &coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const extractor::RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, const extractor::NameTable &name_table, const extractor::SuffixTable &street_name_suffix_table); diff --git a/include/guidance/sliproad_handler.hpp b/include/guidance/sliproad_handler.hpp index 533ac4dcfb2..a7e43f3c66e 100644 --- a/include/guidance/sliproad_handler.hpp +++ b/include/guidance/sliproad_handler.hpp @@ -24,7 +24,7 @@ class SliproadHandler final : public IntersectionHandler const std::vector<util::Coordinate> &coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const extractor::RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, const extractor::NameTable &name_table, const extractor::SuffixTable &street_name_suffix_table); diff --git a/include/guidance/statistics_handler.hpp b/include/guidance/statistics_handler.hpp index f0e3401c70a..3e4123754fa 100644 --- a/include/guidance/statistics_handler.hpp +++ b/include/guidance/statistics_handler.hpp @@ -28,7 +28,7 @@ class StatisticsHandler final : public IntersectionHandler const std::vector<util::Coordinate> &coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const extractor::RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, const extractor::NameTable &name_table, const extractor::SuffixTable &street_name_suffix_table) @@ -37,7 +37,7 @@ class StatisticsHandler final : public IntersectionHandler coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, name_table, street_name_suffix_table) diff --git a/include/guidance/suppress_mode_handler.hpp b/include/guidance/suppress_mode_handler.hpp index 447a3fdb3b0..cf9acde18b9 100644 --- a/include/guidance/suppress_mode_handler.hpp +++ b/include/guidance/suppress_mode_handler.hpp @@ -22,7 +22,7 @@ class SuppressModeHandler final : public IntersectionHandler const std::vector<util::Coordinate> &coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const extractor::RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, const extractor::NameTable &name_table, const extractor::SuffixTable &street_name_suffix_table); diff --git a/include/guidance/turn_analysis.hpp b/include/guidance/turn_analysis.hpp index 56a3e5804bc..704ef007dce 100644 --- a/include/guidance/turn_analysis.hpp +++ b/include/guidance/turn_analysis.hpp @@ -33,7 +33,7 @@ class TurnAnalysis const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_edge_container, const extractor::RestrictionMap &restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, const extractor::NameTable &name_table, const extractor::SuffixTable &street_name_suffix_table); diff --git a/include/guidance/turn_discovery.hpp b/include/guidance/turn_discovery.hpp index 67aaa1259c2..d354e5ee9b8 100644 --- a/include/guidance/turn_discovery.hpp +++ b/include/guidance/turn_discovery.hpp @@ -2,6 +2,7 @@ #define OSRM_GUIDANCE_TURN_DISCOVERY_HPP_ #include "extractor/node_restriction_map.hpp" +#include "extractor/obstacles.hpp" #include "guidance/intersection.hpp" #include "guidance/turn_lane_data.hpp" #include "util/typedefs.hpp" @@ -35,7 +36,7 @@ bool findPreviousIntersection( const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const extractor::RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, // output parameters, will be in an arbitrary state on failure NodeID &result_node, diff --git a/include/guidance/turn_handler.hpp b/include/guidance/turn_handler.hpp index 5d4348cab4a..e2ac0564e25 100644 --- a/include/guidance/turn_handler.hpp +++ b/include/guidance/turn_handler.hpp @@ -26,7 +26,7 @@ class TurnHandler final : public IntersectionHandler const std::vector<util::Coordinate> &coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const extractor::RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, const extractor::NameTable &name_table, const extractor::SuffixTable &street_name_suffix_table); diff --git a/include/guidance/turn_lane_handler.hpp b/include/guidance/turn_lane_handler.hpp index b7c9e1a042b..53791a02f98 100644 --- a/include/guidance/turn_lane_handler.hpp +++ b/include/guidance/turn_lane_handler.hpp @@ -57,7 +57,7 @@ class TurnLaneHandler const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const extractor::RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, extractor::LaneDescriptionMap &lane_description_map, const TurnAnalysis &turn_analysis, @@ -78,7 +78,7 @@ class TurnLaneHandler const std::vector<util::Coordinate> &node_coordinates; const extractor::CompressedEdgeContainer &compressed_geometries; const extractor::RestrictionMap &node_restriction_map; - const std::unordered_set<NodeID> &barrier_nodes; + const extractor::ObstacleMap &obstacle_nodes; const extractor::TurnLanesIndexedArray &turn_lanes_data; std::vector<std::uint32_t> turn_lane_offsets; diff --git a/profiles/bicycle.lua b/profiles/bicycle.lua index 2c701e218b3..76335155365 100644 --- a/profiles/bicycle.lua +++ b/profiles/bicycle.lua @@ -17,7 +17,7 @@ function setup() return { properties = { u_turn_penalty = 20, - traffic_light_penalty = 2, + traffic_signal_penalty = 2, --weight_name = 'cyclability', weight_name = 'duration', process_call_tagless_node = false, @@ -706,7 +706,7 @@ function process_turn(profile, turn) end if turn.has_traffic_light then - turn.duration = turn.duration + profile.properties.traffic_light_penalty + turn.duration = turn.duration + profile.properties.traffic_signal_penalty end if profile.properties.weight_name == 'cyclability' then turn.weight = turn.duration diff --git a/profiles/car.lua b/profiles/car.lua index 24079bfaae0..35b4178d9cd 100644 --- a/profiles/car.lua +++ b/profiles/car.lua @@ -6,7 +6,7 @@ Set = require('lib/set') Sequence = require('lib/sequence') Handlers = require("lib/way_handlers") Relations = require("lib/relations") -TrafficSignal = require("lib/traffic_signal") +Obstacles = require("lib/obstacles") find_access_tag = require("lib/access").find_access_tag limit = require("lib/maxspeed").limit Utils = require("lib/utils") @@ -27,7 +27,6 @@ function setup() continue_straight_at_waypoint = true, use_turn_restrictions = true, left_hand_driving = false, - traffic_light_penalty = 2, }, default_mode = mode.driving, @@ -333,7 +332,7 @@ function process_node(profile, node, result, relations) local access = find_access_tag(node, profile.access_tags_hierarchy) if access then if profile.access_tag_blacklist[access] and not profile.restricted_access_tag_list[access] then - result.barrier = true + obstacle_map:add(node, Obstacle.new(obstacle_type.barrier)) end else local barrier = node:get_value_by_key("barrier") @@ -361,13 +360,12 @@ function process_node(profile, node, result, relations) and not flat_kerb and not highway_crossing_kerb or restricted_by_height then - result.barrier = true + obstacle_map:add(node, Obstacle.new(obstacle_type.barrier)) end end end - -- check if node is a traffic light - result.traffic_lights = TrafficSignal.get_value(node) + Obstacles.process_node(profile, node) end function process_way(profile, way, result, relations) @@ -476,8 +474,24 @@ function process_turn(profile, turn) local turn_penalty = profile.turn_penalty local turn_bias = turn.is_left_hand_driving and 1. / profile.turn_bias or profile.turn_bias - if turn.has_traffic_light then - turn.duration = profile.properties.traffic_light_penalty + for _, obs in pairs(obstacle_map:get(turn.from, turn.via)) do + -- disregard a minor stop if entering by the major road + -- rationale: if a stop sign is tagged at the center of the intersection with stop=minor + -- it should only penalize the minor roads entering the intersection + if obs.type == obstacle_type.stop_minor and not Obstacles.entering_by_minor_road(turn) then + goto skip + end + -- heuristic to infer the direction of a stop without an explicit direction tag + -- rationale: a stop sign should not be placed farther than 20m from the intersection + if turn.number_of_roads == 2 + and obs.type == obstacle_type.stop + and obs.direction == obstacle_direction.none + and turn.source_road.distance < 20 + and turn.target_road.distance > 20 then + goto skip + end + turn.duration = turn.duration + obs.duration + ::skip:: end if turn.number_of_roads > 2 or turn.source_mode ~= turn.target_mode or turn.is_u_turn then diff --git a/profiles/foot.lua b/profiles/foot.lua index fa5f8b6634f..b0a97127210 100644 --- a/profiles/foot.lua +++ b/profiles/foot.lua @@ -14,7 +14,7 @@ function setup() weight_name = 'duration', max_speed_for_map_matching = 40/3.6, -- kmph -> m/s call_tagless_node_function = false, - traffic_light_penalty = 2, + traffic_signal_penalty = 2, u_turn_penalty = 2, continue_straight_at_waypoint = false, use_turn_restrictions = false, @@ -252,7 +252,7 @@ function process_turn (profile, turn) end if turn.has_traffic_light then - turn.duration = profile.properties.traffic_light_penalty + turn.duration = profile.properties.traffic_signal_penalty end if profile.properties.weight_name == 'routability' then -- penalize turns from non-local access only segments onto local access only tags diff --git a/profiles/lib/obstacles.lua b/profiles/lib/obstacles.lua new file mode 100644 index 00000000000..a2ba2ca4aa7 --- /dev/null +++ b/profiles/lib/obstacles.lua @@ -0,0 +1,53 @@ +-- Assigns obstacle value to nodes as defined by +-- include/extractor/obstacles.hpp + +local Obstacles = {} + +-- process the obstacles at the given node +-- note: does not process barriers +function Obstacles.process_node(profile, node) + local highway = node:get_value_by_key("highway") + if highway then + local type = obstacle_type[highway] + -- barriers already handled in car.lua + if type and type ~= obstacle_type.barrier then + local direction = node:get_value_by_key("direction") + local weight = 0 + local duration = 0 + local minor = false + + if type == obstacle_type.traffic_signals then + -- traffic_signals:direction trumps direction + direction = node:get_value_by_key("traffic_signals:direction") or direction + -- traffic_signal_penalty is deprecated + -- but there's still unit_tests using it + duration = profile.properties.traffic_signal_penalty or 2 + end + if type == obstacle_type.stop then + if node:get_value_by_key("stop") == "minor" then + type = obstacle_type.stop_minor + end + duration = 2 + end + if type == obstacle_type.give_way then + duration = 1 + end + obstacle_map:add(node, Obstacle.new(type, obstacle_direction[direction] or obstacle_direction.none, duration, weight)) + end + end +end + +-- return true if the source road of this turn is a minor road at the intersection +function Obstacles.entering_by_minor_road(turn) + -- implementation: comparing road speeds (anybody has a better idea?) + local max_speed = turn.target_speed + for _, turn_leg in pairs(turn.roads_on_the_right) do + max_speed = math.max(max_speed, turn_leg.speed) + end + for _, turn_leg in pairs(turn.roads_on_the_left) do + max_speed = math.max(max_speed, turn_leg.speed) + end + return max_speed > turn.source_speed +end + +return Obstacles diff --git a/profiles/testbot.lua b/profiles/testbot.lua index a796be21ff5..aabc028a46c 100644 --- a/profiles/testbot.lua +++ b/profiles/testbot.lua @@ -15,8 +15,8 @@ function setup() max_speed_for_map_matching = 30/3.6, --km -> m/s weight_name = 'duration', process_call_tagless_node = false, - u_turn_penalty = 20, - traffic_light_penalty = 7, -- seconds + u_turn_penalty = 20, + traffic_signal_penalty = 7, -- seconds use_turn_restrictions = true }, @@ -131,7 +131,7 @@ function process_turn (profile, turn) turn.weight = turn.weight + profile.properties.u_turn_penalty end if turn.has_traffic_light then - turn.duration = turn.duration + profile.properties.traffic_light_penalty + turn.duration = turn.duration + profile.properties.traffic_signal_penalty end end diff --git a/scripts/check_taginfo.py b/scripts/check_taginfo.py index c71b46882e3..2e664799f40 100755 --- a/scripts/check_taginfo.py +++ b/scripts/check_taginfo.py @@ -19,10 +19,12 @@ valid_strings = [t["key"] for t in taginfo["tags"]] valid_strings += [t["value"] for t in taginfo["tags"] if "value" in t] -valid_strings += [t["value"].lower() for t in taginfo["tags"] if "value" in t] # lower is for max speed +valid_strings += [ + t["value"].lower() for t in taginfo["tags"] if "value" in t +] # lower is for max speed valid_strings = set(valid_strings) -string_regxp = re.compile("\"([\d\w\_:]+)\"") +string_regxp = re.compile(r"\"([\d\w\_:]+)\"") profile = None with open(profile_path) as f: @@ -40,7 +42,7 @@ errors = [] for token in tokens: if token not in WHITELIST and token not in valid_strings: - idx = line.find("\""+token+"\"") + idx = line.find('"' + token + '"') errors.append((idx, token)) errors = sorted(errors) n_errors += len(errors) @@ -49,7 +51,7 @@ offset = len(prefix) for idx, token in errors: sys.stdout.write(prefix + line) - marker = " "*(idx+offset) + "~"*(len(token)+2) + marker = " " * (idx + offset) + "~" * (len(token) + 2) print(marker) if n_errors > 0: diff --git a/src/extractor/edge_based_graph_factory.cpp b/src/extractor/edge_based_graph_factory.cpp index b5ab53e25c7..2a447a2741f 100644 --- a/src/extractor/edge_based_graph_factory.cpp +++ b/src/extractor/edge_based_graph_factory.cpp @@ -39,16 +39,13 @@ EdgeBasedGraphFactory::EdgeBasedGraphFactory( const util::NodeBasedDynamicGraph &node_based_graph, EdgeBasedNodeDataContainer &node_data_container, const CompressedEdgeContainer &compressed_edge_container, - const std::unordered_set<NodeID> &barrier_nodes, - const TrafficSignals &traffic_signals, const std::vector<util::Coordinate> &coordinates, const NameTable &name_table, const std::unordered_set<EdgeID> &segregated_edges, const extractor::LaneDescriptionMap &lane_description_map) : 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_node_based_graph(node_based_graph), m_compressed_edge_container(compressed_edge_container), name_table(name_table), segregated_edges(segregated_edges), lane_description_map(lane_description_map) { @@ -492,7 +489,7 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( m_coordinates, m_compressed_edge_container, unconditional_node_restriction_map, - m_barrier_nodes, + scripting_environment.m_obstacle_map, turn_lanes_data, name_table, street_name_suffix_table); @@ -585,76 +582,88 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( } }); + // connected_roads.begin() + // turn // Generate edges for either artificial nodes or the main graph - const auto generate_edge = [this, &scripting_environment, weight_multiplier]( - // what nodes will be used? In most cases this will be the id - // stored in the edge_data. In case of duplicated nodes (e.g. - // due to via-way restrictions), one/both of these might - // refer to a newly added edge based node - const auto edge_based_node_from, - const auto edge_based_node_to, - // the situation of the turn - const auto node_along_road_entering, - const auto node_based_edge_from, - const auto intersection_node, - const auto node_based_edge_to, - const auto &turn_angle, - const auto &road_legs_on_the_right, - const auto &road_legs_on_the_left, - const auto &edge_geometries) + const auto generate_edge = + [this, &scripting_environment, weight_multiplier]( + // what nodes will be used? In most cases this will be the id + // stored in the edge_data. In case of duplicated nodes (e.g. + // due to via-way restrictions), one/both of these might + // refer to a newly added edge based node + const NodeID edge_based_node_from, + const NodeID edge_based_node_to, + // the situation of the turn + const NodeID node_along_road_entering, + const EdgeID node_based_edge_from, + const NodeID intersection_node, + const EdgeID node_based_edge_to, + const double &turn_angle, + const ExtractionTurnLeg &incoming_road_leg, + const ExtractionTurnLeg &outgoing_road_leg, + const std::vector<ExtractionTurnLeg> &road_legs_on_the_right, + const std::vector<ExtractionTurnLeg> &road_legs_on_the_left, + const intersection::IntersectionEdgeGeometries &edge_geometries) -> EdgeWithData { const auto &edge_data1 = m_node_based_graph.GetEdgeData(node_based_edge_from); const auto &edge_data2 = m_node_based_graph.GetEdgeData(node_based_edge_to); + const NodeID node_along_road_exiting = m_node_based_graph.GetTarget(node_based_edge_to); + BOOST_ASSERT(nbe_to_ebn_mapping[node_based_edge_from] != nbe_to_ebn_mapping[node_based_edge_to]); BOOST_ASSERT(!edge_data1.reversed); BOOST_ASSERT(!edge_data2.reversed); // compute weight and duration penalties - // 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(node_along_road_entering, intersection_node); - const auto is_uturn = + // In theory we shouldn't get a directed obstacle on a turn, as it indicates that + // the obstacle direction was potentially ambiguously annotated on the junction + // node. But we'll check anyway. + const bool is_traffic_light = scripting_environment.m_obstacle_map.any( + node_along_road_entering, intersection_node, Obstacle::Type::TrafficSignals); + const bool is_uturn = guidance::getTurnDirection(turn_angle) == guidance::DirectionModifier::UTurn; - ExtractionTurn extracted_turn( + ExtractionTurn extracted_turn{ // general info turn_angle, - road_legs_on_the_right.size() + road_legs_on_the_left.size() + 2 - is_uturn, + static_cast<int>(road_legs_on_the_right.size() + road_legs_on_the_left.size() + 2 - + is_uturn), is_uturn, is_traffic_light, m_edge_based_node_container.GetAnnotation(edge_data1.annotation_data) .is_left_hand_driving, // source info - edge_data1.flags.restricted, + edge_data1.flags.IsRestricted(), m_edge_based_node_container.GetAnnotation(edge_data1.annotation_data).travel_mode, edge_data1.flags.road_classification.IsMotorwayClass(), edge_data1.flags.road_classification.IsLinkClass(), edge_data1.flags.road_classification.GetNumberOfLanes(), edge_data1.flags.highway_turn_classification, edge_data1.flags.access_turn_classification, - ((double)intersection::findEdgeLength(edge_geometries, node_based_edge_from) / - from_alias<double>(edge_data1.duration)) * - 36, + static_cast<int>( + intersection::findEdgeLength(edge_geometries, node_based_edge_from) / + from_alias<double>(edge_data1.duration) * 36.0), edge_data1.flags.road_classification.GetPriority(), // target info - edge_data2.flags.restricted, + edge_data2.flags.IsRestricted(), m_edge_based_node_container.GetAnnotation(edge_data2.annotation_data).travel_mode, edge_data2.flags.road_classification.IsMotorwayClass(), edge_data2.flags.road_classification.IsLinkClass(), edge_data2.flags.road_classification.GetNumberOfLanes(), edge_data2.flags.highway_turn_classification, edge_data2.flags.access_turn_classification, - ((double)intersection::findEdgeLength(edge_geometries, node_based_edge_to) / - from_alias<double>(edge_data2.duration)) * - 36, + static_cast<int>(intersection::findEdgeLength(edge_geometries, node_based_edge_to) / + from_alias<double>(edge_data2.duration) * 36.0), edge_data2.flags.road_classification.GetPriority(), // connected roads + incoming_road_leg, + outgoing_road_leg, road_legs_on_the_right, - road_legs_on_the_left); + road_legs_on_the_left, + node_along_road_entering, + intersection_node, + node_along_road_exiting}; scripting_environment.ProcessTurn(extracted_turn); @@ -718,8 +727,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( auto buffer = std::make_shared<EdgesPipelineBuffer>(); buffer->nodes_processed = intersection_node_range.size(); - for (auto intersection_node = intersection_node_range.begin(), - end = intersection_node_range.end(); + for (NodeID intersection_node = intersection_node_range.begin(), + end = intersection_node_range.end(); intersection_node < end; ++intersection_node) { @@ -761,32 +770,32 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( // an outgoing edge. Therefore, we have to search all connected edges for edges // entering `b` - for (const auto &incoming_edge : incoming_edges) + for (const intersection::IntersectionEdge &incoming_edge : incoming_edges) { ++node_based_edge_counter; - const auto connected_roads = - extractor::intersection::getConnectedRoadsForEdgeGeometries( + const intersection::IntersectionView connected_roads = + intersection::getConnectedRoadsForEdgeGeometries( m_node_based_graph, m_edge_based_node_container, unconditional_node_restriction_map, - m_barrier_nodes, + scripting_environment.m_obstacle_map, turn_lanes_data, incoming_edge, edge_geometries, merged_edge_ids); // check if this edge is part of a restriction via-way - const auto is_restriction_via_edge = + const bool is_restriction_via_edge = way_restriction_map.IsViaWayEdge(incoming_edge.node, intersection_node); - for (const auto &outgoing_edge : outgoing_edges) + for (const intersection::IntersectionEdge &outgoing_edge : outgoing_edges) { - auto is_turn_allowed = + const bool is_turn_allowed = intersection::isTurnAllowed(m_node_based_graph, m_edge_based_node_container, unconditional_node_restriction_map, - m_barrier_nodes, + scripting_environment.m_obstacle_map, edge_geometries, turn_lanes_data, incoming_edge, @@ -804,10 +813,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( OSRM_ASSERT(turn != connected_roads.end(), m_coordinates[intersection_node]); - std::vector<ExtractionTurnLeg> road_legs_on_the_right; - std::vector<ExtractionTurnLeg> road_legs_on_the_left; - - auto get_connected_road_info = [&](const auto &connected_edge) + auto get_connected_road_info = + [&](const auto &connected_edge) -> ExtractionTurnLeg { const auto &edge_data = m_node_based_graph.GetEdgeData(connected_edge.eid); @@ -841,23 +848,30 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( is_outgoing = true; } + double distance = intersection::findEdgeLength(edge_geometries, + connected_edge.eid); - return ExtractionTurnLeg( - edge_data.flags.restricted, + return ExtractionTurnLeg{ + edge_data.flags.IsRestricted(), edge_data.flags.road_classification.IsMotorwayClass(), edge_data.flags.road_classification.IsLinkClass(), edge_data.flags.road_classification.GetNumberOfLanes(), edge_data.flags.highway_turn_classification, edge_data.flags.access_turn_classification, - ((double)intersection::findEdgeLength(edge_geometries, - connected_edge.eid) / - from_alias<double>(edge_data.duration)) * - 36, + static_cast<int>(36.0 * distance / + from_alias<double>(edge_data.duration)), + distance, edge_data.flags.road_classification.GetPriority(), is_incoming, - is_outgoing); + is_outgoing}; }; + ExtractionTurnLeg incoming_road_leg = + get_connected_road_info(connected_roads[0]); + ExtractionTurnLeg outgoing_road_leg = get_connected_road_info(*turn); + std::vector<ExtractionTurnLeg> road_legs_on_the_right; + std::vector<ExtractionTurnLeg> road_legs_on_the_left; + // all connected roads on the right of a u turn const auto is_uturn = guidance::getTurnDirection(turn->angle) == guidance::DirectionModifier::UTurn; @@ -959,6 +973,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( outgoing_edge.node, outgoing_edge.edge, turn->angle, + incoming_road_leg, + outgoing_road_leg, road_legs_on_the_right, road_legs_on_the_left, edge_geometries); @@ -1039,6 +1055,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( outgoing_edge.node, outgoing_edge.edge, turn->angle, + incoming_road_leg, + outgoing_road_leg, road_legs_on_the_right, road_legs_on_the_left, edge_geometries); @@ -1090,6 +1108,8 @@ void EdgeBasedGraphFactory::GenerateEdgeExpandedEdges( outgoing_edge.node, outgoing_edge.edge, turn->angle, + incoming_road_leg, + outgoing_road_leg, road_legs_on_the_right, road_legs_on_the_left, edge_geometries); diff --git a/src/extractor/extraction_containers.cpp b/src/extractor/extraction_containers.cpp index 9445c7c252b..879bb1bebea 100644 --- a/src/extractor/extraction_containers.cpp +++ b/src/extractor/extraction_containers.cpp @@ -395,7 +395,9 @@ ExtractionContainers::ExtractionContainers() /** * Processes the collected data and serializes it. - * At this point nodes are still referenced by their OSM id. + * + * In this function the nodes will eventually be converted from their 64bit OSM id to the + * internal 32bit OSRM id. * * - Identify nodes of ways used in restrictions and maneuver overrides * - Filter nodes list to nodes that are referenced by ways @@ -408,12 +410,12 @@ void ExtractionContainers::PrepareData(ScriptingEnvironment &scripting_environme { const auto restriction_ways = IdentifyRestrictionWays(); const auto maneuver_override_ways = IdentifyManeuverOverrideWays(); - const auto traffic_signals = IdentifyTrafficSignals(); + scripting_environment.m_obstacle_map.preProcess(used_node_id_list, way_node_id_offsets); PrepareNodes(); PrepareEdges(scripting_environment); + scripting_environment.m_obstacle_map.fixupNodes(used_node_id_list); - PrepareTrafficSignals(traffic_signals); PrepareManeuverOverrides(maneuver_override_ways); PrepareRestrictions(restriction_ways); WriteCharData(name_file_name); @@ -545,22 +547,6 @@ void ExtractionContainers::PrepareNodes() log << "ok, after " << TIMER_SEC(write_nodes) << "s"; } - { - util::UnbufferedLog log; - log << "Writing barrier nodes ... "; - TIMER_START(write_nodes); - for (const auto osm_id : barrier_nodes) - { - const auto node_id = mapExternalToInternalNodeID( - used_node_id_list.begin(), used_node_id_list.end(), osm_id); - if (node_id != SPECIAL_NODEID) - { - used_barrier_nodes.emplace(node_id); - } - } - log << "ok, after " << TIMER_SEC(write_nodes) << "s"; - } - util::Log() << "Processed " << max_internal_node_id << " nodes"; } @@ -940,49 +926,6 @@ 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>> 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) @@ -1169,97 +1112,6 @@ 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) { diff --git a/src/extractor/extractor.cpp b/src/extractor/extractor.cpp index 80b327e7179..389d22bcae4 100644 --- a/src/extractor/extractor.cpp +++ b/src/extractor/extractor.cpp @@ -176,7 +176,7 @@ std::vector<CompressedNodeBasedGraphEdge> toEdgeList(const util::NodeBasedDynami * That includes: * - extracting turn restrictions * - splitting ways into (directional!) edge segments - * - checking if nodes are barriers or traffic signal + * - checking if nodes are obstacles, that must be kept * - discarding all tag information: All relevant type information for nodes/ways * is extracted at this point. * @@ -218,8 +218,6 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) NodeBasedGraphFactory node_based_graph_factory(scripting_environment, parsed_osm_data.turn_restrictions, parsed_osm_data.unresolved_maneuver_overrides, - parsed_osm_data.traffic_signals, - std::move(parsed_osm_data.barriers), std::move(parsed_osm_data.osm_coordinates), std::move(parsed_osm_data.osm_node_ids), parsed_osm_data.edge_list, @@ -257,7 +255,6 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) node_based_graph_factory.GetCompressedEdges().PrintStatistics(); - const auto &barrier_nodes = node_based_graph_factory.GetBarriers(); // stealing the annotation data from the node-based graph edge_based_nodes_container = EdgeBasedNodeDataContainer({}, std::move(node_based_graph_factory.GetAnnotationData())); @@ -274,8 +271,6 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) BuildEdgeExpandedGraph(node_based_graph, coordinates, node_based_graph_factory.GetCompressedEdges(), - barrier_nodes, - parsed_osm_data.traffic_signals, restriction_graph, segregated_edges, name_table, @@ -294,7 +289,6 @@ int Extractor::run(ScriptingEnvironment &scripting_environment) edge_based_nodes_container, coordinates, node_based_graph_factory.GetCompressedEdges(), - barrier_nodes, restriction_graph, name_table, std::move(parsed_osm_data.turn_lane_map), @@ -505,6 +499,7 @@ Extractor::ParsedOSMData Extractor::ParseOSMData(ScriptingEnvironment &scripting { extractor_callbacks->ProcessNode(result.first, result.second); } + number_of_ways += parsed_buffer.resulting_ways.size(); for (const auto &result : parsed_buffer.resulting_ways) { @@ -651,8 +646,6 @@ Extractor::ParsedOSMData Extractor::ParseOSMData(ScriptingEnvironment &scripting return ParsedOSMData{std::move(turn_lane_map), std::move(extraction_containers.turn_restrictions), std::move(extraction_containers.internal_maneuver_overrides), - std::move(extraction_containers.internal_traffic_signals), - std::move(extraction_containers.used_barrier_nodes), std::move(osm_coordinates), std::move(osm_node_ids), std::move(extraction_containers.used_edges), @@ -726,8 +719,6 @@ EdgeID Extractor::BuildEdgeExpandedGraph( const util::NodeBasedDynamicGraph &node_based_graph, const std::vector<util::Coordinate> &coordinates, const CompressedEdgeContainer &compressed_edge_container, - const std::unordered_set<NodeID> &barrier_nodes, - const TrafficSignals &traffic_signals, const RestrictionGraph &restriction_graph, const std::unordered_set<EdgeID> &segregated_edges, const NameTable &name_table, @@ -747,8 +738,6 @@ EdgeID Extractor::BuildEdgeExpandedGraph( EdgeBasedGraphFactory edge_based_graph_factory(node_based_graph, edge_based_nodes_container, compressed_edge_container, - barrier_nodes, - traffic_signals, coordinates, name_table, segregated_edges, @@ -836,7 +825,6 @@ void Extractor::ProcessGuidanceTurns( const extractor::EdgeBasedNodeDataContainer &edge_based_node_container, const std::vector<util::Coordinate> &node_coordinates, const CompressedEdgeContainer &compressed_edge_container, - const std::unordered_set<NodeID> &barrier_nodes, const RestrictionGraph &restriction_graph, const NameTable &name_table, LaneDescriptionMap lane_description_map, @@ -863,7 +851,7 @@ void Extractor::ProcessGuidanceTurns( edge_based_node_container, node_coordinates, compressed_edge_container, - barrier_nodes, + scripting_environment.m_obstacle_map, unconditional_node_restriction_map, way_restriction_map, name_table, diff --git a/src/extractor/extractor_callbacks.cpp b/src/extractor/extractor_callbacks.cpp index 5e47f15e3c6..b89ce671040 100644 --- a/src/extractor/extractor_callbacks.cpp +++ b/src/extractor/extractor_callbacks.cpp @@ -41,10 +41,9 @@ ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers &extraction_containe std::unordered_map<std::string, ClassData> &classes_map, LaneDescriptionMap &lane_description_map, const ProfileProperties &properties) - : external_memory(extraction_containers_), classes_map(classes_map), - lane_description_map(lane_description_map), + : classes_map(classes_map), lane_description_map(lane_description_map), fallback_to_duration(properties.fallback_to_duration), - force_split_edges(properties.force_split_edges) + force_split_edges(properties.force_split_edges), external_memory(extraction_containers_) { // we reserved 0, 1, 2, 3, 4 for the empty case string_map[MapKey("", "", "", "", "")] = 0; @@ -57,24 +56,13 @@ ExtractorCallbacks::ExtractorCallbacks(ExtractionContainers &extraction_containe * * warning: caller needs to take care of synchronization! */ -void ExtractorCallbacks::ProcessNode(const osmium::Node &input_node, - const ExtractionNode &result_node) +void ExtractorCallbacks::ProcessNode(const osmium::Node &input_node, const ExtractionNode &) { - const auto id = OSMNodeID{static_cast<std::uint64_t>(input_node.id())}; - + const auto id = to_alias<OSMNodeID>(input_node.id()); external_memory.all_nodes_list.push_back( QueryNode{util::toFixed(util::UnsafeFloatLongitude{input_node.location().lon()}), util::toFixed(util::UnsafeFloatLatitude{input_node.location().lat()}), id}); - - if (result_node.barrier) - { - external_memory.barrier_nodes.push_back(id); - } - if (result_node.traffic_lights != TrafficLightClass::NONE) - { - external_memory.external_traffic_signals.push_back({id, result_node.traffic_lights}); - } } void ExtractorCallbacks::ProcessRestriction(const InputTurnRestriction &restriction) diff --git a/src/extractor/graph_compressor.cpp b/src/extractor/graph_compressor.cpp index 931668f2676..b410b4ab3e2 100644 --- a/src/extractor/graph_compressor.cpp +++ b/src/extractor/graph_compressor.cpp @@ -19,9 +19,7 @@ namespace osrm::extractor static constexpr int SECOND_TO_DECISECOND = 10; -void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes, - TrafficSignals &traffic_signals, - ScriptingEnvironment &scripting_environment, +void GraphCompressor::Compress(ScriptingEnvironment &scripting_environment, std::vector<TurnRestriction> &turn_restrictions, std::vector<UnresolvedManeuverOverride> &maneuver_overrides, util::NodeBasedDynamicGraph &graph, @@ -30,6 +28,7 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes, { const unsigned original_number_of_nodes = graph.GetNumberOfNodes(); const unsigned original_number_of_edges = graph.GetNumberOfEdges(); + const std::vector<ExtractionTurnLeg> no_other_roads; TurnPathCompressor turn_path_compressor(turn_restrictions, maneuver_overrides); @@ -76,8 +75,9 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes, continue; } - // don't contract barrier node - if (barrier_nodes.end() != barrier_nodes.find(node_v)) + // don't compress nodes with these obstacle types + if (scripting_environment.m_obstacle_map.any( + SPECIAL_NODEID, node_v, Obstacle::Type::Incompressible)) { continue; } @@ -160,8 +160,7 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes, graph.GetEdgeData(reverse_e1).reversed)); /* * Remember Lane Data for compressed parts. This handles scenarios where lane-data - * is - * only kept up until a traffic light. + * is only kept up until a traffic light. * * | | * ---------------- | @@ -173,17 +172,14 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes, * * u ------- v ---- w * - * Since the edge is compressable, we can transfer: - * "left|right" (uv) and "" (uw) into a string with "left|right" (uw) for the - * compressed - * edge. - * Doing so, we might mess up the point from where the lanes are shown. It should be - * reasonable, since the announcements have to come early anyhow. So there is a - * potential danger in here, but it saves us from adding a lot of additional edges - * for - * turn-lanes. Without this, we would have to treat any turn-lane beginning/ending - * just - * like a barrier. + * Since the edge is compressible, we can transfer: "left|right" (uv) + * and "" (uw) into a string with "left|right" (uw) for the compressed + * edge. Doing so, we might mess up the point from where the lanes are + * shown. It should be reasonable, since the announcements have to come + * early anyhow. So there is a potential danger in here, but it saves us + * from adding a lot of additional edges for turn-lanes. Without this, + * we would have to treat any turn-lane beginning or ending just like an + * obstacle. */ const auto selectAnnotation = [&node_data_container](const AnnotationID front_annotation, @@ -208,70 +204,9 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes, graph.GetEdgeData(reverse_e2).annotation_data = selectAnnotation( rev_edge_data2.annotation_data, rev_edge_data1.annotation_data); - // Add node penalty when compress edge crosses a traffic signal - 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 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, - 2, - false, - true, - false, - false, - TRAVEL_MODE_DRIVING, - false, - false, - 1, - 0, - 0, - 0, - 0, - false, - TRAVEL_MODE_DRIVING, - false, - false, - 1, - 0, - 0, - 0, - 0, - roads_on_the_right, - roads_on_the_left); - scripting_environment.ProcessTurn(extraction_turn); - - auto update_direction_penalty = - [&extraction_turn, weight_multiplier]( - bool signal, EdgeDuration &duration_penalty, EdgeWeight &weight_penalty) - { - if (signal) - { - duration_penalty = to_alias<EdgeDuration>(extraction_turn.duration * - SECOND_TO_DECISECOND); - weight_penalty = - to_alias<EdgeWeight>(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); - } + // 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; // Get weights before graph is modified const auto forward_weight1 = fwd_edge_data1.weight; @@ -302,33 +237,60 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes, BOOST_ASSERT(EdgeWeight{0} != reverse_weight1); BOOST_ASSERT(EdgeWeight{0} != reverse_weight2); - auto apply_e2_to_e1 = [&graph](EdgeID edge1, - EdgeID edge2, - EdgeWeight &weight_penalty, - EdgeDuration &duration_penalty) + struct EdgePenalties { - auto &edge1_data = graph.GetEdgeData(edge1); - const auto &edge2_data = graph.GetEdgeData(edge2); - edge1_data.weight += edge2_data.weight; - edge1_data.duration += edge2_data.duration; - edge1_data.distance += edge2_data.distance; - if (weight_penalty != INVALID_EDGE_WEIGHT && - duration_penalty != MAXIMAL_EDGE_DURATION) - { - edge1_data.weight += weight_penalty; - edge1_data.duration += duration_penalty; - // Note: no penalties for distances - } + EdgeDuration duration; + EdgeWeight weight; + }; + + auto update_edge = + [](EdgeData &to, const EdgeData &from, const EdgePenalties &penalties) + { + to.weight += from.weight; + to.duration += from.duration; + to.distance += from.distance; + to.weight += penalties.weight; + to.duration += penalties.duration; + }; + + // Add the obstacle's penalties to the edge when compressing an edge with + // an obstacle + auto get_obstacle_penalty = [&scripting_environment, + weight_multiplier, + no_other_roads](const NodeID from, + const NodeID via, + const NodeID to, + const EdgeData &from_edge, + const EdgeData &to_edge, + EdgePenalties &penalties) + { + // generate an artificial turn for the turn penalty generation + ExtractionTurn fake_turn{ + from, via, to, from_edge, to_edge, no_other_roads, no_other_roads}; + scripting_environment.ProcessTurn(fake_turn); + penalties.duration += + to_alias<EdgeDuration>(fake_turn.duration * SECOND_TO_DECISECOND); + penalties.weight += to_alias<EdgeWeight>(fake_turn.weight * weight_multiplier); }; - apply_e2_to_e1(forward_e1, - forward_e2, - forward_node_weight_penalty, - forward_node_duration_penalty); - apply_e2_to_e1(reverse_e1, - reverse_e2, - reverse_node_weight_penalty, - reverse_node_duration_penalty); + auto &f1_data = graph.GetEdgeData(forward_e1); + auto &b1_data = graph.GetEdgeData(reverse_e1); + const auto &f2_data = graph.GetEdgeData(forward_e2); + const auto &b2_data = graph.GetEdgeData(reverse_e2); + + EdgePenalties forward_penalties{{0}, {0}}; + EdgePenalties backward_penalties{{0}, {0}}; + + if (scripting_environment.m_obstacle_map.any(node_v)) + { + get_obstacle_penalty( + node_u, node_v, node_w, f1_data, f2_data, forward_penalties); + get_obstacle_penalty( + node_w, node_v, node_u, b1_data, b2_data, backward_penalties); + } + + update_edge(f1_data, f2_data, forward_penalties); + update_edge(b1_data, b2_data, backward_penalties); // extend e1's to targets of e2's graph.SetTarget(forward_e1, node_w); @@ -341,28 +303,20 @@ 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); - // Update traffic signal paths containing compressed node. - traffic_signals.Compress(node_u, node_v, node_w); + // Update obstacle paths containing the compressed node. + scripting_environment.m_obstacle_map.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) + // Forward and backward penalties must both be valid or both be invalid. + auto set_dummy_penalty = [](EdgePenalties &f, EdgePenalties &b) { - if (weight_penalty == INVALID_EDGE_WEIGHT && - other_weight_penalty != INVALID_EDGE_WEIGHT) + if (f.weight == INVALID_EDGE_WEIGHT && b.weight != INVALID_EDGE_WEIGHT) { - weight_penalty = {0}; - duration_penalty = {0}; + f.weight = {0}; + f.duration = {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); + set_dummy_penalty(forward_penalties, backward_penalties); + set_dummy_penalty(backward_penalties, forward_penalties); // store compressed geometry in container geometry_compressor.CompressEdge(forward_e1, @@ -373,8 +327,8 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes, forward_weight2, forward_duration1, forward_duration2, - forward_node_weight_penalty, - forward_node_duration_penalty); + forward_penalties.weight, + forward_penalties.duration); geometry_compressor.CompressEdge(reverse_e1, reverse_e2, node_v, @@ -383,8 +337,8 @@ void GraphCompressor::Compress(const std::unordered_set<NodeID> &barrier_nodes, reverse_weight2, reverse_duration1, reverse_duration2, - reverse_node_weight_penalty, - reverse_node_duration_penalty); + backward_penalties.weight, + backward_penalties.duration); } } } diff --git a/src/extractor/intersection/intersection_analysis.cpp b/src/extractor/intersection/intersection_analysis.cpp index 2850e06235a..d8b68c644db 100644 --- a/src/extractor/intersection/intersection_analysis.cpp +++ b/src/extractor/intersection/intersection_analysis.cpp @@ -434,7 +434,7 @@ bool isTurnRestricted(RestrictionsRange restrictions, const NodeID to) bool isTurnAllowed(const util::NodeBasedDynamicGraph &graph, const EdgeBasedNodeDataContainer &node_data_container, const RestrictionMap &restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const ObstacleMap &obstacle_nodes, const IntersectionEdgeGeometries &geometries, const TurnLanesIndexedArray &turn_lanes_data, const IntersectionEdge &from, @@ -506,14 +506,18 @@ bool isTurnAllowed(const util::NodeBasedDynamicGraph &graph, } } - // 3) if the intersection has a barrier - const bool is_barrier_node = barrier_nodes.find(intersection_node) != barrier_nodes.end(); + // 3) if the intersection has an obstacle or is a designated turning place + + bool is_barrier_node = + obstacle_nodes.any(SPECIAL_NODEID, intersection_node, Obstacle::Type::Barrier); + bool is_turning_node = + obstacle_nodes.any(SPECIAL_NODEID, intersection_node, Obstacle::Type::Turning); // Check a U-turn if (from.node == destination_node) { - // Allow U-turns before barrier nodes - if (is_barrier_node) + // Allow U-turns before barrier nodes or at designated turning places + if (is_barrier_node || is_turning_node) return true; // Allow U-turns at dead-ends @@ -597,7 +601,7 @@ bool isTurnAllowed(const util::NodeBasedDynamicGraph &graph, IntersectionView convertToIntersectionView(const util::NodeBasedDynamicGraph &graph, const EdgeBasedNodeDataContainer &node_data_container, const RestrictionMap &restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const ObstacleMap &obstacle_nodes, const IntersectionEdgeGeometries &edge_geometries, const TurnLanesIndexedArray &turn_lanes_data, const IntersectionEdge &incoming_edge, @@ -625,7 +629,7 @@ IntersectionView convertToIntersectionView(const util::NodeBasedDynamicGraph &gr const auto is_turn_allowed = intersection::isTurnAllowed(graph, node_data_container, restriction_map, - barrier_nodes, + obstacle_nodes, edge_geometries, turn_lanes_data, incoming_edge, @@ -748,7 +752,7 @@ IntersectionView getConnectedRoads(const util::NodeBasedDynamicGraph &graph, const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const ObstacleMap &obstacle_nodes, const TurnLanesIndexedArray &turn_lanes_data, const IntersectionEdge &incoming_edge) { @@ -760,7 +764,7 @@ IntersectionView getConnectedRoads(const util::NodeBasedDynamicGraph &graph, return getConnectedRoadsForEdgeGeometries(graph, node_data_container, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, incoming_edge, edge_geometries, @@ -771,7 +775,7 @@ IntersectionView getConnectedRoadsForEdgeGeometries(const util::NodeBasedDynamicGraph &graph, const EdgeBasedNodeDataContainer &node_data_container, const RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const ObstacleMap &obstacle_nodes, const TurnLanesIndexedArray &turn_lanes_data, const IntersectionEdge &incoming_edge, const IntersectionEdgeGeometries &edge_geometries, @@ -802,7 +806,7 @@ getConnectedRoadsForEdgeGeometries(const util::NodeBasedDynamicGraph &graph, return convertToIntersectionView(graph, node_data_container, node_restriction_map, - barrier_nodes, + obstacle_nodes, processed_edge_geometries, turn_lanes_data, incoming_edge, @@ -816,7 +820,7 @@ getConnectedRoads<false>(const util::NodeBasedDynamicGraph &graph, const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const ObstacleMap &obstacle_nodes, const TurnLanesIndexedArray &turn_lanes_data, const IntersectionEdge &incoming_edge); @@ -826,7 +830,7 @@ getConnectedRoads<true>(const util::NodeBasedDynamicGraph &graph, const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const ObstacleMap &obstacle_nodes, const TurnLanesIndexedArray &turn_lanes_data, const IntersectionEdge &incoming_edge); diff --git a/src/extractor/intersection/mergable_road_detector.cpp b/src/extractor/intersection/mergable_road_detector.cpp index adfb601cb44..69d93d80af3 100644 --- a/src/extractor/intersection/mergable_road_detector.cpp +++ b/src/extractor/intersection/mergable_road_detector.cpp @@ -54,13 +54,13 @@ MergableRoadDetector::MergableRoadDetector( const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, const NameTable &name_table, const SuffixTable &street_name_suffix_table) : node_based_graph(node_based_graph), node_data_container(node_data_container), node_coordinates(node_coordinates), compressed_geometries(compressed_geometries), - node_restriction_map(node_restriction_map), barrier_nodes(barrier_nodes), + node_restriction_map(node_restriction_map), obstacle_nodes(obstacle_nodes), turn_lanes_data(turn_lanes_data), name_table(name_table), street_name_suffix_table(street_name_suffix_table), coordinate_extractor(node_based_graph, compressed_geometries, node_coordinates) @@ -180,7 +180,7 @@ bool MergableRoadDetector::IsNarrowTriangle(const NodeID intersection_node, node_coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data), right_accumulator(SMALL_RANDOM_HOPLIMIT, node_based_graph, @@ -188,7 +188,7 @@ bool MergableRoadDetector::IsNarrowTriangle(const NodeID intersection_node, node_coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data); /* Standard following the straightmost road @@ -206,7 +206,7 @@ bool MergableRoadDetector::IsNarrowTriangle(const NodeID intersection_node, node_coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data); graph_walker.TraverseRoad(intersection_node, lhs.eid, left_accumulator, selector); /* if the intersection does not have a right turn, we continue onto the next one once @@ -286,7 +286,7 @@ bool MergableRoadDetector::IsNarrowTriangle(const NodeID intersection_node, node_coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data); graph_walker.TraverseRoad(node_based_graph.GetTarget(left_accumulator.via_edge_id), connector_turn->eid, @@ -307,7 +307,7 @@ bool MergableRoadDetector::IsCircularShape(const NodeID intersection_node, node_coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data); const auto getCoordinatesAlongWay = [&](const EdgeID edge_id, const double max_length) { @@ -351,7 +351,7 @@ bool MergableRoadDetector::IsCircularShape(const NodeID intersection_node, // ---- ---- // \ / // ------- - const auto constexpr CIRCULAR_POLYGON_ISOPERIMETRIC_LOWER_BOUND = 0.85 / (4 * std::numbers::pi); + const auto CIRCULAR_POLYGON_ISOPERIMETRIC_LOWER_BOUND = 0.85 / (4 * std::numbers::pi); if (connect_again && coordinates_to_the_left.front() == coordinates_to_the_left.back()) { // if the left and right roads connect again and are closed polygons ... const auto area = util::coordinate_calculation::computeArea(coordinates_to_the_left); @@ -380,7 +380,7 @@ bool MergableRoadDetector::HaveSameDirection(const NodeID intersection_node, node_coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data); const auto getCoordinatesAlongWay = [&](const EdgeID edge_id, const double max_length) { @@ -565,7 +565,7 @@ bool MergableRoadDetector::IsLinkRoad(const NodeID intersection_node, node_coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, next_intersection_parameters); const auto extract_name_id = [this](const MergableRoadData &road) diff --git a/src/extractor/intersection/node_based_graph_walker.cpp b/src/extractor/intersection/node_based_graph_walker.cpp index c1ee0fc642e..3f9414a2502 100644 --- a/src/extractor/intersection/node_based_graph_walker.cpp +++ b/src/extractor/intersection/node_based_graph_walker.cpp @@ -17,11 +17,11 @@ NodeBasedGraphWalker::NodeBasedGraphWalker( const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const ObstacleMap &obstacle_nodes, const TurnLanesIndexedArray &turn_lanes_data) : node_based_graph(node_based_graph), node_data_container(node_data_container), node_coordinates(node_coordinates), compressed_geometries(compressed_geometries), - node_restriction_map(node_restriction_map), barrier_nodes(barrier_nodes), + node_restriction_map(node_restriction_map), obstacle_nodes(obstacle_nodes), turn_lanes_data(turn_lanes_data) { } @@ -252,12 +252,12 @@ IntersectionFinderAccumulator::IntersectionFinderAccumulator( const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const ObstacleMap &obstacle_nodes, const TurnLanesIndexedArray &turn_lanes_data) : hops(0), hop_limit(hop_limit), node_based_graph(node_based_graph), node_data_container(node_data_container), node_coordinates(node_coordinates), compressed_geometries(compressed_geometries), node_restriction_map(node_restriction_map), - barrier_nodes(barrier_nodes), turn_lanes_data(turn_lanes_data) + obstacle_nodes(obstacle_nodes), turn_lanes_data(turn_lanes_data) { } @@ -287,7 +287,7 @@ void IntersectionFinderAccumulator::update(const NodeID from_node, node_coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, {from_node, via_edge}); } diff --git a/src/extractor/node_based_graph_factory.cpp b/src/extractor/node_based_graph_factory.cpp index 9fb50149d4d..b11d39f1a9b 100644 --- a/src/extractor/node_based_graph_factory.cpp +++ b/src/extractor/node_based_graph_factory.cpp @@ -17,17 +17,15 @@ NodeBasedGraphFactory::NodeBasedGraphFactory( ScriptingEnvironment &scripting_environment, std::vector<TurnRestriction> &turn_restrictions, std::vector<UnresolvedManeuverOverride> &maneuver_overrides, - TrafficSignals &traffic_signals, - std::unordered_set<NodeID> &&barriers, std::vector<util::Coordinate> &&coordinates, extractor::PackedOSMIDs &&osm_node_ids, const std::vector<NodeBasedEdge> &edge_list, std::vector<NodeBasedEdgeAnnotation> &&annotation_data) - : annotation_data(std::move(annotation_data)), barriers(std::move(barriers)), - coordinates(std::move(coordinates)), osm_node_ids(std::move(osm_node_ids)) + : annotation_data(std::move(annotation_data)), 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); CompressGeometry(); CompressAnnotationData(); } @@ -75,13 +73,10 @@ void NodeBasedGraphFactory::BuildCompressedOutputGraph(const std::vector<NodeBas void NodeBasedGraphFactory::Compress(ScriptingEnvironment &scripting_environment, std::vector<TurnRestriction> &turn_restrictions, - std::vector<UnresolvedManeuverOverride> &maneuver_overrides, - TrafficSignals &traffic_signals) + std::vector<UnresolvedManeuverOverride> &maneuver_overrides) { GraphCompressor graph_compressor; - graph_compressor.Compress(barriers, - traffic_signals, - scripting_environment, + graph_compressor.Compress(scripting_environment, turn_restrictions, maneuver_overrides, compressed_output_graph, diff --git a/src/extractor/obstacles.cpp b/src/extractor/obstacles.cpp new file mode 100644 index 00000000000..b4ca86617f5 --- /dev/null +++ b/src/extractor/obstacles.cpp @@ -0,0 +1,159 @@ +/* + +Copyright (c) 2025, Project OSRM contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list +of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this +list of conditions and the following disclaimer in the documentation and/or +other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "extractor/obstacles.hpp" + +#include "util/log.hpp" +#include "util/timing_util.hpp" + +namespace osrm::extractor +{ + +const std::initializer_list<std::pair<std::string_view, Obstacle::Type>> + Obstacle::enum_type_initializer_list{{"none", Obstacle::Type::None}, + {"barrier", Obstacle::Type::Barrier}, + {"traffic_signals", Obstacle::Type::TrafficSignals}, + {"stop", Obstacle::Type::Stop}, + {"stop_minor", Obstacle::Type::StopMinor}, + {"give_way", Obstacle::Type::GiveWay}, + {"crossing", Obstacle::Type::Crossing}, + {"traffic_calming", Obstacle::Type::TrafficCalming}, + {"mini_roundabout", Obstacle::Type::MiniRoundabout}, + {"turning_loop", Obstacle::Type::TurningLoop}, + {"turning_circle", Obstacle::Type::TurningCircle}}; + +const std::initializer_list<std::pair<std::string_view, Obstacle::Direction>> + Obstacle::enum_direction_initializer_list{{"none", Obstacle::Direction::None}, + {"forward", Obstacle::Direction::Forward}, + {"backward", Obstacle::Direction::Backward}, + {"both", Obstacle::Direction::Both}}; + +void ObstacleMap::preProcess(const NodeIDVector &node_ids, const WayNodeIDOffsets &way_node_offsets) +{ + util::UnbufferedLog log; + log << "Collecting information on " << osm_obstacles.size() << " obstacles..."; + TIMER_START(preProcess); + + // build a map to speed up the next step + // multimap of OSMNodeId to index into way_node_offsets + std::unordered_multimap<OSMNodeID, size_t> node2start_index; + + for (size_t i = 0, j = 1; j < way_node_offsets.size(); ++i, ++j) + { + for (size_t k = way_node_offsets[i]; k < way_node_offsets[j]; ++k) + { + node2start_index.emplace(node_ids[k], i); + } + } + + // for each unidirectional obstacle + // for each way that crosses the obstacle + // for each node of the crossing way + // find the node immediately before or after the obstacle + // add the unidirectional obstacle + // note that we don't remove the bidirectional obstacle here, + // but in fixupNodes() + + for (auto &[from_id, to_id, obstacle] : osm_obstacles) + { + if (obstacle.direction == Obstacle::Direction::Forward || + obstacle.direction == Obstacle::Direction::Backward) + { + bool forward = obstacle.direction == Obstacle::Direction::Forward; + auto [wno_begin, wno_end] = node2start_index.equal_range(to_id); + // for each way that crosses the obstacle + for (auto wno_iter = wno_begin; wno_iter != wno_end; ++wno_iter) + { + using NodeIdIterator = NodeIDVector::const_iterator; + + NodeIdIterator begin = node_ids.cbegin() + way_node_offsets[wno_iter->second]; + NodeIdIterator end = node_ids.cbegin() + way_node_offsets[wno_iter->second + 1]; + if (forward) + ++begin; + else + --end; + + NodeIdIterator node_iter = find(begin, end, to_id); + if (node_iter != end) + { + osm_obstacles.emplace_back(*(node_iter + (forward ? -1 : 1)), to_id, obstacle); + } + } + } + } + + TIMER_STOP(preProcess); + log << "ok, after " << TIMER_SEC(preProcess) << "s"; +} + +void ObstacleMap::fixupNodes(const NodeIDVector &node_ids) +{ + const auto begin = node_ids.cbegin(); + const auto end = node_ids.cend(); + + auto osm_to_internal = [&](const OSMNodeID &osm_node) -> NodeID + { + if (osm_node == SPECIAL_OSM_NODEID) + { + return SPECIAL_NODEID; + } + const auto it = std::lower_bound(begin, end, osm_node); + return (it == end || osm_node < *it) ? SPECIAL_NODEID + : static_cast<NodeID>(std::distance(begin, it)); + }; + + for (const auto &[osm_from, osm_to, obstacle] : osm_obstacles) + { + if ((obstacle.direction == Obstacle::Direction::Forward || + obstacle.direction == Obstacle::Direction::Backward) && + osm_from == SPECIAL_OSM_NODEID) + // drop these bidirectional entries because we have generated an + // unidirectional copy of them + continue; + emplace(osm_to_internal(osm_from), osm_to_internal(osm_to), obstacle); + } + osm_obstacles.clear(); +} + +void ObstacleMap::compress(NodeID node1, NodeID delendus, NodeID node2) +{ + auto comp = [this, delendus](NodeID first, NodeID last) + { + const auto &[begin, end] = obstacles.equal_range(last); + for (auto i = begin; i != end; ++i) + { + auto &[from, to, obstacle] = i->second; + if (from == delendus) + from = first; + } + }; + + comp(node1, node2); + comp(node2, node1); +} + +} // namespace osrm::extractor diff --git a/src/extractor/scripting_environment_lua.cpp b/src/extractor/scripting_environment_lua.cpp index 9aaf7977812..ca565751c80 100644 --- a/src/extractor/scripting_environment_lua.cpp +++ b/src/extractor/scripting_environment_lua.cpp @@ -6,11 +6,11 @@ #include "extractor/extraction_segment.hpp" #include "extractor/extraction_turn.hpp" #include "extractor/extraction_way.hpp" +#include "extractor/graph_compressor.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" #include "extractor/restriction_parser.hpp" #include "guidance/turn_instruction.hpp" @@ -99,11 +99,12 @@ void handle_lua_error(const sol::protected_function_result &luares) const auto msg = luaerr.what(); if (msg != nullptr) { - std::cerr << msg << "\n"; + // util::Log is thread-safe + util::UnbufferedLog(logERROR) << msg << "\n"; } else { - std::cerr << "unknown error\n"; + util::UnbufferedLog(logERROR) << "unknown error\n"; } throw util::exception("Lua error (see stderr for traceback)"); } @@ -303,40 +304,96 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context) context.state.new_enum("traffic_lights", "none", - extractor::TrafficLightClass::NONE, + Obstacle::Direction::None, "direction_all", - extractor::TrafficLightClass::DIRECTION_ALL, + Obstacle::Direction::Both, "direction_forward", - extractor::TrafficLightClass::DIRECTION_FORWARD, + Obstacle::Direction::Forward, "direction_reverse", - extractor::TrafficLightClass::DIRECTION_REVERSE); + Obstacle::Direction::Backward); + + context.state.new_enum("obstacle_type", Obstacle::enum_type_initializer_list); + context.state.new_enum("obstacle_direction", Obstacle::enum_direction_initializer_list); + + context.state.new_usertype<Obstacle>( + "Obstacle", + sol::constructors<Obstacle(Obstacle::Type), + Obstacle(Obstacle::Type, Obstacle::Direction), + Obstacle(Obstacle::Type, Obstacle::Direction, float, float)>(), + "type", + sol::readonly(&Obstacle::type), + "direction", + sol::readonly(&Obstacle::direction), + "duration", + sol::readonly(&Obstacle::duration), + "weight", + sol::readonly(&Obstacle::weight)); + + context.state.new_usertype<ObstacleMap>( + "ObstacleMap", + "add", + [](ObstacleMap &obstacles, const osmium::Node &from, Obstacle obstacle) + { + OSMNodeID id = to_alias<OSMNodeID>(from.id()); + obstacles.emplace(id, obstacle); + }, + "get", + sol::overload([](const ObstacleMap &om, NodeID to) { return om.get(to); }, + [](const ObstacleMap &om, NodeID from, NodeID to) + { return om.get(from, to); }, + [](const ObstacleMap &om, NodeID from, NodeID to, Obstacle::Type type) + { return om.get(from, to, type); }), + "any", + sol::overload([](const ObstacleMap &om, NodeID to) { return om.any(to); }, + [](const ObstacleMap &om, NodeID from, NodeID to) + { return om.any(from, to, Obstacle::Type::All); }, + [](const ObstacleMap &om, NodeID from, NodeID to, Obstacle::Type type) + { return om.any(from, to, type); })); + + context.state["obstacle_map"] = std::ref(m_obstacle_map); context.state.new_usertype<ExtractionNode>( "ResultNode", + // for API compatibility only "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; - } - }), + sol::property( + [&context, this](ExtractionNode &node, const sol::object &obj) + { + if (obj.is<Obstacle::Direction>()) + { + m_obstacle_map.emplace( + to_alias<OSMNodeID>(node.node->id()), + Obstacle{Obstacle::Type::TrafficSignals, + obj.as<Obstacle::Direction>(), + static_cast<float>(context.properties.GetTrafficSignalPenalty()), + 0}); + return; + } + if (obj.is<bool>() && obj.as<bool>()) + { + // The old approach of assigning a boolean traffic light + // state to the node + // TODO: Make a breaking API change and remove this option. + m_obstacle_map.emplace( + to_alias<OSMNodeID>(node.node->id()), + Obstacle{Obstacle::Type::TrafficSignals, + Obstacle::Direction::Both, + static_cast<float>(context.properties.GetTrafficSignalPenalty()), + 0}); + } + }), + // for API compatibility only "barrier", - &ExtractionNode::barrier); + sol::property( + [this](ExtractionNode &node, const sol::object &obj) + { + if (obj.is<bool>() && obj.as<bool>()) + { + m_obstacle_map.emplace( + to_alias<OSMNodeID>(node.node->id()), + Obstacle{Obstacle::Type::Barrier, Obstacle::Direction::Both}); + } + })); context.state.new_usertype<RoadClassification>( "RoadClassification", @@ -807,6 +864,8 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context) &ExtractionTurnLeg::access_turn_classification, "speed", &ExtractionTurnLeg::speed, + "distance", + &ExtractionTurnLeg::distance, "priority_class", &ExtractionTurnLeg::priority_class, "is_incoming", @@ -865,10 +924,21 @@ void Sol2ScriptingEnvironment::InitContext(LuaScriptingContext &context) "target_priority_class", &ExtractionTurn::target_priority_class, + "from", + &ExtractionTurn::from, + "via", + &ExtractionTurn::via, + "to", + &ExtractionTurn::to, + "source_road", + &ExtractionTurn::source_road, + "target_road", + &ExtractionTurn::target_road, "roads_on_the_right", &ExtractionTurn::roads_on_the_right, "roads_on_the_left", &ExtractionTurn::roads_on_the_left, + "weight", &ExtractionTurn::weight, "duration", @@ -975,13 +1045,13 @@ void Sol2ScriptingEnvironment::ProcessElements( case osmium::item_type::node: { const auto &node = static_cast<const osmium::Node &>(*entity); - // NOLINTNEXTLINE(bugprone-use-after-move) - result_node.clear(); + result_node.node = &node; if (local_context.has_node_function && (!node.tags().empty() || local_context.properties.call_tagless_node_function)) { local_context.ProcessNode(node, result_node, relations); } + result_node.node = nullptr; resulting_nodes.push_back({node, result_node}); } break; diff --git a/src/guidance/driveway_handler.cpp b/src/guidance/driveway_handler.cpp index 5e781a9bb30..20cdf25ef5c 100644 --- a/src/guidance/driveway_handler.cpp +++ b/src/guidance/driveway_handler.cpp @@ -10,7 +10,7 @@ DrivewayHandler::DrivewayHandler(const util::NodeBasedDynamicGraph &node_based_g const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const extractor::RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, const extractor::NameTable &name_table, const extractor::SuffixTable &street_name_suffix_table) @@ -19,7 +19,7 @@ DrivewayHandler::DrivewayHandler(const util::NodeBasedDynamicGraph &node_based_g node_coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, name_table, street_name_suffix_table) diff --git a/src/guidance/guidance_processing.cpp b/src/guidance/guidance_processing.cpp index 2debabb04f8..d26ba8928f2 100644 --- a/src/guidance/guidance_processing.cpp +++ b/src/guidance/guidance_processing.cpp @@ -20,7 +20,7 @@ void annotateTurns(const util::NodeBasedDynamicGraph &node_based_graph, const extractor::EdgeBasedNodeDataContainer &edge_based_node_container, const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_edge_container, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::RestrictionMap &node_restriction_map, const extractor::WayRestrictionMap &way_restriction_map, const extractor::NameTable &name_table, @@ -41,7 +41,7 @@ void annotateTurns(const util::NodeBasedDynamicGraph &node_based_graph, node_coordinates, compressed_edge_container, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, name_table, suffix_table); @@ -51,7 +51,7 @@ void annotateTurns(const util::NodeBasedDynamicGraph &node_based_graph, node_coordinates, compressed_edge_container, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, name_table, suffix_table); @@ -61,7 +61,7 @@ void annotateTurns(const util::NodeBasedDynamicGraph &node_based_graph, node_coordinates, compressed_edge_container, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, lane_description_map, turn_analysis, @@ -173,7 +173,7 @@ void annotateTurns(const util::NodeBasedDynamicGraph &node_based_graph, node_based_graph, edge_based_node_container, node_restriction_map, - barrier_nodes, + obstacle_nodes, edge_geometries, turn_lanes_data, incoming_edge, @@ -213,7 +213,7 @@ void annotateTurns(const util::NodeBasedDynamicGraph &node_based_graph, extractor::intersection::isTurnAllowed(node_based_graph, edge_based_node_container, node_restriction_map, - barrier_nodes, + obstacle_nodes, edge_geometries, turn_lanes_data, incoming_edge, diff --git a/src/guidance/intersection_handler.cpp b/src/guidance/intersection_handler.cpp index b11597d5f46..5f839e97a13 100644 --- a/src/guidance/intersection_handler.cpp +++ b/src/guidance/intersection_handler.cpp @@ -46,20 +46,20 @@ IntersectionHandler::IntersectionHandler( const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const extractor::RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, const extractor::NameTable &name_table, const extractor::SuffixTable &street_name_suffix_table) : node_based_graph(node_based_graph), node_data_container(node_data_container), node_coordinates(node_coordinates), compressed_geometries(compressed_geometries), - node_restriction_map(node_restriction_map), barrier_nodes(barrier_nodes), + node_restriction_map(node_restriction_map), obstacle_nodes(obstacle_nodes), turn_lanes_data(turn_lanes_data), name_table(name_table), street_name_suffix_table(street_name_suffix_table), graph_walker(node_based_graph, node_data_container, node_coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data) { } @@ -430,7 +430,7 @@ void IntersectionHandler::assignTrivialTurns(const EdgeID via_eid, std::optional<IntersectionHandler::IntersectionViewAndNode> IntersectionHandler::getNextIntersection(const NodeID at, const EdgeID via) const { - // We use the intersection generator to jump over traffic signals, barriers. The intersection + // We use the intersection generator to jump over obstacles. The intersection // generater takes a starting node and a corresponding edge starting at this node. It returns // the next non-artificial intersection writing as out param. the source node and the edge // for which the target is the next intersection. @@ -458,12 +458,12 @@ IntersectionHandler::getNextIntersection(const NodeID at, const EdgeID via) cons node_coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, intersection_parameters); auto intersection_node = node_based_graph.GetTarget(intersection_parameters.edge); - if (intersection.size() <= 2 || intersection.isTrafficSignalOrBarrier()) + if (intersection.size() <= 2 || intersection.isObstacle()) { return std::nullopt; } diff --git a/src/guidance/motorway_handler.cpp b/src/guidance/motorway_handler.cpp index 5c85e2edf5f..258124d9963 100644 --- a/src/guidance/motorway_handler.cpp +++ b/src/guidance/motorway_handler.cpp @@ -44,7 +44,7 @@ MotorwayHandler::MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_g const std::vector<util::Coordinate> &coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const extractor::RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, const extractor::NameTable &name_table, const extractor::SuffixTable &street_name_suffix_table) @@ -53,7 +53,7 @@ MotorwayHandler::MotorwayHandler(const util::NodeBasedDynamicGraph &node_based_g coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, name_table, street_name_suffix_table) diff --git a/src/guidance/roundabout_handler.cpp b/src/guidance/roundabout_handler.cpp index 451ebf7bf5c..a1390b5c2c0 100644 --- a/src/guidance/roundabout_handler.cpp +++ b/src/guidance/roundabout_handler.cpp @@ -24,7 +24,7 @@ RoundaboutHandler::RoundaboutHandler( const std::vector<util::Coordinate> &coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const extractor::RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, const extractor::NameTable &name_table, const extractor::SuffixTable &street_name_suffix_table) @@ -33,7 +33,7 @@ RoundaboutHandler::RoundaboutHandler( coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, name_table, street_name_suffix_table), diff --git a/src/guidance/sliproad_handler.cpp b/src/guidance/sliproad_handler.cpp index 90a92801f53..d5686632a0b 100644 --- a/src/guidance/sliproad_handler.cpp +++ b/src/guidance/sliproad_handler.cpp @@ -22,7 +22,7 @@ SliproadHandler::SliproadHandler(const util::NodeBasedDynamicGraph &node_based_g const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const extractor::RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, const extractor::NameTable &name_table, const extractor::SuffixTable &street_name_suffix_table) @@ -31,7 +31,7 @@ SliproadHandler::SliproadHandler(const util::NodeBasedDynamicGraph &node_based_g node_coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, name_table, street_name_suffix_table), @@ -255,9 +255,9 @@ Intersection SliproadHandler::operator()(const NodeID /*nid*/, node_coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data}; - const extractor::intersection::SkipTrafficSignalBarrierRoadSelector road_selector{}; + const extractor::intersection::SkipObstacleRoadSelector road_selector{}; (void)graph_walker.TraverseRoad(intersection_node_id, // start node sliproad_edge, // onto edge intersection_finder, // accumulator @@ -585,10 +585,10 @@ Intersection SliproadHandler::operator()(const NodeID /*nid*/, node_coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, {node_based_graph.GetTarget(sliproad_edge), candidate_road.eid}); - if (skip_traffic_light_intersection.isTrafficSignalOrBarrier() && + if (skip_traffic_light_intersection.isObstacle() && node_based_graph.GetTarget(skip_traffic_light_intersection[1].eid) == main_road_intersection->node) { @@ -703,7 +703,7 @@ bool SliproadHandler::nextIntersectionIsTooFarAway(const NodeID start, const Edg extractor::intersection::DistanceToNextIntersectionAccumulator accumulator{ coordinate_extractor, node_based_graph, threshold}; - const extractor::intersection::SkipTrafficSignalBarrierRoadSelector selector{}; + const extractor::intersection::SkipObstacleRoadSelector selector{}; (void)graph_walker.TraverseRoad(start, onto, accumulator, selector); diff --git a/src/guidance/suppress_mode_handler.cpp b/src/guidance/suppress_mode_handler.cpp index e1356de6b9f..c910732fa6d 100644 --- a/src/guidance/suppress_mode_handler.cpp +++ b/src/guidance/suppress_mode_handler.cpp @@ -13,7 +13,7 @@ SuppressModeHandler::SuppressModeHandler( const std::vector<util::Coordinate> &coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const extractor::RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, const extractor::NameTable &name_table, const extractor::SuffixTable &street_name_suffix_table) @@ -22,7 +22,7 @@ SuppressModeHandler::SuppressModeHandler( coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, name_table, street_name_suffix_table) diff --git a/src/guidance/turn_analysis.cpp b/src/guidance/turn_analysis.cpp index 5e51a5cbe27..08b419d361a 100644 --- a/src/guidance/turn_analysis.cpp +++ b/src/guidance/turn_analysis.cpp @@ -19,7 +19,7 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph, const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_edge_container, const extractor::RestrictionMap &restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, const extractor::NameTable &name_table, const extractor::SuffixTable &street_name_suffix_table) @@ -28,7 +28,7 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph, node_coordinates, compressed_edge_container, restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, name_table, street_name_suffix_table), @@ -37,7 +37,7 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph, node_coordinates, compressed_edge_container, restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, name_table, street_name_suffix_table), @@ -46,7 +46,7 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph, node_coordinates, compressed_edge_container, restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, name_table, street_name_suffix_table), @@ -55,7 +55,7 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph, node_coordinates, compressed_edge_container, restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, name_table, street_name_suffix_table), @@ -64,7 +64,7 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph, node_coordinates, compressed_edge_container, restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, name_table, street_name_suffix_table), @@ -73,7 +73,7 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph, node_coordinates, compressed_edge_container, restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, name_table, street_name_suffix_table), @@ -82,7 +82,7 @@ TurnAnalysis::TurnAnalysis(const util::NodeBasedDynamicGraph &node_based_graph, node_coordinates, compressed_edge_container, restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, name_table, street_name_suffix_table) diff --git a/src/guidance/turn_discovery.cpp b/src/guidance/turn_discovery.cpp index 57b66f8a75c..0911a5f22f0 100644 --- a/src/guidance/turn_discovery.cpp +++ b/src/guidance/turn_discovery.cpp @@ -18,7 +18,7 @@ bool findPreviousIntersection(const NodeID node_v, const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const extractor::RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, // output parameters NodeID &result_node, @@ -74,7 +74,7 @@ bool findPreviousIntersection(const NodeID node_v, node_coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, {node_w, u_turn_at_node_w}); // Continue along the straightmost turn. If there is no straight turn, we cannot find a valid @@ -94,7 +94,7 @@ bool findPreviousIntersection(const NodeID node_v, node_coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, {node_v, straightmost_at_v_in_reverse->eid}); @@ -120,7 +120,7 @@ bool findPreviousIntersection(const NodeID node_v, node_coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, {node_u, result_via_edge}); const auto check_via_edge = diff --git a/src/guidance/turn_handler.cpp b/src/guidance/turn_handler.cpp index 0a77243604f..5672f62c7b5 100644 --- a/src/guidance/turn_handler.cpp +++ b/src/guidance/turn_handler.cpp @@ -110,7 +110,7 @@ TurnHandler::TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph, const std::vector<util::Coordinate> &coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const extractor::RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, const extractor::NameTable &name_table, const extractor::SuffixTable &street_name_suffix_table) @@ -119,7 +119,7 @@ TurnHandler::TurnHandler(const util::NodeBasedDynamicGraph &node_based_graph, coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, name_table, street_name_suffix_table) diff --git a/src/guidance/turn_lane_handler.cpp b/src/guidance/turn_lane_handler.cpp index 19d246bc24e..8622d696cf0 100644 --- a/src/guidance/turn_lane_handler.cpp +++ b/src/guidance/turn_lane_handler.cpp @@ -34,14 +34,14 @@ TurnLaneHandler::TurnLaneHandler(const util::NodeBasedDynamicGraph &node_based_g const std::vector<util::Coordinate> &node_coordinates, const extractor::CompressedEdgeContainer &compressed_geometries, const extractor::RestrictionMap &node_restriction_map, - const std::unordered_set<NodeID> &barrier_nodes, + const extractor::ObstacleMap &obstacle_nodes, const extractor::TurnLanesIndexedArray &turn_lanes_data, extractor::LaneDescriptionMap &lane_description_map, const TurnAnalysis &turn_analysis, util::guidance::LaneDataIdMap &id_map) : node_based_graph(node_based_graph), node_data_container(node_data_container), node_coordinates(node_coordinates), compressed_geometries(compressed_geometries), - node_restriction_map(node_restriction_map), barrier_nodes(barrier_nodes), + node_restriction_map(node_restriction_map), obstacle_nodes(obstacle_nodes), turn_lanes_data(turn_lanes_data), lane_description_map(lane_description_map), turn_analysis(turn_analysis), id_map(id_map) { @@ -213,7 +213,7 @@ TurnLaneScenario TurnLaneHandler::deduceScenario(const NodeID at, node_coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, previous_node, previous_via_edge, @@ -268,7 +268,7 @@ TurnLaneScenario TurnLaneHandler::deduceScenario(const NodeID at, return TurnLaneScenario::MERGE; // Dead end streets that don't have any left-tag. This can happen due to the fallbacks for - // broken data/barriers. + // broken data or obstacles. const bool has_non_usable_u_turn = (intersection[0].entry_allowed && !hasTag(TurnLaneType::none | TurnLaneType::left | TurnLaneType::sharp_left | TurnLaneType::uturn, @@ -579,7 +579,7 @@ std::pair<LaneDataVector, LaneDataVector> TurnLaneHandler::partitionLaneData( node_coordinates, compressed_geometries, node_restriction_map, - barrier_nodes, + obstacle_nodes, turn_lanes_data, {at, straightmost->eid})); diff --git a/taginfo.json b/taginfo.json index dfe48f96a6f..c2bb0367d30 100644 --- a/taginfo.json +++ b/taginfo.json @@ -124,8 +124,21 @@ {"key": "side_road", "value": "yes", "description": "gets speed penalty"}, {"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": "crossing", "object_types": ["node"]}, + {"key": "highway", "value": "give_way", "object_types": ["node"]}, + {"key": "highway", "value": "mini_roundabout", "object_types": ["node"]}, + {"key": "highway", "value": "stop", "object_types": ["node"]}, + {"key": "highway", "value": "traffic_calming", "object_types": ["node"]}, + {"key": "highway", "value": "traffic_signals", "object_types": ["node"]}, + {"key": "highway", "value": "turning_circle", "object_types": ["node"]}, + {"key": "highway", "value": "turning_loop", "object_types": ["node"]}, + {"key": "direction", "value": "forward", "object_types": ["node"]}, + {"key": "direction", "value": "backward", "object_types": ["node"]}, + {"key": "direction", "value": "both", "object_types": ["node"]}, + {"key": "traffic_signals:direction", "value": "forward", "object_types": ["node"]}, + {"key": "traffic_signals:direction", "value": "backward", "object_types": ["node"]}, + {"key": "traffic_signals:direction", "value": "both", "object_types": ["node"]}, + {"key": "stop", "value": "minor", "object_types": ["node"]}, {"key": "access", "value": "yes"}, {"key": "access", "value": "motorcar"}, {"key": "access", "value": "motor_vehicle"}, diff --git a/test/data/profiles/bad_node.lua b/test/data/profiles/bad_node.lua index 74c730587bc..fd974799841 100644 --- a/test/data/profiles/bad_node.lua +++ b/test/data/profiles/bad_node.lua @@ -9,8 +9,8 @@ function setup() max_speed_for_map_matching = 30/3.6, --km -> m/s weight_name = 'duration', process_call_tagless_node = false, - u_turn_penalty = 20, - traffic_light_penalty = 7, -- seconds + u_turn_penalty = 20, + traffic_signal_penalty = 7, -- seconds use_turn_restrictions = true }, @@ -128,7 +128,7 @@ function process_turn (profile, turn) turn.weight = turn.weight + profile.properties.u_turn_penalty end if turn.has_traffic_light then - turn.duration = turn.duration + profile.properties.traffic_light_penalty + turn.duration = turn.duration + profile.properties.traffic_signal_penalty end end diff --git a/test/data/profiles/bad_segment.lua b/test/data/profiles/bad_segment.lua index cbb5bac1932..3c33bb542c8 100644 --- a/test/data/profiles/bad_segment.lua +++ b/test/data/profiles/bad_segment.lua @@ -9,8 +9,8 @@ function setup() max_speed_for_map_matching = 30/3.6, --km -> m/s weight_name = 'duration', process_call_tagless_node = false, - u_turn_penalty = 20, - traffic_light_penalty = 7, -- seconds + u_turn_penalty = 20, + traffic_signal_penalty = 7, -- seconds use_turn_restrictions = true }, @@ -124,7 +124,7 @@ function process_turn (profile, turn) turn.weight = turn.weight + profile.properties.u_turn_penalty end if turn.has_traffic_light then - turn.duration = turn.duration + profile.properties.traffic_light_penalty + turn.duration = turn.duration + profile.properties.traffic_signal_penalty end end diff --git a/test/data/profiles/bad_setup.lua b/test/data/profiles/bad_setup.lua index 72e32cc40ce..2604ca85f03 100644 --- a/test/data/profiles/bad_setup.lua +++ b/test/data/profiles/bad_setup.lua @@ -13,8 +13,8 @@ function setup() max_speed_for_map_matching = 30/3.6, --km -> m/s weight_name = 'duration', process_call_tagless_node = false, - u_turn_penalty = 20, - traffic_light_penalty = 7, -- seconds + u_turn_penalty = 20, + traffic_signal_penalty = 7, -- seconds use_turn_restrictions = true }, @@ -128,7 +128,7 @@ function process_turn (profile, turn) turn.weight = turn.weight + profile.properties.u_turn_penalty end if turn.has_traffic_light then - turn.duration = turn.duration + profile.properties.traffic_light_penalty + turn.duration = turn.duration + profile.properties.traffic_signal_penalty end end diff --git a/test/data/profiles/bad_turn.lua b/test/data/profiles/bad_turn.lua index 0fecb7d2d07..79e25b29587 100644 --- a/test/data/profiles/bad_turn.lua +++ b/test/data/profiles/bad_turn.lua @@ -9,8 +9,8 @@ function setup() max_speed_for_map_matching = 30/3.6, --km -> m/s weight_name = 'duration', process_call_tagless_node = false, - u_turn_penalty = 20, - traffic_light_penalty = 7, -- seconds + u_turn_penalty = 20, + traffic_signal_penalty = 7, -- seconds use_turn_restrictions = true }, @@ -128,7 +128,7 @@ function process_turn (profile, turn) turn.weight = turn.weight + profile.properties.u_turn_penalty end if turn.has_traffic_light then - turn.duration = turn.duration + profile.properties.traffic_light_penalty + turn.duration = turn.duration + profile.properties.traffic_signal_penalty end end diff --git a/test/data/profiles/bad_way.lua b/test/data/profiles/bad_way.lua index cb0a3eb7206..f3cc6804ab4 100644 --- a/test/data/profiles/bad_way.lua +++ b/test/data/profiles/bad_way.lua @@ -9,8 +9,8 @@ function setup() max_speed_for_map_matching = 30/3.6, --km -> m/s weight_name = 'duration', process_call_tagless_node = false, - u_turn_penalty = 20, - traffic_light_penalty = 7, -- seconds + u_turn_penalty = 20, + traffic_signal_penalty = 7, -- seconds use_turn_restrictions = true }, @@ -128,7 +128,7 @@ function process_turn (profile, turn) turn.weight = turn.weight + profile.properties.u_turn_penalty end if turn.has_traffic_light then - turn.duration = turn.duration + profile.properties.traffic_light_penalty + turn.duration = turn.duration + profile.properties.traffic_signal_penalty end end diff --git a/unit_tests/extractor/graph_compressor.cpp b/unit_tests/extractor/graph_compressor.cpp index f70d71b4f91..c12b48a3646 100644 --- a/unit_tests/extractor/graph_compressor.cpp +++ b/unit_tests/extractor/graph_compressor.cpp @@ -64,8 +64,6 @@ BOOST_AUTO_TEST_CASE(long_road_test) // GraphCompressor compressor; - std::unordered_set<NodeID> barrier_nodes; - TrafficSignals traffic_lights; std::vector<TurnRestriction> restrictions; std::vector<NodeBasedEdgeAnnotation> annotations(1); CompressedEdgeContainer container; @@ -86,14 +84,8 @@ BOOST_AUTO_TEST_CASE(long_road_test) BOOST_CHECK(compatible(graph, annotations, 2, 4)); BOOST_CHECK(compatible(graph, annotations, 4, 6)); - compressor.Compress(barrier_nodes, - traffic_lights, - scripting_environment, - restrictions, - maneuver_overrides, - graph, - annotations, - container); + compressor.Compress( + scripting_environment, restrictions, maneuver_overrides, graph, annotations, container); BOOST_CHECK_EQUAL(graph.FindEdge(0, 1), SPECIAL_EDGEID); BOOST_CHECK_EQUAL(graph.FindEdge(1, 2), SPECIAL_EDGEID); BOOST_CHECK_EQUAL(graph.FindEdge(2, 3), SPECIAL_EDGEID); @@ -110,8 +102,6 @@ BOOST_AUTO_TEST_CASE(loop_test) // GraphCompressor compressor; - std::unordered_set<NodeID> barrier_nodes; - TrafficSignals traffic_lights; std::vector<TurnRestriction> restrictions; CompressedEdgeContainer container; std::vector<NodeBasedEdgeAnnotation> annotations(1); @@ -146,14 +136,8 @@ BOOST_AUTO_TEST_CASE(loop_test) BOOST_CHECK(compatible(graph, annotations, 10, 11)); BOOST_CHECK(compatible(graph, annotations, 11, 0)); - compressor.Compress(barrier_nodes, - traffic_lights, - scripting_environment, - restrictions, - maneuver_overrides, - graph, - annotations, - container); + compressor.Compress( + scripting_environment, restrictions, maneuver_overrides, graph, annotations, container); BOOST_CHECK_EQUAL(graph.FindEdge(5, 0), SPECIAL_EDGEID); BOOST_CHECK_EQUAL(graph.FindEdge(0, 1), SPECIAL_EDGEID); @@ -173,8 +157,6 @@ BOOST_AUTO_TEST_CASE(t_intersection) // GraphCompressor compressor; - std::unordered_set<NodeID> barrier_nodes; - TrafficSignals traffic_lights; std::vector<NodeBasedEdgeAnnotation> annotations(1); std::vector<TurnRestriction> restrictions; CompressedEdgeContainer container; @@ -195,14 +177,8 @@ BOOST_AUTO_TEST_CASE(t_intersection) BOOST_CHECK(compatible(graph, annotations, 3, 4)); BOOST_CHECK(compatible(graph, annotations, 4, 5)); - compressor.Compress(barrier_nodes, - traffic_lights, - scripting_environment, - restrictions, - maneuver_overrides, - graph, - annotations, - container); + compressor.Compress( + scripting_environment, restrictions, maneuver_overrides, graph, annotations, container); BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID); BOOST_CHECK(graph.FindEdge(1, 2) != SPECIAL_EDGEID); @@ -216,8 +192,6 @@ BOOST_AUTO_TEST_CASE(street_name_changes) // GraphCompressor compressor; - std::unordered_set<NodeID> barrier_nodes; - TrafficSignals traffic_lights; std::vector<NodeBasedEdgeAnnotation> annotations(2); std::vector<TurnRestriction> restrictions; CompressedEdgeContainer container; @@ -234,14 +208,8 @@ BOOST_AUTO_TEST_CASE(street_name_changes) BOOST_CHECK(compatible(graph, annotations, 0, 1)); BOOST_CHECK(compatible(graph, annotations, 2, 3)); - compressor.Compress(barrier_nodes, - traffic_lights, - scripting_environment, - restrictions, - maneuver_overrides, - graph, - annotations, - container); + compressor.Compress( + scripting_environment, restrictions, maneuver_overrides, graph, annotations, container); BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID); BOOST_CHECK(graph.FindEdge(1, 2) != SPECIAL_EDGEID); @@ -254,8 +222,6 @@ BOOST_AUTO_TEST_CASE(direction_changes) // GraphCompressor compressor; - std::unordered_set<NodeID> barrier_nodes; - TrafficSignals traffic_lights; std::vector<NodeBasedEdgeAnnotation> annotations(1); std::vector<TurnRestriction> restrictions; CompressedEdgeContainer container; @@ -268,14 +234,8 @@ BOOST_AUTO_TEST_CASE(direction_changes) edges[1].data.reversed = true; Graph graph(5, edges); - compressor.Compress(barrier_nodes, - traffic_lights, - scripting_environment, - restrictions, - maneuver_overrides, - graph, - annotations, - container); + compressor.Compress( + scripting_environment, restrictions, maneuver_overrides, graph, annotations, container); BOOST_CHECK(graph.FindEdge(0, 1) != SPECIAL_EDGEID); BOOST_CHECK(graph.FindEdge(1, 2) != SPECIAL_EDGEID); diff --git a/unit_tests/extractor/intersection_analysis_tests.cpp b/unit_tests/extractor/intersection_analysis_tests.cpp index 947359c598a..79b261ac74c 100644 --- a/unit_tests/extractor/intersection_analysis_tests.cpp +++ b/unit_tests/extractor/intersection_analysis_tests.cpp @@ -18,8 +18,6 @@ using Graph = util::NodeBasedDynamicGraph; BOOST_AUTO_TEST_CASE(simple_intersection_connectivity) { - std::unordered_set<NodeID> barrier_nodes{6}; - TrafficSignals traffic_lights; std::vector<NodeBasedEdgeAnnotation> annotations{ {EMPTY_NAMEID, 0, INAVLID_CLASS_DATA, TRAVEL_MODE_DRIVING, false}, {EMPTY_NAMEID, 1, INAVLID_CLASS_DATA, TRAVEL_MODE_DRIVING, false}}; @@ -27,6 +25,7 @@ BOOST_AUTO_TEST_CASE(simple_intersection_connectivity) CompressedEdgeContainer container; test::MockScriptingEnvironment scripting_environment; std::vector<UnresolvedManeuverOverride> maneuver_overrides; + scripting_environment.m_obstacle_map.emplace(SPECIAL_NODEID, 6, {Obstacle::Type::Barrier}); TurnLanesIndexedArray turn_lanes_data{{0, 0, 3}, {TurnLaneType::uturn | TurnLaneType::left, @@ -86,14 +85,8 @@ BOOST_AUTO_TEST_CASE(simple_intersection_connectivity) Graph graph(8, edges); - GraphCompressor().Compress(barrier_nodes, - traffic_lights, - scripting_environment, - restrictions, - maneuver_overrides, - graph, - annotations, - container); + GraphCompressor().Compress( + scripting_environment, restrictions, maneuver_overrides, graph, annotations, container); REQUIRE_SIZE_RANGE(getIncomingEdges(graph, 2), 3); REQUIRE_SIZE_RANGE(getOutgoingEdges(graph, 2), 4); @@ -115,7 +108,7 @@ BOOST_AUTO_TEST_CASE(simple_intersection_connectivity) result.push_back(isTurnAllowed(graph, node_data_container, restriction_map, - barrier_nodes, + scripting_environment.m_obstacle_map, edge_geometries, turn_lanes_data, incoming_edge, @@ -153,8 +146,6 @@ BOOST_AUTO_TEST_CASE(simple_intersection_connectivity) BOOST_AUTO_TEST_CASE(roundabout_intersection_connectivity) { - std::unordered_set<NodeID> barrier_nodes; - TrafficSignals traffic_lights; std::vector<NodeBasedEdgeAnnotation> annotations; std::vector<TurnRestriction> restrictions; CompressedEdgeContainer container; @@ -211,14 +202,8 @@ BOOST_AUTO_TEST_CASE(roundabout_intersection_connectivity) Graph graph(7, edges); - GraphCompressor().Compress(barrier_nodes, - traffic_lights, - scripting_environment, - restrictions, - maneuver_overrides, - graph, - annotations, - container); + GraphCompressor().Compress( + scripting_environment, restrictions, maneuver_overrides, graph, annotations, container); REQUIRE_SIZE_RANGE(getIncomingEdges(graph, 0), 3); REQUIRE_SIZE_RANGE(getOutgoingEdges(graph, 0), 6); @@ -241,7 +226,7 @@ BOOST_AUTO_TEST_CASE(roundabout_intersection_connectivity) result.push_back(isTurnAllowed(graph, node_data_container, restriction_map, - barrier_nodes, + scripting_environment.m_obstacle_map, edge_geometries, turn_lanes_data, incoming_edge, @@ -262,13 +247,14 @@ BOOST_AUTO_TEST_CASE(roundabout_intersection_connectivity) BOOST_AUTO_TEST_CASE(skip_degree_two_nodes) { - std::unordered_set<NodeID> barrier_nodes{1}; - TrafficSignals traffic_lights = {{2}, {}}; std::vector<NodeBasedEdgeAnnotation> annotations(1); std::vector<TurnRestriction> restrictions; CompressedEdgeContainer container; test::MockScriptingEnvironment scripting_environment; std::vector<UnresolvedManeuverOverride> maneuver_overrides; + scripting_environment.m_obstacle_map.emplace(SPECIAL_NODEID, 1, {Obstacle::Type::Barrier}); + scripting_environment.m_obstacle_map.emplace( + SPECIAL_NODEID, 2, {Obstacle::Type::TrafficSignals}); TurnLanesIndexedArray turn_lanes_data; @@ -312,14 +298,8 @@ BOOST_AUTO_TEST_CASE(skip_degree_two_nodes) Graph graph(10, edges); - GraphCompressor().Compress(barrier_nodes, - traffic_lights, - scripting_environment, - restrictions, - maneuver_overrides, - graph, - annotations, - container); + GraphCompressor().Compress( + scripting_environment, restrictions, maneuver_overrides, graph, annotations, container); BOOST_CHECK_EQUAL(graph.GetTarget(skipDegreeTwoNodes(graph, {0, 0}).edge), 4); BOOST_CHECK_EQUAL(graph.GetTarget(skipDegreeTwoNodes(graph, {4, 7}).edge), 0); diff --git a/unit_tests/library/extract.cpp b/unit_tests/library/extract.cpp index 768331c1c22..c4f1f0354f8 100644 --- a/unit_tests/library/extract.cpp +++ b/unit_tests/library/extract.cpp @@ -135,28 +135,24 @@ BOOST_AUTO_TEST_CASE(test_segment_runtime_error) BOOST_CHECK(boost::algorithm::contains( output.str(), "bad_segment.lua:132: attempt to compare number with nil")); } -// NOTE: THIS TEST IS COMMENTED OUT BECAUSE IT FAILS -// BOOST_AUTO_TEST_CASE(test_turn_runtime_error) -// { -// osrm::ExtractorConfig config; -// config.input_path = OSRM_TEST_DATA_DIR "/monaco.osm.pbf"; -// config.UseDefaultOutputNames(OSRM_TEST_DATA_DIR "/monaco.osm.pbf"); -// config.profile_path = OSRM_TEST_DATA_DIR "/profiles/bad_turn.lua"; -// config.small_component_size = 1000; -// config.requested_num_threads = std::thread::hardware_concurrency(); - -// std::stringstream output; - -// { -// redirect_stderr redir(output.rdbuf()); -// BOOST_CHECK_THROW(osrm::extract(config), osrm::util::exception); -// } - -// // We just look for the line number, file name, and error message. This avoids portability -// // issues since the output contains the full path to the file, which may change between -// systems BOOST_CHECK(boost::algorithm::contains(output.str(), -// "bad_turn.lua:122: attempt to compare number with -// nil")); -// } + +BOOST_AUTO_TEST_CASE(test_turn_runtime_error) +{ + osrm::ExtractorConfig config; + config.input_path = OSRM_TEST_DATA_DIR "/monaco.osm.pbf"; + config.UseDefaultOutputNames(OSRM_TEST_DATA_DIR "/monaco.osm.pbf"); + config.profile_path = OSRM_TEST_DATA_DIR "/profiles/bad_turn.lua"; + config.small_component_size = 1000; + config.requested_num_threads = std::thread::hardware_concurrency(); + std::stringstream output; + { + redirect_stderr redir(output.rdbuf()); + BOOST_CHECK_THROW(osrm::extract(config), osrm::util::exception); + } + // We just look for the line number, file name, and error message. This avoids portability + // issues since the output contains the full path to the file, which may change between systems + BOOST_CHECK(boost::algorithm::contains(output.str(), + "bad_turn.lua:122: attempt to compare number with nil")); +} BOOST_AUTO_TEST_SUITE_END()