make TripSpawner a temporary setup object, not something permanently stored in Sim

This commit is contained in:
Dustin Carlino 2020-03-12 15:00:50 -07:00
parent f20b7912eb
commit d852d69535
4 changed files with 152 additions and 100 deletions

View File

@ -20,7 +20,8 @@ use rand::seq::SliceRandom;
use rand::Rng; use rand::Rng;
use rand_xorshift::XorShiftRng; use rand_xorshift::XorShiftRng;
use sim::{ use sim::{
BorderSpawnOverTime, DrivingGoal, OriginDestination, Scenario, SidewalkSpot, Sim, TripSpec, BorderSpawnOverTime, DrivingGoal, OriginDestination, Scenario, SidewalkSpot, Sim, TripSpawner,
TripSpec,
}; };
const SMALL_DT: Duration = Duration::const_seconds(0.1); const SMALL_DT: Duration = Duration::const_seconds(0.1);
@ -270,14 +271,16 @@ impl State for AgentSpawner {
if self.maybe_goal.is_some() && app.per_obj.left_click(ctx, "end the agent here") { if self.maybe_goal.is_some() && app.per_obj.left_click(ctx, "end the agent here") {
let mut rng = app.primary.current_flags.sim_flags.make_rng(); let mut rng = app.primary.current_flags.sim_flags.make_rng();
let sim = &mut app.primary.sim; let sim = &mut app.primary.sim;
let mut spawner = sim.make_spawner();
let err = schedule_trip( let err = schedule_trip(
&self.from, &self.from,
self.maybe_goal.take().unwrap().0, self.maybe_goal.take().unwrap().0,
map, map,
sim, sim,
&mut spawner,
&mut rng, &mut rng,
); );
sim.spawn_all_trips(map, &mut Timer::new("spawn trip"), false); sim.flush_spawner(spawner, map, &mut Timer::new("spawn trip"), false);
sim.normal_step(map, SMALL_DT); sim.normal_step(map, SMALL_DT);
app.recalculate_current_selection(ctx); app.recalculate_current_selection(ctx);
if let Some(e) = err { if let Some(e) = err {
@ -309,6 +312,7 @@ pub fn spawn_agents_around(i: IntersectionID, app: &mut App) {
let map = &app.primary.map; let map = &app.primary.map;
let sim = &mut app.primary.sim; let sim = &mut app.primary.sim;
let mut rng = app.primary.current_flags.sim_flags.make_rng(); let mut rng = app.primary.current_flags.sim_flags.make_rng();
let mut spawner = sim.make_spawner();
if map.all_buildings().is_empty() { if map.all_buildings().is_empty() {
println!("No buildings, can't pick destinations"); println!("No buildings, can't pick destinations");
@ -332,7 +336,7 @@ pub fn spawn_agents_around(i: IntersectionID, app: &mut App) {
if vehicle_spec.length > lane.length() { if vehicle_spec.length > lane.length() {
continue; continue;
} }
sim.schedule_trip( spawner.schedule_trip(
sim.time(), sim.time(),
TripSpec::CarAppearing { TripSpec::CarAppearing {
start_pos: Position::new( start_pos: Position::new(
@ -346,11 +350,12 @@ pub fn spawn_agents_around(i: IntersectionID, app: &mut App) {
ped_speed: Scenario::rand_ped_speed(&mut rng), ped_speed: Scenario::rand_ped_speed(&mut rng),
}, },
map, map,
sim,
); );
} }
} else if lane.is_sidewalk() { } else if lane.is_sidewalk() {
for _ in 0..5 { for _ in 0..5 {
sim.schedule_trip( spawner.schedule_trip(
sim.time(), sim.time(),
TripSpec::JustWalking { TripSpec::JustWalking {
start: SidewalkSpot::suddenly_appear( start: SidewalkSpot::suddenly_appear(
@ -365,12 +370,13 @@ pub fn spawn_agents_around(i: IntersectionID, app: &mut App) {
ped_speed: Scenario::rand_ped_speed(&mut rng), ped_speed: Scenario::rand_ped_speed(&mut rng),
}, },
map, map,
sim,
); );
} }
} }
} }
sim.spawn_all_trips(map, &mut timer, false); sim.flush_spawner(spawner, map, &mut timer, false);
sim.normal_step(map, SMALL_DT); sim.normal_step(map, SMALL_DT);
} }
@ -379,7 +385,8 @@ fn schedule_trip(
src: &Source, src: &Source,
raw_goal: Goal, raw_goal: Goal,
map: &Map, map: &Map,
sim: &mut Sim, sim: &Sim,
spawner: &mut TripSpawner,
rng: &mut XorShiftRng, rng: &mut XorShiftRng,
) -> Option<String> { ) -> Option<String> {
match src { match src {
@ -406,7 +413,7 @@ fn schedule_trip(
map.should_use_transit(start.sidewalk_pos, goal.sidewalk_pos) map.should_use_transit(start.sidewalk_pos, goal.sidewalk_pos)
{ {
println!("Using {} from {} to {}", route, stop1, stop2); println!("Using {} from {} to {}", route, stop1, stop2);
sim.schedule_trip( spawner.schedule_trip(
sim.time(), sim.time(),
TripSpec::UsingTransit { TripSpec::UsingTransit {
start, start,
@ -417,10 +424,11 @@ fn schedule_trip(
ped_speed, ped_speed,
}, },
map, map,
sim,
); );
} else { } else {
println!("Not using transit"); println!("Not using transit");
sim.schedule_trip( spawner.schedule_trip(
sim.time(), sim.time(),
TripSpec::JustWalking { TripSpec::JustWalking {
start, start,
@ -428,6 +436,7 @@ fn schedule_trip(
ped_speed, ped_speed,
}, },
map, map,
sim,
); );
} }
} }
@ -446,7 +455,7 @@ fn schedule_trip(
} }
} }
}; };
sim.schedule_trip( spawner.schedule_trip(
sim.time(), sim.time(),
TripSpec::UsingBike { TripSpec::UsingBike {
start: SidewalkSpot::building(*b, map), start: SidewalkSpot::building(*b, map),
@ -455,6 +464,7 @@ fn schedule_trip(
ped_speed: Scenario::rand_ped_speed(rng), ped_speed: Scenario::rand_ped_speed(rng),
}, },
map, map,
sim,
); );
} }
_ => { _ => {
@ -476,7 +486,7 @@ fn schedule_trip(
match src { match src {
Source::Drive(from) => { Source::Drive(from) => {
if let Some(start_pos) = TripSpec::spawn_car_at(*from, map) { if let Some(start_pos) = TripSpec::spawn_car_at(*from, map) {
sim.schedule_trip( spawner.schedule_trip(
sim.time(), sim.time(),
TripSpec::CarAppearing { TripSpec::CarAppearing {
start_pos, start_pos,
@ -485,13 +495,14 @@ fn schedule_trip(
ped_speed: Scenario::rand_ped_speed(rng), ped_speed: Scenario::rand_ped_speed(rng),
}, },
map, map,
sim,
); );
} else { } else {
return Some(format!("Can't make a car appear at {:?}", from)); return Some(format!("Can't make a car appear at {:?}", from));
} }
} }
Source::WalkFromBldgThenMaybeUseCar(b) => { Source::WalkFromBldgThenMaybeUseCar(b) => {
sim.schedule_trip( spawner.schedule_trip(
sim.time(), sim.time(),
TripSpec::MaybeUsingParkedCar { TripSpec::MaybeUsingParkedCar {
start_bldg: *b, start_bldg: *b,
@ -499,6 +510,7 @@ fn schedule_trip(
ped_speed: Scenario::rand_ped_speed(rng), ped_speed: Scenario::rand_ped_speed(rng),
}, },
map, map,
sim,
); );
} }
_ => unreachable!(), _ => unreachable!(),

View File

@ -1,3 +1,4 @@
use crate::make::TripSpawner;
use crate::{ use crate::{
CarID, DrivingGoal, ParkingSpot, PersonID, SidewalkSpot, Sim, TripSpec, VehicleSpec, CarID, DrivingGoal, ParkingSpot, PersonID, SidewalkSpot, Sim, TripSpec, VehicleSpec,
VehicleType, BIKE_LENGTH, MAX_CAR_LENGTH, MIN_CAR_LENGTH, VehicleType, BIKE_LENGTH, MAX_CAR_LENGTH, MIN_CAR_LENGTH,
@ -104,6 +105,8 @@ impl Scenario {
); );
} }
let mut spawner = sim.make_spawner();
// Don't let two pedestrians starting from one building use the same car. // Don't let two pedestrians starting from one building use the same car.
let mut reserved_cars: HashSet<CarID> = HashSet::new(); let mut reserved_cars: HashSet<CarID> = HashSet::new();
@ -115,16 +118,24 @@ impl Scenario {
timer.start_iter("SpawnOverTime each agent", s.num_agents); timer.start_iter("SpawnOverTime each agent", s.num_agents);
for _ in 0..s.num_agents { for _ in 0..s.num_agents {
timer.next(); timer.next();
s.spawn_agent(rng, sim, &mut reserved_cars, &neighborhoods, map, timer); s.spawn_agent(
rng,
sim,
&mut spawner,
&mut reserved_cars,
&neighborhoods,
map,
timer,
);
} }
} }
timer.start_iter("BorderSpawnOverTime", self.border_spawn_over_time.len()); timer.start_iter("BorderSpawnOverTime", self.border_spawn_over_time.len());
for s in &self.border_spawn_over_time { for s in &self.border_spawn_over_time {
timer.next(); timer.next();
s.spawn_peds(rng, sim, &neighborhoods, map, timer); s.spawn_peds(rng, &mut spawner, &neighborhoods, map, sim, timer);
s.spawn_cars(rng, sim, &neighborhoods, map, timer); s.spawn_cars(rng, &mut spawner, &neighborhoods, map, sim, timer);
s.spawn_bikes(rng, sim, &neighborhoods, map, timer); s.spawn_bikes(rng, &mut spawner, &neighborhoods, map, sim, timer);
} }
let mut individ_parked_cars: Vec<(BuildingID, usize)> = Vec::new(); let mut individ_parked_cars: Vec<(BuildingID, usize)> = Vec::new();
@ -140,10 +151,10 @@ impl Scenario {
for t in &self.population.individ_trips { for t in &self.population.individ_trips {
timer.next(); timer.next();
let spec = t.trip.clone().to_trip_spec(rng); let spec = t.trip.clone().to_trip_spec(rng);
sim.schedule_trip(t.depart, spec, map); spawner.schedule_trip(t.depart, spec, map, sim);
} }
sim.spawn_all_trips(map, timer, true); sim.flush_spawner(spawner, map, timer, true);
timer.stop(format!("Instantiating {}", self.scenario_name)); timer.stop(format!("Instantiating {}", self.scenario_name));
} }
@ -305,7 +316,8 @@ impl SpawnOverTime {
fn spawn_agent( fn spawn_agent(
&self, &self,
rng: &mut XorShiftRng, rng: &mut XorShiftRng,
sim: &mut Sim, sim: &Sim,
spawner: &mut TripSpawner,
reserved_cars: &mut HashSet<CarID>, reserved_cars: &mut HashSet<CarID>,
neighborhoods: &HashMap<String, FullNeighborhoodInfo>, neighborhoods: &HashMap<String, FullNeighborhoodInfo>,
map: &Map, map: &Map,
@ -331,7 +343,7 @@ impl SpawnOverTime {
{ {
reserved_cars.insert(parked_car.vehicle.id); reserved_cars.insert(parked_car.vehicle.id);
let spot = parked_car.spot; let spot = parked_car.spot;
sim.schedule_trip( spawner.schedule_trip(
spawn_time, spawn_time,
TripSpec::UsingParkedCar { TripSpec::UsingParkedCar {
start: SidewalkSpot::building(from_bldg, map), start: SidewalkSpot::building(from_bldg, map),
@ -340,6 +352,7 @@ impl SpawnOverTime {
ped_speed: Scenario::rand_ped_speed(rng), ped_speed: Scenario::rand_ped_speed(rng),
}, },
map, map,
sim,
); );
return; return;
} }
@ -366,7 +379,7 @@ impl SpawnOverTime {
true true
}; };
if ok { if ok {
sim.schedule_trip( spawner.schedule_trip(
spawn_time, spawn_time,
TripSpec::UsingBike { TripSpec::UsingBike {
start: SidewalkSpot::building(from_bldg, map), start: SidewalkSpot::building(from_bldg, map),
@ -375,6 +388,7 @@ impl SpawnOverTime {
ped_speed: Scenario::rand_ped_speed(rng), ped_speed: Scenario::rand_ped_speed(rng),
}, },
map, map,
sim,
); );
return; return;
} }
@ -395,7 +409,7 @@ impl SpawnOverTime {
if let Some((stop1, stop2, route)) = if let Some((stop1, stop2, route)) =
map.should_use_transit(start_spot.sidewalk_pos, goal.sidewalk_pos) map.should_use_transit(start_spot.sidewalk_pos, goal.sidewalk_pos)
{ {
sim.schedule_trip( spawner.schedule_trip(
spawn_time, spawn_time,
TripSpec::UsingTransit { TripSpec::UsingTransit {
start: start_spot, start: start_spot,
@ -406,12 +420,13 @@ impl SpawnOverTime {
ped_speed: Scenario::rand_ped_speed(rng), ped_speed: Scenario::rand_ped_speed(rng),
}, },
map, map,
sim,
); );
return; return;
} }
} }
sim.schedule_trip( spawner.schedule_trip(
spawn_time, spawn_time,
TripSpec::JustWalking { TripSpec::JustWalking {
start: start_spot, start: start_spot,
@ -419,6 +434,7 @@ impl SpawnOverTime {
ped_speed: Scenario::rand_ped_speed(rng), ped_speed: Scenario::rand_ped_speed(rng),
}, },
map, map,
sim,
); );
return; return;
} }
@ -431,9 +447,10 @@ impl BorderSpawnOverTime {
fn spawn_peds( fn spawn_peds(
&self, &self,
rng: &mut XorShiftRng, rng: &mut XorShiftRng,
sim: &mut Sim, spawner: &mut TripSpawner,
neighborhoods: &HashMap<String, FullNeighborhoodInfo>, neighborhoods: &HashMap<String, FullNeighborhoodInfo>,
map: &Map, map: &Map,
sim: &Sim,
timer: &mut Timer, timer: &mut Timer,
) { ) {
if self.num_peds == 0 { if self.num_peds == 0 {
@ -461,7 +478,7 @@ impl BorderSpawnOverTime {
if let Some((stop1, stop2, route)) = if let Some((stop1, stop2, route)) =
map.should_use_transit(start.sidewalk_pos, goal.sidewalk_pos) map.should_use_transit(start.sidewalk_pos, goal.sidewalk_pos)
{ {
sim.schedule_trip( spawner.schedule_trip(
spawn_time, spawn_time,
TripSpec::UsingTransit { TripSpec::UsingTransit {
start: start.clone(), start: start.clone(),
@ -472,12 +489,13 @@ impl BorderSpawnOverTime {
ped_speed: Scenario::rand_ped_speed(rng), ped_speed: Scenario::rand_ped_speed(rng),
}, },
map, map,
sim,
); );
continue; continue;
} }
} }
sim.schedule_trip( spawner.schedule_trip(
spawn_time, spawn_time,
TripSpec::JustWalking { TripSpec::JustWalking {
start: start.clone(), start: start.clone(),
@ -485,6 +503,7 @@ impl BorderSpawnOverTime {
ped_speed: Scenario::rand_ped_speed(rng), ped_speed: Scenario::rand_ped_speed(rng),
}, },
map, map,
sim,
); );
} }
} }
@ -493,9 +512,10 @@ impl BorderSpawnOverTime {
fn spawn_cars( fn spawn_cars(
&self, &self,
rng: &mut XorShiftRng, rng: &mut XorShiftRng,
sim: &mut Sim, spawner: &mut TripSpawner,
neighborhoods: &HashMap<String, FullNeighborhoodInfo>, neighborhoods: &HashMap<String, FullNeighborhoodInfo>,
map: &Map, map: &Map,
sim: &Sim,
timer: &mut Timer, timer: &mut Timer,
) { ) {
if self.num_cars == 0 { if self.num_cars == 0 {
@ -521,7 +541,7 @@ impl BorderSpawnOverTime {
.pick_driving_goal(PathConstraints::Car, map, &neighborhoods, rng, timer) .pick_driving_goal(PathConstraints::Car, map, &neighborhoods, rng, timer)
{ {
let vehicle = Scenario::rand_car(rng); let vehicle = Scenario::rand_car(rng);
sim.schedule_trip( spawner.schedule_trip(
spawn_time, spawn_time,
TripSpec::CarAppearing { TripSpec::CarAppearing {
start_pos: Position::new(*lanes.choose(rng).unwrap(), vehicle.length), start_pos: Position::new(*lanes.choose(rng).unwrap(), vehicle.length),
@ -530,6 +550,7 @@ impl BorderSpawnOverTime {
ped_speed: Scenario::rand_ped_speed(rng), ped_speed: Scenario::rand_ped_speed(rng),
}, },
map, map,
sim,
); );
} }
} }
@ -538,9 +559,10 @@ impl BorderSpawnOverTime {
fn spawn_bikes( fn spawn_bikes(
&self, &self,
rng: &mut XorShiftRng, rng: &mut XorShiftRng,
sim: &mut Sim, spawner: &mut TripSpawner,
neighborhoods: &HashMap<String, FullNeighborhoodInfo>, neighborhoods: &HashMap<String, FullNeighborhoodInfo>,
map: &Map, map: &Map,
sim: &Sim,
timer: &mut Timer, timer: &mut Timer,
) { ) {
if self.num_bikes == 0 { if self.num_bikes == 0 {
@ -566,7 +588,7 @@ impl BorderSpawnOverTime {
.pick_driving_goal(PathConstraints::Bike, map, &neighborhoods, rng, timer) .pick_driving_goal(PathConstraints::Bike, map, &neighborhoods, rng, timer)
{ {
let bike = Scenario::rand_bike(rng); let bike = Scenario::rand_bike(rng);
sim.schedule_trip( spawner.schedule_trip(
spawn_time, spawn_time,
TripSpec::CarAppearing { TripSpec::CarAppearing {
start_pos: Position::new(*lanes.choose(rng).unwrap(), bike.length), start_pos: Position::new(*lanes.choose(rng).unwrap(), bike.length),
@ -575,6 +597,7 @@ impl BorderSpawnOverTime {
ped_speed: Scenario::rand_ped_speed(rng), ped_speed: Scenario::rand_ped_speed(rng),
}, },
map, map,
sim,
); );
} }
} }

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
CarID, Command, CreateCar, CreatePedestrian, DrivingGoal, ParkingSimState, ParkingSpot, CarID, Command, CreateCar, CreatePedestrian, DrivingGoal, ParkingSimState, ParkingSpot,
PedestrianID, Scheduler, SidewalkPOI, SidewalkSpot, TripLeg, TripManager, TripStart, PedestrianID, Scheduler, SidewalkPOI, SidewalkSpot, Sim, TripLeg, TripManager, TripStart,
VehicleSpec, MAX_CAR_LENGTH, VehicleSpec, VehicleType, MAX_CAR_LENGTH,
}; };
use abstutil::Timer; use abstutil::Timer;
use geom::{Speed, Time, EPSILON_DIST}; use geom::{Speed, Time, EPSILON_DIST};
@ -50,28 +50,84 @@ pub enum TripSpec {
}, },
} }
#[derive(Serialize, Deserialize, PartialEq, Clone)] // This structure is created temporarily by a Scenario or to interactively spawn agents.
// TODO The API isn't great. Passing in Sim and having to use friend methods is awkward.
// Alternatives could be somehow consuming Sim temporarily and spitting it back out at the end
// (except the interactive spawner would have to mem::replace with a blank Sim?), or just queueing
// up commands and doing them at the end while holding onto &Sim.
pub struct TripSpawner { pub struct TripSpawner {
parked_cars_claimed: BTreeSet<CarID>, parked_cars_claimed: BTreeSet<CarID>,
trips: Vec<(Time, Option<PedestrianID>, Option<CarID>, TripSpec)>, trips: Vec<(Time, Option<PedestrianID>, Option<CarID>, TripSpec)>,
pub car_id_counter: usize,
pub ped_id_counter: usize,
} }
impl TripSpawner { impl TripSpawner {
pub fn new() -> TripSpawner { pub fn new(car_id_counter: usize, ped_id_counter: usize) -> TripSpawner {
TripSpawner { TripSpawner {
parked_cars_claimed: BTreeSet::new(), parked_cars_claimed: BTreeSet::new(),
trips: Vec::new(), trips: Vec::new(),
car_id_counter,
ped_id_counter,
} }
} }
pub fn schedule_trip( pub fn schedule_trip(
&mut self,
start_time: Time,
spec: TripSpec,
map: &Map,
sim: &Sim,
) -> (Option<PedestrianID>, Option<CarID>) {
let (ped_id, car_id) = match spec {
TripSpec::CarAppearing {
ref vehicle_spec,
ref goal,
..
} => {
let car = CarID(self.car_id_counter, vehicle_spec.vehicle_type);
self.car_id_counter += 1;
let ped = match goal {
DrivingGoal::ParkNear(_) => {
let id = PedestrianID(self.ped_id_counter);
self.ped_id_counter += 1;
Some(id)
}
_ => None,
};
(ped, Some(car))
}
TripSpec::UsingParkedCar { .. }
| TripSpec::MaybeUsingParkedCar { .. }
| TripSpec::JustWalking { .. }
| TripSpec::UsingTransit { .. } => {
let id = PedestrianID(self.ped_id_counter);
self.ped_id_counter += 1;
(Some(id), None)
}
TripSpec::UsingBike { .. } => {
let ped = PedestrianID(self.ped_id_counter);
self.ped_id_counter += 1;
let car = CarID(self.car_id_counter, VehicleType::Bike);
self.car_id_counter += 1;
(Some(ped), Some(car))
}
};
self.inner_schedule_trip(start_time, ped_id, car_id, spec, map, sim);
(ped_id, car_id)
}
// TODO Maybe collapse this in the future
fn inner_schedule_trip(
&mut self, &mut self,
start_time: Time, start_time: Time,
ped_id: Option<PedestrianID>, ped_id: Option<PedestrianID>,
car_id: Option<CarID>, car_id: Option<CarID>,
spec: TripSpec, spec: TripSpec,
map: &Map, map: &Map,
parking: &ParkingSimState, sim: &Sim,
) { ) {
// TODO We'll want to repeat this validation when we spawn stuff later for a second leg... // TODO We'll want to repeat this validation when we spawn stuff later for a second leg...
match &spec { match &spec {
@ -106,7 +162,12 @@ impl TripSpawner {
} }
} }
TripSpec::UsingParkedCar { spot, .. } => { TripSpec::UsingParkedCar { spot, .. } => {
let car_id = parking.get_car_at_spot(*spot).unwrap().vehicle.id; let car_id = sim
.spawner_parking()
.get_car_at_spot(*spot)
.unwrap()
.vehicle
.id;
if self.parked_cars_claimed.contains(&car_id) { if self.parked_cars_claimed.contains(&car_id) {
panic!( panic!(
"A TripSpec wants to use {}, which is already claimed", "A TripSpec wants to use {}, which is already claimed",
@ -179,12 +240,12 @@ impl TripSpawner {
self.trips.push((start_time, ped_id, car_id, spec)); self.trips.push((start_time, ped_id, car_id, spec));
} }
pub fn spawn_all( pub fn finalize(
&mut self, mut self,
map: &Map, map: &Map,
parking: &ParkingSimState,
trips: &mut TripManager, trips: &mut TripManager,
scheduler: &mut Scheduler, scheduler: &mut Scheduler,
parking: &ParkingSimState,
timer: &mut Timer, timer: &mut Timer,
retry_if_no_room: bool, retry_if_no_room: bool,
) { ) {
@ -469,10 +530,6 @@ impl TripSpawner {
scheduler.finalize_batch(); scheduler.finalize_batch();
timer.stop("finalize spawned trips"); timer.stop("finalize spawned trips");
} }
pub fn is_done(&self) -> bool {
self.trips.is_empty()
}
} }
impl TripSpec { impl TripSpec {

View File

@ -30,7 +30,6 @@ pub struct Sim {
intersections: IntersectionSimState, intersections: IntersectionSimState,
transit: TransitSimState, transit: TransitSimState,
trips: TripManager, trips: TripManager,
spawner: TripSpawner,
scheduler: Scheduler, scheduler: Scheduler,
time: Time, time: Time,
car_id_counter: usize, car_id_counter: usize,
@ -107,7 +106,6 @@ impl Sim {
), ),
transit: TransitSimState::new(), transit: TransitSimState::new(),
trips: TripManager::new(), trips: TripManager::new(),
spawner: TripSpawner::new(),
scheduler, scheduler,
time: Time::START_OF_DAY, time: Time::START_OF_DAY,
car_id_counter: 0, car_id_counter: 0,
@ -125,62 +123,31 @@ impl Sim {
} }
} }
pub fn schedule_trip( pub fn make_spawner(&self) -> TripSpawner {
&mut self, TripSpawner::new(self.car_id_counter, self.ped_id_counter)
start_time: Time,
spec: TripSpec,
map: &Map,
) -> (Option<PedestrianID>, Option<CarID>) {
let (ped_id, car_id) = match spec {
TripSpec::CarAppearing {
ref vehicle_spec,
ref goal,
..
} => {
let car = CarID(self.car_id_counter, vehicle_spec.vehicle_type);
self.car_id_counter += 1;
let ped = match goal {
DrivingGoal::ParkNear(_) => {
let id = PedestrianID(self.ped_id_counter);
self.ped_id_counter += 1;
Some(id)
}
_ => None,
};
(ped, Some(car))
}
TripSpec::UsingParkedCar { .. }
| TripSpec::MaybeUsingParkedCar { .. }
| TripSpec::JustWalking { .. }
| TripSpec::UsingTransit { .. } => {
let id = PedestrianID(self.ped_id_counter);
self.ped_id_counter += 1;
(Some(id), None)
}
TripSpec::UsingBike { .. } => {
let ped = PedestrianID(self.ped_id_counter);
self.ped_id_counter += 1;
let car = CarID(self.car_id_counter, VehicleType::Bike);
self.car_id_counter += 1;
(Some(ped), Some(car))
}
};
self.spawner
.schedule_trip(start_time, ped_id, car_id, spec, map, &self.parking);
(ped_id, car_id)
} }
pub fn flush_spawner(
pub fn spawn_all_trips(&mut self, map: &Map, timer: &mut Timer, retry_if_no_room: bool) { &mut self,
self.spawner.spawn_all( spawner: TripSpawner,
map: &Map,
timer: &mut Timer,
retry_if_no_room: bool,
) {
self.car_id_counter = spawner.car_id_counter;
self.ped_id_counter = spawner.ped_id_counter;
spawner.finalize(
map, map,
&self.parking,
&mut self.trips, &mut self.trips,
&mut self.scheduler, &mut self.scheduler,
&self.parking,
timer, timer,
retry_if_no_room, retry_if_no_room,
); );
} }
// TODO Friend method pattern :(
pub(crate) fn spawner_parking(&self) -> &ParkingSimState {
&self.parking
}
pub fn get_free_spots(&self, l: LaneID) -> Vec<ParkingSpot> { pub fn get_free_spots(&self, l: LaneID) -> Vec<ParkingSpot> {
self.parking.get_free_spots(l) self.parking.get_free_spots(l)
@ -372,9 +339,6 @@ impl Sim {
// Advances time as minimally as possible, also limited by max_dt. // Advances time as minimally as possible, also limited by max_dt.
fn minimal_step(&mut self, map: &Map, max_dt: Duration) { fn minimal_step(&mut self, map: &Map, max_dt: Duration) {
self.step_count += 1; self.step_count += 1;
if !self.spawner.is_done() {
panic!("Forgot to call spawn_all_trips");
}
let max_time = if let Some(t) = self.scheduler.peek_next_time() { let max_time = if let Some(t) = self.scheduler.peek_next_time() {
if t > self.time + max_dt { if t > self.time + max_dt {
@ -815,10 +779,6 @@ impl Sim {
"- trips: {} bytes", "- trips: {} bytes",
abstutil::prettyprint_usize(abstutil::serialized_size_bytes(&self.trips)) abstutil::prettyprint_usize(abstutil::serialized_size_bytes(&self.trips))
); );
println!(
"- spawner: {} bytes",
abstutil::prettyprint_usize(abstutil::serialized_size_bytes(&self.spawner))
);
println!( println!(
"- scheduler: {} bytes", "- scheduler: {} bytes",
abstutil::prettyprint_usize(abstutil::serialized_size_bytes(&self.scheduler)) abstutil::prettyprint_usize(abstutil::serialized_size_bytes(&self.scheduler))
@ -868,7 +828,7 @@ impl Sim {
} }
pub fn is_done(&self) -> bool { pub fn is_done(&self) -> bool {
self.spawner.is_done() && self.trips.is_done() self.trips.is_done()
} }
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {