mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-03 01:52:16 +03:00
the new table makes the population map's weird filter irrelevant. also
add sorting by delta time
This commit is contained in:
parent
a34b7acb8b
commit
f0c0d88764
@ -414,7 +414,6 @@ impl Layers {
|
||||
app,
|
||||
population::Options {
|
||||
heatmap: Some(HeatmapOptions::new()),
|
||||
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,
|
||||
Spinner, TextExt, VerticalAlignment, Widget,
|
||||
VerticalAlignment, Widget,
|
||||
};
|
||||
use geom::{Circle, Distance, Pt2D};
|
||||
use sim::{GetDrawAgents, PersonState};
|
||||
@ -13,28 +13,11 @@ use std::collections::HashSet;
|
||||
// TODO Disable drawing unzoomed agents... or alternatively, implement this by asking Sim to
|
||||
// return this kind of data instead!
|
||||
pub fn new(ctx: &mut EventCtx, app: &App, opts: Options) -> Layers {
|
||||
let filter = |p| {
|
||||
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 Some((total, blocked)) = app.primary.sim.finished_trip_time(*t) {
|
||||
(100.0 * blocked / total) as usize >= pct
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
} else {
|
||||
true
|
||||
}
|
||||
};
|
||||
|
||||
let mut pts = Vec::new();
|
||||
// Faster to grab all agent positions than individually map trips to agent positions.
|
||||
for a in app.primary.sim.get_unzoomed_agents(&app.primary.map) {
|
||||
if let Some(p) = a.person {
|
||||
if filter(p) {
|
||||
pts.push(a.pos);
|
||||
}
|
||||
if a.person.is_some() {
|
||||
pts.push(a.pos);
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,14 +31,12 @@ pub fn new(ctx: &mut EventCtx, app: &App, opts: Options) -> Layers {
|
||||
// Already covered above
|
||||
PersonState::Trip(_) => {}
|
||||
PersonState::Inside(b) => {
|
||||
if filter(person.id) {
|
||||
let pt = app.primary.map.get_b(b).polygon.center();
|
||||
if seen_bldgs.contains(&b) {
|
||||
repeat_pts.push(pt);
|
||||
} else {
|
||||
seen_bldgs.insert(b);
|
||||
pts.push(pt);
|
||||
}
|
||||
let pt = app.primary.map.get_b(b).polygon.center();
|
||||
if seen_bldgs.contains(&b) {
|
||||
repeat_pts.push(pt);
|
||||
} else {
|
||||
seen_bldgs.insert(b);
|
||||
pts.push(pt);
|
||||
}
|
||||
}
|
||||
PersonState::OffMap | PersonState::Limbo => {}
|
||||
@ -87,8 +68,6 @@ pub fn new(ctx: &mut EventCtx, app: &App, opts: Options) -> Layers {
|
||||
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_blocked_pct: Option<usize>,
|
||||
}
|
||||
|
||||
fn make_controls(
|
||||
@ -118,21 +97,6 @@ fn make_controls(
|
||||
])
|
||||
.centered(),
|
||||
];
|
||||
col.push(Checkbox::text(
|
||||
ctx,
|
||||
"Filter by people with a finished trip",
|
||||
None,
|
||||
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,
|
||||
@ -155,17 +119,5 @@ pub fn options(c: &mut Composite) -> Options {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Options {
|
||||
heatmap,
|
||||
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
|
||||
},
|
||||
}
|
||||
Options { heatmap }
|
||||
}
|
||||
|
@ -4,8 +4,9 @@ use crate::helpers::cmp_duration_shorter;
|
||||
use crate::info::Tab;
|
||||
use crate::sandbox::SandboxMode;
|
||||
use ezgui::{hotkey, Btn, Composite, EventCtx, GfxCtx, Key, Line, Outcome, Text, Widget};
|
||||
use geom::{Duration, Time};
|
||||
use maplit::btreeset;
|
||||
use sim::TripID;
|
||||
use sim::{TripID, TripMode};
|
||||
|
||||
// TODO Hover over a trip to preview its route on the map
|
||||
|
||||
@ -18,6 +19,7 @@ pub struct TripResults {
|
||||
enum SortBy {
|
||||
Departure,
|
||||
Duration,
|
||||
RelativeDuration,
|
||||
PercentWaiting,
|
||||
}
|
||||
|
||||
@ -42,6 +44,9 @@ impl State for TripResults {
|
||||
"Duration" => {
|
||||
self.composite = make(ctx, app, SortBy::Duration);
|
||||
}
|
||||
"Comparison with baseline" => {
|
||||
self.composite = make(ctx, app, SortBy::RelativeDuration);
|
||||
}
|
||||
"Percent of trip spent waiting" => {
|
||||
self.composite = make(ctx, app, SortBy::PercentWaiting);
|
||||
}
|
||||
@ -71,6 +76,16 @@ impl State for TripResults {
|
||||
}
|
||||
}
|
||||
|
||||
struct Entry {
|
||||
trip: TripID,
|
||||
mode: TripMode,
|
||||
departure: Time,
|
||||
duration: Duration,
|
||||
baseline_duration: Duration,
|
||||
waiting: Duration,
|
||||
percent_waiting: usize,
|
||||
}
|
||||
|
||||
fn make(ctx: &mut EventCtx, app: &App, sort: SortBy) -> Composite {
|
||||
let mut data = Vec::new();
|
||||
let sim = &app.primary.sim;
|
||||
@ -80,29 +95,30 @@ fn make(ctx: &mut EventCtx, app: &App, sort: SortBy) -> Composite {
|
||||
} else {
|
||||
continue;
|
||||
};
|
||||
let (_, blocked) = sim.finished_trip_time(*id).unwrap();
|
||||
let (start_time, _, _, _) = sim.trip_info(*id);
|
||||
let comparison = if app.has_prebaked().is_some() {
|
||||
cmp_duration_shorter(*duration, app.prebaked().finished_trip_time(*id).unwrap())
|
||||
let (_, waiting) = sim.finished_trip_time(*id).unwrap();
|
||||
let (departure, _, _, _) = sim.trip_info(*id);
|
||||
let baseline_duration = if app.has_prebaked().is_some() {
|
||||
app.prebaked().finished_trip_time(*id).unwrap()
|
||||
} else {
|
||||
vec![Line("n/a")]
|
||||
Duration::ZERO
|
||||
};
|
||||
|
||||
data.push((
|
||||
*id,
|
||||
data.push(Entry {
|
||||
trip: *id,
|
||||
mode,
|
||||
start_time,
|
||||
*duration,
|
||||
comparison,
|
||||
blocked,
|
||||
(100.0 * blocked / *duration) as usize,
|
||||
));
|
||||
departure,
|
||||
duration: *duration,
|
||||
baseline_duration,
|
||||
waiting,
|
||||
percent_waiting: (100.0 * waiting / *duration) as usize,
|
||||
});
|
||||
}
|
||||
|
||||
match sort {
|
||||
SortBy::Departure => data.sort_by_key(|(_, _, t, _, _, _, _)| *t),
|
||||
SortBy::Duration => data.sort_by_key(|(_, _, _, dt, _, _, _)| *dt),
|
||||
SortBy::PercentWaiting => data.sort_by_key(|(_, _, _, _, _, _, pct)| *pct),
|
||||
SortBy::Departure => data.sort_by_key(|x| x.departure),
|
||||
SortBy::Duration => data.sort_by_key(|x| x.duration),
|
||||
SortBy::RelativeDuration => data.sort_by_key(|x| x.duration - x.baseline_duration),
|
||||
SortBy::PercentWaiting => data.sort_by_key(|x| x.percent_waiting),
|
||||
}
|
||||
// Descending...
|
||||
data.reverse();
|
||||
@ -114,20 +130,20 @@ fn make(ctx: &mut EventCtx, app: &App, sort: SortBy) -> Composite {
|
||||
let mut col2 = Text::new();
|
||||
let mut col3 = Text::new();
|
||||
let mut col4 = Text::new();
|
||||
let mut col5 = Text::new();
|
||||
let mut maybe_col5 = Text::new();
|
||||
let mut col6 = Text::new();
|
||||
let mut col7 = Text::new();
|
||||
|
||||
for (id, mode, departure, duration, comparison, blocked, pct_blocked) in
|
||||
data.into_iter().take(30)
|
||||
{
|
||||
col1.push(Btn::plaintext(id.0.to_string()).build_def(ctx, None));
|
||||
col2.add(Line(mode.ongoing_verb()));
|
||||
col3.add(Line(departure.ampm_tostring()));
|
||||
col4.add(Line(duration.to_string()));
|
||||
col5.add_appended(comparison);
|
||||
col6.add(Line(blocked.to_string()));
|
||||
col7.add(Line(format!("{}%", pct_blocked)));
|
||||
for x in data.into_iter().take(30) {
|
||||
col1.push(Btn::plaintext(x.trip.0.to_string()).build_def(ctx, None));
|
||||
col2.add(Line(x.mode.ongoing_verb()));
|
||||
col3.add(Line(x.departure.ampm_tostring()));
|
||||
col4.add(Line(x.duration.to_string()));
|
||||
if app.has_prebaked().is_some() {
|
||||
maybe_col5.add_appended(cmp_duration_shorter(x.duration, x.baseline_duration));
|
||||
}
|
||||
col6.add(Line(x.waiting.to_string()));
|
||||
col7.add(Line(format!("{}%", x.percent_waiting)));
|
||||
}
|
||||
|
||||
Composite::new(
|
||||
@ -144,21 +160,30 @@ fn make(ctx: &mut EventCtx, app: &App, sort: SortBy) -> Composite {
|
||||
Line("Trip ID").draw(ctx).margin_right(10),
|
||||
Line("Type").draw(ctx).margin_right(10),
|
||||
if sort == SortBy::Departure {
|
||||
Btn::text_fg("Departure").inactive(ctx)
|
||||
Btn::text_bg2("Departure").inactive(ctx)
|
||||
} else {
|
||||
Btn::text_fg("Departure").build_def(ctx, None)
|
||||
}
|
||||
.margin_right(10),
|
||||
if sort == SortBy::Duration {
|
||||
Btn::text_fg("Duration").inactive(ctx)
|
||||
Btn::text_bg2("Duration").inactive(ctx)
|
||||
} else {
|
||||
Btn::text_fg("Duration").build_def(ctx, None)
|
||||
}
|
||||
.margin_right(10),
|
||||
Line("Comparison with baseline").draw(ctx).margin_right(10),
|
||||
if app.has_prebaked().is_some() {
|
||||
if sort == SortBy::RelativeDuration {
|
||||
Btn::text_bg2("Comparison with baseline").inactive(ctx)
|
||||
} else {
|
||||
Btn::text_fg("Comparison with baseline").build_def(ctx, None)
|
||||
}
|
||||
.margin_right(10)
|
||||
} else {
|
||||
Widget::nothing()
|
||||
},
|
||||
Line("Time spent waiting").draw(ctx).margin_right(10),
|
||||
if sort == SortBy::PercentWaiting {
|
||||
Btn::text_fg("Percent of trip spent waiting").inactive(ctx)
|
||||
Btn::text_bg2("Percent of trip spent waiting").inactive(ctx)
|
||||
} else {
|
||||
Btn::text_fg("Percent of trip spent waiting").build_def(ctx, None)
|
||||
}
|
||||
@ -169,7 +194,11 @@ fn make(ctx: &mut EventCtx, app: &App, sort: SortBy) -> Composite {
|
||||
col2.draw(ctx).margin_right(10),
|
||||
col3.draw(ctx).margin_right(10),
|
||||
col4.draw(ctx).margin_right(10),
|
||||
col5.draw(ctx).margin_right(10),
|
||||
if app.has_prebaked().is_some() {
|
||||
maybe_col5.draw(ctx).margin_right(10)
|
||||
} else {
|
||||
Widget::nothing()
|
||||
},
|
||||
col6.draw(ctx).margin_right(10),
|
||||
col7.draw(ctx).margin_right(10),
|
||||
])
|
||||
|
Loading…
Reference in New Issue
Block a user