diff --git a/geocode/model.py b/geocode/model.py index 5800b24..16efdaa 100644 --- a/geocode/model.py +++ b/geocode/model.py @@ -2,6 +2,10 @@ from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.schema import Column from sqlalchemy.types import Integer, Float, Numeric, String from sqlalchemy.dialects import postgresql +from sqlalchemy.orm import column_property +from sqlalchemy.ext.hybrid import hybrid_property +from sqlalchemy import func + from geoalchemy2 import Geometry from .database import session @@ -12,10 +16,22 @@ class Polygon(Base): __tablename__ = "planet_osm_polygon" osm_id = Column(Integer, primary_key=True, autoincrement=False) + admin_level = Column(String) way_area = Column(Float) tags = Column(postgresql.HSTORE) way = Column(Geometry("GEOMETRY", srid=4326, spatial_index=True), nullable=False) + area = column_property(func.ST_Area(way)) + + @hybrid_property + def area_in_sq_km(self): + return self.area / (1000 * 1000) + + @classmethod + def coords_within(cls, lat, lon): + point = func.ST_SetSRID(func.ST_MakePoint(lon, lat), 4326) + return cls.query.filter(cls.admin_level.isnot(None), + func.ST_Within(point, cls.way)) class Scotland(Base): __tablename__ = "scotland" diff --git a/geocode/overpass.py b/geocode/overpass.py deleted file mode 100644 index 860ea2a..0000000 --- a/geocode/overpass.py +++ /dev/null @@ -1,36 +0,0 @@ -from flask import current_app -from . import headers -import os -import json -import requests - -OVERPASS_URL = "https://lz4.overpass-api.de" - - -def run_query(oql): - return requests.post( - OVERPASS_URL + "/api/interpreter", data=oql.encode("utf-8"), headers=headers - ) - - -def is_in_lat_lon(lat, lon): - oql = f""" -[out:json][timeout:25]; -is_in({lat},{lon})->.a; -(way(pivot.a); rel(pivot.a);); -out bb tags qt;""" - - return run_query(oql) - - -def get_osm_elements(lat, lon): - filename = f"cache/{lat}_{lon}.json" - use_cache = current_app.config["USE_CACHE"] - - if use_cache and os.path.exists(filename): - return json.load(open(filename))["elements"] - - r = is_in_lat_lon(lat, lon) - if use_cache: - open(filename, "wb").write(r.content) - return r.json()["elements"] diff --git a/lookup.py b/lookup.py index a3445f7..e33fd0a 100755 --- a/lookup.py +++ b/lookup.py @@ -2,10 +2,9 @@ from flask import Flask, render_template, request, jsonify, redirect, url_for import geocode -from geocode import wikidata, overpass, scotland, database, model +from geocode import wikidata, scotland, database, model import urllib.parse import random -from geopy.distance import distance # select gid, code, name from scotland where st_contains(geom, ST_Transform(ST_SetSRID(ST_MakePoint(-4.177, 55.7644), 4326), 27700)); @@ -32,15 +31,6 @@ def get_random_lat_lon(): return lat, lon -def bounding_box_area(element): - bbox = element["bounds"] - - x = distance((bbox["maxlat"], bbox["minlon"]), (bbox["maxlat"], bbox["maxlon"])) - y = distance((bbox["minlat"], bbox["maxlon"]), (bbox["maxlat"], bbox["minlon"])) - - return x.km * y.km - - def wd_to_qid(wd): # expecting {"type": "url", "value": "https://www.wikidata.org/wiki/Q30"} if wd["type"] == "uri": @@ -131,7 +121,7 @@ def lat_lon_to_wikidata(lat, lon): return {"elements": elements, "result": result} - elements = overpass.get_osm_elements(lat, lon) + elements = model.Polygon.coords_within(lat, lon) result = do_lookup(elements, lat, lon) # special case because the City of London is admin_level=6 in OSM @@ -190,12 +180,10 @@ def get_commons_cat_from_gss(gss): def osm_lookup(elements, lat, lon): - elements.sort(key=lambda e: bounding_box_area(e)) + elements = sorted(elements, key=lambda e: e.area) for e in elements: - if "tags" not in e: - continue - tags = e["tags"] + tags = e.tags admin_level_tag = tags.get("admin_level") admin_level = ( int(admin_level_tag) @@ -265,7 +253,7 @@ def index(): def random_location(): lat, lon = get_random_lat_lon() - elements = overpass.get_osm_elements(lat, lon) + elements = model.Polygon.coords_within(lat, lon) result = do_lookup(elements, lat, lon) return render_template( @@ -286,7 +274,7 @@ def wikidata_tag(): elements = [] result = build_dict(hit, lat, lon) else: - elements = overpass.get_osm_elements(lat, lon) + elements = model.Polygon.coords_within(lat, lon) result = do_lookup(elements, lat, lon) return render_template( diff --git a/templates/detail.html b/templates/detail.html index b372a5c..941d8bf 100644 --- a/templates/detail.html +++ b/templates/detail.html @@ -32,7 +32,7 @@ {% for element in elements %} {% set tags = element.tags %} -
{{ element | pprint }}
+
{{ element.tags | pprint }}
{% endfor %}