Skip to main content

rustsim_mobility/
leg.rs

1//! Trip plans made of per-mode [`Leg`]s.
2
3use rustsim_geometry::vec3::Vec3;
4use rustsim_modes::TravelMode;
5use rustsim_transit::{RouteId, StopId};
6
7/// A labelled point along a trip. Positions are 3-D so layered-building
8/// transitions (floors, lifts) can be expressed natively.
9#[derive(Debug, Clone, Copy, PartialEq)]
10pub struct Waypoint {
11    /// Position in metres.
12    pub pos: Vec3,
13    /// Associated floor index (for layered 2.5-D); ignored otherwise.
14    pub floor: i32,
15}
16
17impl Waypoint {
18    /// Construct a ground-floor waypoint.
19    pub fn ground(x: f64, y: f64) -> Self {
20        Self {
21            pos: [x, y, 0.0],
22            floor: 0,
23        }
24    }
25}
26
27/// A single leg of a multi-modal trip.
28#[derive(Debug, Clone)]
29pub enum Leg {
30    /// Walk between two waypoints (possibly across floors via connectors).
31    Walk {
32        /// Starting point.
33        from: Waypoint,
34        /// Ending point.
35        to: Waypoint,
36    },
37    /// Ride a private vehicle (car, bicycle, motorcycle) between two waypoints.
38    DriveSelf {
39        /// Vehicle mode.
40        mode: TravelMode,
41        /// Starting point.
42        from: Waypoint,
43        /// Ending point.
44        to: Waypoint,
45    },
46    /// Hail or board a shared ride (taxi, ride-hail) between two waypoints.
47    Hail {
48        /// Transport mode (usually `Vehicle`).
49        mode: TravelMode,
50        /// Starting point.
51        from: Waypoint,
52        /// Ending point.
53        to: Waypoint,
54    },
55    /// Board a fixed-route transit service.
56    Transit {
57        /// Route to board.
58        route: RouteId,
59        /// Stop to board at.
60        board_at: StopId,
61        /// Stop to alight at.
62        alight_at: StopId,
63    },
64    /// Ride a vertical connector (stair/escalator/ramp/lift).
65    Connector {
66        /// Connector identifier, opaque to this crate.
67        connector_id: u64,
68    },
69}
70
71impl Leg {
72    /// Travel mode associated with this leg.
73    pub fn mode(&self) -> TravelMode {
74        match self {
75            Leg::Walk { .. } | Leg::Connector { .. } => TravelMode::Pedestrian,
76            Leg::DriveSelf { mode, .. } | Leg::Hail { mode, .. } => *mode,
77            Leg::Transit { .. } => TravelMode::Transit,
78        }
79    }
80}
81
82/// A planned multi-modal trip.
83#[derive(Debug, Clone)]
84pub struct TripPlan {
85    /// Stable trip identifier.
86    pub id: u64,
87    /// Ordered legs.
88    pub legs: Vec<Leg>,
89}
90
91impl TripPlan {
92    /// Number of legs.
93    pub fn len(&self) -> usize {
94        self.legs.len()
95    }
96
97    /// True if the trip has no legs.
98    pub fn is_empty(&self) -> bool {
99        self.legs.is_empty()
100    }
101}
102
103#[cfg(test)]
104mod tests {
105    use super::*;
106
107    #[test]
108    fn leg_mode_dispatch() {
109        let walk = Leg::Walk {
110            from: Waypoint::ground(0.0, 0.0),
111            to: Waypoint::ground(1.0, 0.0),
112        };
113        assert_eq!(walk.mode(), TravelMode::Pedestrian);
114
115        let transit = Leg::Transit {
116            route: 1,
117            board_at: 10,
118            alight_at: 20,
119        };
120        assert_eq!(transit.mode(), TravelMode::Transit);
121
122        let drive = Leg::DriveSelf {
123            mode: TravelMode::Vehicle,
124            from: Waypoint::ground(0.0, 0.0),
125            to: Waypoint::ground(5.0, 0.0),
126        };
127        assert_eq!(drive.mode(), TravelMode::Vehicle);
128    }
129}