From 220f33e2ecab1812663bb4f7d03516b349c1b5f9 Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Wed, 9 Sep 2020 10:47:14 -0700 Subject: [PATCH] Abort cars bound to park on edited lanes. #312 --- game/src/edit/mod.rs | 3 +- sim/src/mechanics/driving.rs | 22 ++++++++-- sim/src/mechanics/parking.rs | 2 +- sim/src/mechanics/walking.rs | 17 +++----- sim/src/router.rs | 8 +++- sim/src/sim.rs | 78 +++++++++++++++++++++--------------- 6 files changed, 78 insertions(+), 52 deletions(-) diff --git a/game/src/edit/mod.rs b/game/src/edit/mod.rs index 0eb1884637..0995144667 100644 --- a/game/src/edit/mod.rs +++ b/game/src/edit/mod.rs @@ -95,8 +95,7 @@ impl EditMode { app.primary .sim .handle_live_edited_traffic_signals(&app.primary.map); - app.primary.sim.handle_live_edited_lanes(&app.primary.map); - app.primary.sim.handle_live_edited_parking(&app.primary.map); + app.primary.sim.handle_live_edits(&app.primary.map); Transition::Pop }) } diff --git a/sim/src/mechanics/driving.rs b/sim/src/mechanics/driving.rs index c6bfd4538f..0a4c293ad1 100644 --- a/sim/src/mechanics/driving.rs +++ b/sim/src/mechanics/driving.rs @@ -4,14 +4,14 @@ use crate::sim::Ctx; use crate::{ ActionAtEnd, AgentID, AgentProperties, CarID, Command, CreateCar, DistanceInterval, DrawCarInput, Event, IntersectionSimState, ParkedCar, ParkingSimState, ParkingSpot, PersonID, - Scheduler, TimeInterval, TransitSimState, TripManager, UnzoomedAgent, Vehicle, WalkingSimState, - FOLLOWING_DISTANCE, + Scheduler, TimeInterval, TransitSimState, TripID, TripManager, UnzoomedAgent, Vehicle, + WalkingSimState, FOLLOWING_DISTANCE, }; use abstutil::{deserialize_btreemap, serialize_btreemap}; use geom::{Distance, Duration, PolyLine, Time}; use map_model::{LaneID, Map, Path, PathStep, Traversable}; use serde::{Deserialize, Serialize}; -use std::collections::{BTreeMap, HashSet, VecDeque}; +use std::collections::{BTreeMap, BTreeSet, HashSet, VecDeque}; const TIME_TO_UNPARK_ONSTRET: Duration = Duration::const_seconds(10.0); const TIME_TO_PARK_ONSTREET: Duration = Duration::const_seconds(15.0); @@ -1024,4 +1024,20 @@ impl DrivingSimState { pub fn target_lane_penalty(&self, l: LaneID) -> (usize, usize) { self.queues[&Traversable::Lane(l)].target_lane_penalty() } + + pub fn find_trips_to_edited_parking( + &self, + spots: BTreeSet, + ) -> Vec<(AgentID, TripID)> { + let mut affected = Vec::new(); + for car in self.cars.values() { + if let Some(spot) = car.router.get_parking_spot_goal() { + if !spots.contains(spot) { + // Buses don't park + affected.push((AgentID::Car(car.vehicle.id), car.trip_and_person.unwrap().0)); + } + } + } + affected + } } diff --git a/sim/src/mechanics/parking.rs b/sim/src/mechanics/parking.rs index 493743877a..77744d8f55 100644 --- a/sim/src/mechanics/parking.rs +++ b/sim/src/mechanics/parking.rs @@ -100,7 +100,7 @@ impl ParkingSimState { } // Returns any cars that got very abruptly evicted from existence - pub fn handle_map_updates(&mut self, map: &Map, timer: &mut Timer) -> Vec { + pub fn handle_live_edits(&mut self, map: &Map, timer: &mut Timer) -> Vec { let (filled_before, _) = self.get_all_parking_spots(); let new = ParkingSimState::new(map, timer); let (_, avail_after) = new.get_all_parking_spots(); diff --git a/sim/src/mechanics/walking.rs b/sim/src/mechanics/walking.rs index e74bf3354a..4f115e0941 100644 --- a/sim/src/mechanics/walking.rs +++ b/sim/src/mechanics/walking.rs @@ -489,25 +489,18 @@ impl WalkingSimState { std::mem::replace(&mut self.events, Vec::new()) } - pub fn handle_live_edited_parking( - &mut self, - deleted_cars: Vec, - scheduler: &mut Scheduler, - ) { - let goals: BTreeSet = deleted_cars + pub fn find_trips_to_parking(&self, evicted_cars: Vec) -> Vec<(AgentID, TripID)> { + let goals: BTreeSet = evicted_cars .into_iter() .map(|p| SidewalkPOI::ParkingSpot(p.spot)) .collect(); - let mut delete = Vec::new(); + let mut affected = Vec::new(); for ped in self.peds.values() { if goals.contains(&ped.goal.connection) { - delete.push(ped.id); + affected.push((AgentID::Pedestrian(ped.id), ped.trip)); } } - - for id in delete { - self.delete_ped(id, scheduler); - } + affected } } diff --git a/sim/src/router.rs b/sim/src/router.rs index 0279d83a88..69a3d31c03 100644 --- a/sim/src/router.rs +++ b/sim/src/router.rs @@ -32,7 +32,6 @@ pub enum ActionAtEnd { #[derive(Serialize, Deserialize, Clone, Debug, PartialEq)] enum Goal { // Spot and cached distance along the last driving lane - // TODO Right now, the building is ignored when choosing the best spot. ParkNearBuilding { target: BuildingID, spot: Option<(ParkingSpot, Distance)>, @@ -429,4 +428,11 @@ impl Router { _ => false, } } + + pub fn get_parking_spot_goal(&self) -> Option<&ParkingSpot> { + match self.goal { + Goal::ParkNearBuilding { ref spot, .. } => spot.as_ref().map(|(s, _)| s), + _ => None, + } + } } diff --git a/sim/src/sim.rs b/sim/src/sim.rs index 49c224183c..22aae03489 100644 --- a/sim/src/sim.rs +++ b/sim/src/sim.rs @@ -17,7 +17,7 @@ use map_model::{ }; use rand_xorshift::XorShiftRng; use serde::{Deserialize, Serialize}; -use std::collections::{BTreeMap, HashSet}; +use std::collections::{BTreeMap, BTreeSet, HashSet}; use std::panic; // TODO Do something else. @@ -849,32 +849,8 @@ impl Sim { .handle_live_edited_traffic_signals(self.time, map, &mut self.scheduler) } - pub fn handle_live_edited_lanes(&mut self, map: &Map) { - // TODO Handle changes to access restrictions - - // Find every active trip whose path crosses a modified lane or closed intersection - let (edited_lanes, _) = map.get_edits().changed_lanes(map); - let mut closed_intersections = HashSet::new(); - for i in map.get_edits().original_intersections.keys() { - if map.get_i(*i).is_closed() { - closed_intersections.insert(*i); - } - } - let mut affected = Vec::new(); - for (a, trip) in self.trips.active_agents_and_trips() { - if let Some(path) = self.get_path(*a) { - if path - .get_steps() - .iter() - .any(|step| match step.as_traversable() { - Traversable::Lane(l) => edited_lanes.contains(&l), - Traversable::Turn(t) => closed_intersections.contains(&t.parent), - }) - { - affected.push((*a, *trip)); - } - } - } + pub fn handle_live_edits(&mut self, map: &Map) { + let affected = self.find_trips_affected_by_live_edits(map); // V1: Just abort every trip crossing an affected area. // (V2 is probably rerouting everyone, only aborting when that fails) @@ -902,12 +878,48 @@ impl Sim { } } - pub fn handle_live_edited_parking(&mut self, map: &Map) { - self.walking.handle_live_edited_parking( - self.parking - .handle_map_updates(map, &mut Timer::throwaway()), - &mut self.scheduler, - ); + fn find_trips_affected_by_live_edits(&mut self, map: &Map) -> Vec<(AgentID, TripID)> { + let mut affected: Vec<(AgentID, TripID)> = Vec::new(); + + // TODO Handle changes to access restrictions + + { + // Find every active trip whose path crosses a modified lane or closed intersection + let (edited_lanes, _) = map.get_edits().changed_lanes(map); + let mut closed_intersections = HashSet::new(); + for i in map.get_edits().original_intersections.keys() { + if map.get_i(*i).is_closed() { + closed_intersections.insert(*i); + } + } + for (a, trip) in self.trips.active_agents_and_trips() { + if let Some(path) = self.get_path(*a) { + if path + .get_steps() + .iter() + .any(|step| match step.as_traversable() { + Traversable::Lane(l) => edited_lanes.contains(&l), + Traversable::Turn(t) => closed_intersections.contains(&t.parent), + }) + { + affected.push((*a, *trip)); + } + } + } + } + + { + let evicted_cars = self.parking.handle_live_edits(map, &mut Timer::throwaway()); + affected.extend(self.walking.find_trips_to_parking(evicted_cars)); + + let (filled, avail) = self.parking.get_all_parking_spots(); + let mut all_spots: BTreeSet = BTreeSet::new(); + all_spots.extend(filled); + all_spots.extend(avail); + affected.extend(self.driving.find_trips_to_edited_parking(all_spots)); + } + + affected } }