mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-25 23:43:25 +03:00
match offstreet parking KML to buildings
This commit is contained in:
parent
8aee410046
commit
1936f5f75e
@ -5,9 +5,9 @@ mod remove_disconnected;
|
||||
mod split_ways;
|
||||
|
||||
use abstutil::Timer;
|
||||
use geom::{FindClosest, GPSBounds, LonLat, PolyLine, Pt2D};
|
||||
use geom::{Distance, FindClosest, GPSBounds, LonLat, PolyLine, Polygon, Pt2D};
|
||||
use kml::ExtraShapes;
|
||||
use map_model::{raw_data, LANE_THICKNESS};
|
||||
use map_model::{raw_data, OffstreetParking, LANE_THICKNESS};
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader};
|
||||
use structopt::StructOpt;
|
||||
@ -23,6 +23,10 @@ pub struct Flags {
|
||||
#[structopt(long = "parking_shapes", default_value = "")]
|
||||
pub parking_shapes: String,
|
||||
|
||||
/// KML file with offstreet parking info. Optional.
|
||||
#[structopt(long = "offstreet_parking", default_value = "")]
|
||||
pub offstreet_parking: String,
|
||||
|
||||
/// GTFS directory. Optional.
|
||||
#[structopt(long = "gtfs", default_value = "")]
|
||||
pub gtfs: String,
|
||||
@ -67,6 +71,9 @@ pub fn convert(flags: &Flags, timer: &mut abstutil::Timer) -> raw_data::Map {
|
||||
if !flags.parking_shapes.is_empty() {
|
||||
use_parking_hints(&mut map, &flags.parking_shapes, timer);
|
||||
}
|
||||
if !flags.offstreet_parking.is_empty() {
|
||||
use_offstreet_parking(&mut map, &flags.offstreet_parking, timer);
|
||||
}
|
||||
if !flags.gtfs.is_empty() {
|
||||
timer.start("load GTFS");
|
||||
map.bus_routes = gtfs::load(&flags.gtfs).unwrap();
|
||||
@ -155,3 +162,40 @@ fn read_osmosis_polygon(path: &str) -> Vec<LonLat> {
|
||||
}
|
||||
pts
|
||||
}
|
||||
|
||||
fn use_offstreet_parking(map: &mut raw_data::Map, path: &str, timer: &mut Timer) {
|
||||
timer.start("match offstreet parking points");
|
||||
let shapes = kml::load(path, &map.gps_bounds, timer).expect("loading offstreet_parking failed");
|
||||
|
||||
// Building indices
|
||||
let mut closest: FindClosest<usize> = FindClosest::new(&map.gps_bounds.to_bounds());
|
||||
for (idx, b) in map.buildings.iter().enumerate() {
|
||||
let mut pts = map.gps_bounds.must_convert(&b.points);
|
||||
// Close off the polygon
|
||||
pts.push(pts[0]);
|
||||
closest.add(idx, &pts);
|
||||
}
|
||||
|
||||
// TODO Another function just to use ?. Try blocks would rock.
|
||||
let mut handle_shape: Box<dyn FnMut(kml::ExtraShape) -> Option<()>> = Box::new(|s| {
|
||||
assert_eq!(s.points.len(), 1);
|
||||
let pt = Pt2D::from_gps(s.points[0], &map.gps_bounds)?;
|
||||
let (idx, _) = closest.closest_pt(pt, Distance::meters(50.0))?;
|
||||
// TODO If we ditched LonLat up-front, things like this would be much easier.
|
||||
let poly = Polygon::new(&map.gps_bounds.must_convert(&map.buildings[idx].points));
|
||||
// TODO Handle parking lots.
|
||||
if !poly.contains_pt(pt) {
|
||||
return None;
|
||||
}
|
||||
let name = s.attributes.get("DEA_FACILITY_NAME")?.to_string();
|
||||
let num_stalls = s.attributes.get("DEA_STALLS")?.parse::<usize>().ok()?;
|
||||
assert_eq!(map.buildings[idx].parking, None);
|
||||
map.buildings[idx].parking = Some(OffstreetParking { name, num_stalls });
|
||||
None
|
||||
});
|
||||
|
||||
for s in shapes.shapes.into_iter() {
|
||||
handle_shape(s);
|
||||
}
|
||||
timer.stop("match offstreet parking points");
|
||||
}
|
||||
|
@ -79,6 +79,7 @@ pub fn osm_to_raw_roads(
|
||||
osm_way_id: way.id,
|
||||
points: pts,
|
||||
osm_tags: tags,
|
||||
parking: None,
|
||||
});
|
||||
} else if let Some(at) = get_area_type(&tags) {
|
||||
areas.push(raw_data::Area {
|
||||
|
@ -47,7 +47,8 @@ for some portion of Seattle. Each map has these objects:
|
||||
distinguish crosswalks at each end of a sidewalk.)
|
||||
- **Buildings**: A building has a position, OSM metadata, and a **front path**
|
||||
connecting the edge of the building to the nearest sidewalk. Most trips in A/B
|
||||
Street begin and end at buildings.
|
||||
Street begin and end at buildings. Some buildings also contain a number of
|
||||
off-street parking spots.
|
||||
- **Area**: An area has geometry and OSM metadata and represents a body of
|
||||
water, forest, park, etc. They're just used for drawing.
|
||||
- **Bus stop**: A bus stop is placed some distance along a sidewalk, with a
|
||||
@ -130,6 +131,9 @@ it only takes a few seconds to load a serialized map.
|
||||
- `lib.rs`: Apply parking hints from a King County GIS blockface dataset
|
||||
- Match each blockface to the nearest edge of a road
|
||||
- Interpret the metadata to assign on-street parking there or not
|
||||
- `lib.rs`: Apply offstreet parking hints from a King County GIS dataset
|
||||
- Match each point to the building containing it, plumbing through the number
|
||||
of spots
|
||||
- `lib.rs` using the `gtfs` crate: Load bus route info from GTFS
|
||||
- `neighborhoods.rs`: Load neighborhood polygons from an extra geojson file
|
||||
- If the polygon isn't completely in-bounds, just remove it
|
||||
|
@ -112,9 +112,16 @@ impl CommonState {
|
||||
osd.append(map.get_parent(*l).get_name(), Some(name_color));
|
||||
}
|
||||
Some(ID::Building(b)) => {
|
||||
let bldg = map.get_b(*b);
|
||||
osd.append(format!("{}", b), Some(id_color));
|
||||
osd.append(" is ".to_string(), None);
|
||||
osd.append(map.get_b(*b).get_name(), Some(name_color));
|
||||
osd.append(bldg.get_name(), Some(name_color));
|
||||
if let Some(ref p) = bldg.parking {
|
||||
osd.append(
|
||||
format!(" ({} parking spots via {})", p.num_stalls, p.name),
|
||||
None,
|
||||
);
|
||||
}
|
||||
}
|
||||
Some(ID::Turn(t)) => {
|
||||
osd.append(
|
||||
|
@ -95,10 +95,11 @@ for poly in `ls ../data/polygons/`; do
|
||||
RUST_BACKTRACE=1 cargo run --release -- \
|
||||
--osm=../data/input/$name.osm \
|
||||
--parking_shapes=../data/shapes/blockface.bin \
|
||||
--offstreet_parking=../data/input/offstreet_parking.kml \
|
||||
--gtfs=../data/input/google_transit_2018_18_08 \
|
||||
--neighborhoods=../data/input/neighborhoods.geojson \
|
||||
--clip=../data/polygons/$name.poly \
|
||||
--output=../data/raw_maps/$name.bin
|
||||
done
|
||||
|
||||
# To run manually: cargo run -- --osm=../data/input/montlake.osm --parking_shapes=../data/shapes/blockface.bin --gtfs=../data/input/google_transit_2018_18_08 --neighborhoods=../data/input/neighborhoods.geojson --clip=../data/polygons/montlake.poly --output=../data/raw_maps/montlake.bin --fast_dev
|
||||
# To run manually: cargo run -- --osm=../data/input/montlake.osm --parking_shapes=../data/shapes/blockface.bin --offstreet_parking=../data/input/offstreet_parking.kml --gtfs=../data/input/google_transit_2018_18_08 --neighborhoods=../data/input/neighborhoods.geojson --clip=../data/polygons/montlake.poly --output=../data/raw_maps/montlake.bin --fast_dev
|
||||
|
@ -23,6 +23,12 @@ pub struct FrontPath {
|
||||
pub line: Line,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||
pub struct OffstreetParking {
|
||||
pub name: String,
|
||||
pub num_stalls: usize,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Building {
|
||||
pub id: BuildingID,
|
||||
@ -34,6 +40,7 @@ pub struct Building {
|
||||
pub label_center: Pt2D,
|
||||
|
||||
pub front_path: FrontPath,
|
||||
pub parking: Option<OffstreetParking>,
|
||||
}
|
||||
|
||||
impl Building {
|
||||
|
@ -16,7 +16,7 @@ mod traversable;
|
||||
mod turn;
|
||||
|
||||
pub use crate::area::{Area, AreaID, AreaType};
|
||||
pub use crate::building::{Building, BuildingID, FrontPath};
|
||||
pub use crate::building::{Building, BuildingID, FrontPath, OffstreetParking};
|
||||
pub use crate::bus_stop::{BusRoute, BusRouteID, BusStop, BusStopID};
|
||||
pub use crate::edits::MapEdits;
|
||||
pub use crate::intersection::{Intersection, IntersectionID, IntersectionType};
|
||||
|
@ -54,6 +54,7 @@ pub fn make_all_buildings(
|
||||
sidewalk: *sidewalk_pos,
|
||||
line,
|
||||
},
|
||||
parking: input[idx].parking.clone(),
|
||||
label_center: Polygon::polylabel(&points),
|
||||
});
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::make::get_lane_types;
|
||||
pub use crate::make::{Hint, Hints, InitialMap};
|
||||
use crate::{AreaType, IntersectionType, RoadSpec};
|
||||
use crate::{AreaType, IntersectionType, OffstreetParking, RoadSpec};
|
||||
use geom::{GPSBounds, LonLat};
|
||||
use gtfs::Route;
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
@ -164,6 +164,7 @@ pub struct Building {
|
||||
pub points: Vec<LonLat>,
|
||||
pub osm_tags: BTreeMap<String, String>,
|
||||
pub osm_way_id: i64,
|
||||
pub parking: Option<OffstreetParking>,
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize)]
|
||||
|
@ -363,6 +363,7 @@ impl Model {
|
||||
points: b.polygon().points().iter().map(|p| pt(*p)).collect(),
|
||||
osm_tags,
|
||||
osm_way_id: idx as i64,
|
||||
parking: None,
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -8,6 +8,7 @@ pub fn run(t: &mut TestRunner) {
|
||||
let flags = convert_osm::Flags {
|
||||
osm: "../data/input/montlake.osm".to_string(),
|
||||
parking_shapes: "../data/shapes/blockface.bin".to_string(),
|
||||
offstreet_parking: "../data/input/offstreet_parking.kml".to_string(),
|
||||
gtfs: "../data/input/google_transit_2018_18_08".to_string(),
|
||||
neighborhoods: "../data/input/neighborhoods.geojson".to_string(),
|
||||
clip: abstutil::path_polygon("montlake"),
|
||||
|
Loading…
Reference in New Issue
Block a user