mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-01 02:33:54 +03:00
moving pedestrian spawning
This commit is contained in:
parent
af8a583f77
commit
29ad509401
@ -86,8 +86,8 @@ impl Tick {
|
|||||||
(self.0 as f64) * TIMESTEP
|
(self.0 as f64) * TIMESTEP
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn increment(&mut self) {
|
pub fn next(self) -> Tick {
|
||||||
self.0 += 1;
|
Tick(self.0 + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO er, little weird
|
// TODO er, little weird
|
||||||
|
@ -278,68 +278,25 @@ impl Sim {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn spawn_pedestrian(&mut self, map: &Map, sidewalk: LaneID) -> bool {
|
pub fn spawn_pedestrian(&mut self, map: &Map, sidewalk: LaneID) {
|
||||||
assert!(map.get_l(sidewalk).is_sidewalk());
|
self.spawner
|
||||||
|
.spawn_pedestrian(self.time.next(), map, sidewalk, &mut self.rng);
|
||||||
if let Some(path) = pick_goal_and_find_path(&mut self.rng, map, sidewalk) {
|
|
||||||
self.walking_state
|
|
||||||
.seed_pedestrian(map, VecDeque::from(path));
|
|
||||||
println!("Spawned a pedestrian at {}", sidewalk);
|
|
||||||
true
|
|
||||||
} else {
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn seed_pedestrians(&mut self, map: &Map, num: usize) {
|
pub fn seed_pedestrians(&mut self, map: &Map, num: usize) {
|
||||||
use rayon::prelude::*;
|
self.spawner
|
||||||
|
.spawn_many_pedestrians(self.time.next(), map, num, &mut self.rng);
|
||||||
let mut sidewalks: Vec<LaneID> = Vec::new();
|
|
||||||
for l in map.all_lanes() {
|
|
||||||
if l.is_sidewalk() {
|
|
||||||
sidewalks.push(l.id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut requested_paths: Vec<(LaneID, LaneID)> = Vec::new();
|
|
||||||
for _i in 0..num {
|
|
||||||
let start = *self.rng.choose(&sidewalks).unwrap();
|
|
||||||
let goal = choose_different(&mut self.rng, &sidewalks, start);
|
|
||||||
requested_paths.push((start, goal));
|
|
||||||
}
|
|
||||||
|
|
||||||
println!("Calculating {} paths for pedestrians", num);
|
|
||||||
// TODO better timer macro
|
|
||||||
let timer = Instant::now();
|
|
||||||
let paths: Vec<Option<Vec<LaneID>>> = requested_paths
|
|
||||||
.par_iter()
|
|
||||||
.map(|(start, goal)| map_model::pathfind(map, *start, *goal))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let mut actual = 0;
|
|
||||||
for path in paths.into_iter() {
|
|
||||||
if let Some(steps) = path {
|
|
||||||
self.walking_state
|
|
||||||
.seed_pedestrian(map, VecDeque::from(steps));
|
|
||||||
actual += 1;
|
|
||||||
} else {
|
|
||||||
// zip with request to have start/goal?
|
|
||||||
//println!("Failed to pathfind for a pedestrian");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
println!(
|
|
||||||
"Calculating {} pedestrian paths took {:?}",
|
|
||||||
num,
|
|
||||||
timer.elapsed()
|
|
||||||
);
|
|
||||||
println!("Spawned {} pedestrians of requested {}", actual, num);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step(&mut self, map: &Map, control_map: &ControlMap) {
|
pub fn step(&mut self, map: &Map, control_map: &ControlMap) {
|
||||||
self.time.increment();
|
self.time = self.time.next();
|
||||||
|
|
||||||
self.spawner.step(self.time, &mut self.parking_state);
|
self.spawner.step(
|
||||||
|
self.time,
|
||||||
|
map,
|
||||||
|
&mut self.parking_state,
|
||||||
|
&mut self.walking_state,
|
||||||
|
);
|
||||||
|
|
||||||
match self.driving_state.step(
|
match self.driving_state.step(
|
||||||
self.time,
|
self.time,
|
||||||
|
159
sim/src/spawn.rs
159
sim/src/spawn.rs
@ -1,7 +1,11 @@
|
|||||||
use map_model::LaneID;
|
use map_model;
|
||||||
|
use map_model::{LaneID, Map};
|
||||||
use parking::ParkingSimState;
|
use parking::ParkingSimState;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
use sim::CarParking;
|
use sim::CarParking;
|
||||||
|
use std::collections::VecDeque;
|
||||||
|
use std::time::Instant;
|
||||||
|
use walking::WalkingSimState;
|
||||||
use {CarID, PedestrianID, Tick};
|
use {CarID, PedestrianID, Tick};
|
||||||
|
|
||||||
// TODO move the stuff in sim that does RNG stuff, picks goals, etc to here. make the UI commands
|
// TODO move the stuff in sim that does RNG stuff, picks goals, etc to here. make the UI commands
|
||||||
@ -15,6 +19,15 @@ enum Command {
|
|||||||
SpawnPedestrian(Tick, PedestrianID, LaneID, LaneID),
|
SpawnPedestrian(Tick, PedestrianID, LaneID, LaneID),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Command {
|
||||||
|
fn get_time(&self) -> Tick {
|
||||||
|
match self {
|
||||||
|
Command::StartParkedCar(time, _, _) => *time,
|
||||||
|
Command::SpawnPedestrian(time, _, _, _) => *time,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// This must get the car/ped IDs correct.
|
// This must get the car/ped IDs correct.
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Eq)]
|
#[derive(Serialize, Deserialize, PartialEq, Eq)]
|
||||||
pub struct Spawner {
|
pub struct Spawner {
|
||||||
@ -23,24 +36,81 @@ pub struct Spawner {
|
|||||||
spawn_parked_cars: Vec<CarParking>,
|
spawn_parked_cars: Vec<CarParking>,
|
||||||
|
|
||||||
// Ordered by time
|
// Ordered by time
|
||||||
commands: Vec<Command>,
|
commands: VecDeque<Command>,
|
||||||
|
|
||||||
car_id_counter: usize,
|
car_id_counter: usize,
|
||||||
|
ped_id_counter: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Spawner {
|
impl Spawner {
|
||||||
pub fn empty() -> Spawner {
|
pub fn empty() -> Spawner {
|
||||||
Spawner {
|
Spawner {
|
||||||
spawn_parked_cars: Vec::new(),
|
spawn_parked_cars: Vec::new(),
|
||||||
commands: Vec::new(),
|
commands: VecDeque::new(),
|
||||||
car_id_counter: 0,
|
car_id_counter: 0,
|
||||||
|
ped_id_counter: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step(&mut self, _time: Tick, parking_sim: &mut ParkingSimState) {
|
pub fn step(
|
||||||
|
&mut self,
|
||||||
|
now: Tick,
|
||||||
|
map: &Map,
|
||||||
|
parking_sim: &mut ParkingSimState,
|
||||||
|
walking_sim: &mut WalkingSimState,
|
||||||
|
) {
|
||||||
for p in self.spawn_parked_cars.drain(0..) {
|
for p in self.spawn_parked_cars.drain(0..) {
|
||||||
parking_sim.add_parked_car(p);
|
parking_sim.add_parked_car(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut spawn_peds: Vec<PedestrianID> = Vec::new();
|
||||||
|
let mut requested_paths: Vec<(LaneID, LaneID)> = Vec::new();
|
||||||
|
loop {
|
||||||
|
let pop = if let Some(cmd) = self.commands.front() {
|
||||||
|
match cmd {
|
||||||
|
Command::StartParkedCar(time, car, goal) => {
|
||||||
|
println!("TODO");
|
||||||
|
false
|
||||||
|
}
|
||||||
|
Command::SpawnPedestrian(time, ped, start, goal) => {
|
||||||
|
if now == *time {
|
||||||
|
spawn_peds.push(*ped);
|
||||||
|
requested_paths.push((*start, *goal));
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
if pop {
|
||||||
|
self.commands.pop_front();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if requested_paths.is_empty() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let paths = calculate_paths(&requested_paths, map);
|
||||||
|
let mut spawned_peds = 0;
|
||||||
|
for (ped, (req, maybe_path)) in spawn_peds.iter().zip(requested_paths.iter().zip(paths)) {
|
||||||
|
if let Some(path) = maybe_path {
|
||||||
|
walking_sim.seed_pedestrian(*ped, map, VecDeque::from(path));
|
||||||
|
spawned_peds += 1;
|
||||||
|
} else {
|
||||||
|
println!("Couldn't find path from {} to {} for {}", req.0, req.1, ped);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!(
|
||||||
|
"Spawned {} pedestrians of requested {}",
|
||||||
|
spawned_peds,
|
||||||
|
spawn_peds.len()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO the mut is temporary
|
// TODO the mut is temporary
|
||||||
@ -72,4 +142,85 @@ impl Spawner {
|
|||||||
new_cars, total_capacity
|
new_cars, total_capacity
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn spawn_pedestrian<R: Rng + ?Sized>(
|
||||||
|
&mut self,
|
||||||
|
at: Tick,
|
||||||
|
map: &Map,
|
||||||
|
sidewalk: LaneID,
|
||||||
|
rng: &mut R,
|
||||||
|
) {
|
||||||
|
if let Some(cmd) = self.commands.back() {
|
||||||
|
assert!(at >= cmd.get_time());
|
||||||
|
}
|
||||||
|
assert!(map.get_l(sidewalk).is_sidewalk());
|
||||||
|
|
||||||
|
let goal = pick_goal(rng, map, sidewalk);
|
||||||
|
self.commands.push_back(Command::SpawnPedestrian(
|
||||||
|
at,
|
||||||
|
PedestrianID(self.ped_id_counter),
|
||||||
|
sidewalk,
|
||||||
|
goal,
|
||||||
|
));
|
||||||
|
self.ped_id_counter += 1;
|
||||||
|
println!("Spawned a pedestrian at {}", sidewalk);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spawn_many_pedestrians<R: Rng + ?Sized>(
|
||||||
|
&mut self,
|
||||||
|
at: Tick,
|
||||||
|
map: &Map,
|
||||||
|
num: usize,
|
||||||
|
rng: &mut R,
|
||||||
|
) {
|
||||||
|
if let Some(cmd) = self.commands.back() {
|
||||||
|
assert!(at >= cmd.get_time());
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut sidewalks: Vec<LaneID> = Vec::new();
|
||||||
|
for l in map.all_lanes() {
|
||||||
|
if l.is_sidewalk() {
|
||||||
|
sidewalks.push(l.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _i in 0..num {
|
||||||
|
let start = *rng.choose(&sidewalks).unwrap();
|
||||||
|
self.spawn_pedestrian(at, map, start, rng);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pick_goal<R: Rng + ?Sized>(rng: &mut R, map: &Map, start: LaneID) -> LaneID {
|
||||||
|
let lane_type = map.get_l(start).lane_type;
|
||||||
|
let candidate_goals: Vec<LaneID> = map.all_lanes()
|
||||||
|
.iter()
|
||||||
|
.filter_map(|l| {
|
||||||
|
if l.lane_type != lane_type || l.id == start {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(l.id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
*rng.choose(&candidate_goals).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn calculate_paths(requested_paths: &Vec<(LaneID, LaneID)>, map: &Map) -> Vec<Option<Vec<LaneID>>> {
|
||||||
|
use rayon::prelude::*;
|
||||||
|
|
||||||
|
println!("Calculating {} paths", requested_paths.len());
|
||||||
|
// TODO better timer macro
|
||||||
|
let timer = Instant::now();
|
||||||
|
let paths: Vec<Option<Vec<LaneID>>> = requested_paths
|
||||||
|
.par_iter()
|
||||||
|
.map(|(start, goal)| map_model::pathfind(map, *start, *goal))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
println!(
|
||||||
|
"Calculating {} paths took {:?}",
|
||||||
|
paths.len(),
|
||||||
|
timer.elapsed()
|
||||||
|
);
|
||||||
|
paths
|
||||||
}
|
}
|
||||||
|
@ -147,8 +147,6 @@ pub struct WalkingSimState {
|
|||||||
#[serde(serialize_with = "serialize_multimap")]
|
#[serde(serialize_with = "serialize_multimap")]
|
||||||
#[serde(deserialize_with = "deserialize_multimap")]
|
#[serde(deserialize_with = "deserialize_multimap")]
|
||||||
peds_per_turn: MultiMap<TurnID, PedestrianID>,
|
peds_per_turn: MultiMap<TurnID, PedestrianID>,
|
||||||
|
|
||||||
id_counter: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WalkingSimState {
|
impl WalkingSimState {
|
||||||
@ -157,7 +155,6 @@ impl WalkingSimState {
|
|||||||
peds: BTreeMap::new(),
|
peds: BTreeMap::new(),
|
||||||
peds_per_sidewalk: MultiMap::new(),
|
peds_per_sidewalk: MultiMap::new(),
|
||||||
peds_per_turn: MultiMap::new(),
|
peds_per_turn: MultiMap::new(),
|
||||||
id_counter: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,10 +269,7 @@ impl WalkingSimState {
|
|||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn seed_pedestrian(&mut self, map: &Map, mut path: VecDeque<LaneID>) {
|
pub fn seed_pedestrian(&mut self, id: PedestrianID, map: &Map, mut path: VecDeque<LaneID>) {
|
||||||
let id = PedestrianID(self.id_counter);
|
|
||||||
self.id_counter += 1;
|
|
||||||
|
|
||||||
let start = path.pop_front().unwrap();
|
let start = path.pop_front().unwrap();
|
||||||
let contraflow = is_contraflow(map, start, path[0]);
|
let contraflow = is_contraflow(map, start, path[0]);
|
||||||
self.peds.insert(
|
self.peds.insert(
|
||||||
|
Loading…
Reference in New Issue
Block a user