make stop sign editor use stop signs on the side of the road for

controls
This commit is contained in:
Dustin Carlino 2019-05-19 12:25:29 -07:00
parent 7760d42d4a
commit e6a3b02689
2 changed files with 64 additions and 88 deletions

View File

@ -2,17 +2,18 @@ use crate::common::CommonState;
use crate::edit::apply_map_edits;
use crate::game::GameState;
use crate::helpers::ID;
use crate::render::{DrawOptions, DrawTurn};
use crate::render::{DrawIntersection, DrawOptions, DrawTurn};
use crate::ui::{ShowEverything, UI};
use ezgui::{Color, EventCtx, GeomBatch, GfxCtx, Key, ModalMenu, Text};
use geom::{Angle, Distance, Polygon, Pt2D};
use geom::Polygon;
use map_model::{IntersectionID, RoadID, TurnID, TurnPriority};
use std::collections::HashMap;
pub struct StopSignEditor {
menu: ModalMenu,
id: IntersectionID,
octagons: HashMap<RoadID, Polygon>,
// (octagon, pole)
geom: HashMap<RoadID, (Polygon, Polygon)>,
selected_sign: Option<RoadID>,
selected_turn: Option<TurnID>,
}
@ -20,30 +21,16 @@ pub struct StopSignEditor {
impl StopSignEditor {
pub fn new(id: IntersectionID, ctx: &EventCtx, ui: &mut UI) -> StopSignEditor {
ui.primary.current_selection = None;
let octagons = ui
let geom = ui
.primary
.map
.get_stop_sign(id)
.roads
.iter()
.map(|(r, ss)| {
// In most cases, the lanes will all have the same last angle
let angle = ui.primary.map.get_l(ss.travel_lanes[0]).last_line().angle();
// Find the middle of the travel lanes
let center = Pt2D::center(
&ss.travel_lanes
.iter()
.map(|l| ui.primary.map.get_l(*l).last_pt())
.collect(),
);
(
*r,
make_octagon(
center.project_away(Distance::meters(2.0), angle),
Distance::meters(2.0),
angle,
),
)
let (octagon, pole) =
DrawIntersection::stop_sign_geom(ss, &ui.primary.map).unwrap();
(*r, (octagon, pole))
})
.collect();
StopSignEditor {
@ -56,7 +43,7 @@ impl StopSignEditor {
ctx,
),
id,
octagons,
geom,
selected_sign: None,
selected_turn: None,
}
@ -71,7 +58,7 @@ impl StopSignEditor {
if let Some(pt) = ctx.canvas.get_cursor_in_map_space() {
self.selected_sign = None;
self.selected_turn = None;
for (r, octagon) in &self.octagons {
for (r, (octagon, _)) in &self.geom {
if octagon.contains_pt(pt) {
self.selected_sign = Some(*r);
break;
@ -141,20 +128,23 @@ impl StopSignEditor {
let mut batch = GeomBatch::new();
for (r, octagon) in &self.octagons {
batch.push(
if Some(*r) == self.selected_sign {
state.ui.cs.get("selected")
} else if sign.roads[r].enabled {
state.ui.cs.get_def("enabled stop sign octagon", Color::RED)
} else {
state
.ui
.cs
.get_def("disabled stop sign octagon", Color::RED.alpha(0.2))
},
octagon.clone(),
);
for (r, (octagon, pole)) in &self.geom {
// The intersection will already draw enabled stop signs
if Some(*r) == self.selected_sign {
batch.push(
state.ui.cs.get_def("selected stop sign", Color::BLUE),
octagon.clone(),
);
if !sign.roads[r].enabled {
batch.push(state.ui.cs.get("stop sign pole").alpha(0.6), pole.clone());
}
} else if !sign.roads[r].enabled {
batch.push(
state.ui.cs.get("stop sign on side of road").alpha(0.6),
octagon.clone(),
);
batch.push(state.ui.cs.get("stop sign pole").alpha(0.6), pole.clone());
}
}
for t in &state.ui.primary.draw_map.get_turns(self.id, map) {
@ -197,16 +187,3 @@ impl StopSignEditor {
}
}
}
fn make_octagon(center: Pt2D, radius: Distance, facing: Angle) -> Polygon {
Polygon::new(
&(0..8)
.map(|i| {
center.project_away(
radius,
facing + Angle::new_degs(22.5 + (i * 360 / 8) as f64),
)
})
.collect(),
)
}

View File

@ -4,7 +4,7 @@ use abstutil::Timer;
use ezgui::{Color, Drawable, GeomBatch, GfxCtx, Prerender, ScreenPt, Text};
use geom::{Angle, Circle, Distance, Duration, Line, PolyLine, Polygon, Pt2D};
use map_model::{
ControlStopSign, Cycle, Intersection, IntersectionID, IntersectionType, Map, Road,
Cycle, Intersection, IntersectionID, IntersectionType, Map, Road, RoadWithStopSign,
TurnPriority, TurnType, LANE_THICKNESS,
};
use ordered_float::NotNan;
@ -55,7 +55,15 @@ impl DrawIntersection {
);
}
IntersectionType::StopSign => {
calculate_stop_sign(&mut default_geom, map, cs, map.get_stop_sign(i.id));
for (_, ss) in &map.get_stop_sign(i.id).roads {
if ss.enabled {
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);
}
}
}
}
IntersectionType::TrafficSignal => {}
}
@ -76,6 +84,33 @@ impl DrawIntersection {
draw_signal_cycle(cycle, Some(t), g, ctx);
}
}
// Returns the (octagon, pole) if there's room to draw it.
pub fn stop_sign_geom(ss: &RoadWithStopSign, map: &Map) -> Option<(Polygon, Polygon)> {
let trim_back = Distance::meters(0.7);
let rightmost = &map.get_l(*ss.travel_lanes.last().unwrap()).lane_center_pts;
if rightmost.length() < trim_back {
// TODO warn
return None;
}
let last_line = rightmost
.exact_slice(Distance::ZERO, rightmost.length() - trim_back)
.last_line()
.shift_right(1.0 * LANE_THICKNESS);
let octagon = make_octagon(last_line.pt2(), Distance::meters(1.0), last_line.angle());
let pole = Line::new(
last_line
.pt2()
.project_away(Distance::meters(1.5), last_line.angle().opposite()),
// TODO Slightly < 0.9
last_line
.pt2()
.project_away(Distance::meters(0.9), last_line.angle().opposite()),
)
.make_polygons(Distance::meters(0.3));
Some((octagon, pole))
}
}
impl Renderable for DrawIntersection {
@ -494,42 +529,6 @@ fn calculate_border_arrows(i: &Intersection, r: &Road, timer: &mut Timer) -> Vec
result
}
fn calculate_stop_sign(batch: &mut GeomBatch, map: &Map, cs: &ColorScheme, sign: &ControlStopSign) {
let trim_back = Distance::meters(0.7);
for (_, ss) in &sign.roads {
if ss.enabled {
let rightmost = &map.get_l(*ss.travel_lanes.last().unwrap()).lane_center_pts;
if rightmost.length() < trim_back {
continue;
}
let last_line = rightmost
.exact_slice(Distance::ZERO, rightmost.length() - trim_back)
.last_line()
.shift_right(1.0 * LANE_THICKNESS);
batch.push(
cs.get_def("stop sign on side of road", Color::RED),
make_octagon(last_line.pt2(), Distance::meters(1.0), last_line.angle()),
);
// A little pole for it too!
batch.push(
cs.get_def("stop sign pole", Color::grey(0.5)),
Line::new(
last_line
.pt2()
.project_away(Distance::meters(1.5), last_line.angle().opposite()),
// TODO Slightly < 0.9
last_line
.pt2()
.project_away(Distance::meters(0.9), last_line.angle().opposite()),
)
.make_polygons(Distance::meters(0.3)),
);
}
}
}
// TODO A squished octagon would look better
fn make_octagon(center: Pt2D, radius: Distance, facing: Angle) -> Polygon {
Polygon::new(