import_osm: add osm_multipolygons

This commit is contained in:
Astro 2021-08-27 23:11:06 +02:00
parent a3ecb3ed5a
commit 2958855a2b
2 changed files with 94 additions and 11 deletions

12
db.sql
View File

@ -25,3 +25,15 @@ CREATE TABLE osm_ways (
attrs jsonb
);
CREATE INDEX osm_ways_box_coords ON osm_ways USING GIST (box(polygon(pclose(geo))));
CREATE TABLE osm_multipolygons (
id bigint,
attrs jsonb
);
CREATE TABLE osm_multipolygon_members (
id bigint,
m_geo polygon,
m_role text,
m_id bigint
);
CREATE INDEX osm_ways_box_coords ON osm_ways USING GIST (box(m_geo));

View File

@ -8,6 +8,7 @@ use std::sync::Arc;
use std::thread;
use osm_pbf_iter::*;
use geo::LineString;
use indicatif::{ProgressBar, ProgressStyle};
pub struct PrimSource {
@ -143,7 +144,7 @@ fn main() {
println!("{} nodes", node_coords.len());
let node_coords = Arc::new(node_coords);
let mut way_coords: HashMap<i64, Vec<(f64, f64)>> = HashMap::new();
let mut way_paths: HashMap<i64, LineString<f64>> = HashMap::new();
// phase 2: ways
for arg in args().skip(1) {
let node_coords = node_coords.clone();
@ -166,13 +167,15 @@ fn main() {
let tags: serde_json::Map<String, serde_json::Value> = way.tags()
.map(|(k, v)| (k.to_string(), serde_json::Value::String(v.to_string())))
.collect();
let points = way.refs()
.filter_map(|id| node_coords.get(&id))
.cloned()
.collect::<Vec<_>>();
let points = LineString::from(
way.refs()
.filter_map(|id| node_coords.get(&id))
.cloned()
.collect::<Vec<_>>()
);
tx.execute(
"INSERT INTO osm_ways (geo, id, attrs) VALUES ($1, $2, $3)",
&[&geo::LineString::from(points.clone()), &(way.id as i64), &serde_json::Value::Object(tags)]
&[&points, &(way.id as i64), &serde_json::Value::Object(tags)]
).unwrap();
res.insert(way.id as i64, points);
}
@ -187,17 +190,85 @@ fn main() {
res
});
for mut res in worker_res {
if way_coords.is_empty() {
way_coords = res;
if way_paths.is_empty() {
way_paths = res;
} else {
// merge
for (id, coords) in res.drain() {
way_coords.insert(id, coords);
way_paths.insert(id, coords);
}
}
}
}
let way_coords = Arc::new(way_coords);
let way_paths = Arc::new(way_paths);
// phase 3: rels (TODO)
// phase 3: rels
for arg in args().skip(1) {
let way_paths = way_paths.clone();
process_osm(&arg, move |prim_src| {
const DB_URL: &str = "host=10.233.1.2 dbname=treeadvisor user=treeadvisor password=123";
let mut db = postgres::Client::connect(DB_URL, postgres::NoTls)
.expect("DB");
let mut running = true;
while running {
running = prim_src.recv_primitives(|iter| {
let mut tx = db.transaction().unwrap();
for primitive in iter {
match primitive {
Primitive::Node(_) => {}
Primitive::Way(_) => {}
Primitive::Relation(rel) => {
let tags: serde_json::Map<String, serde_json::Value> = rel.tags()
.map(|(k, v)| (k.to_string(), serde_json::Value::String(v.to_string())))
.collect();
let get_members = |target_role| rel.members()
.filter_map(|(role, id, member_type)| {
if member_type == RelationMemberType::Way && role == target_role {
way_paths.get(&(id as i64))
.and_then(|path| {
if path.is_closed() {
Some((id, path))
} else {
None
}
})
} else {
None
}
})
.collect::<Vec<_>>();
let outers = get_members("outer");
if outers.len() > 0 {
tx.execute(
"INSERT INTO osm_multipolygons (id, attrs) VALUES ($1, $2)",
&[&(rel.id as i64), &serde_json::Value::Object(tags)]
).unwrap();
for (member_id, path) in outers.into_iter() {
tx.execute(
"INSERT INTO osm_multipolygon_members (id, m_id, m_role, m_geo) VALUES ($1, $2, 'outer', polygon(pclose($3::path)))",
&[&(rel.id as i64), &(member_id as i64), &path]
).unwrap();
}
let inners = get_members("inner");
for (member_id, path) in inners.into_iter() {
tx.execute(
"INSERT INTO osm_multipolygon_members (id, m_id, m_role, m_geo) VALUES ($1, $2, 'inner', polygon(pclose($3::path)))",
&[&(rel.id as i64), &(member_id as i64), &path]
).unwrap();
}
}
}
}
}
tx.commit().unwrap();
true
}).unwrap_or(false);
}
});
}
}