diff --git a/docs/TODO_quality.md b/docs/TODO_quality.md index 33c8ba49ff..4d1d52a0e9 100644 --- a/docs/TODO_quality.md +++ b/docs/TODO_quality.md @@ -2,9 +2,6 @@ ## Boundary clipping -- lakes missing from huge_seattle - - just connecting the ends of ways doesnt always work well - - maybe increase the Bounds for areas, and let clipping clean up later? - some border intersections have weird OOBish geometry, or the arrows look weird - simplify border node detection, only do it in convert_osm? @@ -69,17 +66,12 @@ - iterative process... have to redo affected roads and intersections - we havent filtered buildings by proximity to sidewalk yet - if we dont filter at all, we pick up some houseboats! :) should draw water... -- undo disabled traffic signal assertion ## Map edits - lane type can affect border intersections - lane type can affect turn idx - assert turns are the same -- crash when loading some edits (priori->bikelanez) - - edit an intersection first, then change lanes to destroy turns. need to recalculate the policy, preserving edits! - - just revert intersection and warn - - or store overrides more granularly and warn or do something reasonable ## Sim bugs/tests needed diff --git a/docs/TODO_ux.md b/docs/TODO_ux.md index 6f7e6d4104..5b8afbd27d 100644 --- a/docs/TODO_ux.md +++ b/docs/TODO_ux.md @@ -20,7 +20,6 @@ - optionally limit canvas scrolling/zooming to some map bounds - start context menu when left click releases and we're not dragging -- distinguish hints from status of modal menus, for hiding purposes - move context menus out of ezgui - simplify/remove UserInput. - maybe separate impls for context, wizard, modal menu make sense. diff --git a/game/src/render/pedestrian.rs b/game/src/render/pedestrian.rs index 9c670a0d63..0a633a0cef 100644 --- a/game/src/render/pedestrian.rs +++ b/game/src/render/pedestrian.rs @@ -3,7 +3,7 @@ use crate::render::{AgentColorScheme, DrawCtx, DrawOptions, Renderable, OUTLINE_ use ezgui::{Canvas, Color, Drawable, GeomBatch, GfxCtx, Line, Prerender, Text}; use geom::{Circle, Distance, PolyLine, Polygon}; use map_model::{Map, LANE_THICKNESS}; -use sim::{DrawPedCrowdInput, DrawPedestrianInput, PedestrianID}; +use sim::{DrawPedCrowdInput, DrawPedestrianInput, PedCrowdLocation, PedestrianID}; pub struct DrawPedestrian { pub id: PedestrianID, @@ -201,12 +201,21 @@ impl DrawPedCrowd { prerender: &Prerender, cs: &ColorScheme, ) -> DrawPedCrowd { - // TODO front path - let pl_slice = input.on.exact_slice(input.low, input.high, map); - let pl_shifted = if input.contraflow { - pl_slice.shift_left(LANE_THICKNESS / 4.0).unwrap() - } else { - pl_slice.shift_right(LANE_THICKNESS / 4.0).unwrap() + let pl_shifted = match input.location { + PedCrowdLocation::Sidewalk(on, contraflow) => { + let pl_slice = on.exact_slice(input.low, input.high, map); + if contraflow { + pl_slice.shift_left(LANE_THICKNESS / 4.0).unwrap() + } else { + pl_slice.shift_right(LANE_THICKNESS / 4.0).unwrap() + } + } + PedCrowdLocation::FrontPath(b) => map + .get_b(b) + .front_path + .line + .to_polyline() + .exact_slice(input.low, input.high), }; let blob = pl_shifted.make_polygons(LANE_THICKNESS / 2.0); let draw_default = prerender.upload_borrowed(vec![(cs.get("pedestrian"), &blob)]); @@ -223,7 +232,10 @@ impl DrawPedCrowd { members: input.members, blob_pl: pl_shifted, blob, - zorder: input.on.get_zorder(map), + zorder: match input.location { + PedCrowdLocation::Sidewalk(on, _) => on.get_zorder(map), + PedCrowdLocation::FrontPath(_) => 0, + }, draw_default, label, } diff --git a/sim/src/lib.rs b/sim/src/lib.rs index c3e6794539..09fa9cb442 100644 --- a/sim/src/lib.rs +++ b/sim/src/lib.rs @@ -27,7 +27,7 @@ pub use self::trips::{TripCount, TripResult}; pub(crate) use self::trips::{TripLeg, TripManager}; pub use crate::render::{ AgentMetadata, CarStatus, DontDrawAgents, DrawCarInput, DrawPedCrowdInput, DrawPedestrianInput, - GetDrawAgents, UnzoomedAgent, + GetDrawAgents, PedCrowdLocation, UnzoomedAgent, }; use abstutil::Cloneable; use geom::{Distance, Duration, Pt2D, Speed}; diff --git a/sim/src/mechanics/walking.rs b/sim/src/mechanics/walking.rs index 121e213804..578199de2a 100644 --- a/sim/src/mechanics/walking.rs +++ b/sim/src/mechanics/walking.rs @@ -1,8 +1,8 @@ use crate::{ AgentID, AgentMetadata, Command, CreatePedestrian, DistanceInterval, DrawPedCrowdInput, - DrawPedestrianInput, Event, IntersectionSimState, ParkingSimState, ParkingSpot, PedestrianID, - Scheduler, SidewalkPOI, SidewalkSpot, TimeInterval, TransitSimState, TripID, TripManager, - TripPositions, UnzoomedAgent, + DrawPedestrianInput, Event, IntersectionSimState, ParkingSimState, ParkingSpot, + PedCrowdLocation, PedestrianID, Scheduler, SidewalkPOI, SidewalkSpot, TimeInterval, + TransitSimState, TripID, TripManager, TripPositions, UnzoomedAgent, }; use abstutil::{deserialize_multimap, serialize_multimap, MultiMap}; use geom::{Distance, Duration, Line, PolyLine, Speed}; @@ -329,8 +329,6 @@ impl WalkingSimState { let mut backwards: Vec<(PedestrianID, Distance)> = Vec::new(); let mut front_path: MultiMap = MultiMap::new(); - let mut loners: Vec = Vec::new(); - for id in self.peds_per_traversable.get(on) { let ped = &self.peds[id]; let dist = ped.get_dist_along(now, map); @@ -350,14 +348,13 @@ impl WalkingSimState { forwards.push((*id, dist)); } } - PedState::LeavingBuilding(b, _) | PedState::EnteringBuilding(b, _) => { - // TODO Group on front paths too. - if false { - // TODO Distance along the front path - front_path.insert(b, (*id, dist)); - } else { - loners.push(ped.get_draw_ped(now, map)); - } + PedState::LeavingBuilding(b, ref int) => { + let len = map.get_b(b).front_path.line.length(); + front_path.insert(b, (*id, int.percent(now) * len)); + } + PedState::EnteringBuilding(b, ref int) => { + let len = map.get_b(b).front_path.line.length(); + front_path.insert(b, (*id, (1.0 - int.percent(now)) * len)); } PedState::StartingToBike(_, _, _) | PedState::FinishingBiking(_, _, _) @@ -369,29 +366,38 @@ impl WalkingSimState { } let mut crowds: Vec = Vec::new(); - let on_len = on.length(map); + let mut loners: Vec = Vec::new(); // For each group, sort by distance along. Attempt to bundle into intervals. - for (idx, mut group) in vec![forwards, backwards] - .into_iter() - .chain( - front_path - .consume() - .values() - .map(|set| set.iter().cloned().collect::>()), + for (mut group, location, on_len) in vec![ + ( + forwards, + PedCrowdLocation::Sidewalk(on, false), + on.length(map), + ), + ( + backwards, + PedCrowdLocation::Sidewalk(on, true), + on.length(map), + ), + ] + .into_iter() + .chain(front_path.consume().into_iter().map(|(b, set)| { + ( + set.into_iter().collect::>(), + PedCrowdLocation::FrontPath(b), + map.get_b(b).front_path.line.length(), ) - .enumerate() - { + })) { if group.is_empty() { continue; } group.sort_by_key(|(_, dist)| *dist); - let (individs, these_crowds) = find_crowds(group, on); + let (individs, these_crowds) = find_crowds(group, location); for id in individs { loners.push(self.peds[&id].get_draw_ped(now, map)); } for mut crowd in these_crowds { - crowd.contraflow = idx == 1; // Clamp the distance intervals. if crowd.low < Distance::ZERO { crowd.low = Distance::ZERO; @@ -491,11 +497,7 @@ impl Pedestrian { ( front_path .line - .dist_along(time_int.percent(now) * front_path.line.length()) - .project_away( - LANE_THICKNESS / 4.0, - front_path.line.angle().rotate_degs(90.0), - ), + .dist_along(time_int.percent(now) * front_path.line.length()), front_path.line.angle(), ) } @@ -505,11 +507,7 @@ impl Pedestrian { front_path .line .reverse() - .dist_along(time_int.percent(now) * front_path.line.length()) - .project_away( - LANE_THICKNESS / 4.0, - front_path.line.angle().rotate_degs(-90.0), - ), + .dist_along(time_int.percent(now) * front_path.line.length()), front_path.line.angle().opposite(), ) } @@ -628,7 +626,7 @@ impl PedState { // The crowds returned here may have low/high values extending up to radius past the real geometry. fn find_crowds( input: Vec<(PedestrianID, Distance)>, - on: Traversable, + location: PedCrowdLocation, ) -> (Vec, Vec) { let mut loners = Vec::new(); let mut crowds = Vec::new(); @@ -637,9 +635,8 @@ fn find_crowds( let mut current_crowd = DrawPedCrowdInput { low: input[0].1 - radius, high: input[0].1 + radius, - contraflow: false, members: vec![input[0].0], - on, + location: location.clone(), }; for (id, dist) in input.into_iter().skip(1) { // If the pedestrian circles would overlap at all, @@ -656,9 +653,8 @@ fn find_crowds( current_crowd = DrawPedCrowdInput { low: dist - radius, high: dist + radius, - contraflow: false, members: vec![id], - on, + location: location.clone(), }; } } diff --git a/sim/src/render.rs b/sim/src/render.rs index 5de8eee647..daad94805e 100644 --- a/sim/src/render.rs +++ b/sim/src/render.rs @@ -1,6 +1,6 @@ use crate::{CarID, PedestrianID, VehicleType}; use geom::{Angle, Distance, Duration, PolyLine, Pt2D}; -use map_model::{Map, Traversable, TurnID}; +use map_model::{BuildingID, Map, Traversable, TurnID}; // Intermediate structures so that sim and game crates don't have a cyclic dependency. #[derive(Clone)] @@ -25,9 +25,15 @@ pub struct AgentMetadata { pub struct DrawPedCrowdInput { pub low: Distance, pub high: Distance, - pub contraflow: bool, pub members: Vec, - pub on: Traversable, + pub location: PedCrowdLocation, +} + +#[derive(Clone)] +pub enum PedCrowdLocation { + // bool is contraflow + Sidewalk(Traversable, bool), + FrontPath(BuildingID), } #[derive(Clone)]