From 140a9ed598b2e1eaa521135ed8612a4e0a98fea4 Mon Sep 17 00:00:00 2001
From: Edward Betts <edward@4angle.com>
Date: Fri, 14 May 2021 17:09:56 +0200
Subject: [PATCH] Show address nodes for buildings

---
 static/js/map.js |  9 +++++-
 web_view.py      | 77 +++++++++++++++++++++++++++++++++++-------------
 2 files changed, 64 insertions(+), 22 deletions(-)

diff --git a/static/js/map.js b/static/js/map.js
index b118cea..e9b5b1e 100644
--- a/static/js/map.js
+++ b/static/js/map.js
@@ -453,7 +453,14 @@ function mouse_events(marker, qid) {
               osm_html += osm.name;
             }
             if (!osm.presets.length && !osm.name) {
-              osm_html += "no name";
+              osm_html += " no name";
+            }
+            if (osm.address_list && osm.address_list.length) {
+              if (osm.address_list.length == 1) {
+                osm_html += " address node: " + osm.address_list[0];
+              } else {
+                osm_html += " address nodes: " + osm.address_list.join("; ")
+              }
             }
             osm_html += ` <a href="https://www.openstreetmap.org/${osm.identifier}" target="_blank">`
             osm_html += '<i class="fa fa-map-o"></i></a></span><br>';
diff --git a/web_view.py b/web_view.py
index 481cdcc..9e4a61f 100755
--- a/web_view.py
+++ b/web_view.py
@@ -812,34 +812,63 @@ def get_nearby(bbox, item, max_distance=200):
     return nearby[:10]
 
 
-def get_presets_from_tags(tags):
+def find_preset_file(k, v, ending):
     preset_dir = app.config["ID_PRESET_DIR"]
+
+    filename = os.path.join(preset_dir, k, v + ".json")
+    if os.path.exists(filename):
+        return {"tag_or_key": f"Tag:{k}={v}", "filename": filename}
+
+    filename = os.path.join(preset_dir, k, f"{v}_{ending}.json")
+    if os.path.exists(filename):
+        return {"tag_or_key": f"Tag:{k}={v}", "filename": filename}
+
+    filename = os.path.join(preset_dir, k, "_" + v + ".json")
+    if os.path.exists(filename):
+        return {"tag_or_key": f"Tag:{k}={v}", "filename": filename}
+
+    filename = os.path.join(preset_dir, k + ".json")
+    if os.path.exists(filename):
+        return {"tag_or_key": f"Key:{k}", "filename": filename}
+
+
+def get_presets_from_tags(osm):
     found = []
-    for k, v in tags.items():
-        if k == 'amenity' and v == 'clock' and tags.get('display') == 'sundial':
+    ending = {
+        model.Point: "point",
+        model.Line: "line",
+        model.Polygon: "area"
+    }[type(osm)]
+    for k, v in osm.tags.items():
+        if k == 'amenity' and v == 'clock' and osm.tags.get('display') == 'sundial':
             tag_or_key = f"Tag:{k}={v}"
             found.append({"tag_or_key": tag_or_key, "name": "Sundial"})
             continue
 
-        filename = os.path.join(preset_dir, k, v + ".json")
-        if os.path.exists(filename):
-            tag_or_key = f"Tag:{k}={v}"
-        else:
-            filename = os.path.join(preset_dir, k, "_" + v + ".json")
-            if os.path.exists(filename):
-                tag_or_key = f"Tag:{k}={v}"
-            else:
-                filename = os.path.join(preset_dir, k + ".json")
-                if os.path.exists(filename):
-                    tag_or_key = f"Key:{k}"
-                else:
-                    continue
-        data = json.load(open(filename))
-        name = data["name"]
-        found.append({"tag_or_key": tag_or_key, "name": name})
+        match = find_preset_file(k, v, ending)
+        if not match:
+            continue
+
+        match["name"] = json.load(open(match.pop("filename")))["name"]
+        found.append(match)
 
     return found
 
+def get_address_nodes_within_building(building, bbox):
+    db_bbox = make_envelope(bbox)
+    ewkt = building.as_EWKT
+    q = model.Point.query.filter(
+        func.ST_Intersects(db_bbox, model.Point.way),
+        func.ST_Covers(func.ST_GeomFromEWKT(ewkt), model.Point.way),
+        model.Point.tags.has_key("addr:street"),
+        model.Point.tags.has_key("addr:housenumber"),
+    )
+
+    return [node.tags for node in q]
+
+def address_from_tags(tags):
+    return " ".join(tags["addr:" + k] for k in ("street", "housenumber"))
+
 
 @app.route("/api/1/item/Q<int:item_id>/candidates")
 def api_find_osm_candidates(item_id):
@@ -852,15 +881,21 @@ def api_find_osm_candidates(item_id):
         tags = osm.tags
         name = osm.name or tags.get("addr:housename")
         if not name and "addr:housenumber" in tags and "addr:street" in tags:
-            name = tags["addr:housenumber"] + " " + tags["addr:street"]
+            name = address_from_tags(tags)
 
+        if isinstance(osm, model.Polygon) and "building" in osm.tags:
+            address_nodes = get_address_nodes_within_building(osm, bounds)
+            address_list = [address_from_tags(addr) for addr in address_nodes]
+        else:
+            address_list = []
         cur = {
             "identifier": osm.identifier,
             "distance": dist,
             "name": name,
             "tags": tags,
             "geojson": osm.geojson(),
-            "presets": get_presets_from_tags(tags),
+            "presets": get_presets_from_tags(osm),
+            "address_list": address_list,
         }
         if hasattr(osm, 'area'):
             cur["area"] = osm.area