#[macro_use]
extern crate log;
use std::fmt;
use serde::{Deserialize, Serialize};
use abstutil::{deserialize_usize, serialize_usize};
use geom::{Distance, Pt2D, Speed, Time};
use map_model::{
BuildingID, BusRouteID, BusStopID, DirectedRoadID, IntersectionID, LaneID, Map, ParkingLotID,
Path, PathConstraints, PathRequest, Position,
};
pub use crate::render::{
CarStatus, DrawCarInput, DrawPedCrowdInput, DrawPedestrianInput, PedCrowdLocation,
UnzoomedAgent,
};
pub use self::analytics::{Analytics, TripPhase};
pub(crate) use self::cap::CapSimState;
pub(crate) use self::events::Event;
pub use self::events::{AlertLocation, TripPhaseType};
pub use self::make::{
BorderSpawnOverTime, ExternalPerson, ExternalTrip, ExternalTripEndpoint, IndividTrip,
OffMapLocation, OriginDestination, PersonSpec, Scenario, ScenarioGenerator, ScenarioModifier,
SimFlags, SpawnOverTime, SpawnTrip, TripPurpose, TripSpawner, TripSpec,
};
pub(crate) use self::mechanics::{
DrivingSimState, IntersectionSimState, ParkingSim, ParkingSimState, WalkingSimState,
};
pub(crate) use self::pandemic::PandemicModel;
pub(crate) use self::router::{ActionAtEnd, Router};
pub(crate) use self::scheduler::{Command, Scheduler};
pub use self::sim::{AgentProperties, AlertHandler, Sim, SimCallback, SimOptions};
pub(crate) use self::transit::TransitSimState;
pub use self::trips::{Person, PersonState, TripInfo, TripResult};
pub use self::trips::{TripEndpoint, TripMode};
pub(crate) use self::trips::{TripLeg, TripManager};
mod analytics;
mod cap;
mod events;
mod make;
mod mechanics;
mod pandemic;
mod render;
mod router;
mod scheduler;
mod sim;
mod transit;
mod trips;
pub const BIKE_LENGTH: Distance = Distance::const_meters(1.8);
pub const MIN_CAR_LENGTH: Distance = Distance::const_meters(4.5);
pub const MAX_CAR_LENGTH: Distance = Distance::const_meters(6.5);
pub const BUS_LENGTH: Distance = Distance::const_meters(12.5);
pub const LIGHT_RAIL_LENGTH: Distance = Distance::const_meters(60.0);
pub const FOLLOWING_DISTANCE: Distance = Distance::const_meters(1.0);
pub const SPAWN_DIST: Distance = Distance::const_meters(0.05);
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct CarID(
#[serde(
serialize_with = "serialize_usize",
deserialize_with = "deserialize_usize"
)]
pub usize,
pub VehicleType,
);
impl fmt::Display for CarID {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.1 {
VehicleType::Car => write!(f, "Car #{}", self.0),
VehicleType::Bus => write!(f, "Bus #{}", self.0),
VehicleType::Train => write!(f, "Train #{}", self.0),
VehicleType::Bike => write!(f, "Bike #{}", self.0),
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct PedestrianID(
#[serde(
serialize_with = "serialize_usize",
deserialize_with = "deserialize_usize"
)]
pub usize,
);
impl fmt::Display for PedestrianID {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Pedestrian #{}", self.0)
}
}
#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Hash)]
pub enum AgentID {
Car(CarID),
Pedestrian(PedestrianID),
BusPassenger(PersonID, CarID),
}
impl AgentID {
pub(crate) fn as_car(self) -> CarID {
match self {
AgentID::Car(id) => id,
_ => panic!("Not a CarID: {:?}", self),
}
}
pub fn to_type(self) -> AgentType {
match self {
AgentID::Car(c) => match c.1 {
VehicleType::Car => AgentType::Car,
VehicleType::Bike => AgentType::Bike,
VehicleType::Bus => AgentType::Bus,
VehicleType::Train => AgentType::Train,
},
AgentID::Pedestrian(_) => AgentType::Pedestrian,
AgentID::BusPassenger(_, _) => AgentType::TransitRider,
}
}
}
impl fmt::Display for AgentID {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AgentID::Car(id) => write!(f, "AgentID({})", id),
AgentID::Pedestrian(id) => write!(f, "AgentID({})", id),
AgentID::BusPassenger(person, bus) => write!(f, "AgentID({} on {})", person, bus),
}
}
}
#[derive(Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug, Hash)]
pub enum AgentType {
Car,
Bike,
Bus,
Train,
Pedestrian,
TransitRider,
}
impl AgentType {
pub fn all() -> Vec<AgentType> {
vec![
AgentType::Car,
AgentType::Bike,
AgentType::Bus,
AgentType::Train,
AgentType::Pedestrian,
AgentType::TransitRider,
]
}
pub fn noun(self) -> &'static str {
match self {
AgentType::Car => "Car",
AgentType::Bike => "Bike",
AgentType::Bus => "Bus",
AgentType::Train => "Train",
AgentType::Pedestrian => "Pedestrian",
AgentType::TransitRider => "Transit rider",
}
}
pub fn plural_noun(self) -> &'static str {
match self {
AgentType::Car => "cars",
AgentType::Bike => "bikes",
AgentType::Bus => "buses",
AgentType::Train => "trains",
AgentType::Pedestrian => "pedestrians",
AgentType::TransitRider => "transit riders",
}
}
pub fn ongoing_verb(self) -> &'static str {
match self {
AgentType::Car => "driving",
AgentType::Bike => "biking",
AgentType::Bus | AgentType::Train => unreachable!(),
AgentType::Pedestrian => "walking",
AgentType::TransitRider => "riding transit",
}
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct TripID(
#[serde(
serialize_with = "serialize_usize",
deserialize_with = "deserialize_usize"
)]
pub usize,
);
impl fmt::Display for TripID {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Trip #{}", self.0)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct PersonID(
#[serde(
serialize_with = "serialize_usize",
deserialize_with = "deserialize_usize"
)]
pub usize,
);
impl fmt::Display for PersonID {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Person {}", self.0)
}
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
pub struct OrigPersonID(
#[serde(
serialize_with = "serialize_usize",
deserialize_with = "deserialize_usize"
)]
pub usize,
#[serde(
serialize_with = "serialize_usize",
deserialize_with = "deserialize_usize"
)]
pub usize,
);
#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
pub enum VehicleType {
Car,
Bus,
Train,
Bike,
}
impl fmt::Display for VehicleType {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
VehicleType::Car => write!(f, "car"),
VehicleType::Bus => write!(f, "bus"),
VehicleType::Train => write!(f, "train"),
VehicleType::Bike => write!(f, "bike"),
}
}
}
impl VehicleType {
pub fn to_constraints(self) -> PathConstraints {
match self {
VehicleType::Car => PathConstraints::Car,
VehicleType::Bus => PathConstraints::Bus,
VehicleType::Train => PathConstraints::Train,
VehicleType::Bike => PathConstraints::Bike,
}
}
pub(crate) fn is_transit(self) -> bool {
match self {
VehicleType::Car => false,
VehicleType::Bus => true,
VehicleType::Train => true,
VehicleType::Bike => false,
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct Vehicle {
pub id: CarID,
pub owner: Option<PersonID>,
pub vehicle_type: VehicleType,
pub length: Distance,
pub max_speed: Option<Speed>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
pub struct VehicleSpec {
pub vehicle_type: VehicleType,
pub length: Distance,
pub max_speed: Option<Speed>,
}
impl VehicleSpec {
pub fn make(self, id: CarID, owner: Option<PersonID>) -> Vehicle {
assert_eq!(id.1, self.vehicle_type);
Vehicle {
id,
owner,
vehicle_type: self.vehicle_type,
length: self.length,
max_speed: self.max_speed,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum ParkingSpot {
Onstreet(LaneID, usize),
Offstreet(BuildingID, usize),
Lot(ParkingLotID, usize),
}
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct ParkedCar {
pub vehicle: Vehicle,
pub spot: ParkingSpot,
pub parked_since: Time,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum DrivingGoal {
ParkNear(BuildingID),
Border(IntersectionID, LaneID, Option<OffMapLocation>),
}
impl DrivingGoal {
pub fn end_at_border(
dr: DirectedRoadID,
constraints: PathConstraints,
destination: Option<OffMapLocation>,
map: &Map,
) -> Option<DrivingGoal> {
let lanes = dr.lanes(constraints, map);
if lanes.is_empty() {
None
} else {
Some(DrivingGoal::Border(dr.dst_i(map), lanes[0], destination))
}
}
pub fn goal_pos(&self, constraints: PathConstraints, map: &Map) -> Option<Position> {
match self {
DrivingGoal::ParkNear(b) => match constraints {
PathConstraints::Car => {
Some(Position::start(map.find_driving_lane_near_building(*b)))
}
PathConstraints::Bike => Some(map.get_b(*b).biking_connection(map)?.0),
PathConstraints::Bus | PathConstraints::Train | PathConstraints::Pedestrian => {
unreachable!()
}
},
DrivingGoal::Border(_, l, _) => Some(Position::end(*l, map)),
}
}
pub(crate) fn make_router(&self, owner: CarID, path: Path, map: &Map) -> Router {
match self {
DrivingGoal::ParkNear(b) => {
if owner.1 == VehicleType::Bike {
Router::bike_then_stop(owner, path, SidewalkSpot::bike_rack(*b, map).unwrap())
} else {
Router::park_near(owner, path, *b)
}
}
DrivingGoal::Border(i, last_lane, _) => {
Router::end_at_border(owner, path, map.get_l(*last_lane).length(), *i)
}
}
}
pub fn pt(&self, map: &Map) -> Pt2D {
match self {
DrivingGoal::ParkNear(b) => map.get_b(*b).polygon.center(),
DrivingGoal::Border(i, _, _) => map.get_i(*i).polygon.center(),
}
}
}
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct SidewalkSpot {
pub connection: SidewalkPOI,
pub sidewalk_pos: Position,
}
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum SidewalkPOI {
ParkingSpot(ParkingSpot),
DeferredParkingSpot,
Building(BuildingID),
BusStop(BusStopID),
Border(IntersectionID, Option<OffMapLocation>),
BikeRack(Position),
SuddenlyAppear,
}
impl SidewalkSpot {
pub fn deferred_parking_spot() -> SidewalkSpot {
SidewalkSpot {
connection: SidewalkPOI::DeferredParkingSpot,
sidewalk_pos: Position::start(LaneID(0)),
}
}
pub fn parking_spot(
spot: ParkingSpot,
map: &Map,
parking_sim: &ParkingSimState,
) -> SidewalkSpot {
SidewalkSpot {
connection: SidewalkPOI::ParkingSpot(spot),
sidewalk_pos: parking_sim.spot_to_sidewalk_pos(spot, map),
}
}
pub fn building(b: BuildingID, map: &Map) -> SidewalkSpot {
SidewalkSpot {
connection: SidewalkPOI::Building(b),
sidewalk_pos: map.get_b(b).sidewalk_pos,
}
}
pub fn bike_rack(b: BuildingID, map: &Map) -> Option<SidewalkSpot> {
let (bike_pos, sidewalk_pos) = map.get_b(b).biking_connection(map)?;
Some(SidewalkSpot {
connection: SidewalkPOI::BikeRack(bike_pos),
sidewalk_pos,
})
}
pub fn bus_stop(stop: BusStopID, map: &Map) -> SidewalkSpot {
SidewalkSpot {
sidewalk_pos: map.get_bs(stop).sidewalk_pos,
connection: SidewalkPOI::BusStop(stop),
}
}
pub fn start_at_border(
i: IntersectionID,
origin: Option<OffMapLocation>,
map: &Map,
) -> Option<SidewalkSpot> {
let lanes = map
.get_i(i)
.get_outgoing_lanes(map, PathConstraints::Pedestrian);
if !lanes.is_empty() {
return Some(SidewalkSpot {
sidewalk_pos: Position::start(lanes[0]),
connection: SidewalkPOI::Border(i, origin),
});
}
map.get_i(i)
.get_incoming_lanes(map, PathConstraints::Pedestrian)
.get(0)
.map(|l| SidewalkSpot {
sidewalk_pos: Position::end(*l, map),
connection: SidewalkPOI::Border(i, origin),
})
}
pub fn end_at_border(
i: IntersectionID,
destination: Option<OffMapLocation>,
map: &Map,
) -> Option<SidewalkSpot> {
if let Some(l) = map
.get_i(i)
.get_incoming_lanes(map, PathConstraints::Pedestrian)
.get(0)
{
return Some(SidewalkSpot {
sidewalk_pos: Position::end(*l, map),
connection: SidewalkPOI::Border(i, destination),
});
}
let lanes = map
.get_i(i)
.get_outgoing_lanes(map, PathConstraints::Pedestrian);
if lanes.is_empty() {
return None;
}
Some(SidewalkSpot {
sidewalk_pos: Position::start(lanes[0]),
connection: SidewalkPOI::Border(i, destination),
})
}
pub fn suddenly_appear(l: LaneID, dist: Distance, map: &Map) -> SidewalkSpot {
let lane = map.get_l(l);
assert!(lane.is_walkable());
assert!(dist <= lane.length());
SidewalkSpot {
sidewalk_pos: Position::new(l, dist),
connection: SidewalkPOI::SuddenlyAppear,
}
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)]
pub struct TimeInterval {
pub start: Time,
pub end: Time,
}
impl TimeInterval {
pub fn new(start: Time, end: Time) -> TimeInterval {
if end < start {
panic!("Bad TimeInterval {} .. {}", start, end);
}
TimeInterval { start, end }
}
pub fn percent(&self, t: Time) -> f64 {
if self.start == self.end {
return 1.0;
}
let x = (t - self.start) / (self.end - self.start);
assert!(x >= 0.0 && x <= 1.0);
x
}
pub fn percent_clamp_end(&self, t: Time) -> f64 {
if t > self.end {
return 1.0;
}
self.percent(t)
}
}
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy)]
pub struct DistanceInterval {
pub start: Distance,
pub end: Distance,
}
impl DistanceInterval {
pub fn new_driving(start: Distance, end: Distance) -> DistanceInterval {
if end < start {
panic!("Bad DistanceInterval {} .. {}", start, end);
}
DistanceInterval { start, end }
}
pub fn new_walking(start: Distance, end: Distance) -> DistanceInterval {
DistanceInterval { start, end }
}
pub fn lerp(&self, x: f64) -> Distance {
assert!(x >= 0.0 && x <= 1.0);
self.start + x * (self.end - self.start)
}
pub fn length(&self) -> Distance {
(self.end - self.start).abs()
}
}
#[derive(Serialize, Deserialize, PartialEq, Debug, Clone)]
pub struct CreatePedestrian {
pub id: PedestrianID,
pub start: SidewalkSpot,
pub speed: Speed,
pub goal: SidewalkSpot,
pub req: PathRequest,
pub path: Path,
pub trip: TripID,
pub person: PersonID,
}
#[derive(Serialize, Deserialize, PartialEq, Clone, Debug)]
pub struct CreateCar {
pub vehicle: Vehicle,
pub router: Router,
pub req: PathRequest,
pub start_dist: Distance,
pub maybe_parked_car: Option<ParkedCar>,
pub trip_and_person: Option<(TripID, PersonID)>,
pub maybe_route: Option<BusRouteID>,
}
impl CreateCar {
pub fn for_appearing(
vehicle: Vehicle,
start_pos: Position,
router: Router,
req: PathRequest,
trip: TripID,
person: PersonID,
) -> CreateCar {
CreateCar {
vehicle,
router,
req,
start_dist: start_pos.dist_along(),
maybe_parked_car: None,
trip_and_person: Some((trip, person)),
maybe_route: None,
}
}
pub fn for_parked_car(
parked_car: ParkedCar,
router: Router,
req: PathRequest,
start_dist: Distance,
trip: TripID,
person: PersonID,
) -> CreateCar {
CreateCar {
vehicle: parked_car.vehicle.clone(),
router,
req,
start_dist,
maybe_parked_car: Some(parked_car),
trip_and_person: Some((trip, person)),
maybe_route: None,
}
}
}