From 3198ade5d1b989bfaddfabf4f802b60a9bd65703 Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Wed, 5 Dec 2018 09:27:08 -0800 Subject: [PATCH] add a 4th turn priority... can completely ban turns. make pathfinding pay attention to this. --- editor/src/plugins/stop_sign_editor.rs | 2 ++ editor/src/plugins/traffic_signal_editor.rs | 14 ++++++++++---- map_model/src/lane.rs | 4 ++-- map_model/src/map.rs | 19 +++++++++++++++++-- map_model/src/pathfind.rs | 8 ++++++-- map_model/src/stop_signs.rs | 12 ++++++------ map_model/src/traffic_signals.rs | 9 ++++++--- map_model/src/turn.rs | 4 +++- 8 files changed, 52 insertions(+), 20 deletions(-) diff --git a/editor/src/plugins/stop_sign_editor.rs b/editor/src/plugins/stop_sign_editor.rs index ab4a113987..90fbbb9c23 100644 --- a/editor/src/plugins/stop_sign_editor.rs +++ b/editor/src/plugins/stop_sign_editor.rs @@ -84,6 +84,7 @@ impl Plugin for StopSignEditor { sign.set_priority(id, TurnPriority::Yield, map); } } + _ => {} }; map.edit_stop_sign(sign); @@ -113,6 +114,7 @@ impl Plugin for StopSignEditor { } TurnPriority::Yield => Some(ctx.cs.get("yield stop sign turn", Color::YELLOW)), TurnPriority::Stop => Some(ctx.cs.get("stop turn", Color::RED)), + TurnPriority::Banned => Some(ctx.cs.get("banned turn", Color::PURPLE)), } } _ => None, diff --git a/editor/src/plugins/traffic_signal_editor.rs b/editor/src/plugins/traffic_signal_editor.rs index a3abb4f6fd..2f515d20ca 100644 --- a/editor/src/plugins/traffic_signal_editor.rs +++ b/editor/src/plugins/traffic_signal_editor.rs @@ -129,7 +129,7 @@ impl Plugin for TrafficSignalEditor { let cycle = &mut signal.cycles[*current_cycle]; // Just one key to toggle between the 3 states let next_priority = match cycle.get_priority(id) { - TurnPriority::Stop => { + TurnPriority::Banned => { if ctx.primary.map.get_t(id).turn_type == TurnType::Crosswalk { if cycle.could_be_priority_turn(id, &ctx.primary.map) { Some(TurnPriority::Priority) @@ -144,10 +144,13 @@ impl Plugin for TrafficSignalEditor { if cycle.could_be_priority_turn(id, &ctx.primary.map) { Some(TurnPriority::Priority) } else { - Some(TurnPriority::Stop) + Some(TurnPriority::Banned) } } - TurnPriority::Priority => Some(TurnPriority::Stop), + TurnPriority::Priority => Some(TurnPriority::Banned), + TurnPriority::Stop => { + panic!("Can't have TurnPriority::Stop in a traffic signal"); + } }; if let Some(pri) = next_priority { if input.key_pressed(Key::Space, &format!("make {:?} {:?}", id, pri)) { @@ -358,9 +361,12 @@ impl Plugin for TrafficSignalEditor { TurnPriority::Yield => ctx .cs .get("yield turn in current cycle", Color::rgb(255, 105, 180)), - TurnPriority::Stop => ctx + TurnPriority::Banned => ctx .cs .get("turn conflicts with current cycle", Color::BLACK), + TurnPriority::Stop => { + panic!("Can't have TurnPriority::Stop in a traffic signal") + } }) } _ => None, diff --git a/map_model/src/lane.rs b/map_model/src/lane.rs index 4a4217f978..a62429e9de 100644 --- a/map_model/src/lane.rs +++ b/map_model/src/lane.rs @@ -9,8 +9,8 @@ use std::fmt; use {BuildingID, BusStopID, IntersectionID, RoadID}; pub const PARKING_SPOT_LENGTH: si::Meter = si::Meter { - // TODO look up a real value - value_unsafe: 10.0, + // Bit longer than the longest car. + value_unsafe: 8.0, _marker: std::marker::PhantomData, }; diff --git a/map_model/src/map.rs b/map_model/src/map.rs index dd1ebd27a5..20ce9e29e4 100644 --- a/map_model/src/map.rs +++ b/map_model/src/map.rs @@ -12,7 +12,7 @@ use std::path; use { Area, AreaID, Building, BuildingID, BusRoute, BusRouteID, BusStop, BusStopID, ControlStopSign, ControlTrafficSignal, Intersection, IntersectionID, IntersectionType, Lane, LaneID, LaneType, - Parcel, ParcelID, Road, RoadID, Turn, TurnID, LANE_THICKNESS, + Parcel, ParcelID, Road, RoadID, Turn, TurnID, TurnPriority, LANE_THICKNESS, }; #[derive(Serialize, Deserialize, Debug)] @@ -349,7 +349,8 @@ impl Map { } } - pub fn edit_stop_sign(&mut self, sign: ControlStopSign) { + pub fn edit_stop_sign(&mut self, mut sign: ControlStopSign) { + sign.changed = true; self.edits.stop_signs.insert(sign.id, sign.clone()); self.stop_signs.insert(sign.id, sign); } @@ -661,6 +662,20 @@ impl Map { } panic!("No parking lane has label {}", label); } + + pub(crate) fn is_turn_allowed(&self, t: TurnID) -> bool { + if let Some(ss) = self.stop_signs.get(&t.parent) { + ss.get_priority(t) != TurnPriority::Banned + } else if let Some(ts) = self.traffic_signals.get(&t.parent) { + ts.cycles + .iter() + .find(|c| c.get_priority(t) != TurnPriority::Banned) + .is_some() + } else { + // Border nodes have no turns... + panic!("{}'s intersection isn't a stop sign or traffic signal", t); + } + } } fn is_border(intersection: &Intersection, map: &Map) -> bool { diff --git a/map_model/src/pathfind.rs b/map_model/src/pathfind.rs index a860823727..2015782087 100644 --- a/map_model/src/pathfind.rs +++ b/map_model/src/pathfind.rs @@ -318,7 +318,9 @@ impl Pathfinder { map.get_l(l).src_i }; for (turn, next) in map.get_next_turns_and_lanes(l, endpoint).into_iter() { - if !self.can_use_bike_lanes && next.lane_type == LaneType::Biking { + if !map.is_turn_allowed(turn.id) { + // Skip + } else if !self.can_use_bike_lanes && next.lane_type == LaneType::Biking { // Skip } else if !self.can_use_bus_lanes && next.lane_type == LaneType::Bus { // Skip @@ -345,7 +347,9 @@ impl Pathfinder { // Don't forget multiple turns in a row. for (turn, next) in map.get_next_turns_and_lanes(dst.id, t.parent).into_iter() { - if !self.can_use_bike_lanes && next.lane_type == LaneType::Biking { + if !map.is_turn_allowed(turn.id) { + // Skip + } else if !self.can_use_bike_lanes && next.lane_type == LaneType::Biking { // Skip } else if !self.can_use_bus_lanes && next.lane_type == LaneType::Bus { // Skip diff --git a/map_model/src/stop_signs.rs b/map_model/src/stop_signs.rs index 2f54456fbd..0eb164087b 100644 --- a/map_model/src/stop_signs.rs +++ b/map_model/src/stop_signs.rs @@ -5,13 +5,13 @@ use {IntersectionID, LaneID, Map, TurnID, TurnPriority, TurnType}; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct ControlStopSign { pub id: IntersectionID, + // Turns may be present here as Banned. #[serde( serialize_with = "serialize_btreemap", deserialize_with = "deserialize_btreemap" )] turns: BTreeMap, - // TODO - changed: bool, + pub(crate) changed: bool, } impl ControlStopSign { @@ -26,11 +26,11 @@ impl ControlStopSign { } pub fn set_priority(&mut self, turn: TurnID, priority: TurnPriority, map: &Map) { + assert_ne!(self.turns[&turn], priority); if priority == TurnPriority::Priority { assert!(self.could_be_priority_turn(turn, map)); } self.turns.insert(turn, priority); - self.changed = true; } pub fn could_be_priority_turn(&self, id: TurnID, map: &Map) -> bool { @@ -43,15 +43,15 @@ impl ControlStopSign { } pub fn is_changed(&self) -> bool { - // TODO detect edits that've been undone, equivalent to original self.changed } + // Only Yield and Priority pub fn is_priority_lane(&self, lane: LaneID) -> bool { self.turns .iter() - .find(|(turn, pri)| turn.src == lane && **pri > TurnPriority::Stop) - .is_some() + .find(|(turn, pri)| turn.src == lane && **pri <= TurnPriority::Stop) + .is_none() } fn validate(&self, map: &Map) -> Result<(), Error> { diff --git a/map_model/src/traffic_signals.rs b/map_model/src/traffic_signals.rs index 9b70fa8664..1779189d83 100644 --- a/map_model/src/traffic_signals.rs +++ b/map_model/src/traffic_signals.rs @@ -335,7 +335,7 @@ impl Cycle { } else if self.yield_turns.contains(&t) { TurnPriority::Yield } else { - TurnPriority::Stop + TurnPriority::Banned } } @@ -354,7 +354,7 @@ impl Cycle { assert_ne!(pri, TurnPriority::Yield); self.yield_turns.remove(&t); } else { - assert_ne!(pri, TurnPriority::Stop); + assert_ne!(pri, TurnPriority::Banned); } // Now add to the new set @@ -370,7 +370,10 @@ impl Cycle { assert_ne!(turn.turn_type, TurnType::Crosswalk); self.yield_turns.insert(t); } - TurnPriority::Stop => {} + TurnPriority::Stop => { + panic!("Can't set a cycle's TurnPriority to Stop"); + } + TurnPriority::Banned => {} } } diff --git a/map_model/src/turn.rs b/map_model/src/turn.rs index 0adf420ec2..0e74c48395 100644 --- a/map_model/src/turn.rs +++ b/map_model/src/turn.rs @@ -49,8 +49,10 @@ impl TurnType { #[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy, PartialOrd)] pub enum TurnPriority { + // Can't do this turn at all! + Banned, // For stop signs: cars have to stop before doing this turn, and are accepted with the lowest priority. - // For traffic signals: can't do this turn at all. + // For traffic signals: this priority doesn't make sense; can't be used. Stop, // Cars can do this immediately if there are no previously accepted conflicting turns. Yield,