game/debug/
path_counter.rs

1use crate::ID;
2use abstutil::Counter;
3use map_gui::tools::ColorNetwork;
4use map_model::{IntersectionID, PathStep, RoadID, Traversable};
5use widgetry::mapspace::ToggleZoomed;
6use widgetry::tools::ColorLegend;
7use widgetry::{
8    Color, EventCtx, GfxCtx, HorizontalAlignment, Line, Outcome, Panel, State, Text,
9    VerticalAlignment, Widget,
10};
11
12use crate::app::App;
13use crate::app::Transition;
14use crate::common::CommonState;
15
16/// A state to count the number of trips that will cross different roads.
17pub struct PathCounter {
18    panel: Panel,
19    draw: ToggleZoomed,
20    cnt: Counter<RoadID>,
21    tooltip: Option<Text>,
22}
23
24impl PathCounter {
25    pub fn demand_across_intersection(
26        ctx: &mut EventCtx,
27        app: &App,
28        i: IntersectionID,
29    ) -> Box<dyn State<App>> {
30        let map = &app.primary.map;
31        let sim = &app.primary.sim;
32        let mut cnt = Counter::new();
33        // Find all active agents whose path crosses this intersection
34        for agent in sim.active_agents() {
35            if let Some(path) = sim.get_path(agent) {
36                if path.get_steps().iter().any(|step| match step {
37                    PathStep::Turn(t) | PathStep::ContraflowTurn(t) => t.parent == i,
38                    _ => false,
39                }) {
40                    // Count what lanes they'll cross
41                    for step in path.get_steps() {
42                        if let Traversable::Lane(l) = step.as_traversable() {
43                            cnt.inc(l.road);
44                        }
45                    }
46                }
47            }
48        }
49
50        let mut colorer = ColorNetwork::new(app);
51        // Highlight the intersection
52        colorer
53            .draw
54            .unzoomed
55            .push(Color::CYAN, map.get_i(i).polygon.clone());
56        colorer
57            .draw
58            .zoomed
59            .push(Color::CYAN.alpha(0.5), map.get_i(i).polygon.clone());
60
61        colorer.pct_roads(cnt.clone(), &app.cs.good_to_bad_red);
62
63        Box::new(PathCounter {
64            draw: colorer.build(ctx),
65            tooltip: None,
66            cnt,
67            panel: Panel::new_builder(Widget::col(vec![
68                Widget::row(vec![
69                    Line(format!("Paths across {}", i))
70                        .small_heading()
71                        .into_widget(ctx),
72                    ctx.style().btn_close_widget(ctx),
73                ]),
74                ColorLegend::gradient(
75                    ctx,
76                    &app.cs.good_to_bad_red,
77                    vec!["lowest count", "highest"],
78                ),
79            ]))
80            .aligned(HorizontalAlignment::Center, VerticalAlignment::Top)
81            .build(ctx),
82        })
83    }
84}
85
86impl State<App> for PathCounter {
87    fn event(&mut self, ctx: &mut EventCtx, app: &mut App) -> Transition {
88        ctx.canvas_movement();
89        if ctx.redo_mouseover() {
90            app.primary.current_selection = app.mouseover_unzoomed_roads_and_intersections(ctx);
91            self.tooltip = None;
92            if let Some(r) = match app.primary.current_selection {
93                Some(ID::Lane(l)) => Some(l.road),
94                Some(ID::Road(r)) => Some(r),
95                _ => None,
96            } {
97                let n = self.cnt.get(r);
98                if n > 0 {
99                    self.tooltip = Some(Text::from(abstutil::prettyprint_usize(n)));
100                }
101            } else {
102                app.primary.current_selection = None;
103            }
104        }
105
106        if let Outcome::Clicked(x) = self.panel.event(ctx) {
107            match x.as_ref() {
108                "close" => {
109                    return Transition::Pop;
110                }
111                _ => unreachable!(),
112            }
113        }
114
115        Transition::Keep
116    }
117
118    fn draw(&self, g: &mut GfxCtx, app: &App) {
119        self.panel.draw(g);
120        CommonState::draw_osd(g, app);
121
122        self.draw.draw(g);
123
124        if let Some(ref txt) = self.tooltip {
125            g.draw_mouse_tooltip(txt.clone());
126        }
127    }
128}