Query database instead of overpass
This commit is contained in:
parent
54b280655f
commit
44241751b2
|
@ -2,6 +2,10 @@ from sqlalchemy.ext.declarative import declarative_base
|
||||||
from sqlalchemy.schema import Column
|
from sqlalchemy.schema import Column
|
||||||
from sqlalchemy.types import Integer, Float, Numeric, String
|
from sqlalchemy.types import Integer, Float, Numeric, String
|
||||||
from sqlalchemy.dialects import postgresql
|
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 geoalchemy2 import Geometry
|
||||||
from .database import session
|
from .database import session
|
||||||
|
|
||||||
|
@ -12,10 +16,22 @@ class Polygon(Base):
|
||||||
__tablename__ = "planet_osm_polygon"
|
__tablename__ = "planet_osm_polygon"
|
||||||
|
|
||||||
osm_id = Column(Integer, primary_key=True, autoincrement=False)
|
osm_id = Column(Integer, primary_key=True, autoincrement=False)
|
||||||
|
admin_level = Column(String)
|
||||||
|
|
||||||
way_area = Column(Float)
|
way_area = Column(Float)
|
||||||
tags = Column(postgresql.HSTORE)
|
tags = Column(postgresql.HSTORE)
|
||||||
way = Column(Geometry("GEOMETRY", srid=4326, spatial_index=True), nullable=False)
|
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):
|
class Scotland(Base):
|
||||||
__tablename__ = "scotland"
|
__tablename__ = "scotland"
|
||||||
|
|
|
@ -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"]
|
|
24
lookup.py
24
lookup.py
|
@ -2,10 +2,9 @@
|
||||||
|
|
||||||
from flask import Flask, render_template, request, jsonify, redirect, url_for
|
from flask import Flask, render_template, request, jsonify, redirect, url_for
|
||||||
import geocode
|
import geocode
|
||||||
from geocode import wikidata, overpass, scotland, database, model
|
from geocode import wikidata, scotland, database, model
|
||||||
import urllib.parse
|
import urllib.parse
|
||||||
import random
|
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));
|
# 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
|
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):
|
def wd_to_qid(wd):
|
||||||
# expecting {"type": "url", "value": "https://www.wikidata.org/wiki/Q30"}
|
# expecting {"type": "url", "value": "https://www.wikidata.org/wiki/Q30"}
|
||||||
if wd["type"] == "uri":
|
if wd["type"] == "uri":
|
||||||
|
@ -131,7 +121,7 @@ def lat_lon_to_wikidata(lat, lon):
|
||||||
|
|
||||||
return {"elements": elements, "result": result}
|
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)
|
result = do_lookup(elements, lat, lon)
|
||||||
|
|
||||||
# special case because the City of London is admin_level=6 in OSM
|
# 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):
|
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:
|
for e in elements:
|
||||||
if "tags" not in e:
|
tags = e.tags
|
||||||
continue
|
|
||||||
tags = e["tags"]
|
|
||||||
admin_level_tag = tags.get("admin_level")
|
admin_level_tag = tags.get("admin_level")
|
||||||
admin_level = (
|
admin_level = (
|
||||||
int(admin_level_tag)
|
int(admin_level_tag)
|
||||||
|
@ -265,7 +253,7 @@ def index():
|
||||||
def random_location():
|
def random_location():
|
||||||
lat, lon = get_random_lat_lon()
|
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)
|
result = do_lookup(elements, lat, lon)
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
|
@ -286,7 +274,7 @@ def wikidata_tag():
|
||||||
elements = []
|
elements = []
|
||||||
result = build_dict(hit, lat, lon)
|
result = build_dict(hit, lat, lon)
|
||||||
else:
|
else:
|
||||||
elements = overpass.get_osm_elements(lat, lon)
|
elements = model.Polygon.coords_within(lat, lon)
|
||||||
result = do_lookup(elements, lat, lon)
|
result = do_lookup(elements, lat, lon)
|
||||||
|
|
||||||
return render_template(
|
return render_template(
|
||||||
|
|
|
@ -32,7 +32,7 @@
|
||||||
|
|
||||||
{% for element in elements %}
|
{% for element in elements %}
|
||||||
{% set tags = element.tags %}
|
{% set tags = element.tags %}
|
||||||
<pre>{{ element | pprint }}</pre>
|
<pre>{{ element.tags | pprint }}</pre>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue