mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-29 12:43:38 +03:00
cleaning up trip_details
This commit is contained in:
parent
5948f226a6
commit
1f0b225b6b
@ -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))),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
|
@ -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),
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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()))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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));
|
||||||
|
@ -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();
|
||||||
|
Loading…
Reference in New Issue
Block a user