center pedestrians on bldg front paths, and group them into crowds when

appropriate
This commit is contained in:
Dustin Carlino 2019-11-21 09:57:01 -08:00
parent d40002bb17
commit f39bb7c6cb
6 changed files with 66 additions and 61 deletions

View File

@ -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

View File

@ -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.

View File

@ -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,
}

View File

@ -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};

View File

@ -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<BuildingID, (PedestrianID, Distance)> = MultiMap::new();
let mut loners: Vec<DrawPedestrianInput> = 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<DrawPedCrowdInput> = Vec::new();
let on_len = on.length(map);
let mut loners: Vec<DrawPedestrianInput> = 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::<Vec<_>>()),
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::<Vec<_>>(),
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<PedestrianID>, Vec<DrawPedCrowdInput>) {
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(),
};
}
}

View File

@ -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<PedestrianID>,
pub on: Traversable,
pub location: PedCrowdLocation,
}
#[derive(Clone)]
pub enum PedCrowdLocation {
// bool is contraflow
Sidewalk(Traversable, bool),
FrontPath(BuildingID),
}
#[derive(Clone)]