diff --git a/docs/design.md b/docs/design.md index 077d497138..32cbfeba55 100644 --- a/docs/design.md +++ b/docs/design.md @@ -696,7 +696,6 @@ step 2: move interactive and testish spawning stuff to init() or similar, leavin - i just physically want the code in a separate file. can we implement a trait in a second file? step 3: enhance the trip stuff to have a concept of hardcoded legs, and make it choose how to use a bus - seed a trip using a bus - - wire up the transitions to board and deboard the bus - test a basic bus scenario diff --git a/docs/references.md b/docs/references.md index 43650182ce..8b513f943a 100644 --- a/docs/references.md +++ b/docs/references.md @@ -4,3 +4,7 @@ - Seattle Times Traffic Lab - https://www.citylab.com/transportation/2018/08/is-it-time-to-rethink-what-a-bike-lane-is/568483/ + +## Similar projects + +- Urban Footprint (https://news.ycombinator.com/item?id=17895739) diff --git a/sim/src/sim.rs b/sim/src/sim.rs index a81d67201f..c36270d613 100644 --- a/sim/src/sim.rs +++ b/sim/src/sim.rs @@ -178,8 +178,13 @@ impl Sim { ); } - self.transit_state - .step(&mut events, &mut self.walking_state, &mut self.trips_state); + self.transit_state.step( + self.time, + &mut events, + &mut self.walking_state, + &mut self.trips_state, + &mut self.spawner, + ); // TODO want to pass self as a lazy QueryCar trait, but intersection_state is mutably // borrowed :( diff --git a/sim/src/spawn.rs b/sim/src/spawn.rs index aac20c5b4c..20fe22fbf5 100644 --- a/sim/src/spawn.rs +++ b/sim/src/spawn.rs @@ -336,6 +336,23 @@ impl Spawner { } // Trip transitions + pub fn ped_finished_bus_ride( + &mut self, + at: Tick, + ped: PedestrianID, + stop: BusStop, + trips: &mut TripManager, + ) { + let (trip, walk_to) = trips.ped_finished_bus_ride(ped); + self.commands.push_back(Command::Walk( + at.next(), + trip, + ped, + SidewalkSpot::bus_stop(stop), + walk_to, + )); + } + pub fn car_reached_parking_spot( &mut self, at: Tick, diff --git a/sim/src/transit.rs b/sim/src/transit.rs index 795395495f..dfa53aebef 100644 --- a/sim/src/transit.rs +++ b/sim/src/transit.rs @@ -4,6 +4,7 @@ use driving::CarView; use events::Event; use map_model; use map_model::{BusStop, LaneID, Map}; +use spawn::Spawner; use std::collections::{BTreeMap, VecDeque}; use trips::TripManager; use walking::WalkingSimState; @@ -188,9 +189,11 @@ impl TransitSimState { pub fn step( &mut self, + now: Tick, events: &mut Vec, walking_sim: &mut WalkingSimState, trips: &mut TripManager, + spawner: &mut Spawner, ) { for b in self.buses.values_mut() { if let BusState::AtStop(stop_idx, _) = b.state { @@ -214,10 +217,11 @@ impl TransitSimState { // which is called by router! thats convoluted let car = b.car; b.passengers.retain(|p| { - println!("TODO should {} leave bus {}?", p, car); - if false { + if trips.should_ped_leave_bus(*p, &stop) { events.push(Event::PedLeavesBus(*p, car)); - // TODO call something on the spawner to join the walking sim again + // TODO would be a little cleaner to return this info up to sim and have it + // plumb through to spawner? not sure + spawner.ped_finished_bus_ride(now, *p, stop.clone(), trips); false } else { true diff --git a/sim/src/trips.rs b/sim/src/trips.rs index 740c1eff9c..faa4c61334 100644 --- a/sim/src/trips.rs +++ b/sim/src/trips.rs @@ -82,14 +82,44 @@ impl TripManager { return false; } - // They're boarding! - self.active_trip_mode.remove(&AgentID::Pedestrian(ped)); // Could assert that the first leg is walking to the right bus stop trip.legs.pop_front(); + // Leave active_trip_mode as Pedestrian, since the transit sim tracks passengers as + // PedestrianIDs. true } + pub fn should_ped_leave_bus(&self, ped: PedestrianID, stop: &BusStop) -> bool { + let trip = &self.trips[self.active_trip_mode[&AgentID::Pedestrian(ped)].0]; + + match trip.legs[0] { + TripLeg::RideBus(_, ref until_stop) => stop == until_stop, + ref x => panic!("{} is on a bus stop, but first leg is {:?}", ped, x), + } + } + + // Where to walk next? + pub fn ped_finished_bus_ride(&mut self, ped: PedestrianID) -> (TripID, SidewalkSpot) { + // The spawner will call agent_starting_trip_leg, so briefly remove the active PedestrianID. + let trip = &mut self.trips[self.active_trip_mode + .remove(&AgentID::Pedestrian(ped)) + .unwrap() + .0]; + + match trip.legs.pop_front().unwrap() { + TripLeg::RideBus(_, _) => {} + x => panic!("First trip leg {:?} doesn't match ped_finished_bus_ride", x), + }; + // TODO there are only some valid sequences of trips. it'd be neat to guarantee these are + // valid by construction with a fluent API. + let walk_to = match trip.legs[0] { + TripLeg::Walk(ref to) => to, + ref x => panic!("Next trip leg is {:?}, not walking", x), + }; + (trip.id, walk_to.clone()) + } + // Creation from the interactive part of spawner pub fn new_trip( &mut self,