diff --git a/data/MANIFEST.txt b/data/MANIFEST.txt index 42a1335da6..a5ee9ef369 100644 --- a/data/MANIFEST.txt +++ b/data/MANIFEST.txt @@ -374,9 +374,9 @@ data/system/maps/montlake.bin,d58d14b9fbae8cfdf6c547fe140ff3fe,https://www.dropb data/system/maps/mt_baker.bin,09dd0d4220e1ebbed4fc730ed2081933,https://www.dropbox.com/s/cetje663p04cbgp/mt_baker.bin.zip?dl=0 data/system/maps/udistrict.bin,4de690facca9297f148396f3f09c3a6a,https://www.dropbox.com/s/zqt2je8fadssz5j/udistrict.bin.zip?dl=0 data/system/maps/west_seattle.bin,867b16afdf12c484d680bfbc73cbd919,https://www.dropbox.com/s/5pp1ik9l40yj3wh/west_seattle.bin.zip?dl=0 -data/system/prebaked_results/lakeslice/weekday.bin,cbd73a7a14a8406a99cafac4e2eedf5b,https://www.dropbox.com/s/1c1sohvy50263wg/weekday.bin.zip?dl=0 +data/system/prebaked_results/lakeslice/weekday.bin,5402db739bd44a5f763f64fa14887733,https://www.dropbox.com/s/1c1sohvy50263wg/weekday.bin.zip?dl=0 data/system/prebaked_results/montlake/car vs bike contention.bin,ac46a6b81a65431209075a7de5ed9227,https://www.dropbox.com/s/jefg0ikjy9dsrdd/car%20vs%20bike%20contention.bin.zip?dl=0 -data/system/prebaked_results/montlake/weekday.bin,cd953900d32389809fb2dda206789528,https://www.dropbox.com/s/1aq7n9ow8tfqb5d/weekday.bin.zip?dl=0 +data/system/prebaked_results/montlake/weekday.bin,0a06da39f1f76199744d27b137bc1bc0,https://www.dropbox.com/s/1aq7n9ow8tfqb5d/weekday.bin.zip?dl=0 data/system/scenarios/ballard/weekday.bin,60d3eb1cdb8672e2d29cf3acf23ccabe,https://www.dropbox.com/s/67hys1v7m7oe979/weekday.bin.zip?dl=0 data/system/scenarios/downtown/weekday.bin,8821147124da650f975483ed1e5bbb69,https://www.dropbox.com/s/pstvu4p7xj3gaoi/weekday.bin.zip?dl=0 data/system/scenarios/huge_seattle/weekday.bin,31bfc23f39bb54bef939119f6cfbd2e2,https://www.dropbox.com/s/u3pmsshwnf13g83/weekday.bin.zip?dl=0 diff --git a/game/src/render/pedestrian.rs b/game/src/render/pedestrian.rs index 40be6315fd..aac499233c 100644 --- a/game/src/render/pedestrian.rs +++ b/game/src/render/pedestrian.rs @@ -212,12 +212,17 @@ impl DrawPedCrowd { map.right_shift(pl_slice, SIDEWALK_THICKNESS / 4.0).unwrap() } } - PedCrowdLocation::FrontPath(b) => map + PedCrowdLocation::BldgFrontPath(b) => map .get_b(b) .front_path .line .to_polyline() .exact_slice(input.low, input.high), + PedCrowdLocation::LotFrontPath(pl) => map + .get_pl(pl) + .sidewalk_line + .to_polyline() + .exact_slice(input.low, input.high), }; let blob = pl_shifted.make_polygons(SIDEWALK_THICKNESS / 2.0); let mut batch = GeomBatch::new(); @@ -235,7 +240,8 @@ impl DrawPedCrowd { blob, zorder: match input.location { PedCrowdLocation::Sidewalk(on, _) => on.get_zorder(map), - PedCrowdLocation::FrontPath(_) => 0, + PedCrowdLocation::BldgFrontPath(_) => 0, + PedCrowdLocation::LotFrontPath(_) => 0, }, draw_default: prerender.upload(batch), } diff --git a/map_model/src/parking_lot.rs b/map_model/src/parking_lot.rs index b10a11d84d..1d0d3be46a 100644 --- a/map_model/src/parking_lot.rs +++ b/map_model/src/parking_lot.rs @@ -6,6 +6,12 @@ use std::fmt; // TODO For now, ignore the mapped roads linking things and just use the same driveway approach // that buildings use. +// TODO Nits: +// - handle relations with individual slots, like https://www.openstreetmap.org/relation/2580595? +// - Northlake: onstreet or a lot? +// - E1 at UW filtered out +// - aisle clipping isnt perfect (23rd and rainier, pepsi) + #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord, Serialize, Deserialize)] pub struct ParkingLotID(pub usize); diff --git a/sim/src/mechanics/walking.rs b/sim/src/mechanics/walking.rs index 239868b600..b5e0333ae5 100644 --- a/sim/src/mechanics/walking.rs +++ b/sim/src/mechanics/walking.rs @@ -6,7 +6,9 @@ use crate::{ }; use abstutil::{deserialize_multimap, serialize_multimap, MultiMap}; use geom::{Distance, Duration, Line, PolyLine, Speed, Time}; -use map_model::{BuildingID, BusRouteID, Map, Path, PathStep, Traversable, SIDEWALK_THICKNESS}; +use map_model::{ + BuildingID, BusRouteID, Map, ParkingLotID, Path, PathStep, Traversable, SIDEWALK_THICKNESS, +}; use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; @@ -73,6 +75,10 @@ impl WalkingSimState { TimeInterval::new(now, now + map.get_b(b).front_path.line.length() / ped.speed), ) } + SidewalkPOI::ParkingSpot(ParkingSpot::Lot(pl, _)) => PedState::LeavingParkingLot( + pl, + TimeInterval::new(now, now + map.get_pl(pl).sidewalk_line.length() / ped.speed), + ), SidewalkPOI::BikeRack(driving_pos) => PedState::FinishingBiking( params.start.clone(), Line::new(driving_pos.pt(map), params.start.sidewalk_pos.pt(map)), @@ -122,18 +128,30 @@ impl WalkingSimState { if ped.path.is_last_step() { match ped.goal.connection { SidewalkPOI::ParkingSpot(spot) => { - self.peds_per_traversable - .remove(ped.path.current_step().as_traversable(), ped.id); - trips.ped_reached_parking_spot( - now, - ped.id, - spot, - ped.total_blocked_time, - map, - parking, - scheduler, - ); - self.peds.remove(&id); + if let ParkingSpot::Lot(pl, _) = spot { + ped.state = PedState::EnteringParkingLot( + pl, + TimeInterval::new( + now, + now + map.get_pl(pl).sidewalk_line.length() / ped.speed, + ), + ); + scheduler + .push(ped.state.get_end_time(), Command::UpdatePed(ped.id)); + } else { + self.peds_per_traversable + .remove(ped.path.current_step().as_traversable(), ped.id); + trips.ped_reached_parking_spot( + now, + ped.id, + spot, + ped.total_blocked_time, + map, + parking, + scheduler, + ); + self.peds.remove(&id); + } } SidewalkPOI::Building(b) => { ped.state = PedState::EnteringBuilding( @@ -247,6 +265,27 @@ impl WalkingSimState { ); self.peds.remove(&id); } + PedState::LeavingParkingLot(pl, _) => { + ped.state = ped.crossing_state(map.get_pl(pl).sidewalk_pos.dist_along(), now, map); + scheduler.push(ped.state.get_end_time(), Command::UpdatePed(ped.id)); + } + PedState::EnteringParkingLot(_, _) => { + self.peds_per_traversable + .remove(ped.path.current_step().as_traversable(), ped.id); + trips.ped_reached_parking_spot( + now, + ped.id, + match ped.goal.connection { + SidewalkPOI::ParkingSpot(spot) => spot, + _ => unreachable!(), + }, + ped.total_blocked_time, + map, + parking, + scheduler, + ); + self.peds.remove(&id); + } PedState::StartingToBike(ref spot, _, _) => { self.peds_per_traversable .remove(ped.path.current_step().as_traversable(), ped.id); @@ -364,10 +403,11 @@ impl WalkingSimState { on: Traversable, map: &Map, ) -> (Vec, Vec) { - // Classify into direction-based groups or by building front path. + // Classify into direction-based groups or by building/parking lot front path. let mut forwards: Vec<(PedestrianID, Distance)> = Vec::new(); let mut backwards: Vec<(PedestrianID, Distance)> = Vec::new(); - let mut front_path: MultiMap = MultiMap::new(); + let mut bldg_front_path: MultiMap = MultiMap::new(); + let mut lot_front_path: MultiMap = MultiMap::new(); for id in self.peds_per_traversable.get(on) { let ped = &self.peds[id]; @@ -390,11 +430,19 @@ impl WalkingSimState { } PedState::LeavingBuilding(b, ref int) => { let len = map.get_b(b).front_path.line.length(); - front_path.insert(b, (*id, int.percent(now) * len)); + bldg_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)); + bldg_front_path.insert(b, (*id, (1.0 - int.percent(now)) * len)); + } + PedState::LeavingParkingLot(pl, ref int) => { + let len = map.get_pl(pl).sidewalk_line.length(); + lot_front_path.insert(pl, (*id, int.percent(now) * len)); + } + PedState::EnteringParkingLot(pl, ref int) => { + let len = map.get_pl(pl).sidewalk_line.length(); + lot_front_path.insert(pl, (*id, (1.0 - int.percent(now)) * len)); } PedState::StartingToBike(_, _, _) | PedState::FinishingBiking(_, _, _) @@ -422,12 +470,19 @@ impl WalkingSimState { ), ] .into_iter() - .chain(front_path.consume().into_iter().map(|(b, set)| { + .chain(bldg_front_path.consume().into_iter().map(|(b, set)| { ( set.into_iter().collect::>(), - PedCrowdLocation::FrontPath(b), + PedCrowdLocation::BldgFrontPath(b), map.get_b(b).front_path.line.length(), ) + })) + .chain(lot_front_path.consume().into_iter().map(|(pl, set)| { + ( + set.into_iter().collect::>(), + PedCrowdLocation::LotFrontPath(pl), + map.get_pl(pl).sidewalk_line.length(), + ) })) { if group.is_empty() { continue; @@ -493,8 +548,12 @@ impl Pedestrian { match self.state { PedState::Crossing(ref dist_int, ref time_int) => dist_int.lerp(time_int.percent(now)), PedState::WaitingToTurn(dist, _) => dist, - PedState::LeavingBuilding(b, _) => map.get_b(b).front_path.sidewalk.dist_along(), - PedState::EnteringBuilding(b, _) => map.get_b(b).front_path.sidewalk.dist_along(), + PedState::LeavingBuilding(b, _) | PedState::EnteringBuilding(b, _) => { + map.get_b(b).front_path.sidewalk.dist_along() + } + PedState::LeavingParkingLot(pl, _) | PedState::EnteringParkingLot(pl, _) => { + map.get_pl(pl).sidewalk_pos.dist_along() + } PedState::StartingToBike(ref spot, _, _) => spot.sidewalk_pos.dist_along(), PedState::FinishingBiking(ref spot, _, _) => spot.sidewalk_pos.dist_along(), PedState::WaitingForBus(_, _) => self.goal.sidewalk_pos.dist_along(), @@ -540,22 +599,33 @@ impl Pedestrian { ) } PedState::LeavingBuilding(b, ref time_int) => { - let front_path = &map.get_b(b).front_path; + let line = &map.get_b(b).front_path.line; ( - front_path - .line - .dist_along(time_int.percent(now) * front_path.line.length()), - front_path.line.angle(), + line.dist_along(time_int.percent(now) * line.length()), + line.angle(), ) } PedState::EnteringBuilding(b, ref time_int) => { - let front_path = &map.get_b(b).front_path; + let line = &map.get_b(b).front_path.line; ( - front_path - .line - .reverse() - .dist_along(time_int.percent(now) * front_path.line.length()), - front_path.line.angle().opposite(), + line.reverse() + .dist_along(time_int.percent(now) * line.length()), + line.angle().opposite(), + ) + } + PedState::LeavingParkingLot(pl, ref time_int) => { + let line = &map.get_pl(pl).sidewalk_line; + ( + line.dist_along(time_int.percent(now) * line.length()), + line.angle(), + ) + } + PedState::EnteringParkingLot(pl, ref time_int) => { + let line = &map.get_pl(pl).sidewalk_line; + ( + line.reverse() + .dist_along(time_int.percent(now) * line.length()), + line.angle().opposite(), ) } PedState::StartingToBike(_, ref line, ref time_int) => { @@ -639,6 +709,8 @@ enum PedState { WaitingToTurn(Distance, Time), LeavingBuilding(BuildingID, TimeInterval), EnteringBuilding(BuildingID, TimeInterval), + LeavingParkingLot(ParkingLotID, TimeInterval), + EnteringParkingLot(ParkingLotID, TimeInterval), StartingToBike(SidewalkSpot, Line, TimeInterval), FinishingBiking(SidewalkSpot, Line, TimeInterval), WaitingForBus(BusRouteID, Time), @@ -651,6 +723,8 @@ impl PedState { PedState::WaitingToTurn(_, _) => unreachable!(), PedState::LeavingBuilding(_, ref time_int) => time_int.end, PedState::EnteringBuilding(_, ref time_int) => time_int.end, + PedState::LeavingParkingLot(_, ref time_int) => time_int.end, + PedState::EnteringParkingLot(_, ref time_int) => time_int.end, PedState::StartingToBike(_, _, ref time_int) => time_int.end, PedState::FinishingBiking(_, _, ref time_int) => time_int.end, PedState::WaitingForBus(_, _) => unreachable!(), diff --git a/sim/src/render.rs b/sim/src/render.rs index fcfdf5379e..9aafec2514 100644 --- a/sim/src/render.rs +++ b/sim/src/render.rs @@ -1,6 +1,6 @@ use crate::{CarID, PedestrianID, PersonID, VehicleType}; use geom::{Angle, Distance, PolyLine, Pt2D, Time}; -use map_model::{BuildingID, Map, Traversable, TurnID}; +use map_model::{BuildingID, Map, ParkingLotID, Traversable, TurnID}; // Intermediate structures so that sim and game crates don't have a cyclic dependency. #[derive(Clone)] @@ -25,7 +25,8 @@ pub struct DrawPedCrowdInput { pub enum PedCrowdLocation { // bool is contraflow Sidewalk(Traversable, bool), - FrontPath(BuildingID), + BldgFrontPath(BuildingID), + LotFrontPath(ParkingLotID), } #[derive(Clone)]