mirror of
https://github.com/a-b-street/abstreet.git
synced 2025-01-04 12:36:46 +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::render::MIN_ZOOM_FOR_DETAIL;
|
||||
use ezgui::{EventLoopMode, GfxCtx, Key};
|
||||
use geom::{Duration, Speed};
|
||||
use geom::{Distance, Duration, Speed};
|
||||
use map_model::{LaneID, Map, Traversable};
|
||||
use rand::seq::SliceRandom;
|
||||
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]);
|
||||
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 {
|
||||
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,
|
||||
path.clone(),
|
||||
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;
|
||||
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) {
|
||||
let path = random_path(l.id, &mut rng, map);
|
||||
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,
|
||||
path,
|
||||
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;
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
use crate::plugins::sim::new_des_model::{FREEFLOW, VEHICLE_LENGTH};
|
||||
use ezgui::Color;
|
||||
use crate::plugins::sim::new_des_model::VEHICLE_LENGTH;
|
||||
use geom::{Distance, Duration, PolyLine, Speed};
|
||||
use map_model::{Map, Traversable};
|
||||
use sim::{CarID, DrawCarInput};
|
||||
@ -31,7 +30,7 @@ impl Car {
|
||||
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);
|
||||
let body = if front >= VEHICLE_LENGTH {
|
||||
self.path[0]
|
||||
@ -69,10 +68,11 @@ impl Car {
|
||||
id: self.id,
|
||||
waiting_for_turn: None,
|
||||
stopping_trace: None,
|
||||
state: if color == FREEFLOW {
|
||||
sim::CarState::Moving
|
||||
} else {
|
||||
sim::CarState::Stuck
|
||||
state: match self.state {
|
||||
// TODO Cars can be Queued behind a slow CrossingLane. Looks kind of weird.
|
||||
CarState::Queued => sim::CarState::Stuck,
|
||||
CarState::CrossingLane(_) => sim::CarState::Moving,
|
||||
CarState::CrossingTurn(_) => sim::CarState::Moving,
|
||||
},
|
||||
vehicle_type: self.id.tmp_get_vehicle_type(),
|
||||
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 map_model::{IntersectionID, Map};
|
||||
use sim::DrawCarInput;
|
||||
@ -16,7 +16,7 @@ impl IntersectionController {
|
||||
CarState::CrossingTurn(ref int) => int.percent(time),
|
||||
_ => 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];
|
||||
}
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ pub struct World {
|
||||
queues: BTreeMap<LaneID, Queue>,
|
||||
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 {
|
||||
@ -41,6 +41,7 @@ impl World {
|
||||
max_capacity: ((l.length() / (VEHICLE_LENGTH + FOLLOWING_DISTANCE)).floor()
|
||||
as usize)
|
||||
.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> {
|
||||
let mut result = Vec::new();
|
||||
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() {
|
||||
result.extend(i.get_draw_cars(time, map));
|
||||
@ -140,7 +146,11 @@ impl World {
|
||||
) -> Vec<DrawCarInput> {
|
||||
match on {
|
||||
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(),
|
||||
},
|
||||
Traversable::Turn(t) => self.intersections[&t.parent]
|
||||
@ -157,14 +167,30 @@ impl World {
|
||||
max_speed: Option<Speed>,
|
||||
path: Vec<Traversable>,
|
||||
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) {
|
||||
// Spawn cars.
|
||||
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();
|
||||
if time >= start_time
|
||||
&& !self.queues[&first_lane].is_full()
|
||||
@ -190,7 +216,7 @@ impl World {
|
||||
last_steps: VecDeque::new(),
|
||||
});
|
||||
} 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;
|
||||
|
@ -1,15 +1,14 @@
|
||||
use crate::plugins::sim::new_des_model::{
|
||||
Car, CarState, FOLLOWING_DISTANCE, FREEFLOW, VEHICLE_LENGTH, WAITING,
|
||||
};
|
||||
use crate::plugins::sim::new_des_model::{Car, CarState, FOLLOWING_DISTANCE, VEHICLE_LENGTH};
|
||||
use geom::{Distance, Duration};
|
||||
use map_model::{LaneID, Map};
|
||||
use sim::DrawCarInput;
|
||||
use map_model::LaneID;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
pub struct Queue {
|
||||
pub id: LaneID,
|
||||
pub cars: VecDeque<Car>,
|
||||
pub max_capacity: usize,
|
||||
|
||||
pub lane_len: Distance,
|
||||
}
|
||||
|
||||
impl Queue {
|
||||
@ -21,32 +20,24 @@ impl Queue {
|
||||
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() {
|
||||
return Vec::new();
|
||||
}
|
||||
let l = map.get_l(self.id);
|
||||
|
||||
let mut result: Vec<DrawCarInput> = Vec::new();
|
||||
let mut last_car_back: Option<Distance> = None;
|
||||
let mut result: Vec<(&Car, Distance)> = Vec::new();
|
||||
|
||||
for car in &self.cars {
|
||||
let (front, color) = match car.state {
|
||||
CarState::Queued => {
|
||||
if last_car_back.is_none() {
|
||||
(l.length(), WAITING)
|
||||
} else {
|
||||
// TODO If the last car is still CrossingLane, then kinda weird to draw
|
||||
// us as queued
|
||||
(last_car_back.unwrap() - FOLLOWING_DISTANCE, WAITING)
|
||||
}
|
||||
}
|
||||
CarState::CrossingLane(ref i) => {
|
||||
let bound = last_car_back
|
||||
.map(|b| b - FOLLOWING_DISTANCE)
|
||||
.unwrap_or_else(|| l.length());
|
||||
(i.percent(time) * bound, FREEFLOW)
|
||||
}
|
||||
let bound = match result.last() {
|
||||
Some((_, last_dist)) => *last_dist - VEHICLE_LENGTH - FOLLOWING_DISTANCE,
|
||||
None => self.lane_len,
|
||||
};
|
||||
|
||||
let front = match car.state {
|
||||
CarState::Queued => bound,
|
||||
CarState::CrossingLane(ref i) => i.percent(time) * bound,
|
||||
CarState::CrossingTurn(_) => unreachable!(),
|
||||
};
|
||||
|
||||
@ -59,11 +50,7 @@ impl Queue {
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
if let Some(d) = car.get_draw_car(front, color, map) {
|
||||
result.push(d);
|
||||
}
|
||||
last_car_back = Some(front - VEHICLE_LENGTH);
|
||||
result.push((car, front));
|
||||
}
|
||||
result
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user