mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-27 08:24:15 +03:00
experiment with finding sources of gridlock, exposed as a new heatmap
This commit is contained in:
parent
1ffcd1e5b5
commit
e19f88cd40
@ -20,6 +20,7 @@ pub enum Overlays {
|
||||
Inactive,
|
||||
ParkingAvailability(Time, Colorer),
|
||||
IntersectionDelay(Time, Colorer),
|
||||
Gridlock(Time, Colorer),
|
||||
CumulativeThroughput(Time, Colorer),
|
||||
BikeNetwork(Colorer),
|
||||
BusNetwork(Colorer),
|
||||
@ -48,6 +49,11 @@ impl Overlays {
|
||||
ui.overlay = Overlays::intersection_delay(ctx, ui);
|
||||
}
|
||||
}
|
||||
Overlays::Gridlock(t, _) => {
|
||||
if now != t {
|
||||
ui.overlay = Overlays::gridlock(ctx, ui);
|
||||
}
|
||||
}
|
||||
Overlays::CumulativeThroughput(t, _) => {
|
||||
if now != t {
|
||||
ui.overlay = Overlays::cumulative_throughput(ctx, ui);
|
||||
@ -94,6 +100,7 @@ impl Overlays {
|
||||
| Overlays::BikeNetwork(ref mut heatmap)
|
||||
| Overlays::BusNetwork(ref mut heatmap)
|
||||
| Overlays::IntersectionDelay(_, ref mut heatmap)
|
||||
| Overlays::Gridlock(_, ref mut heatmap)
|
||||
| Overlays::CumulativeThroughput(_, ref mut heatmap)
|
||||
| Overlays::Edits(ref mut heatmap) => {
|
||||
heatmap.legend.align_above(ctx, minimap);
|
||||
@ -182,6 +189,7 @@ impl Overlays {
|
||||
| Overlays::BikeNetwork(ref heatmap)
|
||||
| Overlays::BusNetwork(ref heatmap)
|
||||
| Overlays::IntersectionDelay(_, ref heatmap)
|
||||
| Overlays::Gridlock(_, ref heatmap)
|
||||
| Overlays::CumulativeThroughput(_, ref heatmap)
|
||||
| Overlays::Edits(ref heatmap) => {
|
||||
heatmap.draw(g);
|
||||
@ -209,6 +217,7 @@ impl Overlays {
|
||||
| Overlays::BikeNetwork(ref heatmap)
|
||||
| Overlays::BusNetwork(ref heatmap)
|
||||
| Overlays::IntersectionDelay(_, ref heatmap)
|
||||
| Overlays::Gridlock(_, ref heatmap)
|
||||
| Overlays::CumulativeThroughput(_, ref heatmap)
|
||||
| Overlays::Edits(ref heatmap) => Some(heatmap),
|
||||
Overlays::BusRoute(_, _, ref s) => Some(&s.colorer),
|
||||
@ -220,6 +229,7 @@ impl Overlays {
|
||||
let mut choices = vec![
|
||||
WrappedComposite::text_button(ctx, "None", hotkey(Key::N)),
|
||||
WrappedComposite::text_button(ctx, "map edits", hotkey(Key::E)),
|
||||
WrappedComposite::text_button(ctx, "worst traffic jams", hotkey(Key::G)),
|
||||
ManagedWidget::btn(Button::rectangle_svg(
|
||||
"../data/system/assets/layers/parking_avail.svg",
|
||||
"parking availability",
|
||||
@ -267,6 +277,10 @@ impl Overlays {
|
||||
"intersection delay",
|
||||
ManagedWidget::draw_svg(ctx, "../data/system/assets/layers/intersection_delay.svg"),
|
||||
)),
|
||||
Overlays::Gridlock(_, _) => Some((
|
||||
"worst traffic jams",
|
||||
Button::inactive_button(ctx, "worst traffic jams"),
|
||||
)),
|
||||
Overlays::CumulativeThroughput(_, _) => Some((
|
||||
"throughput",
|
||||
ManagedWidget::draw_svg(ctx, "../data/system/assets/layers/throughput.svg"),
|
||||
@ -328,6 +342,13 @@ impl Overlays {
|
||||
Some(Transition::Pop)
|
||||
}),
|
||||
)
|
||||
.maybe_cb(
|
||||
"worst traffic jams",
|
||||
Box::new(|ctx, ui| {
|
||||
ui.overlay = Overlays::gridlock(ctx, ui);
|
||||
Some(Transition::Pop)
|
||||
}),
|
||||
)
|
||||
.maybe_cb(
|
||||
"throughput",
|
||||
Box::new(|ctx, ui| {
|
||||
@ -465,6 +486,35 @@ impl Overlays {
|
||||
Overlays::IntersectionDelay(ui.primary.sim.time(), colorer.build(ctx, ui))
|
||||
}
|
||||
|
||||
fn gridlock(ctx: &mut EventCtx, ui: &UI) -> Overlays {
|
||||
let jams = ui.primary.sim.delayed_intersections(Duration::minutes(5));
|
||||
|
||||
// TODO Silly colors
|
||||
let others = Color::hex("#7FFA4D");
|
||||
let early = Color::hex("#F4DA22");
|
||||
let earliest = Color::hex("#EB5757");
|
||||
let mut colorer = Colorer::new(
|
||||
Text::from(Line(format!("{} traffic jams", jams.len()))),
|
||||
vec![
|
||||
("longest lasting", earliest),
|
||||
("recent problems", early),
|
||||
("others", others),
|
||||
],
|
||||
);
|
||||
|
||||
for (idx, (i, _)) in jams.into_iter().enumerate() {
|
||||
if idx == 0 {
|
||||
colorer.add_i(i, earliest);
|
||||
} else if idx <= 5 {
|
||||
colorer.add_i(i, early);
|
||||
} else {
|
||||
colorer.add_i(i, others);
|
||||
}
|
||||
}
|
||||
|
||||
Overlays::Gridlock(ui.primary.sim.time(), colorer.build(ctx, ui))
|
||||
}
|
||||
|
||||
fn cumulative_throughput(ctx: &mut EventCtx, ui: &UI) -> Overlays {
|
||||
let light = Color::hex("#7FFA4D");
|
||||
let medium = Color::hex("#F4DA22");
|
||||
|
@ -475,6 +475,7 @@ impl TimeWarpScreen {
|
||||
WrappedComposite::text_bg_button(ctx, "stop now", hotkey(Key::Escape))
|
||||
.centered_horiz(),
|
||||
])
|
||||
.padding(10)
|
||||
.bg(colors::PANEL_BG),
|
||||
)
|
||||
.build(ctx),
|
||||
|
@ -267,6 +267,19 @@ impl IntersectionSimState {
|
||||
pub fn collect_events(&mut self) -> Vec<Event> {
|
||||
std::mem::replace(&mut self.events, Vec::new())
|
||||
}
|
||||
|
||||
pub fn find_gridlock(&self, now: Time, threshold: Duration) -> Vec<(IntersectionID, Time)> {
|
||||
let mut candidates = Vec::new();
|
||||
for state in self.state.values() {
|
||||
if let Some(earliest) = state.waiting.values().min() {
|
||||
if now - *earliest >= threshold {
|
||||
candidates.push((state.id, *earliest));
|
||||
}
|
||||
}
|
||||
}
|
||||
candidates.sort_by_key(|(_, t)| *t);
|
||||
candidates
|
||||
}
|
||||
}
|
||||
|
||||
impl State {
|
||||
|
@ -1060,6 +1060,12 @@ impl Sim {
|
||||
.find_blockage_front(car, map, &self.intersections)
|
||||
}
|
||||
|
||||
// For intersections with an agent waiting beyond some threshold, return when they started
|
||||
// waiting. Sorted by earliest waiting (likely the root cause of gridlock).
|
||||
pub fn delayed_intersections(&self, threshold: Duration) -> Vec<(IntersectionID, Time)> {
|
||||
self.intersections.find_gridlock(self.time, threshold)
|
||||
}
|
||||
|
||||
pub fn trip_spec_to_path_req(&self, spec: &TripSpec, map: &Map) -> PathRequest {
|
||||
spec.get_pathfinding_request(map, &self.parking)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user