1use std::collections::{BTreeMap, VecDeque};
2
3use serde::{Deserialize, Serialize};
4
5use abstutil::{deserialize_btreemap, serialize_btreemap, Counter};
6use geom::{Distance, Duration, Speed, Time};
7use map_model::{
8 BuildingID, IntersectionID, Map, PathConstraints, PathRequest, Position, TransitRouteID,
9 TransitStopID,
10};
11use synthpop::{
12 IndividTrip, OrigPersonID, PersonSpec, Scenario, TripEndpoint, TripMode, TripPurpose,
13};
14
15use crate::sim::Ctx;
16use crate::{
17 AgentID, AgentType, AlertLocation, CarID, Command, CreateCar, CreatePedestrian, DrivingGoal,
18 Event, ParkedCar, ParkingSim, ParkingSpot, PedestrianID, PersonID, SidewalkPOI, SidewalkSpot,
19 StartTripArgs, TransitSimState, TripID, TripPhaseType, TripSpec, Vehicle, VehicleSpec,
20 VehicleType, WalkingSimState,
21};
22
23#[derive(Serialize, Deserialize, Debug, Clone)]
30pub(crate) struct TripManager {
31 trips: Vec<Trip>,
32 people: Vec<Person>,
33 #[serde(
35 serialize_with = "serialize_btreemap",
36 deserialize_with = "deserialize_btreemap"
37 )]
38 active_trip_mode: BTreeMap<AgentID, TripID>,
39 unfinished_trips: usize,
40
41 car_id_counter: usize,
42
43 events: Vec<Event>,
44}
45
46impl TripManager {
48 pub fn new() -> TripManager {
49 TripManager {
50 trips: Vec::new(),
51 people: Vec::new(),
52 active_trip_mode: BTreeMap::new(),
53 unfinished_trips: 0,
54 car_id_counter: 0,
55 events: Vec::new(),
56 }
57 }
58
59 pub fn new_person(
61 &mut self,
62 orig_id: Option<OrigPersonID>,
63 ped_speed: Speed,
64 vehicle_specs: Vec<VehicleSpec>,
65 ) -> &Person {
66 let id = PersonID(self.people.len());
67 let vehicles = vehicle_specs
68 .into_iter()
69 .map(|v| {
70 let c = CarID {
71 id: self.new_car_id(),
72 vehicle_type: v.vehicle_type,
73 };
74 v.make(c, Some(id))
75 })
76 .collect();
77 self.people.push(Person {
78 id,
79 orig_id,
80 trips: Vec::new(),
81 state: PersonState::OffMap,
83 ped: PedestrianID(id.0),
84 ped_speed,
85 vehicles,
86 delayed_trips: Vec::new(),
87 on_bus: None,
88 });
89 self.get_person(id).unwrap()
90 }
91
92 pub fn new_car_id(&mut self) -> usize {
93 let id = self.car_id_counter;
94 self.car_id_counter += 1;
95 id
96 }
97
98 pub fn new_trip(&mut self, person: PersonID, info: TripInfo) -> TripID {
99 let id = TripID(self.trips.len());
100 let trip = Trip {
101 id,
102 info,
103 person,
104 started: false,
105 finished_at: None,
106 total_blocked_time: Duration::ZERO,
107 total_distance: Distance::ZERO,
108 legs: VecDeque::new(),
109 };
110 self.unfinished_trips += 1;
111 let person = &mut self.people[trip.person.0];
112 if person.trips.is_empty() {
113 person.state = match trip.info.start {
114 TripEndpoint::Building(b) => {
115 self.events
116 .push(Event::PersonEntersBuilding(trip.person, b));
117 PersonState::Inside(b)
118 }
119 TripEndpoint::Border(_) | TripEndpoint::SuddenlyAppear(_) => PersonState::OffMap,
120 };
121 }
122 if let Some(t) = person.trips.last() {
123 if self.trips[t.0].info.departure > trip.info.departure {
125 panic!(
126 "{} has a trip starting at {}, then one at {}",
127 person.id, self.trips[t.0].info.departure, trip.info.departure
128 );
129 }
130 }
131 person.trips.push(id);
132 self.trips.push(trip);
133 id
134 }
135
136 pub fn start_trip(&mut self, now: Time, trip: TripID, args: StartTripArgs, ctx: &mut Ctx) {
137 assert!(self.trips[trip.0].info.cancellation_reason.is_none());
138
139 let person = &mut self.people[self.trips[trip.0].person.0];
140 if let PersonState::Trip(_) = person.state {
141 if false {
143 self.events.push(Event::Alert(
144 AlertLocation::Person(person.id),
145 format!(
146 "{} is still doing a trip, so not starting {} yet",
147 person.id, trip
148 ),
149 ));
150 }
151 person.delayed_trips.push((trip, args));
152 self.events.push(Event::TripPhaseStarting(
153 trip,
154 person.id,
155 None,
156 TripPhaseType::DelayedStart,
157 ));
158 return;
159 }
160 self.trips[trip.0].started = true;
161
162 let info = &self.trips[trip.0].info;
163 let spec = match TripSpec::maybe_new(
164 info.start,
165 info.end,
166 info.mode,
167 args.use_vehicle,
168 args.retry_if_no_room,
169 ctx.map,
170 ) {
171 Ok(spec) => spec,
172 Err(error) => TripSpec::SpawningFailure {
173 use_vehicle: args.use_vehicle,
174 error: error.to_string(),
175 },
176 };
177 let (spec, legs) = spec.into_plan(ctx.map);
179 assert!(self.trips[trip.0].legs.is_empty());
180 self.trips[trip.0].legs.extend(legs);
181
182 match spec {
183 TripSpec::VehicleAppearing {
184 start_pos,
185 goal,
186 retry_if_no_room,
187 use_vehicle,
188 } => {
189 assert_eq!(person.state, PersonState::OffMap);
190 self.events.push(Event::PersonEntersMap(
191 person.id,
192 AgentID::Car(use_vehicle),
193 ctx.map.get_l(start_pos.lane()).src_i,
194 ));
195 person.state = PersonState::Trip(trip);
196
197 let vehicle = person.get_vehicle(use_vehicle);
198 assert!(ctx.parking.lookup_parked_car(vehicle.id).is_none());
199 let constraints = if use_vehicle.vehicle_type == VehicleType::Bike {
200 PathConstraints::Bike
201 } else {
202 PathConstraints::Car
203 };
204 let req = PathRequest::vehicle(
205 start_pos,
206 goal.goal_pos(constraints, ctx.map).unwrap(),
207 constraints,
208 );
209 let person = person.id;
210
211 match ctx.map.pathfind(req) {
212 Ok(path) => {
213 let router = goal.make_router(vehicle.id, path, ctx.map);
214 ctx.scheduler.push(
215 now,
216 Command::SpawnCar(
217 CreateCar::for_appearing(vehicle, router, trip, person),
218 retry_if_no_room,
219 ),
220 );
221 }
222 Err(err) => {
223 self.cancel_trip(now, trip, err.to_string(), Some(vehicle), ctx);
224 }
225 }
226 }
227 TripSpec::SpawningFailure {
228 use_vehicle, error, ..
229 } => {
230 let vehicle = use_vehicle.map(|v| person.get_vehicle(v));
231 self.cancel_trip(now, trip, error, vehicle, ctx);
232 }
233 TripSpec::UsingParkedCar {
234 car, start_bldg, ..
235 } => {
236 assert_eq!(person.state, PersonState::Inside(start_bldg));
237 person.state = PersonState::Trip(trip);
238
239 if let Some(parked_car) = ctx.parking.lookup_parked_car(car).cloned() {
240 let start = SidewalkSpot::building(start_bldg, ctx.map);
241 let walking_goal =
242 SidewalkSpot::parking_spot(parked_car.spot, ctx.map, ctx.parking);
243 let req = PathRequest::walking(start.sidewalk_pos, walking_goal.sidewalk_pos);
244 match ctx.map.pathfind(req) {
245 Ok(path) => {
246 ctx.scheduler.push(
247 now,
248 Command::SpawnPed(CreatePedestrian {
249 id: person.ped,
250 speed: person.ped_speed,
251 start,
252 goal: walking_goal,
253 path,
254 trip,
255 person: person.id,
256 }),
257 );
258 }
259 Err(err) => {
260 ctx.parking.remove_parked_car(parked_car.clone());
262 self.cancel_trip(
263 now,
264 trip,
265 err.to_string(),
266 Some(parked_car.vehicle),
267 ctx,
268 );
269 }
270 }
271 } else {
272 self.cancel_trip(
275 now,
276 trip,
277 format!("should have {} parked somewhere, but it's unavailable", car),
278 None,
279 ctx,
280 );
281 }
282 }
283 TripSpec::JustWalking { start, goal } => {
284 assert_eq!(
285 person.state,
286 match start.connection {
287 SidewalkPOI::Building(b) => PersonState::Inside(b),
288 SidewalkPOI::Border(i) => {
289 self.events.push(Event::PersonEntersMap(
290 person.id,
291 AgentID::Pedestrian(person.ped),
292 i,
293 ));
294 PersonState::OffMap
295 }
296 SidewalkPOI::SuddenlyAppear => {
297 self.events.push(Event::PersonEntersMap(
300 person.id,
301 AgentID::Pedestrian(person.ped),
302 ctx.map.get_l(start.sidewalk_pos.lane()).src_i,
303 ));
304 PersonState::OffMap
305 }
306 _ => unreachable!(),
307 }
308 );
309 person.state = PersonState::Trip(trip);
310
311 let req = PathRequest::walking(start.sidewalk_pos, goal.sidewalk_pos);
312 match ctx.map.pathfind(req) {
313 Ok(path) => {
314 ctx.scheduler.push(
315 now,
316 Command::SpawnPed(CreatePedestrian {
317 id: person.ped,
318 speed: person.ped_speed,
319 start,
320 goal,
321 path,
322 trip,
323 person: person.id,
324 }),
325 );
326 }
327 Err(err) => {
328 self.cancel_trip(now, trip, err.to_string(), None, ctx);
329 }
330 }
331 }
332 TripSpec::UsingBike { start, .. } => {
333 assert_eq!(person.state, PersonState::Inside(start));
334 person.state = PersonState::Trip(trip);
335
336 if let Some(walk_to) = SidewalkSpot::bike_rack(start, ctx.map) {
337 let req = PathRequest::walking(
338 SidewalkSpot::building(start, ctx.map).sidewalk_pos,
339 walk_to.sidewalk_pos,
340 );
341 match ctx.map.pathfind(req) {
342 Ok(path) => {
343 match self.trips[trip.0].legs.front_mut() {
346 Some(TripLeg::Walk(ref mut spot)) => {
347 if spot.clone() != walk_to {
348 *spot = walk_to.clone();
350 }
351 }
352 _ => unreachable!(),
353 }
354
355 ctx.scheduler.push(
356 now,
357 Command::SpawnPed(CreatePedestrian {
358 id: person.ped,
359 speed: person.ped_speed,
360 start: SidewalkSpot::building(start, ctx.map),
361 goal: walk_to,
362 path,
363 trip,
364 person: person.id,
365 }),
366 );
367 }
368 Err(err) => {
369 self.cancel_trip(now, trip, err.to_string(), None, ctx);
370 }
371 }
372 } else {
373 self.cancel_trip(
374 now,
375 trip,
376 format!(
377 "UsingBike trip couldn't find a way to start biking from {}",
378 start
379 ),
380 None,
381 ctx,
382 );
383 }
384 }
385 TripSpec::UsingTransit { start, stop1, .. } => {
386 assert_eq!(
387 person.state,
388 match start.connection {
389 SidewalkPOI::Building(b) => PersonState::Inside(b),
390 SidewalkPOI::Border(i) => {
391 self.events.push(Event::PersonEntersMap(
392 person.id,
393 AgentID::Pedestrian(person.ped),
394 i,
395 ));
396 PersonState::OffMap
397 }
398 SidewalkPOI::SuddenlyAppear => {
399 self.events.push(Event::PersonEntersMap(
402 person.id,
403 AgentID::Pedestrian(person.ped),
404 ctx.map.get_l(start.sidewalk_pos.lane()).src_i,
405 ));
406 PersonState::OffMap
407 }
408 _ => unreachable!(),
409 }
410 );
411 person.state = PersonState::Trip(trip);
412
413 let walk_to = SidewalkSpot::bus_stop(stop1, ctx.map);
414 let req = PathRequest::walking(start.sidewalk_pos, walk_to.sidewalk_pos);
415 match ctx.map.pathfind(req) {
416 Ok(path) => {
417 ctx.scheduler.push(
418 now,
419 Command::SpawnPed(CreatePedestrian {
420 id: person.ped,
421 speed: person.ped_speed,
422 start,
423 goal: walk_to,
424 path,
425 trip,
426 person: person.id,
427 }),
428 );
429 }
430 Err(err) => {
431 self.cancel_trip(now, trip, err.to_string(), None, ctx);
432 }
433 }
434 }
435 }
436 }
437
438 pub fn collect_events(&mut self) -> Vec<Event> {
439 std::mem::take(&mut self.events)
440 }
441}
442
443impl TripManager {
445 pub fn agent_starting_trip_leg(&mut self, agent: AgentID, t: TripID) {
447 if let Some(other) = self.active_trip_mode.get(&agent) {
448 if *other != t {
449 panic!("{} is doing both {} and {}?", agent, t, other);
450 }
451 }
452 self.active_trip_mode.insert(agent, t);
453 }
454
455 pub fn car_reached_parking_spot(
456 &mut self,
457 now: Time,
458 car: CarID,
459 spot: ParkingSpot,
460 blocked_time: Duration,
461 distance_crossed: Distance,
462 ctx: &mut Ctx,
463 ) {
464 let trip = &mut self.trips[self.active_trip_mode.remove(&AgentID::Car(car)).unwrap().0];
465 trip.total_blocked_time += blocked_time;
466 trip.total_distance += distance_crossed;
467
468 match trip.legs.pop_front() {
469 Some(TripLeg::Drive(c, DrivingGoal::ParkNear(_))) => {
470 assert_eq!(car, c);
471 }
472 _ => unreachable!(),
473 };
474
475 match &trip.legs[0] {
476 TripLeg::Walk(to) => match (spot, &to.connection) {
477 (ParkingSpot::Offstreet(b1, _), SidewalkPOI::Building(b2)) if b1 == *b2 => {
478 assert_eq!(trip.legs.len(), 1);
479 trip.legs.pop_front().unwrap();
480
481 self.people[trip.person.0].state = PersonState::Inside(b1);
482 self.events
483 .push(Event::PersonEntersBuilding(trip.person, b1));
484 let id = trip.id;
485 self.trip_finished(now, id, ctx);
486 return;
487 }
488 _ => {}
489 },
490 _ => unreachable!(),
491 };
492
493 let id = trip.id;
494 self.spawn_ped(
495 now,
496 id,
497 SidewalkSpot::parking_spot(spot, ctx.map, ctx.parking),
498 ctx,
499 );
500 }
501
502 pub fn ped_reached_parking_spot(
503 &mut self,
504 now: Time,
505 ped: PedestrianID,
506 spot: ParkingSpot,
507 blocked_time: Duration,
508 distance_crossed: Distance,
509 ctx: &mut Ctx,
510 ) {
511 self.events.push(Event::PedReachedParkingSpot(ped, spot));
512 let trip = &mut self.trips[self
513 .active_trip_mode
514 .remove(&AgentID::Pedestrian(ped))
515 .unwrap()
516 .0];
517 trip.total_blocked_time += blocked_time;
518 trip.total_distance += distance_crossed;
519
520 trip.assert_walking_leg(SidewalkSpot::deferred_parking_spot());
521 let parked_car = ctx.parking.get_car_at_spot(spot).unwrap().clone();
522 let drive_to = match trip.legs[0] {
523 TripLeg::Drive(c, ref to) => {
524 assert_eq!(c, parked_car.vehicle.id);
525 to.clone()
526 }
527 _ => unreachable!(),
528 };
529
530 let base_start =
531 ctx.parking
532 .spot_to_driving_pos(parked_car.spot, &parked_car.vehicle, ctx.map);
533 let end = drive_to.goal_pos(PathConstraints::Car, ctx.map).unwrap();
534 let req = match spot {
535 ParkingSpot::Onstreet(_, _) => {
536 PathRequest::vehicle(base_start, end, PathConstraints::Car)
537 }
538 ParkingSpot::Offstreet(b, _) => {
539 self.events
540 .push(Event::PersonEntersBuilding(trip.person, b));
541 PathRequest::leave_from_driveway(base_start, end, PathConstraints::Car, ctx.map)
542 }
543 ParkingSpot::Lot(_, _) => {
544 PathRequest::leave_from_driveway(base_start, end, PathConstraints::Car, ctx.map)
545 }
546 };
547
548 let person = trip.person;
549 let trip = trip.id;
550 match ctx.map.pathfind(req) {
551 Ok(path) => {
552 let router = drive_to.make_router(parked_car.vehicle.id, path, ctx.map);
553 ctx.scheduler.push(
554 now,
555 Command::SpawnCar(
556 CreateCar::for_parked_car(parked_car, router, trip, person),
557 true,
558 ),
559 );
560 }
561 Err(err) => {
562 ctx.parking.remove_parked_car(parked_car.clone());
564 self.cancel_trip(now, trip, err.to_string(), Some(parked_car.vehicle), ctx);
565 }
566 }
567 }
568
569 pub fn ped_ready_to_bike(
570 &mut self,
571 now: Time,
572 ped: PedestrianID,
573 spot: SidewalkSpot,
574 blocked_time: Duration,
575 distance_crossed: Distance,
576 ctx: &mut Ctx,
577 ) {
578 let trip = &mut self.trips[self
579 .active_trip_mode
580 .remove(&AgentID::Pedestrian(ped))
581 .unwrap()
582 .0];
583 trip.total_blocked_time += blocked_time;
584 trip.total_distance += distance_crossed;
585
586 trip.assert_walking_leg(spot.clone());
587 let (bike, drive_to) = match trip.legs[0] {
588 TripLeg::Drive(bike, ref to) => (bike, to.clone()),
589 _ => unreachable!(),
590 };
591 let driving_pos = match spot.connection {
592 SidewalkPOI::BikeRack(p) => p,
593 _ => unreachable!(),
594 };
595
596 let end = if let Some(end) = drive_to.goal_pos(PathConstraints::Bike, ctx.map) {
597 end
598 } else {
599 let trip = trip.id;
600 self.cancel_trip(
601 now,
602 trip,
603 format!("no bike connection at {:?}", drive_to),
604 None,
605 ctx,
606 );
607 return;
608 };
609 let req = PathRequest::vehicle(driving_pos, end, PathConstraints::Bike);
610 let maybe_router = if req.start.lane() == req.end.lane() {
611 Err(anyhow!(
614 "biking to a different part of {} is silly, why not walk?",
615 req.start.lane()
616 ))
617 } else {
618 ctx.map
619 .pathfind(req)
620 .map(|path| drive_to.make_router(bike, path, ctx.map))
621 };
622 match maybe_router {
623 Ok(router) => {
624 ctx.scheduler.push(
625 now,
626 Command::SpawnCar(
627 CreateCar::for_appearing(
628 self.people[trip.person.0].get_vehicle(bike),
629 router,
630 trip.id,
631 trip.person,
632 ),
633 true,
634 ),
635 );
636 }
637 Err(err) => {
638 let trip = trip.id;
639 self.cancel_trip(now, trip, err.to_string(), None, ctx);
640 }
641 }
642 }
643
644 pub fn bike_reached_end(
645 &mut self,
646 now: Time,
647 bike: CarID,
648 bike_rack: SidewalkSpot,
649 blocked_time: Duration,
650 distance_crossed: Distance,
651 ctx: &mut Ctx,
652 ) {
653 self.events.push(Event::BikeStoppedAtSidewalk(
654 bike,
655 bike_rack.sidewalk_pos.lane(),
656 ));
657 let trip = &mut self.trips[self.active_trip_mode.remove(&AgentID::Car(bike)).unwrap().0];
658 trip.total_blocked_time += blocked_time;
659 trip.total_distance += distance_crossed;
660
661 match trip.legs.pop_front() {
662 Some(TripLeg::Drive(c, DrivingGoal::ParkNear(_))) => {
663 assert_eq!(c, bike);
664 }
665 _ => unreachable!(),
666 };
667
668 let id = trip.id;
669 self.spawn_ped(now, id, bike_rack, ctx);
670 }
671
672 pub fn ped_reached_building(
673 &mut self,
674 now: Time,
675 ped: PedestrianID,
676 bldg: BuildingID,
677 blocked_time: Duration,
678 distance_crossed: Distance,
679 ctx: &mut Ctx,
680 ) {
681 let trip = &mut self.trips[self
682 .active_trip_mode
683 .remove(&AgentID::Pedestrian(ped))
684 .unwrap()
685 .0];
686 trip.total_blocked_time += blocked_time;
687 trip.total_distance += distance_crossed;
688
689 trip.assert_walking_leg(SidewalkSpot::building(bldg, ctx.map));
690
691 self.people[trip.person.0].state = PersonState::Inside(bldg);
692 self.events
693 .push(Event::PersonEntersBuilding(trip.person, bldg));
694
695 let id = trip.id;
696 self.trip_finished(now, id, ctx);
697 }
698
699 pub fn ped_reached_bus_stop(
701 &mut self,
702 now: Time,
703 ped: PedestrianID,
704 stop: TransitStopID,
705 blocked_time: Duration,
706 distance_crossed: Distance,
707 ctx: &mut Ctx,
708 transit: &mut TransitSimState,
709 ) -> Option<TransitRouteID> {
710 let trip = &mut self.trips[self.active_trip_mode[&AgentID::Pedestrian(ped)].0];
711 trip.total_blocked_time += blocked_time;
712 trip.total_distance += distance_crossed;
713
714 match trip.legs[0] {
715 TripLeg::Walk(ref spot) => {
716 assert_eq!(*spot, SidewalkSpot::bus_stop(stop, ctx.map));
717 }
718 _ => unreachable!(),
719 }
720 match trip.legs[1] {
721 TripLeg::RideBus(route, maybe_stop2) => {
722 self.events.push(Event::TripPhaseStarting(
723 trip.id,
724 trip.person,
725 None,
726 TripPhaseType::WaitingForBus(route, stop),
727 ));
728 if let Some(bus) = transit.ped_waiting_for_bus(
729 now,
730 ped,
731 trip.id,
732 trip.person,
733 stop,
734 route,
735 maybe_stop2,
736 ctx.map,
737 ) {
738 trip.legs.pop_front();
739 self.active_trip_mode
740 .remove(&AgentID::Pedestrian(ped))
741 .unwrap();
742 self.active_trip_mode
743 .insert(AgentID::BusPassenger(trip.person, bus), trip.id);
744 self.people[trip.person.0].on_bus = Some(bus);
745 None
746 } else {
747 Some(route)
748 }
749 }
750 _ => unreachable!(),
751 }
752 }
753
754 pub fn ped_boarded_bus(
755 &mut self,
756 now: Time,
757 ped: PedestrianID,
758 bus: CarID,
759 blocked_time: Duration,
760 walking: &mut WalkingSimState,
761 ) -> (TripID, PersonID) {
762 let trip = &mut self.trips[self
763 .active_trip_mode
764 .remove(&AgentID::Pedestrian(ped))
765 .unwrap()
766 .0];
767 trip.total_blocked_time += blocked_time;
768 trip.legs.pop_front();
771 walking.ped_boarded_bus(now, ped);
772 self.active_trip_mode
773 .insert(AgentID::BusPassenger(trip.person, bus), trip.id);
774 self.people[trip.person.0].on_bus = Some(bus);
775 (trip.id, trip.person)
776 }
777
778 pub fn person_left_bus(&mut self, now: Time, person: PersonID, bus: CarID, ctx: &mut Ctx) {
780 let trip = &mut self.trips[self
781 .active_trip_mode
782 .remove(&AgentID::BusPassenger(person, bus))
783 .unwrap()
784 .0];
785 let start = match trip.legs.pop_front().unwrap() {
786 TripLeg::RideBus(_, maybe_stop2) => SidewalkSpot::bus_stop(
787 maybe_stop2.expect("someone left a bus, even though they should've ridden off-map"),
788 ctx.map,
789 ),
790 _ => unreachable!(),
791 };
792 self.people[person.0].on_bus.take().unwrap();
793
794 let id = trip.id;
795 self.spawn_ped(now, id, start, ctx);
796 }
797
798 pub fn ped_reached_border(
799 &mut self,
800 now: Time,
801 ped: PedestrianID,
802 i: IntersectionID,
803 blocked_time: Duration,
804 distance_crossed: Distance,
805 ctx: &mut Ctx,
806 ) {
807 let trip = &mut self.trips[self
808 .active_trip_mode
809 .remove(&AgentID::Pedestrian(ped))
810 .unwrap()
811 .0];
812 trip.total_blocked_time += blocked_time;
813 trip.total_distance += distance_crossed;
814
815 match trip.legs.pop_front() {
816 Some(TripLeg::Walk(spot)) => match spot.connection {
817 SidewalkPOI::Border(i2) => assert_eq!(i, i2),
818 _ => unreachable!(),
819 },
820 _ => unreachable!(),
821 }
822
823 if let TripEndpoint::Border(_) = trip.info.end {
824 self.events.push(Event::PersonLeavesMap(
825 trip.person,
826 Some(AgentID::Pedestrian(ped)),
827 i,
828 ));
829 }
830 self.people[trip.person.0].state = PersonState::OffMap;
831
832 let id = trip.id;
833 self.trip_finished(now, id, ctx);
834 }
835
836 pub fn transit_rider_reached_border(
837 &mut self,
838 now: Time,
839 person: PersonID,
840 bus: CarID,
841 ctx: &mut Ctx,
842 ) {
843 let agent = AgentID::BusPassenger(person, bus);
844 let trip = &mut self.trips[self.active_trip_mode.remove(&agent).unwrap().0];
845
846 match trip.legs.pop_front() {
847 Some(TripLeg::RideBus(_, maybe_spot2)) => assert!(maybe_spot2.is_none()),
848 _ => unreachable!(),
849 }
850
851 if let TripEndpoint::Border(i) = trip.info.end {
852 self.events
853 .push(Event::PersonLeavesMap(trip.person, Some(agent), i));
854 } else {
855 unreachable!()
856 }
857 self.people[trip.person.0].state = PersonState::OffMap;
858
859 let id = trip.id;
860 self.trip_finished(now, id, ctx);
861 }
862
863 pub fn car_or_bike_reached_border(
864 &mut self,
865 now: Time,
866 car: CarID,
867 i: IntersectionID,
868 blocked_time: Duration,
869 distance_crossed: Distance,
870 ctx: &mut Ctx,
871 ) {
872 let trip = &mut self.trips[self.active_trip_mode.remove(&AgentID::Car(car)).unwrap().0];
873 trip.total_blocked_time += blocked_time;
874 trip.total_distance += distance_crossed;
875
876 match trip.legs.pop_front().unwrap() {
877 TripLeg::Drive(c, DrivingGoal::Border(int, _)) => {
878 assert_eq!(car, c);
879 assert_eq!(i, int);
880 }
881 _ => unreachable!(),
882 };
883
884 self.people[trip.person.0].state = PersonState::OffMap;
885 if let TripEndpoint::Border(_) = trip.info.end {
886 self.events.push(Event::PersonLeavesMap(
887 trip.person,
888 Some(AgentID::Car(car)),
889 i,
890 ));
891 }
892
893 let id = trip.id;
894 self.trip_finished(now, id, ctx);
895 }
896
897 fn trip_finished(&mut self, now: Time, id: TripID, ctx: &mut Ctx) {
898 let trip = &mut self.trips[id.0];
899 assert!(trip.legs.is_empty());
900 assert!(!trip.finished_at.is_some());
901 trip.finished_at = Some(now);
902 self.unfinished_trips -= 1;
903 self.events.push(Event::TripFinished {
904 trip: trip.id,
905 mode: trip.info.mode,
906 total_time: now - trip.info.departure,
907 blocked_time: trip.total_blocked_time,
908 });
909
910 let person = trip.person;
911 self.start_delayed_trip(now, person, ctx);
912 }
913
914 fn start_delayed_trip(&mut self, now: Time, id: PersonID, ctx: &mut Ctx) {
915 let person = &mut self.people[id.0];
916 if person.delayed_trips.is_empty() {
917 return;
918 }
919 let (trip, args) = person.delayed_trips.remove(0);
920 if false {
921 self.events.push(Event::Alert(
922 AlertLocation::Person(person.id),
923 format!(
924 "{} just freed up, so starting delayed trip {}",
925 person.id, trip
926 ),
927 ));
928 }
929 self.start_trip(now, trip, args, ctx);
930 }
931
932 fn spawn_ped(&mut self, now: Time, id: TripID, start: SidewalkSpot, ctx: &mut Ctx) {
933 let trip = &self.trips[id.0];
934 let walk_to = match trip.legs[0] {
935 TripLeg::Walk(ref to) => to.clone(),
936 _ => unreachable!(),
937 };
938
939 let req = PathRequest::walking(start.sidewalk_pos, walk_to.sidewalk_pos);
940 match ctx.map.pathfind(req) {
941 Ok(path) => {
942 let person = &self.people[trip.person.0];
943 ctx.scheduler.push(
944 now,
945 Command::SpawnPed(CreatePedestrian {
946 id: person.ped,
947 speed: person.ped_speed,
948 start,
949 goal: walk_to,
950 path,
951 trip: id,
952 person: person.id,
953 }),
954 );
955 }
956 Err(err) => {
957 self.cancel_trip(now, id, err.to_string(), None, ctx);
958 }
959 }
960 }
961}
962
963impl TripManager {
965 pub fn cancel_unstarted_trip(&mut self, id: TripID, reason: String) {
967 let trip = &mut self.trips[id.0];
968 self.unfinished_trips -= 1;
969 trip.info.cancellation_reason = Some(reason);
970 self.events
971 .push(Event::TripCancelled(trip.id, trip.info.mode));
972 }
973
974 pub fn cancel_trip(
977 &mut self,
978 now: Time,
979 id: TripID,
980 reason: String,
981 abandoned_vehicle: Option<Vehicle>,
982 ctx: &mut Ctx,
983 ) {
984 let trip = &mut self.trips[id.0];
985 self.unfinished_trips -= 1;
986 trip.info.cancellation_reason = Some(reason);
987 self.events
988 .push(Event::TripCancelled(trip.id, trip.info.mode));
989 let person = trip.person;
990
991 if let PersonState::Inside(b) = self.people[person.0].state {
993 self.events.push(Event::PersonLeavesBuilding(person, b));
994 }
995 self.people[person.0].state = match trip.info.end {
997 TripEndpoint::Building(b) => {
998 self.events.push(Event::PersonEntersBuilding(person, b));
999 PersonState::Inside(b)
1000 }
1001 TripEndpoint::Border(i) => {
1002 self.events.push(Event::PersonLeavesMap(person, None, i));
1003 PersonState::OffMap
1004 }
1005 TripEndpoint::SuddenlyAppear(_) => unreachable!(),
1007 };
1008
1009 if let Some(vehicle) = abandoned_vehicle {
1011 if vehicle.vehicle_type == VehicleType::Car {
1012 if let Some(parked_car) = ctx.parking.lookup_parked_car(vehicle.id).cloned() {
1015 ctx.parking.remove_parked_car(parked_car);
1016 }
1017
1018 if let TripEndpoint::Building(b) = trip.info.end {
1019 let driving_lane = ctx.map.find_driving_lane_near_building(b);
1020 if let Some(spot) = ctx
1021 .parking
1022 .get_all_free_spots(Position::start(driving_lane), &vehicle, b, ctx.map)
1023 .get(0)
1026 .map(|(spot, _)| *spot)
1027 .or_else(|| {
1028 ctx.parking
1029 .path_to_free_parking_spot(driving_lane, &vehicle, b, ctx.map)
1030 .map(|(_, spot, _)| spot)
1031 })
1032 {
1033 self.events.push(Event::Alert(
1034 AlertLocation::Person(person),
1035 format!(
1036 "{} had a trip cancelled, and their car was warped to {:?}",
1037 person, spot
1038 ),
1039 ));
1040 ctx.parking.reserve_spot(spot, vehicle.id);
1041 ctx.parking.add_parked_car(ParkedCar {
1042 vehicle,
1043 spot,
1044 parked_since: now,
1045 });
1046 } else {
1047 self.events.push(Event::Alert(
1048 AlertLocation::Person(person),
1049 format!(
1050 "{} had a trip cancelled, but nowhere to warp their car! Sucks.",
1051 person
1052 ),
1053 ));
1054 }
1055 }
1056 }
1057 } else {
1058 if let TripLeg::Drive(c, _) = &trip.legs[0] {
1061 if let Some(t) = self.active_trip_mode.remove(&AgentID::Car(*c)) {
1062 assert_eq!(t, trip.id);
1063 }
1064 }
1065 }
1066
1067 self.start_delayed_trip(now, person, ctx);
1068 }
1069
1070 pub fn trip_abruptly_cancelled(&mut self, trip: TripID, agent: AgentID) {
1071 assert_eq!(self.active_trip_mode.remove(&agent), Some(trip));
1072 }
1073}
1074
1075impl TripManager {
1077 pub fn active_agents(&self) -> Vec<AgentID> {
1078 self.active_trip_mode.keys().cloned().collect()
1079 }
1080 pub fn active_agents_and_trips(&self) -> &BTreeMap<AgentID, TripID> {
1081 &self.active_trip_mode
1082 }
1083 pub fn num_active_agents(&self) -> usize {
1084 self.active_trip_mode.len()
1085 }
1086
1087 pub fn trip_to_agent(&self, id: TripID) -> TripResult<AgentID> {
1088 if id.0 >= self.trips.len() {
1089 return TripResult::TripDoesntExist;
1090 }
1091 let trip = &self.trips[id.0];
1092
1093 if trip.finished_at.is_some() {
1094 return TripResult::TripDone;
1095 }
1096 if trip.info.cancellation_reason.is_some() {
1097 return TripResult::TripCancelled;
1098 }
1099 if !trip.started {
1100 return TripResult::TripNotStarted;
1101 }
1102
1103 let person = &self.people[trip.person.0];
1104 let a = match &trip.legs[0] {
1105 TripLeg::Walk(_) => AgentID::Pedestrian(person.ped),
1106 TripLeg::Drive(c, _) => AgentID::Car(*c),
1107 TripLeg::RideBus(_, _) => AgentID::BusPassenger(person.id, person.on_bus.unwrap()),
1108 };
1109 if self.active_trip_mode.get(&a) == Some(&id) {
1110 TripResult::Ok(a)
1111 } else {
1112 TripResult::ModeChange
1114 }
1115 }
1116
1117 pub fn agent_to_trip(&self, id: AgentID) -> Option<TripID> {
1119 self.active_trip_mode.get(&id).cloned()
1120 }
1121
1122 pub fn debug_trip(&self, id: AgentID) {
1123 if let Some(t) = self.active_trip_mode.get(&id) {
1124 let trip = &self.trips[t.0];
1125 println!("{} has goal {:?}", trip.id, trip.legs.back().unwrap());
1126 } else {
1127 println!("{} has no trip, must be parked car", id);
1128 }
1129 }
1130
1131 pub fn num_trips(&self) -> (usize, usize) {
1132 (
1133 self.trips.len() - self.unfinished_trips,
1134 self.unfinished_trips,
1135 )
1136 }
1137 pub fn num_agents(&self, transit: &TransitSimState) -> Counter<AgentType> {
1138 let mut cnt = Counter::new();
1139 for a in self.active_trip_mode.keys() {
1140 cnt.inc(a.to_type());
1141 }
1142 let (buses, trains) = transit.active_vehicles();
1143 cnt.add(AgentType::Bus, buses);
1144 cnt.add(AgentType::Train, trains);
1145 cnt
1146 }
1147 pub fn num_commuters_vehicles(
1148 &self,
1149 transit: &TransitSimState,
1150 walking: &WalkingSimState,
1151 ) -> CommutersVehiclesCounts {
1152 let (buses, trains) = transit.active_vehicles();
1153 let mut cnt = CommutersVehiclesCounts {
1154 walking_commuters: 0,
1155 walking_to_from_transit: 0,
1156 walking_to_from_car: 0,
1157 walking_to_from_bike: 0,
1158
1159 cyclists: 0,
1160
1161 sov_drivers: 0,
1162
1163 buses,
1164 trains,
1165 bus_riders: 0,
1166 train_riders: 0,
1167 };
1168
1169 for a in self.active_trip_mode.keys() {
1170 match a {
1171 AgentID::Car(c) => match c.vehicle_type {
1172 VehicleType::Car => {
1173 cnt.sov_drivers += 1;
1174 }
1175 VehicleType::Bike => {
1176 cnt.cyclists += 1;
1177 }
1178 VehicleType::Bus | VehicleType::Train => unreachable!(),
1179 },
1180 AgentID::BusPassenger(_, c) => match c.vehicle_type {
1181 VehicleType::Bus => {
1182 cnt.bus_riders += 1;
1183 }
1184 VehicleType::Train => {
1185 cnt.train_riders += 1;
1186 }
1187 VehicleType::Car | VehicleType::Bike => unreachable!(),
1188 },
1189 AgentID::Pedestrian(_) => {}
1191 }
1192 }
1193 walking.populate_commuter_counts(&mut cnt);
1194
1195 cnt
1196 }
1197 pub fn num_ppl(&self) -> (usize, usize, usize) {
1198 let mut ppl_in_bldg = 0;
1199 let mut ppl_off_map = 0;
1200 for p in &self.people {
1201 match p.state {
1202 PersonState::Trip(_) => {}
1203 PersonState::Inside(_) => {
1204 ppl_in_bldg += 1;
1205 }
1206 PersonState::OffMap => {
1207 ppl_off_map += 1;
1208 }
1209 }
1210 }
1211 (self.people.len(), ppl_in_bldg, ppl_off_map)
1212 }
1213
1214 pub fn is_done(&self) -> bool {
1215 self.unfinished_trips == 0
1216 }
1217
1218 pub fn trip_info(&self, id: TripID) -> TripInfo {
1219 self.trips[id.0].info.clone()
1220 }
1221 pub fn all_trip_info(&self) -> Vec<(TripID, TripInfo)> {
1222 self.trips.iter().map(|t| (t.id, t.info.clone())).collect()
1223 }
1224 pub fn finished_trip_details(&self, id: TripID) -> Option<(Duration, Duration, Distance)> {
1225 let t = &self.trips[id.0];
1226 Some((
1227 t.finished_at? - t.info.departure,
1228 t.total_blocked_time,
1229 t.total_distance,
1230 ))
1231 }
1232 pub fn trip_blocked_time(&self, id: TripID) -> Duration {
1233 let t = &self.trips[id.0];
1234 t.total_blocked_time
1235 }
1236 pub fn bldg_to_people(&self, b: BuildingID) -> Vec<PersonID> {
1237 let mut people = Vec::new();
1238 for p in &self.people {
1239 if p.state == PersonState::Inside(b) {
1240 people.push(p.id);
1241 }
1242 }
1243 people
1244 }
1245
1246 pub fn get_person(&self, p: PersonID) -> Option<&Person> {
1247 self.people.get(p.0)
1248 }
1249 pub fn get_all_people(&self) -> &Vec<Person> {
1250 &self.people
1251 }
1252
1253 pub fn trip_to_person(&self, id: TripID) -> Option<PersonID> {
1254 Some(self.trips.get(id.0)?.person)
1255 }
1256
1257 pub fn all_arrivals_at_border(&self, at: IntersectionID) -> Vec<(Time, AgentType)> {
1258 let mut times = Vec::new();
1259 for t in &self.trips {
1260 if t.info.cancellation_reason.is_some() {
1261 continue;
1262 }
1263 if let TripEndpoint::Border(i) = t.info.start {
1264 if i == at {
1265 let agent_type = match t.info.mode {
1267 TripMode::Walk => AgentType::Pedestrian,
1268 TripMode::Bike => AgentType::Bike,
1269 TripMode::Drive => AgentType::Car,
1270 TripMode::Transit => AgentType::Pedestrian,
1273 };
1274 times.push((t.info.departure, agent_type));
1275 }
1276 }
1277 }
1278 times.sort();
1279 times
1280 }
1281
1282 pub fn generate_scenario(&self, map: &Map, name: String) -> Scenario {
1285 let mut scenario = Scenario::empty(map, &name);
1286 for p in &self.people {
1287 scenario.people.push(PersonSpec {
1288 orig_id: p.orig_id,
1289 trips: p
1290 .trips
1291 .iter()
1292 .map(|t| {
1293 let trip = &self.trips[t.0];
1294 IndividTrip::new(
1295 trip.info.departure,
1296 trip.info.purpose,
1297 trip.info.start,
1298 trip.info.end,
1299 trip.info.mode,
1300 )
1301 })
1302 .collect(),
1303 });
1304 }
1305 scenario
1306 }
1307}
1308
1309#[derive(Serialize, Deserialize, Debug, Clone)]
1310struct Trip {
1311 id: TripID,
1312 info: TripInfo,
1313 started: bool,
1314 finished_at: Option<Time>,
1315 total_blocked_time: Duration,
1316 total_distance: Distance,
1317 legs: VecDeque<TripLeg>,
1319 person: PersonID,
1320}
1321
1322#[derive(Serialize, Deserialize, Debug, Clone)]
1323pub struct TripInfo {
1324 pub departure: Time,
1326 pub mode: TripMode,
1327 pub start: TripEndpoint,
1328 pub end: TripEndpoint,
1329 pub purpose: TripPurpose,
1330 pub modified: bool,
1332 pub cancellation_reason: Option<String>,
1333}
1334
1335impl Trip {
1336 fn assert_walking_leg(&mut self, goal: SidewalkSpot) {
1337 match self.legs.pop_front() {
1338 Some(TripLeg::Walk(spot)) => {
1339 assert_eq!(goal, spot);
1340 }
1341 _ => unreachable!(),
1342 }
1343 }
1344}
1345
1346#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
1349pub(crate) enum TripLeg {
1350 Walk(SidewalkSpot),
1351 Drive(CarID, DrivingGoal),
1353 RideBus(TransitRouteID, Option<TransitStopID>),
1355}
1356
1357pub enum TripResult<T> {
1358 Ok(T),
1359 ModeChange,
1360 TripDone,
1361 TripDoesntExist,
1362 TripNotStarted,
1363 TripCancelled,
1364}
1365
1366impl<T> TripResult<T> {
1367 pub fn ok(self) -> Option<T> {
1368 match self {
1369 TripResult::Ok(data) => Some(data),
1370 _ => None,
1371 }
1372 }
1373
1374 pub fn propagate_error<X>(self) -> TripResult<X> {
1375 match self {
1376 TripResult::Ok(_) => panic!("TripResult is Ok, can't propagate_error"),
1377 TripResult::ModeChange => TripResult::ModeChange,
1378 TripResult::TripDone => TripResult::TripDone,
1379 TripResult::TripDoesntExist => TripResult::TripDoesntExist,
1380 TripResult::TripNotStarted => TripResult::TripNotStarted,
1381 TripResult::TripCancelled => TripResult::TripCancelled,
1382 }
1383 }
1384}
1385
1386#[derive(Serialize, Deserialize, Debug, Clone)]
1387pub struct Person {
1388 pub id: PersonID,
1389 pub orig_id: Option<OrigPersonID>,
1390 pub trips: Vec<TripID>,
1391 pub state: PersonState,
1392
1393 pub ped: PedestrianID,
1394 pub ped_speed: Speed,
1395 pub vehicles: Vec<Vehicle>,
1397
1398 delayed_trips: Vec<(TripID, StartTripArgs)>,
1399 on_bus: Option<CarID>,
1400}
1401
1402impl Person {
1403 fn get_vehicle(&self, id: CarID) -> Vehicle {
1404 self.vehicles.iter().find(|v| v.id == id).unwrap().clone()
1405 }
1406}
1407
1408#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
1409pub enum PersonState {
1410 Trip(TripID),
1411 Inside(BuildingID),
1412 OffMap,
1413}
1414
1415pub struct CommutersVehiclesCounts {
1417 pub walking_commuters: usize,
1418 pub walking_to_from_transit: usize,
1419 pub walking_to_from_car: usize,
1420 pub walking_to_from_bike: usize,
1421
1422 pub cyclists: usize,
1423
1424 pub sov_drivers: usize,
1425
1426 pub buses: usize,
1427 pub trains: usize,
1428 pub bus_riders: usize,
1429 pub train_riders: usize,
1430}