Release v2.0 - add Netherlands POI analysis
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Importeer alleen benodigde POI's uit een OSM PBF naar PostGIS.
|
||||
Veel lichter dan volledige osm2pgsql-import voor heel Nederland.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import os
|
||||
|
||||
import osmium
|
||||
import psycopg2
|
||||
from psycopg2.extras import execute_values
|
||||
|
||||
DB_DSN = os.environ.get(
|
||||
"ADRES_ANALYSE_DB_DSN",
|
||||
"host=127.0.0.1 port=5433 dbname=adresanalyse user=adres password=adres",
|
||||
)
|
||||
|
||||
SCHEMA_SQL = """
|
||||
CREATE EXTENSION IF NOT EXISTS postgis;
|
||||
DROP TABLE IF EXISTS osm_pois;
|
||||
CREATE TABLE osm_pois (
|
||||
id bigserial PRIMARY KEY,
|
||||
osm_type text NOT NULL,
|
||||
osm_id bigint NOT NULL,
|
||||
category text NOT NULL,
|
||||
name text NOT NULL,
|
||||
brand text,
|
||||
operator text,
|
||||
lon double precision NOT NULL,
|
||||
lat double precision NOT NULL,
|
||||
geom geometry(Point, 4326) NOT NULL
|
||||
);
|
||||
CREATE INDEX osm_pois_category_geom_gix ON osm_pois USING GIST (geom);
|
||||
CREATE INDEX osm_pois_category_idx ON osm_pois (category);
|
||||
CREATE INDEX osm_pois_name_idx ON osm_pois (lower(name));
|
||||
|
||||
CREATE OR REPLACE VIEW poi_supermarkten AS
|
||||
SELECT osm_id, name, 'supermarkt'::text AS category, 'supermarket'::text AS shop, NULL::text AS amenity, brand, operator, geom
|
||||
FROM osm_pois WHERE category = 'supermarkt';
|
||||
|
||||
CREATE OR REPLACE VIEW poi_scholen AS
|
||||
SELECT osm_id, name, 'school'::text AS category, NULL::text AS shop, 'school'::text AS amenity, brand, operator, geom
|
||||
FROM osm_pois WHERE category = 'school';
|
||||
"""
|
||||
|
||||
|
||||
def poi_from_tags(tags):
|
||||
if tags.get("shop") == "supermarket":
|
||||
return "supermarkt", tags.get("name") or tags.get("brand") or "Supermarkt"
|
||||
if tags.get("amenity") == "school":
|
||||
return "school", tags.get("name") or "School"
|
||||
return None, None
|
||||
|
||||
|
||||
class PoiHandler(osmium.SimpleHandler):
|
||||
def __init__(self, conn, batch_size=1000):
|
||||
super().__init__()
|
||||
self.conn = conn
|
||||
self.batch_size = batch_size
|
||||
self.rows = []
|
||||
self.count = 0
|
||||
self.factory = osmium.geom.WKBFactory()
|
||||
|
||||
def flush(self):
|
||||
if not self.rows:
|
||||
return
|
||||
with self.conn.cursor() as cur:
|
||||
execute_values(
|
||||
cur,
|
||||
"""
|
||||
INSERT INTO osm_pois (osm_type, osm_id, category, name, brand, operator, lon, lat, geom)
|
||||
VALUES %s
|
||||
""",
|
||||
self.rows,
|
||||
)
|
||||
self.conn.commit()
|
||||
self.rows.clear()
|
||||
|
||||
def add_row(self, osm_type, osm_id, tags, lon, lat):
|
||||
category, name = poi_from_tags(tags)
|
||||
if not category:
|
||||
return
|
||||
self.rows.append((
|
||||
osm_type,
|
||||
int(osm_id),
|
||||
category,
|
||||
name,
|
||||
tags.get("brand"),
|
||||
tags.get("operator"),
|
||||
float(lon),
|
||||
float(lat),
|
||||
f"SRID=4326;POINT({float(lon)} {float(lat)})",
|
||||
))
|
||||
self.count += 1
|
||||
if len(self.rows) >= self.batch_size:
|
||||
self.flush()
|
||||
|
||||
def node(self, n):
|
||||
if not n.location.valid():
|
||||
return
|
||||
self.add_row("node", n.id, n.tags, n.location.lon, n.location.lat)
|
||||
|
||||
def area(self, a):
|
||||
category, _ = poi_from_tags(a.tags)
|
||||
if not category:
|
||||
return
|
||||
try:
|
||||
wkb = self.factory.create_multipolygon(a)
|
||||
with self.conn.cursor() as cur:
|
||||
cur.execute("SELECT ST_X(p), ST_Y(p) FROM (SELECT ST_PointOnSurface(ST_GeomFromWKB(%s, 4326)) p) s", (psycopg2.Binary(wkb),))
|
||||
lon, lat = cur.fetchone()
|
||||
self.add_row("area", a.orig_id(), a.tags, lon, lat)
|
||||
except Exception:
|
||||
return
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("pbf")
|
||||
args = parser.parse_args()
|
||||
|
||||
with psycopg2.connect(DB_DSN) as conn:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(SCHEMA_SQL)
|
||||
conn.commit()
|
||||
handler = PoiHandler(conn)
|
||||
handler.apply_file(args.pbf, locations=True)
|
||||
handler.flush()
|
||||
with conn.cursor() as cur:
|
||||
cur.execute("ANALYZE osm_pois")
|
||||
conn.commit()
|
||||
print(f"Imported {handler.count} POIs into osm_pois")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user