2021-10-28 03:36:18 +02:00
|
|
|
use std::collections::HashMap;
|
2021-10-30 00:12:34 +02:00
|
|
|
use std::io::BufReader;
|
2021-10-28 03:36:18 +02:00
|
|
|
use std::fs::File;
|
|
|
|
use std::sync::Arc;
|
|
|
|
|
|
|
|
use geo::prelude::{Area, Contains};
|
|
|
|
|
|
|
|
|
|
|
|
type Polygon = geo::Polygon<f64>;
|
|
|
|
|
|
|
|
struct Location {
|
|
|
|
name: Arc<String>,
|
2021-10-28 17:43:12 +02:00
|
|
|
poly: Arc<Polygon>,
|
2021-10-28 03:36:18 +02:00
|
|
|
area: f64,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Location {
|
2021-10-28 17:43:12 +02:00
|
|
|
pub fn new(name: &str, poly: Arc<Polygon>) -> Self {
|
|
|
|
let area = poly.unsigned_area();
|
2021-10-28 03:36:18 +02:00
|
|
|
Location {
|
|
|
|
name: Arc::new(name.to_owned()),
|
2021-10-28 17:43:12 +02:00
|
|
|
poly,
|
2021-10-28 03:36:18 +02:00
|
|
|
area,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn contains(&self, coord: &geo::Coordinate<f64>) -> bool {
|
2021-10-28 17:43:12 +02:00
|
|
|
self.poly.contains(coord)
|
2021-10-28 03:36:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct Locations {
|
|
|
|
locations: Vec<Location>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Locations {
|
|
|
|
pub fn load(file: &str) -> Self {
|
|
|
|
println!("Loading {}...", file);
|
2021-10-30 00:12:34 +02:00
|
|
|
let json: serde_json::Value = serde_json::from_reader(BufReader::new(File::open(file).unwrap()))
|
2021-10-28 03:36:18 +02:00
|
|
|
.unwrap();
|
2021-10-28 17:43:12 +02:00
|
|
|
println!("parsed JSON");
|
2021-10-28 03:36:18 +02:00
|
|
|
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());
|
|
|
|
|
|
|
|
let mut nodes = HashMap::new();
|
|
|
|
for el in els {
|
|
|
|
let el = el.as_object().expect("el");
|
|
|
|
|
|
|
|
match el.get("type").and_then(|v| v.as_str()) {
|
|
|
|
Some("node") => {
|
|
|
|
let id = el.get("id").and_then(|v| v.as_u64()).expect("id");
|
|
|
|
let lon = el.get("lon").expect("lon")
|
|
|
|
.as_f64().expect("lon f64");
|
|
|
|
let lat = el.get("lat").expect("lat")
|
|
|
|
.as_f64().expect("lat f64");
|
|
|
|
let coord = geo::Coordinate { x: lon, y: lat };
|
|
|
|
nodes.insert(id, coord);
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
println!("{} nodes", nodes.len());
|
|
|
|
|
|
|
|
let mut locations = vec![];
|
|
|
|
let mut ways = HashMap::new();
|
|
|
|
for el in els {
|
|
|
|
let el = el.as_object().expect("el");
|
|
|
|
|
|
|
|
match el.get("type").and_then(|v| v.as_str()) {
|
|
|
|
Some("way") => {
|
|
|
|
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()
|
2021-10-28 17:43:12 +02:00
|
|
|
.map(|way_node| way_node.as_u64().expect("way_node"))
|
2021-10-28 03:36:18 +02:00
|
|
|
.collect::<Vec<_>>();
|
2021-10-28 17:43:12 +02:00
|
|
|
ways.insert(id, way_nodes.clone());
|
2021-10-28 03:36:18 +02:00
|
|
|
|
|
|
|
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()) {
|
2021-10-28 17:43:12 +02:00
|
|
|
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));
|
2021-10-28 03:36:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
println!("{} ways", ways.len());
|
|
|
|
|
|
|
|
for el in els {
|
|
|
|
let el = el.as_object().expect("el");
|
|
|
|
|
|
|
|
match el.get("type").and_then(|v| v.as_str()) {
|
|
|
|
Some("relation") => {
|
2021-10-28 17:43:12 +02:00
|
|
|
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::<Vec<_>>();
|
|
|
|
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);
|
2021-10-28 03:36:18 +02:00
|
|
|
} else {
|
2021-10-28 17:43:12 +02:00
|
|
|
println!("inconclusive polygon for relation {}", el.get("id").unwrap().as_u64().unwrap());
|
|
|
|
println!("rel_nodes: {:?}", rel_nodes);
|
|
|
|
println!("remain: {:?}", outers);
|
|
|
|
rel_nodes = vec![];
|
|
|
|
break;
|
2021-10-28 03:36:18 +02:00
|
|
|
}
|
2021-10-28 17:43:12 +02:00
|
|
|
|
|
|
|
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());
|
2021-10-28 03:36:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
locations.sort_by(|a, b| a.area.partial_cmp(&b.area).unwrap());
|
|
|
|
println!("{} locations", locations.len());
|
|
|
|
|
|
|
|
Locations {
|
|
|
|
locations,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn find(&self, coord: &geo::Coordinate<f64>) -> Option<Arc<String>> {
|
|
|
|
for l in &self.locations {
|
|
|
|
if l.contains(coord) {
|
|
|
|
return Some(l.name.clone());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None
|
|
|
|
}
|
|
|
|
}
|