#!/usr/bin/env python3 """ Adres Analyse - Rapport generator Gebruikt PDOK voor geocoding, ORS voor isochronen/routes en PostGIS OSM-data voor voorzieningen. Slaat rapport en HTML-kaarten op in /root/mkdocs/docs/docs/Huizenjacht/ """ import json import sys import os import re import urllib.request import urllib.parse from datetime import datetime import base64 from io import BytesIO try: from PIL import Image HAS_PIL = True except ImportError: HAS_PIL = False from voorzieningen import analyse_voorzieningen, format_voorzieningen_markdown, format_afstand, format_duur # Config ORS_BASE = "http://192.168.1.71:9080/ors/v2" PDOK_BASE = "https://api.pdok.nl/bzk/locatieserver/search/v3_1" MKDOCS_DIR = "/root/mkdocs/docs/docs/Huizenjacht" def geocode_adres(adres): """Geocode adres naar coördinaten via PDOK Locatieserver""" params = urllib.parse.urlencode({ 'q': adres, 'rows': 5, 'fl': 'centroide_ll,weergavenaam,postcode,woonplaatsnaam,type,huisnummer' }) url = f"{PDOK_BASE}/free?{params}" with urllib.request.urlopen(url, timeout=10) as resp: data = json.loads(resp.read()) if not data['response']['docs']: raise ValueError(f"Adres niet gevonden: {adres}") doc = None for d in data['response']['docs']: if d.get('type') == 'adres': doc = d break if not doc: doc = data['response']['docs'][0] point = doc['centroide_ll'] coords = point.replace('POINT(', '').replace(')', '').split() lon, lat = float(coords[0]), float(coords[1]) return { 'adres': doc.get('weergavenaam', adres), 'postcode': doc.get('postcode', ''), 'woonplaats': doc.get('woonplaatsnaam', ''), 'lat': lat, 'lon': lon } def haal_isochroon(lon, lat, profiel='driving-car', minuten=20): """Haal isochroon op van ORS""" url = f"{ORS_BASE}/isochrones/{profiel}" payload = { "locations": [[lon, lat]], "range": [minuten * 60], "attributes": ["area", "reachfactor", "total_pop"] } req = urllib.request.Request( url, data=json.dumps(payload).encode(), headers={'Content-Type': 'application/json'}, method='POST' ) with urllib.request.urlopen(req, timeout=30) as resp: return json.loads(resp.read()) def format_oppervlakte(m2): """Converteer m² naar leesbaar formaat""" if m2 >= 1_000_000: return f"{m2/1_000_000:.1f} km²" elif m2 >= 10_000: return f"{m2/10_000:.1f} ha" else: return f"{m2:.0f} m²" def schrijf_naar_mkdocs(content, adres, nummer, ext=".md"): """Schrijf content naar MkDocs docs map als bestand met oplopend nummer""" os.makedirs(MKDOCS_DIR, exist_ok=True) safe_name = re.sub(r'[^a-zA-Z0-9]+', '-', adres) safe_name = safe_name.strip('-') filename = f"{nummer}-{safe_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}{ext}" filepath = os.path.join(MKDOCS_DIR, filename) with open(filepath, 'w', encoding='utf-8') as f: f.write(content) return filepath, filename def genereer_isochroon_html(adres_naam, lat, lon, auto_iso, fiets_iso, voorzieningen=None): """Genereer een zelf-contained HTML kaart met Leaflet + POI markers""" # Bouw JSON voor POI markers poi_json = {"supermarkten": [], "scholen": []} if voorzieningen: for s in voorzieningen.get("supermarkten", []): poi_json["supermarkten"].append({ "naam": s.naam, "lat": s.lat, "lon": s.lon, "hemelsbreed": round(s.hemelsbreed_m), "fiets": f"{format_afstand(s.fiets_afstand_m)} / {format_duur(s.fiets_duur_s)}" if s.fiets_afstand_m else "n.b.", "auto": f"{format_afstand(s.auto_afstand_m)} / {format_duur(s.auto_duur_s)}" if s.auto_afstand_m else "n.b.", }) for s in voorzieningen.get("scholen", []): poi_json["scholen"].append({ "naam": s.naam, "lat": s.lat, "lon": s.lon, "hemelsbreed": round(s.hemelsbreed_m), "fiets": f"{format_afstand(s.fiets_afstand_m)} / {format_duur(s.fiets_duur_s)}" if s.fiets_afstand_m else "n.b.", "auto": f"{format_afstand(s.auto_afstand_m)} / {format_duur(s.auto_duur_s)}" if s.auto_afstand_m else "n.b.", }) html = f'''