count the buildings and parking spots in each tract

This commit is contained in:
Dustin Carlino 2019-05-20 09:53:37 -07:00
parent 083b96f0e7
commit 6f2b907927
2 changed files with 59 additions and 29 deletions

View File

@ -1,15 +1,16 @@
use crate::common::CommonState;
use crate::helpers::rotating_color;
use crate::helpers::{rotating_color, ID};
use crate::ui::UI;
use abstutil::Timer;
use abstutil::{prettyprint_usize, Timer};
use ezgui::{Color, EventCtx, GfxCtx, Key, ModalMenu, Text};
use geom::{GPSBounds, Polygon};
use geom::Polygon;
use popdat::PopDat;
use std::collections::BTreeMap;
pub struct DataVisualizer {
menu: ModalMenu,
popdat: PopDat,
tracts: Vec<Tract>,
tracts: BTreeMap<String, Tract>,
// TODO Urgh. 0, 1, or 2.
current_dataset: usize,
@ -17,9 +18,11 @@ pub struct DataVisualizer {
}
struct Tract {
name: String,
polygon: Polygon,
color: Color,
num_bldgs: usize,
num_parking_spots: usize,
}
impl DataVisualizer {
@ -39,7 +42,7 @@ impl DataVisualizer {
],
ctx,
),
tracts: clip(&popdat, &ui.primary.map.get_gps_bounds()),
tracts: clip(&popdat, ui, &mut timer),
popdat,
current_dataset: 0,
current_tract: None,
@ -52,6 +55,12 @@ impl DataVisualizer {
if let Some(ref name) = self.current_tract {
txt.add_line("Census ".to_string());
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));
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 let Some(pt) = ctx.canvas.get_cursor_in_map_space() {
self.current_tract = None;
for tract in &self.tracts {
for (name, tract) in &self.tracts {
if tract.polygon.contains_pt(pt) {
self.current_tract = Some(tract.name.clone());
self.current_tract = Some(name.clone());
break;
}
}
@ -83,8 +92,8 @@ impl DataVisualizer {
}
pub fn draw(&self, g: &mut GfxCtx, ui: &UI) {
for tract in &self.tracts {
let color = if Some(tract.name.clone()) == self.current_tract {
for (name, tract) in &self.tracts {
let color = if Some(name.clone()) == self.current_tract {
ui.cs.get("selected")
} else {
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.
let mut results = Vec::new();
let mut results = BTreeMap::new();
timer.start_iter("clip tracts", popdat.tracts.len());
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
// map's boundary.
results.push(Tract {
name: name.clone(),
polygon: Polygon::new(&pts),
let polygon = Polygon::new(&pts);
// TODO Don't just use the center...
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!(

View File

@ -298,17 +298,6 @@ impl DrawMap {
&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.
pub fn get_matching_objects(&self, bounds: Bounds) -> Vec<ID> {
let mut results: Vec<ID> = Vec::new();