diff --git a/docs/design/sim.md b/docs/design/sim.md index 75e7747db1..e5fd6d8100 100644 --- a/docs/design/sim.md +++ b/docs/design/sim.md @@ -167,6 +167,14 @@ Next thoughts: - try to be close to building, random jitter to be a little far away - if this process is somewhat stable, then should be fine. doesnt need to be perfectly stable -- removing lanes somewhere might put more pressure on another lane. + +steps for this change: += give cars an optional building as an owner, make a query for parking sim to find available cars, hook up UI debug + = initially randomly assign a building in the neighborhood +- start seeding parked cars per building instead of per spot + - make sure stability is vaguely preserved +- make peds that'll use a car pick from a house with an available car + ## Traces between worlds Alright, now how do we even compare trip progress to show it visually? This is diff --git a/editor/src/objects.rs b/editor/src/objects.rs index 2ced1294f5..d0a5648379 100644 --- a/editor/src/objects.rs +++ b/editor/src/objects.rs @@ -43,6 +43,13 @@ impl ID { ID::Turn(_) => {} ID::Building(id) => { map.get_b(id).dump_debug(); + let parked_cars = sim.get_parked_cars_by_owner(id); + println!( + "{} parked cars are owned by {}: {:?}", + parked_cars.len(), + id, + parked_cars.iter().map(|p| p.car).collect::>() + ); } ID::Car(id) => { sim.debug_car(id); diff --git a/sim/src/driving.rs b/sim/src/driving.rs index d3813abdc2..ca8ea2e24e 100644 --- a/sim/src/driving.rs +++ b/sim/src/driving.rs @@ -5,7 +5,7 @@ use geom::EPSILON_DIST; use intersections::{IntersectionSimState, Request}; use kinematics; use kinematics::Vehicle; -use map_model::{LaneID, Map, Trace, Traversable, TurnID, LANE_THICKNESS}; +use map_model::{BuildingID, LaneID, Map, Trace, Traversable, TurnID, LANE_THICKNESS}; use multimap::MultiMap; use ordered_float::NotNaN; use parking::ParkingSimState; @@ -38,6 +38,7 @@ struct Car { id: CarID, // None for buses trip: Option, + owner: Option, on: Traversable, speed: Speed, dist_along: Distance, @@ -492,7 +493,7 @@ impl DrivingSimState { pub fn tooltip_lines(&self, id: CarID) -> Option> { if let Some(c) = self.cars.get(&id) { Some(vec![ - format!("Car {:?}, part of {:?}", id, c.trip), + format!("Car {:?}, part of {:?}, owned by {:?}", id, c.trip, c.owner), format!( "On {:?}, speed {:?}, dist along {:?}", c.on, c.speed, c.dist_along @@ -591,7 +592,7 @@ impl DrivingSimState { c.parking = Some(ParkingState { is_parking: true, started_at: time, - tuple: ParkedCar::new(*id, *spot, c.vehicle.clone()), + tuple: ParkedCar::new(*id, *spot, c.vehicle.clone(), c.owner), }); } Action::WorkOnParking => { @@ -677,29 +678,23 @@ impl DrivingSimState { &mut self, events: &mut Vec, time: Tick, - car: CarID, - trip: Option, - maybe_parked_car: Option, - vehicle: Vehicle, - dist_along: Distance, - start: LaneID, - router: Router, map: &Map, + params: CreateCar, ) -> bool { // If not, we have a parking lane much longer than a driving lane... - assert!(dist_along <= map.get_l(start).length()); + assert!(params.dist_along <= map.get_l(params.start).length()); // Is it safe to enter the lane right now? Start scanning ahead of where we'll enter, so we // don't hit somebody's back - if let Some(other) = - self.lanes[start.0].first_car_behind(dist_along + Vehicle::worst_case_following_dist()) + if let Some(other) = self.lanes[params.start.0] + .first_car_behind(params.dist_along + Vehicle::worst_case_following_dist()) { let other_dist = self.cars[&other].dist_along; - if other_dist >= dist_along { + if other_dist >= params.dist_along { debug!( "{} can't spawn, because they'd wind up too close ({}) behind {}", - car, - other_dist - dist_along, + params.car, + other_dist - params.dist_along, other ); return false; @@ -709,13 +704,13 @@ impl DrivingSimState { let accel_for_other_to_stop = other_vehicle .accel_to_follow( self.cars[&other].speed, - map.get_parent(start).get_speed_limit(), - &vehicle, - dist_along - other_dist, + map.get_parent(params.start).get_speed_limit(), + ¶ms.vehicle, + params.dist_along - other_dist, 0.0 * si::MPS, ).unwrap(); if accel_for_other_to_stop <= other_vehicle.max_deaccel { - debug!("{} can't spawn {} in front of {}, because {} would have to do {} to not hit {}", car, dist_along - other_dist, other, other, accel_for_other_to_stop, car); + debug!("{} can't spawn {} in front of {}, because {} would have to do {} to not hit {}", params.car, params.dist_along - other_dist, other, other, accel_for_other_to_stop, params.car); return false; } @@ -725,18 +720,19 @@ impl DrivingSimState { } self.cars.insert( - car, + params.car, Car { - id: car, - trip, - dist_along: dist_along, + id: params.car, + trip: params.trip, + owner: params.owner, + on: Traversable::Lane(params.start), + dist_along: params.dist_along, speed: 0.0 * si::MPS, - on: Traversable::Lane(start), - vehicle, + vehicle: params.vehicle, waiting_for: None, debug: false, - is_bus: !maybe_parked_car.is_some(), - parking: maybe_parked_car.and_then(|parked_car| { + is_bus: !params.maybe_parked_car.is_some(), + parking: params.maybe_parked_car.and_then(|parked_car| { Some(ParkingState { is_parking: false, started_at: time, @@ -745,11 +741,11 @@ impl DrivingSimState { }), }, ); - self.routers.insert(car, router); - self.lanes[start.0].insert_at(car, dist_along); + self.routers.insert(params.car, params.router); + self.lanes[params.start.0].insert_at(params.car, params.dist_along); events.push(Event::AgentEntersTraversable( - AgentID::Car(car), - Traversable::Lane(start), + AgentID::Car(params.car), + Traversable::Lane(params.start), )); true } @@ -823,3 +819,14 @@ impl DrivingSimState { Some(r.trace_route(c.on, c.dist_along, map, dist_ahead)) } } + +pub struct CreateCar { + pub car: CarID, + pub trip: Option, + pub owner: Option, + pub maybe_parked_car: Option, + pub vehicle: Vehicle, + pub start: LaneID, + pub dist_along: Distance, + pub router: Router, +} diff --git a/sim/src/helpers.rs b/sim/src/helpers.rs index ce2cd3da1b..33d1c2f4d0 100644 --- a/sim/src/helpers.rs +++ b/sim/src/helpers.rs @@ -143,7 +143,11 @@ impl Sim { // Spawning helpers impl Sim { pub fn small_spawn(&mut self, map: &Map) { - self.seed_parked_cars(map.all_lanes().iter().map(|l| l.id).collect(), 0.5); + self.seed_parked_cars( + map.all_lanes().iter().map(|l| l.id).collect(), + &map.all_buildings().iter().map(|b| b.id).collect(), + 0.5, + ); self.seed_walking_trips(&map, 100); self.seed_driving_trips(&map, 100); @@ -162,14 +166,28 @@ impl Sim { );*/ } pub fn big_spawn(&mut self, map: &Map) { - self.seed_parked_cars(map.all_lanes().iter().map(|l| l.id).collect(), 0.95); + self.seed_parked_cars( + map.all_lanes().iter().map(|l| l.id).collect(), + &map.all_buildings().iter().map(|b| b.id).collect(), + 0.95, + ); self.seed_walking_trips(&map, 1000); self.seed_driving_trips(&map, 1000); } - pub fn seed_parked_cars(&mut self, in_lanes: Vec, percent: f64) { - self.spawner - .seed_parked_cars(percent, in_lanes, &mut self.parking_state, &mut self.rng); + pub fn seed_parked_cars( + &mut self, + in_lanes: Vec, + owner_buildins: &Vec, + percent: f64, + ) { + self.spawner.seed_parked_cars( + percent, + in_lanes, + owner_buildins, + &mut self.parking_state, + &mut self.rng, + ); } pub fn seed_bus_route(&mut self, route: &BusRoute, map: &Map) -> Vec { @@ -186,9 +204,19 @@ impl Sim { ) } - pub fn seed_specific_parked_cars(&mut self, lane: LaneID, spots: Vec) -> Vec { - self.spawner - .seed_specific_parked_cars(lane, spots, &mut self.parking_state, &mut self.rng) + pub fn seed_specific_parked_cars( + &mut self, + lane: LaneID, + owner: BuildingID, + spots: Vec, + ) -> Vec { + self.spawner.seed_specific_parked_cars( + lane, + owner, + spots, + &mut self.parking_state, + &mut self.rng, + ) } pub fn seed_driving_trips(&mut self, map: &Map, num_cars: usize) { diff --git a/sim/src/lib.rs b/sim/src/lib.rs index 06813a15c9..c0048bf317 100644 --- a/sim/src/lib.rs +++ b/sim/src/lib.rs @@ -58,7 +58,7 @@ pub use events::Event; use geom::{Angle, Pt2D}; pub use helpers::{load, SimFlags}; pub use instrument::save_backtraces; -use map_model::{LaneID, Trace, TurnID}; +use map_model::{BuildingID, LaneID, Trace, TurnID}; use rand::{RngCore, SeedableRng, XorShiftRng}; pub use scenario::{Neighborhood, Scenario, SeedParkedCars, SpawnOverTime}; pub use sim::{Benchmark, Sim}; @@ -293,11 +293,22 @@ pub struct ParkedCar { pub car: CarID, pub spot: ParkingSpot, pub vehicle: kinematics::Vehicle, + pub owner: Option, } impl ParkedCar { - pub fn new(car: CarID, spot: ParkingSpot, vehicle: kinematics::Vehicle) -> ParkedCar { - ParkedCar { car, spot, vehicle } + pub fn new( + car: CarID, + spot: ParkingSpot, + vehicle: kinematics::Vehicle, + owner: Option, + ) -> ParkedCar { + ParkedCar { + car, + spot, + vehicle, + owner, + } } } diff --git a/sim/src/parking.rs b/sim/src/parking.rs index 0976f5feb8..ea388a1b8e 100644 --- a/sim/src/parking.rs +++ b/sim/src/parking.rs @@ -1,7 +1,7 @@ use geom::{Angle, Polygon, Pt2D}; use kinematics::Vehicle; use map_model; -use map_model::{Lane, LaneID, LaneType, Map}; +use map_model::{BuildingID, Lane, LaneID, LaneType, Map}; use std::iter; use {CarID, Distance, DrawCarInput, ParkedCar, ParkingSpot}; @@ -138,6 +138,25 @@ impl ParkingSimState { fn get_spot(&self, spot: ParkingSpot) -> &ParkingSpotGeometry { &self.lanes[spot.lane.0].spots[spot.idx] } + + pub fn tooltip_lines(&self, id: CarID) -> Vec { + let c = self.lookup_car(id).unwrap(); + vec![format!("{} is parked, owned by {:?}", c.car, c.owner)] + } + + pub fn get_parked_cars_by_owner(&self, id: BuildingID) -> Vec<&ParkedCar> { + let mut result: Vec<&ParkedCar> = Vec::new(); + for l in &self.lanes { + for maybe_occupant in &l.occupants { + if let Some(o) = maybe_occupant { + if o.owner == Some(id) { + result.push(maybe_occupant.as_ref().unwrap()); + } + } + } + } + result + } } #[derive(Serialize, Deserialize)] diff --git a/sim/src/scenario.rs b/sim/src/scenario.rs index 53ec631522..53d63b30db 100644 --- a/sim/src/scenario.rs +++ b/sim/src/scenario.rs @@ -97,6 +97,7 @@ impl Scenario { for s in &self.seed_parked_cars { sim.seed_parked_cars( neighborhoods[&s.neighborhood].find_matching_lanes(map), + &bldgs_per_neighborhood[&s.neighborhood], s.percent_to_fill, ); } diff --git a/sim/src/sim.rs b/sim/src/sim.rs index ad6f15bfa8..1c8e0b1a05 100644 --- a/sim/src/sim.rs +++ b/sim/src/sim.rs @@ -8,7 +8,7 @@ use driving::DrivingSimState; use geom::Pt2D; use instrument::capture_backtrace; use intersections::IntersectionSimState; -use map_model::{IntersectionID, LaneID, LaneType, Map, Trace, Turn, TurnID}; +use map_model::{BuildingID, IntersectionID, LaneID, LaneType, Map, Trace, Turn, TurnID}; use parking::ParkingSimState; use rand::{FromEntropy, SeedableRng, XorShiftRng}; use spawn::Spawner; @@ -21,8 +21,8 @@ use trips::TripManager; use view::WorldView; use walking::WalkingSimState; use { - AgentID, CarID, CarState, Distance, DrawCarInput, DrawPedestrianInput, Event, PedestrianID, - ScoreSummary, Tick, TripID, TIMESTEP, + AgentID, CarID, CarState, Distance, DrawCarInput, DrawPedestrianInput, Event, ParkedCar, + PedestrianID, ScoreSummary, Tick, TripID, TIMESTEP, }; #[derive(Serialize, Deserialize, Derivative)] @@ -280,7 +280,7 @@ impl Sim { pub fn car_tooltip(&self, car: CarID) -> Vec { self.driving_state .tooltip_lines(car) - .unwrap_or(vec![format!("{} is parked", car)]) + .unwrap_or(self.parking_state.tooltip_lines(car)) } pub fn debug_car(&mut self, id: CarID) { @@ -395,6 +395,10 @@ impl Sim { None => None, } } + + pub fn get_parked_cars_by_owner(&self, id: BuildingID) -> Vec<&ParkedCar> { + self.parking_state.get_parked_cars_by_owner(id) + } } pub struct Benchmark { diff --git a/sim/src/spawn.rs b/sim/src/spawn.rs index 69bf9e7dd0..97964cc80d 100644 --- a/sim/src/spawn.rs +++ b/sim/src/spawn.rs @@ -1,5 +1,5 @@ use abstutil::elapsed_seconds; -use driving::DrivingSimState; +use driving::{CreateCar, DrivingSimState}; use kinematics::Vehicle; use map_model::{BuildingID, BusRoute, BusStopID, LaneID, Map, Pathfinder}; use parking::ParkingSimState; @@ -117,14 +117,17 @@ impl Spawner { if driving_sim.start_car_on_lane( events, now, - car, - Some(trip), - Some(parked_car.clone()), - parked_car.vehicle.clone(), - dist_along, - start, - Router::make_router_to_park(path, goal_bldg), map, + CreateCar { + car, + trip: Some(trip), + owner: parked_car.owner, + maybe_parked_car: Some(parked_car.clone()), + vehicle: parked_car.vehicle.clone(), + start, + dist_along, + router: Router::make_router_to_park(path, goal_bldg), + }, ) { trips.agent_starting_trip_leg(AgentID::Car(car), trip); parking_sim.remove_parked_car(parked_car.clone()); @@ -178,14 +181,17 @@ impl Spawner { if driving_sim.start_car_on_lane( events, now, - id, - None, - None, - vehicle, - start_dist_along, - start, - Router::make_router_for_bus(path), map, + CreateCar { + car: id, + trip: None, + owner: None, + maybe_parked_car: None, + vehicle, + start, + dist_along: start_dist_along, + router: Router::make_router_for_bus(path), + }, ) { transit_sim.bus_created(id, route_id, next_stop_idx); info!("Spawned bus {} for route {} ({})", id, route.name, route_id); @@ -205,6 +211,7 @@ impl Spawner { &mut self, percent_capacity_to_fill: f64, in_lanes: Vec, + owner_buildings: &Vec, parking_sim: &mut ParkingSimState, base_rng: &mut XorShiftRng, ) { @@ -228,6 +235,7 @@ impl Spawner { car, spot, Vehicle::generate_typical_car(car, &mut rng), + Some(*rng.choose(owner_buildings).unwrap()), )); self.car_id_counter += 1; } @@ -242,6 +250,7 @@ impl Spawner { pub fn seed_specific_parked_cars( &mut self, lane: LaneID, + owner: BuildingID, spot_indices: Vec, parking_sim: &mut ParkingSimState, rng: &mut XorShiftRng, @@ -255,6 +264,7 @@ impl Spawner { car, spots[idx], Vehicle::generate_typical_car(car, rng), + Some(owner), )); self.car_id_counter += 1; car