mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 23:43:25 +03:00
make the spawner deal with trips and transitions... big revamp for it
This commit is contained in:
parent
0a944f9864
commit
7745678794
@ -588,10 +588,10 @@ Time to get even more multi-modal / multi-phase!
|
||||
|
||||
|
||||
- next things
|
||||
= make ped have a SidewalkSpot as a start.
|
||||
= make ped have a SidewalkSpot as goal.
|
||||
- make the spawner orchestrate everything!
|
||||
- or should there be something else? spawner currently owns IDs. should maybe split out scenario generation and trip FSM management, but... not yet?
|
||||
- when reaching a parking spot, return up to master sim layer. something needs to make peds at a parking spot become started cars
|
||||
- something needs to make a newly parked car become a ped
|
||||
- when a driving car finishes parking, also tell walking sim to spawn a pedestrian
|
||||
|
||||
|
||||
- by the end of this, the spawner should be pretty simple, right?
|
||||
|
@ -504,8 +504,8 @@ impl gui::GUI for UI {
|
||||
}
|
||||
if input.unimportant_key_pressed(Key::S, "Seed the map with agents") {
|
||||
self.sim_ctrl.sim.seed_parked_cars(0.5);
|
||||
self.sim_ctrl.sim.seed_pedestrians(&self.map, 100);
|
||||
self.sim_ctrl.sim.start_many_parked_cars(&self.map, 100);
|
||||
self.sim_ctrl.sim.seed_walking_trips(&self.map, 100);
|
||||
self.sim_ctrl.sim.seed_driving_trips(&self.map, 100);
|
||||
return gui::EventLoopMode::InputOnly;
|
||||
}
|
||||
|
||||
|
@ -335,4 +335,8 @@ impl Map {
|
||||
let parking = road.find_parking_lane(driving)?;
|
||||
road.find_sidewalk(parking)
|
||||
}
|
||||
|
||||
pub fn get_driving_lane_from_parking(&self, parking: LaneID) -> Option<LaneID> {
|
||||
self.get_parent(parking).find_driving_lane(parking)
|
||||
}
|
||||
}
|
||||
|
@ -5,8 +5,10 @@ use {LaneID, Map};
|
||||
|
||||
// Returns an inclusive path, aka, [start, ..., end]
|
||||
pub fn pathfind(map: &Map, start: LaneID, end: LaneID) -> Option<Vec<LaneID>> {
|
||||
assert_ne!(start, end);
|
||||
assert_eq!(map.get_l(start).lane_type, map.get_l(end).lane_type);
|
||||
if start == end {
|
||||
return Some(vec![start]);
|
||||
}
|
||||
|
||||
// This should be deterministic, since theoretical distance ties would be broken by LaneID.
|
||||
let mut queue: BinaryHeap<(NotNaN<f64>, LaneID)> = BinaryHeap::new();
|
||||
|
@ -141,6 +141,11 @@ impl ParkingSimState {
|
||||
})?;
|
||||
Some(l.spots[idx].clone())
|
||||
}
|
||||
|
||||
pub fn get_car_at_spot(&self, spot: ParkingSpot) -> Option<CarParking> {
|
||||
let l = &self.lanes[spot.parking_lane.0];
|
||||
l.occupants[spot.spot_idx].and_then(|car| Some(CarParking::new(car, spot)))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize)]
|
||||
|
@ -107,8 +107,8 @@ impl Sim {
|
||||
ids
|
||||
}
|
||||
|
||||
pub fn start_many_parked_cars(&mut self, map: &Map, num_cars: usize) {
|
||||
self.spawner.start_many_parked_cars(
|
||||
pub fn seed_driving_trips(&mut self, map: &Map, num_cars: usize) {
|
||||
self.spawner.seed_driving_trips(
|
||||
self.time.next(),
|
||||
map,
|
||||
num_cars,
|
||||
@ -143,9 +143,9 @@ impl Sim {
|
||||
.spawn_pedestrian(self.time.next(), map, sidewalk, &mut self.rng);
|
||||
}
|
||||
|
||||
pub fn seed_pedestrians(&mut self, map: &Map, num: usize) {
|
||||
pub fn seed_walking_trips(&mut self, map: &Map, num: usize) {
|
||||
self.spawner
|
||||
.spawn_many_pedestrians(self.time.next(), map, num, &mut self.rng);
|
||||
.seed_walking_trips(self.time.next(), map, num, &mut self.rng);
|
||||
}
|
||||
|
||||
// TODO not sure returning info for tests like this is ideal
|
||||
@ -172,16 +172,21 @@ impl Sim {
|
||||
) {
|
||||
Ok(parked_cars) => for p in parked_cars {
|
||||
cars_parked_this_step.push(p.clone());
|
||||
self.parking_state.add_parked_car(p);
|
||||
self.parking_state.add_parked_car(p.clone());
|
||||
self.spawner.car_reached_parking_spot(self.time, p);
|
||||
},
|
||||
Err(e) => panic!("At {}: {}", self.time, e),
|
||||
};
|
||||
|
||||
if let Err(e) = self.walking_state
|
||||
match self.walking_state
|
||||
.step(TIMESTEP, map, &mut self.intersection_state)
|
||||
{
|
||||
panic!("At {}: {}", self.time, e);
|
||||
}
|
||||
Ok(peds_ready_to_drive) => for (ped, spot) in peds_ready_to_drive {
|
||||
self.spawner
|
||||
.ped_reached_parking_spot(self.time, ped, spot, &self.parking_state);
|
||||
},
|
||||
Err(e) => panic!("At {}: {}", self.time, e),
|
||||
};
|
||||
|
||||
// TODO want to pass self as a lazy QueryCar trait, but intersection_state is mutably
|
||||
// borrowed :(
|
||||
|
264
sim/src/spawn.rs
264
sim/src/spawn.rs
@ -2,43 +2,77 @@ use driving::DrivingSimState;
|
||||
use kinematics::Vehicle;
|
||||
use map_model;
|
||||
use map_model::{BuildingID, LaneID, Map};
|
||||
use parking::ParkingSimState;
|
||||
use parking::{ParkingSimState, ParkingSpot};
|
||||
use rand::Rng;
|
||||
use sim::CarParking;
|
||||
use std::collections::{BTreeMap, VecDeque};
|
||||
use std::fmt;
|
||||
use std::time::Instant;
|
||||
use walking::{SidewalkSpot, WalkingSimState};
|
||||
use {AgentID, CarID, PedestrianID, Tick};
|
||||
use {CarID, PedestrianID, Tick};
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
|
||||
struct Command {
|
||||
at: Tick,
|
||||
agent: AgentID,
|
||||
start: BuildingID,
|
||||
goal: BuildingID,
|
||||
enum Command {
|
||||
Walk(Tick, TripID, PedestrianID, SidewalkSpot, SidewalkSpot),
|
||||
Drive(Tick, TripID, CarParking, BuildingID),
|
||||
}
|
||||
|
||||
// This must get the car/ped IDs correct.
|
||||
impl Command {
|
||||
fn at(&self) -> Tick {
|
||||
match self {
|
||||
Command::Walk(at, _, _, _, _) => *at,
|
||||
Command::Drive(at, _, _, _) => *at,
|
||||
}
|
||||
}
|
||||
|
||||
fn get_pathfinding_lanes(&self, map: &Map) -> (LaneID, LaneID) {
|
||||
match self {
|
||||
Command::Walk(_, _, _, spot1, spot2) => {
|
||||
(spot1.get_sidewalk_pos(map).0, spot2.get_sidewalk_pos(map).0)
|
||||
}
|
||||
Command::Drive(_, _, car_parking, goal_bldg) => (
|
||||
map.get_driving_lane_from_parking(car_parking.spot.parking_lane)
|
||||
.unwrap(),
|
||||
map.get_driving_lane_from_bldg(*goal_bldg).unwrap(),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn retry_next_tick(&self) -> Command {
|
||||
match self {
|
||||
Command::Walk(at, trip, ped, spot1, spot2) => {
|
||||
Command::Walk(at.next(), *trip, *ped, spot1.clone(), spot2.clone())
|
||||
}
|
||||
Command::Drive(at, trip, car_parking, goal) => {
|
||||
Command::Drive(at.next(), *trip, car_parking.clone(), *goal)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This owns car/ped IDs.
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub struct Spawner {
|
||||
// This happens immediately (at the beginning of the simulation in most cases, except for
|
||||
// interactive UI stuff)
|
||||
spawn_parked_cars: Vec<CarParking>,
|
||||
|
||||
// Ordered by time
|
||||
commands: VecDeque<Command>,
|
||||
|
||||
car_id_counter: usize,
|
||||
ped_id_counter: usize,
|
||||
|
||||
trips: Vec<Trip>,
|
||||
trip_per_ped: BTreeMap<PedestrianID, TripID>,
|
||||
trip_per_car: BTreeMap<CarID, TripID>,
|
||||
}
|
||||
|
||||
impl Spawner {
|
||||
pub fn empty() -> Spawner {
|
||||
Spawner {
|
||||
spawn_parked_cars: Vec::new(),
|
||||
commands: VecDeque::new(),
|
||||
car_id_counter: 0,
|
||||
ped_id_counter: 0,
|
||||
trips: Vec::new(),
|
||||
trip_per_ped: BTreeMap::new(),
|
||||
trip_per_car: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -51,95 +85,62 @@ impl Spawner {
|
||||
driving_sim: &mut DrivingSimState,
|
||||
properties: &BTreeMap<CarID, Vehicle>,
|
||||
) {
|
||||
for p in self.spawn_parked_cars.drain(0..) {
|
||||
parking_sim.add_parked_car(p);
|
||||
}
|
||||
|
||||
let mut spawn_agents: Vec<(AgentID, BuildingID, BuildingID)> = Vec::new();
|
||||
let mut commands: Vec<Command> = Vec::new();
|
||||
let mut requested_paths: Vec<(LaneID, LaneID)> = Vec::new();
|
||||
loop {
|
||||
let pop = if let Some(cmd) = self.commands.front() {
|
||||
if now == cmd.at {
|
||||
spawn_agents.push((cmd.agent, cmd.start, cmd.goal));
|
||||
let (start_lane, goal_lane) = match cmd.agent {
|
||||
AgentID::Car(_) => (
|
||||
map.get_driving_lane_from_bldg(cmd.start).unwrap(),
|
||||
map.get_driving_lane_from_bldg(cmd.goal).unwrap(),
|
||||
),
|
||||
AgentID::Pedestrian(_) => (
|
||||
map.get_b(cmd.start).front_path.sidewalk,
|
||||
map.get_b(cmd.goal).front_path.sidewalk,
|
||||
),
|
||||
};
|
||||
requested_paths.push((start_lane, goal_lane));
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if pop {
|
||||
self.commands.pop_front();
|
||||
if self.commands
|
||||
.front()
|
||||
.and_then(|cmd| Some(now == cmd.at()))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
let cmd = self.commands.pop_front().unwrap();
|
||||
requested_paths.push(cmd.get_pathfinding_lanes(map));
|
||||
commands.push(cmd);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if spawn_agents.is_empty() {
|
||||
if commands.is_empty() {
|
||||
return;
|
||||
}
|
||||
let paths = calculate_paths(&requested_paths, map);
|
||||
|
||||
let mut spawned_agents = 0;
|
||||
for ((agent, start_bldg, goal_bldg), (req, maybe_path)) in spawn_agents
|
||||
.into_iter()
|
||||
.zip(requested_paths.iter().zip(paths))
|
||||
for (cmd, (req, maybe_path)) in commands.into_iter().zip(requested_paths.iter().zip(paths))
|
||||
{
|
||||
if let Some(path) = maybe_path {
|
||||
match agent {
|
||||
AgentID::Car(car) => {
|
||||
let driving_lane = path[0];
|
||||
let parking_lane = map.get_parent(driving_lane)
|
||||
.find_parking_lane(driving_lane)
|
||||
.unwrap();
|
||||
let spot = parking_sim.get_spot_of_car(car, parking_lane);
|
||||
match cmd {
|
||||
Command::Drive(_, trip, ref car_parking, _) => {
|
||||
let car = car_parking.car;
|
||||
let parking_lane = car_parking.spot.parking_lane;
|
||||
|
||||
if driving_sim.start_car_on_lane(
|
||||
now,
|
||||
car,
|
||||
CarParking::new(car, spot),
|
||||
car_parking.clone(),
|
||||
VecDeque::from(path),
|
||||
map,
|
||||
properties,
|
||||
) {
|
||||
self.trip_per_car.insert(car, trip);
|
||||
parking_sim.remove_parked_car(parking_lane, car);
|
||||
spawned_agents += 1;
|
||||
} else {
|
||||
// Try again next tick. Because we already slurped up all the commands
|
||||
// for this tick, the front of the queue is the right spot.
|
||||
self.commands.push_front(Command {
|
||||
at: now.next(),
|
||||
agent: agent,
|
||||
start: start_bldg,
|
||||
goal: goal_bldg,
|
||||
});
|
||||
self.commands.push_front(cmd.retry_next_tick());
|
||||
}
|
||||
}
|
||||
AgentID::Pedestrian(ped) => {
|
||||
walking_sim.seed_pedestrian(
|
||||
ped,
|
||||
SidewalkSpot::Building(start_bldg),
|
||||
SidewalkSpot::Building(goal_bldg),
|
||||
map,
|
||||
VecDeque::from(path),
|
||||
);
|
||||
Command::Walk(_, trip, ped, spot1, spot2) => {
|
||||
self.trip_per_ped.insert(ped, trip);
|
||||
walking_sim.seed_pedestrian(ped, spot1, spot2, map, VecDeque::from(path));
|
||||
spawned_agents += 1;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
println!(
|
||||
"Couldn't find path from {} to {} for {:?}",
|
||||
req.0, req.1, agent
|
||||
req.0, req.1, cmd
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -150,7 +151,7 @@ impl Spawner {
|
||||
);
|
||||
}
|
||||
|
||||
// TODO the mut is temporary
|
||||
// This happens immediately; it isn't scheduled.
|
||||
pub fn seed_parked_cars<R: Rng + ?Sized>(
|
||||
&mut self,
|
||||
percent_capacity_to_fill: f64,
|
||||
@ -158,7 +159,6 @@ impl Spawner {
|
||||
rng: &mut R,
|
||||
) -> Vec<Vehicle> {
|
||||
assert!(percent_capacity_to_fill >= 0.0 && percent_capacity_to_fill <= 1.0);
|
||||
assert!(self.spawn_parked_cars.is_empty());
|
||||
|
||||
let mut total_capacity = 0;
|
||||
let mut new_cars: Vec<Vehicle> = Vec::new();
|
||||
@ -169,7 +169,6 @@ impl Spawner {
|
||||
// TODO since spawning applies during the next step, lots of stuff breaks without
|
||||
// this :(
|
||||
parking_sim.add_parked_car(CarParking::new(id, spot));
|
||||
//self.spawn_parked_cars.push(CarParking::new(CarID(self.car_id_counter), spot));
|
||||
new_cars.push(Vehicle::generate_typical_car(id, rng));
|
||||
self.car_id_counter += 1;
|
||||
}
|
||||
@ -190,14 +189,12 @@ impl Spawner {
|
||||
parking_sim: &mut ParkingSimState,
|
||||
rng: &mut R,
|
||||
) -> Vec<Vehicle> {
|
||||
assert!(self.spawn_parked_cars.is_empty());
|
||||
let spots = parking_sim.get_all_spots(lane);
|
||||
spot_indices
|
||||
.into_iter()
|
||||
.map(|idx| {
|
||||
let id = CarID(self.car_id_counter);
|
||||
parking_sim.add_parked_car(CarParking::new(id, spots[idx].clone()));
|
||||
// TODO push onto spawn_parked_cars?
|
||||
self.car_id_counter += 1;
|
||||
Vehicle::generate_typical_car(id, rng)
|
||||
})
|
||||
@ -214,32 +211,44 @@ impl Spawner {
|
||||
rng: &mut R,
|
||||
) {
|
||||
if let Some(cmd) = self.commands.back() {
|
||||
assert!(at >= cmd.at);
|
||||
assert!(at >= cmd.at());
|
||||
}
|
||||
|
||||
// Don't add duplicate commands.
|
||||
if self.commands
|
||||
.iter()
|
||||
.find(|cmd| cmd.agent == AgentID::Car(car))
|
||||
.is_some()
|
||||
{
|
||||
if let Some(trip) = self.trips.iter().find(|t| t.use_car == Some(car)) {
|
||||
println!(
|
||||
"{} is already scheduled to start, ignoring new request",
|
||||
car
|
||||
"{} is already a part of {:?}, ignoring new request",
|
||||
car, trip
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
let parking_lane = parking_sim.lane_of_car(car).expect("Car isn't parked");
|
||||
let road = map.get_parent(parking_lane);
|
||||
let driving_lane = road.find_driving_lane(parking_lane)
|
||||
.expect("Parking lane has no driving lane");
|
||||
let sidewalk = road.find_sidewalk(parking_lane)
|
||||
.expect("Parking lane has no sidewalk");
|
||||
let start_bldg = pick_bldg_from_sidewalk(rng, map, sidewalk);
|
||||
let goal_bldg = pick_bldg_from_driving_lane(rng, map, goal);
|
||||
|
||||
self.commands.push_back(Command {
|
||||
at,
|
||||
agent: AgentID::Car(car),
|
||||
start: pick_bldg_from_driving_lane(rng, map, driving_lane),
|
||||
goal: pick_bldg_from_driving_lane(rng, map, goal),
|
||||
let trip_id = TripID(self.trips.len());
|
||||
let ped_id = PedestrianID(self.ped_id_counter);
|
||||
self.ped_id_counter += 1;
|
||||
|
||||
self.trips.push(Trip {
|
||||
id: trip_id,
|
||||
ped: ped_id,
|
||||
start_bldg,
|
||||
use_car: Some(car),
|
||||
goal_bldg,
|
||||
});
|
||||
|
||||
self.commands.push_back(Command::Walk(
|
||||
at,
|
||||
trip_id,
|
||||
ped_id,
|
||||
SidewalkSpot::Building(start_bldg),
|
||||
SidewalkSpot::ParkingSpot(parking_sim.get_spot_of_car(car, parking_lane)),
|
||||
));
|
||||
}
|
||||
|
||||
pub fn start_parked_car<R: Rng + ?Sized>(
|
||||
@ -259,7 +268,7 @@ impl Spawner {
|
||||
self.start_parked_car_with_goal(at, map, car, parking_sim, goal, rng);
|
||||
}
|
||||
|
||||
pub fn start_many_parked_cars<R: Rng + ?Sized>(
|
||||
pub fn seed_driving_trips<R: Rng + ?Sized>(
|
||||
&mut self,
|
||||
at: Tick,
|
||||
map: &Map,
|
||||
@ -302,20 +311,34 @@ impl Spawner {
|
||||
rng: &mut R,
|
||||
) {
|
||||
if let Some(cmd) = self.commands.back() {
|
||||
assert!(at >= cmd.at);
|
||||
assert!(at >= cmd.at());
|
||||
}
|
||||
assert!(map.get_l(sidewalk).is_sidewalk());
|
||||
|
||||
self.commands.push_back(Command {
|
||||
at,
|
||||
agent: AgentID::Pedestrian(PedestrianID(self.ped_id_counter)),
|
||||
start: pick_bldg_from_sidewalk(rng, map, sidewalk),
|
||||
goal: pick_ped_goal(rng, map, sidewalk),
|
||||
});
|
||||
let start_bldg = pick_bldg_from_sidewalk(rng, map, sidewalk);
|
||||
let goal_bldg = pick_ped_goal(rng, map, sidewalk);
|
||||
let trip_id = TripID(self.trips.len());
|
||||
let ped_id = PedestrianID(self.ped_id_counter);
|
||||
self.ped_id_counter += 1;
|
||||
|
||||
self.trips.push(Trip {
|
||||
id: trip_id,
|
||||
ped: ped_id,
|
||||
start_bldg,
|
||||
use_car: None,
|
||||
goal_bldg,
|
||||
});
|
||||
|
||||
self.commands.push_back(Command::Walk(
|
||||
at,
|
||||
trip_id,
|
||||
ped_id,
|
||||
SidewalkSpot::Building(start_bldg),
|
||||
SidewalkSpot::Building(goal_bldg),
|
||||
));
|
||||
}
|
||||
|
||||
pub fn spawn_many_pedestrians<R: Rng + ?Sized>(
|
||||
pub fn seed_walking_trips<R: Rng + ?Sized>(
|
||||
&mut self,
|
||||
at: Tick,
|
||||
map: &Map,
|
||||
@ -334,6 +357,34 @@ impl Spawner {
|
||||
self.spawn_pedestrian(at, map, start, rng);
|
||||
}
|
||||
}
|
||||
|
||||
// Trip transitions
|
||||
pub fn car_reached_parking_spot(&mut self, at: Tick, p: CarParking) {
|
||||
let trip = &self.trips[self.trip_per_car.remove(&p.car).unwrap().0];
|
||||
self.commands.push_back(Command::Walk(
|
||||
at.next(),
|
||||
trip.id,
|
||||
trip.ped,
|
||||
SidewalkSpot::ParkingSpot(p.spot),
|
||||
SidewalkSpot::Building(trip.goal_bldg),
|
||||
));
|
||||
}
|
||||
|
||||
pub fn ped_reached_parking_spot(
|
||||
&mut self,
|
||||
at: Tick,
|
||||
ped: PedestrianID,
|
||||
spot: ParkingSpot,
|
||||
parking_sim: &ParkingSimState,
|
||||
) {
|
||||
let trip = &self.trips[self.trip_per_ped.remove(&ped).unwrap().0];
|
||||
self.commands.push_back(Command::Drive(
|
||||
at.next(),
|
||||
trip.id,
|
||||
parking_sim.get_car_at_spot(spot).unwrap(),
|
||||
trip.goal_bldg,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
fn pick_car_goal<R: Rng + ?Sized>(rng: &mut R, map: &Map, start: LaneID) -> LaneID {
|
||||
@ -400,3 +451,22 @@ fn pick_bldg_from_driving_lane<R: Rng + ?Sized>(
|
||||
) -> BuildingID {
|
||||
pick_bldg_from_sidewalk(rng, map, map.get_sidewalk_from_driving_lane(start).unwrap())
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)]
|
||||
pub struct TripID(pub usize);
|
||||
|
||||
impl fmt::Display for TripID {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "TripID({0})", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug)]
|
||||
struct Trip {
|
||||
id: TripID,
|
||||
ped: PedestrianID,
|
||||
start_bldg: BuildingID,
|
||||
// Later, this could be an enum of mode choices, or something even more complicated
|
||||
use_car: Option<CarID>,
|
||||
goal_bldg: BuildingID,
|
||||
}
|
||||
|
@ -21,14 +21,14 @@ const SPEED: Speed = si::MeterPerSecond {
|
||||
|
||||
// A pedestrian can start from a parking spot (after driving and parking) or at a building.
|
||||
// A pedestrian can end at a parking spot (to start driving) or at a building.
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||
pub enum SidewalkSpot {
|
||||
ParkingSpot(ParkingSpot),
|
||||
Building(BuildingID),
|
||||
}
|
||||
|
||||
impl SidewalkSpot {
|
||||
fn get_sidewalk_pos(&self, map: &Map) -> (LaneID, Distance) {
|
||||
pub fn get_sidewalk_pos(&self, map: &Map) -> (LaneID, Distance) {
|
||||
match self {
|
||||
SidewalkSpot::ParkingSpot(spot) => (
|
||||
map.get_parent(spot.parking_lane)
|
||||
@ -281,12 +281,13 @@ impl WalkingSimState {
|
||||
// No-op
|
||||
}
|
||||
|
||||
// Return all the pedestrians that have reached a parking spot.
|
||||
pub fn step(
|
||||
&mut self,
|
||||
delta_time: Time,
|
||||
map: &Map,
|
||||
intersections: &mut IntersectionSimState,
|
||||
) -> Result<(), InvariantViolated> {
|
||||
) -> Result<Vec<(PedestrianID, ParkingSpot)>, InvariantViolated> {
|
||||
// Could be concurrent, since this is deterministic.
|
||||
let mut requested_moves: Vec<(PedestrianID, Action)> = Vec::new();
|
||||
for p in self.peds.values() {
|
||||
@ -296,6 +297,8 @@ impl WalkingSimState {
|
||||
// In AORTA, there was a split here -- react vs step phase. We're still following the same
|
||||
// thing, but it might be slightly more clear to express it differently?
|
||||
|
||||
let mut results = Vec::new();
|
||||
|
||||
// Apply moves. This can also be concurrent, since there are no possible conflicts.
|
||||
for (id, act) in &requested_moves {
|
||||
match *act {
|
||||
@ -305,13 +308,12 @@ impl WalkingSimState {
|
||||
.unwrap()
|
||||
.step_cross_path(delta_time, map)
|
||||
{
|
||||
// TODO return to sim that id has reached spot
|
||||
self.peds.remove(&id);
|
||||
}
|
||||
}
|
||||
Action::StartParkedCar(ref _spot) => {
|
||||
Action::StartParkedCar(ref spot) => {
|
||||
self.peds.remove(&id);
|
||||
// TODO return something up to sim
|
||||
results.push((*id, spot.clone()));
|
||||
}
|
||||
Action::StartCrossingPath(bldg) => {
|
||||
let p = self.peds.get_mut(&id).unwrap();
|
||||
@ -349,7 +351,7 @@ impl WalkingSimState {
|
||||
};
|
||||
}
|
||||
|
||||
Ok(())
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
pub fn debug_ped(&self, id: PedestrianID) {
|
||||
@ -406,7 +408,9 @@ impl WalkingSimState {
|
||||
let start_lane = path.pop_front().unwrap();
|
||||
let (spot_start_lane, start_dist) = start.get_sidewalk_pos(map);
|
||||
assert_eq!(start_lane, spot_start_lane);
|
||||
assert_eq!(*path.back().unwrap(), goal.get_sidewalk_pos(map).0);
|
||||
if !path.is_empty() {
|
||||
assert_eq!(*path.back().unwrap(), goal.get_sidewalk_pos(map).0);
|
||||
}
|
||||
let front_path = if let SidewalkSpot::Building(id) = start {
|
||||
Some(CrossingFrontPath {
|
||||
bldg: id,
|
||||
@ -417,7 +421,11 @@ impl WalkingSimState {
|
||||
None
|
||||
};
|
||||
|
||||
let contraflow = is_contraflow(map, start_lane, path[0]);
|
||||
let contraflow = if path.is_empty() {
|
||||
start_dist > goal.get_sidewalk_pos(map).1
|
||||
} else {
|
||||
is_contraflow(map, start_lane, path[0])
|
||||
};
|
||||
self.peds.insert(
|
||||
id,
|
||||
Pedestrian {
|
||||
|
@ -14,9 +14,9 @@ fn aorta_model_completes() {
|
||||
let control_map = control::ControlMap::new(&map);
|
||||
|
||||
let mut sim = sim::Sim::new(&map, Some(rng_seed));
|
||||
sim.seed_pedestrians(&map, spawn_count);
|
||||
sim.seed_parked_cars(0.5);
|
||||
sim.start_many_parked_cars(&map, spawn_count);
|
||||
sim.seed_walking_trips(&map, spawn_count);
|
||||
sim.seed_driving_trips(&map, spawn_count);
|
||||
|
||||
loop {
|
||||
sim.step(&map, &control_map);
|
||||
|
@ -13,9 +13,9 @@ fn serialization() {
|
||||
let map = map_model::Map::new(input, &map_model::Edits::new()).expect("Couldn't load map");
|
||||
|
||||
let mut sim = sim::Sim::new(&map, Some(rng_seed));
|
||||
sim.seed_pedestrians(&map, spawn_count);
|
||||
sim.seed_parked_cars(0.5);
|
||||
sim.start_many_parked_cars(&map, spawn_count);
|
||||
sim.seed_walking_trips(&map, spawn_count);
|
||||
sim.seed_driving_trips(&map, spawn_count);
|
||||
|
||||
// Does savestating produce the same string?
|
||||
let save1 = abstutil::to_json(&sim);
|
||||
@ -36,12 +36,12 @@ fn from_scratch() {
|
||||
|
||||
let mut sim1 = sim::Sim::new(&map, Some(rng_seed));
|
||||
let mut sim2 = sim::Sim::new(&map, Some(rng_seed));
|
||||
sim1.seed_pedestrians(&map, spawn_count);
|
||||
sim1.seed_parked_cars(0.5);
|
||||
sim1.start_many_parked_cars(&map, spawn_count);
|
||||
sim2.seed_pedestrians(&map, spawn_count);
|
||||
sim1.seed_walking_trips(&map, spawn_count);
|
||||
sim1.seed_driving_trips(&map, spawn_count);
|
||||
sim2.seed_parked_cars(0.5);
|
||||
sim2.start_many_parked_cars(&map, spawn_count);
|
||||
sim2.seed_walking_trips(&map, spawn_count);
|
||||
sim2.seed_driving_trips(&map, spawn_count);
|
||||
|
||||
for _ in 1..600 {
|
||||
if sim1 != sim2 {
|
||||
@ -72,12 +72,12 @@ fn with_savestating() {
|
||||
|
||||
let mut sim1 = sim::Sim::new(&map, Some(rng_seed));
|
||||
let mut sim2 = sim::Sim::new(&map, Some(rng_seed));
|
||||
sim1.seed_pedestrians(&map, spawn_count);
|
||||
sim1.seed_parked_cars(0.5);
|
||||
sim1.start_many_parked_cars(&map, spawn_count);
|
||||
sim2.seed_pedestrians(&map, spawn_count);
|
||||
sim1.seed_walking_trips(&map, spawn_count);
|
||||
sim1.seed_driving_trips(&map, spawn_count);
|
||||
sim2.seed_parked_cars(0.5);
|
||||
sim2.start_many_parked_cars(&map, spawn_count);
|
||||
sim2.seed_walking_trips(&map, spawn_count);
|
||||
sim2.seed_driving_trips(&map, spawn_count);
|
||||
|
||||
for _ in 1..600 {
|
||||
sim1.step(&map, &control_map);
|
||||
|
Loading…
Reference in New Issue
Block a user