1#![allow(clippy::type_complexity, clippy::too_many_arguments)]
14
15#[macro_use]
16extern crate anyhow;
17#[macro_use]
18extern crate log;
19
20use std::fmt;
21
22use serde::{Deserialize, Serialize};
23
24use abstutil::{deserialize_usize, serialize_usize};
25use geom::{Distance, Speed, Time};
26use map_model::{
27 BuildingID, IntersectionID, LaneID, Map, ParkingLotID, Path, PathConstraints, Position,
28 TransitRouteID, TransitStopID,
29};
30use synthpop::TripEndpoint;
31
32pub use crate::render::{
33 CarStatus, DrawCarInput, DrawPedCrowdInput, DrawPedestrianInput, Intent, PedCrowdLocation,
34 UnzoomedAgent,
35};
36
37pub use self::analytics::{Analytics, Problem, ProblemType, SlidingWindow, TripPhase};
38pub(crate) use self::events::Event;
39pub use self::events::{AlertLocation, TripPhaseType};
40pub use self::make::SimFlags;
41pub(crate) use self::make::{StartTripArgs, TripSpec};
42pub(crate) use self::mechanics::{
43 DrivingSimState, IntersectionSimState, ParkingSim, ParkingSimState, WalkingSimState,
44};
45pub(crate) use self::pandemic::PandemicModel;
46pub use self::prebake::PrebakeSummary;
47pub(crate) use self::recorder::TrafficRecorder;
48pub(crate) use self::router::{ActionAtEnd, Router};
49pub(crate) use self::scheduler::{Command, Scheduler};
50pub use self::sim::{
51 count_parked_cars_per_bldg, rand_dist, AgentProperties, AlertHandler, DelayCause, Sim,
52 SimCallback, SimOptions,
53};
54pub(crate) use self::transit::TransitSimState;
55pub use self::trips::{CommutersVehiclesCounts, Person, PersonState, TripInfo, TripResult};
56pub(crate) use self::trips::{TripLeg, TripManager};
57pub use synthpop::make::{fork_rng, BorderSpawnOverTime, ScenarioGenerator, SpawnOverTime};
58
59mod analytics;
60mod events;
61mod make;
62mod mechanics;
63mod pandemic;
64pub mod prebake;
65mod recorder;
66mod render;
67mod router;
68mod scheduler;
69mod sim;
70mod transit;
71mod trips;
72
73pub(crate) const BIKE_LENGTH: Distance = Distance::const_meters(1.8);
75pub(crate) const MIN_CAR_LENGTH: Distance = Distance::const_meters(4.5);
76pub(crate) const MAX_CAR_LENGTH: Distance = Distance::const_meters(6.5);
77pub(crate) const BUS_LENGTH: Distance = Distance::const_meters(12.5);
79pub(crate) const LIGHT_RAIL_LENGTH: Distance = Distance::const_meters(60.0);
80
81pub(crate) const FOLLOWING_DISTANCE: Distance = Distance::const_meters(1.0);
84
85pub(crate) const SPAWN_DIST: Distance = Distance::const_meters(0.05);
88
89#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
91pub struct CarID {
92 #[serde(
94 serialize_with = "serialize_usize",
95 deserialize_with = "deserialize_usize"
96 )]
97 pub id: usize,
98 pub vehicle_type: VehicleType,
100}
101
102impl fmt::Display for CarID {
103 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
104 match self.vehicle_type {
105 VehicleType::Car => write!(f, "Car #{}", self.id),
106 VehicleType::Bus => write!(f, "Bus #{}", self.id),
107 VehicleType::Train => write!(f, "Train #{}", self.id),
108 VehicleType::Bike => write!(f, "Bike #{}", self.id),
109 }
110 }
111}
112
113#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
114pub struct PedestrianID(
115 #[serde(
116 serialize_with = "serialize_usize",
117 deserialize_with = "deserialize_usize"
118 )]
119 pub usize,
120);
121
122impl fmt::Display for PedestrianID {
123 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
124 write!(f, "Pedestrian #{}", self.0)
125 }
126}
127
128#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Hash)]
129pub enum AgentID {
130 Car(CarID),
131 Pedestrian(PedestrianID),
132 BusPassenger(PersonID, CarID),
134}
135
136impl AgentID {
137 pub(crate) fn as_car(self) -> CarID {
138 match self {
139 AgentID::Car(id) => id,
140 _ => panic!("Not a CarID: {:?}", self),
141 }
142 }
143
144 pub fn to_type(self) -> AgentType {
145 match self {
146 AgentID::Car(c) => match c.vehicle_type {
147 VehicleType::Car => AgentType::Car,
148 VehicleType::Bike => AgentType::Bike,
149 VehicleType::Bus => AgentType::Bus,
150 VehicleType::Train => AgentType::Train,
151 },
152 AgentID::Pedestrian(_) => AgentType::Pedestrian,
153 AgentID::BusPassenger(_, _) => AgentType::TransitRider,
154 }
155 }
156
157 pub fn to_vehicle_type(self) -> Option<VehicleType> {
158 match self {
159 AgentID::Car(c) => Some(c.vehicle_type),
160 AgentID::Pedestrian(_) => None,
161 AgentID::BusPassenger(_, _) => None,
162 }
163 }
164
165 #[allow(unused)]
167 pub(crate) fn is_car(&self, id: usize) -> bool {
168 match self {
169 AgentID::Car(c) => c.id == id,
170 _ => false,
171 }
172 }
173
174 pub(crate) fn is_pedestrian(&self) -> bool {
175 matches!(self, AgentID::Pedestrian(_))
176 }
177}
178
179impl fmt::Display for AgentID {
180 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
181 match self {
182 AgentID::Car(id) => write!(f, "AgentID({})", id),
183 AgentID::Pedestrian(id) => write!(f, "AgentID({})", id),
184 AgentID::BusPassenger(person, bus) => write!(f, "AgentID({} on {})", person, bus),
185 }
186 }
187}
188
189#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Hash)]
190pub enum AgentType {
191 Car,
192 Bike,
193 Bus,
194 Train,
195 Pedestrian,
196 TransitRider,
197}
198
199impl AgentType {
200 pub fn all() -> Vec<AgentType> {
201 vec![
202 AgentType::Car,
203 AgentType::Bike,
204 AgentType::Bus,
205 AgentType::Train,
206 AgentType::Pedestrian,
207 AgentType::TransitRider,
208 ]
209 }
210
211 pub fn noun(self) -> &'static str {
212 match self {
213 AgentType::Car => "Car",
214 AgentType::Bike => "Bike",
215 AgentType::Bus => "Bus",
216 AgentType::Train => "Train",
217 AgentType::Pedestrian => "Pedestrian",
218 AgentType::TransitRider => "Transit rider",
219 }
220 }
221
222 pub fn plural_noun(self) -> &'static str {
223 match self {
224 AgentType::Car => "cars",
225 AgentType::Bike => "bikes",
226 AgentType::Bus => "buses",
227 AgentType::Train => "trains",
228 AgentType::Pedestrian => "pedestrians",
229 AgentType::TransitRider => "transit riders",
230 }
231 }
232
233 pub fn ongoing_verb(self) -> &'static str {
234 match self {
235 AgentType::Car => "driving",
236 AgentType::Bike => "biking",
237 AgentType::Bus | AgentType::Train => unreachable!(),
238 AgentType::Pedestrian => "walking",
239 AgentType::TransitRider => "riding transit",
240 }
241 }
242}
243
244#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
245pub struct TripID(
246 #[serde(
247 serialize_with = "serialize_usize",
248 deserialize_with = "deserialize_usize"
249 )]
250 pub usize,
251);
252
253impl abstutil::CloneableAny for TripID {}
254
255impl fmt::Display for TripID {
256 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
257 write!(f, "Trip #{}", self.0)
258 }
259}
260
261#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
262pub struct PersonID(
263 #[serde(
264 serialize_with = "serialize_usize",
265 deserialize_with = "deserialize_usize"
266 )]
267 pub usize,
268);
269
270impl fmt::Display for PersonID {
271 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
272 write!(f, "Person {}", self.0)
273 }
274}
275
276#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
277pub enum VehicleType {
278 Car,
279 Bus,
280 Train,
281 Bike,
282}
283
284impl fmt::Display for VehicleType {
285 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
286 match self {
287 VehicleType::Car => write!(f, "car"),
288 VehicleType::Bus => write!(f, "bus"),
289 VehicleType::Train => write!(f, "train"),
290 VehicleType::Bike => write!(f, "bike"),
291 }
292 }
293}
294
295impl VehicleType {
296 pub fn to_constraints(self) -> PathConstraints {
297 match self {
298 VehicleType::Car => PathConstraints::Car,
299 VehicleType::Bus => PathConstraints::Bus,
300 VehicleType::Train => PathConstraints::Train,
301 VehicleType::Bike => PathConstraints::Bike,
302 }
303 }
304
305 pub(crate) fn is_transit(self) -> bool {
306 match self {
307 VehicleType::Car => false,
308 VehicleType::Bus => true,
309 VehicleType::Train => true,
310 VehicleType::Bike => false,
311 }
312 }
313}
314
315#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
316pub struct Vehicle {
317 pub id: CarID,
318 pub owner: Option<PersonID>,
319 pub vehicle_type: VehicleType,
320 pub length: Distance,
321 pub max_speed: Option<Speed>,
322}
323
324#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
325pub struct VehicleSpec {
326 pub vehicle_type: VehicleType,
327 pub length: Distance,
328 pub max_speed: Option<Speed>,
329}
330
331impl VehicleSpec {
332 pub(crate) fn make(self, id: CarID, owner: Option<PersonID>) -> Vehicle {
333 assert_eq!(id.vehicle_type, self.vehicle_type);
334 Vehicle {
335 id,
336 owner,
337 vehicle_type: self.vehicle_type,
338 length: self.length,
339 max_speed: self.max_speed,
340 }
341 }
342}
343
344#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
345pub enum ParkingSpot {
346 Onstreet(LaneID, usize),
348 Offstreet(BuildingID, usize),
350 Lot(ParkingLotID, usize),
351}
352
353#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
354pub struct ParkedCar {
355 pub vehicle: Vehicle,
356 pub spot: ParkingSpot,
357 pub parked_since: Time,
358}
359
360#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
361pub(crate) enum DrivingGoal {
362 ParkNear(BuildingID),
363 Border(IntersectionID, LaneID),
364}
365
366impl DrivingGoal {
367 pub fn goal_pos(&self, constraints: PathConstraints, map: &Map) -> Option<Position> {
368 match self {
369 DrivingGoal::ParkNear(b) => match constraints {
370 PathConstraints::Car => {
371 let driving_lane = map.find_driving_lane_near_building(*b);
372 let sidewalk_pos = map.get_b(*b).sidewalk_pos;
373 if driving_lane.road == sidewalk_pos.lane().road {
374 Some(sidewalk_pos.equiv_pos(driving_lane, map))
375 } else {
376 Some(Position::start(driving_lane))
377 }
378 }
379 PathConstraints::Bike => Some(map.get_b(*b).biking_connection(map)?.0),
380 PathConstraints::Bus | PathConstraints::Train | PathConstraints::Pedestrian => {
381 unreachable!()
382 }
383 },
384 DrivingGoal::Border(_, l) => Some(Position::end(*l, map)),
385 }
386 }
387
388 pub fn make_router(&self, owner: CarID, path: Path, map: &Map) -> Router {
389 match self {
390 DrivingGoal::ParkNear(b) => {
391 if owner.vehicle_type == VehicleType::Bike {
392 Router::bike_then_stop(owner, path, SidewalkSpot::bike_rack(*b, map).unwrap())
393 } else {
394 Router::park_near(owner, path, *b)
395 }
396 }
397 DrivingGoal::Border(i, last_lane) => {
398 Router::end_at_border(owner, path, map.get_l(*last_lane).length(), *i)
399 }
400 }
401 }
402}
403
404#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
405pub(crate) struct SidewalkSpot {
406 pub connection: SidewalkPOI,
407 pub sidewalk_pos: Position,
408}
409
410#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
412pub(crate) enum SidewalkPOI {
413 ParkingSpot(ParkingSpot),
415 DeferredParkingSpot,
417 Building(BuildingID),
418 TransitStop(TransitStopID),
419 Border(IntersectionID),
420 BikeRack(Position),
422 SuddenlyAppear,
423}
424
425impl SidewalkSpot {
426 pub fn deferred_parking_spot() -> SidewalkSpot {
428 SidewalkSpot {
429 connection: SidewalkPOI::DeferredParkingSpot,
430 sidewalk_pos: Position::start(LaneID::dummy()),
431 }
432 }
433
434 pub fn parking_spot(
435 spot: ParkingSpot,
436 map: &Map,
437 parking_sim: &ParkingSimState,
438 ) -> SidewalkSpot {
439 SidewalkSpot {
440 connection: SidewalkPOI::ParkingSpot(spot),
441 sidewalk_pos: parking_sim.spot_to_sidewalk_pos(spot, map),
442 }
443 }
444
445 pub fn building(b: BuildingID, map: &Map) -> SidewalkSpot {
446 SidewalkSpot {
447 connection: SidewalkPOI::Building(b),
448 sidewalk_pos: map.get_b(b).sidewalk_pos,
449 }
450 }
451
452 pub fn bike_rack(b: BuildingID, map: &Map) -> Option<SidewalkSpot> {
455 let (bike_pos, sidewalk_pos) = map.get_b(b).biking_connection(map)?;
456 Some(SidewalkSpot {
457 connection: SidewalkPOI::BikeRack(bike_pos),
458 sidewalk_pos,
459 })
460 }
461
462 pub fn bus_stop(stop: TransitStopID, map: &Map) -> SidewalkSpot {
463 SidewalkSpot {
464 sidewalk_pos: map.get_ts(stop).sidewalk_pos,
465 connection: SidewalkPOI::TransitStop(stop),
466 }
467 }
468
469 pub fn start_at_border(i: IntersectionID, map: &Map) -> Option<SidewalkSpot> {
471 Some(SidewalkSpot {
472 sidewalk_pos: TripEndpoint::start_walking_at_border(i, map)?,
473 connection: SidewalkPOI::Border(i),
474 })
475 }
476
477 pub fn end_at_border(i: IntersectionID, map: &Map) -> Option<SidewalkSpot> {
478 Some(SidewalkSpot {
479 sidewalk_pos: TripEndpoint::end_walking_at_border(i, map)?,
480 connection: SidewalkPOI::Border(i),
481 })
482 }
483
484 pub fn suddenly_appear(pos: Position, map: &Map) -> SidewalkSpot {
485 let lane = map.get_l(pos.lane());
486 assert!(lane.is_walkable());
487 assert!(pos.dist_along() <= lane.length());
488 SidewalkSpot {
489 sidewalk_pos: pos,
490 connection: SidewalkPOI::SuddenlyAppear,
491 }
492 }
493}
494
495#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)]
496pub(crate) struct TimeInterval {
497 pub start: Time,
499 pub end: Time,
500}
501
502impl TimeInterval {
503 pub fn new(start: Time, end: Time) -> TimeInterval {
504 if end < start {
505 panic!("Bad TimeInterval {} .. {}", start, end);
506 }
507 TimeInterval { start, end }
508 }
509
510 pub fn percent(&self, t: Time) -> f64 {
511 if self.start == self.end {
512 return 1.0;
513 }
514
515 let x = (t - self.start) / (self.end - self.start);
516 assert!((0.0..=1.0).contains(&x));
517 x
518 }
519
520 pub fn percent_clamp_end(&self, t: Time) -> f64 {
521 if t > self.end {
522 return 1.0;
523 }
524 self.percent(t)
525 }
526}
527
528#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)]
529pub(crate) struct DistanceInterval {
530 pub start: Distance,
532 pub end: Distance,
533}
534
535impl DistanceInterval {
536 pub fn new_driving(start: Distance, end: Distance) -> DistanceInterval {
537 if end < start {
538 panic!("Bad DistanceInterval {} .. {}", start, end);
539 }
540 DistanceInterval { start, end }
541 }
542
543 pub fn new_walking(start: Distance, end: Distance) -> DistanceInterval {
544 DistanceInterval { start, end }
546 }
547
548 pub fn lerp(&self, x: f64) -> Distance {
549 assert!((0.0..=1.0).contains(&x));
550 self.start + x * (self.end - self.start)
551 }
552
553 pub fn length(&self) -> Distance {
554 (self.end - self.start).abs()
555 }
556}
557
558#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
559pub(crate) struct CreatePedestrian {
560 pub id: PedestrianID,
561 pub start: SidewalkSpot,
562 pub speed: Speed,
563 pub goal: SidewalkSpot,
564 pub path: Path,
565 pub trip: TripID,
566 pub person: PersonID,
567}
568
569#[derive(Serialize, Deserialize, PartialEq, Clone, Debug)]
570pub(crate) struct CreateCar {
571 pub vehicle: Vehicle,
572 pub router: Router,
573 pub maybe_parked_car: Option<ParkedCar>,
574 pub trip_and_person: Option<(TripID, PersonID)>,
576 pub maybe_route: Option<TransitRouteID>,
577}
578
579impl CreateCar {
580 pub fn for_appearing(
581 vehicle: Vehicle,
582 router: Router,
583 trip: TripID,
584 person: PersonID,
585 ) -> CreateCar {
586 CreateCar {
587 vehicle,
588 router,
589 maybe_parked_car: None,
590 trip_and_person: Some((trip, person)),
591 maybe_route: None,
592 }
593 }
594
595 pub fn for_parked_car(
597 parked_car: ParkedCar,
598 router: Router,
599 trip: TripID,
600 person: PersonID,
601 ) -> CreateCar {
602 CreateCar {
603 vehicle: parked_car.vehicle.clone(),
604 router,
605 maybe_parked_car: Some(parked_car),
606 trip_and_person: Some((trip, person)),
607 maybe_route: None,
608 }
609 }
610}
611
612pub fn pedestrian_body_radius() -> Distance {
613 map_model::SIDEWALK_THICKNESS / 4.0
614}