diff --git a/fetch_locations.sh b/fetch_data.sh similarity index 81% rename from fetch_locations.sh rename to fetch_data.sh index cb64b8b..28eb940 100755 --- a/fetch_locations.sh +++ b/fetch_data.sh @@ -10,4 +10,4 @@ for level in 7 8 9 10 11 ; do Q=$Q'way["admin_level"="'$level'"]('$bbox'); relation["admin_level"="'$level'"]('$bbox');' done -echo overpass "($Q); out body; >; out skel;" \> locations.json +overpass "($Q); out body; >; out skel;" > locations.json diff --git a/src/location.rs b/src/location.rs index 234542d..f3c0766 100644 --- a/src/location.rs +++ b/src/location.rs @@ -9,24 +9,22 @@ type Polygon = geo::Polygon; struct Location { name: Arc, - polys: Vec>, + poly: Arc, area: f64, } impl Location { - pub fn new(name: &str, polys: Vec>) -> Self { - let area = polys.iter() - .map(|poly| poly.unsigned_area()) - .sum(); + pub fn new(name: &str, poly: Arc) -> Self { + let area = poly.unsigned_area(); Location { name: Arc::new(name.to_owned()), - polys, + poly, area, } } pub fn contains(&self, coord: &geo::Coordinate) -> bool { - self.polys.iter().any(|poly| poly.contains(coord)) + self.poly.contains(coord) } } @@ -39,6 +37,7 @@ impl Locations { println!("Loading {}...", file); let json: serde_json::Value = serde_json::from_reader(File::open(file).unwrap()) .unwrap(); + println!("parsed JSON"); let obj = json.as_object().expect("json obj"); let els = obj.get("elements").and_then(|v| v.as_array()).expect("els"); println!("{} elements", els.len()); @@ -72,22 +71,20 @@ impl Locations { let id = el.get("id").and_then(|v| v.as_u64()).expect("id"); let way_nodes = el.get("nodes").and_then(|v| v.as_array()).expect("nodes") .iter() - .map(|way_node| { - let way_node = way_node.as_u64() - .expect("way_node"); - nodes.get(&way_node).expect("way_node node") - }) - .cloned() + .map(|way_node| way_node.as_u64().expect("way_node")) .collect::>(); - let poly = Arc::new(Polygon::new( - geo::LineString(way_nodes), - vec![] - )); - ways.insert(id, poly.clone()); + ways.insert(id, way_nodes.clone()); if let Some(tags) = el.get("tags").and_then(|v| v.as_object()) { if let Some(name) = tags.get("name").and_then(|v| v.as_str()) { - locations.push(Location::new(name, vec![poly])); + let poly = Arc::new(Polygon::new( + geo::LineString(way_nodes.iter() + .map(|node| nodes.get(node).expect("node")) + .cloned() + .collect()), + vec![] + )); + locations.push(Location::new(name, poly)); } } } @@ -101,23 +98,61 @@ impl Locations { match el.get("type").and_then(|v| v.as_str()) { Some("relation") => { - let polys = el.get("members").and_then(|v| v.as_array()).expect("members") - .iter() - .filter_map(|member| { - let member = member.as_object().unwrap(); - let member_type = member.get("type").and_then(|v| v.as_str()).unwrap(); - if member_type == "way" { - let member_ref = member.get("ref").and_then(|v| v.as_u64()).unwrap(); - let way = ways.get(&member_ref).expect("member way"); - Some(way.clone()) + if let Some(name) = el.get("tags") + .and_then(|v| v.as_object()) + .and_then(|tags| tags.get("name")) + .and_then(|v| v.as_str()) + { + let mut outers = el.get("members").and_then(|v| v.as_array()).expect("members") + .iter() + .filter_map(|member| { + let member = member.as_object().unwrap(); + let member_type = member.get("type").and_then(|v| v.as_str()).unwrap(); + let member_role = member.get("role").and_then(|v| v.as_str()).unwrap(); + if member_type == "way" && member_role == "outer" { + let member_ref = member.get("ref").and_then(|v| v.as_u64()).unwrap(); + let way = ways.get(&member_ref).expect("member way"); + Some(way.clone()) + } else { + None + } + }) + .collect::>(); + let mut rel_nodes = vec![]; + while outers.len() > 0 { + if rel_nodes.len() == 0 { + rel_nodes = outers.pop().unwrap(); + } else if let Some(next) = outers.iter().position(|outer| outer[0] == rel_nodes[rel_nodes.len() - 1]) { + rel_nodes.append(&mut outers.remove(next)); + } else if let Some(next) = outers.iter().position(|outer| outer[outer.len() - 1] == rel_nodes[0]) { + let mut new = outers.remove(next); + new.append(&mut rel_nodes); + rel_nodes = new; + } else if let Some(next) = outers.iter().position(|outer| outer[outer.len() - 1] == rel_nodes[rel_nodes.len() - 1]) { + let mut new = outers.remove(next); + new.reverse(); + rel_nodes.append(&mut new); } else { - None + println!("inconclusive polygon for relation {}", el.get("id").unwrap().as_u64().unwrap()); + println!("rel_nodes: {:?}", rel_nodes); + println!("remain: {:?}", outers); + rel_nodes = vec![]; + break; } - }) - .collect::>(); - if let Some(tags) = el.get("tags").and_then(|v| v.as_object()) { - if let Some(name) = tags.get("name").and_then(|v| v.as_str()) { - locations.push(Location::new(name, polys)); + + if rel_nodes[0] == rel_nodes[rel_nodes.len() - 1] { + let poly = Arc::new(Polygon::new( + geo::LineString(rel_nodes.drain(..) + .map(|node| nodes.get(&node).expect("node")) + .cloned() + .collect()), + vec![] + )); + locations.push(Location::new(name, poly)); + } + } + if rel_nodes.len() > 0 { + println!("unclosed polygon for relation {}", el.get("id").unwrap().as_u64().unwrap()); } } }