1 mod analytics;
2 mod cap;
3 mod events;
4 mod make;
5 mod mechanics;
6 mod pandemic;
7 mod render;
8 mod router;
9 mod scheduler;
10 mod sim;
11 mod transit;
12 mod trips;
13 
14 pub use self::analytics::{Analytics, TripPhase};
15 pub(crate) use self::cap::CapSimState;
16 pub(crate) use self::events::Event;
17 pub use self::events::{AlertLocation, TripPhaseType};
18 pub use self::make::{
19     BorderSpawnOverTime, IndividTrip, OffMapLocation, OriginDestination, PersonSpec, Scenario,
20     ScenarioGenerator, ScenarioModifier, SimFlags, SpawnOverTime, SpawnTrip, TripSpawner, TripSpec,
21 };
22 pub(crate) use self::mechanics::{
23     DrivingSimState, IntersectionSimState, ParkingSimState, WalkingSimState,
24 };
25 pub(crate) use self::pandemic::PandemicModel;
26 pub(crate) use self::router::{ActionAtEnd, Router};
27 pub(crate) use self::scheduler::{Command, Scheduler};
28 pub use self::sim::{AgentProperties, AlertHandler, Sim, SimCallback, SimOptions};
29 pub(crate) use self::transit::TransitSimState;
30 pub use self::trips::{Person, PersonState, TripInfo, TripResult};
31 pub use self::trips::{TripEndpoint, TripMode};
32 pub(crate) use self::trips::{TripLeg, TripManager};
33 pub use crate::render::{
34     CarStatus, DontDrawAgents, DrawCarInput, DrawPedCrowdInput, DrawPedestrianInput, GetDrawAgents,
35     PedCrowdLocation, UnzoomedAgent,
36 };
37 use abstutil::{deserialize_usize, serialize_usize};
38 use geom::{Distance, Pt2D, Speed, Time};
39 use map_model::{
40     BuildingID, BusRouteID, BusStopID, DirectedRoadID, IntersectionID, LaneID, Map, ParkingLotID,
41     Path, PathConstraints, PathRequest, Position,
42 };
43 use serde::{Deserialize, Serialize};
44 use std::fmt;
45 
46 // http://pccsc.net/bicycle-parking-info/ says 68 inches, which is 1.73m
47 pub const BIKE_LENGTH: Distance = Distance::const_meters(1.8);
48 // These two must be < PARKING_SPOT_LENGTH
49 pub const MIN_CAR_LENGTH: Distance = Distance::const_meters(4.5);
50 pub const MAX_CAR_LENGTH: Distance = Distance::const_meters(6.5);
51 // Note this is more than MAX_CAR_LENGTH
52 pub const BUS_LENGTH: Distance = Distance::const_meters(12.5);
53 pub const LIGHT_RAIL_LENGTH: Distance = Distance::const_meters(60.0);
54 
55 // At all speeds (including at rest), cars must be at least this far apart, measured from front of
56 // one car to the back of the other.
57 pub const FOLLOWING_DISTANCE: Distance = Distance::const_meters(1.0);
58 
59 // When spawning at borders, start the front of the vehicle this far along and gradually appear.
60 // Getting too close to EPSILON_DIST can lead to get_draw_car having no geometry at all.
61 pub const SPAWN_DIST: Distance = Distance::const_meters(0.05);
62 
63 // The numeric ID must be globally unique, without considering VehicleType. VehicleType is bundled
64 // for convenient debugging.
65 // TODO Implement Eq, Hash, Ord manually to guarantee this.
66 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
67 pub struct CarID(
68     #[serde(
69         serialize_with = "serialize_usize",
70         deserialize_with = "deserialize_usize"
71     )]
72     pub usize,
73     pub VehicleType,
74 );
75 
76 impl fmt::Display for CarID {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result77     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78         match self.1 {
79             VehicleType::Car => write!(f, "Car #{}", self.0),
80             VehicleType::Bus => write!(f, "Bus #{}", self.0),
81             VehicleType::Train => write!(f, "Train #{}", self.0),
82             VehicleType::Bike => write!(f, "Bike #{}", self.0),
83         }
84     }
85 }
86 
87 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
88 pub struct PedestrianID(
89     #[serde(
90         serialize_with = "serialize_usize",
91         deserialize_with = "deserialize_usize"
92     )]
93     pub usize,
94 );
95 
96 impl fmt::Display for PedestrianID {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result97     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
98         write!(f, "Pedestrian #{}", self.0)
99     }
100 }
101 
102 #[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Hash)]
103 pub enum AgentID {
104     Car(CarID),
105     Pedestrian(PedestrianID),
106     // TODO Rename...
107     BusPassenger(PersonID, CarID),
108 }
109 
110 impl AgentID {
as_car(self) -> CarID111     pub(crate) fn as_car(self) -> CarID {
112         match self {
113             AgentID::Car(id) => id,
114             _ => panic!("Not a CarID: {:?}", self),
115         }
116     }
117 
to_type(self) -> AgentType118     pub fn to_type(self) -> AgentType {
119         match self {
120             AgentID::Car(c) => match c.1 {
121                 VehicleType::Car => AgentType::Car,
122                 VehicleType::Bike => AgentType::Bike,
123                 VehicleType::Bus => AgentType::Bus,
124                 VehicleType::Train => AgentType::Train,
125             },
126             AgentID::Pedestrian(_) => AgentType::Pedestrian,
127             AgentID::BusPassenger(_, _) => AgentType::TransitRider,
128         }
129     }
130 }
131 
132 impl fmt::Display for AgentID {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result133     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
134         match self {
135             AgentID::Car(id) => write!(f, "AgentID({})", id),
136             AgentID::Pedestrian(id) => write!(f, "AgentID({})", id),
137             AgentID::BusPassenger(person, bus) => write!(f, "AgentID({} on {})", person, bus),
138         }
139     }
140 }
141 
142 #[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Hash)]
143 pub enum AgentType {
144     Car,
145     Bike,
146     Bus,
147     Train,
148     Pedestrian,
149     TransitRider,
150 }
151 
152 impl AgentType {
all() -> Vec<AgentType>153     pub fn all() -> Vec<AgentType> {
154         vec![
155             AgentType::Car,
156             AgentType::Bike,
157             AgentType::Bus,
158             AgentType::Train,
159             AgentType::Pedestrian,
160             AgentType::TransitRider,
161         ]
162     }
163 
noun(self) -> &'static str164     pub fn noun(self) -> &'static str {
165         match self {
166             AgentType::Car => "Car",
167             AgentType::Bike => "Bike",
168             AgentType::Bus => "Bus",
169             AgentType::Train => "Train",
170             AgentType::Pedestrian => "Pedestrian",
171             AgentType::TransitRider => "Transit rider",
172         }
173     }
174 
ongoing_verb(self) -> &'static str175     pub fn ongoing_verb(self) -> &'static str {
176         match self {
177             AgentType::Car => "driving",
178             AgentType::Bike => "biking",
179             AgentType::Bus | AgentType::Train => unreachable!(),
180             AgentType::Pedestrian => "walking",
181             AgentType::TransitRider => "riding transit",
182         }
183     }
184 }
185 
186 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
187 pub struct TripID(
188     #[serde(
189         serialize_with = "serialize_usize",
190         deserialize_with = "deserialize_usize"
191     )]
192     pub usize,
193 );
194 
195 impl fmt::Display for TripID {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result196     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
197         write!(f, "Trip #{}", self.0)
198     }
199 }
200 
201 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
202 pub struct PersonID(
203     #[serde(
204         serialize_with = "serialize_usize",
205         deserialize_with = "deserialize_usize"
206     )]
207     pub usize,
208 );
209 
210 impl fmt::Display for PersonID {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result211     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
212         write!(f, "Person {}", self.0)
213     }
214 }
215 
216 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
217 pub struct OrigPersonID(
218     #[serde(
219         serialize_with = "serialize_usize",
220         deserialize_with = "deserialize_usize"
221     )]
222     pub usize,
223     #[serde(
224         serialize_with = "serialize_usize",
225         deserialize_with = "deserialize_usize"
226     )]
227     pub usize,
228 );
229 
230 #[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
231 pub enum VehicleType {
232     Car,
233     Bus,
234     Train,
235     Bike,
236 }
237 
238 impl fmt::Display for VehicleType {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result239     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
240         match self {
241             VehicleType::Car => write!(f, "car"),
242             VehicleType::Bus => write!(f, "bus"),
243             VehicleType::Train => write!(f, "train"),
244             VehicleType::Bike => write!(f, "bike"),
245         }
246     }
247 }
248 
249 impl VehicleType {
to_constraints(self) -> PathConstraints250     pub fn to_constraints(self) -> PathConstraints {
251         match self {
252             VehicleType::Car => PathConstraints::Car,
253             VehicleType::Bus => PathConstraints::Bus,
254             VehicleType::Train => PathConstraints::Train,
255             VehicleType::Bike => PathConstraints::Bike,
256         }
257     }
258 
is_transit(self) -> bool259     pub(crate) fn is_transit(self) -> bool {
260         match self {
261             VehicleType::Car => false,
262             VehicleType::Bus => true,
263             VehicleType::Train => true,
264             VehicleType::Bike => false,
265         }
266     }
267 }
268 
269 #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
270 pub struct Vehicle {
271     pub id: CarID,
272     pub owner: Option<PersonID>,
273     pub vehicle_type: VehicleType,
274     pub length: Distance,
275     pub max_speed: Option<Speed>,
276 }
277 
278 #[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
279 pub struct VehicleSpec {
280     pub vehicle_type: VehicleType,
281     pub length: Distance,
282     pub max_speed: Option<Speed>,
283 }
284 
285 impl VehicleSpec {
make(self, id: CarID, owner: Option<PersonID>) -> Vehicle286     pub fn make(self, id: CarID, owner: Option<PersonID>) -> Vehicle {
287         assert_eq!(id.1, self.vehicle_type);
288         Vehicle {
289             id,
290             owner,
291             vehicle_type: self.vehicle_type,
292             length: self.length,
293             max_speed: self.max_speed,
294         }
295     }
296 }
297 
298 #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
299 pub enum ParkingSpot {
300     // Lane and idx
301     Onstreet(LaneID, usize),
302     // Building and idx (pretty meaningless)
303     Offstreet(BuildingID, usize),
304     Lot(ParkingLotID, usize),
305 }
306 
307 #[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
308 pub struct ParkedCar {
309     pub vehicle: Vehicle,
310     pub spot: ParkingSpot,
311 }
312 
313 // It'd be nice to inline the goal_pos like SidewalkSpot does, but DrivingGoal is persisted in
314 // Scenarios, so this wouldn't survive map edits.
315 #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
316 pub enum DrivingGoal {
317     ParkNear(BuildingID),
318     Border(IntersectionID, LaneID, Option<OffMapLocation>),
319 }
320 
321 impl DrivingGoal {
end_at_border( dr: DirectedRoadID, constraints: PathConstraints, destination: Option<OffMapLocation>, map: &Map, ) -> Option<DrivingGoal>322     pub fn end_at_border(
323         dr: DirectedRoadID,
324         constraints: PathConstraints,
325         destination: Option<OffMapLocation>,
326         map: &Map,
327     ) -> Option<DrivingGoal> {
328         let lanes = dr.lanes(constraints, map);
329         if lanes.is_empty() {
330             None
331         } else {
332             // TODO ideally could use any
333             Some(DrivingGoal::Border(dr.dst_i(map), lanes[0], destination))
334         }
335     }
336 
goal_pos(&self, constraints: PathConstraints, map: &Map) -> Option<Position>337     pub fn goal_pos(&self, constraints: PathConstraints, map: &Map) -> Option<Position> {
338         match self {
339             DrivingGoal::ParkNear(b) => match constraints {
340                 PathConstraints::Car => {
341                     Some(Position::start(map.find_driving_lane_near_building(*b)))
342                 }
343                 PathConstraints::Bike => Some(map.get_b(*b).biking_connection(map)?.0),
344                 PathConstraints::Bus | PathConstraints::Train | PathConstraints::Pedestrian => {
345                     unreachable!()
346                 }
347             },
348             DrivingGoal::Border(_, l, _) => Some(Position::end(*l, map)),
349         }
350     }
351 
make_router(&self, owner: CarID, path: Path, map: &Map) -> Router352     pub(crate) fn make_router(&self, owner: CarID, path: Path, map: &Map) -> Router {
353         match self {
354             DrivingGoal::ParkNear(b) => {
355                 if owner.1 == VehicleType::Bike {
356                     Router::bike_then_stop(owner, path, SidewalkSpot::bike_rack(*b, map).unwrap())
357                 } else {
358                     Router::park_near(owner, path, *b)
359                 }
360             }
361             DrivingGoal::Border(i, last_lane, _) => {
362                 Router::end_at_border(owner, path, map.get_l(*last_lane).length(), *i)
363             }
364         }
365     }
366 
pt(&self, map: &Map) -> Pt2D367     pub fn pt(&self, map: &Map) -> Pt2D {
368         match self {
369             DrivingGoal::ParkNear(b) => map.get_b(*b).polygon.center(),
370             DrivingGoal::Border(i, _, _) => map.get_i(*i).polygon.center(),
371         }
372     }
373 }
374 
375 #[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
376 pub struct SidewalkSpot {
377     pub connection: SidewalkPOI,
378     pub sidewalk_pos: Position,
379 }
380 
381 // Point of interest, that is
382 #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
383 pub enum SidewalkPOI {
384     // Note that for offstreet parking, the path will be the same as the building's front path.
385     ParkingSpot(ParkingSpot),
386     // Don't actually know where this goes yet!
387     DeferredParkingSpot,
388     Building(BuildingID),
389     BusStop(BusStopID),
390     Border(IntersectionID, Option<OffMapLocation>),
391     // The bikeable position
392     BikeRack(Position),
393     SuddenlyAppear,
394 }
395 
396 impl SidewalkSpot {
397     // Pretty hacky case
deferred_parking_spot() -> SidewalkSpot398     pub fn deferred_parking_spot() -> SidewalkSpot {
399         SidewalkSpot {
400             connection: SidewalkPOI::DeferredParkingSpot,
401             // Dummy value
402             sidewalk_pos: Position::start(LaneID(0)),
403         }
404     }
405 
parking_spot( spot: ParkingSpot, map: &Map, parking_sim: &ParkingSimState, ) -> SidewalkSpot406     pub fn parking_spot(
407         spot: ParkingSpot,
408         map: &Map,
409         parking_sim: &ParkingSimState,
410     ) -> SidewalkSpot {
411         SidewalkSpot {
412             connection: SidewalkPOI::ParkingSpot(spot),
413             sidewalk_pos: parking_sim.spot_to_sidewalk_pos(spot, map),
414         }
415     }
416 
building(b: BuildingID, map: &Map) -> SidewalkSpot417     pub fn building(b: BuildingID, map: &Map) -> SidewalkSpot {
418         SidewalkSpot {
419             connection: SidewalkPOI::Building(b),
420             sidewalk_pos: map.get_b(b).sidewalk_pos,
421         }
422     }
423 
424     // TODO For the case when we have to start/stop biking somewhere else, this won't match up with
425     // a building though!
bike_rack(b: BuildingID, map: &Map) -> Option<SidewalkSpot>426     pub fn bike_rack(b: BuildingID, map: &Map) -> Option<SidewalkSpot> {
427         let (bike_pos, sidewalk_pos) = map.get_b(b).biking_connection(map)?;
428         Some(SidewalkSpot {
429             connection: SidewalkPOI::BikeRack(bike_pos),
430             sidewalk_pos,
431         })
432     }
433 
bus_stop(stop: BusStopID, map: &Map) -> SidewalkSpot434     pub fn bus_stop(stop: BusStopID, map: &Map) -> SidewalkSpot {
435         SidewalkSpot {
436             sidewalk_pos: map.get_bs(stop).sidewalk_pos,
437             connection: SidewalkPOI::BusStop(stop),
438         }
439     }
440 
441     // Recall sidewalks are bidirectional.
start_at_border( i: IntersectionID, origin: Option<OffMapLocation>, map: &Map, ) -> Option<SidewalkSpot>442     pub fn start_at_border(
443         i: IntersectionID,
444         origin: Option<OffMapLocation>,
445         map: &Map,
446     ) -> Option<SidewalkSpot> {
447         let lanes = map
448             .get_i(i)
449             .get_outgoing_lanes(map, PathConstraints::Pedestrian);
450         if !lanes.is_empty() {
451             return Some(SidewalkSpot {
452                 sidewalk_pos: Position::start(lanes[0]),
453                 connection: SidewalkPOI::Border(i, origin),
454             });
455         }
456 
457         map.get_i(i)
458             .get_incoming_lanes(map, PathConstraints::Pedestrian)
459             .next()
460             .map(|l| SidewalkSpot {
461                 sidewalk_pos: Position::end(l, map),
462                 connection: SidewalkPOI::Border(i, origin),
463             })
464     }
465 
end_at_border( i: IntersectionID, destination: Option<OffMapLocation>, map: &Map, ) -> Option<SidewalkSpot>466     pub fn end_at_border(
467         i: IntersectionID,
468         destination: Option<OffMapLocation>,
469         map: &Map,
470     ) -> Option<SidewalkSpot> {
471         if let Some(l) = map
472             .get_i(i)
473             .get_incoming_lanes(map, PathConstraints::Pedestrian)
474             .next()
475         {
476             return Some(SidewalkSpot {
477                 sidewalk_pos: Position::end(l, map),
478                 connection: SidewalkPOI::Border(i, destination),
479             });
480         }
481 
482         let lanes = map
483             .get_i(i)
484             .get_outgoing_lanes(map, PathConstraints::Pedestrian);
485         if lanes.is_empty() {
486             return None;
487         }
488         Some(SidewalkSpot {
489             sidewalk_pos: Position::start(lanes[0]),
490             connection: SidewalkPOI::Border(i, destination),
491         })
492     }
493 
suddenly_appear(l: LaneID, dist: Distance, map: &Map) -> SidewalkSpot494     pub fn suddenly_appear(l: LaneID, dist: Distance, map: &Map) -> SidewalkSpot {
495         let lane = map.get_l(l);
496         assert!(lane.is_walkable());
497         assert!(dist <= lane.length());
498         SidewalkSpot {
499             sidewalk_pos: Position::new(l, dist),
500             connection: SidewalkPOI::SuddenlyAppear,
501         }
502     }
503 }
504 
505 #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
506 pub struct TimeInterval {
507     // TODO Private fields
508     pub start: Time,
509     pub end: Time,
510 }
511 
512 impl TimeInterval {
new(start: Time, end: Time) -> TimeInterval513     pub fn new(start: Time, end: Time) -> TimeInterval {
514         if end < start {
515             panic!("Bad TimeInterval {} .. {}", start, end);
516         }
517         TimeInterval { start, end }
518     }
519 
percent(&self, t: Time) -> f64520     pub fn percent(&self, t: Time) -> f64 {
521         if self.start == self.end {
522             return 1.0;
523         }
524 
525         let x = (t - self.start) / (self.end - self.start);
526         assert!(x >= 0.0 && x <= 1.0);
527         x
528     }
529 
percent_clamp_end(&self, t: Time) -> f64530     pub fn percent_clamp_end(&self, t: Time) -> f64 {
531         if t > self.end {
532             return 1.0;
533         }
534         self.percent(t)
535     }
536 }
537 
538 #[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
539 pub struct DistanceInterval {
540     // TODO Private fields
541     pub start: Distance,
542     pub end: Distance,
543 }
544 
545 impl DistanceInterval {
new_driving(start: Distance, end: Distance) -> DistanceInterval546     pub fn new_driving(start: Distance, end: Distance) -> DistanceInterval {
547         if end < start {
548             panic!("Bad DistanceInterval {} .. {}", start, end);
549         }
550         DistanceInterval { start, end }
551     }
552 
new_walking(start: Distance, end: Distance) -> DistanceInterval553     pub fn new_walking(start: Distance, end: Distance) -> DistanceInterval {
554         // start > end is fine, might be contraflow.
555         DistanceInterval { start, end }
556     }
557 
lerp(&self, x: f64) -> Distance558     pub fn lerp(&self, x: f64) -> Distance {
559         assert!(x >= 0.0 && x <= 1.0);
560         self.start + x * (self.end - self.start)
561     }
562 
length(&self) -> Distance563     pub fn length(&self) -> Distance {
564         (self.end - self.start).abs()
565     }
566 }
567 
568 #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
569 pub struct CreatePedestrian {
570     pub id: PedestrianID,
571     pub start: SidewalkSpot,
572     pub speed: Speed,
573     pub goal: SidewalkSpot,
574     pub req: PathRequest,
575     pub path: Path,
576     pub trip: TripID,
577     pub person: PersonID,
578 }
579 
580 #[derive(Serialize, Deserialize, PartialEq, Clone, Debug)]
581 pub struct CreateCar {
582     pub vehicle: Vehicle,
583     pub router: Router,
584     pub req: PathRequest,
585     pub start_dist: Distance,
586     pub maybe_parked_car: Option<ParkedCar>,
587     // None for buses
588     pub trip_and_person: Option<(TripID, PersonID)>,
589     pub maybe_route: Option<BusRouteID>,
590 }
591 
592 impl CreateCar {
for_appearing( vehicle: Vehicle, start_pos: Position, router: Router, req: PathRequest, trip: TripID, person: PersonID, ) -> CreateCar593     pub fn for_appearing(
594         vehicle: Vehicle,
595         start_pos: Position,
596         router: Router,
597         req: PathRequest,
598         trip: TripID,
599         person: PersonID,
600     ) -> CreateCar {
601         CreateCar {
602             vehicle,
603             router,
604             req,
605             start_dist: start_pos.dist_along(),
606             maybe_parked_car: None,
607             trip_and_person: Some((trip, person)),
608             maybe_route: None,
609         }
610     }
611 
612     // TODO Maybe inline in trips, the only caller.
for_parked_car( parked_car: ParkedCar, router: Router, req: PathRequest, start_dist: Distance, trip: TripID, person: PersonID, ) -> CreateCar613     pub fn for_parked_car(
614         parked_car: ParkedCar,
615         router: Router,
616         req: PathRequest,
617         start_dist: Distance,
618         trip: TripID,
619         person: PersonID,
620     ) -> CreateCar {
621         CreateCar {
622             vehicle: parked_car.vehicle.clone(),
623             router,
624             req,
625             start_dist,
626             maybe_parked_car: Some(parked_car),
627             trip_and_person: Some((trip, person)),
628             maybe_route: None,
629         }
630     }
631 }
632