diff --git a/game/src/info/building.rs b/game/src/info/building.rs index e48b7dcfea..c6400f1199 100644 --- a/game/src/info/building.rs +++ b/game/src/info/building.rs @@ -1,10 +1,11 @@ use crate::app::App; -use crate::helpers::ID; +use crate::helpers::{ColorScheme, ID}; use crate::info::{header_btns, make_table, make_tabs, Details, Tab}; +use crate::render::DrawPedestrian; use ezgui::{Btn, EventCtx, Line, Text, TextExt, Widget}; -use geom::Time; -use map_model::BuildingID; -use sim::{TripMode, TripResult}; +use geom::{Angle, Time}; +use map_model::{Building, BuildingID, LaneID, Traversable, SIDEWALK_THICKNESS}; +use sim::{DrawPedestrianInput, PedestrianID, TripMode, TripResult}; pub fn info(ctx: &mut EventCtx, app: &App, details: &mut Details, id: BuildingID) -> Vec { let mut rows = header(ctx, app, details, id, Tab::BldgInfo(id)); @@ -165,5 +166,58 @@ fn header( ); } + draw_occupants( + details, + &app.cs, + app.primary.map.get_b(id), + app.primary.sim.bldg_to_people(id).len(), + ); + rows } + +fn draw_occupants(details: &mut Details, cs: &ColorScheme, bldg: &Building, num_ppl: usize) { + // TODO Lots of fun ideas here. Have a deterministic simulation based on building ID and time + // to have people "realistically" move around. Draw little floor plans. + + let num_rows_cols = (num_ppl as f64).sqrt().ceil() as usize; + + let ped_len = SIDEWALK_THICKNESS.inner_meters() / 2.0; + let separation = ped_len * 1.5; + + let total_width_height = (num_rows_cols as f64) * (ped_len + separation); + let top_left = bldg + .label_center + .offset(-total_width_height / 2.0, -total_width_height / 2.0); + + // TODO Current thing is inefficient and can easily wind up outside the building. + + let mut cnt = 0; + 'OUTER: for x in 0..num_rows_cols { + for y in 0..num_rows_cols { + DrawPedestrian::geometry( + &mut details.zoomed, + cs, + &DrawPedestrianInput { + id: PedestrianID(cnt), + pos: top_left.offset( + (x as f64) * (ped_len + separation), + (y as f64) * (ped_len + separation), + ), + facing: Angle::new_degs(90.0), + waiting_for_turn: None, + preparing_bike: false, + // Both hands and feet! + waiting_for_bus: true, + on: Traversable::Lane(LaneID(0)), + }, + 0, + ); + + cnt += 1; + if cnt == num_ppl { + break 'OUTER; + } + } + } +} diff --git a/game/src/render/mod.rs b/game/src/render/mod.rs index 04dd6e704e..2cc941b939 100644 --- a/game/src/render/mod.rs +++ b/game/src/render/mod.rs @@ -20,7 +20,7 @@ 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, AgentColorScheme, DrawMap}; -use crate::render::pedestrian::{DrawPedCrowd, DrawPedestrian}; +pub use crate::render::pedestrian::{DrawPedCrowd, DrawPedestrian}; pub use crate::render::road::DrawRoad; pub use crate::render::traffic_signal::{draw_signal_phase, make_signal_diagram}; pub use crate::render::turn::{DrawTurn, DrawTurnGroup}; diff --git a/game/src/render/pedestrian.rs b/game/src/render/pedestrian.rs index 061a24ec4e..fcd59d1ba1 100644 --- a/game/src/render/pedestrian.rs +++ b/game/src/render/pedestrian.rs @@ -22,6 +22,40 @@ impl DrawPedestrian { prerender: &Prerender, cs: &ColorScheme, ) -> DrawPedestrian { + let mut draw_default = GeomBatch::new(); + DrawPedestrian::geometry(&mut draw_default, cs, &input, step_count); + + let radius = SIDEWALK_THICKNESS / 4.0; // TODO make const after const fn is better + let body_circle = Circle::new(input.pos, radius); + + if let Some(t) = input.waiting_for_turn { + // A silly idea for peds... use hands to point at their turn? + let angle = map.get_t(t).angle(); + draw_default.push( + cs.get("turn arrow"), + PolyLine::new(vec![ + input.pos.project_away(radius / 2.0, angle.opposite()), + input.pos.project_away(radius / 2.0, angle), + ]) + .make_arrow(Distance::meters(0.15)) + .unwrap(), + ); + } + + DrawPedestrian { + id: input.id, + body_circle, + zorder: input.on.get_zorder(map), + draw_default: prerender.upload(draw_default), + } + } + + pub fn geometry( + batch: &mut GeomBatch, + cs: &ColorScheme, + input: &DrawPedestrianInput, + step_count: usize, + ) { // TODO Slight issues with rendering small pedestrians: // - route visualization is thick // - there are little skips when making turns @@ -29,8 +63,6 @@ impl DrawPedestrian { let radius = SIDEWALK_THICKNESS / 4.0; // TODO make const after const fn is better let body_circle = Circle::new(input.pos, radius); - let mut draw_default = GeomBatch::new(); - let foot_radius = 0.2 * radius; let hand_radius = 0.2 * radius; let left_foot_angle = 30.0; @@ -68,13 +100,13 @@ impl DrawPedestrian { let jitter = input.id.0 % 2 == 0; let remainder = step_count % 6; if input.waiting_for_turn.is_some() || input.waiting_for_bus { - draw_default.push(foot_color, left_foot.to_polygon()); - draw_default.push(foot_color, right_foot.to_polygon()); - draw_default.push(hand_color, left_hand.to_polygon()); - draw_default.push(hand_color, right_hand.to_polygon()); + batch.push(foot_color, left_foot.to_polygon()); + batch.push(foot_color, right_foot.to_polygon()); + batch.push(hand_color, left_hand.to_polygon()); + batch.push(hand_color, right_hand.to_polygon()); } else if jitter == (remainder < 3) { - draw_default.push(foot_color, left_foot.to_polygon()); - draw_default.push( + batch.push(foot_color, left_foot.to_polygon()); + batch.push( foot_color, Circle::new( input @@ -85,8 +117,8 @@ impl DrawPedestrian { .to_polygon(), ); - draw_default.push(hand_color, right_hand.to_polygon()); - draw_default.push( + batch.push(hand_color, right_hand.to_polygon()); + batch.push( hand_color, Circle::new( input @@ -97,8 +129,8 @@ impl DrawPedestrian { .to_polygon(), ); } else { - draw_default.push(foot_color, right_foot.to_polygon()); - draw_default.push( + batch.push(foot_color, right_foot.to_polygon()); + batch.push( foot_color, Circle::new( input @@ -109,8 +141,8 @@ impl DrawPedestrian { .to_polygon(), ); - draw_default.push(hand_color, left_hand.to_polygon()); - draw_default.push( + batch.push(hand_color, left_hand.to_polygon()); + batch.push( hand_color, Circle::new( input @@ -123,32 +155,11 @@ impl DrawPedestrian { }; let head_circle = Circle::new(input.pos, 0.5 * radius); - draw_default.push(zoomed_color_ped(&input, cs), body_circle.to_polygon()); - draw_default.push( + batch.push(zoomed_color_ped(&input, cs), body_circle.to_polygon()); + batch.push( cs.get_def("pedestrian head", Color::rgb(139, 69, 19)), head_circle.to_polygon(), ); - - if let Some(t) = input.waiting_for_turn { - // A silly idea for peds... use hands to point at their turn? - let angle = map.get_t(t).angle(); - draw_default.push( - cs.get("turn arrow"), - PolyLine::new(vec![ - input.pos.project_away(radius / 2.0, angle.opposite()), - input.pos.project_away(radius / 2.0, angle), - ]) - .make_arrow(Distance::meters(0.15)) - .unwrap(), - ); - } - - DrawPedestrian { - id: input.id, - body_circle, - zorder: input.on.get_zorder(map), - draw_default: prerender.upload(draw_default), - } } }