mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-29 01:13:53 +03:00
count the buildings and parking spots in each tract
This commit is contained in:
parent
083b96f0e7
commit
6f2b907927
@ -1,15 +1,16 @@
|
|||||||
use crate::common::CommonState;
|
use crate::common::CommonState;
|
||||||
use crate::helpers::rotating_color;
|
use crate::helpers::{rotating_color, ID};
|
||||||
use crate::ui::UI;
|
use crate::ui::UI;
|
||||||
use abstutil::Timer;
|
use abstutil::{prettyprint_usize, Timer};
|
||||||
use ezgui::{Color, EventCtx, GfxCtx, Key, ModalMenu, Text};
|
use ezgui::{Color, EventCtx, GfxCtx, Key, ModalMenu, Text};
|
||||||
use geom::{GPSBounds, Polygon};
|
use geom::Polygon;
|
||||||
use popdat::PopDat;
|
use popdat::PopDat;
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
pub struct DataVisualizer {
|
pub struct DataVisualizer {
|
||||||
menu: ModalMenu,
|
menu: ModalMenu,
|
||||||
popdat: PopDat,
|
popdat: PopDat,
|
||||||
tracts: Vec<Tract>,
|
tracts: BTreeMap<String, Tract>,
|
||||||
|
|
||||||
// TODO Urgh. 0, 1, or 2.
|
// TODO Urgh. 0, 1, or 2.
|
||||||
current_dataset: usize,
|
current_dataset: usize,
|
||||||
@ -17,9 +18,11 @@ pub struct DataVisualizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct Tract {
|
struct Tract {
|
||||||
name: String,
|
|
||||||
polygon: Polygon,
|
polygon: Polygon,
|
||||||
color: Color,
|
color: Color,
|
||||||
|
|
||||||
|
num_bldgs: usize,
|
||||||
|
num_parking_spots: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DataVisualizer {
|
impl DataVisualizer {
|
||||||
@ -39,7 +42,7 @@ impl DataVisualizer {
|
|||||||
],
|
],
|
||||||
ctx,
|
ctx,
|
||||||
),
|
),
|
||||||
tracts: clip(&popdat, &ui.primary.map.get_gps_bounds()),
|
tracts: clip(&popdat, ui, &mut timer),
|
||||||
popdat,
|
popdat,
|
||||||
current_dataset: 0,
|
current_dataset: 0,
|
||||||
current_tract: None,
|
current_tract: None,
|
||||||
@ -52,6 +55,12 @@ impl DataVisualizer {
|
|||||||
if let Some(ref name) = self.current_tract {
|
if let Some(ref name) = self.current_tract {
|
||||||
txt.add_line("Census ".to_string());
|
txt.add_line("Census ".to_string());
|
||||||
txt.append(name.clone(), Some(ui.cs.get("OSD name color")));
|
txt.append(name.clone(), Some(ui.cs.get("OSD name color")));
|
||||||
|
let tract = &self.tracts[name];
|
||||||
|
txt.add_line(format!("{} buildings", prettyprint_usize(tract.num_bldgs)));
|
||||||
|
txt.add_line(format!(
|
||||||
|
"{} parking spots ",
|
||||||
|
prettyprint_usize(tract.num_parking_spots)
|
||||||
|
));
|
||||||
}
|
}
|
||||||
self.menu.handle_event(ctx, Some(txt));
|
self.menu.handle_event(ctx, Some(txt));
|
||||||
ctx.canvas.handle_event(ctx.input);
|
ctx.canvas.handle_event(ctx.input);
|
||||||
@ -70,9 +79,9 @@ impl DataVisualizer {
|
|||||||
if !ctx.canvas.is_dragging() && ctx.input.get_moved_mouse().is_some() {
|
if !ctx.canvas.is_dragging() && ctx.input.get_moved_mouse().is_some() {
|
||||||
if let Some(pt) = ctx.canvas.get_cursor_in_map_space() {
|
if let Some(pt) = ctx.canvas.get_cursor_in_map_space() {
|
||||||
self.current_tract = None;
|
self.current_tract = None;
|
||||||
for tract in &self.tracts {
|
for (name, tract) in &self.tracts {
|
||||||
if tract.polygon.contains_pt(pt) {
|
if tract.polygon.contains_pt(pt) {
|
||||||
self.current_tract = Some(tract.name.clone());
|
self.current_tract = Some(name.clone());
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -83,8 +92,8 @@ impl DataVisualizer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw(&self, g: &mut GfxCtx, ui: &UI) {
|
pub fn draw(&self, g: &mut GfxCtx, ui: &UI) {
|
||||||
for tract in &self.tracts {
|
for (name, tract) in &self.tracts {
|
||||||
let color = if Some(tract.name.clone()) == self.current_tract {
|
let color = if Some(name.clone()) == self.current_tract {
|
||||||
ui.cs.get("selected")
|
ui.cs.get("selected")
|
||||||
} else {
|
} else {
|
||||||
tract.color
|
tract.color
|
||||||
@ -104,18 +113,50 @@ impl DataVisualizer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clip(popdat: &PopDat, bounds: &GPSBounds) -> Vec<Tract> {
|
fn clip(popdat: &PopDat, ui: &UI, timer: &mut Timer) -> BTreeMap<String, Tract> {
|
||||||
// TODO Partial clipping could be neat, except it'd be confusing to interpret totals.
|
// TODO Partial clipping could be neat, except it'd be confusing to interpret totals.
|
||||||
let mut results = Vec::new();
|
let mut results = BTreeMap::new();
|
||||||
|
timer.start_iter("clip tracts", popdat.tracts.len());
|
||||||
for (name, tract) in &popdat.tracts {
|
for (name, tract) in &popdat.tracts {
|
||||||
if let Some(pts) = bounds.try_convert(&tract.pts) {
|
timer.next();
|
||||||
|
if let Some(pts) = ui.primary.map.get_gps_bounds().try_convert(&tract.pts) {
|
||||||
// TODO We should actually make sure the polygon is completely contained within the
|
// TODO We should actually make sure the polygon is completely contained within the
|
||||||
// map's boundary.
|
// map's boundary.
|
||||||
results.push(Tract {
|
let polygon = Polygon::new(&pts);
|
||||||
name: name.clone(),
|
|
||||||
polygon: Polygon::new(&pts),
|
// TODO Don't just use the center...
|
||||||
color: rotating_color(results.len()),
|
let mut num_bldgs = 0;
|
||||||
});
|
let mut num_parking_spots = 0;
|
||||||
|
for id in ui
|
||||||
|
.primary
|
||||||
|
.draw_map
|
||||||
|
.get_matching_objects(polygon.get_bounds())
|
||||||
|
{
|
||||||
|
match id {
|
||||||
|
ID::Building(b) => {
|
||||||
|
if polygon.contains_pt(ui.primary.map.get_b(b).polygon.center()) {
|
||||||
|
num_bldgs += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ID::Lane(l) => {
|
||||||
|
let lane = ui.primary.map.get_l(l);
|
||||||
|
if lane.is_parking() && polygon.contains_pt(lane.lane_center_pts.middle()) {
|
||||||
|
num_parking_spots += lane.number_parking_spots();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
results.insert(
|
||||||
|
name.clone(),
|
||||||
|
Tract {
|
||||||
|
polygon,
|
||||||
|
color: rotating_color(results.len()),
|
||||||
|
num_bldgs,
|
||||||
|
num_parking_spots,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
println!(
|
println!(
|
||||||
|
@ -298,17 +298,6 @@ impl DrawMap {
|
|||||||
&self.areas[id.0]
|
&self.areas[id.0]
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn get_matching_lanes(&self, bounds: Bounds) -> Vec<LaneID> {
|
|
||||||
let mut results: Vec<LaneID> = Vec::new();
|
|
||||||
for &(id, _, _) in &self.quadtree.query(bounds.as_bbox()) {
|
|
||||||
if let ID::Lane(id) = id {
|
|
||||||
results.push(*id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
results
|
|
||||||
}
|
|
||||||
|
|
||||||
// Unsorted, unexpanded, raw result.
|
// Unsorted, unexpanded, raw result.
|
||||||
pub fn get_matching_objects(&self, bounds: Bounds) -> Vec<ID> {
|
pub fn get_matching_objects(&self, bounds: Bounds) -> Vec<ID> {
|
||||||
let mut results: Vec<ID> = Vec::new();
|
let mut results: Vec<ID> = Vec::new();
|
||||||
|
Loading…
Reference in New Issue
Block a user