improve turn block rendering

This commit is contained in:
Dustin Carlino 2019-11-21 16:04:53 -08:00
parent aa1d7faa00
commit 55eead8ec7
4 changed files with 118 additions and 62 deletions

View File

@ -6,7 +6,7 @@ use crate::render::{
};
use crate::ui::{ShowEverything, UI};
use ezgui::{hotkey, Choice, Color, EventCtx, GeomBatch, GfxCtx, Key, Line, ModalMenu, Text};
use geom::{Distance, Duration};
use geom::Duration;
use map_model::{
ControlTrafficSignal, EditCmd, IntersectionID, Phase, TurnGroup, TurnID, TurnPriority, TurnType,
};
@ -219,40 +219,48 @@ impl State for TrafficSignalEditor {
for g in &self.groups {
if Some(g.group.clone()) == self.group_selected {
batch.push(Color::RED, g.block.clone());
batch.extend(
ui.cs.get_def("selected turn", Color::RED),
g.group.geom(&ui.primary.map).dashed_polygons(
BIG_ARROW_THICKNESS,
Distance::meters(1.0),
Distance::meters(0.5),
),
batch.push(ui.cs.get_def("solid selected", Color::RED), g.block.clone());
// Overwrite the original thing
batch.push(
ui.cs.get("solid selected"),
g.group
.geom(&ui.primary.map)
.make_arrow(BIG_ARROW_THICKNESS)
.unwrap(),
);
} else {
let color = match phase.get_priority_group(&g.group) {
TurnPriority::Protected => ui.cs.get("turn protected by traffic signal"),
TurnPriority::Yield => ui
.cs
.get("turn that can yield by traffic signal")
.alpha(1.0),
TurnPriority::Banned => {
ui.cs.get_def("turn not in current phase", Color::BLACK)
}
};
batch.push(color, g.block.clone());
batch.push(
ui.cs.get_def("turn block background", Color::grey(0.6)),
g.block.clone(),
);
}
let arrow_color = match phase.get_priority_group(&g.group) {
TurnPriority::Protected => ui.cs.get("turn protected by traffic signal"),
TurnPriority::Yield => ui
.cs
.get("turn that can yield by traffic signal")
.alpha(1.0),
TurnPriority::Banned => ui.cs.get_def("turn not in current phase", Color::BLACK),
};
batch.push(arrow_color, g.arrow.clone());
}
batch.draw(g);
self.diagram.draw(g, &ctx);
self.menu.draw(g);
// TODO groups...
/*if let Some(t) = self.icon_selected {
CommonState::draw_osd(g, ui, &Some(ID::Turn(t)));
} else {*/
CommonState::draw_osd(g, ui, &None);
//}
if let Some(ref group) = self.group_selected {
CommonState::draw_custom_osd(
g,
Text::from(Line(format!(
"Turn from {} to {}",
ui.primary.map.get_r(group.from).get_name(),
ui.primary.map.get_r(group.to).get_name()
))),
);
} else {
CommonState::draw_osd(g, ui, &None);
}
}
}

View File

@ -37,8 +37,6 @@ const EXTRA_SHAPE_POINT_RADIUS: Distance = Distance::const_meters(10.0);
pub const BIG_ARROW_THICKNESS: Distance = Distance::const_meters(0.5);
const TURN_ICON_ARROW_THICKNESS: Distance = Distance::const_meters(0.15);
const TURN_ICON_ARROW_LENGTH: Distance = Distance::const_meters(2.0);
pub const CROSSWALK_LINE_THICKNESS: Distance = Distance::const_meters(0.25);
pub const OUTLINE_THICKNESS: Distance = Distance::const_meters(0.5);

View File

@ -1,20 +1,19 @@
use crate::render::{BIG_ARROW_THICKNESS, TURN_ICON_ARROW_LENGTH};
use crate::render::BIG_ARROW_THICKNESS;
use ezgui::{Color, GeomBatch, GfxCtx};
use geom::{Distance, Line, Polygon};
use map_model::{IntersectionID, Map, RoadID, Turn, TurnGroup, LANE_THICKNESS};
use std::collections::HashMap;
use geom::{Distance, Line, PolyLine, Polygon};
use map_model::{IntersectionID, LaneID, Map, Turn, TurnGroup};
use std::collections::{HashMap, HashSet};
const TURN_ICON_ARROW_LENGTH: Distance = Distance::const_meters(2.0);
pub struct DrawTurn {}
impl DrawTurn {
pub fn full_geom(t: &Turn, batch: &mut GeomBatch, color: Color) {
batch.push(color, t.geom.make_arrow(BIG_ARROW_THICKNESS * 2.0).unwrap());
}
pub fn draw_full(t: &Turn, g: &mut GfxCtx, color: Color) {
let mut batch = GeomBatch::new();
DrawTurn::full_geom(t, &mut batch, color);
batch.draw(g);
g.draw_polygon(
color,
&t.geom.make_arrow(BIG_ARROW_THICKNESS * 2.0).unwrap(),
);
}
// TODO make a polyline.dashed or something
@ -45,41 +44,56 @@ impl DrawTurn {
}
}
// TODO Don't store these in DrawMap; just generate when we hop into the traffic signal editor.
// Simplifies apply_map_edits!
pub struct DrawTurnGroup {
pub group: TurnGroup,
pub block: Polygon,
pub arrow: Polygon,
}
impl DrawTurnGroup {
pub fn for_i(i: IntersectionID, map: &Map) -> Vec<DrawTurnGroup> {
// TODO Sort by angle here if we want some consistency
// TODO Handle short roads
let mut offset_per_road: HashMap<RoadID, f64> = HashMap::new();
let mut offset_per_lane: HashMap<LaneID, usize> = HashMap::new();
let mut draw = Vec::new();
for group in TurnGroup::for_i(i, map) {
let offset = offset_per_road.entry(group.from).or_insert(0.5);
let offset = group
.members
.iter()
.map(|t| *offset_per_lane.entry(t.src).or_insert(0))
.max()
.unwrap() as f64;
let (pl, width) = group.src_center_and_width(map);
let slice = pl.exact_slice(
offset * TURN_ICON_ARROW_LENGTH,
(offset + 1.0) * TURN_ICON_ARROW_LENGTH,
);
let block = slice.make_polygons(width);
// TODO center it properly
let pl = {
let r = map.get_r(group.from);
if r.dst_i == i {
r.center_pts.reversed()
} else {
r.center_pts.clone()
}
let arrow = {
let angle = group.angle(map);
let center = slice.middle();
PolyLine::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))
.unwrap()
};
// TODO Not number of turns, number of source lanes
let block = pl
.exact_slice(
*offset * TURN_ICON_ARROW_LENGTH,
(*offset + 1.0) * TURN_ICON_ARROW_LENGTH,
)
.make_polygons(LANE_THICKNESS * (group.members.len() as f64));
draw.push(DrawTurnGroup { group, block });
*offset += 1.0;
let mut seen_lanes = HashSet::new();
for t in &group.members {
if !seen_lanes.contains(&t.src) {
*offset_per_lane.get_mut(&t.src).unwrap() += 1;
seen_lanes.insert(t.src);
}
}
draw.push(DrawTurnGroup {
group,
block,
arrow,
});
}
draw
}

View File

@ -1,6 +1,6 @@
use crate::{IntersectionID, LaneID, Map, RoadID};
use crate::{IntersectionID, LaneID, Map, RoadID, LANE_THICKNESS};
use abstutil::MultiMap;
use geom::{Angle, PolyLine, Pt2D};
use geom::{Angle, Distance, PolyLine, Pt2D};
use serde_derive::{Deserialize, Serialize};
use std::collections::BTreeSet;
use std::fmt;
@ -164,4 +164,40 @@ impl TurnGroup {
}
PolyLine::new(pts)
}
pub fn angle(&self, map: &Map) -> Angle {
let t = *self.members.iter().next().unwrap();
map.get_t(t).angle()
}
// Polyline points FROM intersection
pub fn src_center_and_width(&self, map: &Map) -> (PolyLine, Distance) {
let r = map.get_r(self.from);
let dir = r.dir_and_offset(self.members.iter().next().unwrap().src).0;
let pl = if dir {
r.center_pts.clone()
} else {
r.center_pts.reversed()
};
let mut offsets: Vec<usize> = self
.members
.iter()
.map(|t| r.dir_and_offset(t.src).1)
.collect();
offsets.sort();
offsets.dedup();
let offset = if offsets.len() % 2 == 0 {
// Middle of two lanes
(offsets[offsets.len() / 2] as f64) - 0.5
} else {
offsets[offsets.len() / 2] as f64
};
let pl = pl
.shift_right(LANE_THICKNESS * (0.5 + offset))
.unwrap()
.reversed();
let width = LANE_THICKNESS * ((*offsets.last().unwrap() - offsets[0] + 1) as f64);
(pl, width)
}
}