diff --git a/editor/src/plugins/sim/even_simpler_model.rs b/editor/src/plugins/sim/even_simpler_model.rs index 8da97613b2..34ea3db8a3 100644 --- a/editor/src/plugins/sim/even_simpler_model.rs +++ b/editor/src/plugins/sim/even_simpler_model.rs @@ -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; } diff --git a/editor/src/plugins/sim/new_des_model/car.rs b/editor/src/plugins/sim/new_des_model/car.rs index 9083eabe09..c76181c646 100644 --- a/editor/src/plugins/sim/new_des_model/car.rs +++ b/editor/src/plugins/sim/new_des_model/car.rs @@ -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 { + pub fn get_draw_car(&self, front: Distance, map: &Map) -> Option { 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], diff --git a/editor/src/plugins/sim/new_des_model/intersection.rs b/editor/src/plugins/sim/new_des_model/intersection.rs index 689ad55f61..c0fd7eaab3 100644 --- a/editor/src/plugins/sim/new_des_model/intersection.rs +++ b/editor/src/plugins/sim/new_des_model/intersection.rs @@ -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]; } } diff --git a/editor/src/plugins/sim/new_des_model/mod.rs b/editor/src/plugins/sim/new_des_model/mod.rs index 16d83c97f5..6d72b7391b 100644 --- a/editor/src/plugins/sim/new_des_model/mod.rs +++ b/editor/src/plugins/sim/new_des_model/mod.rs @@ -20,7 +20,7 @@ pub struct World { queues: BTreeMap, intersections: BTreeMap, - spawn_later: Vec<(CarID, Option, Vec, Duration)>, + spawn_later: Vec<(CarID, Option, Vec, 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 { 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 { 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, path: Vec, 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; diff --git a/editor/src/plugins/sim/new_des_model/queue.rs b/editor/src/plugins/sim/new_des_model/queue.rs index c7340da3bd..ed8230032f 100644 --- a/editor/src/plugins/sim/new_des_model/queue.rs +++ b/editor/src/plugins/sim/new_des_model/queue.rs @@ -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, 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 { + // 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 = Vec::new(); - let mut last_car_back: Option = 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 }