parse OSM multipolygons, like bodies of water, correctly, when they're

completely present in the .osm
This commit is contained in:
Dustin Carlino 2019-02-09 19:28:26 -08:00
parent 0f1d0d24ca
commit f693316290
9 changed files with 50 additions and 25 deletions

View File

@ -67,7 +67,7 @@ pub fn osm_to_raw_roads(
} else if let Some(at) = get_area_type(&tags) { } else if let Some(at) = get_area_type(&tags) {
areas.push(raw_data::Area { areas.push(raw_data::Area {
area_type: at, area_type: at,
osm_way_id: way.id, osm_id: way.id,
points: pts, points: pts,
osm_tags: tags, osm_tags: tags,
}); });
@ -83,35 +83,45 @@ pub fn osm_to_raw_roads(
let tags = tags_to_map(&rel.tags); let tags = tags_to_map(&rel.tags);
if let Some(at) = get_area_type(&tags) { if let Some(at) = get_area_type(&tags) {
if tags.get("type") == Some(&"multipolygon".to_string()) { if tags.get("type") == Some(&"multipolygon".to_string()) {
let mut ok = true;
let mut pts_per_way: Vec<Vec<LonLat>> = Vec::new();
for member in &rel.members { for member in &rel.members {
match *member { match *member {
osm_xml::Member::Way(osm_xml::UnresolvedReference::Way(id), ref role) => { osm_xml::Member::Way(osm_xml::UnresolvedReference::Way(id), ref role) => {
match id_to_way.get(&id) { match id_to_way.get(&id) {
Some(pts) => { Some(pts) => {
if role == "outer" { if role == "outer" {
areas.push(raw_data::Area { pts_per_way.push(pts.to_vec());
area_type: at,
osm_way_id: id,
points: pts.to_vec(),
osm_tags: tags.clone(),
});
} else { } else {
println!( println!(
"Relation {} has unhandled member role {}", "Relation {} has unhandled member role {}",
rel.id, role rel.id, role
); );
ok = false;
} }
} }
None => { None => {
println!("Relation {} refers to unknown way {}", rel.id, id); println!("Relation {} refers to unknown way {}", rel.id, id);
ok = false;
} }
} }
} }
_ => { _ => {
println!("Relation {} refers to {:?}", rel.id, member); println!("Relation {} refers to {:?}", rel.id, member);
ok = false;
} }
} }
} }
if ok {
if let Some(polygon) = glue_multipolygon(pts_per_way) {
areas.push(raw_data::Area {
area_type: at,
osm_id: rel.id,
points: polygon,
osm_tags: tags.clone(),
});
}
}
} }
} }
} }
@ -175,11 +185,29 @@ fn get_area_type(tags: &BTreeMap<String, String>) -> Option<AreaType> {
if tags.get("natural") == Some(&"wood".to_string()) { if tags.get("natural") == Some(&"wood".to_string()) {
return Some(AreaType::Park); return Some(AreaType::Park);
} }
if tags.get("natural") == Some(&"wetland".to_string()) { if tags.contains_key("waterway") || tags.get("natural") == Some(&"water".to_string()) {
return Some(AreaType::Swamp);
}
if tags.contains_key("waterway") {
return Some(AreaType::Water); return Some(AreaType::Water);
} }
None None
} }
fn glue_multipolygon(mut pts_per_way: Vec<Vec<LonLat>>) -> Option<Vec<LonLat>> {
let mut result = pts_per_way.pop().unwrap();
while !pts_per_way.is_empty() {
let glue_pt = *result.last().unwrap();
if let Some(idx) = pts_per_way
.iter()
.position(|pts| pts[0] == glue_pt || *pts.last().unwrap() == glue_pt)
{
let mut append = pts_per_way.remove(idx);
if append[0] != glue_pt {
append.reverse();
}
result.pop();
result.extend(append);
} else {
return None;
}
}
Some(result)
}

View File

@ -39,8 +39,7 @@
- but theyre not marked everywhere - but theyre not marked everywhere
- and theyre hard to associate with roads (sometimes need to infer a planter strip) - and theyre hard to associate with roads (sometimes need to infer a planter strip)
- draw ALL water and greenery areas - draw ALL water and greenery areas
- cant mouseover areas created from polylines, seemingly - how to handle multipolygons referring to clipped ways?
- multipolygons seem broken
- draw benches, bike racks - draw benches, bike racks
- render trees - render trees
- look for current stop sign priorities - look for current stop sign priorities

View File

@ -146,7 +146,7 @@ fn tooltip_lines(obj: ID, g: &mut GfxCtx, ctx: &DrawCtx) -> Text {
} }
ID::Area(id) => { ID::Area(id) => {
let a = map.get_a(id); let a = map.get_a(id);
txt.add_line(format!("{} (from OSM way {})", id, a.osm_way_id)); txt.add_line(format!("{} (from OSM {})", id, a.osm_id));
styled_kv(&mut txt, &a.osm_tags); styled_kv(&mut txt, &a.osm_tags);
} }
ID::Trip(_) => {} ID::Trip(_) => {}

View File

@ -26,7 +26,7 @@ impl ToggleableLayers {
show_parcels: ToggleableLayer::new("parcels", Some(MIN_ZOOM_FOR_PARCELS)), show_parcels: ToggleableLayer::new("parcels", Some(MIN_ZOOM_FOR_PARCELS)),
show_extra_shapes: ToggleableLayer::new("extra shapes", Some(MIN_ZOOM_FOR_LANES)), show_extra_shapes: ToggleableLayer::new("extra shapes", Some(MIN_ZOOM_FOR_LANES)),
show_all_turn_icons: ToggleableLayer::new("all turn icons", None), show_all_turn_icons: ToggleableLayer::new("all turn icons", None),
show_areas: ToggleableLayer::new("areas", None), show_areas: ToggleableLayer::new("areas", Some(0.0)),
debug_mode: ToggleableLayer::new("geometry debug mode", None), debug_mode: ToggleableLayer::new("geometry debug mode", None),
} }
} }

View File

@ -17,9 +17,8 @@ impl DrawArea {
let fill_polygon = area.get_polygon(); let fill_polygon = area.get_polygon();
let draw_default = prerender.upload_borrowed(vec![( let draw_default = prerender.upload_borrowed(vec![(
match area.area_type { match area.area_type {
AreaType::Park => cs.get_def("park area", Color::GREEN), AreaType::Park => cs.get_def("park area", Color::rgb(200, 250, 204)),
AreaType::Swamp => cs.get_def("swamp area", Color::rgb_f(0.0, 1.0, 0.6)), AreaType::Water => cs.get_def("water area", Color::rgb(170, 211, 223)),
AreaType::Water => cs.get_def("water area", Color::BLUE),
}, },
&fill_polygon, &fill_polygon,
)]); )]);

View File

@ -404,8 +404,8 @@ impl<S: UIState> UI<S> {
let map = &state.primary.map; let map = &state.primary.map;
let draw_map = &state.primary.draw_map; let draw_map = &state.primary.draw_map;
let mut areas: Vec<Box<&Renderable>> = Vec::new();
let mut parcels: Vec<Box<&Renderable>> = Vec::new(); let mut parcels: Vec<Box<&Renderable>> = Vec::new();
let mut areas: Vec<Box<&Renderable>> = Vec::new();
let mut lanes: Vec<Box<&Renderable>> = Vec::new(); let mut lanes: Vec<Box<&Renderable>> = Vec::new();
let mut intersections: Vec<Box<&Renderable>> = Vec::new(); let mut intersections: Vec<Box<&Renderable>> = Vec::new();
let mut buildings: Vec<Box<&Renderable>> = Vec::new(); let mut buildings: Vec<Box<&Renderable>> = Vec::new();
@ -419,8 +419,8 @@ impl<S: UIState> UI<S> {
continue; continue;
} }
match id { match id {
ID::Area(id) => areas.push(Box::new(draw_map.get_a(id))),
ID::Parcel(id) => parcels.push(Box::new(draw_map.get_p(id))), ID::Parcel(id) => parcels.push(Box::new(draw_map.get_p(id))),
ID::Area(id) => areas.push(Box::new(draw_map.get_a(id))),
ID::Lane(id) => { ID::Lane(id) => {
lanes.push(Box::new(draw_map.get_l(id))); lanes.push(Box::new(draw_map.get_l(id)));
if !state.show_icons_for(map.get_l(id).dst_i) { if !state.show_icons_for(map.get_l(id).dst_i) {
@ -452,8 +452,8 @@ impl<S: UIState> UI<S> {
// From background to foreground Z-order // From background to foreground Z-order
let mut borrows: Vec<Box<&Renderable>> = Vec::new(); let mut borrows: Vec<Box<&Renderable>> = Vec::new();
borrows.extend(areas);
borrows.extend(parcels); borrows.extend(parcels);
borrows.extend(areas);
borrows.extend(lanes); borrows.extend(lanes);
borrows.extend(intersections); borrows.extend(intersections);
borrows.extend(buildings); borrows.extend(buildings);

View File

@ -18,7 +18,6 @@ impl fmt::Display for AreaID {
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)] #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
pub enum AreaType { pub enum AreaType {
Park, Park,
Swamp,
Water, Water,
} }
@ -29,7 +28,7 @@ pub struct Area {
// Might be a closed loop or not -- waterways can be linear. // Might be a closed loop or not -- waterways can be linear.
pub points: Vec<Pt2D>, pub points: Vec<Pt2D>,
pub osm_tags: BTreeMap<String, String>, pub osm_tags: BTreeMap<String, String>,
pub osm_way_id: i64, pub osm_id: i64,
} }
impl Area { impl Area {

View File

@ -189,7 +189,7 @@ pub fn make_half_map(
.map(|coord| Pt2D::from_gps(*coord, &gps_bounds).unwrap()) .map(|coord| Pt2D::from_gps(*coord, &gps_bounds).unwrap())
.collect(), .collect(),
osm_tags: a.osm_tags.clone(), osm_tags: a.osm_tags.clone(),
osm_way_id: a.osm_way_id, osm_id: a.osm_id,
}); });
} }

View File

@ -125,7 +125,7 @@ pub struct Area {
// last point is always the same as the first // last point is always the same as the first
pub points: Vec<LonLat>, pub points: Vec<LonLat>,
pub osm_tags: BTreeMap<String, String>, pub osm_tags: BTreeMap<String, String>,
pub osm_way_id: i64, pub osm_id: i64,
} }
#[derive(PartialEq, Debug, Serialize, Deserialize)] #[derive(PartialEq, Debug, Serialize, Deserialize)]