mirror of
https://github.com/a-b-street/abstreet.git
synced 2025-01-07 23:20:42 +03:00
preps to spawn cars anywhere along the first lane
This commit is contained in:
parent
09af9e6cda
commit
890eb070b0
@ -3,7 +3,7 @@ use crate::plugins::sim::new_des_model;
|
|||||||
use crate::plugins::{BlockingPlugin, PluginCtx};
|
use crate::plugins::{BlockingPlugin, PluginCtx};
|
||||||
use crate::render::MIN_ZOOM_FOR_DETAIL;
|
use crate::render::MIN_ZOOM_FOR_DETAIL;
|
||||||
use ezgui::{EventLoopMode, GfxCtx, Key};
|
use ezgui::{EventLoopMode, GfxCtx, Key};
|
||||||
use geom::{Duration, Speed};
|
use geom::{Distance, Duration, Speed};
|
||||||
use map_model::{LaneID, Map, Traversable};
|
use map_model::{LaneID, Map, Traversable};
|
||||||
use rand::seq::SliceRandom;
|
use rand::seq::SliceRandom;
|
||||||
use rand::{Rng, SeedableRng};
|
use rand::{Rng, SeedableRng};
|
||||||
@ -135,6 +135,12 @@ fn populate_world(start: LaneID, map: &Map) -> new_des_model::World {
|
|||||||
|
|
||||||
let mut rng = XorShiftRng::from_seed([42; 16]);
|
let mut rng = XorShiftRng::from_seed([42; 16]);
|
||||||
for source in sources {
|
for source in sources {
|
||||||
|
let len = map.get_l(source).length();
|
||||||
|
if len < new_des_model::VEHICLE_LENGTH {
|
||||||
|
println!("Can't spawn cars on {}, it's only {} long", source, len);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
for i in 0..10 {
|
for i in 0..10 {
|
||||||
let path = random_path(source, &mut rng, map);
|
let path = random_path(source, &mut rng, map);
|
||||||
|
|
||||||
@ -150,6 +156,11 @@ fn populate_world(start: LaneID, map: &Map) -> new_des_model::World {
|
|||||||
max_speed,
|
max_speed,
|
||||||
path.clone(),
|
path.clone(),
|
||||||
Duration::seconds(1.0) * (i as f64),
|
Duration::seconds(1.0) * (i as f64),
|
||||||
|
Distance::meters(rng.gen_range(
|
||||||
|
new_des_model::VEHICLE_LENGTH.inner_meters(),
|
||||||
|
len.inner_meters(),
|
||||||
|
)),
|
||||||
|
map,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,7 +174,8 @@ fn densely_populate_world(map: &Map) -> new_des_model::World {
|
|||||||
|
|
||||||
let mut counter = 0;
|
let mut counter = 0;
|
||||||
for l in map.all_lanes() {
|
for l in map.all_lanes() {
|
||||||
if l.is_driving() {
|
let len = l.length();
|
||||||
|
if l.is_driving() && len >= new_des_model::VEHICLE_LENGTH {
|
||||||
for i in 0..rng.gen_range(0, 5) {
|
for i in 0..rng.gen_range(0, 5) {
|
||||||
let path = random_path(l.id, &mut rng, map);
|
let path = random_path(l.id, &mut rng, map);
|
||||||
let max_speed = if rng.gen_bool(0.1) {
|
let max_speed = if rng.gen_bool(0.1) {
|
||||||
@ -177,6 +189,11 @@ fn densely_populate_world(map: &Map) -> new_des_model::World {
|
|||||||
max_speed,
|
max_speed,
|
||||||
path,
|
path,
|
||||||
Duration::seconds(1.0) * (i as f64),
|
Duration::seconds(1.0) * (i as f64),
|
||||||
|
Distance::meters(rng.gen_range(
|
||||||
|
new_des_model::VEHICLE_LENGTH.inner_meters(),
|
||||||
|
len.inner_meters(),
|
||||||
|
)),
|
||||||
|
map,
|
||||||
);
|
);
|
||||||
counter += 1;
|
counter += 1;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
use crate::plugins::sim::new_des_model::{FREEFLOW, VEHICLE_LENGTH};
|
use crate::plugins::sim::new_des_model::VEHICLE_LENGTH;
|
||||||
use ezgui::Color;
|
|
||||||
use geom::{Distance, Duration, PolyLine, Speed};
|
use geom::{Distance, Duration, PolyLine, Speed};
|
||||||
use map_model::{Map, Traversable};
|
use map_model::{Map, Traversable};
|
||||||
use sim::{CarID, DrawCarInput};
|
use sim::{CarID, DrawCarInput};
|
||||||
@ -31,7 +30,7 @@ impl Car {
|
|||||||
self.last_steps = keep;
|
self.last_steps = keep;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_draw_car(&self, front: Distance, color: Color, map: &Map) -> Option<DrawCarInput> {
|
pub fn get_draw_car(&self, front: Distance, map: &Map) -> Option<DrawCarInput> {
|
||||||
assert!(front >= Distance::ZERO);
|
assert!(front >= Distance::ZERO);
|
||||||
let body = if front >= VEHICLE_LENGTH {
|
let body = if front >= VEHICLE_LENGTH {
|
||||||
self.path[0]
|
self.path[0]
|
||||||
@ -69,10 +68,11 @@ impl Car {
|
|||||||
id: self.id,
|
id: self.id,
|
||||||
waiting_for_turn: None,
|
waiting_for_turn: None,
|
||||||
stopping_trace: None,
|
stopping_trace: None,
|
||||||
state: if color == FREEFLOW {
|
state: match self.state {
|
||||||
sim::CarState::Moving
|
// TODO Cars can be Queued behind a slow CrossingLane. Looks kind of weird.
|
||||||
} else {
|
CarState::Queued => sim::CarState::Stuck,
|
||||||
sim::CarState::Stuck
|
CarState::CrossingLane(_) => sim::CarState::Moving,
|
||||||
|
CarState::CrossingTurn(_) => sim::CarState::Moving,
|
||||||
},
|
},
|
||||||
vehicle_type: self.id.tmp_get_vehicle_type(),
|
vehicle_type: self.id.tmp_get_vehicle_type(),
|
||||||
on: self.path[0],
|
on: self.path[0],
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
pub use crate::plugins::sim::new_des_model::{Car, CarState, TimeInterval, FREEFLOW};
|
pub use crate::plugins::sim::new_des_model::{Car, CarState, TimeInterval};
|
||||||
use geom::Duration;
|
use geom::Duration;
|
||||||
use map_model::{IntersectionID, Map};
|
use map_model::{IntersectionID, Map};
|
||||||
use sim::DrawCarInput;
|
use sim::DrawCarInput;
|
||||||
@ -16,7 +16,7 @@ impl IntersectionController {
|
|||||||
CarState::CrossingTurn(ref int) => int.percent(time),
|
CarState::CrossingTurn(ref int) => int.percent(time),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
if let Some(d) = car.get_draw_car(percent * t.geom.length(), FREEFLOW, map) {
|
if let Some(d) = car.get_draw_car(percent * t.geom.length(), map) {
|
||||||
return vec![d];
|
return vec![d];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ pub struct World {
|
|||||||
queues: BTreeMap<LaneID, Queue>,
|
queues: BTreeMap<LaneID, Queue>,
|
||||||
intersections: BTreeMap<IntersectionID, IntersectionController>,
|
intersections: BTreeMap<IntersectionID, IntersectionController>,
|
||||||
|
|
||||||
spawn_later: Vec<(CarID, Option<Speed>, Vec<Traversable>, Duration)>,
|
spawn_later: Vec<(CarID, Option<Speed>, Vec<Traversable>, Duration, Distance)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl World {
|
impl World {
|
||||||
@ -41,6 +41,7 @@ impl World {
|
|||||||
max_capacity: ((l.length() / (VEHICLE_LENGTH + FOLLOWING_DISTANCE)).floor()
|
max_capacity: ((l.length() / (VEHICLE_LENGTH + FOLLOWING_DISTANCE)).floor()
|
||||||
as usize)
|
as usize)
|
||||||
.max(1),
|
.max(1),
|
||||||
|
lane_len: l.length(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -124,7 +125,12 @@ impl World {
|
|||||||
pub fn get_all_draw_cars(&self, time: Duration, map: &Map) -> Vec<DrawCarInput> {
|
pub fn get_all_draw_cars(&self, time: Duration, map: &Map) -> Vec<DrawCarInput> {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
for queue in self.queues.values() {
|
for queue in self.queues.values() {
|
||||||
result.extend(queue.get_draw_cars(time, map));
|
result.extend(
|
||||||
|
queue
|
||||||
|
.get_car_positions(time)
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|(car, dist)| car.get_draw_car(dist, map)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
for i in self.intersections.values() {
|
for i in self.intersections.values() {
|
||||||
result.extend(i.get_draw_cars(time, map));
|
result.extend(i.get_draw_cars(time, map));
|
||||||
@ -140,7 +146,11 @@ impl World {
|
|||||||
) -> Vec<DrawCarInput> {
|
) -> Vec<DrawCarInput> {
|
||||||
match on {
|
match on {
|
||||||
Traversable::Lane(l) => match self.queues.get(&l) {
|
Traversable::Lane(l) => match self.queues.get(&l) {
|
||||||
Some(q) => q.get_draw_cars(time, map),
|
Some(q) => q
|
||||||
|
.get_car_positions(time)
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|(car, dist)| car.get_draw_car(dist, map))
|
||||||
|
.collect(),
|
||||||
None => Vec::new(),
|
None => Vec::new(),
|
||||||
},
|
},
|
||||||
Traversable::Turn(t) => self.intersections[&t.parent]
|
Traversable::Turn(t) => self.intersections[&t.parent]
|
||||||
@ -157,14 +167,30 @@ impl World {
|
|||||||
max_speed: Option<Speed>,
|
max_speed: Option<Speed>,
|
||||||
path: Vec<Traversable>,
|
path: Vec<Traversable>,
|
||||||
start_time: Duration,
|
start_time: Duration,
|
||||||
|
start_dist: Distance,
|
||||||
|
map: &Map,
|
||||||
) {
|
) {
|
||||||
self.spawn_later.push((id, max_speed, path, start_time));
|
if start_dist < VEHICLE_LENGTH {
|
||||||
|
panic!(
|
||||||
|
"Can't spawn a car at {}; too close to the start",
|
||||||
|
start_dist
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if start_dist >= path[0].length(map) {
|
||||||
|
panic!(
|
||||||
|
"Can't spawn a car at {}; {:?} isn't that long",
|
||||||
|
start_dist, path[0]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.spawn_later
|
||||||
|
.push((id, max_speed, path, start_time, start_dist));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step_if_needed(&mut self, time: Duration, map: &Map) {
|
pub fn step_if_needed(&mut self, time: Duration, map: &Map) {
|
||||||
// Spawn cars.
|
// Spawn cars.
|
||||||
let mut retain_spawn = Vec::new();
|
let mut retain_spawn = Vec::new();
|
||||||
for (id, max_speed, path, start_time) in self.spawn_later.drain(..) {
|
for (id, max_speed, path, start_time, start_dist) in self.spawn_later.drain(..) {
|
||||||
let first_lane = path[0].as_lane();
|
let first_lane = path[0].as_lane();
|
||||||
if time >= start_time
|
if time >= start_time
|
||||||
&& !self.queues[&first_lane].is_full()
|
&& !self.queues[&first_lane].is_full()
|
||||||
@ -190,7 +216,7 @@ impl World {
|
|||||||
last_steps: VecDeque::new(),
|
last_steps: VecDeque::new(),
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
retain_spawn.push((id, max_speed, path, start_time));
|
retain_spawn.push((id, max_speed, path, start_time, start_dist));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.spawn_later = retain_spawn;
|
self.spawn_later = retain_spawn;
|
||||||
|
@ -1,15 +1,14 @@
|
|||||||
use crate::plugins::sim::new_des_model::{
|
use crate::plugins::sim::new_des_model::{Car, CarState, FOLLOWING_DISTANCE, VEHICLE_LENGTH};
|
||||||
Car, CarState, FOLLOWING_DISTANCE, FREEFLOW, VEHICLE_LENGTH, WAITING,
|
|
||||||
};
|
|
||||||
use geom::{Distance, Duration};
|
use geom::{Distance, Duration};
|
||||||
use map_model::{LaneID, Map};
|
use map_model::LaneID;
|
||||||
use sim::DrawCarInput;
|
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
|
|
||||||
pub struct Queue {
|
pub struct Queue {
|
||||||
pub id: LaneID,
|
pub id: LaneID,
|
||||||
pub cars: VecDeque<Car>,
|
pub cars: VecDeque<Car>,
|
||||||
pub max_capacity: usize,
|
pub max_capacity: usize,
|
||||||
|
|
||||||
|
pub lane_len: Distance,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Queue {
|
impl Queue {
|
||||||
@ -21,32 +20,24 @@ impl Queue {
|
|||||||
self.cars.len() == self.max_capacity
|
self.cars.len() == self.max_capacity
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_draw_cars(&self, time: Duration, map: &Map) -> Vec<DrawCarInput> {
|
// May not return all of the cars -- some might be temporarily unable to actually enter the end
|
||||||
|
// of the road.
|
||||||
|
pub fn get_car_positions(&self, time: Duration) -> Vec<(&Car, Distance)> {
|
||||||
if self.cars.is_empty() {
|
if self.cars.is_empty() {
|
||||||
return Vec::new();
|
return Vec::new();
|
||||||
}
|
}
|
||||||
let l = map.get_l(self.id);
|
|
||||||
|
|
||||||
let mut result: Vec<DrawCarInput> = Vec::new();
|
let mut result: Vec<(&Car, Distance)> = Vec::new();
|
||||||
let mut last_car_back: Option<Distance> = None;
|
|
||||||
|
|
||||||
for car in &self.cars {
|
for car in &self.cars {
|
||||||
let (front, color) = match car.state {
|
let bound = match result.last() {
|
||||||
CarState::Queued => {
|
Some((_, last_dist)) => *last_dist - VEHICLE_LENGTH - FOLLOWING_DISTANCE,
|
||||||
if last_car_back.is_none() {
|
None => self.lane_len,
|
||||||
(l.length(), WAITING)
|
};
|
||||||
} else {
|
|
||||||
// TODO If the last car is still CrossingLane, then kinda weird to draw
|
let front = match car.state {
|
||||||
// us as queued
|
CarState::Queued => bound,
|
||||||
(last_car_back.unwrap() - FOLLOWING_DISTANCE, WAITING)
|
CarState::CrossingLane(ref i) => i.percent(time) * bound,
|
||||||
}
|
|
||||||
}
|
|
||||||
CarState::CrossingLane(ref i) => {
|
|
||||||
let bound = last_car_back
|
|
||||||
.map(|b| b - FOLLOWING_DISTANCE)
|
|
||||||
.unwrap_or_else(|| l.length());
|
|
||||||
(i.percent(time) * bound, FREEFLOW)
|
|
||||||
}
|
|
||||||
CarState::CrossingTurn(_) => unreachable!(),
|
CarState::CrossingTurn(_) => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -59,11 +50,7 @@ impl Queue {
|
|||||||
);
|
);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
result.push((car, front));
|
||||||
if let Some(d) = car.get_draw_car(front, color, map) {
|
|
||||||
result.push(d);
|
|
||||||
}
|
|
||||||
last_car_back = Some(front - VEHICLE_LENGTH);
|
|
||||||
}
|
}
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user