sim/
transit.rs

1use std::collections::{BTreeMap, BTreeSet};
2
3use serde::{Deserialize, Serialize};
4
5use abstutil::{deserialize_btreemap, serialize_btreemap};
6use geom::Time;
7use map_model::{Map, Path, TransitRoute, TransitRouteID, TransitStopID};
8
9use crate::sim::Ctx;
10use crate::{
11    AgentID, CarID, DrivingSimState, Event, PedestrianID, PersonID, Router, TripID, TripManager,
12    TripPhaseType, UnzoomedAgent, VehicleType, WalkingSimState,
13};
14
15// These index stops along a route, not stops along a single sidewalk.
16type StopIdx = usize;
17
18#[derive(Serialize, Deserialize, Clone)]
19struct Route {
20    // Entry i is the path to drive to stop i. The very last path is to drive from the last step to
21    // the place where the vehicle vanishes.
22    paths: Vec<Path>,
23    stops: Vec<TransitStopID>,
24    active_vehicles: BTreeSet<CarID>,
25}
26
27#[derive(Serialize, Deserialize, Clone)]
28struct Bus {
29    car: CarID,
30    route: TransitRouteID,
31    /// Where does each passenger want to deboard?
32    passengers: Vec<(PersonID, Option<TransitStopID>)>,
33    state: BusState,
34}
35
36#[derive(Serialize, Deserialize, Clone)]
37enum BusState {
38    DrivingToStop(StopIdx),
39    AtStop(StopIdx),
40    // Or to the end of the lane with the last stop
41    DrivingOffMap,
42    Finished,
43}
44
45/// Manages public transit vehicles (buses and trains) that follow a route. The transit model is
46/// currently kind of broken, so not describing the state machine yet.
47#[derive(Serialize, Deserialize, Clone)]
48pub(crate) struct TransitSimState {
49    #[serde(
50        serialize_with = "serialize_btreemap",
51        deserialize_with = "deserialize_btreemap"
52    )]
53    buses: BTreeMap<CarID, Bus>,
54    #[serde(
55        serialize_with = "serialize_btreemap",
56        deserialize_with = "deserialize_btreemap"
57    )]
58    routes: BTreeMap<TransitRouteID, Route>,
59    /// waiting at => (ped, route, bound for, started waiting)
60    #[serde(
61        serialize_with = "serialize_btreemap",
62        deserialize_with = "deserialize_btreemap"
63    )]
64    peds_waiting:
65        BTreeMap<TransitStopID, Vec<(PedestrianID, TransitRouteID, Option<TransitStopID>, Time)>>,
66
67    events: Vec<Event>,
68}
69
70impl TransitSimState {
71    pub fn new(map: &Map) -> TransitSimState {
72        // Keep this filled out always so get_passengers can return &Vec without a hassle
73        let mut peds_waiting = BTreeMap::new();
74        for ts in map.all_transit_stops().keys() {
75            peds_waiting.insert(*ts, Vec::new());
76        }
77
78        TransitSimState {
79            buses: BTreeMap::new(),
80            routes: BTreeMap::new(),
81            peds_waiting,
82            events: Vec::new(),
83        }
84    }
85
86    /// Returns the path for the first leg.
87    pub fn create_empty_route(&mut self, bus_route: &TransitRoute, map: &Map) -> Path {
88        self.routes
89            .entry(bus_route.id)
90            .or_insert_with(|| match bus_route.all_paths(map) {
91                Ok(paths) => {
92                    let stops = bus_route.stops.clone();
93                    assert_eq!(paths.len(), stops.len() + 1);
94                    Route {
95                        stops,
96                        paths,
97                        active_vehicles: BTreeSet::new(),
98                    }
99                }
100                Err(err) => {
101                    panic!("{} wound up with bad paths: {}", bus_route.short_name, err);
102                }
103            });
104
105        self.routes[&bus_route.id].paths[0].clone()
106    }
107
108    pub fn bus_created(&mut self, bus: CarID, r: TransitRouteID) {
109        let route = self.routes.get_mut(&r).unwrap();
110        route.active_vehicles.insert(bus);
111        self.buses.insert(
112            bus,
113            Bus {
114                car: bus,
115                route: r,
116                passengers: Vec::new(),
117                state: BusState::DrivingToStop(0),
118            },
119        );
120    }
121
122    /// If true, the bus is idling. If false, the bus actually arrived at a border and should now
123    /// vanish.
124    ///
125    /// TODO Misnomer -- callback from Router::follow_bus_route
126    pub fn bus_arrived_at_stop(
127        &mut self,
128        now: Time,
129        id: CarID,
130        trips: &mut TripManager,
131        walking: &mut WalkingSimState,
132        ctx: &mut Ctx,
133    ) -> bool {
134        let bus = self.buses.get_mut(&id).unwrap();
135        match bus.state {
136            BusState::DrivingToStop(stop_idx) => {
137                bus.state = BusState::AtStop(stop_idx);
138                let stop1 = self.routes[&bus.route].stops[stop_idx];
139                self.events
140                    .push(Event::BusArrivedAtStop(id, bus.route, stop1));
141
142                // Deboard existing passengers.
143                let mut still_riding = Vec::new();
144                for (person, maybe_stop2) in bus.passengers.drain(..) {
145                    if Some(stop1) == maybe_stop2 {
146                        trips.person_left_bus(now, person, bus.car, ctx);
147                        self.events.push(Event::PassengerAlightsTransit(
148                            person, bus.car, bus.route, stop1,
149                        ));
150                    } else {
151                        still_riding.push((person, maybe_stop2));
152                    }
153                }
154                bus.passengers = still_riding;
155
156                // Board new passengers.
157                let mut still_waiting = Vec::new();
158                for (ped, route, maybe_stop2, started_waiting) in
159                    self.peds_waiting.remove(&stop1).unwrap()
160                {
161                    if bus.route == route {
162                        let (trip, person) = trips.ped_boarded_bus(
163                            now,
164                            ped,
165                            bus.car,
166                            now - started_waiting,
167                            walking,
168                        );
169                        self.events.push(Event::PassengerBoardsTransit(
170                            person,
171                            bus.car,
172                            bus.route,
173                            stop1,
174                            now - started_waiting,
175                        ));
176                        // TODO Recording the PathRequest for the passenger is actually hard. We
177                        // don't want to route directly between their first and last stop, because
178                        // there might be a much shorter path there. Should we record a leg per leg
179                        // of the transit route being followed?
180                        self.events.push(Event::TripPhaseStarting(
181                            trip,
182                            person,
183                            None,
184                            TripPhaseType::RidingBus(route, stop1, bus.car),
185                        ));
186                        bus.passengers.push((person, maybe_stop2));
187                    } else {
188                        still_waiting.push((ped, route, maybe_stop2, started_waiting));
189                    }
190                }
191                self.peds_waiting.insert(stop1, still_waiting);
192                true
193            }
194            BusState::DrivingOffMap => {
195                self.routes
196                    .get_mut(&bus.route)
197                    .unwrap()
198                    .active_vehicles
199                    .remove(&id);
200                for (person, maybe_stop2) in bus.passengers.drain(..) {
201                    if let Some(stop2) = maybe_stop2 {
202                        panic!(
203                            "{} fell asleep on {} and just rode off-map, but they were supposed \
204                             to hop off at {}",
205                            person, bus.car, stop2
206                        );
207                    }
208                    trips.transit_rider_reached_border(now, person, id, ctx);
209                }
210                bus.state = BusState::Finished;
211                false
212            }
213            BusState::AtStop(_) | BusState::Finished => unreachable!(),
214        }
215    }
216
217    pub fn bus_departed_from_stop(&mut self, id: CarID, _: &Map) -> Router {
218        let bus = self.buses.get_mut(&id).unwrap();
219        let route = self.routes.get_mut(&bus.route).unwrap();
220        match bus.state {
221            BusState::AtStop(stop_idx) => {
222                self.events.push(Event::BusDepartedFromStop(
223                    id,
224                    bus.route,
225                    route.stops[stop_idx],
226                ));
227
228                if stop_idx == route.stops.len() - 1 {
229                    bus.state = BusState::DrivingOffMap;
230                } else {
231                    bus.state = BusState::DrivingToStop(stop_idx + 1);
232                }
233                Router::follow_bus_route(id, route.paths[stop_idx + 1].clone())
234            }
235            BusState::DrivingToStop(_) | BusState::DrivingOffMap | BusState::Finished => {
236                unreachable!()
237            }
238        }
239    }
240
241    /// Returns the bus if the pedestrian boarded immediately.
242    pub fn ped_waiting_for_bus(
243        &mut self,
244        now: Time,
245        ped: PedestrianID,
246        trip: TripID,
247        person: PersonID,
248        stop1: TransitStopID,
249        route_id: TransitRouteID,
250        maybe_stop2: Option<TransitStopID>,
251        _: &Map,
252    ) -> Option<CarID> {
253        assert!(Some(stop1) != maybe_stop2);
254        if let Some(route) = self.routes.get(&route_id) {
255            for bus in &route.active_vehicles {
256                if let BusState::AtStop(idx) = self.buses[bus].state {
257                    if route.stops[idx] == stop1 {
258                        self.buses
259                            .get_mut(bus)
260                            .unwrap()
261                            .passengers
262                            .push((person, maybe_stop2));
263                        // TODO Same problem as elsewhere with recording the PathRequest
264                        self.events.push(Event::TripPhaseStarting(
265                            trip,
266                            person,
267                            None,
268                            TripPhaseType::RidingBus(route_id, stop1, *bus),
269                        ));
270                        return Some(*bus);
271                    }
272                }
273            }
274        } else {
275            println!(
276                "WARNING: {} waiting for {}, but that route hasn't been instantiated",
277                ped, route_id
278            );
279        }
280
281        self.peds_waiting
282            .get_mut(&stop1)
283            .unwrap()
284            .push((ped, route_id, maybe_stop2, now));
285        None
286    }
287
288    pub fn collect_events(&mut self) -> Vec<Event> {
289        self.events.drain(..).collect()
290    }
291
292    pub fn get_passengers(&self, bus: CarID) -> &Vec<(PersonID, Option<TransitStopID>)> {
293        &self.buses[&bus].passengers
294    }
295
296    pub fn bus_route(&self, bus: CarID) -> TransitRouteID {
297        self.buses[&bus].route
298    }
299
300    /// also stop idx that the bus is coming from
301    pub fn buses_for_route(&self, route: TransitRouteID) -> Vec<(CarID, Option<usize>)> {
302        if let Some(r) = self.routes.get(&route) {
303            r.active_vehicles
304                .iter()
305                .map(|bus| {
306                    let stop = match self.buses[bus].state {
307                        BusState::DrivingToStop(idx) => {
308                            if idx == 0 {
309                                None
310                            } else {
311                                Some(idx - 1)
312                            }
313                        }
314                        BusState::AtStop(idx) => Some(idx),
315                        BusState::DrivingOffMap => Some(r.stops.len() - 1),
316                        BusState::Finished => unreachable!(),
317                    };
318                    (*bus, stop)
319                })
320                .collect()
321        } else {
322            Vec::new()
323        }
324    }
325
326    /// (buses, trains)
327    pub fn active_vehicles(&self) -> (usize, usize) {
328        let mut buses = 0;
329        let mut trains = 0;
330        for r in self.routes.values() {
331            let len = r.active_vehicles.len();
332            if len > 0 {
333                if r.active_vehicles.iter().next().unwrap().vehicle_type == VehicleType::Bus {
334                    buses += len;
335                } else {
336                    trains += len;
337                }
338            }
339        }
340        (buses, trains)
341    }
342
343    pub fn get_people_waiting_at_stop(
344        &self,
345        at: TransitStopID,
346    ) -> &Vec<(PedestrianID, TransitRouteID, Option<TransitStopID>, Time)> {
347        &self.peds_waiting[&at]
348    }
349
350    pub fn get_unzoomed_transit_riders(
351        &self,
352        now: Time,
353        driving: &DrivingSimState,
354        map: &Map,
355    ) -> Vec<UnzoomedAgent> {
356        let mut results = Vec::new();
357        for (bus_id, bus) in &self.buses {
358            if bus.passengers.is_empty() {
359                continue;
360            }
361            let pos = if let Some(input) = driving.get_single_draw_car(*bus_id, now, map, self) {
362                input.body.last_pt()
363            } else {
364                panic!(
365                    "At {}, bus {} can't be drawn, yet it has passengers {:?}",
366                    now, bus_id, bus.passengers
367                );
368            };
369            for (person, _) in &bus.passengers {
370                let agent = AgentID::BusPassenger(*person, *bus_id);
371                results.push(UnzoomedAgent {
372                    id: agent,
373                    pos,
374                    person: Some(*person),
375                    parking: false,
376                });
377            }
378        }
379        results
380    }
381}