Remove UberTurnGroup and the prototype of editing a cluster of traffic

signals using uber turn groups. #555

This was an old half-baked experiment for handling a cluster of traffic
signals.  Since then, merging intersections (by manually tagging them in
OSM for now, maybe automatically in the future) has proven better.

Removing this old code in preparation for pathfinding v2.
This commit is contained in:
Dustin Carlino 2021-04-05 10:05:27 -07:00
parent 4b1a206a43
commit 1e3708f9b4
8 changed files with 7 additions and 290 deletions

View File

@ -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<IntersectionID>,
@ -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<App> 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) {

View File

@ -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<IntersectionID>,
groups: Vec<DrawUberTurnGroup>,
group_selected: Option<usize>,
}
impl ClusterTrafficSignalEditor {
pub fn new(ctx: &mut EventCtx, app: &mut App, ic: &IntersectionCluster) -> Box<dyn State<App>> {
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<App> 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);
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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<DrawUberTurnGroup> {
let mut offset_per_lane: HashMap<LaneID, usize> = 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;

View File

@ -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};

View File

@ -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;

View File

@ -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<IntersectionID>,
pub uber_turns: Vec<UberTurn>,
@ -256,98 +254,3 @@ impl UberTurn {
pl
}
}
pub struct UberTurnGroup {
pub from: DirectedRoadID,
pub to: DirectedRoadID,
pub members: Vec<UberTurn>,
pub geom: PolyLine,
}
impl IntersectionCluster {
pub fn uber_turn_groups(&self, map: &Map) -> Vec<UberTurnGroup> {
// 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>) -> 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)
}