use std::borrow::Borrow;
use std::collections::HashMap;
use geom::{Circle, Pt2D, QuadTree, Time};
use map_gui::colors::ColorScheme;
use map_gui::options::Options;
use map_model::{Map, Traversable};
use sim::{AgentID, Sim, UnzoomedAgent, VehicleType};
use widgetry::{Color, Drawable, GeomBatch, GfxCtx, Panel, Prerender};
use crate::render::{
draw_vehicle, unzoomed_agent_radius, DrawPedCrowd, DrawPedestrian, GameRenderable,
};
pub struct AgentCache {
pub unzoomed_agents: UnzoomedAgents,
time: Option<Time>,
agents_per_on: HashMap<Traversable, Vec<Box<dyn GameRenderable>>>,
unzoomed: Option<(Time, UnzoomedAgents, QuadTree<AgentID>, Drawable)>,
}
impl AgentCache {
pub fn new() -> AgentCache {
AgentCache {
unzoomed_agents: UnzoomedAgents::new(),
time: None,
agents_per_on: HashMap::new(),
unzoomed: None,
}
}
pub fn get(&self, on: Traversable) -> Vec<&dyn GameRenderable> {
self.agents_per_on[&on]
.iter()
.map(|obj| obj.borrow())
.collect()
}
pub fn populate_if_needed(
&mut self,
on: Traversable,
map: &Map,
sim: &Sim,
cs: &ColorScheme,
prerender: &Prerender,
) {
let now = sim.time();
if Some(now) == self.time && self.agents_per_on.contains_key(&on) {
return;
}
let step_count = sim.step_count();
let mut list: Vec<Box<dyn GameRenderable>> = Vec::new();
for c in sim.get_draw_cars(on, map).into_iter() {
list.push(draw_vehicle(c, map, sim, prerender, cs));
}
let (loners, crowds) = sim.get_draw_peds(on, map);
for p in loners {
list.push(Box::new(DrawPedestrian::new(
p, step_count, map, sim, prerender, cs,
)));
}
for c in crowds {
list.push(Box::new(DrawPedCrowd::new(c, map, prerender, cs)));
}
if Some(now) != self.time {
self.agents_per_on.clear();
self.time = Some(now);
}
self.agents_per_on.insert(on, list);
}
pub fn calculate_unzoomed_agents<P: AsRef<Prerender>>(
&mut self,
prerender: &mut P,
map: &Map,
sim: &Sim,
cs: &ColorScheme,
) -> &QuadTree<AgentID> {
let now = sim.time();
let mut recalc = true;
if let Some((time, ref orig_agents, _, _)) = self.unzoomed {
if now == time && self.unzoomed_agents == orig_agents.clone() {
recalc = false;
}
}
if recalc {
let highlighted = sim.get_highlighted_people();
let mut batch = GeomBatch::new();
let mut quadtree = QuadTree::builder();
let car_circle = Circle::new(
Pt2D::new(0.0, 0.0),
unzoomed_agent_radius(Some(VehicleType::Car)),
)
.to_polygon();
let ped_circle =
Circle::new(Pt2D::new(0.0, 0.0), unzoomed_agent_radius(None)).to_polygon();
for agent in sim.get_unzoomed_agents(map) {
if let Some(mut color) = self.unzoomed_agents.color(&agent, cs) {
if highlighted
.as_ref()
.and_then(|h| agent.person.as_ref().map(|p| !h.contains(p)))
.unwrap_or(false)
{
color = color.tint(0.5);
}
let circle = if agent.id.to_vehicle_type().is_some() {
car_circle.translate(agent.pos.x(), agent.pos.y())
} else {
ped_circle.translate(agent.pos.x(), agent.pos.y())
};
quadtree.add_with_box(agent.id, circle.get_bounds());
batch.push(color, circle);
}
}
let draw = prerender.as_ref().upload(batch);
self.unzoomed = Some((now, self.unzoomed_agents.clone(), quadtree.build(), draw));
}
&self.unzoomed.as_ref().unwrap().2
}
pub fn draw_unzoomed_agents(
&mut self,
g: &mut GfxCtx,
map: &Map,
sim: &Sim,
cs: &ColorScheme,
opts: &Options,
) {
self.calculate_unzoomed_agents(g, map, sim, cs);
g.redraw(&self.unzoomed.as_ref().unwrap().3);
if opts.debug_all_agents {
let mut cnt = 0;
for input in sim.get_all_draw_cars(map) {
cnt += 1;
draw_vehicle(input, map, sim, g.prerender, cs);
}
println!(
"At {}, debugged {} cars",
sim.time(),
abstutil::prettyprint_usize(cnt)
);
}
}
}
#[derive(PartialEq, Clone)]
pub struct UnzoomedAgents {
cars: bool,
bikes: bool,
buses_and_trains: bool,
peds: bool,
}
impl UnzoomedAgents {
pub fn new() -> UnzoomedAgents {
UnzoomedAgents {
cars: true,
bikes: true,
buses_and_trains: true,
peds: true,
}
}
pub fn cars(&self) -> bool {
self.cars
}
pub fn bikes(&self) -> bool {
self.bikes
}
pub fn buses_and_trains(&self) -> bool {
self.buses_and_trains
}
pub fn peds(&self) -> bool {
self.peds
}
fn color(&self, agent: &UnzoomedAgent, color_scheme: &ColorScheme) -> Option<Color> {
match agent.id.to_vehicle_type() {
Some(VehicleType::Car) => {
if self.cars {
Some(color_scheme.unzoomed_car)
} else {
None
}
}
Some(VehicleType::Bike) => {
if self.bikes {
Some(color_scheme.unzoomed_bike)
} else {
None
}
}
Some(VehicleType::Bus) | Some(VehicleType::Train) => {
if self.buses_and_trains {
Some(color_scheme.unzoomed_bus)
} else {
None
}
}
None => {
if self.peds {
Some(color_scheme.unzoomed_pedestrian)
} else {
None
}
}
}
}
pub fn update(&mut self, panel: &Panel) {
self.cars = panel.is_checked("Car");
self.bikes = panel.is_checked("Bike");
self.buses_and_trains = panel.is_checked("Bus");
self.peds = panel.is_checked("Walk");
}
}