mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-01 19:27:11 +03:00
hiding crosswalks way more sanely
This commit is contained in:
parent
d4006d3e93
commit
2c7abcbc3a
@ -4,6 +4,7 @@ use geom::Pt2D;
|
||||
use map_model::{AreaID, BuildingID, BusStopID, IntersectionID, LaneID, Map, ParcelID, TurnID};
|
||||
use render::{DrawMap, ExtraShapeID};
|
||||
use sim::{AgentID, CarID, GetDrawAgents, PedestrianID, Sim, TripID};
|
||||
use std::collections::HashSet;
|
||||
|
||||
#[derive(Clone, Copy, Hash, PartialEq, Eq, Debug, PartialOrd, Ord)]
|
||||
pub enum ID {
|
||||
@ -103,6 +104,7 @@ pub struct RenderingHints {
|
||||
|
||||
// Miscellaneous cases where a plugin needs to control rendering.
|
||||
pub suppress_traffic_signal_icon: Option<IntersectionID>,
|
||||
pub hide_crosswalks: HashSet<TurnID>,
|
||||
}
|
||||
|
||||
// For plugins and rendering. Not sure what module this should live in, here seems fine.
|
||||
@ -113,8 +115,6 @@ pub struct Ctx<'a> {
|
||||
pub canvas: &'a Canvas,
|
||||
pub sim: &'a Sim,
|
||||
pub hints: &'a RenderingHints,
|
||||
// TODO This one's a slight hack
|
||||
pub current_selection: Option<ID>,
|
||||
}
|
||||
|
||||
// TODO not the right module for this, totally temp
|
||||
|
@ -1,5 +1,3 @@
|
||||
// TODO how to edit cycle time?
|
||||
|
||||
use ezgui::{Color, GfxCtx};
|
||||
use geom::{Bounds, Polygon, Pt2D};
|
||||
use map_model::{IntersectionID, TurnPriority};
|
||||
@ -7,6 +5,7 @@ use objects::{Ctx, ID};
|
||||
use piston::input::Key;
|
||||
use plugins::{Plugin, PluginCtx};
|
||||
use render::draw_signal_cycle;
|
||||
use std::collections::HashSet;
|
||||
|
||||
#[derive(PartialEq)]
|
||||
pub enum TrafficSignalEditor {
|
||||
@ -26,13 +25,12 @@ impl TrafficSignalEditor {
|
||||
impl Plugin for TrafficSignalEditor {
|
||||
fn event(&mut self, ctx: PluginCtx) -> bool {
|
||||
let input = ctx.input;
|
||||
let map = &mut ctx.primary.map;
|
||||
let selected = ctx.primary.current_selection;
|
||||
|
||||
if *self == TrafficSignalEditor::Inactive {
|
||||
match selected {
|
||||
Some(ID::Intersection(id)) => {
|
||||
if map.maybe_get_traffic_signal(id).is_some()
|
||||
if ctx.primary.map.maybe_get_traffic_signal(id).is_some()
|
||||
&& input.key_pressed(Key::E, &format!("edit traffic signal for {}", id))
|
||||
{
|
||||
*self = TrafficSignalEditor::Active {
|
||||
@ -54,10 +52,14 @@ impl Plugin for TrafficSignalEditor {
|
||||
new_state = Some(TrafficSignalEditor::Inactive);
|
||||
} else {
|
||||
ctx.hints.suppress_traffic_signal_icon = Some(*i);
|
||||
ctx.hints.hide_crosswalks.extend(
|
||||
ctx.primary.map.get_traffic_signal(*i).cycles[*current_cycle]
|
||||
.get_absent_crosswalks(ctx.primary.map.get_turns_in_intersection(*i)),
|
||||
);
|
||||
|
||||
// Change cycles
|
||||
{
|
||||
let cycles = &map.get_traffic_signal(*i).cycles;
|
||||
let cycles = &ctx.primary.map.get_traffic_signal(*i).cycles;
|
||||
if let Some(n) = input.number_chosen(
|
||||
cycles.len(),
|
||||
&format!(
|
||||
@ -74,7 +76,7 @@ impl Plugin for TrafficSignalEditor {
|
||||
// Change turns
|
||||
if let Some(ID::Turn(id)) = selected {
|
||||
if id.parent == *i {
|
||||
let mut signal = map.get_traffic_signal(*i).clone();
|
||||
let mut signal = ctx.primary.map.get_traffic_signal(*i).clone();
|
||||
{
|
||||
let cycle = &mut signal.cycles[*current_cycle];
|
||||
if cycle.get_priority(id) == TurnPriority::Priority {
|
||||
@ -84,7 +86,7 @@ impl Plugin for TrafficSignalEditor {
|
||||
) {
|
||||
cycle.remove(id);
|
||||
}
|
||||
} else if cycle.could_be_priority_turn(id, map) {
|
||||
} else if cycle.could_be_priority_turn(id, &ctx.primary.map) {
|
||||
if input.key_pressed(
|
||||
Key::Space,
|
||||
"add this turn to this cycle as priority",
|
||||
@ -100,7 +102,7 @@ impl Plugin for TrafficSignalEditor {
|
||||
}
|
||||
}
|
||||
|
||||
map.edit_traffic_signal(signal);
|
||||
ctx.primary.map.edit_traffic_signal(signal);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -116,20 +118,18 @@ impl Plugin for TrafficSignalEditor {
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx, mut ctx: Ctx) {
|
||||
fn draw(&self, g: &mut GfxCtx, ctx: Ctx) {
|
||||
if let TrafficSignalEditor::Active { i, current_cycle } = self {
|
||||
let cycles = &ctx.map.get_traffic_signal(*i).cycles;
|
||||
|
||||
draw_signal_cycle(
|
||||
&cycles[*current_cycle],
|
||||
*i,
|
||||
if ctx.current_selection == Some(ID::Intersection(*i)) {
|
||||
ctx.cs.get("selected", Color::BLUE)
|
||||
} else {
|
||||
ctx.cs.get("unchanged intersection", Color::grey(0.6))
|
||||
},
|
||||
g,
|
||||
&mut ctx,
|
||||
ctx.cs,
|
||||
ctx.map,
|
||||
ctx.draw_map,
|
||||
&ctx.hints.hide_crosswalks,
|
||||
);
|
||||
|
||||
// Draw all of the cycles off to the side
|
||||
@ -148,14 +148,9 @@ impl Plugin for TrafficSignalEditor {
|
||||
)
|
||||
};
|
||||
|
||||
let panel_bg_color = ctx.cs.get("signal editor panel", Color::BLACK.alpha(0.95));
|
||||
let panel_selected_color = ctx.cs.get(
|
||||
"current cycle in signal editor panel",
|
||||
Color::BLUE.alpha(0.95),
|
||||
);
|
||||
let old_ctx = g.fork_screenspace();
|
||||
g.draw_polygon(
|
||||
panel_bg_color,
|
||||
ctx.cs.get("signal editor panel", Color::BLACK.alpha(0.95)),
|
||||
&Polygon::rectangle_topleft(
|
||||
Pt2D::new(10.0, 10.0),
|
||||
width * zoom,
|
||||
@ -165,7 +160,10 @@ impl Plugin for TrafficSignalEditor {
|
||||
// TODO Padding and offsets all a bit off. Abstractions are a bit awkward. Want to
|
||||
// center a map-space thing inside a screen-space box.
|
||||
g.draw_polygon(
|
||||
panel_selected_color,
|
||||
ctx.cs.get(
|
||||
"current cycle in signal editor panel",
|
||||
Color::BLUE.alpha(0.95),
|
||||
),
|
||||
&Polygon::rectangle_topleft(
|
||||
Pt2D::new(
|
||||
10.0,
|
||||
@ -185,16 +183,17 @@ impl Plugin for TrafficSignalEditor {
|
||||
),
|
||||
zoom,
|
||||
);
|
||||
let mut hide_crosswalks = HashSet::new();
|
||||
hide_crosswalks
|
||||
.extend(cycle.get_absent_crosswalks(ctx.map.get_turns_in_intersection(*i)));
|
||||
draw_signal_cycle(
|
||||
cycle,
|
||||
&cycle,
|
||||
*i,
|
||||
if idx == *current_cycle {
|
||||
panel_selected_color
|
||||
} else {
|
||||
panel_bg_color
|
||||
},
|
||||
g,
|
||||
&mut ctx,
|
||||
ctx.cs,
|
||||
ctx.map,
|
||||
ctx.draw_map,
|
||||
&hide_crosswalks,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,15 @@ impl Plugin for TurnCyclerState {
|
||||
Some(ID::Lane(id)) => id,
|
||||
Some(ID::Intersection(id)) => {
|
||||
*self = TurnCyclerState::Intersection(id);
|
||||
ctx.hints.suppress_traffic_signal_icon = Some(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_traffic_signal_icon = Some(id);
|
||||
ctx.hints.hide_crosswalks.extend(
|
||||
cycle.get_absent_crosswalks(ctx.primary.map.get_turns_in_intersection(id)),
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
_ => {
|
||||
@ -64,7 +72,7 @@ impl Plugin for TurnCyclerState {
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx, mut ctx: Ctx) {
|
||||
fn draw(&self, g: &mut GfxCtx, ctx: Ctx) {
|
||||
match self {
|
||||
TurnCyclerState::Inactive => {}
|
||||
TurnCyclerState::Active(l, current_turn_index) => {
|
||||
@ -96,13 +104,15 @@ impl Plugin for TurnCyclerState {
|
||||
let (cycle, time_left) =
|
||||
signal.current_cycle_and_remaining_time(ctx.sim.time.as_time());
|
||||
|
||||
// TODO Ew... there's got to be a way to prevent drawing the intersection instead
|
||||
let hide_crosswalk = if ctx.current_selection == Some(ID::Intersection(*id)) {
|
||||
ctx.cs.get("selected", Color::BLUE)
|
||||
} else {
|
||||
ctx.cs.get("unchanged intersection", Color::grey(0.6))
|
||||
};
|
||||
draw_signal_cycle(cycle, *id, hide_crosswalk, g, &mut ctx);
|
||||
draw_signal_cycle(
|
||||
cycle,
|
||||
*id,
|
||||
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.
|
||||
{
|
||||
|
@ -1,11 +1,16 @@
|
||||
use colors::ColorScheme;
|
||||
use dimensioned::si;
|
||||
use ezgui::{Color, GfxCtx};
|
||||
use geom::{Angle, Bounds, Circle, Polygon, Pt2D};
|
||||
use map_model::{
|
||||
Cycle, Intersection, IntersectionID, IntersectionType, Map, Turn, TurnType, LANE_THICKNESS,
|
||||
Cycle, Intersection, IntersectionID, IntersectionType, Map, Turn, TurnID, TurnType,
|
||||
LANE_THICKNESS,
|
||||
};
|
||||
use objects::{Ctx, ID};
|
||||
use render::{DrawCrosswalk, RenderOptions, Renderable, BIG_ARROW_THICKNESS, BIG_ARROW_TIP_LENGTH};
|
||||
use render::{
|
||||
DrawCrosswalk, DrawMap, RenderOptions, Renderable, BIG_ARROW_THICKNESS, BIG_ARROW_TIP_LENGTH,
|
||||
};
|
||||
use std::collections::HashSet;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DrawIntersection {
|
||||
@ -98,7 +103,11 @@ impl Renderable for DrawIntersection {
|
||||
g.draw_polygon(color, &self.polygon);
|
||||
|
||||
for crosswalk in &self.crosswalks {
|
||||
crosswalk.draw(g, ctx.cs.get("crosswalk", Color::WHITE));
|
||||
if !ctx.hints.hide_crosswalks.contains(&crosswalk.id1)
|
||||
&& !ctx.hints.hide_crosswalks.contains(&crosswalk.id2)
|
||||
{
|
||||
crosswalk.draw(g, ctx.cs.get("crosswalk", Color::WHITE));
|
||||
}
|
||||
}
|
||||
|
||||
for corner in &self.sidewalk_corners {
|
||||
@ -162,49 +171,34 @@ fn calculate_corners(i: IntersectionID, map: &Map) -> Vec<Polygon> {
|
||||
corners
|
||||
}
|
||||
|
||||
// TODO Taking &mut Ctx is a hack to let this be called multiple times in one plugin's draw().
|
||||
// Should really pass down individual pieces of the Ctx, or even better, make it Copy (and rethink
|
||||
// the mutable ColorScheme pattern).
|
||||
pub fn draw_signal_cycle(
|
||||
cycle: &Cycle,
|
||||
id: IntersectionID,
|
||||
hide_crosswalk: Color,
|
||||
g: &mut GfxCtx,
|
||||
ctx: &mut Ctx,
|
||||
cs: &mut ColorScheme,
|
||||
map: &Map,
|
||||
draw_map: &DrawMap,
|
||||
hide_crosswalks: &HashSet<TurnID>,
|
||||
) {
|
||||
let priority_color = ctx
|
||||
.cs
|
||||
.get("turns protected by traffic signal right now", Color::GREEN);
|
||||
let yield_color = ctx.cs.get(
|
||||
let priority_color = cs.get("turns protected by traffic signal right now", Color::GREEN);
|
||||
let yield_color = cs.get(
|
||||
"turns allowed with yielding by traffic signal right now",
|
||||
Color::rgba(255, 105, 180, 0.8),
|
||||
);
|
||||
|
||||
// First over-draw the crosswalks.
|
||||
// TODO Should this use the color_for system? Really want to show/hide...
|
||||
for crosswalk in &ctx.draw_map.get_i(id).crosswalks {
|
||||
let color = if cycle.priority_turns.contains(&crosswalk.id1)
|
||||
|| cycle.priority_turns.contains(&crosswalk.id2)
|
||||
{
|
||||
ctx.cs.get("crosswalk", Color::WHITE)
|
||||
} else if cycle.yield_turns.contains(&crosswalk.id1)
|
||||
|| cycle.yield_turns.contains(&crosswalk.id2)
|
||||
{
|
||||
panic!("Crosswalks shouldn't ever yield")
|
||||
} else {
|
||||
hide_crosswalk
|
||||
};
|
||||
crosswalk.draw(g, color);
|
||||
for crosswalk in &draw_map.get_i(id).crosswalks {
|
||||
if !hide_crosswalks.contains(&crosswalk.id1) && !hide_crosswalks.contains(&crosswalk.id2) {
|
||||
crosswalk.draw(g, cs.get("crosswalk", Color::WHITE));
|
||||
}
|
||||
}
|
||||
|
||||
for t in &cycle.priority_turns {
|
||||
let turn = ctx.map.get_t(*t);
|
||||
let turn = map.get_t(*t);
|
||||
if !turn.between_sidewalks() {
|
||||
draw_full(turn, g, priority_color);
|
||||
}
|
||||
}
|
||||
for t in &cycle.yield_turns {
|
||||
let turn = ctx.map.get_t(*t);
|
||||
let turn = map.get_t(*t);
|
||||
if !turn.between_sidewalks() {
|
||||
for poly in turn
|
||||
.geom
|
||||
|
@ -20,6 +20,7 @@ use render::{DrawMap, RenderOptions};
|
||||
use sim;
|
||||
use sim::{GetDrawAgents, Sim, SimFlags, Tick};
|
||||
use std::cell::RefCell;
|
||||
use std::collections::HashSet;
|
||||
use std::panic;
|
||||
use std::process;
|
||||
|
||||
@ -97,7 +98,6 @@ impl GUI<RenderingHints> for UI {
|
||||
canvas: &self.canvas,
|
||||
sim: &self.primary.sim,
|
||||
hints: &hints,
|
||||
current_selection: self.primary.current_selection,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -117,7 +117,6 @@ impl GUI<RenderingHints> for UI {
|
||||
canvas: &self.canvas,
|
||||
sim: &self.primary.sim,
|
||||
hints: &hints,
|
||||
current_selection: self.primary.current_selection,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -132,7 +131,6 @@ impl GUI<RenderingHints> for UI {
|
||||
canvas: &self.canvas,
|
||||
sim: &self.primary.sim,
|
||||
hints: &hints,
|
||||
current_selection: self.primary.current_selection,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
@ -148,7 +146,6 @@ impl GUI<RenderingHints> for UI {
|
||||
canvas: &self.canvas,
|
||||
sim: &self.primary.sim,
|
||||
hints: &hints,
|
||||
current_selection: self.primary.current_selection,
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -341,6 +338,7 @@ impl UI {
|
||||
mode: EventLoopMode::InputOnly,
|
||||
osd: Text::new(),
|
||||
suppress_traffic_signal_icon: None,
|
||||
hide_crosswalks: HashSet::new(),
|
||||
};
|
||||
|
||||
// First update the camera and handle zoom
|
||||
@ -434,7 +432,6 @@ impl UI {
|
||||
canvas: &self.canvas,
|
||||
sim: &self.primary.sim,
|
||||
hints,
|
||||
current_selection: self.primary.current_selection,
|
||||
};
|
||||
if let Some(p) = self.get_active_plugin() {
|
||||
return p.color_for(id, ctx);
|
||||
|
@ -2,7 +2,7 @@ use abstutil::Error;
|
||||
use dimensioned::si;
|
||||
use std;
|
||||
use std::collections::BTreeSet;
|
||||
use {IntersectionID, Map, RoadID, TurnID, TurnPriority, TurnType};
|
||||
use {IntersectionID, Map, RoadID, Turn, TurnID, TurnPriority, TurnType};
|
||||
|
||||
const CYCLE_DURATION: si::Second<f64> = si::Second {
|
||||
value_unsafe: 15.0,
|
||||
@ -122,6 +122,19 @@ impl Cycle {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_absent_crosswalks(&self, turns: Vec<&Turn>) -> Vec<TurnID> {
|
||||
let mut result = Vec::new();
|
||||
for t in turns.into_iter() {
|
||||
if t.between_sidewalks()
|
||||
&& !self.priority_turns.contains(&t.id)
|
||||
&& !self.yield_turns.contains(&t.id)
|
||||
{
|
||||
result.push(t.id);
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
fn greedy_assignment(map: &Map, intersection: IntersectionID) -> ControlTrafficSignal {
|
||||
|
Loading…
Reference in New Issue
Block a user