diff --git a/game/src/edit/traffic_signals/edits.rs b/game/src/edit/traffic_signals/edits.rs index 81400d53dc..8d4bafb184 100644 --- a/game/src/edit/traffic_signals/edits.rs +++ b/game/src/edit/traffic_signals/edits.rs @@ -52,11 +52,10 @@ impl ChangeDuration { ctx, "stage type", "fixed", - "adaptive", + "variable", None, match signal.stages[idx].stage_type { StageType::Fixed(_) => true, - StageType::Adaptive(_) => false, StageType::Variable(_, _, _) => false, }, ), @@ -71,7 +70,6 @@ impl ChangeDuration { (1, 300), match signal.stages[idx].stage_type { StageType::Fixed(_) => 0, - StageType::Adaptive(_) => 0, StageType::Variable(_, _, additional) => { additional.inner_seconds() as isize } @@ -89,7 +87,6 @@ impl ChangeDuration { (1, 300), match signal.stages[idx].stage_type { StageType::Fixed(_) => 0, - StageType::Adaptive(_) => 0, StageType::Variable(_, delay, _) => delay.inner_seconds() as isize, }, ) diff --git a/game/src/edit/traffic_signals/mod.rs b/game/src/edit/traffic_signals/mod.rs index c52f65b187..c1793d8bb0 100644 --- a/game/src/edit/traffic_signals/mod.rs +++ b/game/src/edit/traffic_signals/mod.rs @@ -600,7 +600,7 @@ fn make_side_panel( let mut col = vec![txt.draw(ctx)]; col.push(Widget::horiz_separator(ctx, 0.2)); - // TODO Say "normally" to account for adaptive stages? + // TODO Say "normally" to account for variable stages? col.push( format!( "One full cycle lasts {}", @@ -643,7 +643,6 @@ fn make_side_panel( Widget::row(vec![ match canonical_stage.stage_type { StageType::Fixed(d) => format!("Stage {}: {}", idx + 1, d), - StageType::Adaptive(d) => format!("Stage {}: {} (adaptive)", idx + 1, d), StageType::Variable(min, delay, additional) => format!( "Stage {}: {}, {}, {} (variable)", idx + 1, diff --git a/game/src/edit/traffic_signals/preview.rs b/game/src/edit/traffic_signals/preview.rs index 0b0d71435d..60ecbd9547 100644 --- a/game/src/edit/traffic_signals/preview.rs +++ b/game/src/edit/traffic_signals/preview.rs @@ -94,7 +94,7 @@ pub fn make_previewer( // Start at the current stage let signal = app.primary.map.get_traffic_signal(*i); // TODO Use the offset correctly - // TODO If there are adaptive stages, this could land anywhere + // TODO If there are variable stages, this could land anywhere let mut step = Duration::ZERO; for idx in 0..stage { step += signal.stages[idx].stage_type.simple_duration(); diff --git a/game/src/info/intersection.rs b/game/src/info/intersection.rs index 42ce31eaab..9b169699ad 100644 --- a/game/src/info/intersection.rs +++ b/game/src/info/intersection.rs @@ -283,7 +283,6 @@ pub fn traffic_signal( rows.push( match stage.stage_type { StageType::Fixed(d) => Line(format!("Stage {}: {}", idx + 1, d)), - StageType::Adaptive(d) => Line(format!("Stage {}: {} (adaptive)", idx + 1, d)), StageType::Variable(min, delay, additional) => Line(format!( "Stage {}: {}, {}, {} (variable)", idx + 1, diff --git a/map_model/src/edits/compat.rs b/map_model/src/edits/compat.rs index fe3d5688b8..eb85b85c5e 100644 --- a/map_model/src/edits/compat.rs +++ b/map_model/src/edits/compat.rs @@ -68,6 +68,13 @@ pub fn upgrade(mut value: Value, map: &Map) -> Result { .unwrap() .insert("version".to_string(), Value::Number(5.into())); } + if value["version"] == Value::Number(5.into()) { + fix_adaptive_stages(&mut value); + value + .as_object_mut() + .unwrap() + .insert("version".to_string(), Value::Number(6.into())); + } abstutil::from_json(&value.to_string().into_bytes()) } @@ -253,6 +260,26 @@ fn fix_phase_to_stage(value: &mut Value) { }); } +// 34e8b0536a4517c68b0e16e5d55cb5e22dae37d8 remove adaptive signal stages. +fn fix_adaptive_stages(value: &mut Value) { + walk(value, &|map| { + if let Some(seconds) = map.remove("Adaptive") { + // The old adaptive policy would repeat the entire stage if there was any demand at + // all, so this isn't quite equivalent, since it only doubles the original time at + // most. This adaptive policy never made any sense, so capturing its behavior more + // clearly here isn't really worth it. + let minimum = seconds.clone(); + let delay = Value::Number(1.into()); + let additional = seconds; + map.insert( + "Variable".to_string(), + Value::Array(vec![minimum, delay, additional]), + ); + } + false + }); +} + // These're old structs used in fix_old_lane_cmds. #[derive(Debug, Deserialize)] struct OriginalLane { diff --git a/map_model/src/edits/perma.rs b/map_model/src/edits/perma.rs index aa10a90283..c2f6066b8b 100644 --- a/map_model/src/edits/perma.rs +++ b/map_model/src/edits/perma.rs @@ -138,7 +138,7 @@ impl MapEdits { map_name: map.get_name().clone(), edits_name: self.edits_name.clone(), // Increase this every time there's a schema change - version: 5, + version: 6, proposal_description: self.proposal_description.clone(), proposal_link: self.proposal_link.clone(), commands: self.commands.iter().map(|cmd| cmd.to_perma(map)).collect(), diff --git a/map_model/src/objects/traffic_signals.rs b/map_model/src/objects/traffic_signals.rs index 6584bf1e91..bcfac081fb 100644 --- a/map_model/src/objects/traffic_signals.rs +++ b/map_model/src/objects/traffic_signals.rs @@ -8,7 +8,6 @@ use abstutil::{deserialize_btreemap, retain_btreeset, serialize_btreemap, Timer} use geom::{Distance, Duration, Speed}; use crate::make::traffic_signals::{brute_force, get_possible_policies}; -use crate::objects::traffic_signals::StageType::{Adaptive, Fixed, Variable}; use crate::raw::OriginalRoad; use crate::{ osm, CompressedMovementID, DirectedRoadID, Direction, IntersectionID, Map, Movement, @@ -47,10 +46,6 @@ pub struct Stage { #[derive(Clone, Debug, Serialize, Deserialize, PartialEq)] pub enum StageType { Fixed(Duration), - /// Same as fixed, but when this stage would normally end, if there's still incoming demand, - /// repeat the stage entirely. - // TODO This is a silly policy, but a start towards variable timers. - Adaptive(Duration), /// Minimum is the minimum duration, 0 allows cycle to be skipped if no demand. /// Delay is the elapsed time with no demand that ends a cycle. /// Additional is the additional duration for an extended cycle. @@ -61,7 +56,7 @@ impl StageType { // TODO Maybe don't have this; force callers to acknowledge different policies pub fn simple_duration(&self) -> Duration { match self { - StageType::Fixed(d) | StageType::Adaptive(d) => *d, + StageType::Fixed(d) => *d, StageType::Variable(duration, delay, _) => { if *duration > Duration::ZERO { *duration @@ -326,9 +321,10 @@ impl Stage { ); if time > self.stage_type.simple_duration() { self.stage_type = match self.stage_type { - StageType::Adaptive(_) => Adaptive(time), - StageType::Fixed(_) => Fixed(time), - StageType::Variable(_, delay, additional) => Variable(time, delay, additional), + StageType::Fixed(_) => StageType::Fixed(time), + StageType::Variable(_, delay, additional) => { + StageType::Variable(time, delay, additional) + } }; } } @@ -356,9 +352,6 @@ impl ControlTrafficSignal { StageType::Fixed(d) => { traffic_signal_data::StageType::Fixed(d.inner_seconds() as usize) } - StageType::Adaptive(d) => { - traffic_signal_data::StageType::Adaptive(d.inner_seconds() as usize) - } StageType::Variable(min, delay, additional) => { traffic_signal_data::StageType::Variable( min.inner_seconds() as usize, @@ -411,9 +404,6 @@ impl ControlTrafficSignal { traffic_signal_data::StageType::Fixed(d) => { StageType::Fixed(Duration::seconds(d as f64)) } - traffic_signal_data::StageType::Adaptive(d) => { - StageType::Adaptive(Duration::seconds(d as f64)) - } traffic_signal_data::StageType::Variable(min, delay, additional) => { StageType::Variable( Duration::seconds(min as f64), diff --git a/sim/src/mechanics/intersection.rs b/sim/src/mechanics/intersection.rs index db7c1a2e52..b9f96144d7 100644 --- a/sim/src/mechanics/intersection.rs +++ b/sim/src/mechanics/intersection.rs @@ -74,7 +74,7 @@ struct SignalState { current_stage: usize, // The time when the signal is checked for advancing stage_ends_at: Time, - // The count of time an adaptive signal has been extended during the current stage. + // The number of times a variable signal has been extended during the current stage. extensions_count: usize, } @@ -273,27 +273,6 @@ impl IntersectionSimState { StageType::Fixed(_) => { duration = advance(signal_state, signal); } - StageType::Adaptive(_) => { - // TODO Make a better policy here. For now, if there's _anyone_ waiting to start a - // protected turn, repeat this stage for the full duration. Note that "waiting" is - // only defined as "at the end of the lane, ready to start the turn." If a - // vehicle/ped is a second away from the intersection, this won't detect that. We - // could pass in all of the Queues here and use that to count all incoming agents, - // even ones a little farther away. - if state.waiting.keys().all(|req| { - old_stage.get_priority_of_turn(req.turn, signal) != TurnPriority::Protected - }) { - duration = advance(signal_state, signal); - self.events.push(Event::Alert( - AlertLocation::Intersection(id), - "Repeating an adaptive stage".to_string(), - )); - } else { - duration = signal.stages[signal_state.current_stage] - .stage_type - .simple_duration(); - } - } StageType::Variable(min, delay, additional) => { // test if anyone is waiting in current stage, and if so, extend the signal cycle. // Filter out pedestrians, as they've had their chance and the delay diff --git a/traffic_signal_data/src/lib.rs b/traffic_signal_data/src/lib.rs index 16e4b60107..277f518e52 100644 --- a/traffic_signal_data/src/lib.rs +++ b/traffic_signal_data/src/lib.rs @@ -36,9 +36,6 @@ pub struct Stage { pub enum StageType { /// A fixed number of seconds. Fixed(usize), - /// Some multiple of a fixed number of seconds. At the end of this stage, based on incoming - /// demand, this stage may repeat. - Adaptive(usize), /// Minimum, Delay, Additional /// Minimum is the minimum cycle duration, 0 allows it to be skipped if no demand. /// Delay is the duration with no demand needed to end a cycle, 0 ends as soon as there is no