diff --git a/convert_osm/src/lib.rs b/convert_osm/src/lib.rs index f93901573b..8cdfe8ca85 100644 --- a/convert_osm/src/lib.rs +++ b/convert_osm/src/lib.rs @@ -3,7 +3,7 @@ mod neighborhoods; mod osm_reader; mod split_ways; -use abstutil::{prettyprint_usize, Timer}; +use abstutil::Timer; use geom::{Distance, FindClosest, Line, PolyLine, Pt2D}; use kml::ExtraShapes; use map_model::raw::{RawMap, StableBuildingID, StableRoadID}; @@ -13,7 +13,6 @@ use std::collections::BTreeMap; pub struct Flags { pub osm: String, pub parking_shapes: Option, - pub street_signs: Option, pub offstreet_parking: Option, pub gtfs: Option, pub neighborhoods: Option, @@ -36,9 +35,6 @@ pub fn convert(flags: &Flags, timer: &mut abstutil::Timer) -> RawMap { if let Some(ref path) = flags.parking_shapes { use_parking_hints(&mut map, path, timer); } - if let Some(ref path) = flags.street_signs { - use_street_signs(&mut map, path, timer); - } if let Some(ref path) = flags.offstreet_parking { use_offstreet_parking(&mut map, path, timer); } @@ -112,109 +108,59 @@ fn use_parking_hints(map: &mut RawMap, path: &str, timer: &mut Timer) { } else { continue; }; - if pts.len() > 1 { - // The blockface line endpoints will be close to other roads, so match based on the - // middle of the blockface. - // TODO Long blockfaces sometimes cover two roads. Should maybe find ALL matches within - // the threshold distance? - let middle = PolyLine::new(pts).middle(); - if let Some(((r, fwds), _)) = closest.closest_pt(middle, LANE_THICKNESS * 5.0) { - // Skip if the road already has this mapped. - if !map.roads[&r].osm_tags.contains_key(osm::INFERRED_PARKING) { - continue; - } - - let category = s.attributes.get("PARKING_CATEGORY"); - let has_parking = category != Some(&"None".to_string()) - && category != Some(&"No Parking Allowed".to_string()); - // Blindly override prior values. - map.roads.get_mut(&r).unwrap().osm_tags.insert( - if fwds { - osm::PARKING_RIGHT.to_string() - } else { - osm::PARKING_LEFT.to_string() - }, - if has_parking { - "parallel".to_string() - } else { - "no_parking".to_string() - }, - ); - map.roads - .get_mut(&r) - .unwrap() - .osm_tags - .remove(osm::PARKING_BOTH); + if pts.len() <= 1 { + continue; + } + // The blockface line endpoints will be close to other roads, so match based on the + // middle of the blockface. + // TODO Long blockfaces sometimes cover two roads. Should maybe find ALL matches within + // the threshold distance? + let middle = PolyLine::new(pts).middle(); + if let Some(((r, fwds), _)) = closest.closest_pt(middle, LANE_THICKNESS * 5.0) { + // Skip if the road already has this mapped. + if !map.roads[&r].osm_tags.contains_key(osm::INFERRED_PARKING) { + continue; } + + let category = s.attributes.get("PARKING_CATEGORY"); + let has_parking = category != Some(&"None".to_string()) + && category != Some(&"No Parking Allowed".to_string()); + + let definitely_no_parking = match map.roads[&r].osm_tags.get(osm::HIGHWAY) { + Some(hwy) => hwy == "motorway" || hwy == "motorway_link", + None => false, + }; + if has_parking && definitely_no_parking { + timer.warn(format!( + "Blockface says there's parking along motorway {}, ignoring", + r + )); + continue; + } + + // Blindly override prior values. + map.roads.get_mut(&r).unwrap().osm_tags.insert( + if fwds { + osm::PARKING_RIGHT.to_string() + } else { + osm::PARKING_LEFT.to_string() + }, + if has_parking { + "parallel".to_string() + } else { + "no_parking".to_string() + }, + ); + map.roads + .get_mut(&r) + .unwrap() + .osm_tags + .remove(osm::PARKING_BOTH); } } timer.stop("apply parking hints"); } -fn use_street_signs(map: &mut RawMap, path: &str, timer: &mut Timer) { - timer.start("apply street signs to override parking hints"); - let shapes: ExtraShapes = - abstutil::read_binary(path, timer).expect("loading street_signs failed"); - - // Match shapes with the nearest road + direction (true for forwards) - let mut closest: FindClosest<(StableRoadID, bool)> = - FindClosest::new(&map.gps_bounds.to_bounds()); - for (id, r) in &map.roads { - let center = PolyLine::new(r.center_points.clone()); - closest.add( - (*id, true), - center.shift_right(LANE_THICKNESS).get(timer).points(), - ); - closest.add( - (*id, false), - center.shift_left(LANE_THICKNESS).get(timer).points(), - ); - } - - let mut applied = 0; - 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 { - if let Some(((r, fwds), _)) = closest.closest_pt(pts[0], LANE_THICKNESS * 5.0) { - // Skip if the road already has this mapped. - if !map.roads[&r].osm_tags.contains_key(osm::INFERRED_PARKING) { - continue; - } - - // TODO Model RPZ, paid on-street spots, limited times, etc. - let no_parking = - s.attributes.get("TEXT") == Some(&"NO PARKING ANYTIME".to_string()); - if no_parking { - applied += 1; - map.roads.get_mut(&r).unwrap().osm_tags.insert( - if fwds { - osm::PARKING_RIGHT - } else { - osm::PARKING_LEFT - } - .to_string(), - "no_parking".to_string(), - ); - map.roads - .get_mut(&r) - .unwrap() - .osm_tags - .remove(osm::PARKING_BOTH); - } - } - } - } - timer.note(format!( - "Applied {} street signs", - prettyprint_usize(applied) - )); - timer.stop("apply street signs to override parking hints"); -} - fn use_offstreet_parking(map: &mut RawMap, 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"); diff --git a/convert_osm/src/main.rs b/convert_osm/src/main.rs index 1f3c53ae69..a439552979 100644 --- a/convert_osm/src/main.rs +++ b/convert_osm/src/main.rs @@ -6,7 +6,6 @@ fn main() { let flags = Flags { osm: args.required("--osm"), parking_shapes: args.optional("--parking_shapes"), - street_signs: args.optional("--street_signs"), offstreet_parking: args.optional("--offstreet_parking"), gtfs: args.optional("--gtfs"), neighborhoods: args.optional("--neighborhoods"), diff --git a/data/screenshots/montlake/MANIFEST b/data/screenshots/montlake/MANIFEST index 362ad14bf2..63b15283ff 100644 --- a/data/screenshots/montlake/MANIFEST +++ b/data/screenshots/montlake/MANIFEST @@ -1,21 +1,21 @@ -e1a6e14f3b585a99d70f4d3d9afc97ea ../data/screenshots/pending_montlake/01x01_i53.png +e1a6e14f3b585a99d70f4d3d9afc97ea ../data/screenshots/pending_montlake/01x01_i52.png 0f008347ce29e2f80006699858f5b024 ../data/screenshots/pending_montlake/02x01_i1.png b3cf25e0c4382a7c91f8a12c5abfc023 ../data/screenshots/pending_montlake/03x01_i0.png f2c7083a2e0e2a6039f0ce3fc75823b0 ../data/screenshots/pending_montlake/01x02_i7.png -4bd77b889539e91216c39917610091fe ../data/screenshots/pending_montlake/02x02_i126.png -d8f709a41a307871389c3e05a3fa66ec ../data/screenshots/pending_montlake/03x02_i31.png -75c7bba069f59f245d05c79588891538 ../data/screenshots/pending_montlake/01x03_i97.png +1af3029a2c2c64af9568760ada59c9f5 ../data/screenshots/pending_montlake/02x02_i125.png +c4b0cf4d2389d9f1d4dbad1a3f95adce ../data/screenshots/pending_montlake/03x02_i30.png +75c7bba069f59f245d05c79588891538 ../data/screenshots/pending_montlake/01x03_i96.png 96a8b52e299032c187ff395bf96e3a54 ../data/screenshots/pending_montlake/02x03_i5.png -c25dd6296e4b034fa971909b028116eb ../data/screenshots/pending_montlake/03x03_i14.png +c25dd6296e4b034fa971909b028116eb ../data/screenshots/pending_montlake/03x03_i13.png 615e04c96503dc3a0eec27ae1b9e953e ../data/screenshots/pending_montlake/01x04_i3.png -515cbe5b6ad4545f5771dd7f9cee297e ../data/screenshots/pending_montlake/02x04_i27.png -24cfe9e237b59ba7ef61d7348bd6a683 ../data/screenshots/pending_montlake/03x04_i13.png -bb7b19d3ec9435ded8a5f00a2c4ad04d ../data/screenshots/pending_montlake/01x05_i42.png -81261d07f7af826511941b9b9019d08d ../data/screenshots/pending_montlake/02x05_i41.png -20744688172dfca19683a621438b6825 ../data/screenshots/pending_montlake/03x05_i21.png -cbd1dc516addd9cff0434a1a39773e8c ../data/screenshots/pending_montlake/01x06_i11.png +515cbe5b6ad4545f5771dd7f9cee297e ../data/screenshots/pending_montlake/02x04_i26.png +24cfe9e237b59ba7ef61d7348bd6a683 ../data/screenshots/pending_montlake/03x04_i12.png +bb7b19d3ec9435ded8a5f00a2c4ad04d ../data/screenshots/pending_montlake/01x05_i41.png +81261d07f7af826511941b9b9019d08d ../data/screenshots/pending_montlake/02x05_i40.png +20744688172dfca19683a621438b6825 ../data/screenshots/pending_montlake/03x05_i20.png +96108b40fb32b44ab64cf569941e5faf ../data/screenshots/pending_montlake/01x06_i11.png d66a4f0e23bd6662201ddad433476e73 ../data/screenshots/pending_montlake/02x06_i9.png -75bb186a8bee1eae263a6085ee20a7ba ../data/screenshots/pending_montlake/03x06_i17.png -228d874db835c89248966a4eda679465 ../data/screenshots/pending_montlake/01x07_i104.png -ddbd185ea6e662c014be4b35b101a29c ../data/screenshots/pending_montlake/02x07_i19.png -50e1b4fb5206edbeed33c44a9c3f7765 ../data/screenshots/pending_montlake/03x07_i18.png +75bb186a8bee1eae263a6085ee20a7ba ../data/screenshots/pending_montlake/03x06_i16.png +228d874db835c89248966a4eda679465 ../data/screenshots/pending_montlake/01x07_i103.png +ddbd185ea6e662c014be4b35b101a29c ../data/screenshots/pending_montlake/02x07_i18.png +50e1b4fb5206edbeed33c44a9c3f7765 ../data/screenshots/pending_montlake/03x07_i17.png diff --git a/import.sh b/import.sh index c79dbb257c..50a024ab73 100755 --- a/import.sh +++ b/import.sh @@ -73,14 +73,14 @@ if [ ! -f data/shapes/blockface.bin ]; then cd .. fi -if [ ! -f data/shapes/street_signs.bin ]; then - # From http://data-seattlecitygis.opendata.arcgis.com/datasets/411a96b39c834a2380a256b8afa5003b_0 - get_if_needed https://opendata.arcgis.com/datasets/411a96b39c834a2380a256b8afa5003b_0.kml data/input/street_signs.kml; +if [ ! -f data/shapes/sidewalks.bin ]; then + # From https://data-seattlecitygis.opendata.arcgis.com/datasets/sidewalks + get_if_needed https://opendata.arcgis.com/datasets/ee6d0642d2a04e35892d0eab77d971d6_2.kml data/input/sidewalks.kml; cd kml time cargo run --release -- \ - --input=../data/input/street_signs.kml \ - --output=../data/shapes/street_signs.bin + --input=../data/input/sidewalks.kml \ + --output=../data/shapes/sidewalks.bin cd .. fi @@ -123,6 +123,4 @@ for poly in `ls ../data/polygons/`; do --neighborhoods=../data/input/neighborhoods.geojson \ --clip=../data/polygons/$name.poly \ --output=../data/raw_maps/$name.bin - # Disabled, because it removes lots of parking that's really there. - #--street_signs=../data/shapes/street_signs.bin \ done diff --git a/map_model/src/make/initial/lane_specs.rs b/map_model/src/make/initial/lane_specs.rs index c61f533390..1291b1c035 100644 --- a/map_model/src/make/initial/lane_specs.rs +++ b/map_model/src/make/initial/lane_specs.rs @@ -13,16 +13,6 @@ pub fn get_lane_types(osm_tags: &BTreeMap) -> (Vec, Ve } } - fn has_parking(value: Option<&String>) -> bool { - value == Some(&"parallel".to_string()) - || value == Some(&"diagonal".to_string()) - || value == Some(&"perpendicular".to_string()) - } - let parking_lane_fwd = has_parking(osm_tags.get(osm::PARKING_RIGHT)) - || has_parking(osm_tags.get(osm::PARKING_BOTH)); - let parking_lane_back = has_parking(osm_tags.get(osm::PARKING_LEFT)) - || has_parking(osm_tags.get(osm::PARKING_BOTH)); - // Easy special cases first. if osm_tags.get("junction") == Some(&"roundabout".to_string()) { return (vec![LaneType::Driving, LaneType::Sidewalk], Vec::new()); @@ -121,15 +111,19 @@ pub fn get_lane_types(osm_tags: &BTreeMap) -> (Vec, Ve } } - // TODO Should we warn when one of these has parking assigned to it from the blockface? - let definitely_no_parking = match osm_tags.get(osm::HIGHWAY) { - Some(hwy) => hwy.ends_with("_link") || hwy == "motorway", - None => false, - }; - if parking_lane_fwd && !definitely_no_parking { + fn has_parking(value: Option<&String>) -> bool { + value == Some(&"parallel".to_string()) + || value == Some(&"diagonal".to_string()) + || value == Some(&"perpendicular".to_string()) + } + let parking_lane_fwd = has_parking(osm_tags.get(osm::PARKING_RIGHT)) + || has_parking(osm_tags.get(osm::PARKING_BOTH)); + let parking_lane_back = has_parking(osm_tags.get(osm::PARKING_LEFT)) + || has_parking(osm_tags.get(osm::PARKING_BOTH)); + if parking_lane_fwd { fwd_side.push(LaneType::Parking); } - if parking_lane_back && !definitely_no_parking { + if parking_lane_back { back_side.push(LaneType::Parking); } diff --git a/tests/src/map_conversion.rs b/tests/src/map_conversion.rs index a6068213c1..d5d1137f19 100644 --- a/tests/src/map_conversion.rs +++ b/tests/src/map_conversion.rs @@ -8,7 +8,6 @@ pub fn run(t: &mut TestRunner) { let flags = convert_osm::Flags { osm: "../data/input/montlake.osm".to_string(), parking_shapes: Some("../data/shapes/blockface.bin".to_string()), - street_signs: Some("../data/shapes/street_signs.bin".to_string()), offstreet_parking: Some("../data/input/offstreet_parking.kml".to_string()), gtfs: Some("../data/input/google_transit_2018_18_08".to_string()), neighborhoods: Some("../data/input/neighborhoods.geojson".to_string()),