Skip to content

Commit

Permalink
Support OSM traffic signal directions (#6153)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
mjjbell authored Aug 30, 2022
1 parent d8b358e commit b17cbb4
Show file tree
Hide file tree
Showing 26 changed files with 649 additions and 140 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
- FIXED: Improvements to maneuver override processing [#6125](https://github.com/Project-OSRM/osrm-backend/pull/6125)
- ADDED: Support snapping to multiple ways at an input location. [#5953](https://github.com/Project-OSRM/osrm-backend/pull/5953)
- FIXED: Fix snapping target locations to ways used in turn restrictions. [#6339](https://github.com/Project-OSRM/osrm-backend/pull/6339)
- ADDED: Support OSM traffic signal directions. [#6153](https://github.com/Project-OSRM/osrm-backend/pull/6153)

# 5.26.0
- Changes from 5.25.0
Expand Down
219 changes: 218 additions & 1 deletion features/car/traffic_light_penalties.feature
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,113 @@ Feature: Car - Handle traffic lights
| k | n | 20.7s | turn with traffic light |


Scenario: Tarrif Signal Geometry
Scenario: Car - Traffic signal direction
Given the node map
"""
a-1-b-2-c
d-3-e-4-f
g-5-h-6-i
j-7-k-8-l
"""

And the ways
| nodes | highway |
| abc | primary |
| def | primary |
| ghi | primary |
| jkl | primary |

And the nodes
| node | highway | traffic_signals:direction |
| e | traffic_signals | |
| h | traffic_signals | forward |
| k | traffic_signals | backward |

When I route I should get
| from | to | time | # |
| 1 | 2 | 11.1s | no turn with no traffic light |
| 2 | 1 | 11.1s | no turn with no traffic light |
| 3 | 4 | 13.1s | no turn with traffic light |
| 4 | 3 | 13.1s | no turn with traffic light |
| 5 | 6 | 13.1s | no turn with traffic light |
| 6 | 5 | 11.1s | no turn with no traffic light |
| 7 | 8 | 11.1s | no turn with no traffic light |
| 8 | 7 | 13.1s | no turn with traffic light |


Scenario: Car - Encounters a traffic light
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 | primary |
| hgi | primary |
| fgj | primary |
| lmn | primary |
| kmo | primary |

And the nodes

This comment has been minimized.

Copy link
@hy05190134

hy05190134 Sep 12, 2023

Is there lack of the traffic description of node c, because when route from a to e get traffic light below

This comment has been minimized.

Copy link
@hy05190134

This comment has been minimized.

Copy link
@mjjbell

mjjbell Mar 16, 2024

Author Member

Yes the comments do not reflect the test configuration. Will update in a new PR.

| node | highway | traffic_signals:direction |
| g | traffic_signals | forward |
| m | traffic_signals | backward |


When I route I should get
| from | to | time | # |
| a | d | 21.9s | no turn with no traffic light |
| a | e | 22.2s | no turn with traffic light |
| a | b | 18.7s | turn with no traffic light |
| e | b | 21.9s | no turn with no traffic light |
| e | a | 22.2s | no turn with traffic light |
| e | d | 18.7s | turn with no traffic light |
| d | e | 21.9s | no turn with no traffic light |
| d | b | 11s | no turn with traffic light |
| d | a | 18.7s | turn with no traffic light |
| b | a | 21.9s | no turn with no traffic light |
| b | d | 11s | no turn with traffic light |
| b | e | 18.7s | turn with no traffic light |

| f | i | 23.9s | no turn with no traffic light |
| f | j | 24.2s | no turn with traffic light |
| f | h | 20.7s | turn with no traffic light |
| j | h | 21.9s | no turn with no traffic light |
| j | f | 22.2s | no turn with traffic light |
| j | i | 18.7s | turn with no traffic light |
| i | j | 21.9s | no turn with no traffic light |
| i | h | 11s | no turn with traffic light |
| i | f | 18.7s | turn with no traffic light |
| h | f | 23.9s | no turn with no traffic light |
| h | i | 13s | no turn with traffic light |
| h | j | 20.7s | turn with no traffic light |

| k | n | 21.9s | no turn with no traffic light |
| k | o | 22.2s | no turn with traffic light |
| k | l | 18.7s | turn with no traffic light |
| o | l | 23.9s | no turn with no traffic light |
| o | k | 24.2s | no turn with traffic light |
| o | n | 20.7s | turn with no traffic light |
| n | o | 23.9s | no turn with no traffic light |
| n | l | 13s | no turn with traffic light |
| n | k | 20.7s | turn with no traffic light |
| l | k | 21.9s | no turn with no traffic light |
| l | n | 11s | no turn with traffic light |
| l | o | 18.7s | turn with no traffic light |


Scenario: Traffic Signal Geometry
Given the query options
| overview | full |
| geometries | polyline |
Expand All @@ -61,6 +167,53 @@ Feature: Car - Handle traffic lights
| from | to | route | geometry |
| a | c | abc,abc | _ibE_ibE?gJ?eJ |


Scenario: Traffic Signal Geometry - forward signal
Given the query options
| overview | full |
| geometries | polyline |

Given the node map
"""
a - b - c
"""

And the ways
| nodes | highway |
| abc | primary |

And the nodes
| node | highway | traffic_signals:direction |
| b | traffic_signals | forward |

When I route I should get
| from | to | route | geometry |
| a | c | abc,abc | _ibE_ibE?gJ?eJ |


Scenario: Traffic Signal Geometry - reverse signal
Given the query options
| overview | full |
| geometries | polyline |

Given the node map
"""
a - b - c
"""

And the ways
| nodes | highway |
| abc | primary |

And the nodes
| node | highway | traffic_signals:direction |
| b | traffic_signals | reverse |

When I route I should get
| from | to | route | geometry |
| a | c | abc,abc | _ibE_ibE?gJ?eJ |


@traffic
Scenario: Traffic update on the edge with a traffic signal
Given the node map
Expand Down Expand Up @@ -91,3 +244,67 @@ Feature: Car - Handle traffic lights
| from | to | route | speed | weights | time | distances | a:datasources | a:nodes | a:speed | a:duration | a:weight |
| 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 |
| 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 |


@traffic
Scenario: Traffic update on the edge with a traffic signal - forward
Given the node map
"""
a - b - c
"""

And the ways
| nodes | highway |
| abc | primary |


And the nodes
| node | highway | traffic_signals:direction |
| b | traffic_signals | forward |

And the contract extra arguments "--segment-speed-file {speeds_file}"
And the customize extra arguments "--segment-speed-file {speeds_file}"
And the speed file
"""
1,2,65
2,1,65
"""
And the query options
| annotations | datasources,nodes,speed,duration,weight |

When I route I should get
| from | to | route | speed | weights | time | distances | a:datasources | a:nodes | a:speed | a:duration | a:weight |
| 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 |
| 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 |


@traffic
Scenario: Traffic update on the edge with a traffic signal - backward
Given the node map
"""
a - b - c
"""

And the ways
| nodes | highway |
| abc | primary |


And the nodes
| node | highway | traffic_signals:direction |
| b | traffic_signals | backward |

And the contract extra arguments "--segment-speed-file {speeds_file}"
And the customize extra arguments "--segment-speed-file {speeds_file}"
And the speed file
"""
1,2,65
2,1,65
"""
And the query options
| annotations | datasources,nodes,speed,duration,weight |

When I route I should get
| from | to | route | speed | weights | time | distances | a:datasources | a:nodes | a:speed | a:duration | a:weight |
| 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 |
| 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 |
5 changes: 3 additions & 2 deletions include/extractor/edge_based_graph_factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "util/typedefs.hpp"

#include "storage/io.hpp"
#include "traffic_signals.hpp"

#include <algorithm>
#include <cstddef>
Expand Down Expand Up @@ -68,7 +69,7 @@ class EdgeBasedGraphFactory
EdgeBasedNodeDataContainer &node_data_container,
const CompressedEdgeContainer &compressed_edge_container,
const std::unordered_set<NodeID> &barrier_nodes,
const std::unordered_set<NodeID> &traffic_lights,
const TrafficSignals &traffic_signals,
const std::vector<util::Coordinate> &coordinates,
const NameTable &name_table,
const std::unordered_set<EdgeID> &segregated_edges,
Expand Down Expand Up @@ -134,7 +135,7 @@ class EdgeBasedGraphFactory
const util::NodeBasedDynamicGraph &m_node_based_graph;

const std::unordered_set<NodeID> &m_barrier_nodes;
const std::unordered_set<NodeID> &m_traffic_lights;
const TrafficSignals &m_traffic_signals;
const CompressedEdgeContainer &m_compressed_edge_container;

const NameTable &name_table;
Expand Down
14 changes: 12 additions & 2 deletions include/extractor/extraction_containers.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@
#include "extractor/scripting_environment.hpp"

#include "storage/tar_fwd.hpp"
#include "traffic_lights.hpp"
#include "traffic_signals.hpp"

#include <unordered_map>
#include <unordered_set>

namespace osrm
{
Expand All @@ -25,15 +28,19 @@ namespace 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 prior to
// We identify the ways and nodes relevant to restrictions/overrides/signals prior to
// node processing so that they can be referenced in the preparation phase.
ReferencedWays IdentifyRestrictionWays();
ReferencedWays IdentifyManeuverOverrideWays();
ReferencedTrafficSignals IdentifyTrafficSignals();

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 WriteNodes(storage::tar::FileWriter &file_out) const;
Expand All @@ -50,9 +57,9 @@ 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;
std::vector<OSMNodeID> traffic_signals;
NodeIDVector used_node_id_list;
NodeVector all_nodes_list;
EdgeVector all_edges_list;
Expand All @@ -65,6 +72,9 @@ class ExtractionContainers

unsigned max_internal_node_id;

std::vector<InputTrafficSignal> external_traffic_signals;
TrafficSignals internal_traffic_signals;

// List of restrictions (conditional and unconditional) before we transform them into the
// output types. Input containers reference OSMNodeIDs. We can only transform them to the
// correct internal IDs after we've read everything. Without a multi-parse approach,
Expand Down
12 changes: 9 additions & 3 deletions include/extractor/extraction_node.hpp
Original file line number Diff line number Diff line change
@@ -1,16 +1,22 @@
#ifndef EXTRACTION_NODE_HPP
#define EXTRACTION_NODE_HPP

#include "traffic_lights.hpp"

namespace osrm
{
namespace extractor
{

struct ExtractionNode
{
ExtractionNode() : traffic_lights(false), barrier(false) {}
void clear() { traffic_lights = barrier = false; }
bool traffic_lights;
ExtractionNode() : traffic_lights(TrafficLightClass::NONE), barrier(false) {}
void clear()
{
traffic_lights = TrafficLightClass::NONE;
barrier = false;
}
TrafficLightClass::Direction traffic_lights;
bool barrier;
};
} // namespace extractor
Expand Down
6 changes: 4 additions & 2 deletions include/extractor/extractor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ 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
Expand All @@ -64,7 +65,8 @@ class Extractor

std::tuple<LaneDescriptionMap,
std::vector<TurnRestriction>,
std::vector<UnresolvedManeuverOverride>>
std::vector<UnresolvedManeuverOverride>,
TrafficSignals>
ParseOSMData(ScriptingEnvironment &scripting_environment, const unsigned number_of_threads);

EdgeID BuildEdgeExpandedGraph(
Expand All @@ -73,7 +75,7 @@ class Extractor
const std::vector<util::Coordinate> &coordinates,
const CompressedEdgeContainer &compressed_edge_container,
const std::unordered_set<NodeID> &barrier_nodes,
const std::unordered_set<NodeID> &traffic_lights,
const TrafficSignals &traffic_signals,
const RestrictionGraph &restriction_graph,
const std::unordered_set<EdgeID> &segregated_edges,
const NameTable &name_table,
Expand Down
5 changes: 1 addition & 4 deletions include/extractor/files.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -444,10 +444,9 @@ inline void readConditionalRestrictions(const boost::filesystem::path &path,
}

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

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

reader.ReadStreaming<NodeID>("/extractor/traffic_lights", traffic_signals);

storage::serialization::read(reader, "/extractor/edges", edge_list);
storage::serialization::read(reader, "/extractor/annotations", annotations);
}
Expand Down
Loading

0 comments on commit b17cbb4

Please sign in to comment.