map_model/edits/
perma_traffic_signal.rs

1//! A representation of traffic signal configuration that references OpenStreetMap IDs and is
2//! hopefully robust to minor edits over time.
3
4use std::collections::BTreeSet;
5
6use serde::{Deserialize, Serialize};
7
8#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
9pub struct TrafficSignal {
10    /// The ID of the OSM node representing the intersection with the traffic signal. This node
11    /// should be tagged `highway = traffic_signals` in OSM.
12    ///
13    /// TODO Describe how consolidated intersections are handled.
14    pub intersection_osm_node_id: i64,
15    /// The traffic signal uses configuration from one plan at a time. The plans must be listed in
16    /// order of ascending `start_time_seconds`, the first plan must begin at `0` (midnight), and
17    /// the last plan must not start after 24 hours.
18    pub plans: Vec<Plan>,
19}
20
21/// A plan describes how a traffic signal is configured during some period of time. Multiple plans
22/// allow a single intersection to behave differently in the middle of the night with low traffic,
23/// compared to the middle of rush hour.
24#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
25pub struct Plan {
26    /// This plan takes effect at this local time, measured in seconds after midnight. The plan
27    /// lasts until the next plan in the listed sequence starts, or ends at midnight if it's the
28    /// last plan.
29    pub start_time_seconds: usize,
30    /// The traffic signal repeatedly cycles through these stages. During each stage, only some
31    /// turns are protected and permitted through the intersection.
32    pub stages: Vec<Stage>,
33    /// Relative to a central clock, delay the first stage by this many seconds.
34    pub offset_seconds: usize,
35}
36
37/// A traffic signal is in one stage at any time. The stage describes what movements are possible.
38#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
39pub struct Stage {
40    /// During this stage, these turns can be performed with the highest priority, protected by a
41    /// green light. No two protected turns in the same stage should cross; that would be a
42    /// conflict.
43    pub protected_turns: BTreeSet<Turn>,
44    /// During this stage, these turns can be performed after yielding. For example, an unprotected
45    /// left turn after yielding to oncoming traffic, or a right turn on red after yielding to
46    /// oncoming traffic and crosswalks.
47    pub permitted_turns: BTreeSet<Turn>,
48    /// The stage lasts this long before moving to the next one.
49    pub stage_type: StageType,
50}
51
52/// How long a stage lasts before moving to the next one.
53#[derive(Serialize, Deserialize, Clone, Debug, PartialEq)]
54pub enum StageType {
55    /// A fixed number of seconds.
56    Fixed(usize),
57    /// Minimum, Delay, Additional
58    /// Minimum is the minimum cycle duration, 0 allows it to be skipped if no demand.
59    /// Delay is the duration with no demand needed to end a cycle, 0 ends as soon as there is no
60    /// demand. Additional is the maximum additional duration for an extended cycle. If minimum
61    /// is 20, and additional is 40, the maximum cycle duration is 60.
62    /// If there are crosswalks, the minimum is the minimum for the maximum crosswalks
63    Variable(usize, usize, usize),
64}
65
66/// A movement through an intersection.
67///
68/// Movements over crosswalks are a little confusing to understand. See the crosswalk_turns.png
69/// diagram in this repository for some clarification.
70#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
71pub struct Turn {
72    /// The movement begins at the end of this road segment.
73    pub from: DirectedRoad,
74    /// The movement ends at the beginning of this road segment.
75    pub to: DirectedRoad,
76    /// The ID of the OSM node representing the intersection. This is redundant for turns performed
77    /// by vehicles, but is necessary for disambiguating the 4 cases of crosswalks.
78    pub intersection_osm_node_id: i64,
79    /// True iff the movement is along a crosswalk. Note that moving over a crosswalk has a
80    /// different `Turn` for each direction.
81    pub is_crosswalk: bool,
82}
83
84/// A road segment connecting two intersections, and a direction along the segment.
85#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
86pub struct DirectedRoad {
87    /// The ID of the OSM way representing the road.
88    pub osm_way_id: i64,
89    /// The ID of the OSM node at the start of this road segment.
90    pub osm_node1: i64,
91    /// The ID of the OSM node at the end of this road segment.
92    pub osm_node2: i64,
93    /// The direction along the road segment. See
94    /// https://wiki.openstreetmap.org/wiki/Forward_%26_backward,_left_%26_right for details.
95    pub is_forwards: bool,
96}