Skip to content

Commit b17cbb4

Browse files
authored
Support OSM traffic signal directions (#6153)
Currently OSRM parses traffic signal nodes without consideration for the direction in which the signal applies. This can lead to duplicated routing penalties, especially when a forward and backward signal are in close proximity on a way. This commit adds support for directed signals to the extraction and graph creation. Signal penalties are only applied in the direction specified by the OSM tag. We add the assignment of traffic directions to the lua scripts, maintaining backwards compatibility with the existing boolean traffic states. As part of the changes to the internal structures used for tracking traffic signals during extraction, we stop serialising/deserialising signals to the `.osrm` file. The traffic signals are only used by `osrm-extract` so whilst this is a data format change, it will not break any existing user processes.
1 parent d8b358e commit b17cbb4

26 files changed

+649
-140
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@
5454
- FIXED: Improvements to maneuver override processing [#6125](https://github.com/Project-OSRM/osrm-backend/pull/6125)
5555
- ADDED: Support snapping to multiple ways at an input location. [#5953](https://github.com/Project-OSRM/osrm-backend/pull/5953)
5656
- FIXED: Fix snapping target locations to ways used in turn restrictions. [#6339](https://github.com/Project-OSRM/osrm-backend/pull/6339)
57+
- ADDED: Support OSM traffic signal directions. [#6153](https://github.com/Project-OSRM/osrm-backend/pull/6153)
5758

5859
# 5.26.0
5960
- Changes from 5.25.0

features/car/traffic_light_penalties.feature

Lines changed: 218 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,113 @@ Feature: Car - Handle traffic lights
3939
| k | n | 20.7s | turn with traffic light |
4040

4141

42-
Scenario: Tarrif Signal Geometry
42+
Scenario: Car - Traffic signal direction
43+
Given the node map
44+
"""
45+
a-1-b-2-c
46+
47+
d-3-e-4-f
48+
49+
g-5-h-6-i
50+
51+
j-7-k-8-l
52+
53+
"""
54+
55+
And the ways
56+
| nodes | highway |
57+
| abc | primary |
58+
| def | primary |
59+
| ghi | primary |
60+
| jkl | primary |
61+
62+
And the nodes
63+
| node | highway | traffic_signals:direction |
64+
| e | traffic_signals | |
65+
| h | traffic_signals | forward |
66+
| k | traffic_signals | backward |
67+
68+
When I route I should get
69+
| from | to | time | # |
70+
| 1 | 2 | 11.1s | no turn with no traffic light |
71+
| 2 | 1 | 11.1s | no turn with no traffic light |
72+
| 3 | 4 | 13.1s | no turn with traffic light |
73+
| 4 | 3 | 13.1s | no turn with traffic light |
74+
| 5 | 6 | 13.1s | no turn with traffic light |
75+
| 6 | 5 | 11.1s | no turn with no traffic light |
76+
| 7 | 8 | 11.1s | no turn with no traffic light |
77+
| 8 | 7 | 13.1s | no turn with traffic light |
78+
79+
80+
Scenario: Car - Encounters a traffic light
81+
Given the node map
82+
"""
83+
a f k
84+
| | |
85+
b-c-d h-g-i l-m-n
86+
| | |
87+
e j o
88+
89+
"""
90+
91+
And the ways
92+
| nodes | highway |
93+
| bcd | primary |
94+
| ace | primary |
95+
| hgi | primary |
96+
| fgj | primary |
97+
| lmn | primary |
98+
| kmo | primary |
99+
100+
And the nodes
101+
| node | highway | traffic_signals:direction |
102+
| g | traffic_signals | forward |
103+
| m | traffic_signals | backward |
104+
105+
106+
When I route I should get
107+
| from | to | time | # |
108+
| a | d | 21.9s | no turn with no traffic light |
109+
| a | e | 22.2s | no turn with traffic light |
110+
| a | b | 18.7s | turn with no traffic light |
111+
| e | b | 21.9s | no turn with no traffic light |
112+
| e | a | 22.2s | no turn with traffic light |
113+
| e | d | 18.7s | turn with no traffic light |
114+
| d | e | 21.9s | no turn with no traffic light |
115+
| d | b | 11s | no turn with traffic light |
116+
| d | a | 18.7s | turn with no traffic light |
117+
| b | a | 21.9s | no turn with no traffic light |
118+
| b | d | 11s | no turn with traffic light |
119+
| b | e | 18.7s | turn with no traffic light |
120+
121+
| f | i | 23.9s | no turn with no traffic light |
122+
| f | j | 24.2s | no turn with traffic light |
123+
| f | h | 20.7s | turn with no traffic light |
124+
| j | h | 21.9s | no turn with no traffic light |
125+
| j | f | 22.2s | no turn with traffic light |
126+
| j | i | 18.7s | turn with no traffic light |
127+
| i | j | 21.9s | no turn with no traffic light |
128+
| i | h | 11s | no turn with traffic light |
129+
| i | f | 18.7s | turn with no traffic light |
130+
| h | f | 23.9s | no turn with no traffic light |
131+
| h | i | 13s | no turn with traffic light |
132+
| h | j | 20.7s | turn with no traffic light |
133+
134+
| k | n | 21.9s | no turn with no traffic light |
135+
| k | o | 22.2s | no turn with traffic light |
136+
| k | l | 18.7s | turn with no traffic light |
137+
| o | l | 23.9s | no turn with no traffic light |
138+
| o | k | 24.2s | no turn with traffic light |
139+
| o | n | 20.7s | turn with no traffic light |
140+
| n | o | 23.9s | no turn with no traffic light |
141+
| n | l | 13s | no turn with traffic light |
142+
| n | k | 20.7s | turn with no traffic light |
143+
| l | k | 21.9s | no turn with no traffic light |
144+
| l | n | 11s | no turn with traffic light |
145+
| l | o | 18.7s | turn with no traffic light |
146+
147+
148+
Scenario: Traffic Signal Geometry
43149
Given the query options
44150
| overview | full |
45151
| geometries | polyline |
@@ -61,6 +167,53 @@ Feature: Car - Handle traffic lights
61167
| from | to | route | geometry |
62168
| a | c | abc,abc | _ibE_ibE?gJ?eJ |
63169

170+
171+
Scenario: Traffic Signal Geometry - forward signal
172+
Given the query options
173+
| overview | full |
174+
| geometries | polyline |
175+
176+
Given the node map
177+
"""
178+
a - b - c
179+
"""
180+
181+
And the ways
182+
| nodes | highway |
183+
| abc | primary |
184+
185+
And the nodes
186+
| node | highway | traffic_signals:direction |
187+
| b | traffic_signals | forward |
188+
189+
When I route I should get
190+
| from | to | route | geometry |
191+
| a | c | abc,abc | _ibE_ibE?gJ?eJ |
192+
193+
194+
Scenario: Traffic Signal Geometry - reverse signal
195+
Given the query options
196+
| overview | full |
197+
| geometries | polyline |
198+
199+
Given the node map
200+
"""
201+
a - b - c
202+
"""
203+
204+
And the ways
205+
| nodes | highway |
206+
| abc | primary |
207+
208+
And the nodes
209+
| node | highway | traffic_signals:direction |
210+
| b | traffic_signals | reverse |
211+
212+
When I route I should get
213+
| from | to | route | geometry |
214+
| a | c | abc,abc | _ibE_ibE?gJ?eJ |
215+
216+
64217
@traffic
65218
Scenario: Traffic update on the edge with a traffic signal
66219
Given the node map
@@ -91,3 +244,67 @@ Feature: Car - Handle traffic lights
91244
| from | to | route | speed | weights | time | distances | a:datasources | a:nodes | a:speed | a:duration | a:weight |
92245
| a | c | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 1:0 | 1:2:3 | 18:18 | 11.1:11.1 | 11.1:11.1 |
93246
| c | a | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 0:1 | 3:2:1 | 18:18 | 11.1:11.1 | 11.1:11.1 |
247+
248+
249+
@traffic
250+
Scenario: Traffic update on the edge with a traffic signal - forward
251+
Given the node map
252+
"""
253+
a - b - c
254+
"""
255+
256+
And the ways
257+
| nodes | highway |
258+
| abc | primary |
259+
260+
261+
And the nodes
262+
| node | highway | traffic_signals:direction |
263+
| b | traffic_signals | forward |
264+
265+
And the contract extra arguments "--segment-speed-file {speeds_file}"
266+
And the customize extra arguments "--segment-speed-file {speeds_file}"
267+
And the speed file
268+
"""
269+
1,2,65
270+
2,1,65
271+
"""
272+
And the query options
273+
| annotations | datasources,nodes,speed,duration,weight |
274+
275+
When I route I should get
276+
| from | to | route | speed | weights | time | distances | a:datasources | a:nodes | a:speed | a:duration | a:weight |
277+
| a | c | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 1:0 | 1:2:3 | 18:18 | 11.1:11.1 | 11.1:11.1 |
278+
| c | a | abc,abc | 65 km/h | 22.2,0 | 22.2s | 400m,0m | 0:1 | 3:2:1 | 18:18 | 11.1:11.1 | 11.1:11.1 |
279+
280+
281+
@traffic
282+
Scenario: Traffic update on the edge with a traffic signal - backward
283+
Given the node map
284+
"""
285+
a - b - c
286+
"""
287+
288+
And the ways
289+
| nodes | highway |
290+
| abc | primary |
291+
292+
293+
And the nodes
294+
| node | highway | traffic_signals:direction |
295+
| b | traffic_signals | backward |
296+
297+
And the contract extra arguments "--segment-speed-file {speeds_file}"
298+
And the customize extra arguments "--segment-speed-file {speeds_file}"
299+
And the speed file
300+
"""
301+
1,2,65
302+
2,1,65
303+
"""
304+
And the query options
305+
| annotations | datasources,nodes,speed,duration,weight |
306+
307+
When I route I should get
308+
| from | to | route | speed | weights | time | distances | a:datasources | a:nodes | a:speed | a:duration | a:weight |
309+
| a | c | abc,abc | 65 km/h | 22.2,0 | 22.2s | 400m,0m | 1:0 | 1:2:3 | 18:18 | 11.1:11.1 | 11.1:11.1 |
310+
| c | a | abc,abc | 60 km/h | 24.2,0 | 24.2s | 400m,0m | 0:1 | 3:2:1 | 18:18 | 11.1:11.1 | 11.1:11.1 |

include/extractor/edge_based_graph_factory.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "util/typedefs.hpp"
2424

2525
#include "storage/io.hpp"
26+
#include "traffic_signals.hpp"
2627

2728
#include <algorithm>
2829
#include <cstddef>
@@ -68,7 +69,7 @@ class EdgeBasedGraphFactory
6869
EdgeBasedNodeDataContainer &node_data_container,
6970
const CompressedEdgeContainer &compressed_edge_container,
7071
const std::unordered_set<NodeID> &barrier_nodes,
71-
const std::unordered_set<NodeID> &traffic_lights,
72+
const TrafficSignals &traffic_signals,
7273
const std::vector<util::Coordinate> &coordinates,
7374
const NameTable &name_table,
7475
const std::unordered_set<EdgeID> &segregated_edges,
@@ -134,7 +135,7 @@ class EdgeBasedGraphFactory
134135
const util::NodeBasedDynamicGraph &m_node_based_graph;
135136

136137
const std::unordered_set<NodeID> &m_barrier_nodes;
137-
const std::unordered_set<NodeID> &m_traffic_lights;
138+
const TrafficSignals &m_traffic_signals;
138139
const CompressedEdgeContainer &m_compressed_edge_container;
139140

140141
const NameTable &name_table;

include/extractor/extraction_containers.hpp

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,11 @@
88
#include "extractor/scripting_environment.hpp"
99

1010
#include "storage/tar_fwd.hpp"
11+
#include "traffic_lights.hpp"
12+
#include "traffic_signals.hpp"
1113

1214
#include <unordered_map>
15+
#include <unordered_set>
1316

1417
namespace osrm
1518
{
@@ -25,15 +28,19 @@ namespace extractor
2528
class ExtractionContainers
2629
{
2730
using ReferencedWays = std::unordered_map<OSMWayID, NodesOfWay>;
31+
using ReferencedTrafficSignals =
32+
std::pair<std::unordered_set<OSMNodeID>, std::unordered_multimap<OSMNodeID, OSMNodeID>>;
2833
// The relationship between way and nodes is lost during node preparation.
29-
// We identify the ways and nodes relevant to restrictions/overrides prior to
34+
// We identify the ways and nodes relevant to restrictions/overrides/signals prior to
3035
// node processing so that they can be referenced in the preparation phase.
3136
ReferencedWays IdentifyRestrictionWays();
3237
ReferencedWays IdentifyManeuverOverrideWays();
38+
ReferencedTrafficSignals IdentifyTrafficSignals();
3339

3440
void PrepareNodes();
3541
void PrepareManeuverOverrides(const ReferencedWays &maneuver_override_ways);
3642
void PrepareRestrictions(const ReferencedWays &restriction_ways);
43+
void PrepareTrafficSignals(const ReferencedTrafficSignals &referenced_traffic_signals);
3744
void PrepareEdges(ScriptingEnvironment &scripting_environment);
3845

3946
void WriteNodes(storage::tar::FileWriter &file_out) const;
@@ -50,9 +57,9 @@ class ExtractionContainers
5057
using NameOffsets = std::vector<size_t>;
5158
using WayIDVector = std::vector<OSMWayID>;
5259
using WayNodeIDOffsets = std::vector<size_t>;
60+
using InputTrafficSignal = std::pair<OSMNodeID, TrafficLightClass::Direction>;
5361

5462
std::vector<OSMNodeID> barrier_nodes;
55-
std::vector<OSMNodeID> traffic_signals;
5663
NodeIDVector used_node_id_list;
5764
NodeVector all_nodes_list;
5865
EdgeVector all_edges_list;
@@ -65,6 +72,9 @@ class ExtractionContainers
6572

6673
unsigned max_internal_node_id;
6774

75+
std::vector<InputTrafficSignal> external_traffic_signals;
76+
TrafficSignals internal_traffic_signals;
77+
6878
// List of restrictions (conditional and unconditional) before we transform them into the
6979
// output types. Input containers reference OSMNodeIDs. We can only transform them to the
7080
// correct internal IDs after we've read everything. Without a multi-parse approach,

include/extractor/extraction_node.hpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
#ifndef EXTRACTION_NODE_HPP
22
#define EXTRACTION_NODE_HPP
33

4+
#include "traffic_lights.hpp"
5+
46
namespace osrm
57
{
68
namespace extractor
79
{
810

911
struct ExtractionNode
1012
{
11-
ExtractionNode() : traffic_lights(false), barrier(false) {}
12-
void clear() { traffic_lights = barrier = false; }
13-
bool traffic_lights;
13+
ExtractionNode() : traffic_lights(TrafficLightClass::NONE), barrier(false) {}
14+
void clear()
15+
{
16+
traffic_lights = TrafficLightClass::NONE;
17+
barrier = false;
18+
}
19+
TrafficLightClass::Direction traffic_lights;
1420
bool barrier;
1521
};
1622
} // namespace extractor

include/extractor/extractor.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
4343
#include "util/guidance/turn_lanes.hpp"
4444

4545
#include "restriction_graph.hpp"
46+
#include "traffic_signals.hpp"
4647
#include "util/typedefs.hpp"
4748

4849
namespace osrm
@@ -64,7 +65,8 @@ class Extractor
6465

6566
std::tuple<LaneDescriptionMap,
6667
std::vector<TurnRestriction>,
67-
std::vector<UnresolvedManeuverOverride>>
68+
std::vector<UnresolvedManeuverOverride>,
69+
TrafficSignals>
6870
ParseOSMData(ScriptingEnvironment &scripting_environment, const unsigned number_of_threads);
6971

7072
EdgeID BuildEdgeExpandedGraph(
@@ -73,7 +75,7 @@ class Extractor
7375
const std::vector<util::Coordinate> &coordinates,
7476
const CompressedEdgeContainer &compressed_edge_container,
7577
const std::unordered_set<NodeID> &barrier_nodes,
76-
const std::unordered_set<NodeID> &traffic_lights,
78+
const TrafficSignals &traffic_signals,
7779
const RestrictionGraph &restriction_graph,
7880
const std::unordered_set<EdgeID> &segregated_edges,
7981
const NameTable &name_table,

include/extractor/files.hpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -444,10 +444,9 @@ inline void readConditionalRestrictions(const boost::filesystem::path &path,
444444
}
445445

446446
// reads .osrm file which is a temporary file of osrm-extract
447-
template <typename BarrierOutIter, typename TrafficSignalsOutIter, typename PackedOSMIDsT>
447+
template <typename BarrierOutIter, typename PackedOSMIDsT>
448448
void readRawNBGraph(const boost::filesystem::path &path,
449449
BarrierOutIter barriers,
450-
TrafficSignalsOutIter traffic_signals,
451450
std::vector<util::Coordinate> &coordinates,
452451
PackedOSMIDsT &osm_node_ids,
453452
std::vector<extractor::NodeBasedEdge> &edge_list,
@@ -471,8 +470,6 @@ void readRawNBGraph(const boost::filesystem::path &path,
471470

472471
reader.ReadStreaming<NodeID>("/extractor/barriers", barriers);
473472

474-
reader.ReadStreaming<NodeID>("/extractor/traffic_lights", traffic_signals);
475-
476473
storage::serialization::read(reader, "/extractor/edges", edge_list);
477474
storage::serialization::read(reader, "/extractor/annotations", annotations);
478475
}

0 commit comments

Comments
 (0)