1 use crate::sim::Ctx;
2 use crate::{
3     AgentID, AgentType, AlertLocation, CarID, Command, CreateCar, CreatePedestrian, DrivingGoal,
4     Event, IndividTrip, OffMapLocation, OrigPersonID, ParkedCar, ParkingSpot, PedestrianID,
5     PersonID, PersonSpec, Scenario, Scheduler, SidewalkPOI, SidewalkSpot, SpawnTrip,
6     TransitSimState, TripID, TripPhaseType, TripSpec, Vehicle, VehicleSpec, VehicleType,
7     WalkingSimState,
8 };
9 use abstutil::{deserialize_btreemap, serialize_btreemap, Counter};
10 use geom::{Duration, Speed, Time};
11 use map_model::{
12     BuildingID, BusRouteID, BusStopID, IntersectionID, Map, Path, PathConstraints, PathRequest,
13     Position,
14 };
15 use serde::{Deserialize, Serialize};
16 use std::collections::{BTreeMap, VecDeque};
17 
18 #[derive(Serialize, Deserialize, Debug, Clone)]
19 pub struct TripManager {
20     trips: Vec<Trip>,
21     people: Vec<Person>,
22     // For quick lookup of active agents
23     #[serde(
24         serialize_with = "serialize_btreemap",
25         deserialize_with = "deserialize_btreemap"
26     )]
27     active_trip_mode: BTreeMap<AgentID, TripID>,
28     unfinished_trips: usize,
29     pub pathfinding_upfront: bool,
30 
31     car_id_counter: usize,
32 
33     events: Vec<Event>,
34 }
35 
36 impl TripManager {
new(pathfinding_upfront: bool) -> TripManager37     pub fn new(pathfinding_upfront: bool) -> TripManager {
38         TripManager {
39             trips: Vec::new(),
40             people: Vec::new(),
41             active_trip_mode: BTreeMap::new(),
42             unfinished_trips: 0,
43             car_id_counter: 0,
44             events: Vec::new(),
45             pathfinding_upfront,
46         }
47     }
48 
49     // TODO assert the specs are correct yo
new_person( &mut self, id: PersonID, orig_id: Option<OrigPersonID>, ped_speed: Speed, vehicle_specs: Vec<VehicleSpec>, )50     pub fn new_person(
51         &mut self,
52         id: PersonID,
53         orig_id: Option<OrigPersonID>,
54         ped_speed: Speed,
55         vehicle_specs: Vec<VehicleSpec>,
56     ) {
57         assert_eq!(id.0, self.people.len());
58         let vehicles = vehicle_specs
59             .into_iter()
60             .map(|v| {
61                 let c = CarID(self.new_car_id(), v.vehicle_type);
62                 v.make(c, Some(id))
63             })
64             .collect();
65         self.people.push(Person {
66             id,
67             orig_id,
68             trips: Vec::new(),
69             // The first new_trip will set this properly.
70             state: PersonState::OffMap,
71             ped: PedestrianID(id.0),
72             ped_speed,
73             vehicles,
74             delayed_trips: Vec::new(),
75             on_bus: None,
76         });
77     }
random_person(&mut self, ped_speed: Speed, vehicle_specs: Vec<VehicleSpec>) -> &Person78     pub fn random_person(&mut self, ped_speed: Speed, vehicle_specs: Vec<VehicleSpec>) -> &Person {
79         let id = PersonID(self.people.len());
80         self.new_person(id, None, ped_speed, vehicle_specs);
81         self.get_person(id).unwrap()
82     }
83 
new_car_id(&mut self) -> usize84     pub fn new_car_id(&mut self) -> usize {
85         let id = self.car_id_counter;
86         self.car_id_counter += 1;
87         id
88     }
89 
new_trip( &mut self, person: PersonID, departure: Time, start: TripEndpoint, mode: TripMode, modified: bool, legs: Vec<TripLeg>, map: &Map, ) -> TripID90     pub fn new_trip(
91         &mut self,
92         person: PersonID,
93         departure: Time,
94         start: TripEndpoint,
95         mode: TripMode,
96         modified: bool,
97         legs: Vec<TripLeg>,
98         map: &Map,
99     ) -> TripID {
100         assert!(!legs.is_empty());
101         // TODO Make sure the legs constitute a valid state machine.
102 
103         let id = TripID(self.trips.len());
104         let end = match legs.last() {
105             Some(TripLeg::Walk(ref spot)) => match spot.connection {
106                 SidewalkPOI::Building(b) => TripEndpoint::Bldg(b),
107                 SidewalkPOI::Border(i, ref loc) => TripEndpoint::Border(i, loc.clone()),
108                 _ => unreachable!(),
109             },
110             Some(TripLeg::Drive(_, ref goal)) => match goal {
111                 DrivingGoal::ParkNear(b) => TripEndpoint::Bldg(*b),
112                 DrivingGoal::Border(i, _, loc) => TripEndpoint::Border(*i, loc.clone()),
113             },
114             Some(TripLeg::Remote(ref to)) => {
115                 TripEndpoint::Border(map.all_incoming_borders()[0].id, Some(to.clone()))
116             }
117             Some(TripLeg::RideBus(r, ref maybe_stop2)) => {
118                 assert!(maybe_stop2.is_none());
119                 // TODO No way to plumb OffMapLocation here
120                 TripEndpoint::Border(map.get_l(map.get_br(*r).end_border.unwrap()).dst_i, None)
121             }
122             _ => unreachable!(),
123         };
124         let trip = Trip {
125             id,
126             info: TripInfo {
127                 departure,
128                 mode,
129                 start,
130                 end,
131                 modified,
132             },
133             person,
134             started: false,
135             finished_at: None,
136             total_blocked_time: Duration::ZERO,
137             aborted: false,
138             cancelled: false,
139             legs: VecDeque::from(legs),
140         };
141         self.unfinished_trips += 1;
142         let person = &mut self.people[trip.person.0];
143         if person.trips.is_empty() {
144             person.state = match trip.info.start {
145                 TripEndpoint::Bldg(b) => {
146                     self.events
147                         .push(Event::PersonEntersBuilding(trip.person, b));
148                     PersonState::Inside(b)
149                 }
150                 TripEndpoint::Border(_, ref loc) => {
151                     if let Some(loc) = loc {
152                         self.events
153                             .push(Event::PersonEntersRemoteBuilding(trip.person, loc.clone()));
154                     }
155                     PersonState::OffMap
156                 }
157             };
158         }
159         if let Some(t) = person.trips.last() {
160             // TODO If it's exactly ==, what?! See the ID.
161             if self.trips[t.0].info.departure > trip.info.departure {
162                 panic!(
163                     "{} has a trip starting at {}, then one at {}",
164                     person.id, self.trips[t.0].info.departure, trip.info.departure
165                 );
166             }
167         }
168         person.trips.push(id);
169         self.trips.push(trip);
170         id
171     }
172 
agent_starting_trip_leg(&mut self, agent: AgentID, t: TripID)173     pub fn agent_starting_trip_leg(&mut self, agent: AgentID, t: TripID) {
174         if let Some(other) = self.active_trip_mode.get(&agent) {
175             panic!("{} is doing both {} and {}?", agent, t, other);
176         }
177         self.active_trip_mode.insert(agent, t);
178     }
179 
car_reached_parking_spot( &mut self, now: Time, car: CarID, spot: ParkingSpot, blocked_time: Duration, ctx: &mut Ctx, )180     pub fn car_reached_parking_spot(
181         &mut self,
182         now: Time,
183         car: CarID,
184         spot: ParkingSpot,
185         blocked_time: Duration,
186         ctx: &mut Ctx,
187     ) {
188         let trip = &mut self.trips[self.active_trip_mode.remove(&AgentID::Car(car)).unwrap().0];
189         trip.total_blocked_time += blocked_time;
190 
191         match trip.legs.pop_front() {
192             Some(TripLeg::Drive(c, DrivingGoal::ParkNear(_))) => {
193                 assert_eq!(car, c);
194             }
195             _ => unreachable!(),
196         };
197 
198         match &trip.legs[0] {
199             TripLeg::Walk(to) => match (spot, &to.connection) {
200                 (ParkingSpot::Offstreet(b1, _), SidewalkPOI::Building(b2)) if b1 == *b2 => {
201                     // Do the relevant parts of ped_reached_parking_spot.
202                     assert_eq!(trip.legs.len(), 1);
203                     assert!(!trip.finished_at.is_some());
204                     trip.finished_at = Some(now);
205                     self.unfinished_trips -= 1;
206                     self.events.push(Event::TripFinished {
207                         trip: trip.id,
208                         mode: trip.info.mode,
209                         total_time: now - trip.info.departure,
210                         blocked_time: trip.total_blocked_time,
211                     });
212                     let person = trip.person;
213                     self.people[person.0].state = PersonState::Inside(b1);
214                     self.events.push(Event::PersonEntersBuilding(person, b1));
215                     self.person_finished_trip(now, person, ctx);
216                     return;
217                 }
218                 _ => {}
219             },
220             _ => unreachable!(),
221         };
222 
223         if !trip.spawn_ped(
224             now,
225             SidewalkSpot::parking_spot(spot, ctx.map, ctx.parking),
226             &self.people[trip.person.0],
227             ctx.map,
228             ctx.scheduler,
229             &mut self.events,
230         ) {
231             self.unfinished_trips -= 1;
232         }
233     }
234 
ped_reached_parking_spot( &mut self, now: Time, ped: PedestrianID, spot: ParkingSpot, blocked_time: Duration, ctx: &mut Ctx, )235     pub fn ped_reached_parking_spot(
236         &mut self,
237         now: Time,
238         ped: PedestrianID,
239         spot: ParkingSpot,
240         blocked_time: Duration,
241         ctx: &mut Ctx,
242     ) {
243         self.events.push(Event::PedReachedParkingSpot(ped, spot));
244         let trip = &mut self.trips[self
245             .active_trip_mode
246             .remove(&AgentID::Pedestrian(ped))
247             .unwrap()
248             .0];
249         trip.total_blocked_time += blocked_time;
250 
251         trip.assert_walking_leg(SidewalkSpot::deferred_parking_spot());
252         let parked_car = ctx.parking.get_car_at_spot(spot).unwrap().clone();
253         let drive_to = match trip.legs[0] {
254             TripLeg::Drive(c, ref to) => {
255                 assert_eq!(c, parked_car.vehicle.id);
256                 to.clone()
257             }
258             _ => unreachable!(),
259         };
260 
261         let mut start =
262             ctx.parking
263                 .spot_to_driving_pos(parked_car.spot, &parked_car.vehicle, ctx.map);
264         match spot {
265             ParkingSpot::Onstreet(_, _) => {}
266             ParkingSpot::Offstreet(b, _) => {
267                 self.events
268                     .push(Event::PersonEntersBuilding(trip.person, b));
269                 // Actually, to unpark, the car's front should be where it'll wind up at the end.
270                 start = Position::new(start.lane(), start.dist_along() + parked_car.vehicle.length);
271             }
272             ParkingSpot::Lot(_, _) => {
273                 start = Position::new(start.lane(), start.dist_along() + parked_car.vehicle.length);
274             }
275         }
276         let end = drive_to.goal_pos(PathConstraints::Car, ctx.map).unwrap();
277         let req = PathRequest {
278             start,
279             end,
280             constraints: PathConstraints::Car,
281         };
282         let path = if let Some(p) = ctx.map.pathfind(req.clone()) {
283             p
284         } else {
285             self.events.push(Event::Alert(
286                 AlertLocation::Person(trip.person),
287                 format!(
288                     "Aborting {} because no path for the car portion! {} to {}",
289                     trip.id, start, end
290                 ),
291             ));
292             // Move the car to the destination...
293             ctx.parking.remove_parked_car(parked_car.clone());
294             let trip = trip.id;
295             self.abort_trip(now, trip, Some(parked_car.vehicle), ctx);
296             return;
297         };
298 
299         if !ctx.cap.allow_trip(parked_car.vehicle.id, &path) {
300             // TODO Different ways to handle this: abort the trip, delay it an hour, route around
301             // the zone, switch modes...
302             self.events.push(Event::Alert(
303                 AlertLocation::Person(trip.person),
304                 format!(
305                     "Aborting {} because it would exceed the cap through some zone",
306                     trip.id
307                 ),
308             ));
309             // Move the car to the destination...
310             ctx.parking.remove_parked_car(parked_car.clone());
311             let trip = trip.id;
312             self.abort_trip(now, trip, Some(parked_car.vehicle), ctx);
313             return;
314         }
315 
316         let router = drive_to.make_router(parked_car.vehicle.id, path, ctx.map);
317         ctx.scheduler.push(
318             now,
319             Command::SpawnCar(
320                 CreateCar::for_parked_car(
321                     parked_car,
322                     router,
323                     req,
324                     start.dist_along(),
325                     trip.id,
326                     trip.person,
327                 ),
328                 true,
329             ),
330         );
331     }
332 
ped_ready_to_bike( &mut self, now: Time, ped: PedestrianID, spot: SidewalkSpot, blocked_time: Duration, ctx: &mut Ctx, )333     pub fn ped_ready_to_bike(
334         &mut self,
335         now: Time,
336         ped: PedestrianID,
337         spot: SidewalkSpot,
338         blocked_time: Duration,
339         ctx: &mut Ctx,
340     ) {
341         let trip = &mut self.trips[self
342             .active_trip_mode
343             .remove(&AgentID::Pedestrian(ped))
344             .unwrap()
345             .0];
346         trip.total_blocked_time += blocked_time;
347 
348         trip.assert_walking_leg(spot.clone());
349         let (bike, drive_to) = match trip.legs[0] {
350             TripLeg::Drive(bike, ref to) => (bike, to.clone()),
351             _ => unreachable!(),
352         };
353         let driving_pos = match spot.connection {
354             SidewalkPOI::BikeRack(p) => p,
355             _ => unreachable!(),
356         };
357 
358         let end = if let Some(end) = drive_to.goal_pos(PathConstraints::Bike, ctx.map) {
359             end
360         } else {
361             self.events.push(Event::Alert(
362                 AlertLocation::Person(trip.person),
363                 format!(
364                     "Aborting {} because no bike connection at {:?}",
365                     trip.id, drive_to
366                 ),
367             ));
368             let trip = trip.id;
369             self.abort_trip(now, trip, None, ctx);
370             return;
371         };
372         let req = PathRequest {
373             start: driving_pos,
374             end,
375             constraints: PathConstraints::Bike,
376         };
377         if let Some(router) = ctx
378             .map
379             .pathfind(req.clone())
380             .map(|path| drive_to.make_router(bike, path, ctx.map))
381         {
382             ctx.scheduler.push(
383                 now,
384                 Command::SpawnCar(
385                     CreateCar::for_appearing(
386                         self.people[trip.person.0].get_vehicle(bike),
387                         driving_pos,
388                         router,
389                         req,
390                         trip.id,
391                         trip.person,
392                     ),
393                     true,
394                 ),
395             );
396         } else {
397             self.events.push(Event::Alert(
398                 AlertLocation::Person(trip.person),
399                 format!(
400                     "Aborting {} because no path for the bike portion (or sidewalk connection at \
401                      the end)! {} to {}",
402                     trip.id, driving_pos, end
403                 ),
404             ));
405             let trip = trip.id;
406             self.abort_trip(now, trip, None, ctx);
407         }
408     }
409 
bike_reached_end( &mut self, now: Time, bike: CarID, bike_rack: SidewalkSpot, blocked_time: Duration, map: &Map, scheduler: &mut Scheduler, )410     pub fn bike_reached_end(
411         &mut self,
412         now: Time,
413         bike: CarID,
414         bike_rack: SidewalkSpot,
415         blocked_time: Duration,
416         map: &Map,
417         scheduler: &mut Scheduler,
418     ) {
419         self.events.push(Event::BikeStoppedAtSidewalk(
420             bike,
421             bike_rack.sidewalk_pos.lane(),
422         ));
423         let trip = &mut self.trips[self.active_trip_mode.remove(&AgentID::Car(bike)).unwrap().0];
424         trip.total_blocked_time += blocked_time;
425 
426         match trip.legs.pop_front() {
427             Some(TripLeg::Drive(c, DrivingGoal::ParkNear(_))) => {
428                 assert_eq!(c, bike);
429             }
430             _ => unreachable!(),
431         };
432 
433         if !trip.spawn_ped(
434             now,
435             bike_rack,
436             &self.people[trip.person.0],
437             map,
438             scheduler,
439             &mut self.events,
440         ) {
441             self.unfinished_trips -= 1;
442         }
443     }
444 
ped_reached_building( &mut self, now: Time, ped: PedestrianID, bldg: BuildingID, blocked_time: Duration, ctx: &mut Ctx, )445     pub fn ped_reached_building(
446         &mut self,
447         now: Time,
448         ped: PedestrianID,
449         bldg: BuildingID,
450         blocked_time: Duration,
451         ctx: &mut Ctx,
452     ) {
453         let trip = &mut self.trips[self
454             .active_trip_mode
455             .remove(&AgentID::Pedestrian(ped))
456             .unwrap()
457             .0];
458         trip.total_blocked_time += blocked_time;
459 
460         trip.assert_walking_leg(SidewalkSpot::building(bldg, ctx.map));
461         assert!(trip.legs.is_empty());
462         assert!(!trip.finished_at.is_some());
463         trip.finished_at = Some(now);
464         self.unfinished_trips -= 1;
465         self.events.push(Event::TripFinished {
466             trip: trip.id,
467             mode: trip.info.mode,
468             total_time: now - trip.info.departure,
469             blocked_time: trip.total_blocked_time,
470         });
471         let person = trip.person;
472         self.people[person.0].state = PersonState::Inside(bldg);
473         self.events.push(Event::PersonEntersBuilding(person, bldg));
474         self.person_finished_trip(now, person, ctx);
475     }
476 
477     // If no route is returned, the pedestrian boarded a bus immediately.
ped_reached_bus_stop( &mut self, now: Time, ped: PedestrianID, stop: BusStopID, blocked_time: Duration, ctx: &mut Ctx, transit: &mut TransitSimState, ) -> Option<BusRouteID>478     pub fn ped_reached_bus_stop(
479         &mut self,
480         now: Time,
481         ped: PedestrianID,
482         stop: BusStopID,
483         blocked_time: Duration,
484         ctx: &mut Ctx,
485         transit: &mut TransitSimState,
486     ) -> Option<BusRouteID> {
487         let trip = &mut self.trips[self.active_trip_mode[&AgentID::Pedestrian(ped)].0];
488         trip.total_blocked_time += blocked_time;
489 
490         match trip.legs[0] {
491             TripLeg::Walk(ref spot) => {
492                 assert_eq!(*spot, SidewalkSpot::bus_stop(stop, ctx.map));
493             }
494             _ => unreachable!(),
495         }
496         match trip.legs[1] {
497             TripLeg::RideBus(route, maybe_stop2) => {
498                 self.events.push(Event::TripPhaseStarting(
499                     trip.id,
500                     trip.person,
501                     None,
502                     TripPhaseType::WaitingForBus(route, stop),
503                 ));
504                 if let Some(bus) = transit.ped_waiting_for_bus(
505                     now,
506                     ped,
507                     trip.id,
508                     trip.person,
509                     stop,
510                     route,
511                     maybe_stop2,
512                     ctx.map,
513                 ) {
514                     trip.legs.pop_front();
515                     self.active_trip_mode
516                         .remove(&AgentID::Pedestrian(ped))
517                         .unwrap();
518                     self.active_trip_mode
519                         .insert(AgentID::BusPassenger(trip.person, bus), trip.id);
520                     self.people[trip.person.0].on_bus = Some(bus);
521                     None
522                 } else {
523                     Some(route)
524                 }
525             }
526             _ => unreachable!(),
527         }
528     }
529 
ped_boarded_bus( &mut self, now: Time, ped: PedestrianID, bus: CarID, blocked_time: Duration, walking: &mut WalkingSimState, ) -> (TripID, PersonID)530     pub fn ped_boarded_bus(
531         &mut self,
532         now: Time,
533         ped: PedestrianID,
534         bus: CarID,
535         blocked_time: Duration,
536         walking: &mut WalkingSimState,
537     ) -> (TripID, PersonID) {
538         let trip = &mut self.trips[self
539             .active_trip_mode
540             .remove(&AgentID::Pedestrian(ped))
541             .unwrap()
542             .0];
543         trip.total_blocked_time += blocked_time;
544 
545         trip.legs.pop_front();
546         walking.ped_boarded_bus(now, ped);
547         self.active_trip_mode
548             .insert(AgentID::BusPassenger(trip.person, bus), trip.id);
549         self.people[trip.person.0].on_bus = Some(bus);
550         (trip.id, trip.person)
551     }
552 
553     // TODO Need to characterize delay the bus experienced
person_left_bus(&mut self, now: Time, person: PersonID, bus: CarID, ctx: &mut Ctx)554     pub fn person_left_bus(&mut self, now: Time, person: PersonID, bus: CarID, ctx: &mut Ctx) {
555         let trip = &mut self.trips[self
556             .active_trip_mode
557             .remove(&AgentID::BusPassenger(person, bus))
558             .unwrap()
559             .0];
560         let start = match trip.legs.pop_front().unwrap() {
561             TripLeg::RideBus(_, maybe_stop2) => SidewalkSpot::bus_stop(
562                 maybe_stop2.expect("someone left a bus, even though they should've ridden off-map"),
563                 ctx.map,
564             ),
565             _ => unreachable!(),
566         };
567         self.people[person.0].on_bus.take().unwrap();
568 
569         if !trip.spawn_ped(
570             now,
571             start,
572             &self.people[trip.person.0],
573             ctx.map,
574             ctx.scheduler,
575             &mut self.events,
576         ) {
577             self.unfinished_trips -= 1;
578         }
579     }
580 
ped_reached_border( &mut self, now: Time, ped: PedestrianID, i: IntersectionID, blocked_time: Duration, ctx: &mut Ctx, )581     pub fn ped_reached_border(
582         &mut self,
583         now: Time,
584         ped: PedestrianID,
585         i: IntersectionID,
586         blocked_time: Duration,
587         ctx: &mut Ctx,
588     ) {
589         let trip = &mut self.trips[self
590             .active_trip_mode
591             .remove(&AgentID::Pedestrian(ped))
592             .unwrap()
593             .0];
594         trip.total_blocked_time += blocked_time;
595 
596         match trip.legs.pop_front() {
597             Some(TripLeg::Walk(spot)) => match spot.connection {
598                 SidewalkPOI::Border(i2, _) => assert_eq!(i, i2),
599                 _ => unreachable!(),
600             },
601             _ => unreachable!(),
602         }
603         assert!(trip.legs.is_empty());
604         assert!(!trip.finished_at.is_some());
605         trip.finished_at = Some(now);
606         self.unfinished_trips -= 1;
607         self.events.push(Event::TripFinished {
608             trip: trip.id,
609             mode: trip.info.mode,
610             total_time: now - trip.info.departure,
611             blocked_time: trip.total_blocked_time,
612         });
613         let person = trip.person;
614         if let TripEndpoint::Border(_, ref loc) = trip.info.end {
615             self.events.push(Event::PersonLeavesMap(
616                 person,
617                 Some(AgentID::Pedestrian(ped)),
618                 i,
619                 loc.clone(),
620             ));
621         }
622         self.people[person.0].state = PersonState::OffMap;
623         self.person_finished_trip(now, person, ctx);
624     }
625 
transit_rider_reached_border( &mut self, now: Time, person: PersonID, bus: CarID, ctx: &mut Ctx, )626     pub fn transit_rider_reached_border(
627         &mut self,
628         now: Time,
629         person: PersonID,
630         bus: CarID,
631         ctx: &mut Ctx,
632     ) {
633         let agent = AgentID::BusPassenger(person, bus);
634         let trip = &mut self.trips[self.active_trip_mode.remove(&agent).unwrap().0];
635 
636         match trip.legs.pop_front() {
637             Some(TripLeg::RideBus(_, maybe_spot2)) => assert!(maybe_spot2.is_none()),
638             _ => unreachable!(),
639         }
640         assert!(trip.legs.is_empty());
641         assert!(!trip.finished_at.is_some());
642         trip.finished_at = Some(now);
643         self.unfinished_trips -= 1;
644         self.events.push(Event::TripFinished {
645             trip: trip.id,
646             mode: trip.info.mode,
647             total_time: now - trip.info.departure,
648             blocked_time: trip.total_blocked_time,
649         });
650         let person = trip.person;
651         if let TripEndpoint::Border(i, ref loc) = trip.info.end {
652             self.events
653                 .push(Event::PersonLeavesMap(person, Some(agent), i, loc.clone()));
654         } else {
655             unreachable!()
656         }
657         self.people[person.0].state = PersonState::OffMap;
658         self.person_finished_trip(now, person, ctx);
659     }
660 
car_or_bike_reached_border( &mut self, now: Time, car: CarID, i: IntersectionID, blocked_time: Duration, ctx: &mut Ctx, )661     pub fn car_or_bike_reached_border(
662         &mut self,
663         now: Time,
664         car: CarID,
665         i: IntersectionID,
666         blocked_time: Duration,
667         ctx: &mut Ctx,
668     ) {
669         let trip = &mut self.trips[self.active_trip_mode.remove(&AgentID::Car(car)).unwrap().0];
670         trip.total_blocked_time += blocked_time;
671 
672         match trip.legs.pop_front().unwrap() {
673             TripLeg::Drive(c, DrivingGoal::Border(int, _, _)) => {
674                 assert_eq!(car, c);
675                 assert_eq!(i, int);
676             }
677             _ => unreachable!(),
678         };
679         assert!(trip.legs.is_empty());
680         assert!(!trip.finished_at.is_some());
681         trip.finished_at = Some(now);
682         self.unfinished_trips -= 1;
683         self.events.push(Event::TripFinished {
684             trip: trip.id,
685             mode: trip.info.mode,
686             total_time: now - trip.info.departure,
687             blocked_time: trip.total_blocked_time,
688         });
689         let person = trip.person;
690         self.people[person.0].state = PersonState::OffMap;
691         if let TripEndpoint::Border(_, ref loc) = trip.info.end {
692             self.events.push(Event::PersonLeavesMap(
693                 person,
694                 Some(AgentID::Car(car)),
695                 i,
696                 loc.clone(),
697             ));
698         }
699         self.person_finished_trip(now, person, ctx);
700     }
701 
remote_trip_finished(&mut self, now: Time, id: TripID, ctx: &mut Ctx)702     pub fn remote_trip_finished(&mut self, now: Time, id: TripID, ctx: &mut Ctx) {
703         let trip = &mut self.trips[id.0];
704 
705         let to = match trip.legs.pop_front() {
706             Some(TripLeg::Remote(to)) => to,
707             _ => unreachable!(),
708         };
709         assert!(trip.legs.is_empty());
710         assert!(!trip.finished_at.is_some());
711         trip.finished_at = Some(now);
712         self.unfinished_trips -= 1;
713         self.events.push(Event::TripFinished {
714             trip: trip.id,
715             mode: trip.info.mode,
716             total_time: now - trip.info.departure,
717             blocked_time: trip.total_blocked_time,
718         });
719         let person = trip.person;
720         self.events
721             .push(Event::PersonEntersRemoteBuilding(person, to));
722         self.people[person.0].state = PersonState::OffMap;
723         self.person_finished_trip(now, person, ctx);
724     }
725 
726     // Different than aborting a trip. Don't warp any vehicles or change where the person is.
cancel_trip(&mut self, id: TripID)727     pub fn cancel_trip(&mut self, id: TripID) {
728         let trip = &mut self.trips[id.0];
729         self.unfinished_trips -= 1;
730         trip.cancelled = true;
731         // TODO Still representing the same way in analytics
732         self.events.push(Event::TripAborted(trip.id));
733     }
734 
abort_trip( &mut self, now: Time, id: TripID, abandoned_vehicle: Option<Vehicle>, ctx: &mut Ctx, )735     pub fn abort_trip(
736         &mut self,
737         now: Time,
738         id: TripID,
739         abandoned_vehicle: Option<Vehicle>,
740         ctx: &mut Ctx,
741     ) {
742         let trip = &mut self.trips[id.0];
743         self.unfinished_trips -= 1;
744         trip.aborted = true;
745         self.events.push(Event::TripAborted(trip.id));
746         let person = trip.person;
747 
748         // Maintain consistentency for anyone listening to events
749         if let PersonState::Inside(b) = self.people[person.0].state {
750             self.events.push(Event::PersonLeavesBuilding(person, b));
751         }
752         match trip.info.end {
753             TripEndpoint::Bldg(b) => {
754                 self.events.push(Event::PersonEntersBuilding(person, b));
755             }
756             TripEndpoint::Border(i, ref loc) => {
757                 self.events
758                     .push(Event::PersonLeavesMap(person, None, i, loc.clone()));
759             }
760         }
761 
762         // Warp to the destination
763         self.people[person.0].state = match trip.info.end {
764             TripEndpoint::Bldg(b) => PersonState::Inside(b),
765             TripEndpoint::Border(_, _) => PersonState::OffMap,
766         };
767         // Don't forget the car!
768         if let Some(vehicle) = abandoned_vehicle {
769             if vehicle.vehicle_type == VehicleType::Car {
770                 if let TripEndpoint::Bldg(b) = trip.info.end {
771                     let driving_lane = ctx.map.find_driving_lane_near_building(b);
772                     if let Some(spot) = ctx
773                         .parking
774                         .get_all_free_spots(Position::start(driving_lane), &vehicle, b, ctx.map)
775                         // TODO Could pick something closer, but meh, aborted trips are bugs anyway
776                         .get(0)
777                         .map(|(spot, _)| spot.clone())
778                         .or_else(|| {
779                             ctx.parking
780                                 .path_to_free_parking_spot(driving_lane, &vehicle, b, ctx.map)
781                                 .map(|(_, spot, _)| spot)
782                         })
783                     {
784                         self.events.push(Event::Alert(
785                             AlertLocation::Person(person),
786                             format!(
787                                 "{} had a trip aborted, and their car was warped to {:?}",
788                                 person, spot
789                             ),
790                         ));
791                         ctx.parking.reserve_spot(spot);
792                         ctx.parking.add_parked_car(ParkedCar { vehicle, spot });
793                     } else {
794                         self.events.push(Event::Alert(
795                             AlertLocation::Person(person),
796                             format!(
797                                 "{} had a trip aborted, but nowhere to warp their car! Sucks.",
798                                 person
799                             ),
800                         ));
801                     }
802                 }
803             }
804         } else {
805             // If the trip was aborted because we'e totally out of parking, don't forget to clean
806             // this up.
807             if let TripLeg::Drive(c, _) = &trip.legs[0] {
808                 if let Some(t) = self.active_trip_mode.remove(&AgentID::Car(*c)) {
809                     assert_eq!(t, trip.id);
810                 }
811             }
812         }
813 
814         self.person_finished_trip(now, person, ctx);
815     }
816 
active_agents(&self) -> Vec<AgentID>817     pub fn active_agents(&self) -> Vec<AgentID> {
818         self.active_trip_mode.keys().cloned().collect()
819     }
get_active_trips(&self) -> Vec<TripID>820     pub fn get_active_trips(&self) -> Vec<TripID> {
821         self.active_trip_mode.values().cloned().collect()
822     }
num_active_agents(&self) -> usize823     pub fn num_active_agents(&self) -> usize {
824         self.active_trip_mode.len()
825     }
826 
trip_to_agent(&self, id: TripID) -> TripResult<AgentID>827     pub fn trip_to_agent(&self, id: TripID) -> TripResult<AgentID> {
828         if id.0 >= self.trips.len() {
829             return TripResult::TripDoesntExist;
830         }
831         let trip = &self.trips[id.0];
832 
833         if trip.finished_at.is_some() {
834             return TripResult::TripDone;
835         }
836         if trip.aborted {
837             return TripResult::TripAborted;
838         }
839         if trip.cancelled {
840             return TripResult::TripCancelled;
841         }
842         if !trip.started {
843             return TripResult::TripNotStarted;
844         }
845 
846         let person = &self.people[trip.person.0];
847         let a = match &trip.legs[0] {
848             TripLeg::Walk(_) => AgentID::Pedestrian(person.ped),
849             TripLeg::Drive(c, _) => AgentID::Car(*c),
850             TripLeg::RideBus(_, _) => AgentID::BusPassenger(person.id, person.on_bus.unwrap()),
851             TripLeg::Remote(_) => {
852                 return TripResult::RemoteTrip;
853             }
854         };
855         if self.active_trip_mode.get(&a) == Some(&id) {
856             TripResult::Ok(a)
857         } else {
858             //panic!("{} should be ongoing, but no agent in active_trip_mode", id);
859             TripResult::ModeChange
860         }
861     }
862 
863     // This will be None for parked cars and buses. Should always work for pedestrians.
agent_to_trip(&self, id: AgentID) -> Option<TripID>864     pub fn agent_to_trip(&self, id: AgentID) -> Option<TripID> {
865         self.active_trip_mode.get(&id).cloned()
866     }
867 
debug_trip(&self, id: AgentID)868     pub fn debug_trip(&self, id: AgentID) {
869         if let Some(t) = self.active_trip_mode.get(&id) {
870             let trip = &self.trips[t.0];
871             println!("{} has goal {:?}", trip.id, trip.legs.back().unwrap());
872         } else {
873             println!("{} has no trip, must be parked car", id);
874         }
875     }
876 
num_trips(&self) -> (usize, usize)877     pub fn num_trips(&self) -> (usize, usize) {
878         (
879             self.trips.len() - self.unfinished_trips,
880             self.unfinished_trips,
881         )
882     }
num_agents(&self, transit: &TransitSimState) -> Counter<AgentType>883     pub fn num_agents(&self, transit: &TransitSimState) -> Counter<AgentType> {
884         let mut cnt = Counter::new();
885         for a in self.active_trip_mode.keys() {
886             cnt.inc(a.to_type());
887         }
888         let (buses, trains) = transit.active_vehicles();
889         cnt.add(AgentType::Bus, buses);
890         cnt.add(AgentType::Train, trains);
891         cnt
892     }
num_ppl(&self) -> (usize, usize, usize)893     pub fn num_ppl(&self) -> (usize, usize, usize) {
894         let mut ppl_in_bldg = 0;
895         let mut ppl_off_map = 0;
896         for p in &self.people {
897             match p.state {
898                 PersonState::Trip(_) => {}
899                 PersonState::Inside(_) => {
900                     ppl_in_bldg += 1;
901                 }
902                 PersonState::OffMap => {
903                     ppl_off_map += 1;
904                 }
905             }
906         }
907         (self.people.len(), ppl_in_bldg, ppl_off_map)
908     }
909 
is_done(&self) -> bool910     pub fn is_done(&self) -> bool {
911         self.unfinished_trips == 0
912     }
913 
collect_events(&mut self) -> Vec<Event>914     pub fn collect_events(&mut self) -> Vec<Event> {
915         std::mem::replace(&mut self.events, Vec::new())
916     }
917 
trip_info(&self, id: TripID) -> TripInfo918     pub fn trip_info(&self, id: TripID) -> TripInfo {
919         self.trips[id.0].info.clone()
920     }
all_trip_info(&self) -> Vec<(TripID, TripInfo)>921     pub fn all_trip_info(&self) -> Vec<(TripID, TripInfo)> {
922         self.trips.iter().map(|t| (t.id, t.info.clone())).collect()
923     }
finished_trip_time(&self, id: TripID) -> Option<(Duration, Duration)>924     pub fn finished_trip_time(&self, id: TripID) -> Option<(Duration, Duration)> {
925         let t = &self.trips[id.0];
926         Some((t.finished_at? - t.info.departure, t.total_blocked_time))
927     }
928 
bldg_to_people(&self, b: BuildingID) -> Vec<PersonID>929     pub fn bldg_to_people(&self, b: BuildingID) -> Vec<PersonID> {
930         let mut people = Vec::new();
931         for p in &self.people {
932             if p.state == PersonState::Inside(b) {
933                 people.push(p.id);
934             }
935         }
936         people
937     }
938 
get_person(&self, p: PersonID) -> Option<&Person>939     pub fn get_person(&self, p: PersonID) -> Option<&Person> {
940         self.people.get(p.0)
941     }
get_all_people(&self) -> &Vec<Person>942     pub fn get_all_people(&self) -> &Vec<Person> {
943         &self.people
944     }
945 
trip_to_person(&self, id: TripID) -> PersonID946     pub fn trip_to_person(&self, id: TripID) -> PersonID {
947         self.trips[id.0].person
948     }
949 
person_finished_trip(&mut self, now: Time, person: PersonID, ctx: &mut Ctx)950     fn person_finished_trip(&mut self, now: Time, person: PersonID, ctx: &mut Ctx) {
951         let person = &mut self.people[person.0];
952         if person.delayed_trips.is_empty() {
953             return;
954         }
955         let (trip, spec, maybe_req, maybe_path) = person.delayed_trips.remove(0);
956         if false {
957             self.events.push(Event::Alert(
958                 AlertLocation::Person(person.id),
959                 format!(
960                     "{} just freed up, so starting delayed trip {}",
961                     person.id, trip
962                 ),
963             ));
964         }
965         self.start_trip(now, trip, spec, maybe_req, maybe_path, ctx);
966     }
967 
start_trip( &mut self, now: Time, trip: TripID, spec: TripSpec, maybe_req: Option<PathRequest>, mut maybe_path: Option<Path>, ctx: &mut Ctx, )968     pub fn start_trip(
969         &mut self,
970         now: Time,
971         trip: TripID,
972         spec: TripSpec,
973         maybe_req: Option<PathRequest>,
974         mut maybe_path: Option<Path>,
975         ctx: &mut Ctx,
976     ) {
977         assert!(!self.trips[trip.0].cancelled);
978         assert!(!self.trips[trip.0].aborted);
979         if !self.pathfinding_upfront && maybe_path.is_none() && maybe_req.is_some() {
980             maybe_path = ctx.map.pathfind(maybe_req.clone().unwrap());
981         }
982 
983         let person = &mut self.people[self.trips[trip.0].person.0];
984         if let PersonState::Trip(_) = person.state {
985             // Previous trip isn't done. Defer this one!
986             if false {
987                 self.events.push(Event::Alert(
988                     AlertLocation::Person(person.id),
989                     format!(
990                         "{} is still doing a trip, so not starting {} yet",
991                         person.id, trip
992                     ),
993                 ));
994             }
995             person
996                 .delayed_trips
997                 .push((trip, spec, maybe_req, maybe_path));
998             self.events.push(Event::TripPhaseStarting(
999                 trip,
1000                 person.id,
1001                 None,
1002                 TripPhaseType::DelayedStart,
1003             ));
1004             return;
1005         }
1006         self.trips[trip.0].started = true;
1007 
1008         match spec {
1009             TripSpec::VehicleAppearing {
1010                 start_pos,
1011                 goal,
1012                 retry_if_no_room,
1013                 use_vehicle,
1014                 origin,
1015             } => {
1016                 assert_eq!(person.state, PersonState::OffMap);
1017                 self.events.push(Event::PersonEntersMap(
1018                     person.id,
1019                     AgentID::Car(use_vehicle),
1020                     ctx.map.get_l(start_pos.lane()).src_i,
1021                     origin,
1022                 ));
1023                 person.state = PersonState::Trip(trip);
1024 
1025                 let vehicle = person.get_vehicle(use_vehicle);
1026                 assert!(ctx.parking.lookup_parked_car(vehicle.id).is_none());
1027                 let req = maybe_req.unwrap();
1028                 if let Some(router) =
1029                     maybe_path.map(|path| goal.make_router(vehicle.id, path, ctx.map))
1030                 {
1031                     if !ctx.cap.allow_trip(vehicle.id, router.get_path()) {
1032                         self.events.push(Event::Alert(
1033                             AlertLocation::Person(person.id),
1034                             format!(
1035                                 "Aborting {} because it would exceed the cap through some zone",
1036                                 trip
1037                             ),
1038                         ));
1039                         self.abort_trip(now, trip, Some(vehicle), ctx);
1040                         return;
1041                     }
1042 
1043                     ctx.scheduler.push(
1044                         now,
1045                         Command::SpawnCar(
1046                             CreateCar::for_appearing(
1047                                 vehicle, start_pos, router, req, trip, person.id,
1048                             ),
1049                             retry_if_no_room,
1050                         ),
1051                     );
1052                 } else {
1053                     self.events.push(Event::Alert(
1054                         AlertLocation::Person(person.id),
1055                         format!(
1056                             "VehicleAppearing trip couldn't find the first path: {}",
1057                             req
1058                         ),
1059                     ));
1060                     self.abort_trip(now, trip, Some(vehicle), ctx);
1061                 }
1062             }
1063             TripSpec::NoRoomToSpawn {
1064                 i,
1065                 use_vehicle,
1066                 error,
1067                 ..
1068             } => {
1069                 self.events.push(Event::Alert(
1070                     AlertLocation::Intersection(i),
1071                     format!("{} couldn't spawn at border {}: {}", person.id, i, error),
1072                 ));
1073                 let vehicle = person.get_vehicle(use_vehicle);
1074                 self.abort_trip(now, trip, Some(vehicle), ctx);
1075             }
1076             TripSpec::UsingParkedCar {
1077                 car, start_bldg, ..
1078             } => {
1079                 assert_eq!(person.state, PersonState::Inside(start_bldg));
1080                 person.state = PersonState::Trip(trip);
1081 
1082                 // TODO For now, use the car we decided to statically. That makes sense in most
1083                 // cases.
1084 
1085                 if let Some(parked_car) = ctx.parking.lookup_parked_car(car).cloned() {
1086                     let start = SidewalkSpot::building(start_bldg, ctx.map);
1087                     let walking_goal =
1088                         SidewalkSpot::parking_spot(parked_car.spot, ctx.map, ctx.parking);
1089                     let req = PathRequest {
1090                         start: start.sidewalk_pos,
1091                         end: walking_goal.sidewalk_pos,
1092                         constraints: PathConstraints::Pedestrian,
1093                     };
1094                     if let Some(path) = ctx.map.pathfind(req.clone()) {
1095                         ctx.scheduler.push(
1096                             now,
1097                             Command::SpawnPed(CreatePedestrian {
1098                                 id: person.ped,
1099                                 speed: person.ped_speed,
1100                                 start,
1101                                 goal: walking_goal,
1102                                 path,
1103                                 req,
1104                                 trip,
1105                                 person: person.id,
1106                             }),
1107                         );
1108                     } else {
1109                         self.events.push(Event::Alert(
1110                             AlertLocation::Person(person.id),
1111                             format!("UsingParkedCar trip couldn't find the walking path {}", req),
1112                         ));
1113                         // Move the car to the destination
1114                         ctx.parking.remove_parked_car(parked_car.clone());
1115                         self.abort_trip(now, trip, Some(parked_car.vehicle), ctx);
1116                     }
1117                 } else {
1118                     // This should only happen when a driving trip has been aborted and there was
1119                     // absolutely no room to warp the car.
1120                     self.events.push(Event::Alert(
1121                         AlertLocation::Person(person.id),
1122                         format!(
1123                             "{} should have {} parked somewhere, but it's unavailable, so \
1124                              aborting {}",
1125                             person.id, car, trip
1126                         ),
1127                     ));
1128                     self.abort_trip(now, trip, None, ctx);
1129                 }
1130             }
1131             TripSpec::JustWalking { start, goal } => {
1132                 assert_eq!(
1133                     person.state,
1134                     match start.connection {
1135                         SidewalkPOI::Building(b) => PersonState::Inside(b),
1136                         SidewalkPOI::Border(i, ref loc) => {
1137                             self.events.push(Event::PersonEntersMap(
1138                                 person.id,
1139                                 AgentID::Pedestrian(person.ped),
1140                                 i,
1141                                 loc.clone(),
1142                             ));
1143                             PersonState::OffMap
1144                         }
1145                         SidewalkPOI::SuddenlyAppear => {
1146                             // Unclear which end of the sidewalk this person should be associated
1147                             // with. For interactively spawned people, doesn't really matter.
1148                             self.events.push(Event::PersonEntersMap(
1149                                 person.id,
1150                                 AgentID::Pedestrian(person.ped),
1151                                 ctx.map.get_l(start.sidewalk_pos.lane()).src_i,
1152                                 None,
1153                             ));
1154                             PersonState::OffMap
1155                         }
1156                         _ => unreachable!(),
1157                     }
1158                 );
1159                 person.state = PersonState::Trip(trip);
1160 
1161                 let req = maybe_req.unwrap();
1162                 if let Some(path) = maybe_path {
1163                     ctx.scheduler.push(
1164                         now,
1165                         Command::SpawnPed(CreatePedestrian {
1166                             id: person.ped,
1167                             speed: person.ped_speed,
1168                             start,
1169                             goal,
1170                             path,
1171                             req,
1172                             trip,
1173                             person: person.id,
1174                         }),
1175                     );
1176                 } else {
1177                     self.events.push(Event::Alert(
1178                         AlertLocation::Person(person.id),
1179                         format!("JustWalking trip couldn't find the first path {}", req),
1180                     ));
1181                     self.abort_trip(now, trip, None, ctx);
1182                 }
1183             }
1184             TripSpec::UsingBike { start, .. } => {
1185                 assert_eq!(person.state, PersonState::Inside(start));
1186                 person.state = PersonState::Trip(trip);
1187 
1188                 if let Some(walk_to) = SidewalkSpot::bike_rack(start, ctx.map) {
1189                     let req = maybe_req.unwrap();
1190                     if let Some(path) = maybe_path {
1191                         ctx.scheduler.push(
1192                             now,
1193                             Command::SpawnPed(CreatePedestrian {
1194                                 id: person.ped,
1195                                 speed: person.ped_speed,
1196                                 start: SidewalkSpot::building(start, ctx.map),
1197                                 goal: walk_to,
1198                                 path,
1199                                 req,
1200                                 trip,
1201                                 person: person.id,
1202                             }),
1203                         );
1204                     } else {
1205                         self.events.push(Event::Alert(
1206                             AlertLocation::Person(person.id),
1207                             format!("UsingBike trip couldn't find the first path {}", req),
1208                         ));
1209                         self.abort_trip(now, trip, None, ctx);
1210                     }
1211                 } else {
1212                     self.events.push(Event::Alert(
1213                         AlertLocation::Person(person.id),
1214                         format!(
1215                             "UsingBike trip couldn't find a way to start biking from {}",
1216                             start
1217                         ),
1218                     ));
1219                     self.abort_trip(now, trip, None, ctx);
1220                 }
1221             }
1222             TripSpec::UsingTransit { start, stop1, .. } => {
1223                 assert_eq!(
1224                     person.state,
1225                     match start.connection {
1226                         SidewalkPOI::Building(b) => PersonState::Inside(b),
1227                         SidewalkPOI::Border(i, ref loc) => {
1228                             self.events.push(Event::PersonEntersMap(
1229                                 person.id,
1230                                 AgentID::Pedestrian(person.ped),
1231                                 i,
1232                                 loc.clone(),
1233                             ));
1234                             PersonState::OffMap
1235                         }
1236                         SidewalkPOI::SuddenlyAppear => {
1237                             // Unclear which end of the sidewalk this person should be associated
1238                             // with. For interactively spawned people, doesn't really matter.
1239                             self.events.push(Event::PersonEntersMap(
1240                                 person.id,
1241                                 AgentID::Pedestrian(person.ped),
1242                                 ctx.map.get_l(start.sidewalk_pos.lane()).src_i,
1243                                 None,
1244                             ));
1245                             PersonState::OffMap
1246                         }
1247                         _ => unreachable!(),
1248                     }
1249                 );
1250                 person.state = PersonState::Trip(trip);
1251 
1252                 let walk_to = SidewalkSpot::bus_stop(stop1, ctx.map);
1253                 let req = maybe_req.unwrap();
1254                 if let Some(path) = maybe_path {
1255                     ctx.scheduler.push(
1256                         now,
1257                         Command::SpawnPed(CreatePedestrian {
1258                             id: person.ped,
1259                             speed: person.ped_speed,
1260                             start,
1261                             goal: walk_to,
1262                             path,
1263                             req,
1264                             trip,
1265                             person: person.id,
1266                         }),
1267                     );
1268                 } else {
1269                     self.events.push(Event::Alert(
1270                         AlertLocation::Person(person.id),
1271                         format!("UsingTransit trip couldn't find the first path {}", req),
1272                     ));
1273                     self.abort_trip(now, trip, None, ctx);
1274                 }
1275             }
1276             TripSpec::Remote {
1277                 trip_time, from, ..
1278             } => {
1279                 assert_eq!(person.state, PersonState::OffMap);
1280                 person.state = PersonState::Trip(trip);
1281                 self.events
1282                     .push(Event::PersonLeavesRemoteBuilding(person.id, from));
1283                 ctx.scheduler
1284                     .push(now + trip_time, Command::FinishRemoteTrip(trip));
1285                 self.events.push(Event::TripPhaseStarting(
1286                     trip,
1287                     person.id,
1288                     None,
1289                     TripPhaseType::Remote,
1290                 ));
1291             }
1292         }
1293     }
1294 
all_arrivals_at_border(&self, at: IntersectionID) -> Vec<(Time, AgentType)>1295     pub fn all_arrivals_at_border(&self, at: IntersectionID) -> Vec<(Time, AgentType)> {
1296         let mut times = Vec::new();
1297         for t in &self.trips {
1298             if t.aborted || t.cancelled {
1299                 continue;
1300             }
1301             if let TripEndpoint::Border(i, _) = t.info.start {
1302                 if i == at {
1303                     // We can make some assumptions here.
1304                     let agent_type = match t.info.mode {
1305                         TripMode::Walk => AgentType::Pedestrian,
1306                         TripMode::Bike => AgentType::Bike,
1307                         TripMode::Drive => AgentType::Car,
1308                         // TODO Not true for long. People will be able to spawn at borders already
1309                         // on a bus.
1310                         TripMode::Transit => AgentType::Pedestrian,
1311                     };
1312                     times.push((t.info.departure, agent_type));
1313                 }
1314             }
1315         }
1316         times.sort();
1317         times
1318     }
1319 
1320     // TODO This could be lossy. There are a few layers in spawning trips, and things like
1321     // spawn_agents_around reach into one of the middle layers directly. So here in TripManager, we
1322     // might not have retained enough state to create a proper scenario. But this should work
1323     // reasonably for most cases.
generate_scenario(&self, map: &Map, name: String) -> Scenario1324     pub fn generate_scenario(&self, map: &Map, name: String) -> Scenario {
1325         let mut scenario = Scenario::empty(map, &name);
1326         for p in &self.people {
1327             scenario.people.push(PersonSpec {
1328                 id: p.id,
1329                 orig_id: p.orig_id,
1330                 trips: p
1331                     .trips
1332                     .iter()
1333                     .filter_map(|t| {
1334                         let trip = &self.trips[t.0];
1335                         SpawnTrip::new(
1336                             trip.info.start.clone(),
1337                             trip.info.end.clone(),
1338                             trip.info.mode,
1339                             map,
1340                         )
1341                         .map(|spawn| IndividTrip::new(trip.info.departure, spawn))
1342                     })
1343                     .collect(),
1344             });
1345         }
1346         scenario
1347     }
1348 }
1349 
1350 #[derive(Serialize, Deserialize, Debug, Clone)]
1351 struct Trip {
1352     id: TripID,
1353     info: TripInfo,
1354     started: bool,
1355     finished_at: Option<Time>,
1356     total_blocked_time: Duration,
1357     aborted: bool,
1358     cancelled: bool,
1359     legs: VecDeque<TripLeg>,
1360     person: PersonID,
1361 }
1362 
1363 #[derive(Serialize, Deserialize, Debug, Clone)]
1364 pub struct TripInfo {
1365     // Scheduled departure; the start may be delayed if the previous trip is taking too long.
1366     pub departure: Time,
1367     pub mode: TripMode,
1368     pub start: TripEndpoint,
1369     pub end: TripEndpoint,
1370     // Did a ScenarioModifier apply to this?
1371     pub modified: bool,
1372 }
1373 
1374 impl Trip {
1375     // Returns true if this succeeds. If not, trip aborted.
spawn_ped( &self, now: Time, start: SidewalkSpot, person: &Person, map: &Map, scheduler: &mut Scheduler, events: &mut Vec<Event>, ) -> bool1376     fn spawn_ped(
1377         &self,
1378         now: Time,
1379         start: SidewalkSpot,
1380         person: &Person,
1381         map: &Map,
1382         scheduler: &mut Scheduler,
1383         events: &mut Vec<Event>,
1384     ) -> bool {
1385         let walk_to = match self.legs[0] {
1386             TripLeg::Walk(ref to) => to.clone(),
1387             _ => unreachable!(),
1388         };
1389 
1390         let req = PathRequest {
1391             start: start.sidewalk_pos,
1392             end: walk_to.sidewalk_pos,
1393             constraints: PathConstraints::Pedestrian,
1394         };
1395         let path = if let Some(p) = map.pathfind(req.clone()) {
1396             p
1397         } else {
1398             events.push(Event::Alert(
1399                 AlertLocation::Person(self.person),
1400                 format!(
1401                     "Aborting {} because no path for the walking portion! {:?} to {:?}",
1402                     self.id, start, walk_to
1403                 ),
1404             ));
1405             return false;
1406         };
1407 
1408         scheduler.push(
1409             now,
1410             Command::SpawnPed(CreatePedestrian {
1411                 id: person.ped,
1412                 speed: person.ped_speed,
1413                 start,
1414                 goal: walk_to,
1415                 path,
1416                 req,
1417                 trip: self.id,
1418                 person: self.person,
1419             }),
1420         );
1421         true
1422     }
1423 
assert_walking_leg(&mut self, goal: SidewalkSpot)1424     fn assert_walking_leg(&mut self, goal: SidewalkSpot) {
1425         match self.legs.pop_front() {
1426             Some(TripLeg::Walk(spot)) => {
1427                 assert_eq!(goal, spot);
1428             }
1429             _ => unreachable!(),
1430         }
1431     }
1432 }
1433 
1434 // These don't specify where the leg starts, since it might be unknown -- like when we drive and
1435 // don't know where we'll wind up parking.
1436 #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
1437 pub enum TripLeg {
1438     Walk(SidewalkSpot),
1439     // A person may own many vehicles, so specify which they use
1440     Drive(CarID, DrivingGoal),
1441     // Maybe get off at a stop, maybe ride off-map
1442     RideBus(BusRouteID, Option<BusStopID>),
1443     Remote(OffMapLocation),
1444 }
1445 
1446 #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, Copy, PartialOrd, Ord)]
1447 pub enum TripMode {
1448     Walk,
1449     Bike,
1450     Transit,
1451     Drive,
1452 }
1453 
1454 impl TripMode {
all() -> Vec<TripMode>1455     pub fn all() -> Vec<TripMode> {
1456         vec![
1457             TripMode::Walk,
1458             TripMode::Bike,
1459             TripMode::Transit,
1460             TripMode::Drive,
1461         ]
1462     }
1463 
verb(self) -> &'static str1464     pub fn verb(self) -> &'static str {
1465         match self {
1466             TripMode::Walk => "walk",
1467             TripMode::Bike => "bike",
1468             TripMode::Transit => "use transit",
1469             TripMode::Drive => "drive",
1470         }
1471     }
1472 
1473     // If I used "present participle" in a method name, I'd never live it down.
ongoing_verb(self) -> &'static str1474     pub fn ongoing_verb(self) -> &'static str {
1475         match self {
1476             TripMode::Walk => "walking",
1477             TripMode::Bike => "biking",
1478             TripMode::Transit => "using transit",
1479             TripMode::Drive => "driving",
1480         }
1481     }
1482 
noun(self) -> &'static str1483     pub fn noun(self) -> &'static str {
1484         match self {
1485             TripMode::Walk => "Pedestrian",
1486             TripMode::Bike => "Bike",
1487             TripMode::Transit => "Bus",
1488             TripMode::Drive => "Car",
1489         }
1490     }
1491 
to_constraints(self) -> PathConstraints1492     pub fn to_constraints(self) -> PathConstraints {
1493         match self {
1494             TripMode::Walk => PathConstraints::Pedestrian,
1495             TripMode::Bike => PathConstraints::Bike,
1496             // TODO WRONG
1497             TripMode::Transit => PathConstraints::Bus,
1498             TripMode::Drive => PathConstraints::Car,
1499         }
1500     }
1501 
from_constraints(c: PathConstraints) -> TripMode1502     pub fn from_constraints(c: PathConstraints) -> TripMode {
1503         match c {
1504             PathConstraints::Pedestrian => TripMode::Walk,
1505             PathConstraints::Bike => TripMode::Bike,
1506             // TODO The bijection breaks down... transit rider vs train vs bus...
1507             PathConstraints::Bus | PathConstraints::Train => TripMode::Transit,
1508             PathConstraints::Car => TripMode::Drive,
1509         }
1510     }
1511 }
1512 
1513 #[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Debug, Clone)]
1514 pub enum TripEndpoint {
1515     Bldg(BuildingID),
1516     Border(IntersectionID, Option<OffMapLocation>),
1517 }
1518 
1519 impl TripEndpoint {
path_req( from: TripEndpoint, to: TripEndpoint, mode: TripMode, map: &Map, ) -> Option<PathRequest>1520     pub fn path_req(
1521         from: TripEndpoint,
1522         to: TripEndpoint,
1523         mode: TripMode,
1524         map: &Map,
1525     ) -> Option<PathRequest> {
1526         Some(PathRequest {
1527             start: pos(from, mode, true, map)?,
1528             end: pos(to, mode, false, map)?,
1529             constraints: match mode {
1530                 TripMode::Walk | TripMode::Transit => PathConstraints::Pedestrian,
1531                 TripMode::Drive => PathConstraints::Car,
1532                 TripMode::Bike => PathConstraints::Bike,
1533             },
1534         })
1535     }
1536 }
1537 
pos(endpt: TripEndpoint, mode: TripMode, from: bool, map: &Map) -> Option<Position>1538 fn pos(endpt: TripEndpoint, mode: TripMode, from: bool, map: &Map) -> Option<Position> {
1539     match endpt {
1540         TripEndpoint::Bldg(b) => match mode {
1541             TripMode::Walk | TripMode::Transit => Some(map.get_b(b).sidewalk_pos),
1542             TripMode::Bike => Some(DrivingGoal::ParkNear(b).goal_pos(PathConstraints::Bike, map)?),
1543             TripMode::Drive => Some(
1544                 DrivingGoal::ParkNear(b)
1545                     .goal_pos(PathConstraints::Car, map)
1546                     .unwrap(),
1547             ),
1548         },
1549         TripEndpoint::Border(i, _) => match mode {
1550             TripMode::Walk | TripMode::Transit => if from {
1551                 SidewalkSpot::start_at_border(i, None, map)
1552             } else {
1553                 SidewalkSpot::end_at_border(i, None, map)
1554             }
1555             .map(|spot| spot.sidewalk_pos),
1556             TripMode::Bike | TripMode::Drive => (if from {
1557                 map.get_i(i).some_outgoing_road(map)
1558             } else {
1559                 map.get_i(i).some_incoming_road(map)
1560             })
1561             .and_then(|dr| {
1562                 dr.lanes(
1563                     if mode == TripMode::Bike {
1564                         PathConstraints::Bike
1565                     } else {
1566                         PathConstraints::Car
1567                     },
1568                     map,
1569                 )
1570                 .get(0)
1571                 .map(|l| Position::start(*l))
1572             }),
1573         },
1574     }
1575 }
1576 
1577 pub enum TripResult<T> {
1578     Ok(T),
1579     ModeChange,
1580     TripDone,
1581     TripDoesntExist,
1582     TripNotStarted,
1583     TripAborted,
1584     TripCancelled,
1585     RemoteTrip,
1586 }
1587 
1588 impl<T> TripResult<T> {
ok(self) -> Option<T>1589     pub fn ok(self) -> Option<T> {
1590         match self {
1591             TripResult::Ok(data) => Some(data),
1592             _ => None,
1593         }
1594     }
1595 
propagate_error<X>(self) -> TripResult<X>1596     pub fn propagate_error<X>(self) -> TripResult<X> {
1597         match self {
1598             TripResult::Ok(_) => panic!("TripResult is Ok, can't propagate_error"),
1599             TripResult::ModeChange => TripResult::ModeChange,
1600             TripResult::TripDone => TripResult::TripDone,
1601             TripResult::TripDoesntExist => TripResult::TripDoesntExist,
1602             TripResult::TripNotStarted => TripResult::TripNotStarted,
1603             TripResult::TripAborted => TripResult::TripAborted,
1604             TripResult::TripCancelled => TripResult::TripCancelled,
1605             TripResult::RemoteTrip => TripResult::RemoteTrip,
1606         }
1607     }
1608 }
1609 
1610 #[derive(Serialize, Deserialize, Debug, Clone)]
1611 pub struct Person {
1612     pub id: PersonID,
1613     pub orig_id: Option<OrigPersonID>,
1614     pub trips: Vec<TripID>,
1615     // TODO home
1616     pub state: PersonState,
1617 
1618     pub ped: PedestrianID,
1619     pub ped_speed: Speed,
1620     // Both cars and bikes
1621     pub vehicles: Vec<Vehicle>,
1622 
1623     delayed_trips: Vec<(TripID, TripSpec, Option<PathRequest>, Option<Path>)>,
1624     on_bus: Option<CarID>,
1625 }
1626 
1627 impl Person {
get_vehicle(&self, id: CarID) -> Vehicle1628     pub(crate) fn get_vehicle(&self, id: CarID) -> Vehicle {
1629         self.vehicles.iter().find(|v| v.id == id).unwrap().clone()
1630     }
1631 }
1632 
1633 #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
1634 pub enum PersonState {
1635     Trip(TripID),
1636     Inside(BuildingID),
1637     OffMap,
1638 }
1639 
1640 impl TripEndpoint {
start_sidewalk_spot(&self, map: &Map) -> Option<SidewalkSpot>1641     pub(crate) fn start_sidewalk_spot(&self, map: &Map) -> Option<SidewalkSpot> {
1642         match self {
1643             TripEndpoint::Bldg(b) => Some(SidewalkSpot::building(*b, map)),
1644             TripEndpoint::Border(i, origin) => {
1645                 SidewalkSpot::start_at_border(*i, origin.clone(), map)
1646             }
1647         }
1648     }
1649 
end_sidewalk_spot(&self, map: &Map) -> Option<SidewalkSpot>1650     pub(crate) fn end_sidewalk_spot(&self, map: &Map) -> Option<SidewalkSpot> {
1651         match self {
1652             TripEndpoint::Bldg(b) => Some(SidewalkSpot::building(*b, map)),
1653             TripEndpoint::Border(i, destination) => {
1654                 SidewalkSpot::end_at_border(*i, destination.clone(), map)
1655             }
1656         }
1657     }
1658 
driving_goal( &self, constraints: PathConstraints, map: &Map, ) -> Option<DrivingGoal>1659     pub(crate) fn driving_goal(
1660         &self,
1661         constraints: PathConstraints,
1662         map: &Map,
1663     ) -> Option<DrivingGoal> {
1664         match self {
1665             TripEndpoint::Bldg(b) => Some(DrivingGoal::ParkNear(*b)),
1666             TripEndpoint::Border(i, destination) => DrivingGoal::end_at_border(
1667                 map.get_i(*i).some_incoming_road(map)?,
1668                 constraints,
1669                 destination.clone(),
1670                 map,
1671             ),
1672         }
1673     }
1674 }
1675