mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-26 07:52:05 +03:00
stable IDs for buildings in raw layer too. stop futzing with ID problems there.
This commit is contained in:
parent
33ab7d4553
commit
eee5981c14
@ -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()
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
@ -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.
|
||||||
|
@ -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(),
|
||||||
|
@ -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),
|
||||||
|
@ -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),
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user