diff --git a/game/src/edit/mod.rs b/game/src/edit/mod.rs index bf2174de5e..f9b80a82d4 100644 --- a/game/src/edit/mod.rs +++ b/game/src/edit/mod.rs @@ -222,6 +222,17 @@ impl State for EditMode { apply_map_edits(&mut ui.primary, &ui.cs, ctx, new_edits); } } + if !ui.primary.map.get_i(id).is_closed() + && ctx + .input + .contextual_action(Key::C, "close for construction") + { + let mut new_edits = orig_edits.clone(); + new_edits.stop_sign_overrides.remove(&id); + new_edits.traffic_signal_overrides.remove(&id); + new_edits.intersections_under_construction.insert(id); + apply_map_edits(&mut ui.primary, &ui.cs, ctx, new_edits); + } } Transition::Keep diff --git a/game/src/render/intersection.rs b/game/src/render/intersection.rs index 0a7001d853..dd26f94cc4 100644 --- a/game/src/render/intersection.rs +++ b/game/src/render/intersection.rs @@ -36,6 +36,8 @@ impl DrawIntersection { default_geom.push( if i.is_border() { cs.get_def("border intersection", Color::rgb(50, 205, 50)) + } else if i.is_closed() { + cs.get("construction background") } else { cs.get_def("normal intersection", Color::grey(0.2)) }, @@ -78,6 +80,9 @@ impl DrawIntersection { } } } + IntersectionType::Construction => { + default_geom.push(cs.get("construction hatching"), i.polygon.clone()); + } IntersectionType::TrafficSignal => {} } diff --git a/game/src/render/lane.rs b/game/src/render/lane.rs index 200a3b9755..9a69cf67ed 100644 --- a/game/src/render/lane.rs +++ b/game/src/render/lane.rs @@ -53,7 +53,9 @@ impl DrawLane { LaneType::Sidewalk => cs.get_def("sidewalk", Color::grey(0.8)), LaneType::Biking => cs.get_def("bike lane", Color::rgb(15, 125, 75)), LaneType::SharedLeftTurn => cs.get("driving lane"), - LaneType::Construction => cs.get_def("construction lane", Color::rgb(255, 109, 0)), + LaneType::Construction => { + cs.get_def("construction background", Color::rgb(255, 109, 0)) + } }, polygon.clone(), ); diff --git a/game/src/render/map.rs b/game/src/render/map.rs index f181a0afcc..7062827b44 100644 --- a/game/src/render/map.rs +++ b/game/src/render/map.rs @@ -131,6 +131,8 @@ impl DrawMap { intersection_refs.sort_by_key(|i| i.get_zorder(map)); let mut all_intersections = GeomBatch::new(); for i in intersection_refs { + // TODO Would be neat to show closed intersections here, but then edits need to + // regenerate this if i.is_stop_sign() { all_intersections.push(osm_rank_to_color(cs, i.get_rank(map)), i.polygon.clone()); if false { diff --git a/map_model/src/edits.rs b/map_model/src/edits.rs index 1ee9796f0d..4252588cfe 100644 --- a/map_model/src/edits.rs +++ b/map_model/src/edits.rs @@ -1,7 +1,7 @@ use crate::{ControlStopSign, ControlTrafficSignal, IntersectionID, LaneID, LaneType}; use abstutil::Timer; use serde_derive::{Deserialize, Serialize}; -use std::collections::BTreeMap; +use std::collections::{BTreeMap, BTreeSet}; #[derive(Serialize, Deserialize, Debug, Clone)] pub struct MapEdits { @@ -14,6 +14,7 @@ pub struct MapEdits { // TODO Storing the entire thing is maybe a bit dramatic, but works for now. pub stop_sign_overrides: BTreeMap, pub traffic_signal_overrides: BTreeMap, + pub intersections_under_construction: BTreeSet, #[serde(skip_serializing, skip_deserializing)] pub dirty: bool, @@ -29,6 +30,7 @@ impl MapEdits { contraflow_lanes: BTreeMap::new(), stop_sign_overrides: BTreeMap::new(), traffic_signal_overrides: BTreeMap::new(), + intersections_under_construction: BTreeSet::new(), dirty: false, } } diff --git a/map_model/src/intersection.rs b/map_model/src/intersection.rs index f4c221689c..3e07f6b611 100644 --- a/map_model/src/intersection.rs +++ b/map_model/src/intersection.rs @@ -21,6 +21,7 @@ pub enum IntersectionType { StopSign, TrafficSignal, Border, + Construction, } #[derive(Serialize, Deserialize, Debug)] @@ -47,6 +48,10 @@ impl Intersection { self.intersection_type == IntersectionType::Border } + pub fn is_closed(&self) -> bool { + self.intersection_type == IntersectionType::Construction + } + pub fn is_stop_sign(&self) -> bool { self.intersection_type == IntersectionType::StopSign } diff --git a/map_model/src/map.rs b/map_model/src/map.rs index a75024fed7..8d4a7f71f2 100644 --- a/map_model/src/map.rs +++ b/map_model/src/map.rs @@ -114,7 +114,7 @@ impl Map { IntersectionType::TrafficSignal => { traffic_signals.insert(i.id, ControlTrafficSignal::new(&m, i.id, timer)); } - IntersectionType::Border => {} + IntersectionType::Border | IntersectionType::Construction => {} }; } m.stop_signs = stop_signs; @@ -650,6 +650,7 @@ impl Map { let mut all_stop_sign_edits: BTreeMap = BTreeMap::new(); let mut all_traffic_signals: BTreeMap = BTreeMap::new(); + let mut all_closed_intersections: BTreeSet = BTreeSet::new(); for (id, lt) in &new_edits.lane_overrides { if self.edits.lane_overrides.get(id) != Some(lt) { all_lane_edits.insert(*id, *lt); @@ -670,6 +671,11 @@ impl Map { all_traffic_signals.insert(*id, ts.clone()); } } + for id in &new_edits.intersections_under_construction { + if !self.edits.intersections_under_construction.contains(id) { + all_closed_intersections.insert(*id); + } + } // May need to revert some previous changes for id in self.edits.lane_overrides.keys() { @@ -692,13 +698,20 @@ impl Map { all_traffic_signals.insert(*id, ControlTrafficSignal::new(self, *id, timer)); } } + // TODO Be able to un-close intersections + /*for id in &self.edits.intersections_under_construction { + if !new_edits.intersections_under_construction.contains(id) { + all_closed_intersections.insert(*id); + } + }*/ timer.note(format!( - "Total diff: {} lane types, {} contraflow lanes, {} stop signs, {} traffic signals", + "Total diff: {} lane types, {} contraflow lanes, {} stop signs, {} traffic signals, {} closed intersections", all_lane_edits.len(), all_contraflow_lanes.len(), all_stop_sign_edits.len(), - all_traffic_signals.len() + all_traffic_signals.len(), + all_closed_intersections.len(), )); let mut changed_lanes = BTreeSet::new(); @@ -797,6 +810,10 @@ impl Map { delete_turns.insert(id); } + if i.is_closed() { + continue; + } + for t in make::make_all_turns(i, &self.roads, &self.lanes, timer) { add_turns.insert(t.id); i.turns.push(t.id); @@ -818,7 +835,7 @@ impl Map { self.traffic_signals .insert(id, ControlTrafficSignal::new(self, id, timer)); } - IntersectionType::Border => unreachable!(), + IntersectionType::Border | IntersectionType::Construction => unreachable!(), } } @@ -842,6 +859,14 @@ impl Map { changed_lanes.insert(*l); } } + for id in all_closed_intersections { + let i = &mut self.intersections[id.0]; + i.intersection_type = IntersectionType::Construction; + for id in i.turns.drain(..) { + self.turns.remove(&id).unwrap(); + delete_turns.insert(id); + } + } self.edits = new_edits; self.pathfinder_dirty = true; @@ -1087,6 +1112,9 @@ fn make_half_map( } continue; } + if i.is_closed() { + continue; + } if i.incoming_lanes.is_empty() || i.outgoing_lanes.is_empty() { timer.warn(format!("{:?} is orphaned!", i));