stable IDs for buildings in raw layer too. stop futzing with ID problems there.

This commit is contained in:
Dustin Carlino 2019-09-17 13:11:08 -07:00
parent 33ab7d4553
commit eee5981c14
7 changed files with 82 additions and 60 deletions

View File

@ -92,7 +92,7 @@ pub fn clip_map(map: &mut raw_data::Map, timer: &mut Timer) {
} }
} }
map.buildings.retain(|b| { retain_btreemap(&mut map.buildings, |_, b| {
b.polygon b.polygon
.points() .points()
.iter() .iter()

View File

@ -211,32 +211,32 @@ fn use_offstreet_parking(map: &mut raw_data::Map, path: &str, timer: &mut Timer)
timer.start("match offstreet parking points"); timer.start("match offstreet parking points");
let shapes = kml::load(path, &map.gps_bounds, timer).expect("loading offstreet_parking failed"); let shapes = kml::load(path, &map.gps_bounds, timer).expect("loading offstreet_parking failed");
// Building indices let mut closest: FindClosest<raw_data::StableBuildingID> =
let mut closest: FindClosest<usize> = FindClosest::new(&map.gps_bounds.to_bounds()); FindClosest::new(&map.gps_bounds.to_bounds());
for (idx, b) in map.buildings.iter().enumerate() { for (id, b) in &map.buildings {
closest.add(idx, b.polygon.points()); closest.add(*id, b.polygon.points());
} }
// TODO Another function just to use ?. Try blocks would rock. // TODO Another function just to use ?. Try blocks would rock.
let mut handle_shape: Box<dyn FnMut(kml::ExtraShape) -> Option<()>> = Box::new(|s| { let mut handle_shape: Box<dyn FnMut(kml::ExtraShape) -> Option<()>> = Box::new(|s| {
assert_eq!(s.points.len(), 1); assert_eq!(s.points.len(), 1);
let pt = Pt2D::from_gps(s.points[0], &map.gps_bounds)?; let pt = Pt2D::from_gps(s.points[0], &map.gps_bounds)?;
let (idx, _) = closest.closest_pt(pt, Distance::meters(50.0))?; let (id, _) = closest.closest_pt(pt, Distance::meters(50.0))?;
// TODO Handle parking lots. // TODO Handle parking lots.
if !map.buildings[idx].polygon.contains_pt(pt) { if !map.buildings[&id].polygon.contains_pt(pt) {
return None; return None;
} }
let name = s.attributes.get("DEA_FACILITY_NAME")?.to_string(); let name = s.attributes.get("DEA_FACILITY_NAME")?.to_string();
let num_stalls = s.attributes.get("DEA_STALLS")?.parse::<usize>().ok()?; let num_stalls = s.attributes.get("DEA_STALLS")?.parse::<usize>().ok()?;
// TODO Update the existing one instead // TODO Update the existing one instead
if let Some(ref existing) = map.buildings[idx].parking { if let Some(ref existing) = map.buildings[&id].parking {
// TODO Can't use timer inside this closure // TODO Can't use timer inside this closure
println!( println!(
"Two offstreet parking hints apply to building {}: {} @ {}, and {} @ {}", "Two offstreet parking hints apply to {}: {} @ {}, and {} @ {}",
idx, existing.num_stalls, existing.name, num_stalls, name id, existing.num_stalls, existing.name, num_stalls, name
); );
} }
map.buildings[idx].parking = Some(OffstreetParking { map.buildings.get_mut(&id).unwrap().parking = Some(OffstreetParking {
name, name,
num_stalls, num_stalls,
// Temporary values, populate later // Temporary values, populate later

View File

@ -97,12 +97,16 @@ pub fn extract_osm(
if deduped.len() < 3 { if deduped.len() < 3 {
continue; continue;
} }
map.buildings.push(raw_data::Building { let id = raw_data::StableBuildingID(map.buildings.len());
osm_way_id: way.id, map.buildings.insert(
polygon: Polygon::new(&deduped), id,
osm_tags: tags, raw_data::Building {
parking: None, osm_way_id: way.id,
}); polygon: Polygon::new(&deduped),
osm_tags: tags,
parking: None,
},
);
} else if let Some(at) = get_area_type(&tags) { } else if let Some(at) = get_area_type(&tags) {
if pts.len() < 3 { if pts.len() < 3 {
continue; continue;

View File

@ -2,26 +2,26 @@ use crate::make::sidewalk_finder::find_sidewalk_points;
use crate::{raw_data, Building, BuildingID, FrontPath, Lane, LaneID, Position, Road}; use crate::{raw_data, Building, BuildingID, FrontPath, Lane, LaneID, Position, Road};
use abstutil::Timer; use abstutil::Timer;
use geom::{Bounds, Distance, FindClosest, HashablePt2D, Line, Polygon}; use geom::{Bounds, Distance, FindClosest, HashablePt2D, Line, Polygon};
use std::collections::HashSet; use std::collections::{BTreeMap, HashSet};
pub fn make_all_buildings( pub fn make_all_buildings(
results: &mut Vec<Building>, results: &mut Vec<Building>,
input: &Vec<raw_data::Building>, input: &BTreeMap<raw_data::StableBuildingID, raw_data::Building>,
bounds: &Bounds, bounds: &Bounds,
lanes: &Vec<Lane>, lanes: &Vec<Lane>,
roads: &Vec<Road>, roads: &Vec<Road>,
timer: &mut Timer, timer: &mut Timer,
) { ) {
timer.start("convert buildings"); timer.start("convert buildings");
let mut center_per_bldg: Vec<HashablePt2D> = Vec::new(); let mut center_per_bldg: BTreeMap<raw_data::StableBuildingID, HashablePt2D> = BTreeMap::new();
let mut query: HashSet<HashablePt2D> = HashSet::new(); let mut query: HashSet<HashablePt2D> = HashSet::new();
timer.start_iter("get building center points", input.len()); timer.start_iter("get building center points", input.len());
for b in input { for (id, b) in input {
timer.next(); timer.next();
// TODO Use the polylabel? Want to have visually distinct lines for front path and // TODO Use the polylabel? Want to have visually distinct lines for front path and
// driveway; using two different "centers" is a lazy way for now. // driveway; using two different "centers" is a lazy way for now.
let center = b.polygon.center().to_hashable(); let center = b.polygon.center().to_hashable();
center_per_bldg.push(center); center_per_bldg.insert(*id, center);
query.insert(center); query.insert(center);
} }
@ -45,7 +45,7 @@ pub fn make_all_buildings(
let sidewalk_pts = find_sidewalk_points(bounds, query, lanes, Distance::meters(100.0), timer); let sidewalk_pts = find_sidewalk_points(bounds, query, lanes, Distance::meters(100.0), timer);
timer.start_iter("create building front paths", center_per_bldg.len()); timer.start_iter("create building front paths", center_per_bldg.len());
for (idx, bldg_center) in center_per_bldg.into_iter().enumerate() { for (stable_id, bldg_center) in center_per_bldg {
timer.next(); timer.next();
if let Some(sidewalk_pos) = sidewalk_pts.get(&bldg_center) { if let Some(sidewalk_pos) = sidewalk_pts.get(&bldg_center) {
let sidewalk_pt = lanes[sidewalk_pos.lane().0] let sidewalk_pt = lanes[sidewalk_pos.lane().0]
@ -55,21 +55,21 @@ pub fn make_all_buildings(
timer.warn("Skipping a building because front path has 0 length".to_string()); timer.warn("Skipping a building because front path has 0 length".to_string());
continue; continue;
} }
let polygon = &input[idx].polygon; let b = &input[&stable_id];
let line = trim_path(polygon, Line::new(bldg_center.to_pt2d(), sidewalk_pt)); let line = trim_path(&b.polygon, Line::new(bldg_center.to_pt2d(), sidewalk_pt));
let id = BuildingID(results.len()); let id = BuildingID(results.len());
let mut bldg = Building { let mut bldg = Building {
id, id,
polygon: polygon.clone(), polygon: b.polygon.clone(),
osm_tags: input[idx].osm_tags.clone(), osm_tags: b.osm_tags.clone(),
osm_way_id: input[idx].osm_way_id, osm_way_id: b.osm_way_id,
front_path: FrontPath { front_path: FrontPath {
sidewalk: *sidewalk_pos, sidewalk: *sidewalk_pos,
line, line,
}, },
parking: input[idx].parking.clone(), parking: b.parking.clone(),
label_center: polygon.polylabel(), label_center: b.polygon.polylabel(),
}; };
// Make a driveway from the parking icon to the nearest road. // Make a driveway from the parking icon to the nearest road.

View File

@ -25,12 +25,20 @@ impl fmt::Display for StableIntersectionID {
} }
} }
#[derive(PartialEq, Eq, Debug, Serialize, Deserialize, PartialOrd, Ord, Clone, Copy, Hash)]
pub struct StableBuildingID(pub usize);
impl fmt::Display for StableBuildingID {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "StableBuildingID({0})", self.0)
}
}
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct Map { pub struct Map {
pub name: String, pub name: String,
pub roads: BTreeMap<StableRoadID, Road>, pub roads: BTreeMap<StableRoadID, Road>,
pub intersections: BTreeMap<StableIntersectionID, Intersection>, pub intersections: BTreeMap<StableIntersectionID, Intersection>,
pub buildings: Vec<Building>, pub buildings: BTreeMap<StableBuildingID, Building>,
pub bus_routes: Vec<Route>, pub bus_routes: Vec<Route>,
pub areas: Vec<Area>, pub areas: Vec<Area>,
// from OSM way => [(restriction, to OSM way)] // from OSM way => [(restriction, to OSM way)]
@ -46,7 +54,7 @@ impl Map {
name, name,
roads: BTreeMap::new(), roads: BTreeMap::new(),
intersections: BTreeMap::new(), intersections: BTreeMap::new(),
buildings: Vec::new(), buildings: BTreeMap::new(),
bus_routes: Vec::new(), bus_routes: Vec::new(),
areas: Vec::new(), areas: Vec::new(),
turn_restrictions: BTreeMap::new(), turn_restrictions: BTreeMap::new(),

View File

@ -2,8 +2,8 @@ mod model;
use ezgui::{Color, EventCtx, EventLoopMode, GfxCtx, Key, Line, Text, Wizard, GUI}; use ezgui::{Color, EventCtx, EventLoopMode, GfxCtx, Key, Line, Text, Wizard, GUI};
use geom::{Distance, Line, Polygon, Pt2D}; use geom::{Distance, Line, Polygon, Pt2D};
use map_model::raw_data::{StableIntersectionID, StableRoadID}; use map_model::raw_data::{StableBuildingID, StableIntersectionID, StableRoadID};
use model::{BuildingID, Direction, Model, ID}; use model::{Direction, Model, ID};
use std::{env, process}; use std::{env, process};
struct UI { struct UI {
@ -15,8 +15,8 @@ struct UI {
enum State { enum State {
Viewing, Viewing,
MovingIntersection(StableIntersectionID), MovingIntersection(StableIntersectionID),
MovingBuilding(BuildingID), MovingBuilding(StableBuildingID),
LabelingBuilding(BuildingID, Wizard), LabelingBuilding(StableBuildingID, Wizard),
LabelingRoad((StableRoadID, Direction), Wizard), LabelingRoad((StableRoadID, Direction), Wizard),
LabelingIntersection(StableIntersectionID, Wizard), LabelingIntersection(StableIntersectionID, Wizard),
CreatingRoad(StableIntersectionID), CreatingRoad(StableIntersectionID),

View File

@ -2,7 +2,7 @@ use abstutil::{read_binary, MultiMap, Timer};
use ezgui::world::{Object, ObjectID, World}; use ezgui::world::{Object, ObjectID, World};
use ezgui::{Color, EventCtx, GfxCtx, Line, Prerender, Text}; use ezgui::{Color, EventCtx, GfxCtx, Line, Prerender, Text};
use geom::{Bounds, Circle, Distance, PolyLine, Polygon, Pt2D}; use geom::{Bounds, Circle, Distance, PolyLine, Polygon, Pt2D};
use map_model::raw_data::{MapFix, MapFixes, StableIntersectionID, StableRoadID}; use map_model::raw_data::{MapFix, MapFixes, StableBuildingID, StableIntersectionID, StableRoadID};
use map_model::{raw_data, IntersectionType, LaneType, RoadSpec, LANE_THICKNESS}; use map_model::{raw_data, IntersectionType, LaneType, RoadSpec, LANE_THICKNESS};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::mem; use std::mem;
@ -13,7 +13,6 @@ const CENTER_LINE_THICKNESS: Distance = Distance::const_meters(0.5);
const SYNTHETIC_OSM_WAY_ID: i64 = -1; const SYNTHETIC_OSM_WAY_ID: i64 = -1;
pub type BuildingID = usize;
pub type Direction = bool; pub type Direction = bool;
const FORWARDS: Direction = true; const FORWARDS: Direction = true;
const BACKWARDS: Direction = false; const BACKWARDS: Direction = false;
@ -52,6 +51,10 @@ impl Model {
model.map = read_binary(path, &mut timer).unwrap(); model.map = read_binary(path, &mut timer).unwrap();
model.map.apply_fixes(&model.fixes, &mut timer); model.map.apply_fixes(&model.fixes, &mut timer);
for id in model.map.buildings.keys() {
model.id_counter = model.id_counter.max(id.0 + 1);
}
for id in model.map.intersections.keys() { for id in model.map.intersections.keys() {
model.id_counter = model.id_counter.max(id.0 + 1); model.id_counter = model.id_counter.max(id.0 + 1);
} }
@ -65,7 +68,7 @@ impl Model {
model.world = World::new(&model.compute_bounds()); model.world = World::new(&model.compute_bounds());
if !model.exclude_bldgs { if !model.exclude_bldgs {
for id in 0..model.map.buildings.len() { for id in model.map.buildings.keys().cloned().collect::<Vec<_>>() {
model.bldg_added(id, prerender); model.bldg_added(id, prerender);
} }
} }
@ -114,7 +117,7 @@ impl Model {
fn compute_bounds(&self) -> Bounds { fn compute_bounds(&self) -> Bounds {
let mut bounds = Bounds::new(); let mut bounds = Bounds::new();
for b in &self.map.buildings { for b in self.map.buildings.values() {
for pt in b.polygon.points() { for pt in b.polygon.points() {
bounds.update(*pt); bounds.update(*pt);
} }
@ -132,8 +135,8 @@ impl Model {
pub fn delete_everything_inside(&mut self, area: Polygon) { pub fn delete_everything_inside(&mut self, area: Polygon) {
if !self.exclude_bldgs { if !self.exclude_bldgs {
for id in 0..self.map.buildings.len() { for id in self.map.buildings.keys().cloned().collect::<Vec<_>>() {
if area.contains_pt(self.map.buildings[id].polygon.center()) { if area.contains_pt(self.map.buildings[&id].polygon.center()) {
self.delete_b(id); self.delete_b(id);
} }
} }
@ -496,8 +499,8 @@ impl Model {
} }
impl Model { impl Model {
fn bldg_added(&mut self, id: BuildingID, prerender: &Prerender) { fn bldg_added(&mut self, id: StableBuildingID, prerender: &Prerender) {
let b = &self.map.buildings[id]; let b = &self.map.buildings[&id];
self.world.add( self.world.add(
prerender, prerender,
Object::new(ID::Building(id), Color::BLUE, b.polygon.clone()) Object::new(ID::Building(id), Color::BLUE, b.polygon.clone())
@ -506,21 +509,25 @@ impl Model {
} }
pub fn create_b(&mut self, center: Pt2D, prerender: &Prerender) { pub fn create_b(&mut self, center: Pt2D, prerender: &Prerender) {
let id = self.map.buildings.len(); let id = StableBuildingID(self.id_counter);
self.map.buildings.push(raw_data::Building { self.id_counter += 1;
polygon: Polygon::rectangle(center, BUILDING_LENGTH, BUILDING_LENGTH), self.map.buildings.insert(
osm_tags: BTreeMap::new(), id,
osm_way_id: SYNTHETIC_OSM_WAY_ID, raw_data::Building {
parking: None, polygon: Polygon::rectangle(center, BUILDING_LENGTH, BUILDING_LENGTH),
}); osm_tags: BTreeMap::new(),
osm_way_id: SYNTHETIC_OSM_WAY_ID,
parking: None,
},
);
self.bldg_added(id, prerender); self.bldg_added(id, prerender);
} }
pub fn move_b(&mut self, id: BuildingID, new_center: Pt2D, prerender: &Prerender) { pub fn move_b(&mut self, id: StableBuildingID, new_center: Pt2D, prerender: &Prerender) {
self.world.delete(ID::Building(id)); self.world.delete(ID::Building(id));
let b = &mut self.map.buildings[id]; let b = self.map.buildings.get_mut(&id).unwrap();
let old_center = b.polygon.center(); let old_center = b.polygon.center();
b.polygon = b.polygon.translate( b.polygon = b.polygon.translate(
Distance::meters(new_center.x() - old_center.x()), Distance::meters(new_center.x() - old_center.x()),
@ -530,30 +537,33 @@ impl Model {
self.bldg_added(id, prerender); self.bldg_added(id, prerender);
} }
pub fn set_b_label(&mut self, id: BuildingID, label: String, prerender: &Prerender) { pub fn set_b_label(&mut self, id: StableBuildingID, label: String, prerender: &Prerender) {
self.world.delete(ID::Building(id)); self.world.delete(ID::Building(id));
self.map.buildings[id] self.map
.buildings
.get_mut(&id)
.unwrap()
.osm_tags .osm_tags
.insert("abst:label".to_string(), label); .insert("abst:label".to_string(), label);
self.bldg_added(id, prerender); self.bldg_added(id, prerender);
} }
pub fn get_b_label(&self, id: BuildingID) -> Option<String> { pub fn get_b_label(&self, id: StableBuildingID) -> Option<String> {
self.map.buildings[id].osm_tags.get("abst:label").cloned() self.map.buildings[&id].osm_tags.get("abst:label").cloned()
} }
pub fn delete_b(&mut self, id: BuildingID) { pub fn delete_b(&mut self, id: StableBuildingID) {
self.world.delete(ID::Building(id)); self.world.delete(ID::Building(id));
self.map.buildings.remove(id); self.map.buildings.remove(&id);
} }
} }
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)] #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
pub enum ID { pub enum ID {
Building(BuildingID), Building(StableBuildingID),
Intersection(StableIntersectionID), Intersection(StableIntersectionID),
Lane(StableRoadID, Direction, usize), Lane(StableRoadID, Direction, usize),
} }