prep before bringing in king county sidewalks. clean up lane type

calculation, move motorway/parking filter earlier. stop bringing in
street signs.
This commit is contained in:
Dustin Carlino 2019-10-23 09:35:41 -07:00
parent d5c82a63e0
commit 9cab5bf903
6 changed files with 79 additions and 143 deletions

View File

@ -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<String>,
pub street_signs: Option<String>,
pub offstreet_parking: Option<String>,
pub gtfs: Option<String>,
pub neighborhoods: Option<String>,
@ -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");

View File

@ -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"),

View File

@ -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

View File

@ -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

View File

@ -13,16 +13,6 @@ pub fn get_lane_types(osm_tags: &BTreeMap<String, String>) -> (Vec<LaneType>, 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<String, String>) -> (Vec<LaneType>, 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);
}

View File

@ -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()),