From 3639379313c612294d6b1119a590ecabda976e2e Mon Sep 17 00:00:00 2001 From: Dustin Carlino Date: Thu, 9 Jul 2020 15:14:08 -0700 Subject: [PATCH] importer option to assume onstreet parking on some residential roads, if OSM doesnt say anything. give 50% of residential roads in krakow some parking. fixes #171 also clean up the seattle sidewalks dataset for now; the matching code is quite bad, and not planning to use this anytime soon --- convert_osm/src/lib.rs | 155 ++++++++++++++++------------------------ data/MANIFEST.txt | 6 +- importer/src/austin.rs | 10 +-- importer/src/krakow.rs | 10 +-- importer/src/main.rs | 10 +-- importer/src/seattle.rs | 28 ++++---- updater/src/main.rs | 2 +- 7 files changed, 92 insertions(+), 129 deletions(-) diff --git a/convert_osm/src/lib.rs b/convert_osm/src/lib.rs index 6098caaee1..3cc325d1b4 100644 --- a/convert_osm/src/lib.rs +++ b/convert_osm/src/lib.rs @@ -17,13 +17,41 @@ pub struct Options { pub city_name: String, pub name: String, - pub parking_shapes: Option, - pub public_offstreet_parking: Option, - pub private_offstreet_parking: PrivateOffstreetParking, - pub sidewalks: Option, - pub elevation: Option, + // The path to an osmosis boundary polygon. Highly recommended. pub clip: Option, pub drive_on_right: bool, + + pub onstreet_parking: OnstreetParking, + pub public_offstreet_parking: PublicOffstreetParking, + pub private_offstreet_parking: PrivateOffstreetParking, + // If provided, pull elevation data from this SRTM file. The SRTM parser is incorrect, so the + // results will be nonsense. + pub elevation: Option, +} + +// What roads will have on-street parking lanes? Data from +// https://wiki.openstreetmap.org/wiki/Key:parking:lane is always used if available. +pub enum OnstreetParking { + // If not tagged, there won't be parking. + JustOSM, + // If OSM data is missing, then try to match data from + // http://data-seattlecitygis.opendata.arcgis.com/datasets/blockface. This is Seattle specific. + Blockface(String), + // If OSM data is missing, then infer parking lanes on some percentage of + // "highway=residential" roads. + SomeResidential { + // [0, 100] + pct: usize, + }, +} + +// How many spots are available in public parking garages? +pub enum PublicOffstreetParking { + None, + // Pull data from + // https://data-seattlecitygis.opendata.arcgis.com/datasets/public-garages-or-parking-lots, a + // Seattle-specific data source. + GIS(String), } // If a building doesn't have anything from public_offstreet_parking, how many private spots should @@ -57,16 +85,37 @@ pub fn convert(opts: Options, timer: &mut abstutil::Timer) -> RawMap { use_amenities(&mut map, amenities, timer); - if let Some(ref path) = opts.parking_shapes { - use_parking_hints(&mut map, path.clone(), timer); + match opts.onstreet_parking { + OnstreetParking::JustOSM => {} + OnstreetParking::Blockface(ref path) => { + use_parking_hints(&mut map, path.clone(), timer); + } + OnstreetParking::SomeResidential { pct } => { + let pct = pct as i64; + for (id, r) in map.roads.iter_mut() { + if r.osm_tags.contains_key(osm::INFERRED_PARKING) + && r.osm_tags.get(osm::HIGHWAY) == Some(&"residential".to_string()) + && id.osm_way_id % 100 <= pct + { + if r.osm_tags.get("oneway") == Some(&"yes".to_string()) { + r.osm_tags.remove(osm::PARKING_BOTH); + r.osm_tags + .insert(osm::PARKING_RIGHT.to_string(), "parallel".to_string()); + } else { + r.osm_tags + .insert(osm::PARKING_BOTH.to_string(), "parallel".to_string()); + } + } + } + } } - if let Some(ref path) = opts.public_offstreet_parking { - use_offstreet_parking(&mut map, path.clone(), timer); + match opts.public_offstreet_parking { + PublicOffstreetParking::None => {} + PublicOffstreetParking::GIS(ref path) => { + use_offstreet_parking(&mut map, path.clone(), timer); + } } apply_private_offstreet_parking(&mut map, opts.private_offstreet_parking); - if let Some(ref path) = opts.sidewalks { - use_sidewalk_hints(&mut map, path.clone(), timer); - } if let Some(ref path) = opts.elevation { use_elevation(&mut map, path, timer); } @@ -237,88 +286,6 @@ fn apply_private_offstreet_parking(map: &mut RawMap, policy: PrivateOffstreetPar } } -fn use_sidewalk_hints(map: &mut RawMap, path: String, timer: &mut Timer) { - timer.start("apply sidewalk hints"); - let shapes: ExtraShapes = abstutil::read_binary(path, timer); - - // Match shapes with the nearest road + direction (true for forwards) - let mut closest: FindClosest<(OriginalRoad, bool)> = - FindClosest::new(&map.gps_bounds.to_bounds()); - for (id, r) in &map.roads { - if r.is_light_rail() { - continue; - } - let center = PolyLine::new(r.center_points.clone()); - closest.add( - (*id, true), - map.driving_side - .right_shift(center.clone(), DIRECTED_ROAD_THICKNESS) - .get(timer) - .points(), - ); - closest.add( - (*id, false), - map.driving_side - .left_shift(center, DIRECTED_ROAD_THICKNESS) - .get(timer) - .points(), - ); - } - - for s in shapes.shapes.into_iter() { - let pts = if let Some(pts) = map.gps_bounds.try_convert(&s.points) { - pts - } else { - continue; - }; - if pts.len() <= 1 { - continue; - } - // The endpoints will be close to other roads, so match based on the middle of the - // blockface. - // TODO Long lines sometimes cover two roads. Should maybe find ALL matches within the - // threshold distance? - if let Some(middle) = PolyLine::maybe_new(pts).map(|pl| pl.middle()) { - if let Some(((r, fwds), _)) = closest.closest_pt(middle, DIRECTED_ROAD_THICKNESS * 5.0) - { - let osm_tags = &mut map.roads.get_mut(&r).unwrap().osm_tags; - - // Skip if the road already has this mapped. - if !osm_tags.contains_key(osm::INFERRED_SIDEWALKS) { - continue; - } - - let definitely_no_sidewalks = match osm_tags.get(osm::HIGHWAY) { - Some(hwy) => hwy == "motorway" || hwy == "motorway_link", - None => false, - }; - if definitely_no_sidewalks { - timer.warn(format!( - "Sidewalks shapefile says there's something along motorway {}, ignoring", - r - )); - continue; - } - - if fwds { - if osm_tags.get(osm::SIDEWALK) == Some(&"left".to_string()) { - osm_tags.insert(osm::SIDEWALK.to_string(), "both".to_string()); - } else { - osm_tags.insert(osm::SIDEWALK.to_string(), "right".to_string()); - } - } else { - if osm_tags.get(osm::SIDEWALK) == Some(&"right".to_string()) { - osm_tags.insert(osm::SIDEWALK.to_string(), "both".to_string()); - } else { - osm_tags.insert(osm::SIDEWALK.to_string(), "left".to_string()); - } - } - } - } - } - timer.stop("apply sidewalk hints"); -} - fn use_amenities(map: &mut RawMap, amenities: Vec<(Pt2D, String, String)>, timer: &mut Timer) { let mut closest: FindClosest = FindClosest::new(&map.gps_bounds.to_bounds()); for (id, b) in &map.buildings { diff --git a/data/MANIFEST.txt b/data/MANIFEST.txt index da1e1057db..f9aaccee63 100644 --- a/data/MANIFEST.txt +++ b/data/MANIFEST.txt @@ -7,7 +7,7 @@ data/input/raw_maps/ballard.bin,eeb376efa9a87e3a7f8cea5a0a1795c2,https://www.dro data/input/raw_maps/downtown.bin,4560307f46e64e2b4495494a4406e458,https://www.dropbox.com/s/20zw8valbf35tci/downtown.bin.zip?dl=0 data/input/raw_maps/downtown_atx.bin,cf2cd0fea92b70e5555ac693b2d4a653,https://www.dropbox.com/s/02moxvh1gn41x5s/downtown_atx.bin.zip?dl=0 data/input/raw_maps/huge_austin.bin,d37364ac2da4e9d44de886457ba915ed,https://www.dropbox.com/s/updgay4ia9dsbot/huge_austin.bin.zip?dl=0 -data/input/raw_maps/huge_krakow.bin,1324c55f870307b5b8e77ff37a66ef7b,https://www.dropbox.com/s/8l6dyjca08rejhf/huge_krakow.bin.zip?dl=0 +data/input/raw_maps/huge_krakow.bin,ce8340583a51ac371084455717ab5926,https://www.dropbox.com/s/jpi5fewb4fex3ej/huge_krakow.bin.zip?dl=0 data/input/raw_maps/huge_seattle.bin,5c06f78dd172f5717895283ac1ea0f65,https://www.dropbox.com/s/mst2n74jqjknyv5/huge_seattle.bin.zip?dl=0 data/input/raw_maps/lakeslice.bin,f3b6e1820abf31f77d30a8cce3963f0d,https://www.dropbox.com/s/6jz3aisto2rhsjj/lakeslice.bin.zip?dl=0 data/input/raw_maps/montlake.bin,749507726d6acc94fbde892bf78bd137,https://www.dropbox.com/s/q7w9lwitdrv3ln2/montlake.bin.zip?dl=0 @@ -35,15 +35,13 @@ data/input/seattle/osm/west_seattle.osm,ce708f4701cd9118c2e9de0573e69457,https:/ data/input/seattle/parcels.bin,5fd9e42c47827328a067a43b83686a1a,https://www.dropbox.com/s/4lql4s0fo3n5smf/parcels.bin.zip?dl=0 data/input/seattle/parcels_urbansim.txt,db63d7d606e8702d12f9399e87e6a00f,https://www.dropbox.com/s/6g8rbsf200dssj3/parcels_urbansim.txt.zip?dl=0 data/input/seattle/popdat.bin,b607f9990528d0ca2fbeec9f02a5755e,https://www.dropbox.com/s/hcf80kvl66a4yai/popdat.bin.zip?dl=0 -data/input/seattle/sidewalks.bin,034dd47ab77902dbc81c0107f13d8965,https://www.dropbox.com/s/ma9bmisijc7v7xa/sidewalks.bin.zip?dl=0 -data/input/seattle/sidewalks.kml,94d385ba03ef1b57a5ba10965913ec6c,https://www.dropbox.com/s/vn8amar9xi6vbvh/sidewalks.kml.zip?dl=0 data/input/seattle/trips_2014.csv,d4a8e733045b28c0385fb81359d6df03,https://www.dropbox.com/s/5ppravwmk6bf20d/trips_2014.csv.zip?dl=0 data/system/cities/seattle.bin,d8e88217584d6ece7abaf1ec4222c7e6,https://www.dropbox.com/s/s1i208j6oy5pd5o/seattle.bin.zip?dl=0 data/system/maps/ballard.bin,3ee77b40b60ce5f95e80251956ca823a,https://www.dropbox.com/s/6f3nlghhqhrf8e4/ballard.bin.zip?dl=0 data/system/maps/downtown.bin,e2e739e380416cae1b733704be5b2dc2,https://www.dropbox.com/s/b8vso3pfevmdm5f/downtown.bin.zip?dl=0 data/system/maps/downtown_atx.bin,a76df031940aa3f5d9f680fa82846f26,https://www.dropbox.com/s/umfhjtr0mw058l2/downtown_atx.bin.zip?dl=0 data/system/maps/huge_austin.bin,87be99eeaa1b1c6d9d074a23df872240,https://www.dropbox.com/s/g25smuci2uta2h2/huge_austin.bin.zip?dl=0 -data/system/maps/huge_krakow.bin,0d97a27aa4afbaba3f9e71c6a3f1286d,https://www.dropbox.com/s/ya9cvv3ydm3d27s/huge_krakow.bin.zip?dl=0 +data/system/maps/huge_krakow.bin,1f7d1f91ec180499edcd629148975332,https://www.dropbox.com/s/h78wsd9071bkz73/huge_krakow.bin.zip?dl=0 data/system/maps/huge_seattle.bin,767b051c74b6c3a07aba02e0d540afbe,https://www.dropbox.com/s/rod1ohltfkkfh9f/huge_seattle.bin.zip?dl=0 data/system/maps/lakeslice.bin,c89ec7b553f609e6ededfd3a60571126,https://www.dropbox.com/s/bpjsehxrzh82at9/lakeslice.bin.zip?dl=0 data/system/maps/montlake.bin,50c92ff0b5bca1f86432cdfbd220c035,https://www.dropbox.com/s/4xd14op12txfi8h/montlake.bin.zip?dl=0 diff --git a/importer/src/austin.rs b/importer/src/austin.rs index a1b41b84ef..394da494c5 100644 --- a/importer/src/austin.rs +++ b/importer/src/austin.rs @@ -22,16 +22,16 @@ pub fn osm_to_raw(name: &str) { city_name: "austin".to_string(), name: name.to_string(), - parking_shapes: None, - public_offstreet_parking: None, - private_offstreet_parking: convert_osm::PrivateOffstreetParking::FixedPerBldg(1), - sidewalks: None, - elevation: None, clip: Some(abstutil::path(format!( "input/austin/polygons/{}.poly", name ))), drive_on_right: true, + + onstreet_parking: convert_osm::OnstreetParking::JustOSM, + public_offstreet_parking: convert_osm::PublicOffstreetParking::None, + private_offstreet_parking: convert_osm::PrivateOffstreetParking::FixedPerBldg(1), + elevation: None, }, &mut abstutil::Timer::throwaway(), ); diff --git a/importer/src/krakow.rs b/importer/src/krakow.rs index 38dc2e776f..2824ddbb8e 100644 --- a/importer/src/krakow.rs +++ b/importer/src/krakow.rs @@ -22,16 +22,16 @@ pub fn osm_to_raw(name: &str) { city_name: "krakow".to_string(), name: name.to_string(), - parking_shapes: None, - public_offstreet_parking: None, - private_offstreet_parking: convert_osm::PrivateOffstreetParking::FixedPerBldg(1), - sidewalks: None, - elevation: None, clip: Some(abstutil::path(format!( "input/krakow/polygons/{}.poly", name ))), drive_on_right: true, + + onstreet_parking: convert_osm::OnstreetParking::SomeResidential { pct: 50 }, + public_offstreet_parking: convert_osm::PublicOffstreetParking::None, + private_offstreet_parking: convert_osm::PrivateOffstreetParking::FixedPerBldg(1), + elevation: None, }, &mut abstutil::Timer::throwaway(), ); diff --git a/importer/src/main.rs b/importer/src/main.rs index 851e04185e..47465f58b7 100644 --- a/importer/src/main.rs +++ b/importer/src/main.rs @@ -161,13 +161,13 @@ fn oneshot(osm_path: String, clip: Option, drive_on_right: bool) { city_name: "oneshot".to_string(), name: name.clone(), - parking_shapes: None, - public_offstreet_parking: None, - private_offstreet_parking: convert_osm::PrivateOffstreetParking::FixedPerBldg(1), - sidewalks: None, - elevation: None, clip, drive_on_right, + + onstreet_parking: convert_osm::OnstreetParking::JustOSM, + public_offstreet_parking: convert_osm::PublicOffstreetParking::None, + private_offstreet_parking: convert_osm::PrivateOffstreetParking::FixedPerBldg(1), + elevation: None, }, &mut timer, ); diff --git a/importer/src/seattle.rs b/importer/src/seattle.rs index c314efacd7..e5324104bf 100644 --- a/importer/src/seattle.rs +++ b/importer/src/seattle.rs @@ -22,12 +22,7 @@ fn input() { "input/seattle/blockface.bin", "https://opendata.arcgis.com/datasets/a1458ad1abca41869b81f7c0db0cd777_0.kml", ); - // From https://data-seattlecitygis.opendata.arcgis.com/datasets/sidewalks - download( - "input/seattle/sidewalks.bin", - "https://opendata.arcgis.com/datasets/ee6d0642d2a04e35892d0eab77d971d6_2.kml", - ); - // From https://data.seattle.gov/Transportation/Public-Garages-or-Parking-Lots/xefx-khzm + // From https://data-seattlecitygis.opendata.arcgis.com/datasets/public-garages-or-parking-lots download("input/seattle/offstreet_parking.bin", "http://data-seattlecitygis.opendata.arcgis.com/datasets/8e52dfde6d5d45948f7a90654c8d50cd_0.kml"); } @@ -46,8 +41,18 @@ pub fn osm_to_raw(name: &str) { city_name: "seattle".to_string(), name: name.to_string(), - parking_shapes: Some(abstutil::path("input/seattle/blockface.bin")), - public_offstreet_parking: Some(abstutil::path("input/seattle/offstreet_parking.bin")), + clip: Some(abstutil::path(format!( + "input/seattle/polygons/{}.poly", + name + ))), + drive_on_right: true, + + onstreet_parking: convert_osm::OnstreetParking::Blockface(abstutil::path( + "input/seattle/blockface.bin", + )), + public_offstreet_parking: convert_osm::PublicOffstreetParking::GIS(abstutil::path( + "input/seattle/offstreet_parking.bin", + )), private_offstreet_parking: convert_osm::PrivateOffstreetParking::FixedPerBldg( // TODO Utter guesses match name { @@ -57,14 +62,7 @@ pub fn osm_to_raw(name: &str) { _ => 1, }, ), - // TODO These're buggy. - sidewalks: None, elevation: Some(abstutil::path("input/seattle/N47W122.hgt")), - clip: Some(abstutil::path(format!( - "input/seattle/polygons/{}.poly", - name - ))), - drive_on_right: true, }, &mut abstutil::Timer::throwaway(), ); diff --git a/updater/src/main.rs b/updater/src/main.rs index ccb95e8128..cd7d38f2c0 100644 --- a/updater/src/main.rs +++ b/updater/src/main.rs @@ -266,7 +266,7 @@ impl Manifest { "huge_seattle" => map == "huge_seattle", "austin" => map == "downtown_atx" || map == "huge_austin", "krakow" => map == "huge_krakow", - _ => panic!("Unknown city {}", city), + _ => panic!("Unknown city {}. Check your data/config", city), } }