diff --git a/editor/src/common/mod.rs b/editor/src/common/mod.rs index 12a00d92f0..d442219ea2 100644 --- a/editor/src/common/mod.rs +++ b/editor/src/common/mod.rs @@ -16,29 +16,18 @@ pub use self::speed::SpeedControls; pub use self::time::time_controls; pub use self::trip_explorer::TripExplorer; use crate::game::Transition; -use crate::helpers::{rotating_color, ID}; -use crate::render::{DrawOptions, MIN_ZOOM_FOR_DETAIL}; +use crate::helpers::ID; +use crate::render::{AgentColorScheme, DrawOptions}; use crate::ui::UI; use ezgui::{ - Color, EventCtx, EventLoopMode, GeomBatch, GfxCtx, HorizontalAlignment, ModalMenu, Text, - VerticalAlignment, + Color, EventCtx, EventLoopMode, GfxCtx, HorizontalAlignment, ModalMenu, Text, VerticalAlignment, }; -use geom::{Circle, Distance, Duration}; use std::collections::BTreeSet; pub struct CommonState { associated: associated::ShowAssociatedState, turn_cycler: turn_cycler::TurnCyclerState, - agent_colors: AgentColorScheme, -} - -// TODO Have a more general colorscheme that can be changed and affect everything. Show a little -// legend when it's first activated. -#[derive(Clone, Copy, PartialEq)] -enum AgentColorScheme { - VehicleTypes, - Delay, - RemainingDistance, + agent_cs: AgentColorScheme, } impl CommonState { @@ -46,7 +35,7 @@ impl CommonState { CommonState { associated: associated::ShowAssociatedState::Inactive, turn_cycler: turn_cycler::TurnCyclerState::Inactive, - agent_colors: AgentColorScheme::VehicleTypes, + agent_cs: AgentColorScheme::VehicleTypes, } } @@ -69,14 +58,14 @@ impl CommonState { // This kind of belongs in AgentTools, except that can't influence DrawOptions as easily. // TODO This needs to be a mutex radio button style thing. if menu.action("show/hide delayed traffic") { - self.agent_colors = match self.agent_colors { + self.agent_cs = match self.agent_cs { AgentColorScheme::VehicleTypes => AgentColorScheme::Delay, AgentColorScheme::Delay => AgentColorScheme::VehicleTypes, x => x, }; } if menu.action("show/hide distance remaining") { - self.agent_colors = match self.agent_colors { + self.agent_cs = match self.agent_cs { AgentColorScheme::VehicleTypes => AgentColorScheme::RemainingDistance, AgentColorScheme::RemainingDistance => AgentColorScheme::VehicleTypes, x => x, @@ -99,30 +88,6 @@ impl CommonState { pub fn draw(&self, g: &mut GfxCtx, ui: &UI) { self.turn_cycler.draw(g, ui); - if self.agent_colors != AgentColorScheme::VehicleTypes - && g.canvas.cam_zoom < MIN_ZOOM_FOR_DETAIL - { - let mut batch = GeomBatch::new(); - let radius = Distance::meters(10.0) / g.canvas.cam_zoom; - for agent in ui - .primary - .sim - .get_unzoomed_agents_with_details(&ui.primary.map) - { - batch.push( - match self.agent_colors { - AgentColorScheme::VehicleTypes => unreachable!(), - AgentColorScheme::Delay => delay_color(agent.time_spent_blocked), - AgentColorScheme::RemainingDistance => { - percent_color(agent.percent_dist_crossed) - } - }, - Circle::new(agent.pos, radius).to_polygon(), - ); - } - batch.draw(g); - } - CommonState::draw_osd(g, ui, &ui.primary.current_selection); } @@ -220,25 +185,10 @@ impl CommonState { let mut opts = DrawOptions::new(); self.associated .override_colors(&mut opts.override_colors, ui); + opts.agent_cs = self.agent_cs; opts.suppress_traffic_signal_details = self .turn_cycler .suppress_traffic_signal_details(&ui.primary.map); - opts.suppress_unzoomed_agents = self.agent_colors != AgentColorScheme::VehicleTypes; opts } } - -fn delay_color(delay: Duration) -> Color { - // TODO Better gradient - if delay <= Duration::minutes(1) { - return Color::BLUE.alpha(0.3); - } - if delay <= Duration::minutes(5) { - return Color::ORANGE.alpha(0.5); - } - Color::RED.alpha(0.8) -} - -fn percent_color(percent: f64) -> Color { - rotating_color((percent * 10.0).round() as usize) -} diff --git a/editor/src/render/map.rs b/editor/src/render/map.rs index 9f3db7888c..b3b7d43c74 100644 --- a/editor/src/render/map.rs +++ b/editor/src/render/map.rs @@ -1,4 +1,4 @@ -use crate::helpers::{ColorScheme, ID}; +use crate::helpers::{rotating_color, ColorScheme, ID}; use crate::render::area::DrawArea; use crate::render::building::DrawBuilding; use crate::render::bus_stop::DrawBusStop; @@ -17,6 +17,7 @@ use map_model::{ AreaID, BuildingID, BusStopID, DirectedRoadID, IntersectionID, IntersectionType, Lane, LaneID, Map, RoadID, Traversable, Turn, TurnID, TurnType, LANE_THICKNESS, }; +use sim::{UnzoomedAgent, VehicleType}; use std::borrow::Borrow; use std::cell::RefCell; use std::collections::HashMap; @@ -326,11 +327,11 @@ impl DrawMap { } } -// TODO Invalidate when we interactively spawn stuff elsewhere? pub struct AgentCache { time: Option, agents_per_on: HashMap>>, - unzoomed: Option<(f64, Drawable)>, + // cam_zoom and AgentColorScheme also matter + unzoomed: Option<(f64, AgentColorScheme, Drawable)>, } impl AgentCache { @@ -359,35 +360,33 @@ impl AgentCache { self.agents_per_on.insert(on, agents); } - pub fn draw_unzoomed_agents(&mut self, primary: &PerMapUI, cs: &ColorScheme, g: &mut GfxCtx) { + pub fn draw_unzoomed_agents( + &mut self, + primary: &PerMapUI, + acs: AgentColorScheme, + cs: &ColorScheme, + g: &mut GfxCtx, + ) { let now = primary.sim.time(); - if let Some((z, ref draw)) = self.unzoomed { - if g.canvas.cam_zoom == z && Some(now) == self.time { + if let Some((z, old_acs, ref draw)) = self.unzoomed { + if g.canvas.cam_zoom == z && acs == old_acs && Some(now) == self.time { g.redraw(draw); return; } } - let (cars, bikes, buses, peds) = primary.sim.get_unzoomed_agents(&primary.map); let mut batch = GeomBatch::new(); let radius = Distance::meters(10.0) / g.canvas.cam_zoom; - for (color, agents) in vec![ - (cs.get_def("unzoomed car", Color::RED.alpha(0.5)), cars), - (cs.get_def("unzoomed bike", Color::GREEN.alpha(0.5)), bikes), - (cs.get_def("unzoomed bus", Color::BLUE.alpha(0.5)), buses), - ( - cs.get_def("unzoomed pedestrian", Color::ORANGE.alpha(0.5)), - peds, - ), - ] { - for pt in agents { - batch.push(color, Circle::new(pt, radius).to_polygon()); - } + for agent in primary.sim.get_unzoomed_agents_with_details(&primary.map) { + batch.push( + acs.color_for(&agent, cs), + Circle::new(agent.pos, radius).to_polygon(), + ); } let draw = g.upload(batch); g.redraw(&draw); - self.unzoomed = Some((g.canvas.cam_zoom, draw)); + self.unzoomed = Some((g.canvas.cam_zoom, acs, draw)); if Some(now) != self.time { self.agents_per_on.clear(); self.time = Some(now); @@ -404,3 +403,42 @@ fn osm_rank_to_color(cs: &ColorScheme, rank: usize) -> Color { cs.get_def("unzoomed residential road", Color::WHITE) } } + +// TODO Have a more general colorscheme that can be changed and affect everything. Show a little +// legend when it's first activated. +#[derive(Clone, Copy, PartialEq)] +pub enum AgentColorScheme { + VehicleTypes, + Delay, + RemainingDistance, +} + +impl AgentColorScheme { + pub fn color_for(&self, agent: &UnzoomedAgent, cs: &ColorScheme) -> Color { + match self { + AgentColorScheme::VehicleTypes => match agent.vehicle_type { + Some(VehicleType::Car) => cs.get_def("unzoomed car", Color::RED.alpha(0.5)), + Some(VehicleType::Bike) => cs.get_def("unzoomed bike", Color::GREEN.alpha(0.5)), + Some(VehicleType::Bus) => cs.get_def("unzoomed bus", Color::BLUE.alpha(0.5)), + None => cs.get_def("unzoomed pedestrian", Color::ORANGE.alpha(0.5)), + }, + AgentColorScheme::Delay => delay_color(agent.time_spent_blocked), + AgentColorScheme::RemainingDistance => percent_color(agent.percent_dist_crossed), + } + } +} + +fn delay_color(delay: Duration) -> Color { + // TODO Better gradient + if delay <= Duration::minutes(1) { + return Color::BLUE.alpha(0.3); + } + if delay <= Duration::minutes(5) { + return Color::ORANGE.alpha(0.5); + } + Color::RED.alpha(0.8) +} + +fn percent_color(percent: f64) -> Color { + rotating_color((percent * 10.0).round() as usize) +} diff --git a/editor/src/render/mod.rs b/editor/src/render/mod.rs index 01f0ae0532..f689f6817f 100644 --- a/editor/src/render/mod.rs +++ b/editor/src/render/mod.rs @@ -19,7 +19,7 @@ use crate::render::car::DrawCar; pub use crate::render::extra_shape::ExtraShapeID; pub use crate::render::intersection::{calculate_corners, DrawIntersection}; pub use crate::render::lane::DrawLane; -pub use crate::render::map::{AgentCache, DrawMap}; +pub use crate::render::map::{AgentCache, AgentColorScheme, DrawMap}; pub use crate::render::pedestrian::{DrawPedCrowd, DrawPedestrian}; pub use crate::render::road::DrawRoad; pub use crate::render::traffic_signal::{draw_signal_cycle, TrafficSignalDiagram}; @@ -86,9 +86,9 @@ pub struct DrawOptions { pub override_colors: HashMap, pub suppress_traffic_signal_details: Option, pub geom_debug_mode: bool, - pub suppress_unzoomed_agents: bool, pub label_buildings: bool, pub label_roads: bool, + pub agent_cs: AgentColorScheme, } impl DrawOptions { @@ -97,9 +97,9 @@ impl DrawOptions { override_colors: HashMap::new(), suppress_traffic_signal_details: None, geom_debug_mode: false, - suppress_unzoomed_agents: false, label_buildings: false, label_roads: false, + agent_cs: AgentColorScheme::VehicleTypes, } } diff --git a/editor/src/ui.rs b/editor/src/ui.rs index 9364e8a668..9fb75475ba 100644 --- a/editor/src/ui.rs +++ b/editor/src/ui.rs @@ -125,10 +125,8 @@ impl UI { ); } - if !opts.suppress_unzoomed_agents { - let mut cache = self.primary.draw_map.agents.borrow_mut(); - cache.draw_unzoomed_agents(&self.primary, &self.cs, g); - } + let mut cache = self.primary.draw_map.agents.borrow_mut(); + cache.draw_unzoomed_agents(&self.primary, opts.agent_cs, &self.cs, g); } else { let mut cache = self.primary.draw_map.agents.borrow_mut(); let objects = self.get_renderables_back_to_front( diff --git a/sim/src/mechanics/driving.rs b/sim/src/mechanics/driving.rs index 8a0752cf0c..a7c4940708 100644 --- a/sim/src/mechanics/driving.rs +++ b/sim/src/mechanics/driving.rs @@ -699,6 +699,7 @@ impl DrivingSimState { let car = &self.cars[&c]; let path = car.router.get_path(); result.push(UnzoomedAgent { + vehicle_type: Some(car.vehicle.vehicle_type), pos: queue.id.dist_along(dist, map).0, time_spent_blocked: car .blocked_since diff --git a/sim/src/mechanics/walking.rs b/sim/src/mechanics/walking.rs index f0987d529f..36a79d7abd 100644 --- a/sim/src/mechanics/walking.rs +++ b/sim/src/mechanics/walking.rs @@ -277,6 +277,7 @@ impl WalkingSimState { for ped in self.peds.values() { peds.push(UnzoomedAgent { + vehicle_type: None, pos: ped.get_draw_ped(now, map).pos, time_spent_blocked: ped.blocked_since.map(|t| now - t).unwrap_or(Duration::ZERO), percent_dist_crossed: ped.path.crossed_so_far() / ped.path.total_length(), diff --git a/sim/src/render.rs b/sim/src/render.rs index c5d8ee0a22..c4d788fed1 100644 --- a/sim/src/render.rs +++ b/sim/src/render.rs @@ -1,4 +1,4 @@ -use crate::{CarID, PedestrianID}; +use crate::{CarID, PedestrianID, VehicleType}; use geom::{Angle, Distance, Duration, PolyLine, Pt2D}; use map_model::{Map, Traversable, TurnID}; @@ -42,6 +42,8 @@ pub enum CarStatus { } pub struct UnzoomedAgent { + // None means a pedestrian. + pub vehicle_type: Option, pub pos: Pt2D, pub time_spent_blocked: Duration, pub percent_dist_crossed: f64,