mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-29 12:43:38 +03:00
track blocked time for finished trips, make a way to find people with
high blocked times
This commit is contained in:
parent
008ac27abb
commit
3e49134088
@ -111,7 +111,7 @@ pub fn trips(
|
||||
.has_prebaked()
|
||||
.and_then(|_| app.prebaked().finished_trip_time(*t))
|
||||
{
|
||||
let experiment = app.primary.sim.finished_trip_time(*t);
|
||||
let (experiment, _) = app.primary.sim.finished_trip_time(*t);
|
||||
let mut txt = Text::from(Line("finished ").small());
|
||||
txt.append_all(cmp_duration_shorter(experiment, orig));
|
||||
txt.draw(ctx)
|
||||
|
@ -39,8 +39,9 @@ pub fn details(ctx: &mut EventCtx, app: &App, trip: TripID, details: &mut Detail
|
||||
let total_trip_time = end_time.unwrap_or_else(|| sim.time()) - phases[0].start_time;
|
||||
|
||||
// Describe this leg of the trip
|
||||
let col_width = 7;
|
||||
let progress_along_path = if let Some(a) = sim.trip_to_agent(trip).ok() {
|
||||
let col_width = 7;
|
||||
|
||||
let props = sim.agent_properties(a);
|
||||
// This is different than the entire TripMode, and also not the current TripPhaseType.
|
||||
// Sigh.
|
||||
@ -101,11 +102,19 @@ pub fn details(ctx: &mut EventCtx, app: &App, trip: TripID, details: &mut Detail
|
||||
|
||||
Some(props.dist_crossed / props.total_dist)
|
||||
} else {
|
||||
let col_width = 15;
|
||||
|
||||
// The trip is finished
|
||||
col.push(Widget::row(vec![
|
||||
Widget::row(vec![Line("Trip time").secondary().draw(ctx)]).force_width(ctx, col_width),
|
||||
total_trip_time.to_string().draw_text(ctx),
|
||||
]));
|
||||
let (_, waiting) = sim.finished_trip_time(trip);
|
||||
col.push(Widget::row(vec![
|
||||
Widget::row(vec![Line("Total waiting time").secondary().draw(ctx)])
|
||||
.force_width(ctx, col_width),
|
||||
waiting.to_string().draw_text(ctx),
|
||||
]));
|
||||
None
|
||||
};
|
||||
|
||||
|
@ -414,7 +414,7 @@ impl Layers {
|
||||
app,
|
||||
population::Options {
|
||||
heatmap: Some(HeatmapOptions::new()),
|
||||
with_finished_trip: false,
|
||||
with_finished_trip_blocked_pct: None,
|
||||
},
|
||||
);
|
||||
Some(Transition::Pop)
|
||||
|
@ -4,7 +4,7 @@ use crate::layer::Layers;
|
||||
use abstutil::prettyprint_usize;
|
||||
use ezgui::{
|
||||
hotkey, Btn, Checkbox, Color, Composite, EventCtx, GeomBatch, HorizontalAlignment, Key, Line,
|
||||
VerticalAlignment, Widget,
|
||||
Spinner, TextExt, VerticalAlignment, Widget,
|
||||
};
|
||||
use geom::{Circle, Distance, Pt2D};
|
||||
use sim::{GetDrawAgents, PersonState, TripResult};
|
||||
@ -14,11 +14,12 @@ use std::collections::HashSet;
|
||||
// return this kind of data instead!
|
||||
pub fn new(ctx: &mut EventCtx, app: &App, opts: Options) -> Layers {
|
||||
let filter = |p| {
|
||||
if opts.with_finished_trip {
|
||||
if let Some(pct) = opts.with_finished_trip_blocked_pct {
|
||||
// TODO This is probably inefficient...
|
||||
app.primary.sim.get_person(p).trips.iter().any(|t| {
|
||||
if let TripResult::TripDone = app.primary.sim.trip_to_agent(*t) {
|
||||
true
|
||||
let (total, blocked) = app.primary.sim.finished_trip_time(*t);
|
||||
(100.0 * blocked / total) as usize >= pct
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@ -88,7 +89,7 @@ pub struct Options {
|
||||
// If None, just a dot map
|
||||
pub heatmap: Option<HeatmapOptions>,
|
||||
// TODO More filters... Find people with finished/future trips of any/some mode
|
||||
pub with_finished_trip: bool,
|
||||
pub with_finished_trip_blocked_pct: Option<usize>,
|
||||
}
|
||||
|
||||
fn make_controls(
|
||||
@ -122,8 +123,17 @@ fn make_controls(
|
||||
ctx,
|
||||
"Filter by people with a finished trip",
|
||||
None,
|
||||
opts.with_finished_trip,
|
||||
opts.with_finished_trip_blocked_pct.is_some(),
|
||||
));
|
||||
if let Some(pct) = opts.with_finished_trip_blocked_pct {
|
||||
col.push(Widget::row(vec![
|
||||
"% of time spent waiting".draw_text(ctx).margin(5),
|
||||
Spinner::new(ctx, (0, 100), pct)
|
||||
.named("blocked ratio")
|
||||
.align_right()
|
||||
.centered_vert(),
|
||||
]));
|
||||
}
|
||||
|
||||
col.push(Checkbox::text(
|
||||
ctx,
|
||||
@ -148,6 +158,15 @@ pub fn options(c: &mut Composite) -> Options {
|
||||
};
|
||||
Options {
|
||||
heatmap,
|
||||
with_finished_trip: c.is_checked("Filter by people with a finished trip"),
|
||||
with_finished_trip_blocked_pct: if c.is_checked("Filter by people with a finished trip") {
|
||||
if c.has_widget("blocked ratio") {
|
||||
Some(c.spinner("blocked ratio"))
|
||||
} else {
|
||||
// Just changed, use default
|
||||
Some(0)
|
||||
}
|
||||
} else {
|
||||
None
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -131,8 +131,15 @@ impl Analytics {
|
||||
}
|
||||
|
||||
// Finished trips
|
||||
if let Event::TripFinished(id, mode, dt) = ev {
|
||||
self.finished_trips.push((time, id, Some(mode), dt));
|
||||
if let Event::TripFinished {
|
||||
trip,
|
||||
mode,
|
||||
total_time,
|
||||
..
|
||||
} = ev
|
||||
{
|
||||
self.finished_trips
|
||||
.push((time, trip, Some(mode), total_time));
|
||||
} else if let Event::TripAborted(id, mode) = ev {
|
||||
self.finished_trips.push((time, id, None, Duration::ZERO));
|
||||
if !self.started_trips.contains_key(&id) {
|
||||
@ -156,9 +163,9 @@ impl Analytics {
|
||||
Event::TripAborted(id, _) => {
|
||||
self.trip_log.push((time, id, None, TripPhaseType::Aborted));
|
||||
}
|
||||
Event::TripFinished(id, _, _) => {
|
||||
Event::TripFinished { trip, .. } => {
|
||||
self.trip_log
|
||||
.push((time, id, None, TripPhaseType::Finished));
|
||||
.push((time, trip, None, TripPhaseType::Finished));
|
||||
}
|
||||
Event::PathAmended(path) => {
|
||||
self.record_demand(&path, map);
|
||||
|
@ -27,7 +27,12 @@ pub enum Event {
|
||||
AgentEntersTraversable(AgentID, Traversable),
|
||||
IntersectionDelayMeasured(IntersectionID, Duration),
|
||||
|
||||
TripFinished(TripID, TripMode, Duration),
|
||||
TripFinished {
|
||||
trip: TripID,
|
||||
mode: TripMode,
|
||||
total_time: Duration,
|
||||
blocked_time: Duration,
|
||||
},
|
||||
TripAborted(TripID, TripMode),
|
||||
TripPhaseStarting(
|
||||
TripID,
|
||||
|
@ -451,7 +451,12 @@ impl DrivingSimState {
|
||||
) {
|
||||
Some(ActionAtEnd::VanishAtBorder(i)) => {
|
||||
car.total_blocked_time += now - blocked_since;
|
||||
trips.car_or_bike_reached_border(now, car.vehicle.id, i);
|
||||
trips.car_or_bike_reached_border(
|
||||
now,
|
||||
car.vehicle.id,
|
||||
i,
|
||||
car.total_blocked_time,
|
||||
);
|
||||
false
|
||||
}
|
||||
Some(ActionAtEnd::AbortTrip) => {
|
||||
@ -483,7 +488,14 @@ impl DrivingSimState {
|
||||
}
|
||||
Some(ActionAtEnd::StopBiking(bike_rack)) => {
|
||||
car.total_blocked_time += now - blocked_since;
|
||||
trips.bike_reached_end(now, car.vehicle.id, bike_rack, map, scheduler);
|
||||
trips.bike_reached_end(
|
||||
now,
|
||||
car.vehicle.id,
|
||||
bike_rack,
|
||||
car.total_blocked_time,
|
||||
map,
|
||||
scheduler,
|
||||
);
|
||||
false
|
||||
}
|
||||
Some(ActionAtEnd::BusAtStop) => {
|
||||
@ -538,7 +550,15 @@ impl DrivingSimState {
|
||||
vehicle: car.vehicle.clone(),
|
||||
spot,
|
||||
});
|
||||
trips.car_reached_parking_spot(now, car.vehicle.id, spot, map, parking, scheduler);
|
||||
trips.car_reached_parking_spot(
|
||||
now,
|
||||
car.vehicle.id,
|
||||
spot,
|
||||
car.total_blocked_time,
|
||||
map,
|
||||
parking,
|
||||
scheduler,
|
||||
);
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -125,7 +125,13 @@ impl WalkingSimState {
|
||||
self.peds_per_traversable
|
||||
.remove(ped.path.current_step().as_traversable(), ped.id);
|
||||
trips.ped_reached_parking_spot(
|
||||
now, ped.id, spot, map, parking, scheduler,
|
||||
now,
|
||||
ped.id,
|
||||
spot,
|
||||
ped.total_blocked_time,
|
||||
map,
|
||||
parking,
|
||||
scheduler,
|
||||
);
|
||||
self.peds.remove(&id);
|
||||
}
|
||||
@ -140,9 +146,14 @@ impl WalkingSimState {
|
||||
scheduler.push(ped.state.get_end_time(), Command::UpdatePed(ped.id));
|
||||
}
|
||||
SidewalkPOI::BusStop(stop) => {
|
||||
if let Some(route) =
|
||||
trips.ped_reached_bus_stop(now, ped.id, stop, map, transit)
|
||||
{
|
||||
if let Some(route) = trips.ped_reached_bus_stop(
|
||||
now,
|
||||
ped.id,
|
||||
stop,
|
||||
ped.total_blocked_time,
|
||||
map,
|
||||
transit,
|
||||
) {
|
||||
ped.state = PedState::WaitingForBus(route, now);
|
||||
} else {
|
||||
self.peds_per_traversable
|
||||
@ -153,7 +164,7 @@ impl WalkingSimState {
|
||||
SidewalkPOI::Border(i) => {
|
||||
self.peds_per_traversable
|
||||
.remove(ped.path.current_step().as_traversable(), ped.id);
|
||||
trips.ped_reached_border(now, ped.id, i, map);
|
||||
trips.ped_reached_border(now, ped.id, i, ped.total_blocked_time, map);
|
||||
self.peds.remove(&id);
|
||||
}
|
||||
SidewalkPOI::BikeRack(driving_pos) => {
|
||||
@ -217,13 +228,20 @@ impl WalkingSimState {
|
||||
PedState::EnteringBuilding(bldg, _) => {
|
||||
self.peds_per_traversable
|
||||
.remove(ped.path.current_step().as_traversable(), ped.id);
|
||||
trips.ped_reached_building(now, ped.id, bldg, map);
|
||||
trips.ped_reached_building(now, ped.id, bldg, ped.total_blocked_time, map);
|
||||
self.peds.remove(&id);
|
||||
}
|
||||
PedState::StartingToBike(ref spot, _, _) => {
|
||||
self.peds_per_traversable
|
||||
.remove(ped.path.current_step().as_traversable(), ped.id);
|
||||
trips.ped_ready_to_bike(now, ped.id, spot.clone(), map, scheduler);
|
||||
trips.ped_ready_to_bike(
|
||||
now,
|
||||
ped.id,
|
||||
spot.clone(),
|
||||
ped.total_blocked_time,
|
||||
map,
|
||||
scheduler,
|
||||
);
|
||||
self.peds.remove(&id);
|
||||
}
|
||||
PedState::FinishingBiking(ref spot, _, _) => {
|
||||
|
@ -535,6 +535,7 @@ impl Sim {
|
||||
self.time,
|
||||
create_ped.id,
|
||||
ParkingSpot::Offstreet(*b2, *idx),
|
||||
Duration::ZERO,
|
||||
map,
|
||||
&self.parking,
|
||||
&mut self.scheduler,
|
||||
@ -966,7 +967,8 @@ impl Sim {
|
||||
pub fn trip_info(&self, id: TripID) -> (Time, TripEndpoint, TripEndpoint, TripMode) {
|
||||
self.trips.trip_info(id)
|
||||
}
|
||||
pub fn finished_trip_time(&self, id: TripID) -> Duration {
|
||||
// Only for finished trips. Returns (total time, total waiting time)
|
||||
pub fn finished_trip_time(&self, id: TripID) -> (Duration, Duration) {
|
||||
self.trips.finished_trip_time(id)
|
||||
}
|
||||
|
||||
|
@ -182,7 +182,8 @@ impl TransitSimState {
|
||||
{
|
||||
if bus.route == route {
|
||||
bus.passengers.push((ped, stop2));
|
||||
let (trip, person) = trips.ped_boarded_bus(now, ped, walking);
|
||||
let (trip, person) =
|
||||
trips.ped_boarded_bus(now, ped, now - started_waiting, walking);
|
||||
self.events.push(Event::TripPhaseStarting(
|
||||
trip,
|
||||
person,
|
||||
|
@ -103,6 +103,7 @@ impl TripManager {
|
||||
person,
|
||||
spawned_at,
|
||||
finished_at: None,
|
||||
total_blocked_time: Duration::ZERO,
|
||||
aborted: false,
|
||||
mode,
|
||||
legs: VecDeque::from(legs),
|
||||
@ -156,12 +157,14 @@ impl TripManager {
|
||||
now: Time,
|
||||
car: CarID,
|
||||
spot: ParkingSpot,
|
||||
blocked_time: Duration,
|
||||
map: &Map,
|
||||
parking: &ParkingSimState,
|
||||
scheduler: &mut Scheduler,
|
||||
) {
|
||||
self.events.push(Event::CarReachedParkingSpot(car, spot));
|
||||
let trip = &mut self.trips[self.active_trip_mode.remove(&AgentID::Car(car)).unwrap().0];
|
||||
trip.total_blocked_time += blocked_time;
|
||||
|
||||
match trip.legs.pop_front() {
|
||||
Some(TripLeg::Drive(vehicle, DrivingGoal::ParkNear(_))) => assert_eq!(car, vehicle.id),
|
||||
@ -176,11 +179,12 @@ impl TripManager {
|
||||
assert!(!trip.finished_at.is_some());
|
||||
trip.finished_at = Some(now);
|
||||
self.unfinished_trips -= 1;
|
||||
self.events.push(Event::TripFinished(
|
||||
trip.id,
|
||||
trip.mode,
|
||||
now - trip.spawned_at,
|
||||
));
|
||||
self.events.push(Event::TripFinished {
|
||||
trip: trip.id,
|
||||
mode: trip.mode,
|
||||
total_time: now - trip.spawned_at,
|
||||
blocked_time: trip.total_blocked_time,
|
||||
});
|
||||
self.people[trip.person.0].state = PersonState::Inside(b1);
|
||||
self.events
|
||||
.push(Event::PersonEntersBuilding(trip.person, b1));
|
||||
@ -206,6 +210,7 @@ impl TripManager {
|
||||
now: Time,
|
||||
ped: PedestrianID,
|
||||
spot: ParkingSpot,
|
||||
blocked_time: Duration,
|
||||
map: &Map,
|
||||
parking: &ParkingSimState,
|
||||
scheduler: &mut Scheduler,
|
||||
@ -216,6 +221,7 @@ impl TripManager {
|
||||
.remove(&AgentID::Pedestrian(ped))
|
||||
.unwrap()
|
||||
.0];
|
||||
trip.total_blocked_time += blocked_time;
|
||||
|
||||
trip.assert_walking_leg(ped, SidewalkSpot::parking_spot(spot, map, parking));
|
||||
let (car, drive_to) = match trip.legs[0] {
|
||||
@ -272,6 +278,7 @@ impl TripManager {
|
||||
now: Time,
|
||||
ped: PedestrianID,
|
||||
spot: SidewalkSpot,
|
||||
blocked_time: Duration,
|
||||
map: &Map,
|
||||
scheduler: &mut Scheduler,
|
||||
) {
|
||||
@ -280,6 +287,7 @@ impl TripManager {
|
||||
.remove(&AgentID::Pedestrian(ped))
|
||||
.unwrap()
|
||||
.0];
|
||||
trip.total_blocked_time += blocked_time;
|
||||
|
||||
trip.assert_walking_leg(ped, spot.clone());
|
||||
let (vehicle, drive_to) = match trip.legs[0] {
|
||||
@ -326,6 +334,7 @@ impl TripManager {
|
||||
now: Time,
|
||||
bike: CarID,
|
||||
bike_rack: SidewalkSpot,
|
||||
blocked_time: Duration,
|
||||
map: &Map,
|
||||
scheduler: &mut Scheduler,
|
||||
) {
|
||||
@ -334,6 +343,7 @@ impl TripManager {
|
||||
bike_rack.sidewalk_pos.lane(),
|
||||
));
|
||||
let trip = &mut self.trips[self.active_trip_mode.remove(&AgentID::Car(bike)).unwrap().0];
|
||||
trip.total_blocked_time += blocked_time;
|
||||
|
||||
match trip.legs.pop_front() {
|
||||
Some(TripLeg::Drive(vehicle, DrivingGoal::ParkNear(_))) => assert_eq!(vehicle.id, bike),
|
||||
@ -350,6 +360,7 @@ impl TripManager {
|
||||
now: Time,
|
||||
ped: PedestrianID,
|
||||
bldg: BuildingID,
|
||||
blocked_time: Duration,
|
||||
map: &Map,
|
||||
) {
|
||||
let trip = &mut self.trips[self
|
||||
@ -357,16 +368,19 @@ impl TripManager {
|
||||
.remove(&AgentID::Pedestrian(ped))
|
||||
.unwrap()
|
||||
.0];
|
||||
trip.total_blocked_time += blocked_time;
|
||||
|
||||
trip.assert_walking_leg(ped, SidewalkSpot::building(bldg, map));
|
||||
assert!(trip.legs.is_empty());
|
||||
assert!(!trip.finished_at.is_some());
|
||||
trip.finished_at = Some(now);
|
||||
self.unfinished_trips -= 1;
|
||||
self.events.push(Event::TripFinished(
|
||||
trip.id,
|
||||
trip.mode,
|
||||
now - trip.spawned_at,
|
||||
));
|
||||
self.events.push(Event::TripFinished {
|
||||
trip: trip.id,
|
||||
mode: trip.mode,
|
||||
total_time: now - trip.spawned_at,
|
||||
blocked_time: trip.total_blocked_time,
|
||||
});
|
||||
self.people[trip.person.0].state = PersonState::Inside(bldg);
|
||||
self.events
|
||||
.push(Event::PersonEntersBuilding(trip.person, bldg));
|
||||
@ -378,10 +392,13 @@ impl TripManager {
|
||||
now: Time,
|
||||
ped: PedestrianID,
|
||||
stop: BusStopID,
|
||||
blocked_time: Duration,
|
||||
map: &Map,
|
||||
transit: &mut TransitSimState,
|
||||
) -> Option<BusRouteID> {
|
||||
let trip = &mut self.trips[self.active_trip_mode[&AgentID::Pedestrian(ped)].0];
|
||||
trip.total_blocked_time += blocked_time;
|
||||
|
||||
match trip.legs[0] {
|
||||
TripLeg::Walk(p, _, ref spot) => {
|
||||
assert_eq!(p, ped);
|
||||
@ -422,15 +439,19 @@ impl TripManager {
|
||||
&mut self,
|
||||
now: Time,
|
||||
ped: PedestrianID,
|
||||
blocked_time: Duration,
|
||||
walking: &mut WalkingSimState,
|
||||
) -> (TripID, PersonID) {
|
||||
// TODO Make sure canonical pt is the bus while the ped is riding it
|
||||
let trip = &mut self.trips[self.active_trip_mode[&AgentID::Pedestrian(ped)].0];
|
||||
trip.total_blocked_time += blocked_time;
|
||||
|
||||
trip.legs.pop_front();
|
||||
walking.ped_boarded_bus(now, ped);
|
||||
(trip.id, trip.person)
|
||||
}
|
||||
|
||||
// TODO Need to characterize delay the bus experienced
|
||||
pub fn ped_left_bus(
|
||||
&mut self,
|
||||
now: Time,
|
||||
@ -458,6 +479,7 @@ impl TripManager {
|
||||
now: Time,
|
||||
ped: PedestrianID,
|
||||
i: IntersectionID,
|
||||
blocked_time: Duration,
|
||||
map: &Map,
|
||||
) {
|
||||
self.events.push(Event::PedReachedBorder(ped, i));
|
||||
@ -466,22 +488,33 @@ impl TripManager {
|
||||
.remove(&AgentID::Pedestrian(ped))
|
||||
.unwrap()
|
||||
.0];
|
||||
trip.total_blocked_time += blocked_time;
|
||||
|
||||
trip.assert_walking_leg(ped, SidewalkSpot::end_at_border(i, map).unwrap());
|
||||
assert!(trip.legs.is_empty());
|
||||
assert!(!trip.finished_at.is_some());
|
||||
trip.finished_at = Some(now);
|
||||
self.unfinished_trips -= 1;
|
||||
self.events.push(Event::TripFinished(
|
||||
trip.id,
|
||||
trip.mode,
|
||||
now - trip.spawned_at,
|
||||
));
|
||||
self.events.push(Event::TripFinished {
|
||||
trip: trip.id,
|
||||
mode: trip.mode,
|
||||
total_time: now - trip.spawned_at,
|
||||
blocked_time: trip.total_blocked_time,
|
||||
});
|
||||
self.people[trip.person.0].state = PersonState::OffMap;
|
||||
}
|
||||
|
||||
pub fn car_or_bike_reached_border(&mut self, now: Time, car: CarID, i: IntersectionID) {
|
||||
pub fn car_or_bike_reached_border(
|
||||
&mut self,
|
||||
now: Time,
|
||||
car: CarID,
|
||||
i: IntersectionID,
|
||||
blocked_time: Duration,
|
||||
) {
|
||||
self.events.push(Event::CarOrBikeReachedBorder(car, i));
|
||||
let trip = &mut self.trips[self.active_trip_mode.remove(&AgentID::Car(car)).unwrap().0];
|
||||
trip.total_blocked_time += blocked_time;
|
||||
|
||||
match trip.legs.pop_front().unwrap() {
|
||||
TripLeg::Drive(_, DrivingGoal::Border(int, _)) => assert_eq!(i, int),
|
||||
_ => unreachable!(),
|
||||
@ -490,11 +523,12 @@ impl TripManager {
|
||||
assert!(!trip.finished_at.is_some());
|
||||
trip.finished_at = Some(now);
|
||||
self.unfinished_trips -= 1;
|
||||
self.events.push(Event::TripFinished(
|
||||
trip.id,
|
||||
trip.mode,
|
||||
now - trip.spawned_at,
|
||||
));
|
||||
self.events.push(Event::TripFinished {
|
||||
trip: trip.id,
|
||||
mode: trip.mode,
|
||||
total_time: now - trip.spawned_at,
|
||||
blocked_time: trip.total_blocked_time,
|
||||
});
|
||||
self.people[trip.person.0].state = PersonState::OffMap;
|
||||
}
|
||||
|
||||
@ -616,9 +650,9 @@ impl TripManager {
|
||||
let t = &self.trips[id.0];
|
||||
(t.spawned_at, t.start.clone(), t.end.clone(), t.mode)
|
||||
}
|
||||
pub fn finished_trip_time(&self, id: TripID) -> Duration {
|
||||
pub fn finished_trip_time(&self, id: TripID) -> (Duration, Duration) {
|
||||
let t = &self.trips[id.0];
|
||||
t.finished_at.unwrap() - t.spawned_at
|
||||
(t.finished_at.unwrap() - t.spawned_at, t.total_blocked_time)
|
||||
}
|
||||
|
||||
pub fn count_trips(&self, endpt: TripEndpoint, now: Time) -> TripCount {
|
||||
@ -708,6 +742,7 @@ struct Trip {
|
||||
id: TripID,
|
||||
spawned_at: Time,
|
||||
finished_at: Option<Time>,
|
||||
total_blocked_time: Duration,
|
||||
aborted: bool,
|
||||
legs: VecDeque<TripLeg>,
|
||||
mode: TripMode,
|
||||
|
Loading…
Reference in New Issue
Block a user