slowly moving string colors to the struct

This commit is contained in:
Dustin Carlino 2020-04-04 10:59:51 -07:00
parent fd80a7f2a9
commit 4d8ab45750
16 changed files with 179 additions and 147 deletions

View File

@ -71,10 +71,8 @@ impl Color {
Color::rgb_f(f, f, f)
}
pub fn alpha(&self, a: f32) -> Color {
let mut c = self.clone();
c.a = a;
c
pub const fn alpha(&self, a: f32) -> Color {
Color::rgba_f(self.r, self.g, self.b, a)
}
pub fn fade(&self, factor: f32) -> Color {

View File

@ -20,6 +20,41 @@ pub struct ColorScheme {
pub panel_bg: Color,
pub section_bg: Color,
pub inner_panel: Color,
// Roads
pub driving_lane: Color,
pub bus_lane: Color,
pub parking_lane: Color,
pub bike_lane: Color,
pub under_construction: Color,
pub sidewalk: Color,
pub sidewalk_lines: Color,
pub general_road_marking: Color,
pub road_center_line: Color,
// Intersections
pub border_intersection: Color,
pub border_arrow: Color,
pub normal_intersection: Color,
pub stop_sign: Color,
pub stop_sign_pole: Color,
// Unzoomed static elements
pub map_background: Color,
pub unzoomed_interesting_intersection: Color,
// Unzoomed dynamic elements
pub unzoomed_car: Color,
pub unzoomed_bike: Color,
pub unzoomed_bus: Color,
pub unzoomed_pedestrian: Color,
// Agent
pub route: Color,
pub turn_arrow: Color,
pub brake_light: Color,
pub bus_body: Color,
pub bus_label: Color,
}
// Ideal for editing; values are (hex, alpha value).
@ -31,10 +66,46 @@ impl ColorScheme {
ColorScheme {
old: HashMap::new(),
// UI
hovering: Color::ORANGE,
panel_bg: Color::grey(0.4),
section_bg: Color::grey(0.5),
inner_panel: Color::hex("#4C4C4C"),
// Roads
driving_lane: Color::BLACK,
bus_lane: Color::rgb(190, 74, 76),
parking_lane: Color::grey(0.2),
bike_lane: Color::rgb(15, 125, 75),
under_construction: Color::rgb(255, 109, 0),
sidewalk: Color::grey(0.8),
sidewalk_lines: Color::grey(0.7),
general_road_marking: Color::WHITE,
road_center_line: Color::YELLOW,
// Intersections
border_intersection: Color::rgb(50, 205, 50),
border_arrow: Color::PURPLE,
normal_intersection: Color::grey(0.2),
stop_sign: Color::RED,
stop_sign_pole: Color::grey(0.5),
// Unzoomed static elements
map_background: Color::grey(0.87),
unzoomed_interesting_intersection: Color::BLACK,
// Unzoomed dynamic elements
unzoomed_car: Color::hex("#A32015"),
unzoomed_bike: Color::hex("#5D9630"),
unzoomed_bus: Color::hex("#12409D"),
unzoomed_pedestrian: Color::hex("#DF8C3D"),
// Agents
route: Color::ORANGE.alpha(0.5),
turn_arrow: Color::hex("#DF8C3D"),
brake_light: Color::hex("#FF1300"),
bus_body: Color::rgb(50, 133, 117),
bus_label: Color::rgb(249, 206, 24),
}
}
@ -101,6 +172,19 @@ impl ColorScheme {
idx,
)
}
pub fn osm_rank_to_color(&self, rank: usize) -> Color {
if rank >= 16 {
// Highway
Color::rgb(232, 146, 162)
} else if rank >= 6 {
// Arterial
Color::rgb(255, 199, 62)
} else {
// Residential
Color::WHITE
}
}
}
include!(concat!(env!("OUT_DIR"), "/init_colors.rs"));

View File

@ -22,7 +22,7 @@ impl ShowBusRoute {
let mut txt = Text::from(Line(&route.name));
txt.add(Line(format!("{} buses", bus_locations.len())));
let color = app.cs.get("unzoomed bus");
let color = app.cs.unzoomed_bus;
let mut colorer = Colorer::new(txt, vec![("route", color)]);
for (stop1, stop2) in
route

View File

@ -414,7 +414,7 @@ fn calc_all_routes(ctx: &EventCtx, app: &mut App) -> (usize, Drawable) {
{
if let Some(t) = maybe_trace {
cnt += 1;
batch.push(app.cs.get("route"), t);
batch.push(app.cs.route, t);
}
}
(cnt, ctx.upload(batch))

View File

@ -480,10 +480,10 @@ fn throughput<F: Fn(&Analytics, Time) -> BTreeMap<TripMode, Vec<(Time, usize)>>>
fn color_for_mode(m: TripMode, app: &App) -> Color {
match m {
TripMode::Walk => app.cs.get("unzoomed pedestrian"),
TripMode::Bike => app.cs.get("unzoomed bike"),
TripMode::Transit => app.cs.get("unzoomed bus"),
TripMode::Drive => app.cs.get("unzoomed car"),
TripMode::Walk => app.cs.unzoomed_pedestrian,
TripMode::Bike => app.cs.unzoomed_bike,
TripMode::Transit => app.cs.unzoomed_bus,
TripMode::Drive => app.cs.unzoomed_car,
}
}

View File

@ -75,7 +75,7 @@ impl DrawBike {
if let Some(t) = input.waiting_for_turn {
let angle = map.get_t(t).angle();
draw_default.push(
cs.get("turn arrow"),
cs.turn_arrow,
PolyLine::new(vec![
body_pos.project_away(body_radius / 2.0, angle.opposite()),
body_pos.project_away(body_radius / 2.0, angle),

View File

@ -36,12 +36,12 @@ impl DrawBuilding {
cs.get_def("building", Color::rgb(196, 193, 188)),
bldg.polygon.clone(),
);
paths_batch.push(cs.get("sidewalk"), front_path);
paths_batch.push(cs.sidewalk, front_path);
// TODO Do similar trim_back for driveway
if let Some(ref p) = bldg.parking {
paths_batch.push(
cs.get("driving lane"),
cs.driving_lane,
p.driveway_line.make_polygons(NORMAL_LANE_THICKNESS),
);
}

View File

@ -63,7 +63,7 @@ impl DrawCar {
.dist_along(input.body.length() - Distance::meters(2.5));
draw_default.push(
cs.get_def("turn arrow", Color::hex("#DF8C3D")),
cs.turn_arrow,
PolyLine::new(vec![
pos.project_away(arrow_len / 2.0, angle.rotate_degs(90.0)),
pos.project_away(arrow_len / 2.0, angle.rotate_degs(-90.0)),
@ -78,7 +78,7 @@ impl DrawCar {
.dist_along(input.body.length() - Distance::meters(2.5));
draw_default.push(
cs.get("turn arrow"),
cs.turn_arrow,
PolyLine::new(vec![
pos.project_away(arrow_len / 2.0, angle.rotate_degs(-90.0)),
pos.project_away(arrow_len / 2.0, angle.rotate_degs(90.0)),
@ -97,7 +97,7 @@ impl DrawCar {
let window_length_gap = Distance::meters(0.2);
let window_thickness = Distance::meters(0.3);
draw_default.push(
cs.get_def("brake light", Color::hex("#FF1300")),
cs.brake_light,
thick_line_from_angle(
window_thickness,
CAR_WIDTH - window_length_gap * 2.0,
@ -115,7 +115,7 @@ impl DrawCar {
// TODO Would rotation make any sense? Or at least adjust position/size while turning.
// Buses are a constant length, so hardcoding this is fine.
draw_default.add_transformed(
Text::from(Line(line).fg(Color::rgb(249, 206, 24))).render_to_batch(prerender),
Text::from(Line(line).fg(cs.bus_label)).render_to_batch(prerender),
input.body.dist_along(Distance::meters(9.0)).0,
0.07,
Angle::ZERO,
@ -169,7 +169,7 @@ fn thick_line_from_angle(
fn zoomed_color_car(input: &DrawCarInput, cs: &ColorScheme) -> Color {
if input.id.1 == VehicleType::Bus {
cs.get_def("bus", Color::rgb(50, 133, 117))
cs.bus_body
} else {
match input.status {
CarStatus::Moving => cs.rotating_color_agents(input.id.0),

View File

@ -5,7 +5,7 @@ use crate::render::{
draw_signal_phase, DrawOptions, Renderable, CROSSWALK_LINE_THICKNESS, OUTLINE_THICKNESS,
};
use abstutil::Timer;
use ezgui::{Color, Drawable, FancyColor, GeomBatch, GfxCtx, Line, Prerender, Text};
use ezgui::{Drawable, FancyColor, GeomBatch, GfxCtx, Line, Prerender, Text};
use geom::{Angle, Distance, Line, PolyLine, Polygon, Pt2D, Time, EPSILON_DIST};
use map_model::raw::DrivingSide;
use map_model::{
@ -34,15 +34,15 @@ impl DrawIntersection {
let mut default_geom = GeomBatch::new();
default_geom.push(
if i.is_border() {
cs.get_def("border intersection", Color::rgb(50, 205, 50))
cs.border_intersection
} else if i.is_closed() {
cs.get("construction background")
cs.under_construction
} else {
cs.get_def("normal intersection", Color::grey(0.2))
cs.normal_intersection
},
i.polygon.clone(),
);
default_geom.extend(cs.get("sidewalk"), calculate_corners(i, map, timer));
default_geom.extend(cs.sidewalk, calculate_corners(i, map, timer));
for turn in &map.get_turns_in_intersection(i.id) {
// Avoid double-rendering
@ -56,18 +56,14 @@ impl DrawIntersection {
match i.intersection_type {
IntersectionType::Border => {
let r = map.get_r(*i.roads.iter().next().unwrap());
default_geom.extend(
cs.get_def("incoming border node arrow", Color::PURPLE),
calculate_border_arrows(i, r, map, timer),
);
default_geom.extend(cs.border_arrow, calculate_border_arrows(i, r, map, timer));
}
IntersectionType::StopSign => {
for ss in map.get_stop_sign(i.id).roads.values() {
if ss.must_stop {
if let Some((octagon, pole)) = DrawIntersection::stop_sign_geom(ss, map) {
default_geom
.push(cs.get_def("stop sign on side of road", Color::RED), octagon);
default_geom.push(cs.get_def("stop sign pole", Color::grey(0.5)), pole);
default_geom.push(cs.stop_sign, octagon);
default_geom.push(cs.stop_sign_pole, pole);
}
}
}
@ -335,7 +331,7 @@ pub fn make_crosswalk(batch: &mut GeomBatch, turn: &Turn, map: &Map, cs: &ColorS
// Reuse perp_line. Project away an arbitrary amount
let pt2 = pt1.project_away(Distance::meters(1.0), turn.angle());
batch.push(
cs.get("general road marking"),
cs.general_road_marking,
perp_line(Line::new(pt1, pt2), width).make_polygons(CROSSWALK_LINE_THICKNESS),
);
@ -343,7 +339,7 @@ pub fn make_crosswalk(batch: &mut GeomBatch, turn: &Turn, map: &Map, cs: &ColorS
let pt3 = line.dist_along(dist_along + 2.0 * CROSSWALK_LINE_THICKNESS);
let pt4 = pt3.project_away(Distance::meters(1.0), turn.angle());
batch.push(
cs.get("general road marking"),
cs.general_road_marking,
perp_line(Line::new(pt3, pt4), width).make_polygons(CROSSWALK_LINE_THICKNESS),
);

View File

@ -3,7 +3,7 @@ use crate::colors::ColorScheme;
use crate::helpers::ID;
use crate::render::{dashed_lines, DrawOptions, Renderable, OUTLINE_THICKNESS};
use abstutil::Timer;
use ezgui::{Color, Drawable, FancyColor, GeomBatch, GfxCtx, Prerender};
use ezgui::{Drawable, FancyColor, GeomBatch, GfxCtx, Prerender};
use geom::{Angle, Distance, Line, PolyLine, Polygon, Pt2D};
use map_model::{Lane, LaneID, LaneType, Map, Road, TurnType, PARKING_SPOT_LENGTH};
@ -90,57 +90,49 @@ impl DrawLane {
let mut draw = GeomBatch::new();
draw.push(
match lane.lane_type {
LaneType::Driving => cs.get_def("driving lane", Color::BLACK),
LaneType::Bus => cs.get_def("bus lane", Color::rgb(190, 74, 76)),
LaneType::Parking => cs.get_def("parking lane", Color::grey(0.2)),
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 background", Color::rgb(255, 109, 0))
}
LaneType::Driving => cs.driving_lane,
LaneType::Bus => cs.bus_lane,
LaneType::Parking => cs.parking_lane,
LaneType::Sidewalk => cs.sidewalk,
LaneType::Biking => cs.bike_lane,
LaneType::SharedLeftTurn => cs.driving_lane,
LaneType::Construction => cs.under_construction,
},
polygon.clone(),
);
if draw_lane_markings {
match lane.lane_type {
LaneType::Sidewalk => {
draw.extend(
cs.get_def("sidewalk lines", Color::grey(0.7)),
calculate_sidewalk_lines(lane),
);
draw.extend(cs.sidewalk_lines, calculate_sidewalk_lines(lane));
}
LaneType::Parking => {
draw.extend(
cs.get_def("general road marking", Color::WHITE),
calculate_parking_lines(map, lane),
);
draw.extend(cs.general_road_marking, calculate_parking_lines(map, lane));
}
LaneType::Driving | LaneType::Bus => {
draw.extend(
cs.get("general road marking"),
cs.general_road_marking,
calculate_driving_lines(map, lane, road, timer),
);
draw.extend(
cs.get("general road marking"),
cs.general_road_marking,
calculate_turn_markings(map, lane, timer),
);
draw.extend(
cs.get("general road marking"),
cs.general_road_marking,
calculate_one_way_markings(lane, road),
);
}
LaneType::Biking => {}
LaneType::SharedLeftTurn => {
draw.push(
cs.get("road center line"),
cs.road_center_line,
lane.lane_center_pts
.shift_right(lane.width / 2.0)
.get(timer)
.make_polygons(Distance::meters(0.25)),
);
draw.push(
cs.get("road center line"),
cs.road_center_line,
lane.lane_center_pts
.shift_left(lane.width / 2.0)
.get(timer)

View File

@ -65,15 +65,15 @@ impl DrawMap {
let mut all_roads = GeomBatch::new();
for r in road_refs {
all_roads.push(
osm_rank_to_color(cs, r.get_rank()),
cs.osm_rank_to_color(r.get_rank()),
r.get_thick_polygon(map).get(timer),
);
if false {
/*if false {
all_roads.push(
cs.get_def("unzoomed outline", Color::BLACK),
roads[r.id.0].get_outline(map),
);
}
}*/
}
let draw_all_thick_roads = all_roads.upload(ctx);
timer.stop("generate thick roads");
@ -113,18 +113,15 @@ impl DrawMap {
// 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 {
all_intersections.push(
cs.get("unzoomed outline"),
intersections[i.id.0].get_outline(map),
);
}
} else {
all_intersections.push(cs.osm_rank_to_color(i.get_rank(map)), i.polygon.clone());
/*if false {
all_intersections.push(
cs.get_def("unzoomed interesting intersection", Color::BLACK),
i.polygon.clone(),
cs.get("unzoomed outline"),
intersections[i.id.0].get_outline(map),
);
}*/
} else {
all_intersections.push(cs.unzoomed_interesting_intersection, i.polygon.clone());
}
}
let draw_all_unzoomed_intersections = all_intersections.upload(ctx);
@ -210,7 +207,7 @@ impl DrawMap {
timer.stop("upload all areas");
let boundary_polygon = ctx.prerender.upload(GeomBatch::from(vec![(
cs.get_def("map background", Color::grey(0.87)),
cs.map_background,
map.get_boundary_polygon().clone(),
)]));
@ -449,16 +446,6 @@ impl AgentCache {
}
}
fn osm_rank_to_color(cs: &ColorScheme, rank: usize) -> Color {
if rank >= 16 {
cs.get_def("unzoomed highway road", Color::rgb(232, 146, 162))
} else if rank >= 6 {
cs.get_def("unzoomed arterial road", Color::rgb(255, 199, 62))
} else {
cs.get_def("unzoomed residential road", Color::WHITE)
}
}
#[derive(PartialEq, Clone)]
pub struct AgentColorScheme {
// TODO Could consider specializing this more?
@ -469,25 +456,12 @@ impl AgentColorScheme {
pub fn new(cs: &ColorScheme) -> AgentColorScheme {
AgentColorScheme {
rows: vec![
(
"Car".to_string(),
cs.get_def("unzoomed car", Color::hex("#A32015")).alpha(0.8),
true,
),
(
"Bike".to_string(),
cs.get_def("unzoomed bike", Color::hex("#5D9630"))
.alpha(0.8),
true,
),
(
"Bus".to_string(),
cs.get_def("unzoomed bus", Color::hex("#12409D")).alpha(0.8),
true,
),
("Car".to_string(), cs.unzoomed_car.alpha(0.8), true),
("Bike".to_string(), cs.unzoomed_bike.alpha(0.8), true),
("Bus".to_string(), cs.unzoomed_bus.alpha(0.8), true),
(
"Pedestrian".to_string(),
cs.get_def("unzoomed pedestrian", Color::hex("#DF8C3D").alpha(0.8)),
cs.unzoomed_pedestrian.alpha(0.8),
true,
),
],

View File

@ -33,7 +33,7 @@ impl DrawPedestrian {
// A silly idea for peds... use hands to point at their turn?
let angle = map.get_t(t).angle();
draw_default.push(
cs.get("turn arrow"),
cs.turn_arrow,
PolyLine::new(vec![
input.pos.project_away(radius / 2.0, angle.opposite()),
input.pos.project_away(radius / 2.0, angle),

View File

@ -2,7 +2,7 @@ use crate::app::App;
use crate::colors::ColorScheme;
use crate::helpers::ID;
use crate::render::{dashed_lines, DrawOptions, Renderable};
use ezgui::{Color, Drawable, GeomBatch, GfxCtx, Line, Prerender, Text};
use ezgui::{Drawable, GeomBatch, GfxCtx, Line, Prerender, Text};
use geom::{Angle, Distance, Polygon, Pt2D};
use map_model::{LaneType, Map, Road, RoadID};
@ -25,12 +25,12 @@ impl DrawRoad {
.iter()
.all(|(_, lt)| *lt == LaneType::Parking || *lt == LaneType::Sidewalk)
{
draw.push(cs.get("road center line"), center.make_polygons(width));
draw.push(cs.road_center_line, center.make_polygons(width));
} else if r.children_forwards.is_empty()
|| r.children_forwards[0].1 != LaneType::SharedLeftTurn
{
draw.extend(
cs.get_def("road center line", Color::YELLOW),
cs.road_center_line,
dashed_lines(&center, width, Distance::meters(2.0), Distance::meters(1.0)),
);
}

View File

@ -361,9 +361,9 @@ fn pick_bus_route(ctx: &EventCtx, app: &App) -> (Widget, Vec<(String, Callback)>
// TODO Refactor
fn color_for_mode(m: TripMode, app: &App) -> Color {
match m {
TripMode::Walk => app.cs.get("unzoomed pedestrian"),
TripMode::Bike => app.cs.get("unzoomed bike"),
TripMode::Transit => app.cs.get("unzoomed bus"),
TripMode::Drive => app.cs.get("unzoomed car"),
TripMode::Walk => app.cs.unzoomed_pedestrian,
TripMode::Bike => app.cs.unzoomed_bike,
TripMode::Transit => app.cs.unzoomed_bus,
TripMode::Drive => app.cs.unzoomed_car,
}
}

View File

@ -163,10 +163,7 @@ impl State for AgentSpawner {
self.colorer.draw(g);
if let Some((_, Some(ref trace))) = self.maybe_goal {
g.draw_polygon(
app.cs.get("route"),
&trace.make_polygons(NORMAL_LANE_THICKNESS),
);
g.draw_polygon(app.cs.route, &trace.make_polygons(NORMAL_LANE_THICKNESS));
}
self.composite.draw(g);
@ -492,10 +489,7 @@ impl State for SpawnManyAgents {
self.colorer.draw(g);
if let Some((_, Some(ref trace))) = self.maybe_goal {
g.draw_polygon(
app.cs.get("route"),
&trace.make_polygons(NORMAL_LANE_THICKNESS),
);
g.draw_polygon(app.cs.route, &trace.make_polygons(NORMAL_LANE_THICKNESS));
}
self.composite.draw(g);

View File

@ -38,7 +38,7 @@ impl RoutePreview {
if let Some(trace) = app.primary.sim.trace_route(agent, &app.primary.map, None) {
let mut batch = GeomBatch::new();
batch.extend(
app.cs.get_def("route", Color::ORANGE.alpha(0.5)),
app.cs.route,
dashed_lines(
&trace,
Distance::meters(0.75),
@ -208,7 +208,7 @@ impl State for TurnExplorer {
if self.idx == 0 {
for turn in &app.primary.map.get_turns_from_lane(self.l) {
DrawTurn::draw_full(turn, g, color_turn_type(turn.turn_type, app).alpha(0.5));
DrawTurn::draw_full(turn, g, color_turn_type(turn.turn_type).alpha(0.5));
}
} else {
let current = &app.primary.map.get_turns_from_lane(self.l)[self.idx - 1];
@ -216,16 +216,12 @@ impl State for TurnExplorer {
let mut batch = GeomBatch::new();
for t in app.primary.map.get_turns_in_intersection(current.id.parent) {
if current.conflicts_with(t) {
DrawTurn::draw_dashed(
t,
&mut batch,
app.cs.get_def("conflicting turn", Color::RED.alpha(0.8)),
);
DrawTurn::draw_dashed(t, &mut batch, CONFLICTING_TURN);
}
}
batch.draw(g);
DrawTurn::draw_full(current, g, app.cs.get_def("current turn", Color::GREEN));
DrawTurn::draw_full(current, g, CURRENT_TURN);
}
self.composite.draw(g);
@ -273,48 +269,44 @@ impl TurnExplorer {
if app.primary.map.get_l(l).is_sidewalk() {
col.push(ColorLegend::row(
ctx,
app.cs.get("crosswalk turn"),
color_turn_type(TurnType::Crosswalk),
"crosswalk",
));
col.push(ColorLegend::row(
ctx,
app.cs.get("shared sidewalk corner turn"),
color_turn_type(TurnType::SharedSidewalkCorner),
"sidewalk connection",
));
} else {
col.push(ColorLegend::row(
ctx,
app.cs.get("straight turn"),
color_turn_type(TurnType::Straight),
"straight",
));
col.push(ColorLegend::row(
ctx,
app.cs.get("right turn"),
color_turn_type(TurnType::Right),
"right turn",
));
col.push(ColorLegend::row(ctx, app.cs.get("left turn"), "left turn"));
col.push(ColorLegend::row(
ctx,
app.cs.get("change lanes left turn"),
color_turn_type(TurnType::Left),
"left turn",
));
col.push(ColorLegend::row(
ctx,
color_turn_type(TurnType::LaneChangeLeft),
"straight, but lane-change left",
));
col.push(ColorLegend::row(
ctx,
app.cs.get("change lanes right turn"),
color_turn_type(TurnType::LaneChangeRight),
"straight, but lane-change right",
));
}
} else {
col.push(ColorLegend::row(
ctx,
app.cs.get("current turn"),
"current turn",
));
col.push(ColorLegend::row(
ctx,
app.cs.get("conflicting turn"),
"conflicting turn",
));
col.push(ColorLegend::row(ctx, CURRENT_TURN, "current turn"));
col.push(ColorLegend::row(ctx, CONFLICTING_TURN, "conflicting turn"));
}
Composite::new(Widget::col(col).bg(app.cs.panel_bg))
@ -323,16 +315,18 @@ impl TurnExplorer {
}
}
fn color_turn_type(t: TurnType, app: &App) -> Color {
// Since this is extremely localized and probably changing, not going to put this in ColorScheme.
fn color_turn_type(t: TurnType) -> Color {
match t {
TurnType::SharedSidewalkCorner => {
app.cs.get_def("shared sidewalk corner turn", Color::BLACK)
}
TurnType::Crosswalk => app.cs.get_def("crosswalk turn", Color::WHITE),
TurnType::Straight => app.cs.get_def("straight turn", Color::BLUE),
TurnType::LaneChangeLeft => app.cs.get_def("change lanes left turn", Color::CYAN),
TurnType::LaneChangeRight => app.cs.get_def("change lanes right turn", Color::PURPLE),
TurnType::Right => app.cs.get_def("right turn", Color::GREEN),
TurnType::Left => app.cs.get_def("left turn", Color::RED),
TurnType::SharedSidewalkCorner => Color::BLACK,
TurnType::Crosswalk => Color::WHITE,
TurnType::Straight => Color::BLUE,
TurnType::LaneChangeLeft => Color::CYAN,
TurnType::LaneChangeRight => Color::PURPLE,
TurnType::Right => Color::GREEN,
TurnType::Left => Color::RED,
}
}
const CURRENT_TURN: Color = Color::GREEN;
const CONFLICTING_TURN: Color = Color::RED.alpha(0.8);