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}