include ongoing trips in measured trip times. adjust wording of

"finished trips" things.
This commit is contained in:
Dustin Carlino 2020-02-17 15:58:27 -08:00
parent 0a7b8adbe1
commit d56803a12a
14 changed files with 140 additions and 109 deletions

View File

@ -208,9 +208,9 @@ f9f0a109966db097617a13122ecaa6f3 data/system/scenarios/downtown/weekday.bin
dd54763cfda7fce4c401ae122c6daf57 data/system/scenarios/huge_seattle/weekday.bin
47dea892a1c4331da02494d15ce02a02 data/system/scenarios/caphill/weekday.bin
7d6a8e8f5d716ce8674ed63d27f2da51 data/system/scenarios/montlake/weekday.bin
80be03bcfdbb24d809d53b1ad9105b84 data/system/prebaked_results/23rd/weekday.bin
d68c8f3beb5915c359228e38112c970b data/system/prebaked_results/signal_single/tutorial lvl1.bin
a6437680221c61b92964c3f376b76809 data/system/prebaked_results/signal_single/tutorial lvl2.bin
ffc3199512974f67299bfa2a262df6c6 data/system/prebaked_results/montlake/car vs bike contention.bin
b21a3366793c9295a8c6b6050eac778f data/system/prebaked_results/montlake/weekday.bin
0c0bade4ea0fe2fd1d31278a0f8fb3eb data/system/prebaked_results/montlake/car vs bus contention.bin
7dfe19826f9c24e47b64ea973dbabf9c data/system/prebaked_results/23rd/weekday.bin
e5b494a5e969951ea63a19ab932801f8 data/system/prebaked_results/signal_single/tutorial lvl1.bin
08c2771c555f7e52ed0c89c511248f99 data/system/prebaked_results/signal_single/tutorial lvl2.bin
460bd68fcc0c4686db7d654de372f46d data/system/prebaked_results/montlake/car vs bike contention.bin
f3d268e6c1a4b868e4006453b293236b data/system/prebaked_results/montlake/weekday.bin
2a3e97b847acfc9d6e381354e7dc46f7 data/system/prebaked_results/montlake/car vs bus contention.bin

View File

@ -24,7 +24,7 @@ pub enum Overlays {
BikeNetwork(Colorer),
BusNetwork(Colorer),
Edits(Colorer),
FinishedTripsHistogram(Time, Composite),
TripsHistogram(Time, Composite),
// These aren't selectable from the main picker
IntersectionDemand(Time, IntersectionID, Drawable, Composite),
@ -58,9 +58,9 @@ impl Overlays {
ui.overlay = Overlays::intersection_demand(i, ctx, ui);
}
}
Overlays::FinishedTripsHistogram(t, _) => {
Overlays::TripsHistogram(t, _) => {
if now != t {
ui.overlay = Overlays::finished_trips_histogram(ctx, ui);
ui.overlay = Overlays::trips_histogram(ctx, ui);
}
}
Overlays::BusRoute(t, id, _) => {
@ -154,7 +154,7 @@ impl Overlays {
}
}
}
Overlays::FinishedTripsHistogram(_, ref mut c)
Overlays::TripsHistogram(_, ref mut c)
| Overlays::BusDelaysOverTime(_, _, ref mut c) => {
c.align_above(ctx, minimap);
match c.event(ctx) {
@ -186,7 +186,7 @@ impl Overlays {
| Overlays::Edits(ref heatmap) => {
heatmap.draw(g);
}
Overlays::FinishedTripsHistogram(_, ref composite)
Overlays::TripsHistogram(_, ref composite)
| Overlays::BusDelaysOverTime(_, _, ref composite) => {
composite.draw(g);
}
@ -219,7 +219,7 @@ impl Overlays {
pub fn change_overlays(ctx: &mut EventCtx, ui: &UI) -> Option<Transition> {
let mut choices = vec![
WrappedComposite::text_button(ctx, "None", hotkey(Key::N)),
WrappedComposite::text_button(ctx, "finished trips histogram", hotkey(Key::F)),
WrappedComposite::text_button(ctx, "trip times histogram", hotkey(Key::F)),
WrappedComposite::text_button(ctx, "map edits", hotkey(Key::E)),
ManagedWidget::btn(Button::rectangle_svg(
"../data/system/assets/layers/parking_avail.svg",
@ -258,7 +258,7 @@ impl Overlays {
)),
];
if ui.has_prebaked().is_none() {
choices.retain(|w| !w.has_name("finished trips histogram"));
choices.retain(|w| !w.has_name("trip times histogram"));
}
// TODO Grey out the inactive SVGs, and add the green checkmark
if let Some((find, replace)) = match ui.overlay {
@ -284,9 +284,9 @@ impl Overlays {
ManagedWidget::draw_svg(ctx, "../data/system/assets/layers/bus_network.svg"),
)),
Overlays::Edits(_) => Some(("map edits", Button::inactive_button(ctx, "map edits"))),
Overlays::FinishedTripsHistogram(_, _) => Some((
"finished trips histogram",
Button::inactive_button(ctx, "finished trips histogram"),
Overlays::TripsHistogram(_, _) => Some((
"trip times histogram",
Button::inactive_button(ctx, "trip times histogram"),
)),
_ => None,
} {
@ -358,9 +358,9 @@ impl Overlays {
}),
)
.maybe_cb(
"finished trips histogram",
"trip times histogram",
Box::new(|ctx, ui| {
ui.overlay = Overlays::finished_trips_histogram(ctx, ui);
ui.overlay = Overlays::trips_histogram(ctx, ui);
Some(Transition::Pop)
}),
)
@ -567,19 +567,19 @@ impl Overlays {
Overlays::BusNetwork(colorer.build(ctx, ui))
}
pub fn finished_trips_histogram(ctx: &mut EventCtx, ui: &UI) -> Overlays {
pub fn trips_histogram(ctx: &mut EventCtx, ui: &UI) -> Overlays {
if ui.has_prebaked().is_none() {
return Overlays::Inactive;
}
let now = ui.primary.sim.time();
Overlays::FinishedTripsHistogram(
Overlays::TripsHistogram(
now,
Composite::new(
ManagedWidget::col(vec![
ManagedWidget::row(vec![
ManagedWidget::draw_text(ctx, {
let mut txt = Text::from(Line("Are finished trips "));
let mut txt = Text::from(Line("Are trips "));
txt.append(Line("faster").fg(Color::GREEN));
txt.append(Line(", "));
txt.append(Line("slower").fg(Color::RED));
@ -595,7 +595,7 @@ impl Overlays {
ui.primary
.sim
.get_analytics()
.finished_trip_deltas(now, ui.prebaked()),
.trip_time_deltas(now, ui.prebaked()),
ctx,
),
])

View File

@ -19,7 +19,7 @@ use std::collections::BTreeMap;
#[derive(PartialEq, Clone, Copy)]
pub enum Tab {
FinishedTripsSummary,
TripsSummary,
IndividualFinishedTrips(Option<TripMode>),
ParkingOverhead,
ExploreBusRoute,
@ -28,7 +28,7 @@ pub enum Tab {
// Oh the dashboards melted, but we still had the radio
pub fn make(ctx: &mut EventCtx, ui: &UI, tab: Tab) -> Box<dyn State> {
let tab_data = vec![
(Tab::FinishedTripsSummary, "Finished trips summary"),
(Tab::TripsSummary, "Trips summary"),
(
Tab::IndividualFinishedTrips(None),
"Individual finished trips",
@ -50,7 +50,7 @@ pub fn make(ctx: &mut EventCtx, ui: &UI, tab: Tab) -> Box<dyn State> {
.collect::<Vec<_>>();
let (content, cbs) = match tab {
Tab::FinishedTripsSummary => (finished_trips_summary_prebaked(ctx, ui), Vec::new()),
Tab::TripsSummary => (trips_summary_prebaked(ctx, ui), Vec::new()),
Tab::IndividualFinishedTrips(None) => pick_finished_trips_mode(ctx),
Tab::IndividualFinishedTrips(Some(m)) => pick_finished_trips(m, ctx, ui),
Tab::ParkingOverhead => (parking_overhead(ctx, ui), Vec::new()),
@ -91,25 +91,26 @@ pub fn make(ctx: &mut EventCtx, ui: &UI, tab: Tab) -> Box<dyn State> {
ManagedGUIState::fullscreen(c)
}
fn finished_trips_summary_prebaked(ctx: &EventCtx, ui: &UI) -> ManagedWidget {
fn trips_summary_prebaked(ctx: &EventCtx, ui: &UI) -> ManagedWidget {
if ui.has_prebaked().is_none() {
return finished_trips_summary_not_prebaked(ctx, ui);
return trips_summary_not_prebaked(ctx, ui);
}
let (now_all, now_aborted, now_per_mode) = ui
.primary
.sim
.get_analytics()
.all_finished_trips(ui.primary.sim.time());
.trip_times(ui.primary.sim.time());
let (baseline_all, baseline_aborted, baseline_per_mode) =
ui.prebaked().all_finished_trips(ui.primary.sim.time());
ui.prebaked().trip_times(ui.primary.sim.time());
// TODO Include unfinished count
let mut txt = Text::new();
txt.add_appended(vec![
Line("Finished trips as of "),
Line(ui.primary.sim.time().ampm_tostring()).fg(Color::CYAN),
Line("Trips as of "),
Line(ui.primary.sim.time().ampm_tostring()).roboto_bold(),
]);
txt.highlight_last_line(Color::BLUE);
txt.add_appended(vec![
Line(format!(
"{} aborted trips (",
@ -121,7 +122,7 @@ fn finished_trips_summary_prebaked(ctx: &EventCtx, ui: &UI) -> ManagedWidget {
// TODO Refactor
txt.add_appended(vec![
Line(format!(
"{} total finished trips (",
"{} total trips (",
prettyprint_usize(now_all.count())
)),
cmp_count_more(now_all.count(), baseline_all.count()),
@ -129,7 +130,8 @@ fn finished_trips_summary_prebaked(ctx: &EventCtx, ui: &UI) -> ManagedWidget {
]);
if now_all.count() > 0 && baseline_all.count() > 0 {
for stat in Statistic::all() {
txt.add(Line(format!(" {}: {} (", stat, now_all.select(stat))));
// TODO Ideally we could indent
txt.add(Line(format!("{}: {} (", stat, now_all.select(stat))));
txt.append_all(cmp_duration_shorter(
now_all.select(stat),
baseline_all.select(stat),
@ -146,9 +148,10 @@ fn finished_trips_summary_prebaked(ctx: &EventCtx, ui: &UI) -> ManagedWidget {
cmp_count_more(a.count(), b.count()),
Line(")"),
]);
txt.highlight_last_line(Color::BLUE);
if a.count() > 0 && b.count() > 0 {
for stat in Statistic::all() {
txt.add(Line(format!(" {}: {} (", stat, a.select(stat))));
txt.add(Line(format!("{}: {} (", stat, a.select(stat))));
txt.append_all(cmp_duration_shorter(a.select(stat), b.select(stat)));
txt.append(Line(")"));
}
@ -160,45 +163,44 @@ fn finished_trips_summary_prebaked(ctx: &EventCtx, ui: &UI) -> ManagedWidget {
finished_trips_plot(ctx, ui).bg(colors::SECTION_BG),
ManagedWidget::draw_text(
ctx,
Text::from(Line(
"Are finished trips faster or slower than the baseline?",
)),
Text::from(Line("Are trips faster or slower than the baseline?")),
),
Histogram::new(
ui.primary
.sim
.get_analytics()
.finished_trip_deltas(ui.primary.sim.time(), ui.prebaked()),
.trip_time_deltas(ui.primary.sim.time(), ui.prebaked()),
ctx,
)
.bg(colors::SECTION_BG),
])
}
fn finished_trips_summary_not_prebaked(ctx: &EventCtx, ui: &UI) -> ManagedWidget {
fn trips_summary_not_prebaked(ctx: &EventCtx, ui: &UI) -> ManagedWidget {
let (all, aborted, per_mode) = ui
.primary
.sim
.get_analytics()
.all_finished_trips(ui.primary.sim.time());
.trip_times(ui.primary.sim.time());
// TODO Include unfinished count
let mut txt = Text::new();
txt.add_appended(vec![
Line("Finished trips as of "),
Line(ui.primary.sim.time().ampm_tostring()).fg(Color::CYAN),
Line("Trips as of "),
Line(ui.primary.sim.time().ampm_tostring()).roboto_bold(),
]);
txt.highlight_last_line(Color::BLUE);
txt.add(Line(format!(
" {} aborted trips",
"{} aborted trips",
prettyprint_usize(aborted)
)));
txt.add(Line(format!(
"{} total finished trips",
"{} total trips",
prettyprint_usize(all.count())
)));
if all.count() > 0 {
for stat in Statistic::all() {
txt.add(Line(format!(" {}: {}", stat, all.select(stat))));
txt.add(Line(format!("{}: {}", stat, all.select(stat))));
}
}
@ -209,9 +211,10 @@ fn finished_trips_summary_not_prebaked(ctx: &EventCtx, ui: &UI) -> ManagedWidget
prettyprint_usize(a.count()),
mode
)));
txt.highlight_last_line(Color::BLUE);
if a.count() > 0 {
for stat in Statistic::all() {
txt.add(Line(format!(" {}: {}", stat, a.select(stat))));
txt.add(Line(format!("{}: {}", stat, a.select(stat))));
}
}
}

View File

@ -76,14 +76,13 @@ fn gridlock_panel(ui: &UI) -> Text {
.primary
.sim
.get_analytics()
.all_finished_trips(ui.primary.sim.time());
let (baseline_all, _, baseline_per_mode) =
ui.prebaked().all_finished_trips(ui.primary.sim.time());
.trip_times(ui.primary.sim.time());
let (baseline_all, _, baseline_per_mode) = ui.prebaked().trip_times(ui.primary.sim.time());
let mut txt = Text::new();
txt.add_appended(vec![
Line(format!(
"{} total finished trips (",
"{} total trips (",
prettyprint_usize(now_all.count())
)),
cmp_count_fewer(now_all.count(), baseline_all.count()),

View File

@ -65,8 +65,15 @@ impl GameplayState for FasterTrips {
pub fn faster_trips_panel(mode: TripMode, ui: &UI) -> Text {
let time = ui.primary.sim.time();
let now = ui.primary.sim.get_analytics().finished_trips(time, mode);
let baseline = ui.prebaked().finished_trips(time, mode);
let now = ui
.primary
.sim
.get_analytics()
.trip_times(time)
.2
.remove(&mode)
.unwrap();
let baseline = ui.prebaked().trip_times(time).2.remove(&mode).unwrap();
// Enable to debug why sim results don't match prebaked.
if false && !now.seems_eq(&baseline) {
@ -88,7 +95,7 @@ pub fn faster_trips_panel(mode: TripMode, ui: &UI) -> Text {
let mut txt = Text::new();
txt.add_appended(vec![
Line(format!(
"{} finished {} trips (",
"{} {} trips (",
prettyprint_usize(now.count()),
mode
)),

View File

@ -42,7 +42,7 @@ impl GameplayState for FixTrafficSignals {
) -> (Option<Transition>, bool) {
// Once is never...
if self.once {
ui.overlay = Overlays::finished_trips_histogram(ctx, ui);
ui.overlay = Overlays::trips_histogram(ctx, ui);
self.once = false;
}
@ -86,14 +86,10 @@ fn final_score(ui: &UI) -> String {
.primary
.sim
.get_analytics()
.all_finished_trips(time)
.0
.select(Statistic::Mean);
let baseline = ui
.prebaked()
.all_finished_trips(time)
.trip_times(time)
.0
.select(Statistic::Mean);
let baseline = ui.prebaked().trip_times(time).0.select(Statistic::Mean);
if now < baseline - GOAL {
format!(

View File

@ -387,7 +387,7 @@ impl GameplayState for Tutorial {
.primary
.sim
.get_analytics()
.all_finished_trips(ui.primary.sim.time());
.trip_times(ui.primary.sim.time());
let max = all.select(Statistic::Max);
if !tut.score_delivered {

View File

@ -395,7 +395,7 @@ impl AgentMeter {
ManagedWidget::draw_text(ctx, txt)
},
// TODO The SVG button uses clip and doesn't seem to work
WrappedComposite::text_button(ctx, "finished trip data", hotkey(Key::Q)),
WrappedComposite::text_button(ctx, "finished trips data", hotkey(Key::Q)),
];
// TODO Slight hack. If we're jumping right into a tutorial and don't have the prebaked
// stuff loaded yet, just skip a tick.
@ -405,8 +405,8 @@ impl AgentMeter {
.primary
.sim
.get_analytics()
.all_finished_trips(ui.primary.sim.time());
let (baseline, _, _) = ui.prebaked().all_finished_trips(ui.primary.sim.time());
.trip_times(ui.primary.sim.time());
let (baseline, _, _) = ui.prebaked().trip_times(ui.primary.sim.time());
let mut txt = Text::from(Line(format!("{} trip time: ", stat)).size(20));
if now.count() > 0 && baseline.count() > 0 {
txt.append_all(cmp_duration_shorter(
@ -439,11 +439,11 @@ impl AgentMeter {
}
match self.composite.event(ctx) {
Some(Outcome::Clicked(x)) => match x.as_ref() {
"finished trip data" => {
"finished trips data" => {
return Some(Transition::Push(dashboards::make(
ctx,
ui,
dashboards::Tab::FinishedTripsSummary,
dashboards::Tab::TripsSummary,
)));
}
_ => unreachable!(),

View File

@ -15,6 +15,8 @@ pub struct Analytics {
pub(crate) test_expectations: VecDeque<Event>,
pub bus_arrivals: Vec<(Time, CarID, BusRouteID, BusStopID)>,
pub bus_passengers_waiting: Vec<(Time, BusStopID, BusRouteID)>,
// TODO Scraping TripMode from TripPhaseStarting is frustrating.
pub started_trips: BTreeMap<TripID, (Time, TripMode)>,
// TODO Hack: No TripMode means aborted
// Finish time, ID, mode (or None as aborted), trip duration
pub finished_trips: Vec<(Time, TripID, Option<TripMode>, Duration)>,
@ -55,6 +57,7 @@ impl Analytics {
test_expectations: VecDeque::new(),
bus_arrivals: Vec::new(),
bus_passengers_waiting: Vec::new(),
started_trips: BTreeMap::new(),
finished_trips: Vec::new(),
trip_log: Vec::new(),
intersection_delays: BTreeMap::new(),
@ -112,6 +115,19 @@ impl Analytics {
self.bus_passengers_waiting.push((time, stop, route));
}
// Started trips
if let Event::TripPhaseStarting(id, mode, _, _) = ev {
// TODO More efficiently
if !self.started_trips.contains_key(&id)
&& !self
.finished_trips
.iter()
.any(|(_, trip, _, _)| *trip == id)
{
self.started_trips.insert(id, (time, mode));
}
}
// Finished trips
if let Event::TripFinished(id, mode, dt) = ev {
self.finished_trips.push((time, id, Some(mode), dt));
@ -129,7 +145,7 @@ impl Analytics {
// TODO Kinda hacky, but these all consume the event, so kinda bundle em.
match ev {
Event::TripPhaseStarting(id, maybe_req, metadata) => {
Event::TripPhaseStarting(id, _, maybe_req, metadata) => {
self.trip_log.push((time, id, maybe_req, metadata));
}
Event::TripAborted(id) => {
@ -160,21 +176,9 @@ impl Analytics {
// TODO If these ever need to be speeded up, just cache the histogram and index in the events
// list.
pub fn finished_trips(&self, now: Time, mode: TripMode) -> DurationHistogram {
let mut distrib = DurationHistogram::new();
for (t, _, m, dt) in &self.finished_trips {
if *t > now {
break;
}
if *m == Some(mode) {
distrib.add(*dt);
}
}
distrib
}
// Returns (all trips except aborted, number of aborted trips, trips by mode)
pub fn all_finished_trips(
// Returns (all trips except aborted, number of aborted trips, trips by mode). For completed
// and ongoing trips as of now.
pub fn trip_times(
&self,
now: Time,
) -> (
@ -182,16 +186,18 @@ impl Analytics {
usize,
BTreeMap<TripMode, DurationHistogram>,
) {
let mut ongoing = self.started_trips.clone();
let mut per_mode = TripMode::all()
.into_iter()
.map(|m| (m, DurationHistogram::new()))
.collect::<BTreeMap<_, _>>();
let mut all = DurationHistogram::new();
let mut num_aborted = 0;
for (t, _, m, dt) in &self.finished_trips {
for (t, id, m, dt) in &self.finished_trips {
if *t > now {
break;
}
ongoing.remove(id);
if let Some(mode) = *m {
all.add(*dt);
per_mode.get_mut(&mode).unwrap().add(*dt);
@ -199,35 +205,42 @@ impl Analytics {
num_aborted += 1;
}
}
for (_, (start, m)) in ongoing {
if start < now {
all.add(now - start);
per_mode.get_mut(&m).unwrap().add(now - start);
}
}
(all, num_aborted, per_mode)
}
// Returns unsorted list of deltas, one for each trip finished in both worlds. Positive dt
// means faster.
pub fn finished_trip_deltas(&self, now: Time, baseline: &Analytics) -> Vec<Duration> {
let a: BTreeMap<TripID, Duration> = self
.finished_trips
.iter()
.filter_map(|(t, id, mode, dt)| {
if *t <= now && mode.is_some() {
Some((*id, *dt))
} else {
None
// Returns unsorted list of deltas, one for each trip finished or ongoing in both worlds.
// Positive dt means faster.
pub fn trip_time_deltas(&self, now: Time, baseline: &Analytics) -> Vec<Duration> {
fn trip_times(a: &Analytics, now: Time) -> BTreeMap<TripID, Duration> {
let mut ongoing = a.started_trips.clone();
let mut trips = BTreeMap::new();
for (t, id, m, dt) in &a.finished_trips {
if *t > now {
break;
}
})
.collect();
let b: BTreeMap<TripID, Duration> = baseline
.finished_trips
.iter()
.filter_map(|(t, id, mode, dt)| {
if *t <= now && mode.is_some() {
Some((*id, *dt))
} else {
None
ongoing.remove(id);
if m.is_some() {
trips.insert(*id, *dt);
}
})
.collect();
}
for (trip, (start, _)) in ongoing {
if start < now {
trips.insert(trip, now - start);
}
}
trips
}
let a = trip_times(&self, now);
let b = trip_times(baseline, now);
// TODO Think through what missing (aborted) in one but not the other means
a.into_iter()
.filter_map(|(id, dt1)| b.get(&id).map(|dt2| *dt2 - dt1))
.collect()

View File

@ -27,7 +27,7 @@ pub enum Event {
TripFinished(TripID, TripMode, Duration),
TripAborted(TripID),
TripPhaseStarting(TripID, Option<PathRequest>, String),
TripPhaseStarting(TripID, TripMode, Option<PathRequest>, String),
// Just use for parking replanning. Not happy about copying the full path in here, but the way
// to plumb info into Analytics is Event.

View File

@ -1,5 +1,5 @@
use crate::mechanics::Queue;
use crate::{Event, ParkingSimState, ParkingSpot, SidewalkSpot, TripID, Vehicle};
use crate::{Event, ParkingSimState, ParkingSpot, SidewalkSpot, TripID, TripMode, Vehicle};
use geom::Distance;
use map_model::{
BuildingID, IntersectionID, LaneID, Map, Path, PathConstraints, PathRequest, PathStep,
@ -194,6 +194,7 @@ impl Router {
) {
events.push(Event::TripPhaseStarting(
trip,
TripMode::Drive,
Some(PathRequest {
start: Position::new(current_lane, front),
end: new_pos,
@ -214,6 +215,7 @@ impl Router {
// TODO This path might not be the same as the one found here...
events.push(Event::TripPhaseStarting(
trip,
TripMode::Drive,
Some(PathRequest {
start: Position::new(current_lane, front),
end: new_pos,

View File

@ -398,6 +398,12 @@ impl Sim {
}
events.push(Event::TripPhaseStarting(
create_car.trip,
// TODO sketchy...
if create_car.vehicle.id.1 == VehicleType::Car {
TripMode::Drive
} else {
TripMode::Bike
},
Some(create_car.req.clone()),
if create_car.vehicle.id.1 == VehicleType::Car {
"driving".to_string()
@ -485,6 +491,7 @@ impl Sim {
);
events.push(Event::TripPhaseStarting(
create_ped.trip,
TripMode::Walk,
Some(create_ped.req.clone()),
"walking".to_string(),
));

View File

@ -1,4 +1,6 @@
use crate::{CarID, Event, PedestrianID, Router, Scheduler, TripManager, WalkingSimState};
use crate::{
CarID, Event, PedestrianID, Router, Scheduler, TripManager, TripMode, WalkingSimState,
};
use abstutil::{deserialize_btreemap, serialize_btreemap};
use geom::{Distance, Time};
use map_model::{
@ -184,6 +186,7 @@ impl TransitSimState {
let trip = trips.ped_boarded_bus(ped, walking);
self.events.push(Event::TripPhaseStarting(
trip,
TripMode::Transit,
Some(PathRequest {
start: map.get_bs(stop1).driving_pos,
end: map.get_bs(stop2).driving_pos,

View File

@ -351,6 +351,7 @@ impl TripManager {
self.events.push(Event::PedReachedBusStop(ped, stop, route));
self.events.push(Event::TripPhaseStarting(
trip.id,
trip.mode,
None,
format!("waiting for bus {}", map.get_br(route).name),
));