mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-28 08:53:26 +03:00
display when a traffic signal is in overtime
This commit is contained in:
parent
a8ee229793
commit
3f2a7d6e68
@ -157,3 +157,8 @@ Shelby and 23rd...
|
|||||||
- need to fix up IDs everywhere
|
- need to fix up IDs everywhere
|
||||||
|
|
||||||
- ... rest of map construction proceeds
|
- ... rest of map construction proceeds
|
||||||
|
|
||||||
|
## Live editing
|
||||||
|
|
||||||
|
Traffic signal changes can happen live, because weird changes will just look
|
||||||
|
like brief blips of overtime. Same for stop signs, I think...
|
||||||
|
@ -98,6 +98,7 @@ pub fn default_colors() -> HashMap<String, Color> {
|
|||||||
m.insert("sidewalk corner".to_string(), Color::grey(0.7));
|
m.insert("sidewalk corner".to_string(), Color::grey(0.7));
|
||||||
m.insert("sidewalk lines".to_string(), Color::grey(0.7));
|
m.insert("sidewalk lines".to_string(), Color::grey(0.7));
|
||||||
m.insert("signal editor panel".to_string(), Color::BLACK.alpha(0.95));
|
m.insert("signal editor panel".to_string(), Color::BLACK.alpha(0.95));
|
||||||
|
m.insert("signal overtime timer".to_string(), Color::PINK);
|
||||||
m.insert(
|
m.insert(
|
||||||
"something associated with something else".to_string(),
|
"something associated with something else".to_string(),
|
||||||
Color::PURPLE,
|
Color::PURPLE,
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use crate::objects::{Ctx, ID};
|
use crate::objects::{Ctx, ID};
|
||||||
use crate::plugins::{Plugin, PluginCtx};
|
use crate::plugins::{Plugin, PluginCtx};
|
||||||
use crate::render::{draw_signal_cycle, draw_stop_sign, stop_sign_rendering_hints, DrawTurn};
|
use crate::render::{draw_signal_cycle, draw_stop_sign, stop_sign_rendering_hints, DrawTurn};
|
||||||
use ezgui::{Color, GfxCtx};
|
use ezgui::{Color, GfxCtx, Text};
|
||||||
use geom::{Polygon, Pt2D};
|
use geom::{Polygon, Pt2D};
|
||||||
use map_model::{IntersectionID, LaneID, TurnType};
|
use map_model::{IntersectionID, LaneID, TurnType};
|
||||||
use piston::input::Key;
|
use piston::input::Key;
|
||||||
@ -34,12 +34,14 @@ impl Plugin for TurnCyclerState {
|
|||||||
self.state = State::ShowIntersection(id);
|
self.state = State::ShowIntersection(id);
|
||||||
|
|
||||||
if let Some(signal) = ctx.primary.map.maybe_get_traffic_signal(id) {
|
if let Some(signal) = ctx.primary.map.maybe_get_traffic_signal(id) {
|
||||||
let (cycle, _) =
|
|
||||||
signal.current_cycle_and_remaining_time(ctx.primary.sim.time.as_time());
|
|
||||||
ctx.hints.suppress_intersection_icon = Some(id);
|
ctx.hints.suppress_intersection_icon = Some(id);
|
||||||
ctx.hints
|
if !ctx.primary.sim.is_in_overtime(id) {
|
||||||
.hide_crosswalks
|
let (cycle, _) =
|
||||||
.extend(cycle.get_absent_crosswalks(&ctx.primary.map));
|
signal.current_cycle_and_remaining_time(ctx.primary.sim.time.as_time());
|
||||||
|
ctx.hints
|
||||||
|
.hide_crosswalks
|
||||||
|
.extend(cycle.get_absent_crosswalks(&ctx.primary.map));
|
||||||
|
}
|
||||||
} else if let Some(sign) = ctx.primary.map.maybe_get_stop_sign(id) {
|
} else if let Some(sign) = ctx.primary.map.maybe_get_stop_sign(id) {
|
||||||
stop_sign_rendering_hints(&mut ctx.hints, sign, &ctx.primary.map, ctx.cs);
|
stop_sign_rendering_hints(&mut ctx.hints, sign, &ctx.primary.map, ctx.cs);
|
||||||
}
|
}
|
||||||
@ -100,37 +102,54 @@ impl Plugin for TurnCyclerState {
|
|||||||
}
|
}
|
||||||
State::ShowIntersection(id) => {
|
State::ShowIntersection(id) => {
|
||||||
if let Some(signal) = ctx.map.maybe_get_traffic_signal(id) {
|
if let Some(signal) = ctx.map.maybe_get_traffic_signal(id) {
|
||||||
// TODO Cycle might be over-run; should depict that by asking sim layer.
|
if ctx.sim.is_in_overtime(id) {
|
||||||
let (cycle, time_left) =
|
|
||||||
signal.current_cycle_and_remaining_time(ctx.sim.time.as_time());
|
|
||||||
|
|
||||||
draw_signal_cycle(
|
|
||||||
cycle,
|
|
||||||
g,
|
|
||||||
ctx.cs,
|
|
||||||
ctx.map,
|
|
||||||
ctx.draw_map,
|
|
||||||
&ctx.hints.hide_crosswalks,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Draw a little timer box in the top-left corner of the screen.
|
|
||||||
{
|
|
||||||
let old_ctx = g.fork_screenspace();
|
let old_ctx = g.fork_screenspace();
|
||||||
let width = 50.0;
|
let width = 50.0;
|
||||||
let height = 100.0;
|
let height = 100.0;
|
||||||
g.draw_polygon(
|
g.draw_polygon(
|
||||||
ctx.cs.get_def("timer foreground", Color::RED),
|
ctx.cs.get_def("signal overtime timer", Color::PINK),
|
||||||
&Polygon::rectangle_topleft(Pt2D::new(10.0, 10.0), width, height),
|
&Polygon::rectangle_topleft(Pt2D::new(10.0, 10.0), width, height),
|
||||||
);
|
);
|
||||||
g.draw_polygon(
|
// TODO We can't use draw_text_at, because canvas doesn't know about forked
|
||||||
ctx.cs.get_def("timer background", Color::BLACK),
|
// contexts.
|
||||||
&Polygon::rectangle_topleft(
|
ctx.canvas.draw_text_at_screenspace_topleft(
|
||||||
Pt2D::new(10.0, 10.0),
|
g,
|
||||||
width,
|
Text::from_line("Overtime!".to_string()),
|
||||||
(time_left / cycle.duration).value_unsafe * height,
|
(10.0 + width / 2.0, 10.0 + height / 2.0),
|
||||||
),
|
|
||||||
);
|
);
|
||||||
g.unfork(old_ctx);
|
g.unfork(old_ctx);
|
||||||
|
} else {
|
||||||
|
let (cycle, time_left) =
|
||||||
|
signal.current_cycle_and_remaining_time(ctx.sim.time.as_time());
|
||||||
|
|
||||||
|
draw_signal_cycle(
|
||||||
|
cycle,
|
||||||
|
g,
|
||||||
|
ctx.cs,
|
||||||
|
ctx.map,
|
||||||
|
ctx.draw_map,
|
||||||
|
&ctx.hints.hide_crosswalks,
|
||||||
|
);
|
||||||
|
|
||||||
|
// Draw a little timer box in the top-left corner of the screen.
|
||||||
|
{
|
||||||
|
let old_ctx = g.fork_screenspace();
|
||||||
|
let width = 50.0;
|
||||||
|
let height = 100.0;
|
||||||
|
g.draw_polygon(
|
||||||
|
ctx.cs.get_def("timer foreground", Color::RED),
|
||||||
|
&Polygon::rectangle_topleft(Pt2D::new(10.0, 10.0), width, height),
|
||||||
|
);
|
||||||
|
g.draw_polygon(
|
||||||
|
ctx.cs.get_def("timer background", Color::BLACK),
|
||||||
|
&Polygon::rectangle_topleft(
|
||||||
|
Pt2D::new(10.0, 10.0),
|
||||||
|
width,
|
||||||
|
(time_left / cycle.duration).value_unsafe * height,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
g.unfork(old_ctx);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if let Some(sign) = ctx.map.maybe_get_stop_sign(id) {
|
} else if let Some(sign) = ctx.map.maybe_get_stop_sign(id) {
|
||||||
draw_stop_sign(sign, g, ctx.cs, ctx.map);
|
draw_stop_sign(sign, g, ctx.cs, ctx.map);
|
||||||
|
@ -26,6 +26,7 @@ impl Color {
|
|||||||
pub const CYAN: Color = Color([0.0, 1.0, 1.0, 1.0]);
|
pub const CYAN: Color = Color([0.0, 1.0, 1.0, 1.0]);
|
||||||
pub const YELLOW: Color = Color([1.0, 1.0, 0.0, 1.0]);
|
pub const YELLOW: Color = Color([1.0, 1.0, 0.0, 1.0]);
|
||||||
pub const PURPLE: Color = Color([0.5, 0.0, 0.5, 1.0]);
|
pub const PURPLE: Color = Color([0.5, 0.0, 0.5, 1.0]);
|
||||||
|
pub const PINK: Color = Color([1.0, 0.41, 0.71, 1.0]);
|
||||||
|
|
||||||
// TODO should assert stuff about the inputs
|
// TODO should assert stuff about the inputs
|
||||||
|
|
||||||
|
@ -53,6 +53,8 @@ impl<'a> GfxCtx<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Up to the caller to call unfork()!
|
// Up to the caller to call unfork()!
|
||||||
|
// TODO Canvas doesn't understand this change, so things like text drawing that use
|
||||||
|
// map_to_screen will just be confusing.
|
||||||
pub fn fork(&mut self, top_left: Pt2D, zoom: f64) -> graphics::Context {
|
pub fn fork(&mut self, top_left: Pt2D, zoom: f64) -> graphics::Context {
|
||||||
mem::replace(
|
mem::replace(
|
||||||
&mut self.ctx,
|
&mut self.ctx,
|
||||||
|
@ -166,6 +166,14 @@ impl IntersectionSimState {
|
|||||||
IntersectionPolicy::Border => HashSet::new(),
|
IntersectionPolicy::Border => HashSet::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_in_overtime(&self, id: IntersectionID) -> bool {
|
||||||
|
match self.intersections[id.0] {
|
||||||
|
IntersectionPolicy::StopSign(_) => unreachable!(),
|
||||||
|
IntersectionPolicy::TrafficSignal(ref p) => p.overtime,
|
||||||
|
IntersectionPolicy::Border => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Use an enum instead of traits so that serialization works. I couldn't figure out erased_serde.
|
// Use an enum instead of traits so that serialization works. I couldn't figure out erased_serde.
|
||||||
@ -307,6 +315,7 @@ struct TrafficSignal {
|
|||||||
id: IntersectionID,
|
id: IntersectionID,
|
||||||
accepted: BTreeSet<Request>,
|
accepted: BTreeSet<Request>,
|
||||||
requests: BTreeSet<Request>,
|
requests: BTreeSet<Request>,
|
||||||
|
overtime: bool,
|
||||||
debug: bool,
|
debug: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,6 +325,7 @@ impl TrafficSignal {
|
|||||||
id,
|
id,
|
||||||
accepted: BTreeSet::new(),
|
accepted: BTreeSet::new(),
|
||||||
requests: BTreeSet::new(),
|
requests: BTreeSet::new(),
|
||||||
|
overtime: false,
|
||||||
debug: false,
|
debug: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -334,9 +344,11 @@ impl TrafficSignal {
|
|||||||
req.agent, req.turn
|
req.agent, req.turn
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
self.overtime = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
self.overtime = false;
|
||||||
|
|
||||||
let priority_requests: BTreeSet<TurnID> = self
|
let priority_requests: BTreeSet<TurnID> = self
|
||||||
.requests
|
.requests
|
||||||
|
@ -415,6 +415,10 @@ impl Sim {
|
|||||||
self.intersection_state.get_accepted_agents(id)
|
self.intersection_state.get_accepted_agents(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_in_overtime(&self, id: IntersectionID) -> bool {
|
||||||
|
self.intersection_state.is_in_overtime(id)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_stats(&self) -> &SimStats {
|
pub fn get_stats(&self) -> &SimStats {
|
||||||
&self.stats
|
&self.stats
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user