diff --git a/sim/src/mechanics/parking.rs b/sim/src/mechanics/parking.rs index 104c506d62..fb0d99bc04 100644 --- a/sim/src/mechanics/parking.rs +++ b/sim/src/mechanics/parking.rs @@ -14,6 +14,7 @@ use std::collections::{BTreeMap, BTreeSet, BinaryHeap, HashMap}; #[enum_dispatch(ParkingSimState)] pub trait ParkingSim { + // Returns any cars that got very abruptly evicted from existence fn handle_live_edits(&mut self, map: &Map, timer: &mut Timer) -> Vec; fn get_free_onstreet_spots(&self, l: LaneID) -> Vec; fn get_free_offstreet_spots(&self, b: BuildingID) -> Vec; @@ -24,10 +25,13 @@ pub trait ParkingSim { fn get_draw_cars(&self, id: LaneID, map: &Map) -> Vec; fn get_draw_cars_in_lots(&self, id: LaneID, map: &Map) -> Vec; fn get_draw_car(&self, id: CarID, map: &Map) -> Option; + // There's no DrawCarInput for cars parked offstreet, so we need this. fn canonical_pt(&self, id: CarID, map: &Map) -> Option; fn get_all_draw_cars(&self, map: &Map) -> Vec; fn is_free(&self, spot: ParkingSpot) -> bool; fn get_car_at_spot(&self, spot: ParkingSpot) -> Option<&ParkedCar>; + // The vehicle's front is currently at the given driving_pos. Returns all valid spots and their + // driving position. fn get_all_free_spots( &self, driving_pos: Position, @@ -41,7 +45,12 @@ pub trait ParkingSim { fn spot_to_sidewalk_pos(&self, spot: ParkingSpot, map: &Map) -> Position; fn get_owner_of_car(&self, id: CarID) -> Option; fn lookup_parked_car(&self, id: CarID) -> Option<&ParkedCar>; + // (Filled, available) fn get_all_parking_spots(&self) -> (Vec, Vec); + // Unrealistically assumes the driver has knowledge of currently free parking spots, even if + // they're far away. Since they don't reserve the spot in advance, somebody else can still beat + // them there, producing some nice, realistic churn if there's too much contention. + // The first PathStep is the turn after start, NOT PathStep::Lane(start). fn path_to_free_parking_spot( &self, start: LaneID, @@ -57,6 +66,7 @@ pub trait ParkingSim { #[derive(Serialize, Deserialize, Clone)] pub enum ParkingSimState { Normal(NormalParkingSimState), + Infinite(InfiniteParkingSimState), } impl ParkingSimState { @@ -149,11 +159,11 @@ pub struct NormalParkingSimState { } impl ParkingSim for NormalParkingSimState { - // Returns any cars that got very abruptly evicted from existence fn handle_live_edits(&mut self, map: &Map, timer: &mut Timer) -> Vec { let (filled_before, _) = self.get_all_parking_spots(); let new = match ParkingSimState::new(map, timer) { ParkingSimState::Normal(sim) => sim, + _ => unreachable!(), }; let (_, avail_after) = new.get_all_parking_spots(); let avail_after: BTreeSet = avail_after.into_iter().collect(); @@ -331,7 +341,6 @@ impl ParkingSim for NormalParkingSimState { } } - // There's no DrawCarInput for cars parked offstreet, so we need this. fn canonical_pt(&self, id: CarID, map: &Map) -> Option { let p = self.parked_cars.get(&id)?; match p.spot { @@ -363,8 +372,6 @@ impl ParkingSim for NormalParkingSimState { Some(&self.parked_cars[&car]) } - // The vehicle's front is currently at the given driving_pos. Returns all valid spots and their - // driving position. fn get_all_free_spots( &self, driving_pos: Position, @@ -459,7 +466,6 @@ impl ParkingSim for NormalParkingSimState { self.parked_cars.get(&id) } - // (Filled, available) fn get_all_parking_spots(&self) -> (Vec, Vec) { let mut spots = Vec::new(); for lane in self.onstreet_lanes.values() { @@ -488,10 +494,6 @@ impl ParkingSim for NormalParkingSimState { (filled, available) } - // Unrealistically assumes the driver has knowledge of currently free parking spots, even if - // they're far away. Since they don't reserve the spot in advance, somebody else can still beat - // them there, producing some nice, realistic churn if there's too much contention. - // The first PathStep is the turn after start, NOT PathStep::Lane(start). fn path_to_free_parking_spot( &self, start: LaneID, @@ -622,3 +624,191 @@ impl ParkingLane { spots } } + +// This assigns infinite private parking to all buildings and none anywhere else. This effectively +// disables the simulation of parking entirely, making driving trips just go directly between +// buildings. Useful for maps without good parking data (which is currently all of them) and +// experiments where parking contention skews results and just gets in the way. +#[derive(Serialize, Deserialize, Clone)] +pub struct InfiniteParkingSimState { + #[serde( + serialize_with = "serialize_btreemap", + deserialize_with = "deserialize_btreemap" + )] + parked_cars: BTreeMap, + #[serde( + serialize_with = "serialize_btreemap", + deserialize_with = "deserialize_btreemap" + )] + occupants: BTreeMap, + + // Cache dist_along + #[serde( + serialize_with = "serialize_multimap", + deserialize_with = "deserialize_multimap" + )] + driving_to_offstreet: MultiMap, + + events: Vec, +} + +impl InfiniteParkingSimState { + fn get_free_bldg_spot(&self, b: BuildingID) -> ParkingSpot { + let mut i = 0; + loop { + let spot = ParkingSpot::Offstreet(b, i); + if self.is_free(spot) { + return spot; + } + i += 1; + } + } +} + +impl ParkingSim for InfiniteParkingSimState { + fn handle_live_edits(&mut self, map: &Map, timer: &mut Timer) -> Vec { + // Can live edits possibly affect anything? + let new = match ParkingSimState::new(map, timer) { + ParkingSimState::Infinite(sim) => sim, + _ => unreachable!(), + }; + self.driving_to_offstreet = new.driving_to_offstreet; + + Vec::new() + } + + fn get_free_onstreet_spots(&self, _: LaneID) -> Vec { + Vec::new() + } + + fn get_free_offstreet_spots(&self, b: BuildingID) -> Vec { + // TODO INFINITE. just return one or something? + Vec::new() + } + + fn get_free_lot_spots(&self, _: ParkingLotID) -> Vec { + Vec::new() + } + + fn reserve_spot(&mut self, _: ParkingSpot) {} + + fn remove_parked_car(&mut self, p: ParkedCar) { + self.parked_cars + .remove(&p.vehicle.id) + .expect("remove_parked_car missing from parked_cars"); + self.occupants + .remove(&p.spot) + .expect("remove_parked_car missing from occupants"); + self.events + .push(Event::CarLeftParkingSpot(p.vehicle.id, p.spot)); + } + + fn add_parked_car(&mut self, p: ParkedCar) { + self.events + .push(Event::CarReachedParkingSpot(p.vehicle.id, p.spot)); + + assert!(!self.occupants.contains_key(&p.spot)); + self.occupants.insert(p.spot, p.vehicle.id); + + assert!(!self.parked_cars.contains_key(&p.vehicle.id)); + self.parked_cars.insert(p.vehicle.id, p); + } + + fn get_draw_cars(&self, _: LaneID, _: &Map) -> Vec { + Vec::new() + } + + fn get_draw_cars_in_lots(&self, _: LaneID, _: &Map) -> Vec { + Vec::new() + } + + fn get_draw_car(&self, _: CarID, _: &Map) -> Option { + None + } + + fn canonical_pt(&self, id: CarID, map: &Map) -> Option { + let p = self.parked_cars.get(&id)?; + match p.spot { + ParkingSpot::Offstreet(b, _) => Some(map.get_b(b).label_center), + _ => unreachable!(), + } + } + + fn get_all_draw_cars(&self, _: &Map) -> Vec { + Vec::new() + } + + fn is_free(&self, spot: ParkingSpot) -> bool { + !self.occupants.contains_key(&spot) + } + + fn get_car_at_spot(&self, spot: ParkingSpot) -> Option<&ParkedCar> { + let car = self.occupants.get(&spot)?; + Some(&self.parked_cars[&car]) + } + + fn get_all_free_spots( + &self, + _: Position, + vehicle: &Vehicle, + target: BuildingID, + map: &Map, + ) -> Vec<(ParkingSpot, Position)> { + // TODO Shouldn't need to verify the driving pos work, right? + let spot = self.get_free_bldg_spot(target); + vec![(spot, self.spot_to_driving_pos(spot, vehicle, map))] + } + + fn spot_to_driving_pos(&self, spot: ParkingSpot, _: &Vehicle, map: &Map) -> Position { + match spot { + ParkingSpot::Offstreet(b, _) => map.get_b(b).driving_connection(map).unwrap().0, + _ => unreachable!(), + } + } + + fn spot_to_sidewalk_pos(&self, spot: ParkingSpot, map: &Map) -> Position { + match spot { + ParkingSpot::Offstreet(b, _) => map.get_b(b).sidewalk_pos, + _ => unreachable!(), + } + } + + fn get_owner_of_car(&self, id: CarID) -> Option { + self.parked_cars.get(&id).and_then(|p| p.vehicle.owner) + } + fn lookup_parked_car(&self, id: CarID) -> Option<&ParkedCar> { + self.parked_cars.get(&id) + } + + fn get_all_parking_spots(&self) -> (Vec, Vec) { + // TODO something very different + (Vec::new(), Vec::new()) + } + + fn path_to_free_parking_spot( + &self, + _: LaneID, + _: &Vehicle, + _: BuildingID, + _: &Map, + ) -> Option<(Vec, ParkingSpot, Position)> { + // The original building we're aiming for will always have room + unreachable!() + } + + fn collect_events(&mut self) -> Vec { + std::mem::replace(&mut self.events, Vec::new()) + } + + fn all_parked_car_positions(&self, map: &Map) -> Vec<(Position, PersonID)> { + self.parked_cars + .values() + .map(|p| { + ( + self.spot_to_sidewalk_pos(p.spot, map), + p.vehicle.owner.unwrap(), + ) + }) + .collect() + } +}