Handle live map edits that rip away parking while a car is actively parking in it. #312

This commit is contained in:
Dustin Carlino 2020-10-21 13:00:49 -07:00
parent adcd0f65fe
commit 3d1ca3af9e
5 changed files with 50 additions and 33 deletions

View File

@ -143,9 +143,9 @@ pub fn wraparound_get<T>(vec: &Vec<T>, idx: isize) -> &T {
&vec[idx as usize]
}
pub fn retain_btreemap<K: Ord + Clone, V, F: Fn(&K, &V) -> bool>(
pub fn retain_btreemap<K: Ord + Clone, V, F: FnMut(&K, &V) -> bool>(
map: &mut BTreeMap<K, V>,
keep: F,
mut keep: F,
) {
let mut remove_keys: Vec<K> = Vec::new();
for (k, v) in map.iter() {

View File

@ -526,7 +526,7 @@ impl DrivingSimState {
// If we don't do this, then we might have another car creep up behind, see
// the spot free, and start parking too. This can happen with multiple
// lanes and certain vehicle lengths.
ctx.parking.reserve_spot(spot);
ctx.parking.reserve_spot(spot, car.vehicle.id);
ctx.scheduler
.push(car.state.get_end_time(), Command::UpdateCar(car.vehicle.id));
true

View File

@ -4,8 +4,8 @@ use enum_dispatch::enum_dispatch;
use serde::{Deserialize, Serialize};
use abstutil::{
deserialize_btreemap, deserialize_multimap, serialize_btreemap, serialize_multimap, MultiMap,
Timer,
deserialize_btreemap, deserialize_multimap, retain_btreemap, serialize_btreemap,
serialize_multimap, MultiMap, Timer,
};
use geom::{Distance, PolyLine, Pt2D};
use map_model::{
@ -21,12 +21,13 @@ use crate::{CarID, CarStatus, DrawCarInput, Event, ParkedCar, ParkingSpot, Perso
/// ignored
#[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<ParkedCar>;
/// Returns any cars that got very abruptly evicted from existence, and also cars actively
/// moving into a deleted spot.
fn handle_live_edits(&mut self, map: &Map, timer: &mut Timer) -> (Vec<ParkedCar>, Vec<CarID>);
fn get_free_onstreet_spots(&self, l: LaneID) -> Vec<ParkingSpot>;
fn get_free_offstreet_spots(&self, b: BuildingID) -> Vec<ParkingSpot>;
fn get_free_lot_spots(&self, pl: ParkingLotID) -> Vec<ParkingSpot>;
fn reserve_spot(&mut self, spot: ParkingSpot);
fn reserve_spot(&mut self, spot: ParkingSpot, car: CarID);
fn remove_parked_car(&mut self, p: ParkedCar);
fn add_parked_car(&mut self, p: ParkedCar);
fn get_draw_cars(&self, id: LaneID, map: &Map) -> Vec<DrawCarInput>;
@ -108,7 +109,11 @@ pub struct NormalParkingSimState {
deserialize_with = "deserialize_btreemap"
)]
occupants: BTreeMap<ParkingSpot, CarID>,
reserved_spots: BTreeSet<ParkingSpot>,
#[serde(
serialize_with = "serialize_btreemap",
deserialize_with = "deserialize_btreemap"
)]
reserved_spots: BTreeMap<ParkingSpot, CarID>,
// On-street
onstreet_lanes: BTreeMap<LaneID, ParkingLane>,
@ -144,7 +149,7 @@ impl NormalParkingSimState {
let mut sim = NormalParkingSimState {
parked_cars: BTreeMap::new(),
occupants: BTreeMap::new(),
reserved_spots: BTreeSet::new(),
reserved_spots: BTreeMap::new(),
onstreet_lanes: BTreeMap::new(),
driving_to_parking_lanes: MultiMap::new(),
@ -185,7 +190,7 @@ impl NormalParkingSimState {
}
impl ParkingSim for NormalParkingSimState {
fn handle_live_edits(&mut self, map: &Map, timer: &mut Timer) -> Vec<ParkedCar> {
fn handle_live_edits(&mut self, map: &Map, timer: &mut Timer) -> (Vec<ParkedCar>, Vec<CarID>) {
let (filled_before, _) = self.get_all_parking_spots();
let new = NormalParkingSimState::new(map, timer);
let (_, avail_after) = new.get_all_parking_spots();
@ -209,14 +214,17 @@ impl ParkingSim for NormalParkingSimState {
}
}
// TODO How do we handle reserved_spots?
self.reserved_spots = self
.reserved_spots
.difference(&avail_after)
.cloned()
.collect();
let mut moving_into_deleted_spot = Vec::new();
retain_btreemap(&mut self.reserved_spots, |spot, car| {
if avail_after.contains(spot) {
true
} else {
moving_into_deleted_spot.push(*car);
false
}
});
evicted
(evicted, moving_into_deleted_spot)
}
fn get_free_onstreet_spots(&self, l: LaneID) -> Vec<ParkingSpot> {
@ -253,9 +261,9 @@ impl ParkingSim for NormalParkingSimState {
spots
}
fn reserve_spot(&mut self, spot: ParkingSpot) {
fn reserve_spot(&mut self, spot: ParkingSpot, car: CarID) {
assert!(self.is_free(spot));
self.reserved_spots.insert(spot);
self.reserved_spots.insert(spot, car);
// Sanity check the spot exists
match spot {
@ -286,7 +294,7 @@ impl ParkingSim for NormalParkingSimState {
self.events
.push(Event::CarReachedParkingSpot(p.vehicle.id, p.spot));
assert!(self.reserved_spots.remove(&p.spot));
assert_eq!(self.reserved_spots.remove(&p.spot), Some(p.vehicle.id));
assert!(!self.occupants.contains_key(&p.spot));
self.occupants.insert(p.spot, p.vehicle.id);
@ -389,7 +397,7 @@ impl ParkingSim for NormalParkingSimState {
}
fn is_free(&self, spot: ParkingSpot) -> bool {
!self.occupants.contains_key(&spot) && !self.reserved_spots.contains(&spot)
!self.occupants.contains_key(&spot) && !self.reserved_spots.contains_key(&spot)
}
fn get_car_at_spot(&self, spot: ParkingSpot) -> Option<&ParkedCar> {
@ -680,7 +688,11 @@ pub struct InfiniteParkingSimState {
deserialize_with = "deserialize_btreemap"
)]
occupants: BTreeMap<ParkingSpot, CarID>,
reserved_spots: BTreeSet<ParkingSpot>,
#[serde(
serialize_with = "serialize_btreemap",
deserialize_with = "deserialize_btreemap"
)]
reserved_spots: BTreeMap<ParkingSpot, CarID>,
// Cache dist_along
#[serde(
@ -700,7 +712,7 @@ impl InfiniteParkingSimState {
let mut sim = InfiniteParkingSimState {
parked_cars: BTreeMap::new(),
occupants: BTreeMap::new(),
reserved_spots: BTreeSet::new(),
reserved_spots: BTreeMap::new(),
driving_to_offstreet: MultiMap::new(),
blackholed_building_redirects: BTreeMap::new(),
@ -762,13 +774,13 @@ impl InfiniteParkingSimState {
}
impl ParkingSim for InfiniteParkingSimState {
fn handle_live_edits(&mut self, map: &Map, _: &mut Timer) -> Vec<ParkedCar> {
fn handle_live_edits(&mut self, map: &Map, _: &mut Timer) -> (Vec<ParkedCar>, Vec<CarID>) {
// Can live edits possibly affect anything?
let new = InfiniteParkingSimState::new(map);
self.driving_to_offstreet = new.driving_to_offstreet;
self.blackholed_building_redirects = new.blackholed_building_redirects;
Vec::new()
(Vec::new(), Vec::new())
}
fn get_free_onstreet_spots(&self, _: LaneID) -> Vec<ParkingSpot> {
@ -784,9 +796,9 @@ impl ParkingSim for InfiniteParkingSimState {
Vec::new()
}
fn reserve_spot(&mut self, spot: ParkingSpot) {
fn reserve_spot(&mut self, spot: ParkingSpot, car: CarID) {
assert!(self.is_free(spot));
self.reserved_spots.insert(spot);
self.reserved_spots.insert(spot, car);
}
fn remove_parked_car(&mut self, p: ParkedCar) {
@ -804,7 +816,7 @@ impl ParkingSim for InfiniteParkingSimState {
self.events
.push(Event::CarReachedParkingSpot(p.vehicle.id, p.spot));
assert!(self.reserved_spots.remove(&p.spot));
assert_eq!(self.reserved_spots.remove(&p.spot), Some(p.vehicle.id));
assert!(!self.occupants.contains_key(&p.spot));
self.occupants.insert(p.spot, p.vehicle.id);
@ -838,7 +850,7 @@ impl ParkingSim for InfiniteParkingSimState {
}
fn is_free(&self, spot: ParkingSpot) -> bool {
!self.occupants.contains_key(&spot) && !self.reserved_spots.contains(&spot)
!self.occupants.contains_key(&spot) && !self.reserved_spots.contains_key(&spot)
}
fn get_car_at_spot(&self, spot: ParkingSpot) -> Option<&ParkedCar> {

View File

@ -309,7 +309,7 @@ impl Sim {
self.trips.random_person(ped_speed, vehicle_specs)
}
pub(crate) fn seed_parked_car(&mut self, vehicle: Vehicle, spot: ParkingSpot) {
self.parking.reserve_spot(spot);
self.parking.reserve_spot(spot, vehicle.id);
self.parking.add_parked_car(ParkedCar {
vehicle,
spot,
@ -965,8 +965,13 @@ impl Sim {
}
{
let evicted_cars = self.parking.handle_live_edits(map, &mut Timer::throwaway());
let (evicted_cars, cars_parking_in_the_void) =
self.parking.handle_live_edits(map, &mut Timer::throwaway());
affected.extend(self.walking.find_trips_to_parking(evicted_cars));
for car in cars_parking_in_the_void {
let a = AgentID::Car(car);
affected.push((a, self.agent_to_trip(a).unwrap()));
}
if !self.parking.is_infinite() {
let (filled, avail) = self.parking.get_all_parking_spots();

View File

@ -793,7 +793,7 @@ impl TripManager {
person, spot
),
));
ctx.parking.reserve_spot(spot);
ctx.parking.reserve_spot(spot, vehicle.id);
ctx.parking.add_parked_car(ParkedCar {
vehicle,
spot,