spawn a specific number of parked cars per bldg for a scenario. dont use

them yet.
This commit is contained in:
Dustin Carlino 2019-09-05 09:45:02 -07:00
parent c267b27fa0
commit 048976a256
8 changed files with 109 additions and 19 deletions

View File

@ -295,6 +295,7 @@ impl<'a> Timer<'a> {
}
}
// The order of the result is deterministic / matches the input.
pub fn parallelize<I, O, F: Fn(I) -> O>(
&mut self,
timer_name: &str,

View File

@ -12,6 +12,7 @@ use ezgui::{hotkey, EventCtx, GfxCtx, Key, ModalMenu, Wizard, WrappedWizard};
use geom::Duration;
use popdat::trips_to_scenario;
use sim::Scenario;
use std::collections::BTreeMap;
pub struct MissionEditMode {
menu: ModalMenu,
@ -137,6 +138,7 @@ fn create_new_scenario(wiz: &mut Wizard, ctx: &mut EventCtx, ui: &mut UI) -> Opt
spawn_over_time: Vec::new(),
border_spawn_over_time: Vec::new(),
individ_trips: Vec::new(),
individ_parked_cars: BTreeMap::new(),
},
ctx,
ui,

View File

@ -107,8 +107,8 @@ impl ScenarioManager {
}
}
let (filled_spots, total_parking_spots) = ui.primary.sim.get_total_parking_spots();
assert_eq!(filled_spots, 0);
let (filled_spots, free_parking_spots) = ui.primary.sim.get_all_parking_spots();
assert!(filled_spots.is_empty());
ScenarioManager {
menu: ModalMenu::new(
@ -135,7 +135,7 @@ impl ScenarioManager {
trips_to_bldg,
cars_needed_per_bldg,
total_cars_needed,
total_parking_spots,
total_parking_spots: free_parking_spots.len(),
override_colors,
}
}

View File

@ -32,7 +32,7 @@ pub struct Parcel {
pub offstreet_parking_spaces: usize,
}
#[derive(Serialize, Deserialize, Debug, Clone, Copy)]
#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq)]
pub enum Mode {
Walk,
Bike,

View File

@ -4,9 +4,9 @@ use abstutil::Timer;
use geom::{Distance, Duration, LonLat, PolyLine, Polygon, Pt2D};
use map_model::{BuildingID, IntersectionID, LaneType, Map, PathRequest, Position};
use sim::{DrivingGoal, Scenario, SidewalkSpot, SpawnTrip, TripSpec};
use std::collections::HashMap;
use std::collections::{BTreeMap, HashMap};
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct Trip {
pub from: TripEndpt,
pub to: TripEndpt,
@ -20,7 +20,7 @@ pub struct Trip {
pub route: Option<PolyLine>,
}
#[derive(Debug)]
#[derive(Clone, Debug)]
pub enum TripEndpt {
Building(BuildingID),
// The Pt2D is the original point. It'll be outside the map and likely out-of-bounds entirely,
@ -259,8 +259,9 @@ pub fn clip_trips(map: &Map, timer: &mut Timer) -> (Vec<Trip>, HashMap<BuildingI
pub fn trips_to_scenario(map: &Map, t1: Duration, t2: Duration, timer: &mut Timer) -> Scenario {
let (trips, _) = clip_trips(map, timer);
// TODO Don't clone trips for parallelize
let individ_trips = timer
.parallelize("turn PSRC trips into SpawnTrips", trips, |trip| {
.parallelize("turn PSRC trips into SpawnTrips", trips.clone(), |trip| {
if trip.depart_at < t1 || trip.depart_at > t2 {
return None;
}
@ -343,6 +344,29 @@ pub fn trips_to_scenario(map: &Map, t1: Duration, t2: Duration, timer: &mut Time
.flatten()
.collect();
// This is another variation of the 'recycle' algorithm in editor's ScenarioManager.
let mut individ_parked_cars = BTreeMap::new();
let mut avail_per_bldg = BTreeMap::new();
for b in map.all_buildings() {
individ_parked_cars.insert(b.id, 0);
avail_per_bldg.insert(b.id, 0);
}
for trip in trips {
if trip.depart_at < t1 || trip.depart_at > t2 || trip.mode != Mode::Drive {
continue;
}
if let TripEndpt::Building(b) = trip.from {
if avail_per_bldg[&b] > 0 {
*avail_per_bldg.get_mut(&b).unwrap() -= 1;
} else {
*individ_parked_cars.get_mut(&b).unwrap() += 1;
}
}
if let TripEndpt::Building(b) = trip.to {
*avail_per_bldg.get_mut(&b).unwrap() += 1;
}
}
Scenario {
scenario_name: format!("psrc {} to {}", t1, t2),
map_name: map.get_name().to_string(),
@ -350,5 +374,6 @@ pub fn trips_to_scenario(map: &Map, t1: Duration, t2: Duration, timer: &mut Time
spawn_over_time: Vec::new(),
border_spawn_over_time: Vec::new(),
individ_trips,
individ_parked_cars,
}
}

View File

@ -13,17 +13,21 @@ use rand::seq::SliceRandom;
use rand::Rng;
use rand_xorshift::XorShiftRng;
use serde_derive::{Deserialize, Serialize};
use std::collections::{BTreeSet, HashMap, HashSet, VecDeque};
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque};
#[derive(Clone, Serialize, Deserialize, Debug)]
pub struct Scenario {
pub scenario_name: String,
pub map_name: String,
// Higher-level ways of specifying stuff
pub seed_parked_cars: Vec<SeedParkedCars>,
pub spawn_over_time: Vec<SpawnOverTime>,
pub border_spawn_over_time: Vec<BorderSpawnOverTime>,
// Much more detailed
pub individ_trips: Vec<SpawnTrip>,
pub individ_parked_cars: BTreeMap<BuildingID, usize>,
}
// SpawnOverTime and BorderSpawnOverTime should be kept separate. Agents in SpawnOverTime pick
@ -78,6 +82,10 @@ impl Scenario {
prettyprint_usize(self.border_spawn_over_time.len())
),
format!("{} SpawnTrip", prettyprint_usize(self.individ_trips.len())),
format!(
"{} specific parked cars at buildings",
prettyprint_usize(self.individ_parked_cars.len())
),
]
}
@ -134,6 +142,15 @@ impl Scenario {
s.spawn_bikes(rng, sim, &neighborhoods, map, timer);
}
let mut individ_parked_cars: Vec<(BuildingID, usize)> = Vec::new();
for (b, cnt) in &self.individ_parked_cars {
if *cnt != 0 {
individ_parked_cars.push((*b, *cnt));
}
}
individ_parked_cars.shuffle(rng);
seed_individ_parked_cars(individ_parked_cars, sim, map, rng, timer);
timer.start_iter("SpawnTrip", self.individ_trips.len());
for t in &self.individ_trips {
match t.clone() {
@ -249,6 +266,7 @@ impl Scenario {
})
.collect(),
individ_trips: Vec::new(),
individ_parked_cars: BTreeMap::new(),
};
for i in map.all_outgoing_borders() {
s.spawn_over_time.push(SpawnOverTime {
@ -273,6 +291,7 @@ impl Scenario {
spawn_over_time: Vec::new(),
border_spawn_over_time: Vec::new(),
individ_trips: Vec::new(),
individ_parked_cars: BTreeMap::new(),
}
}
@ -298,6 +317,7 @@ impl Scenario {
}],
border_spawn_over_time: Vec::new(),
individ_trips: Vec::new(),
individ_parked_cars: BTreeMap::new(),
}
}
@ -773,6 +793,47 @@ fn seed_parked_cars(
));
}
fn seed_individ_parked_cars(
individ_parked_cars: Vec<(BuildingID, usize)>,
sim: &mut Sim,
map: &Map,
base_rng: &mut XorShiftRng,
timer: &mut Timer,
) {
let mut open_spots_per_road: HashMap<RoadID, Vec<ParkingSpot>> = HashMap::new();
for spot in sim.get_all_parking_spots().1 {
let r = match spot {
ParkingSpot::Onstreet(l, _) => map.get_l(l).parent,
ParkingSpot::Offstreet(b, _) => map.get_l(map.get_b(b).sidewalk()).parent,
};
open_spots_per_road
.entry(r)
.or_insert_with(Vec::new)
.push(spot);
}
let all_roads = map
.all_roads()
.iter()
.map(|r| r.id)
.collect::<BTreeSet<_>>();
timer.start_iter("seed individual parked cars", individ_parked_cars.len());
for (b, cnt) in individ_parked_cars {
timer.next();
for _ in 0..cnt {
// TODO Fork?
if let Some(spot) =
find_spot_near_building(b, &mut open_spots_per_road, &all_roads, map, timer)
{
sim.seed_parked_car(Scenario::rand_car(base_rng), spot, Some(b));
} else {
// TODO Guard against this outright just by total counts.
panic!("No room to seed individual parked cars.");
}
}
}
}
// Pick a parking spot for this building. If the building's road has a free spot, use it. If not,
// start BFSing out from the road in a deterministic way until finding a nearby road with an open
// spot.

View File

@ -292,24 +292,25 @@ impl ParkingSimState {
}
// (Filled, available)
pub fn get_total_parking_spots(&self) -> (usize, usize) {
let mut filled = 0;
let mut available = 0;
pub fn get_all_parking_spots(&self) -> (Vec<ParkingSpot>, Vec<ParkingSpot>) {
let mut filled = Vec::new();
let mut available = Vec::new();
for lane in self.onstreet_lanes.values() {
for spot in lane.spots() {
if self.is_free(spot) {
available += 1;
available.push(spot);
} else {
filled += 1;
filled.push(spot);
}
}
}
for (b, idx) in &self.num_spots_per_offstreet {
if self.is_free(ParkingSpot::Offstreet(*b, *idx)) {
available += 1;
let spot = ParkingSpot::Offstreet(*b, *idx);
if self.is_free(spot) {
available.push(spot);
} else {
filled += 1;
filled.push(spot);
}
}

View File

@ -171,8 +171,8 @@ impl Sim {
}
// (Filled, available)
pub fn get_total_parking_spots(&self) -> (usize, usize) {
self.parking.get_total_parking_spots()
pub fn get_all_parking_spots(&self) -> (Vec<ParkingSpot>, Vec<ParkingSpot>) {
self.parking.get_all_parking_spots()
}
pub fn seed_parked_car(