gistools/readers/gtfs/schedule/pathways.rs
1use crate::readers::csv::parse_csv_as_record;
2use alloc::{collections::BTreeMap, string::String};
3use s2json::MValueCompatible;
4
5/// Describes the type of pathway between two stops or station nodes.
6///
7/// 1 - Walkway
8/// 2 - Stairs
9/// 3 - Moving sidewalk (travelator)
10/// 4 - Escalator
11/// 5 - Elevator
12/// 6 - Fare gate (payment gate)
13/// 7 - Exit gate
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
15pub enum GTFSPathwayMode {
16 /// 1 - Walkway
17 Walkway = 1,
18 /// 2 - Stairs
19 Stairs = 2,
20 /// 3 - Moving sidewalk (travelator)
21 MovingSidewalk = 3,
22 /// 4 - Escalator
23 Escalator = 4,
24 /// 5 - Elevator
25 Elevator = 5,
26 /// 6 - Fare gate (payment gate)
27 FareGate = 6,
28 /// 7 - Exit gate
29 ExitGate = 7,
30}
31impl From<i8> for GTFSPathwayMode {
32 fn from(s: i8) -> Self {
33 match s {
34 2 => GTFSPathwayMode::Stairs,
35 3 => GTFSPathwayMode::MovingSidewalk,
36 4 => GTFSPathwayMode::Escalator,
37 5 => GTFSPathwayMode::Elevator,
38 6 => GTFSPathwayMode::FareGate,
39 7 => GTFSPathwayMode::ExitGate,
40 _ => GTFSPathwayMode::Walkway,
41 }
42 }
43}
44
45/// Indicates whether a pathway can be used in both directions:
46///
47/// 0 - Unidirectional
48/// 1 - Bidirectional
49///
50/// Note: Exit gates (pathway_mode=7) must not be bidirectional.
51#[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)]
52pub enum GTFSIsBidirectional {
53 /// 0 - Unidirectional
54 Unidirectional = 0,
55 /// 1 - Bidirectional
56 Bidirectional = 1,
57}
58impl From<i8> for GTFSIsBidirectional {
59 fn from(s: i8) -> Self {
60 match s {
61 1 => GTFSIsBidirectional::Bidirectional,
62 _ => GTFSIsBidirectional::Unidirectional,
63 }
64 }
65}
66
67/// # Pathways
68///
69/// **Optional**
70/// Represents edges in a station graph describing station interiors, connecting
71/// platforms, entrances/exits, generic nodes, or boarding areas.
72///
73/// **Primary Key**: (pathway_id)
74///
75/// Pathways must be complete if included:
76/// - No dangling locations if any pathways exist, except for platforms that have boarding areas.
77/// - Platforms with boarding areas must not have pathways directly; their boarding areas do.
78/// - Each platform (location_type=0) or boarding area (4) must have at least
79/// one path to an entrance/exit (2) unless it’s impossible for riders to exit at that platform.
80#[derive(Debug, Default, Clone, PartialEq, MValueCompatible)]
81pub struct GTFSPathway {
82 /// **Required**
83 /// Unique ID for the pathway record.
84 pub pathway_id: String,
85 /// **Required**
86 /// The stop or node from which this pathway begins.
87 /// Must be location_type=0, 2, 3, or 4 (platform, entrance/exit, generic node, or boarding area).
88 /// Stations (location_type=1) are forbidden here.
89 pub from_stop_id: String,
90 /// **Required**
91 /// The stop or node at which this pathway ends.
92 /// Must be location_type=0, 2, 3, or 4 (platform, entrance/exit, generic node, or boarding area).
93 /// Stations (location_type=1) are forbidden here.
94 pub to_stop_id: String,
95 /// **Required**
96 /// Pathway mode, e.g. walkway, stairs, escalator.
97 pub pathway_mode: i8, // GTFSPathwayMode;
98 /// **Required**
99 /// 0 = Unidirectional, 1 = Bidirectional
100 pub is_bidirectional: i8, // GTFSIsBidirectional;
101 /// **Optional**
102 /// Horizontal length in meters of the pathway.
103 /// Recommended for walkway, fare gate, exit gate.
104 pub length: Option<f64>,
105 /// **Optional**
106 /// Average time in seconds needed to traverse this pathway.
107 /// Recommended for moving sidewalk, escalator, elevator.
108 pub traversal_time: Option<i64>,
109 /// **Optional**
110 /// Number of stairs in this pathway.
111 /// Positive: fromStopId to toStopId goes upwards
112 /// Negative: fromStopId to toStopId goes downwards
113 /// Recommended for pathway_mode=2 (stairs).
114 pub stair_count: Option<i32>,
115 /// **Optional**
116 /// Maximum slope ratio. Positive for upwards, negative for downwards.
117 /// E.g., 0.083 is an 8.3% slope.
118 /// Used for walkway (1) or moving sidewalk (3) if relevant.
119 pub max_slope: Option<f64>,
120 /// **Optional**
121 /// Minimum width of the pathway in meters, recommended if less than 1 meter.
122 pub min_width: Option<f64>,
123 /// **Optional**
124 /// Public facing text on signage to help riders navigate (e.g. "Follow signs to X").
125 pub signposted_as: Option<String>,
126 /// **Optional**
127 /// Public facing text on signage when traversing the pathway in reverse
128 /// (toStopId -> fromStopId), if different from `signpostedAs`.
129 pub reversed_signposted_as: Option<String>,
130}
131impl GTFSPathway {
132 /// Create a new GTFSPathway
133 pub fn new(source: &str) -> BTreeMap<String, GTFSPathway> {
134 let mut res = BTreeMap::new();
135 for record in parse_csv_as_record::<GTFSPathway>(source, None, None) {
136 res.insert(record.pathway_id.clone(), record);
137 }
138 res
139 }
140 /// Get the pathway_mode
141 pub fn pathway_mode(&self) -> GTFSPathwayMode {
142 GTFSPathwayMode::from(self.pathway_mode)
143 }
144 /// Get the is_bidirectional
145 pub fn is_bidirectional(&self) -> GTFSIsBidirectional {
146 GTFSIsBidirectional::from(self.is_bidirectional)
147 }
148}