diff --git a/game/src/debug/uber_turns.rs b/game/src/debug/uber_turns.rs index 82f8311fbf..9356103ab5 100644 --- a/game/src/debug/uber_turns.rs +++ b/game/src/debug/uber_turns.rs @@ -12,7 +12,6 @@ use widgetry::{ use crate::app::{App, ShowEverything, Transition}; use crate::common::CommonState; -use crate::edit::ClusterTrafficSignalEditor; pub struct UberTurnPicker { members: BTreeSet, @@ -39,11 +38,6 @@ impl UberTurnPicker { .text("View uber-turns") .hotkey(Key::Enter) .build_def(ctx), - ctx.style() - .btn_outline - .text("Edit") - .hotkey(Key::E) - .build_def(ctx), ctx.style() .btn_outline .text("Detect all clusters") @@ -70,20 +64,6 @@ impl SimpleState for UberTurnPicker { } Transition::Replace(UberTurnViewer::new(ctx, app, self.members.clone(), 0, true)) } - "Edit" => { - if self.members.len() < 2 { - return Transition::Push(PopupMsg::new( - ctx, - "Error", - vec!["Select at least two intersections"], - )); - } - Transition::Replace(ClusterTrafficSignalEditor::new( - ctx, - app, - &IntersectionCluster::new(self.members.clone(), &app.primary.map).0, - )) - } "Detect all clusters" => { self.members.clear(); for ic in IntersectionCluster::find_all(&app.primary.map) { diff --git a/game/src/edit/cluster_traffic_signals.rs b/game/src/edit/cluster_traffic_signals.rs deleted file mode 100644 index cc5c526f58..0000000000 --- a/game/src/edit/cluster_traffic_signals.rs +++ /dev/null @@ -1,101 +0,0 @@ -use std::collections::BTreeSet; - -use geom::ArrowCap; -use map_gui::render::{DrawOptions, DrawUberTurnGroup, BIG_ARROW_THICKNESS}; -use map_model::{IntersectionCluster, IntersectionID}; -use widgetry::{ - DrawBaselayer, EventCtx, GeomBatch, GfxCtx, HorizontalAlignment, Key, Outcome, Panel, State, - VerticalAlignment, Widget, -}; - -use crate::app::Transition; -use crate::app::{App, ShowEverything}; - -pub struct ClusterTrafficSignalEditor { - panel: Panel, - - members: BTreeSet, - groups: Vec, - group_selected: Option, -} - -impl ClusterTrafficSignalEditor { - pub fn new(ctx: &mut EventCtx, app: &mut App, ic: &IntersectionCluster) -> Box> { - app.primary.current_selection = None; - Box::new(ClusterTrafficSignalEditor { - panel: Panel::new(Widget::row(vec![ctx - .style() - .btn_solid_primary - .text("Finish") - .hotkey(Key::Escape) - .build_def(ctx)])) - .aligned(HorizontalAlignment::Center, VerticalAlignment::Top) - .build(ctx), - groups: DrawUberTurnGroup::new(ic, &app.primary.map), - group_selected: None, - members: ic.members.clone(), - }) - } -} - -impl State for ClusterTrafficSignalEditor { - fn event(&mut self, ctx: &mut EventCtx, _: &mut App) -> Transition { - match self.panel.event(ctx) { - Outcome::Clicked(x) => match x.as_ref() { - "Finish" => { - return Transition::Pop; - } - _ => unreachable!(), - }, - _ => {} - } - - ctx.canvas_movement(); - if ctx.redo_mouseover() { - self.group_selected = None; - if let Some(pt) = ctx.canvas.get_cursor_in_map_space() { - for (idx, g) in self.groups.iter().enumerate() { - if g.block.contains_pt(pt) { - self.group_selected = Some(idx); - break; - } - } - } - } - - Transition::Keep - } - - fn draw_baselayer(&self) -> DrawBaselayer { - DrawBaselayer::Custom - } - - fn draw(&self, g: &mut GfxCtx, app: &App) { - { - let mut opts = DrawOptions::new(); - opts.suppress_traffic_signal_details - .extend(self.members.clone()); - app.draw(g, opts, &ShowEverything::new()); - } - - let mut batch = GeomBatch::new(); - for (idx, g) in self.groups.iter().enumerate() { - if Some(idx) == self.group_selected { - batch.push(app.cs.selected, g.block.clone()); - batch.push( - app.cs.selected, - g.group - .geom - .make_arrow(BIG_ARROW_THICKNESS, ArrowCap::Triangle), - ); - } else { - batch.push(app.cs.signal_turn_block_bg, g.block.clone()); - } - let arrow_color = app.cs.signal_protected_turn; - batch.push(arrow_color, g.arrow.clone()); - } - batch.draw(g); - - self.panel.draw(g); - } -} diff --git a/game/src/edit/mod.rs b/game/src/edit/mod.rs index d3ae074ab2..88f68037c3 100644 --- a/game/src/edit/mod.rs +++ b/game/src/edit/mod.rs @@ -14,7 +14,6 @@ use widgetry::{ Key, Line, Menu, Outcome, Panel, State, Text, TextExt, VerticalAlignment, Widget, }; -pub use self::cluster_traffic_signals::ClusterTrafficSignalEditor; pub use self::lanes::LaneEditor; pub use self::routes::RouteEditor; pub use self::stop_signs::StopSignEditor; @@ -26,7 +25,6 @@ use crate::debug::DebugMode; use crate::sandbox::{GameplayMode, SandboxMode, TimeWarpScreen}; mod bulk; -mod cluster_traffic_signals; mod lanes; mod routes; mod select; diff --git a/map_gui/src/render/mod.rs b/map_gui/src/render/mod.rs index 871a1bb686..35bdd8f070 100644 --- a/map_gui/src/render/mod.rs +++ b/map_gui/src/render/mod.rs @@ -14,7 +14,7 @@ use crate::render::car::DrawCar; pub use crate::render::intersection::{calculate_corners, DrawIntersection}; pub use crate::render::map::DrawMap; pub use crate::render::pedestrian::{DrawPedCrowd, DrawPedestrian}; -pub use crate::render::turn::{DrawMovement, DrawUberTurnGroup}; +pub use crate::render::turn::DrawMovement; use crate::{AppLike, ID}; mod agents; diff --git a/map_gui/src/render/turn.rs b/map_gui/src/render/turn.rs index 71a519bd88..239b95ee4a 100644 --- a/map_gui/src/render/turn.rs +++ b/map_gui/src/render/turn.rs @@ -1,10 +1,7 @@ use std::collections::{HashMap, HashSet}; use geom::{Angle, ArrowCap, Circle, Distance, PolyLine, Polygon}; -use map_model::{ - IntersectionCluster, IntersectionID, LaneID, Map, MovementID, TurnPriority, UberTurnGroup, - SIDEWALK_THICKNESS, -}; +use map_model::{IntersectionID, LaneID, Map, MovementID, TurnPriority, SIDEWALK_THICKNESS}; use widgetry::{Color, GeomBatch, Prerender}; use crate::colors::ColorScheme; @@ -181,68 +178,6 @@ impl DrawMovement { } } -pub struct DrawUberTurnGroup { - pub group: UberTurnGroup, - pub block: Polygon, - pub arrow: Polygon, -} - -impl DrawUberTurnGroup { - pub fn new(ic: &IntersectionCluster, map: &Map) -> Vec { - let mut offset_per_lane: HashMap = HashMap::new(); - let mut draw = Vec::new(); - for group in ic.uber_turn_groups(map) { - let offset = group - .members - .iter() - .map(|ut| *offset_per_lane.entry(ut.entry()).or_insert(0)) - .max() - .unwrap(); - let (pl, width) = group.src_center_and_width(map); - let (block, arrow) = make_block_geom(offset as f64, pl, width, group.angle()); - let mut seen_lanes = HashSet::new(); - for ut in &group.members { - if !seen_lanes.contains(&ut.entry()) { - *offset_per_lane.get_mut(&ut.entry()).unwrap() = offset + 1; - seen_lanes.insert(ut.entry()); - } - } - - draw.push(DrawUberTurnGroup { - group, - block, - arrow, - }); - } - draw - } -} - -// Produces (block, arrow) -fn make_block_geom(offset: f64, pl: PolyLine, width: Distance, angle: Angle) -> (Polygon, Polygon) { - let height = TURN_ICON_ARROW_LENGTH; - // Always extend the pl first to handle short entry lanes - let extension = PolyLine::must_new(vec![ - pl.last_pt(), - pl.last_pt() - .project_away(Distance::meters(500.0), pl.last_line().angle()), - ]); - let pl = pl.must_extend(extension); - let slice = pl.exact_slice(offset * height, (offset + 1.0) * height); - let block = slice.make_polygons(width); - - let arrow = { - let center = slice.middle(); - PolyLine::must_new(vec![ - center.project_away(TURN_ICON_ARROW_LENGTH / 2.0, angle.opposite()), - center.project_away(TURN_ICON_ARROW_LENGTH / 2.0, angle), - ]) - .make_arrow(Distance::meters(0.5), ArrowCap::Triangle) - }; - - (block, arrow) -} - // Produces (circle, arrow) fn make_circle_geom(offset: f64, pl: PolyLine, angle: Angle) -> (Polygon, Polygon) { let height = 2.0 * TURN_ICON_ARROW_LENGTH; diff --git a/map_model/src/lib.rs b/map_model/src/lib.rs index 9ebfc55427..0adda4ca1f 100644 --- a/map_model/src/lib.rs +++ b/map_model/src/lib.rs @@ -54,7 +54,7 @@ pub use crate::objects::turn::{ CompressedMovementID, Movement, MovementID, Turn, TurnID, TurnPriority, TurnType, }; pub use crate::objects::zone::{AccessRestrictions, Zone}; -pub use crate::pathfind::uber_turns::{IntersectionCluster, UberTurn, UberTurnGroup}; +pub use crate::pathfind::uber_turns::{IntersectionCluster, UberTurn}; use crate::pathfind::Pathfinder; pub use crate::pathfind::{Path, PathConstraints, PathRequest, PathStep, RoutingParams}; pub use crate::traversable::{Position, Traversable, MAX_BIKE_SPEED, MAX_WALKING_SPEED}; diff --git a/map_model/src/pathfind/dijkstra.rs b/map_model/src/pathfind/dijkstra.rs index c5cc3bd484..1cfa22ea8c 100644 --- a/map_model/src/pathfind/dijkstra.rs +++ b/map_model/src/pathfind/dijkstra.rs @@ -1,5 +1,7 @@ //! Pathfinding without needing to build a separate contraction hierarchy. +// TODO Dijkstra's for vehicles currently ignores uber-turns! + use std::collections::BTreeSet; use petgraph::graphmap::DiGraphMap; diff --git a/map_model/src/pathfind/uber_turns.rs b/map_model/src/pathfind/uber_turns.rs index 2dd505a08f..2031edf257 100644 --- a/map_model/src/pathfind/uber_turns.rs +++ b/map_model/src/pathfind/uber_turns.rs @@ -6,14 +6,12 @@ use std::collections::{BTreeMap, BTreeSet}; use petgraph::graphmap::UnGraphMap; use serde::{Deserialize, Serialize}; -use abstutil::MultiMap; -use geom::{Angle, Distance, PolyLine, Pt2D}; +use geom::{Distance, PolyLine}; -use crate::{DirectedRoadID, Direction, IntersectionID, LaneID, Map, TurnID}; +use crate::{IntersectionID, LaneID, Map, TurnID}; /// This only applies to VehiclePathfinder; walking through these intersections is nothing special. // TODO I haven't seen any cases yet with "interior" intersections. Some stuff might break. -#[derive(Clone, Serialize, Deserialize)] pub struct IntersectionCluster { pub members: BTreeSet, pub uber_turns: Vec, @@ -256,98 +254,3 @@ impl UberTurn { pl } } - -pub struct UberTurnGroup { - pub from: DirectedRoadID, - pub to: DirectedRoadID, - pub members: Vec, - pub geom: PolyLine, -} - -impl IntersectionCluster { - pub fn uber_turn_groups(&self, map: &Map) -> Vec { - // TODO LaneType should also be part of the grouping... the entry? exit? everything in - // between? What about mixes? - let mut groups: MultiMap<(DirectedRoadID, DirectedRoadID), usize> = MultiMap::new(); - for (idx, ut) in self.uber_turns.iter().enumerate() { - groups.insert( - ( - map.get_l(ut.entry()).get_directed_parent(map), - map.get_l(ut.exit()).get_directed_parent(map), - ), - idx, - ); - } - - let mut result = Vec::new(); - for ((from, to), member_indices) in groups.consume() { - let mut members = Vec::new(); - let mut polylines = Vec::new(); - for idx in member_indices { - polylines.push(self.uber_turns[idx].geom(map)); - members.push(self.uber_turns[idx].clone()); - } - result.push(UberTurnGroup { - from, - to, - members, - geom: group_geom(polylines), - }); - } - result - } -} - -impl UberTurnGroup { - // TODO Share code with TurnGroup - /// Polyline points FROM intersection - pub fn src_center_and_width(&self, map: &Map) -> (PolyLine, Distance) { - let r = map.get_r(self.from.id); - - let mut leftmost = Distance::meters(99999.0); - let mut rightmost = Distance::ZERO; - let mut left = Distance::ZERO; - - for (l, _, _) in r.lanes_ltr() { - let right = left + map.get_l(l).width; - - if self.members.iter().any(|ut| ut.entry() == l) { - leftmost = leftmost.min(left); - rightmost = rightmost.max(right); - } - - left = right; - } - - let mut pl = r - .get_left_side(map) - .must_shift_right((leftmost + rightmost) / 2.0); - // Point towards the intersection - if self.from.dir == Direction::Back { - pl = pl.reversed(); - } - // Flip direction, so we point away from the intersection - (pl.reversed(), rightmost - leftmost) - } - - pub fn angle(&self) -> Angle { - self.geom.first_pt().angle_to(self.geom.last_pt()) - } -} - -fn group_geom(mut polylines: Vec) -> PolyLine { - let num_pts = polylines[0].points().len(); - for pl in &polylines { - if num_pts != pl.points().len() { - return polylines.remove(0); - } - } - - let mut pts = Vec::new(); - for idx in 0..num_pts { - pts.push(Pt2D::center( - &polylines.iter().map(|pl| pl.points()[idx]).collect(), - )); - } - PolyLine::must_new(pts) -}