mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-26 07:52:05 +03:00
make stop sign editor use stop signs on the side of the road for
controls
This commit is contained in:
parent
7760d42d4a
commit
e6a3b02689
@ -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(),
|
||||
)
|
||||
}
|
||||
|
@ -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(
|
||||
|
Loading…
Reference in New Issue
Block a user