diff --git a/docs/design.md b/docs/design.md index 5c722327e6..1f5b614d78 100644 --- a/docs/design.md +++ b/docs/design.md @@ -980,8 +980,11 @@ so it feels like we implicitly have a big enum of active plugin, with each of th = basically, make UI.event() just the active plugin list thing as much as possible. - deal with overlapping keys that still kinda happen (sim ctrl, escape game) - bug: do need to recalculate current_selection whenever anything potentially changes camera, like follow + + - make draw car/ped implement renderable. + - move Draw* to editor crate, and have an intermediate thing exposed from sim and do the translation in get_blah_onscreen. - then rethink colors, with simplified single plugin - - then finally try out a unified quadtree! + = then finally try out a unified quadtree! = make parcels selectable as well? - and see how much boilerplate a new type would need, by adding bus stops and water/parks diff --git a/editor/src/plugins/debug_objects.rs b/editor/src/plugins/debug_objects.rs index a67a28a764..0f5903b79d 100644 --- a/editor/src/plugins/debug_objects.rs +++ b/editor/src/plugins/debug_objects.rs @@ -104,6 +104,7 @@ fn debug(id: &ID, map: &Map, control_map: &ControlMap, sim: &mut Sim) { } } +// TODO Renderable has tooltip_lines... decide what goes where fn tooltip_lines(id: ID, map: &Map, draw_map: &DrawMap, sim: &Sim) -> Vec { match id { ID::Lane(id) => draw_map.get_l(id).tooltip_lines(map), diff --git a/editor/src/plugins/follow.rs b/editor/src/plugins/follow.rs index 3b9aa1154d..1d48e086b7 100644 --- a/editor/src/plugins/follow.rs +++ b/editor/src/plugins/follow.rs @@ -55,7 +55,7 @@ impl FollowState { } FollowState::FollowingPedestrian(id) => { if let Some(p) = sim.get_draw_ped(*id, map) { - let pt = p.focus_pt(); + let pt = p.pos; canvas.center_on_map_pt(pt.x(), pt.y()); input.key_pressed(Key::Return, "stop following") } else { diff --git a/editor/src/plugins/warp.rs b/editor/src/plugins/warp.rs index 44957ed274..edb53b4d85 100644 --- a/editor/src/plugins/warp.rs +++ b/editor/src/plugins/warp.rs @@ -122,7 +122,7 @@ fn warp(line: String, map: &Map, sim: &Sim, canvas: &mut Canvas, selected: &mut if let Some(p) = sim.get_draw_ped(id, map) { println!("Warping to {}", id); *selected = Some(ID::Pedestrian(id)); - p.focus_pt() + p.pos } else { println!("{} doesn't exist", id); return; diff --git a/editor/src/render/mod.rs b/editor/src/render/mod.rs index 1f3980b9bb..bb69488a3b 100644 --- a/editor/src/render/mod.rs +++ b/editor/src/render/mod.rs @@ -6,6 +6,7 @@ mod intersection; mod lane; mod map; mod parcel; +mod pedestrian; mod turn; use aabb_quadtree::geom::{Point, Rect}; @@ -16,6 +17,7 @@ use graphics::types::Color; use map_model::{geometry, Map}; pub use render::lane::DrawLane; pub use render::map::DrawMap; +pub use render::pedestrian::DrawPedestrian; pub use render::turn::DrawTurn; use std::f64; use std::fmt; diff --git a/editor/src/render/pedestrian.rs b/editor/src/render/pedestrian.rs new file mode 100644 index 0000000000..4a0e776fb7 --- /dev/null +++ b/editor/src/render/pedestrian.rs @@ -0,0 +1,70 @@ +use aabb_quadtree::geom::Rect; +use colors::ColorScheme; +use ezgui::GfxCtx; +use geom::Pt2D; +use graphics; +use graphics::types::Color; +use map_model::{geometry, Map}; +use render::Renderable; +use sim::{DrawPedestrianInput, PedestrianID}; + +const RADIUS: f64 = 1.0; + +// TODO should this live in editor/render? +pub struct DrawPedestrian { + pub id: PedestrianID, + circle: [f64; 4], + turn_arrow: Option<[f64; 4]>, +} + +impl DrawPedestrian { + pub fn new(input: DrawPedestrianInput, map: &Map) -> DrawPedestrian { + let turn_arrow = if let Some(t) = input.waiting_for_turn { + // TODO this isn't quite right, but good enough for now + let angle = map.get_t(t).line.angle(); + let arrow_pt = input.pos.project_away(RADIUS, angle.opposite()); + Some([arrow_pt.x(), arrow_pt.y(), input.pos.x(), input.pos.y()]) + } else { + None + }; + + DrawPedestrian { + id: input.id, + circle: geometry::make_circle(input.pos, RADIUS), + turn_arrow, + } + } +} + +impl Renderable for DrawPedestrian { + type ID = PedestrianID; + + fn get_id(&self) -> PedestrianID { + self.id + } + + fn draw(&self, g: &mut GfxCtx, color: Color, _cs: &ColorScheme) { + g.draw_ellipse(color, self.circle); + + // TODO tune color, sizes + if let Some(a) = self.turn_arrow { + g.draw_arrow( + &graphics::Line::new_round([0.0, 1.0, 1.0, 1.0], 0.25), + a, + 0.3, + ); + } + } + + fn get_bbox(&self) -> Rect { + geometry::circle_to_bbox(&self.circle) + } + + fn contains_pt(&self, pt: Pt2D) -> bool { + geometry::point_in_circle(&self.circle, pt) + } + + fn tooltip_lines(&self, _map: &Map) -> Vec { + vec![self.id.to_string()] + } +} diff --git a/editor/src/ui.rs b/editor/src/ui.rs index ce15317af0..b547d3d2fe 100644 --- a/editor/src/ui.rs +++ b/editor/src/ui.rs @@ -342,7 +342,8 @@ impl UI { return Some(ID::Car(c.id)); } } - for p in &self.sim.get_draw_peds_on_lane(l.id, &self.map) { + for p in self.sim.get_draw_peds_on_lane(l.id, &self.map).into_iter() { + let p = render::DrawPedestrian::new(p, &self.map); if p.contains_pt(pt) { return Some(ID::Pedestrian(p.id)); } @@ -365,7 +366,8 @@ impl UI { return Some(ID::Car(c.id)); } } - for p in &self.sim.get_draw_peds_on_turn(*t, &self.map) { + for p in self.sim.get_draw_peds_on_turn(*t, &self.map).into_iter() { + let p = render::DrawPedestrian::new(p, &self.map); if p.contains_pt(pt) { return Some(ID::Pedestrian(p.id)); } @@ -656,8 +658,9 @@ impl UI { for c in &self.sim.get_draw_cars_on_turn(*t, &self.map) { c.draw(g, self.color_car(c.id)); } - for p in &self.sim.get_draw_peds_on_turn(*t, &self.map) { - p.draw(g, self.color_ped(p.id)); + for p in self.sim.get_draw_peds_on_turn(*t, &self.map).into_iter() { + let p = render::DrawPedestrian::new(p, &self.map); + p.draw(g, self.color_ped(p.id), &self.cs); } } } @@ -689,8 +692,9 @@ impl UI { for c in &self.sim.get_draw_cars_on_lane(l.id, &self.map) { c.draw(g, self.color_car(c.id)); } - for p in &self.sim.get_draw_peds_on_lane(l.id, &self.map) { - p.draw(g, self.color_ped(p.id)); + for p in self.sim.get_draw_peds_on_lane(l.id, &self.map).into_iter() { + let p = render::DrawPedestrian::new(p, &self.map); + p.draw(g, self.color_ped(p.id), &self.cs); } } diff --git a/sim/src/draw_ped.rs b/sim/src/draw_ped.rs deleted file mode 100644 index b248df0213..0000000000 --- a/sim/src/draw_ped.rs +++ /dev/null @@ -1,54 +0,0 @@ -use ezgui::GfxCtx; -use geom::Pt2D; -use graphics; -use map_model::{geometry, Turn}; -use PedestrianID; - -const RADIUS: f64 = 1.0; - -// TODO should this live in editor/render? -pub struct DrawPedestrian { - pub id: PedestrianID, - circle: [f64; 4], - turn_arrow: Option<[f64; 4]>, -} - -impl DrawPedestrian { - pub fn new(id: PedestrianID, pos: Pt2D, waiting_for_turn: Option<&Turn>) -> DrawPedestrian { - let turn_arrow = if let Some(t) = waiting_for_turn { - // TODO this isn't quite right, but good enough for now - let angle = t.line.angle(); - let arrow_pt = pos.project_away(RADIUS, angle.opposite()); - Some([arrow_pt.x(), arrow_pt.y(), pos.x(), pos.y()]) - } else { - None - }; - - DrawPedestrian { - id, - circle: geometry::make_circle(pos, RADIUS), - turn_arrow, - } - } - - pub fn draw(&self, g: &mut GfxCtx, color: graphics::types::Color) { - g.draw_ellipse(color, self.circle); - - // TODO tune color, sizes - if let Some(a) = self.turn_arrow { - g.draw_arrow( - &graphics::Line::new_round([0.0, 1.0, 1.0, 1.0], 0.25), - a, - 0.3, - ); - } - } - - pub fn contains_pt(&self, pt: Pt2D) -> bool { - geometry::point_in_circle(&self.circle, pt) - } - - pub fn focus_pt(&self) -> Pt2D { - geometry::center_of_circle(&self.circle) - } -} diff --git a/sim/src/lib.rs b/sim/src/lib.rs index cf2db02da1..ef696a2b03 100644 --- a/sim/src/lib.rs +++ b/sim/src/lib.rs @@ -28,7 +28,6 @@ extern crate serde; extern crate serde_derive; mod draw_car; -mod draw_ped; mod driving; mod events; mod helpers; @@ -346,3 +345,10 @@ impl ParkedCar { ParkedCar { car, spot } } } + +// Intermediate structures so that sim and editor crates don't have a cyclic dependency. +pub struct DrawPedestrianInput { + pub id: PedestrianID, + pub pos: Pt2D, + pub waiting_for_turn: Option, +} diff --git a/sim/src/sim.rs b/sim/src/sim.rs index 0f5a7e12ad..73a731b05d 100644 --- a/sim/src/sim.rs +++ b/sim/src/sim.rs @@ -4,7 +4,6 @@ use abstutil; use control::ControlMap; use dimensioned::si; use draw_car::DrawCar; -use draw_ped::DrawPedestrian; use driving::DrivingSimState; use failure::Error; use instrument::capture_backtrace; @@ -23,7 +22,7 @@ use transit::TransitSimState; use trips::TripManager; use view::WorldView; use walking::WalkingSimState; -use {AgentID, CarID, CarState, Event, PedestrianID, Tick, TIMESTEP}; +use {AgentID, CarID, CarState, DrawPedestrianInput, Event, PedestrianID, Tick, TIMESTEP}; #[derive(Serialize, Deserialize, Derivative)] #[derivative(PartialEq, Eq)] @@ -234,7 +233,7 @@ impl Sim { }) } - pub fn get_draw_ped(&self, id: PedestrianID, map: &Map) -> Option { + pub fn get_draw_ped(&self, id: PedestrianID, map: &Map) -> Option { self.walking_state.get_draw_ped(id, map) } @@ -257,11 +256,11 @@ impl Sim { .get_draw_cars_on_turn(t, self.time, map, &self.car_properties) } - pub fn get_draw_peds_on_lane(&self, l: LaneID, map: &Map) -> Vec { + pub fn get_draw_peds_on_lane(&self, l: LaneID, map: &Map) -> Vec { self.walking_state.get_draw_peds_on_lane(map.get_l(l), map) } - pub fn get_draw_peds_on_turn(&self, t: TurnID, map: &Map) -> Vec { + pub fn get_draw_peds_on_turn(&self, t: TurnID, map: &Map) -> Vec { self.walking_state.get_draw_peds_on_turn(map.get_t(t)) } diff --git a/sim/src/walking.rs b/sim/src/walking.rs index 2d5f24cf36..587e553e3c 100644 --- a/sim/src/walking.rs +++ b/sim/src/walking.rs @@ -1,7 +1,6 @@ use abstutil; use abstutil::{deserialize_multimap, serialize_multimap}; use dimensioned::si; -use draw_ped::DrawPedestrian; use failure::Error; use geom::{Line, Pt2D}; use instrument::capture_backtrace; @@ -13,8 +12,8 @@ use std; use std::collections::{BTreeMap, VecDeque}; use view::{AgentView, WorldView}; use { - AgentID, Distance, Event, InvariantViolated, On, ParkingSpot, PedestrianID, Speed, Time, - TIMESTEP, + AgentID, Distance, DrawPedestrianInput, Event, InvariantViolated, On, ParkingSpot, + PedestrianID, Speed, Time, TIMESTEP, }; // TODO tune these! @@ -455,37 +454,37 @@ impl WalkingSimState { } } - pub fn get_draw_ped(&self, id: PedestrianID, map: &Map) -> Option { + pub fn get_draw_ped(&self, id: PedestrianID, map: &Map) -> Option { let ped = self.peds.get(&id)?; - Some(DrawPedestrian::new( + Some(DrawPedestrianInput { id, - ped.get_pos(map), + pos: ped.get_pos(map), // TODO this isnt correct, but works right now because this is only called by warp - None, - )) + waiting_for_turn: None, + }) } - pub fn get_draw_peds_on_lane(&self, l: &Lane, map: &Map) -> Vec { + pub fn get_draw_peds_on_lane(&self, l: &Lane, map: &Map) -> Vec { let mut result = Vec::new(); for id in self.peds_per_sidewalk.get_vec(&l.id).unwrap_or(&Vec::new()) { let ped = &self.peds[id]; - result.push(DrawPedestrian::new( - *id, - ped.get_pos(map), - ped.waiting_for.map(|on| map.get_t(on.as_turn())), - )); + result.push(DrawPedestrianInput { + id: *id, + pos: ped.get_pos(map), + waiting_for_turn: ped.waiting_for.map(|on| on.as_turn()), + }); } result } - pub fn get_draw_peds_on_turn(&self, t: &Turn) -> Vec { + pub fn get_draw_peds_on_turn(&self, t: &Turn) -> Vec { let mut result = Vec::new(); for id in self.peds_per_turn.get_vec(&t.id).unwrap_or(&Vec::new()) { - result.push(DrawPedestrian::new( - *id, - t.dist_along(self.peds[id].dist_along).0, - None, - )); + result.push(DrawPedestrianInput { + id: *id, + pos: t.dist_along(self.peds[id].dist_along).0, + waiting_for_turn: None, + }); } result }