cleaning up trip_details

This commit is contained in:
Dustin Carlino 2020-02-12 16:17:41 -08:00
parent 5948f226a6
commit 1f0b225b6b
8 changed files with 116 additions and 105 deletions

View File

@ -173,7 +173,8 @@ impl ColorLegend {
color, color,
Circle::new(Pt2D::new(radius, radius), Distance::meters(radius)).to_polygon(), Circle::new(Pt2D::new(radius, radius), Distance::meters(radius)).to_polygon(),
)]), )]),
), )
.margin(5),
ManagedWidget::draw_text(ctx, Text::from(Line(label))), ManagedWidget::draw_text(ctx, Text::from(Line(label))),
]) ])
} }

View File

@ -13,7 +13,7 @@ use ezgui::{
}; };
use geom::{Circle, Distance, Duration, Statistic, Time}; use geom::{Circle, Distance, Duration, Statistic, Time};
use map_model::{IntersectionID, RoadID}; use map_model::{IntersectionID, RoadID};
use sim::{CarID, TripEnd, TripID, TripMode, TripStart, VehicleType}; use sim::{AgentID, CarID, TripEnd, TripID, TripMode, TripStart, VehicleType};
use std::collections::BTreeSet; use std::collections::BTreeSet;
pub struct InfoPanel { pub struct InfoPanel {
@ -50,7 +50,15 @@ impl InfoPanel {
let trip_details = if let Some(trip) = match id { let trip_details = if let Some(trip) = match id {
ID::Trip(t) => Some(t), ID::Trip(t) => Some(t),
_ => id.agent_id().and_then(|a| ui.primary.sim.agent_to_trip(a)), ID::Car(c) => {
if c.1 == VehicleType::Bus {
None
} else {
ui.primary.sim.agent_to_trip(AgentID::Car(c))
}
}
ID::Pedestrian(p) => ui.primary.sim.agent_to_trip(AgentID::Pedestrian(p)),
_ => None,
} { } {
let (rows, unzoomed, zoomed) = trip_details(trip, ctx, ui); let (rows, unzoomed, zoomed) = trip_details(trip, ctx, ui);
col.push(rows); col.push(rows);
@ -748,20 +756,63 @@ fn color_for_mode(m: TripMode, ui: &UI) -> Color {
fn trip_details(trip: TripID, ctx: &mut EventCtx, ui: &UI) -> (ManagedWidget, Drawable, Drawable) { fn trip_details(trip: TripID, ctx: &mut EventCtx, ui: &UI) -> (ManagedWidget, Drawable, Drawable) {
let map = &ui.primary.map; let map = &ui.primary.map;
let phases = ui.primary.sim.get_analytics().get_trip_phases(trip, map); let phases = ui.primary.sim.get_analytics().get_trip_phases(trip, map);
let (trip_start, trip_end) = ui.primary.sim.trip_endpoints(trip);
let mut col = vec![ManagedWidget::draw_text( let mut col = vec![ManagedWidget::draw_text(ctx, {
ctx, let mut txt = Text::from(Line(""));
Text::from(Line(trip.to_string())), txt.add(Line("Trip timeline").roboto_bold());
)]; txt
})];
let mut unzoomed = GeomBatch::new(); let mut unzoomed = GeomBatch::new();
let mut zoomed = GeomBatch::new(); let mut zoomed = GeomBatch::new();
for (idx, p) in phases.into_iter().enumerate() { // Start
let color = rotating_color_map(idx + 1); {
let color = rotating_color_map(col.len() - 1);
match trip_start {
TripStart::Bldg(b) => {
let bldg = map.get_b(b);
col.push(ColorLegend::row(
ctx,
color,
format!(
"{}: leave {}",
phases[0].start_time.ampm_tostring(),
bldg.just_address(map)
),
));
unzoomed.push(color, bldg.polygon.clone());
zoomed.push(color, bldg.polygon.clone());
}
TripStart::Border(i) => {
let i = map.get_i(i);
// TODO How to name the intersection succinctly?
col.push(ColorLegend::row(
ctx,
color,
format!(
"{}: start at {}",
phases[0].start_time.ampm_tostring(),
i.id
),
));
unzoomed.push(color, i.polygon.clone());
zoomed.push(color, i.polygon.clone());
}
};
}
let mut end_time = None;
for p in phases {
let color = rotating_color_map(col.len() - 1);
col.push(ColorLegend::row( col.push(ColorLegend::row(
ctx, ctx,
color, color,
p.describe(ui.primary.sim.time()), if let Some(t2) = p.end_time {
format!("+{}: {}", t2 - p.start_time, p.description)
} else {
format!("ongoing: {}", p.description)
},
)); ));
// TODO Could really cache this between live updates // TODO Could really cache this between live updates
@ -779,71 +830,43 @@ fn trip_details(trip: TripID, ctx: &mut EventCtx, ui: &UI) -> (ManagedWidget, Dr
); );
} }
} }
end_time = p.end_time;
} }
// Handle endpoints // End
let (trip_start, trip_end) = ui.primary.sim.trip_endpoints(trip); {
let start_color = rotating_color_map(0); let color = rotating_color_map(col.len() - 1);
match trip_start { let time = if let Some(t) = end_time {
TripStart::Bldg(b) => { format!("{}: ", t.ampm_tostring())
let bldg = map.get_b(b); } else {
col.insert( String::new()
1, };
ColorLegend::row(ctx, start_color, format!("start at {}", bldg.get_name(map))), match trip_end {
); TripEnd::Bldg(b) => {
unzoomed.push(start_color, bldg.polygon.clone()); let bldg = map.get_b(b);
zoomed.push(start_color, bldg.polygon.clone()); col.push(ColorLegend::row(
} ctx,
TripStart::Border(i) => { color,
let i = map.get_i(i); format!("{}end at {}", time, bldg.just_address(map)),
col.insert( ));
1, unzoomed.push(color, bldg.polygon.clone());
ColorLegend::row(ctx, start_color, format!("enter map via {}", i.id)), zoomed.push(color, bldg.polygon.clone());
); }
unzoomed.push(start_color, i.polygon.clone()); TripEnd::Border(i) => {
zoomed.push(start_color, i.polygon.clone()); let i = map.get_i(i);
} // TODO name it better
}; col.push(ColorLegend::row(
ctx,
// Is the trip ongoing? color,
if let Some(pt) = ui.primary.sim.get_canonical_pt_per_trip(trip, map).ok() { format!("{}end at {}", time, i.id),
let color = rotating_color_map(col.len()); ));
unzoomed.push(color, Circle::new(pt, Distance::meters(10.0)).to_polygon()); unzoomed.push(color, i.polygon.clone());
// Don't need anything when zoomed; the info panel already focuses on them. zoomed.push(color, i.polygon.clone());
col.push(ColorLegend::row(ctx, color, "currently here")); }
TripEnd::ServeBusRoute(_) => unreachable!(),
};
} }
let end_color = rotating_color_map(col.len());
match trip_end {
TripEnd::Bldg(b) => {
let bldg = map.get_b(b);
col.push(ColorLegend::row(
ctx,
end_color,
format!("end at {}", bldg.get_name(map)),
));
unzoomed.push(end_color, bldg.polygon.clone());
zoomed.push(end_color, bldg.polygon.clone());
}
TripEnd::Border(i) => {
let i = map.get_i(i);
col.push(ColorLegend::row(
ctx,
end_color,
format!("leave map via {}", i.id),
));
unzoomed.push(end_color, i.polygon.clone());
zoomed.push(end_color, i.polygon.clone());
}
TripEnd::ServeBusRoute(br) => {
col.push(ColorLegend::row(
ctx,
end_color,
format!("serve route {} forever", map.get_br(br).name),
));
}
};
( (
ManagedWidget::col(col), ManagedWidget::col(col),
unzoomed.upload(ctx), unzoomed.upload(ctx),

View File

@ -120,7 +120,7 @@ fn dump_debug(id: ID, map: &Map, sim: &Sim, draw_map: &DrawMap) {
if let Some(t) = sim.agent_to_trip(AgentID::Car(id)) { if let Some(t) = sim.agent_to_trip(AgentID::Car(id)) {
println!("Trip log for {}", t); println!("Trip log for {}", t);
for p in sim.get_analytics().get_trip_phases(t, map) { for p in sim.get_analytics().get_trip_phases(t, map) {
println!("- {}", p.describe(sim.time())); println!("- {:?}", p);
} }
} }
} }
@ -129,7 +129,7 @@ fn dump_debug(id: ID, map: &Map, sim: &Sim, draw_map: &DrawMap) {
if let Some(t) = sim.agent_to_trip(AgentID::Pedestrian(id)) { if let Some(t) = sim.agent_to_trip(AgentID::Pedestrian(id)) {
println!("Trip log for {}", t); println!("Trip log for {}", t);
for p in sim.get_analytics().get_trip_phases(t, map) { for p in sim.get_analytics().get_trip_phases(t, map) {
println!("- {}", p.describe(sim.time())); println!("- {:?}", p);
} }
} }
} }

View File

@ -551,6 +551,7 @@ impl Default for Analytics {
} }
} }
#[derive(Debug)]
pub struct TripPhase { pub struct TripPhase {
pub start_time: Time, pub start_time: Time,
pub end_time: Option<Time>, pub end_time: Option<Time>,
@ -559,27 +560,6 @@ pub struct TripPhase {
pub description: String, pub description: String,
} }
impl TripPhase {
pub fn describe(&self, now: Time) -> String {
if let Some(t2) = self.end_time {
format!(
"{} .. {} ({}): {}",
self.start_time,
t2,
t2 - self.start_time,
self.description
)
} else {
format!(
"{} .. ongoing ({} so far): {}",
self.start_time,
now - self.start_time,
self.description
)
}
}
}
struct Window { struct Window {
times: VecDeque<Time>, times: VecDeque<Time>,
window_size: Duration, window_size: Duration,

View File

@ -3,7 +3,7 @@ use crate::mechanics::Queue;
use crate::{ use crate::{
ActionAtEnd, AgentID, AgentMetadata, CarID, Command, CreateCar, DistanceInterval, DrawCarInput, ActionAtEnd, AgentID, AgentMetadata, CarID, Command, CreateCar, DistanceInterval, DrawCarInput,
Event, IntersectionSimState, ParkedCar, ParkingSimState, Scheduler, TimeInterval, Event, IntersectionSimState, ParkedCar, ParkingSimState, Scheduler, TimeInterval,
TransitSimState, TripManager, TripPositions, UnzoomedAgent, WalkingSimState, TransitSimState, TripManager, TripPositions, UnzoomedAgent, VehicleType, WalkingSimState,
FOLLOWING_DISTANCE, FOLLOWING_DISTANCE,
}; };
use abstutil::{deserialize_btreemap, serialize_btreemap}; use abstutil::{deserialize_btreemap, serialize_btreemap};
@ -871,7 +871,7 @@ impl DrivingSimState {
) -> Option<(Vec<(String, String)>, Vec<String>)> { ) -> Option<(Vec<(String, String)>, Vec<String>)> {
let car = self.cars.get(&id)?; let car = self.cars.get(&id)?;
let path = car.router.get_path(); let path = car.router.get_path();
let props = vec![ let mut props = vec![
( (
"Owner".to_string(), "Owner".to_string(),
if let Some(b) = car.vehicle.owner { if let Some(b) = car.vehicle.owner {
@ -905,6 +905,10 @@ impl DrivingSimState {
.to_string(), .to_string(),
), ),
]; ];
// No owner
if id.1 == VehicleType::Bus {
props.remove(0);
}
Some((props, Vec::new())) Some((props, Vec::new()))
} }

View File

@ -399,7 +399,11 @@ impl Sim {
events.push(Event::TripPhaseStarting( events.push(Event::TripPhaseStarting(
create_car.trip, create_car.trip,
Some(create_car.req.clone()), Some(create_car.req.clone()),
format!("{}", create_car.vehicle.id), if create_car.vehicle.id.1 == VehicleType::Car {
"driving".to_string()
} else {
"biking".to_string()
},
)); ));
self.analytics self.analytics
.record_demand(create_car.router.get_path(), map); .record_demand(create_car.router.get_path(), map);
@ -482,12 +486,7 @@ impl Sim {
events.push(Event::TripPhaseStarting( events.push(Event::TripPhaseStarting(
create_ped.trip, create_ped.trip,
Some(create_ped.req.clone()), Some(create_ped.req.clone()),
format!( "walking".to_string(),
"{} from {:?} to {:?}",
create_ped.id,
create_ped.start.connection,
create_ped.goal.connection
),
)); ));
self.analytics.record_demand(&create_ped.path, map); self.analytics.record_demand(&create_ped.path, map);
@ -871,6 +870,10 @@ impl Sim {
pub fn car_properties(&self, car: CarID, map: &Map) -> (Vec<(String, String)>, Vec<String>) { pub fn car_properties(&self, car: CarID, map: &Map) -> (Vec<(String, String)>, Vec<String>) {
if let Some((mut props, extra)) = self.driving.car_properties(car, self.time, map) { if let Some((mut props, extra)) = self.driving.car_properties(car, self.time, map) {
if car.1 == VehicleType::Bus { if car.1 == VehicleType::Bus {
props.push((
"Route".to_string(),
map.get_br(self.transit.bus_route(car)).name.clone(),
));
let passengers = self.transit.get_passengers(car); let passengers = self.transit.get_passengers(car);
props.push(("Passengers".to_string(), passengers.len().to_string())); props.push(("Passengers".to_string(), passengers.len().to_string()));
// TODO Clean this up // TODO Clean this up

View File

@ -189,7 +189,7 @@ impl TransitSimState {
end: map.get_bs(stop2).driving_pos, end: map.get_bs(stop2).driving_pos,
constraints: PathConstraints::Bus, constraints: PathConstraints::Bus,
}), }),
format!("{} riding {}", ped, route), format!("riding bus {}", map.get_br(route).name),
)); ));
} else { } else {
still_waiting.push((ped, route, stop2, started_waiting)); still_waiting.push((ped, route, stop2, started_waiting));

View File

@ -352,7 +352,7 @@ impl TripManager {
self.events.push(Event::TripPhaseStarting( self.events.push(Event::TripPhaseStarting(
trip.id, trip.id,
None, None,
format!("{} waiting at {:?} for {}", ped, stop, route), format!("waiting for bus {}", map.get_br(route).name),
)); ));
if transit.ped_waiting_for_bus(now, ped, stop, route, stop2) { if transit.ped_waiting_for_bus(now, ped, stop, route, stop2) {
trip.legs.pop_front(); trip.legs.pop_front();