mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-11-28 12:12:00 +03:00
changing the activity plugin to show a heatmap of what's currently in view
This commit is contained in:
parent
a610575701
commit
db34ddb2b7
@ -1,14 +1,14 @@
|
||||
use ezgui::Color;
|
||||
use map_model::LaneID;
|
||||
use objects::{Ctx, DEBUG, ID};
|
||||
use ezgui::{Color, GfxCtx};
|
||||
use geom::{Bounds, Pt2D};
|
||||
use map_model::Map;
|
||||
use objects::{Ctx, DEBUG};
|
||||
use piston::input::Key;
|
||||
use plugins::{Plugin, PluginCtx};
|
||||
use sim::Tick;
|
||||
use std::collections::HashSet;
|
||||
use sim::{Sim, Tick};
|
||||
|
||||
pub enum ShowActivityState {
|
||||
Inactive,
|
||||
Active(Tick, HashSet<LaneID>),
|
||||
Active(Tick, Heatmap),
|
||||
}
|
||||
|
||||
impl ShowActivityState {
|
||||
@ -29,21 +29,26 @@ impl Plugin for ShowActivityState {
|
||||
) {
|
||||
new_state = Some(ShowActivityState::Active(
|
||||
ctx.primary.sim.time,
|
||||
ctx.primary.sim.find_lanes_with_movement(),
|
||||
active_agent_heatmap(
|
||||
ctx.canvas.get_screen_bounds(),
|
||||
&ctx.primary.sim,
|
||||
&ctx.primary.map,
|
||||
),
|
||||
));
|
||||
}
|
||||
}
|
||||
ShowActivityState::Active(time, _) => {
|
||||
ShowActivityState::Active(time, ref old_heatmap) => {
|
||||
if ctx
|
||||
.input
|
||||
.key_pressed(Key::Return, "stop showing lanes with active traffic")
|
||||
{
|
||||
new_state = Some(ShowActivityState::Inactive);
|
||||
}
|
||||
if *time != ctx.primary.sim.time {
|
||||
let bounds = ctx.canvas.get_screen_bounds();
|
||||
if *time != ctx.primary.sim.time || bounds != old_heatmap.bounds {
|
||||
new_state = Some(ShowActivityState::Active(
|
||||
ctx.primary.sim.time,
|
||||
ctx.primary.sim.find_lanes_with_movement(),
|
||||
active_agent_heatmap(bounds, &ctx.primary.sim, &ctx.primary.map),
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -57,18 +62,81 @@ impl Plugin for ShowActivityState {
|
||||
}
|
||||
}
|
||||
|
||||
fn color_for(&self, obj: ID, ctx: Ctx) -> Option<Color> {
|
||||
match (obj, self) {
|
||||
(ID::Lane(id), ShowActivityState::Active(_, ref lanes)) => {
|
||||
if lanes.contains(&id) {
|
||||
None
|
||||
} else {
|
||||
// TODO I want to modify the color that'd happen anyway and just make it more
|
||||
// transparent. But how?
|
||||
Some(ctx.cs.get("inactive lane", Color::rgba(0, 0, 0, 0.2)))
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
fn draw(&self, g: &mut GfxCtx, _ctx: Ctx) {
|
||||
if let ShowActivityState::Active(_, ref heatmap) = self {
|
||||
heatmap.draw(g);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A nice 10x10
|
||||
const NUM_TILES: usize = 10;
|
||||
|
||||
pub struct Heatmap {
|
||||
bounds: Bounds,
|
||||
|
||||
counts: [[usize; NUM_TILES]; NUM_TILES],
|
||||
max: usize,
|
||||
}
|
||||
|
||||
impl Heatmap {
|
||||
fn new(bounds: Bounds) -> Heatmap {
|
||||
Heatmap {
|
||||
bounds,
|
||||
counts: [[0; NUM_TILES]; NUM_TILES],
|
||||
max: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn add(&mut self, pt: Pt2D) {
|
||||
// TODO Could also query sim with this filter
|
||||
if !self.bounds.contains(pt) {
|
||||
return;
|
||||
}
|
||||
|
||||
let x = ((pt.x() - self.bounds.min_x) / (self.bounds.max_x - self.bounds.min_x)
|
||||
* (NUM_TILES as f64))
|
||||
.floor() as usize;
|
||||
let y = ((pt.y() - self.bounds.min_y) / (self.bounds.max_y - self.bounds.min_y)
|
||||
* (NUM_TILES as f64))
|
||||
.floor() as usize;
|
||||
self.counts[x][y] += 1;
|
||||
self.max = self.max.max(self.counts[x][y]);
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx) {
|
||||
let tile_width = (self.bounds.max_x - self.bounds.min_x) / (NUM_TILES as f64);
|
||||
let tile_height = (self.bounds.max_y - self.bounds.min_y) / (NUM_TILES as f64);
|
||||
|
||||
for x in 0..NUM_TILES {
|
||||
for y in 0..NUM_TILES {
|
||||
if self.counts[x][y] == 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
let percent = (self.counts[x][y] as f32) / (self.max as f32);
|
||||
// TODO Map percent to hot/cold colors
|
||||
let color = Color::rgba(255, 0, 0, percent);
|
||||
g.draw_rectangle(
|
||||
color,
|
||||
[
|
||||
(x as f64) * tile_width,
|
||||
(y as f64) * tile_height,
|
||||
tile_width,
|
||||
tile_height,
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn active_agent_heatmap(bounds: Bounds, sim: &Sim, map: &Map) -> Heatmap {
|
||||
let mut h = Heatmap::new(bounds);
|
||||
for trip in sim.get_active_trips().into_iter() {
|
||||
if let Some(pt) = sim.get_canonical_point_for_trip(trip, map) {
|
||||
h.add(pt);
|
||||
}
|
||||
}
|
||||
h
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ impl From<Pt2D> for HashablePt2D {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct Bounds {
|
||||
pub min_x: f64,
|
||||
pub min_y: f64,
|
||||
|
@ -874,17 +874,6 @@ impl DrivingSimState {
|
||||
|
||||
(moving_cars, stuck_cars, buses)
|
||||
}
|
||||
|
||||
pub fn find_lanes_with_movement(&self, active: &mut HashSet<LaneID>) {
|
||||
for c in self.cars.values() {
|
||||
if c.speed > kinematics::EPSILON_SPEED {
|
||||
match c.on {
|
||||
Traversable::Lane(id) => active.insert(id),
|
||||
Traversable::Turn(t) => active.insert(t.src),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CreateCar {
|
||||
|
@ -452,15 +452,6 @@ impl Sim {
|
||||
trips_with_ab_test_divergence: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// TODO This is another query like summarize()
|
||||
// Turns count as activity on the origin lane
|
||||
pub fn find_lanes_with_movement(&self) -> HashSet<LaneID> {
|
||||
let mut active: HashSet<LaneID> = HashSet::new();
|
||||
self.driving_state.find_lanes_with_movement(&mut active);
|
||||
self.walking_state.find_lanes_with_movement(&mut active);
|
||||
active
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Benchmark {
|
||||
|
@ -680,17 +680,6 @@ impl WalkingSimState {
|
||||
|
||||
(moving_peds, stuck_peds)
|
||||
}
|
||||
|
||||
pub fn find_lanes_with_movement(&self, active: &mut HashSet<LaneID>) {
|
||||
for p in self.peds.values() {
|
||||
if p.waiting_for.is_none() {
|
||||
match p.on {
|
||||
Traversable::Lane(id) => active.insert(id),
|
||||
Traversable::Turn(t) => active.insert(t.src),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn is_contraflow(map: &Map, from: LaneID, to: LaneID) -> bool {
|
||||
|
Loading…
Reference in New Issue
Block a user