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) {
areas.push(raw_data::Area {
area_type: at,
osm_way_id: way.id,
osm_id: way.id,
points: pts,
osm_tags: tags,
});
@ -83,35 +83,45 @@ pub fn osm_to_raw_roads(
let tags = tags_to_map(&rel.tags);
if let Some(at) = get_area_type(&tags) {
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 {
match *member {
osm_xml::Member::Way(osm_xml::UnresolvedReference::Way(id), ref role) => {
match id_to_way.get(&id) {
Some(pts) => {
if role == "outer" {
areas.push(raw_data::Area {
area_type: at,
osm_way_id: id,
points: pts.to_vec(),
osm_tags: tags.clone(),
});
pts_per_way.push(pts.to_vec());
} else {
println!(
"Relation {} has unhandled member role {}",
rel.id, role
);
ok = false;
}
}
None => {
println!("Relation {} refers to unknown way {}", rel.id, id);
ok = false;
}
}
}
_ => {
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()) {
return Some(AreaType::Park);
}
if tags.get("natural") == Some(&"wetland".to_string()) {
return Some(AreaType::Swamp);
}
if tags.contains_key("waterway") {
if tags.contains_key("waterway") || tags.get("natural") == Some(&"water".to_string()) {
return Some(AreaType::Water);
}
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
- and theyre hard to associate with roads (sometimes need to infer a planter strip)
- draw ALL water and greenery areas
- cant mouseover areas created from polylines, seemingly
- multipolygons seem broken
- how to handle multipolygons referring to clipped ways?
- draw benches, bike racks
- render trees
- 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) => {
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);
}
ID::Trip(_) => {}

View File

@ -26,7 +26,7 @@ impl ToggleableLayers {
show_parcels: ToggleableLayer::new("parcels", Some(MIN_ZOOM_FOR_PARCELS)),
show_extra_shapes: ToggleableLayer::new("extra shapes", Some(MIN_ZOOM_FOR_LANES)),
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),
}
}

View File

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

View File

@ -404,8 +404,8 @@ impl<S: UIState> UI<S> {
let map = &state.primary.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 areas: Vec<Box<&Renderable>> = Vec::new();
let mut lanes: Vec<Box<&Renderable>> = Vec::new();
let mut intersections: Vec<Box<&Renderable>> = Vec::new();
let mut buildings: Vec<Box<&Renderable>> = Vec::new();
@ -419,8 +419,8 @@ impl<S: UIState> UI<S> {
continue;
}
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::Area(id) => areas.push(Box::new(draw_map.get_a(id))),
ID::Lane(id) => {
lanes.push(Box::new(draw_map.get_l(id)));
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
let mut borrows: Vec<Box<&Renderable>> = Vec::new();
borrows.extend(areas);
borrows.extend(parcels);
borrows.extend(areas);
borrows.extend(lanes);
borrows.extend(intersections);
borrows.extend(buildings);

View File

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

View File

@ -189,7 +189,7 @@ pub fn make_half_map(
.map(|coord| Pt2D::from_gps(*coord, &gps_bounds).unwrap())
.collect(),
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
pub points: Vec<LonLat>,
pub osm_tags: BTreeMap<String, String>,
pub osm_way_id: i64,
pub osm_id: i64,
}
#[derive(PartialEq, Debug, Serialize, Deserialize)]