1use std::borrow::Borrow;
2use std::collections::HashMap;
3
4use geom::{Circle, Pt2D, QuadTree, Time};
5use map_gui::colors::ColorScheme;
6use map_gui::options::Options;
7use map_model::{Map, Traversable};
8use sim::{AgentID, Sim, UnzoomedAgent, VehicleType};
9use widgetry::{Color, Drawable, GeomBatch, GfxCtx, Panel, Prerender};
10
11use crate::render::{
12 draw_vehicle, unzoomed_agent_radius, DrawPedCrowd, DrawPedestrian, GameRenderable,
13};
14
15pub struct AgentCache {
16 pub unzoomed_agents: UnzoomedAgents,
18
19 time: Option<Time>,
21 agents_per_on: HashMap<Traversable, Vec<Box<dyn GameRenderable>>>,
22 unzoomed: Option<(Time, UnzoomedAgents, QuadTree<AgentID>, Drawable)>,
25}
26
27impl AgentCache {
28 pub fn new() -> AgentCache {
29 AgentCache {
30 unzoomed_agents: UnzoomedAgents::new(),
31 time: None,
32 agents_per_on: HashMap::new(),
33 unzoomed: None,
34 }
35 }
36
37 pub fn get(&self, on: Traversable) -> Vec<&dyn GameRenderable> {
38 self.agents_per_on[&on]
39 .iter()
40 .map(|obj| obj.borrow())
41 .collect()
42 }
43
44 pub fn populate_if_needed(
45 &mut self,
46 on: Traversable,
47 map: &Map,
48 sim: &Sim,
49 cs: &ColorScheme,
50 prerender: &Prerender,
51 ) {
52 let now = sim.time();
53 if Some(now) == self.time && self.agents_per_on.contains_key(&on) {
54 return;
55 }
56 let step_count = sim.step_count();
57
58 let mut list: Vec<Box<dyn GameRenderable>> = Vec::new();
59 for c in sim.get_draw_cars(on, map).into_iter() {
60 list.push(draw_vehicle(c, map, sim, prerender, cs));
61 }
62 let (loners, crowds) = sim.get_draw_peds(on, map);
63 for p in loners {
64 list.push(Box::new(DrawPedestrian::new(
65 p, step_count, map, sim, prerender, cs,
66 )));
67 }
68 for c in crowds {
69 list.push(Box::new(DrawPedCrowd::new(c, map, prerender, cs)));
70 }
71
72 if Some(now) != self.time {
73 self.agents_per_on.clear();
74 self.time = Some(now);
75 }
76
77 self.agents_per_on.insert(on, list);
78 }
79
80 pub fn calculate_unzoomed_agents<P: AsRef<Prerender>>(
83 &mut self,
84 prerender: &mut P,
85 map: &Map,
86 sim: &Sim,
87 cs: &ColorScheme,
88 ) -> &QuadTree<AgentID> {
89 let now = sim.time();
90 let mut recalc = true;
91 if let Some((time, ref orig_agents, _, _)) = self.unzoomed {
92 if now == time && self.unzoomed_agents == orig_agents.clone() {
93 recalc = false;
94 }
95 }
96
97 if recalc {
98 let highlighted = sim.get_highlighted_people();
99
100 let mut batch = GeomBatch::new();
101 let mut quadtree = QuadTree::builder();
102 let car_circle = Circle::new(
104 Pt2D::new(0.0, 0.0),
105 unzoomed_agent_radius(Some(VehicleType::Car)),
106 )
107 .to_polygon();
108 let ped_circle =
109 Circle::new(Pt2D::new(0.0, 0.0), unzoomed_agent_radius(None)).to_polygon();
110
111 for agent in sim.get_unzoomed_agents(map) {
112 if let Some(mut color) = self.unzoomed_agents.color(&agent, cs) {
113 if highlighted
115 .as_ref()
116 .and_then(|h| agent.person.as_ref().map(|p| !h.contains(p)))
117 .unwrap_or(false)
118 {
119 color = color.tint(0.5);
121 }
122
123 let circle = if agent.id.to_vehicle_type().is_some() {
124 car_circle.translate(agent.pos.x(), agent.pos.y())
125 } else {
126 ped_circle.translate(agent.pos.x(), agent.pos.y())
127 };
128 quadtree.add_with_box(agent.id, circle.get_bounds());
129 batch.push(color, circle);
130 }
131 }
132
133 let draw = prerender.as_ref().upload(batch);
134
135 self.unzoomed = Some((now, self.unzoomed_agents.clone(), quadtree.build(), draw));
136 }
137
138 &self.unzoomed.as_ref().unwrap().2
139 }
140
141 pub fn draw_unzoomed_agents(
142 &mut self,
143 g: &mut GfxCtx,
144 map: &Map,
145 sim: &Sim,
146 cs: &ColorScheme,
147 opts: &Options,
148 ) {
149 self.calculate_unzoomed_agents(g, map, sim, cs);
150 g.redraw(&self.unzoomed.as_ref().unwrap().3);
151
152 if opts.debug_all_agents {
153 let mut cnt = 0;
154 for input in sim.get_all_draw_cars(map) {
155 cnt += 1;
156 draw_vehicle(input, map, sim, g.prerender, cs);
157 }
158 println!(
159 "At {}, debugged {} cars",
160 sim.time(),
161 abstutil::prettyprint_usize(cnt)
162 );
163 }
165 }
166}
167
168#[derive(PartialEq, Clone)]
169pub struct UnzoomedAgents {
170 cars: bool,
171 bikes: bool,
172 buses_and_trains: bool,
173 peds: bool,
174}
175
176impl UnzoomedAgents {
177 pub fn new() -> UnzoomedAgents {
178 UnzoomedAgents {
179 cars: true,
180 bikes: true,
181 buses_and_trains: true,
182 peds: true,
183 }
184 }
185
186 pub fn cars(&self) -> bool {
187 self.cars
188 }
189 pub fn bikes(&self) -> bool {
190 self.bikes
191 }
192 pub fn buses_and_trains(&self) -> bool {
193 self.buses_and_trains
194 }
195 pub fn peds(&self) -> bool {
196 self.peds
197 }
198
199 fn color(&self, agent: &UnzoomedAgent, color_scheme: &ColorScheme) -> Option<Color> {
200 match agent.id.to_vehicle_type() {
201 Some(VehicleType::Car) => {
202 if self.cars {
203 Some(color_scheme.unzoomed_car)
204 } else {
205 None
206 }
207 }
208 Some(VehicleType::Bike) => {
209 if self.bikes {
210 Some(color_scheme.unzoomed_bike)
211 } else {
212 None
213 }
214 }
215 Some(VehicleType::Bus) | Some(VehicleType::Train) => {
216 if self.buses_and_trains {
217 Some(color_scheme.unzoomed_bus)
218 } else {
219 None
220 }
221 }
222 None => {
223 if self.peds {
224 Some(color_scheme.unzoomed_pedestrian)
225 } else {
226 None
227 }
228 }
229 }
230 }
231
232 pub fn update(&mut self, panel: &Panel) {
233 self.cars = panel.is_checked("Car");
234 self.bikes = panel.is_checked("Bike");
235 self.buses_and_trains = panel.is_checked("Bus");
236 self.peds = panel.is_checked("Walk");
237 }
238}