v2.4 - Nummering + directe kaartlink (geen iframe)

This commit is contained in:
Hermes Agent
2026-06-25 09:03:14 +02:00
parent 60596c0510
commit d9da2964dd
2 changed files with 150 additions and 289 deletions
+61 -122
View File
@@ -8,19 +8,13 @@ Slaat rapport en HTML-kaarten op in /root/mkdocs/docs/docs/Huizenjacht/
import json import json
import sys import sys
import os import os
import re
import urllib.request import urllib.request
import urllib.parse import urllib.parse
import re
import base64
from datetime import datetime from datetime import datetime
import base64
from io import BytesIO from io import BytesIO
try:
from playwright.sync_api import sync_playwright
HAS_PLAYWRIGHT = True
except ImportError:
HAS_PLAYWRIGHT = False
try: try:
from PIL import Image from PIL import Image
HAS_PIL = True HAS_PIL = True
@@ -98,12 +92,12 @@ def format_oppervlakte(m2):
else: else:
return f"{m2:.0f} m²" return f"{m2:.0f} m²"
def schrijf_naar_mkdocs(content, adres, ext=".md"): def schrijf_naar_mkdocs(content, adres, nummer, ext=".md"):
"""Schrijf content naar MkDocs docs map als bestand""" """Schrijf content naar MkDocs docs map als bestand met oplopend nummer"""
os.makedirs(MKDOCS_DIR, exist_ok=True) os.makedirs(MKDOCS_DIR, exist_ok=True)
safe_name = re.sub(r'[^a-zA-Z0-9]+', '-', adres) safe_name = re.sub(r'[^a-zA-Z0-9]+', '-', adres)
safe_name = safe_name.strip('-') safe_name = safe_name.strip('-')
filename = f"{safe_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}{ext}" filename = f"{nummer}-{safe_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}{ext}"
filepath = os.path.join(MKDOCS_DIR, filename) filepath = os.path.join(MKDOCS_DIR, filename)
with open(filepath, 'w', encoding='utf-8') as f: with open(filepath, 'w', encoding='utf-8') as f:
@@ -119,10 +113,8 @@ def genereer_isochroon_html(adres_naam, lat, lon, auto_iso, fiets_iso):
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Isochroon - {adres_naam}</title> <title>Isochroon - {adres_naam}</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="" /> <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
<style> <style>
body {{ margin: 0; padding: 0; font-family: system-ui, -apple-system, sans-serif; }} body {{ margin: 0; padding: 0; font-family: system-ui, -apple-system, sans-serif; }}
#map {{ height: 100vh; width: 100vw; }} #map {{ height: 100vh; width: 100vw; }}
@@ -146,7 +138,7 @@ var autoLayer = L.geoJSON(autoGeojson, {{
style: {{ color: '#2563eb', weight: 2, fillColor: '#3b82f6', fillOpacity: 0.2 }}, style: {{ color: '#2563eb', weight: 2, fillColor: '#3b82f6', fillOpacity: 0.2 }},
onEachFeature: function(feature, layer) {{ onEachFeature: function(feature, layer) {{
var props = feature.properties; var props = feature.properties;
layer.bindPopup('<b>Auto 20 min</b><br>Oppervlakte: ' + (props.area/1000000).toFixed(1) + ' km\\u00b2<br>Reach factor: ' + props.reachfactor.toFixed(3)); layer.bindPopup('<b>Auto 20 min</b><br>Oppervlakte: ' + (props.area/1000000).toFixed(1) + ' km²<br>Reach factor: ' + props.reachfactor.toFixed(3));
}} }}
}}).addTo(map); }}).addTo(map);
@@ -154,7 +146,7 @@ var fietsLayer = L.geoJSON(fietsGeojson, {{
style: {{ color: '#16a34a', weight: 2, fillColor: '#22c55e', fillOpacity: 0.2 }}, style: {{ color: '#16a34a', weight: 2, fillColor: '#22c55e', fillOpacity: 0.2 }},
onEachFeature: function(feature, layer) {{ onEachFeature: function(feature, layer) {{
var props = feature.properties; var props = feature.properties;
layer.bindPopup('<b>Fiets 30 min</b><br>Oppervlakte: ' + (props.area/1000000).toFixed(1) + ' km\\u00b2<br>Reach factor: ' + props.reachfactor.toFixed(3)); layer.bindPopup('<b>Fiets 30 min</b><br>Oppervlakte: ' + (props.area/1000000).toFixed(1) + ' km²<br>Reach factor: ' + props.reachfactor.toFixed(3));
}} }}
}}).addTo(map); }}).addTo(map);
@@ -178,140 +170,87 @@ map.fitBounds(autoLayer.getBounds().extend(fietsLayer.getBounds()));
</html>''' </html>'''
return html return html
def maak_isochroon_screenshot(html_content, width=1280, height=900, resize_width=800, quality=70): def print_isochroon_sectie(titel, icoon, iso_data):
"""Genereer een JPEG screenshot van de HTML kaart, retourneer base64 string""" """Genereer isochroon sectie als tekst"""
if not HAS_PLAYWRIGHT: lines = []
return None, "Playwright niet geïnstalleerd" lines.append(f"{icoon} **{titel}**")
if not HAS_PIL:
return None, "Pillow niet geïnstalleerd"
import tempfile
# Write HTML to temp file
with tempfile.NamedTemporaryFile(mode='w', suffix='.html', delete=False, encoding='utf-8') as f:
f.write(html_content)
html_path = f.name
try:
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page(viewport={'width': width, 'height': height})
page.goto(f'file://{html_path}')
page.wait_for_timeout(2500) # Wait for tiles
png_bytes = page.screenshot(full_page=False)
browser.close()
except Exception as e:
os.unlink(html_path)
return None, f"Screenshot fout: {e}"
finally:
os.unlink(html_path)
# Compress to JPEG
img = Image.open(BytesIO(png_bytes))
ratio = resize_width / img.width
resize_height = int(img.height * ratio)
img = img.resize((resize_width, resize_height), Image.Resampling.LANCZOS)
buf = BytesIO()
img.save(buf, format='JPEG', quality=quality, optimize=True)
jpeg_bytes = buf.getvalue()
b64 = base64.b64encode(jpeg_bytes).decode('ascii')
return b64, None
def print_isochroon_sectie(titel, icoon, iso_data, rapport_lines=None):
"""Print isochroon sectie; optioneel ook toevoegen aan rapport_lines"""
text = f"{icoon} **{titel}**"
print(text)
if rapport_lines is not None:
rapport_lines.append(text)
if 'features' in iso_data and iso_data['features']: if 'features' in iso_data and iso_data['features']:
props = iso_data['features'][0]['properties'] props = iso_data['features'][0]['properties']
area_m2 = props.get('area', 0) area_m2 = props.get('area', 0)
reach = props.get('reachfactor', 0) reach = props.get('reachfactor', 0)
text = f"**Oppervlakte:** {format_oppervlakte(area_m2)}" lines.append(f"**Oppervlakte:** {format_oppervlakte(area_m2)}")
print(text) lines.append(f"**Reach factor:** {reach:.3f}")
if rapport_lines is not None:
rapport_lines.append(text)
text = f"**Reach factor:** {reach:.3f}"
print(text)
if rapport_lines is not None:
rapport_lines.append(text)
bbox = iso_data.get('bbox', []) bbox = iso_data.get('bbox', [])
if len(bbox) == 4: if len(bbox) == 4:
text = f"**Bereik:** {bbox[1]:.3f}°-{bbox[3]:.3f}°N, {bbox[0]:.3f}°-{bbox[2]:.3f}°E" lines.append(f"**Bereik:** {bbox[1]:.3f}°-{bbox[3]:.3f}°N, {bbox[0]:.3f}°-{bbox[2]:.3f}°E")
print(text)
if rapport_lines is not None:
rapport_lines.append(text)
else: else:
text = "❌ Geen isochroon data ontvangen" lines.append("❌ Geen isochroon data ontvangen")
print(text) lines.append("")
if rapport_lines is not None: return "\n".join(lines)
rapport_lines.append(text)
print()
if rapport_lines is not None:
rapport_lines.append("")
def genereer_rapport(adres_input): def genereer_rapport(adres_input):
"""Genereer volledig adres analyse rapport""" """Genereer volledig adres analyse rapport"""
rapport_lines = [] lines = []
def print_line(text=""): # Tel bestaande genummerde rapporten voor oplopend nummer
print(text) # Alleen bestanden die beginnen met cijfer-dash (bv. "1-Griendvelden...")
rapport_lines.append(text) alle_files = os.listdir(MKDOCS_DIR) if os.path.exists(MKDOCS_DIR) else []
genummerde_files = [f for f in alle_files if f.endswith('.md') and re.match(r'^\d+-', f)]
nummer = len(genummerde_files) + 1
print_line(f"📍 **Adres Analyse Rapport**") lines.append(f"# {nummer}. {adres_input}")
print_line(f"Gegenereerd: {datetime.now().strftime('%d-%m-%Y %H:%M')}") lines.append(f"*Gegenereerd: {datetime.now().strftime('%d-%m-%Y %H:%M')}*")
print_line() lines.append("")
print_line("🔍 Geocoding...") lines.append("## 🔍 Geocoding")
locatie = geocode_adres(adres_input) locatie = geocode_adres(adres_input)
print_line(f"**Adres:** {locatie['adres']}") lines.append(f"**Adres:** {locatie['adres']}")
print_line(f"**Coördinaten:** {locatie['lat']:.6f}, {locatie['lon']:.6f}") lines.append(f"**Coördinaten:** {locatie['lat']:.6f}, {locatie['lon']:.6f}")
print_line() lines.append("")
auto_iso = haal_isochroon(locatie['lon'], locatie['lat'], 'driving-car', 20) auto_iso = haal_isochroon(locatie['lon'], locatie['lat'], 'driving-car', 20)
fiets_iso = haal_isochroon(locatie['lon'], locatie['lat'], 'cycling-regular', 30) fiets_iso = haal_isochroon(locatie['lon'], locatie['lat'], 'cycling-regular', 30)
print_isochroon_sectie("Bereikbaarheid (Auto 20 min)", "🚗", auto_iso, rapport_lines)
print_isochroon_sectie("Bereikbaarheid (Fiets 30 min)", "🚲", fiets_iso, rapport_lines)
print_line("🏙️ **Voorzieningen dichtbij**") lines.append("## 🚗 Bereikbaarheid")
lines.append(print_isochroon_sectie("Auto (20 min)", "🚗", auto_iso))
lines.append(print_isochroon_sectie("Fiets (30 min)", "🚲", fiets_iso))
lines.append("## 🏙️ Voorzieningen dichtbij")
voorzieningen = analyse_voorzieningen(locatie['lon'], locatie['lat'], limit=5) voorzieningen = analyse_voorzieningen(locatie['lon'], locatie['lat'], limit=5)
print_line(format_voorzieningen_markdown("🛒 **Supermarkten**", voorzieningen['supermarkten'])) lines.append(format_voorzieningen_markdown("🛒 **Supermarkten**", voorzieningen['supermarkten']))
print_line() lines.append("")
print_line(format_voorzieningen_markdown("🏫 **Scholen**", voorzieningen['scholen'])) lines.append(format_voorzieningen_markdown("🏫 **Scholen**", voorzieningen['scholen']))
print_line() lines.append("")
# Genereer interactieve HTML kaart en sla op in MkDocs.map # Genereer interactieve HTML kaart en sla op in MkDocs
html_content = genereer_isochroon_html( html_content = genereer_isochroon_html(
locatie['adres'], locatie['lat'], locatie['lon'], auto_iso, fiets_iso locatie['adres'], locatie['lat'], locatie['lon'], auto_iso, fiets_iso
) )
html_filepath, html_filename = schrijf_naar_mkdocs(html_content, locatie['adres'], ext=".html") html_filepath, html_filename = schrijf_naar_mkdocs(html_content, locatie['adres'], nummer, ext=".html")
print_line(f"🗺️ **Interactieve kaart opgeslagen:** `{html_filepath}`")
# Genereer screenshot en embed in markdown # Voeg link toe aan markdown rapport (betrouwbaar via directe link)
b64_img, err = maak_isochroon_screenshot(html_content) lines.append("## 🗺️ Interactieve kaart")
if b64_img: lines.append(f"")
print_line("") lines.append(f"**[📍 Bekijk interactieve isochroon kaart]({html_filename})**{{:target=\"_blank\"}}")
print_line("**🗺️ Isochroon kaart (auto + fiets):**") lines.append("")
img_md = f"![Isochroon kaart](data:image/jpeg;base64,{b64_img})" lines.append("*Klik op de link om de kaart in een nieuw tabblad te openen. Hier kun je zoomen, pannen en de isochronen bekijken.*")
print_line(img_md) lines.append("")
else:
print_line(f"⚠️ Kon geen screenshot maken: {err}")
# Sla ook ruwe geojson op # Ruwe geojson
output_file = f"/tmp/isochronen_{datetime.now().strftime('%Y%m%d_%H%M%S')}.geojson" output_file = f"/tmp/isochronen_{datetime.now().strftime('%Y%m%d_%H%M%S')}.geojson"
with open(output_file, 'w') as f: with open(output_file, 'w') as f:
json.dump({'auto_20_min': auto_iso, 'fiets_30_min': fiets_iso}, f) json.dump({'auto_20_min': auto_iso, 'fiets_30_min': fiets_iso}, f)
print_line(f"💾 Ruwe isochroondata: `{output_file}`") lines.append("---")
print_line() lines.append("*Onderdelen: geocoding, isochronen, voorzieningen, interactieve kaart*")
print_line("---")
print_line("_Onderdelen: geocoding, isochronen, voorzieningen_")
# Schrijf rapport naar MkDocs map rapport_text = "\n".join(lines)
print_line()
md_filepath, md_filename = schrijf_naar_mkdocs('\n'.join(rapport_lines), locatie['adres'], ext=".md") # Print naar stdout
print_line(f"📝 **Rapport opgeslagen:** `{md_filepath}`") print(rapport_text)
# Sla op in MkDocs
md_filepath, md_filename = schrijf_naar_mkdocs(rapport_text, adres_input, nummer, ext=".md")
print(f"\n📝 Rapport opgeslagen: {md_filepath}")
if __name__ == '__main__': if __name__ == '__main__':
adres = sys.argv[1] if len(sys.argv) > 1 else "Griendvelden 14 Best" adres = sys.argv[1] if len(sys.argv) > 1 else "Griendvelden 14 Best"
+69 -147
View File
@@ -2,24 +2,19 @@
""" """
Adres Analyse - Rapport generator Adres Analyse - Rapport generator
Gebruikt PDOK voor geocoding, ORS voor isochronen/routes en PostGIS OSM-data voor voorzieningen. Gebruikt PDOK voor geocoding, ORS voor isochronen/routes en PostGIS OSM-data voor voorzieningen.
Slaat rapport ook op in Obsidian vault (map: huizenjacht). Slaat rapport en HTML-kaarten op in /root/mkdocs/docs/docs/Huizenjacht/
""" """
import json import json
import sys import sys
import os
import re
import urllib.request import urllib.request
import urllib.parse import urllib.parse
import re
import base64
from datetime import datetime from datetime import datetime
import base64
from io import BytesIO from io import BytesIO
try:
from playwright.sync_api import sync_playwright
HAS_PLAYWRIGHT = True
except ImportError:
HAS_PLAYWRIGHT = False
try: try:
from PIL import Image from PIL import Image
HAS_PIL = True HAS_PIL = True
@@ -31,8 +26,7 @@ from voorzieningen import analyse_voorzieningen, format_voorzieningen_markdown
# Config # Config
ORS_BASE = "http://192.168.1.71:9080/ors/v2" ORS_BASE = "http://192.168.1.71:9080/ors/v2"
PDOK_BASE = "https://api.pdok.nl/bzk/locatieserver/search/v3_1" PDOK_BASE = "https://api.pdok.nl/bzk/locatieserver/search/v3_1"
OBSIDIAN_BASE = "http://192.168.1.50:27123" MKDOCS_DIR = "/root/mkdocs/docs/docs/Huizenjacht"
OBSIDIAN_TOKEN = "90ec" + "6de948dc8ef7832fda3516fd900c7a3071dd526edf852ade145aa9daf637"
def geocode_adres(adres): def geocode_adres(adres):
"""Geocode adres naar coördinaten via PDOK Locatieserver""" """Geocode adres naar coördinaten via PDOK Locatieserver"""
@@ -98,28 +92,18 @@ def format_oppervlakte(m2):
else: else:
return f"{m2:.0f} m²" return f"{m2:.0f} m²"
def schrijf_naar_obsidian(rapport_text, adres, subpath="huizenjacht", ext=".md"): def schrijf_naar_mkdocs(content, adres, nummer, ext=".md"):
"""Schrijf rapport naar Obsidian vault""" """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 = re.sub(r'[^a-zA-Z0-9]+', '-', adres)
safe_name = safe_name.strip('-') safe_name = safe_name.strip('-')
filename = f"{subpath}/{safe_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}{ext}" filename = f"{nummer}-{safe_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}{ext}"
filepath = os.path.join(MKDOCS_DIR, filename)
content_type = "text/html" if ext == ".html" else "text/markdown" with open(filepath, 'w', encoding='utf-8') as f:
req = urllib.request.Request( f.write(content)
f"{OBSIDIAN_BASE}/vault/{filename}",
data=rapport_text.encode('utf-8'),
headers={
'Authorization': f'Bearer {OBSIDIAN_TOKEN}',
'Content-Type': content_type
},
method='POST'
)
with urllib.request.urlopen(req, timeout=10) as resp: return filepath, filename
if resp.status in [200, 204]:
return filename
else:
return None
def genereer_isochroon_html(adres_naam, lat, lon, auto_iso, fiets_iso): def genereer_isochroon_html(adres_naam, lat, lon, auto_iso, fiets_iso):
"""Genereer een zelf-contained HTML kaart met Leaflet""" """Genereer een zelf-contained HTML kaart met Leaflet"""
@@ -129,10 +113,8 @@ def genereer_isochroon_html(adres_naam, lat, lon, auto_iso, fiets_iso):
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Isochroon - {adres_naam}</title> <title>Isochroon - {adres_naam}</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" <link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" />
integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="" /> <script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
<style> <style>
body {{ margin: 0; padding: 0; font-family: system-ui, -apple-system, sans-serif; }} body {{ margin: 0; padding: 0; font-family: system-ui, -apple-system, sans-serif; }}
#map {{ height: 100vh; width: 100vw; }} #map {{ height: 100vh; width: 100vw; }}
@@ -156,7 +138,7 @@ var autoLayer = L.geoJSON(autoGeojson, {{
style: {{ color: '#2563eb', weight: 2, fillColor: '#3b82f6', fillOpacity: 0.2 }}, style: {{ color: '#2563eb', weight: 2, fillColor: '#3b82f6', fillOpacity: 0.2 }},
onEachFeature: function(feature, layer) {{ onEachFeature: function(feature, layer) {{
var props = feature.properties; var props = feature.properties;
layer.bindPopup('<b>Auto 20 min</b><br>Oppervlakte: ' + (props.area/1000000).toFixed(1) + ' km\u00b2<br>Reach factor: ' + props.reachfactor.toFixed(3)); layer.bindPopup('<b>Auto 20 min</b><br>Oppervlakte: ' + (props.area/1000000).toFixed(1) + ' km²<br>Reach factor: ' + props.reachfactor.toFixed(3));
}} }}
}}).addTo(map); }}).addTo(map);
@@ -164,7 +146,7 @@ var fietsLayer = L.geoJSON(fietsGeojson, {{
style: {{ color: '#16a34a', weight: 2, fillColor: '#22c55e', fillOpacity: 0.2 }}, style: {{ color: '#16a34a', weight: 2, fillColor: '#22c55e', fillOpacity: 0.2 }},
onEachFeature: function(feature, layer) {{ onEachFeature: function(feature, layer) {{
var props = feature.properties; var props = feature.properties;
layer.bindPopup('<b>Fiets 30 min</b><br>Oppervlakte: ' + (props.area/1000000).toFixed(1) + ' km\u00b2<br>Reach factor: ' + props.reachfactor.toFixed(3)); layer.bindPopup('<b>Fiets 30 min</b><br>Oppervlakte: ' + (props.area/1000000).toFixed(1) + ' km²<br>Reach factor: ' + props.reachfactor.toFixed(3));
}} }}
}}).addTo(map); }}).addTo(map);
@@ -188,147 +170,87 @@ map.fitBounds(autoLayer.getBounds().extend(fietsLayer.getBounds()));
</html>''' </html>'''
return html return html
def maak_isochroon_screenshot(html_content, width=1280, height=900, resize_width=800, quality=70): def print_isochroon_sectie(titel, icoon, iso_data):
"""Genereer een JPEG screenshot van de HTML kaart, retourneer base64 string""" """Genereer isochroon sectie als tekst"""
if not HAS_PLAYWRIGHT: lines = []
return None, "Playwright niet geïnstalleerd" lines.append(f"{icoon} **{titel}**")
if not HAS_PIL:
return None, "Pillow niet geïnstalleerd"
import tempfile
import os
# Write HTML to temp file
with tempfile.NamedTemporaryFile(mode='w', suffix='.html', delete=False, encoding='utf-8') as f:
f.write(html_content)
html_path = f.name
try:
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page(viewport={'width': width, 'height': height})
page.goto(f'file://{html_path}')
page.wait_for_timeout(2500) # Wait for tiles
png_bytes = page.screenshot(full_page=False)
browser.close()
except Exception as e:
os.unlink(html_path)
return None, f"Screenshot fout: {e}"
finally:
os.unlink(html_path)
# Compress to JPEG
img = Image.open(BytesIO(png_bytes))
ratio = resize_width / img.width
resize_height = int(img.height * ratio)
img = img.resize((resize_width, resize_height), Image.Resampling.LANCZOS)
buf = BytesIO()
img.save(buf, format='JPEG', quality=quality, optimize=True)
jpeg_bytes = buf.getvalue()
b64 = base64.b64encode(jpeg_bytes).decode('ascii')
return b64, None
def print_isochroon_sectie(titel, icoon, iso_data, rapport_lines=None):
"""Print isochroon sectie; optioneel ook toevoegen aan rapport_lines voor Obsidian"""
text = f"{icoon} **{titel}**"
print(text)
if rapport_lines is not None:
rapport_lines.append(text)
if 'features' in iso_data and iso_data['features']: if 'features' in iso_data and iso_data['features']:
props = iso_data['features'][0]['properties'] props = iso_data['features'][0]['properties']
area_m2 = props.get('area', 0) area_m2 = props.get('area', 0)
reach = props.get('reachfactor', 0) reach = props.get('reachfactor', 0)
text = f"**Oppervlakte:** {format_oppervlakte(area_m2)}" lines.append(f"**Oppervlakte:** {format_oppervlakte(area_m2)}")
print(text) lines.append(f"**Reach factor:** {reach:.3f}")
if rapport_lines is not None:
rapport_lines.append(text)
text = f"**Reach factor:** {reach:.3f}"
print(text)
if rapport_lines is not None:
rapport_lines.append(text)
bbox = iso_data.get('bbox', []) bbox = iso_data.get('bbox', [])
if len(bbox) == 4: if len(bbox) == 4:
text = f"**Bereik:** {bbox[1]:.3f}°-{bbox[3]:.3f}°N, {bbox[0]:.3f}°-{bbox[2]:.3f}°E" lines.append(f"**Bereik:** {bbox[1]:.3f}°-{bbox[3]:.3f}°N, {bbox[0]:.3f}°-{bbox[2]:.3f}°E")
print(text)
if rapport_lines is not None:
rapport_lines.append(text)
else: else:
text = "❌ Geen isochroon data ontvangen" lines.append("❌ Geen isochroon data ontvangen")
print(text) lines.append("")
if rapport_lines is not None: return "\n".join(lines)
rapport_lines.append(text)
print()
if rapport_lines is not None:
rapport_lines.append("")
def genereer_rapport(adres_input): def genereer_rapport(adres_input):
"""Genereer volledig adres analyse rapport""" """Genereer volledig adres analyse rapport"""
rapport_lines = [] lines = []
def print_line(text=""): # Tel bestaande genummerde rapporten voor oplopend nummer
print(text) # Alleen bestanden die beginnen met cijfer-dash (bv. "1-Griendvelden...")
rapport_lines.append(text) alle_files = os.listdir(MKDOCS_DIR) if os.path.exists(MKDOCS_DIR) else []
genummerde_files = [f for f in alle_files if f.endswith('.md') and re.match(r'^\d+-', f)]
nummer = len(genummerde_files) + 1
print_line(f"📍 **Adres Analyse Rapport**") lines.append(f"# {nummer}. {adres_input}")
print_line(f"Gegenereerd: {datetime.now().strftime('%d-%m-%Y %H:%M')}") lines.append(f"*Gegenereerd: {datetime.now().strftime('%d-%m-%Y %H:%M')}*")
print_line() lines.append("")
print_line("🔍 Geocoding...") lines.append("## 🔍 Geocoding")
locatie = geocode_adres(adres_input) locatie = geocode_adres(adres_input)
print_line(f"**Adres:** {locatie['adres']}") lines.append(f"**Adres:** {locatie['adres']}")
print_line(f"**Coördinaten:** {locatie['lat']:.6f}, {locatie['lon']:.6f}") lines.append(f"**Coördinaten:** {locatie['lat']:.6f}, {locatie['lon']:.6f}")
print_line() lines.append("")
auto_iso = haal_isochroon(locatie['lon'], locatie['lat'], 'driving-car', 20) auto_iso = haal_isochroon(locatie['lon'], locatie['lat'], 'driving-car', 20)
fiets_iso = haal_isochroon(locatie['lon'], locatie['lat'], 'cycling-regular', 30) fiets_iso = haal_isochroon(locatie['lon'], locatie['lat'], 'cycling-regular', 30)
print_isochroon_sectie("Bereikbaarheid (Auto 20 min)", "🚗", auto_iso, rapport_lines)
print_isochroon_sectie("Bereikbaarheid (Fiets 30 min)", "🚲", fiets_iso, rapport_lines)
print_line("🏙️ **Voorzieningen dichtbij**") lines.append("## 🚗 Bereikbaarheid")
lines.append(print_isochroon_sectie("Auto (20 min)", "🚗", auto_iso))
lines.append(print_isochroon_sectie("Fiets (30 min)", "🚲", fiets_iso))
lines.append("## 🏙️ Voorzieningen dichtbij")
voorzieningen = analyse_voorzieningen(locatie['lon'], locatie['lat'], limit=5) voorzieningen = analyse_voorzieningen(locatie['lon'], locatie['lat'], limit=5)
print_line(format_voorzieningen_markdown("🛒 **Supermarkten**", voorzieningen['supermarkten'])) lines.append(format_voorzieningen_markdown("🛒 **Supermarkten**", voorzieningen['supermarkten']))
print_line() lines.append("")
print_line(format_voorzieningen_markdown("🏫 **Scholen**", voorzieningen['scholen'])) lines.append(format_voorzieningen_markdown("🏫 **Scholen**", voorzieningen['scholen']))
print_line() lines.append("")
# Genereer interactieve HTML kaart en upload naar Obsidian # Genereer interactieve HTML kaart en sla op in MkDocs
html_content = genereer_isochroon_html( html_content = genereer_isochroon_html(
locatie['adres'], locatie['lat'], locatie['lon'], auto_iso, fiets_iso locatie['adres'], locatie['lat'], locatie['lon'], auto_iso, fiets_iso
) )
html_path = schrijf_naar_obsidian(html_content, locatie['adres'], subpath="huizenjacht", ext=".html") html_filepath, html_filename = schrijf_naar_mkdocs(html_content, locatie['adres'], nummer, ext=".html")
if html_path:
print_line(f"🗺️ **[Bekijk interactieve isochroon kaart]({html_path})**")
else:
print_line("⚠️ Kon interactieve kaart niet opslaan in Obsidian")
# Genereer screenshot en embed in markdown # Voeg link toe aan markdown rapport (betrouwbaar via directe link)
b64_img, err = maak_isochroon_screenshot(html_content) lines.append("## 🗺️ Interactieve kaart")
if b64_img: lines.append(f"")
print_line("") lines.append(f"**[📍 Bekijk interactieve isochroon kaart]({html_filename})**{{:target=\"_blank\"}}")
print_line("**🗺️ Isochroon kaart (auto + fiets):**") lines.append("")
img_md = f"![Isochroon kaart](data:image/jpeg;base64,{b64_img})" lines.append("*Klik op de link om de kaart in een nieuw tabblad te openen. Hier kun je zoomen, pannen en de isochronen bekijken.*")
print_line(img_md) lines.append("")
else:
print_line(f"⚠️ Kon geen screenshot maken: {err}")
# Sla ook ruwe geojson op (lokaal, niet in Obsidian) # Ruwe geojson
output_file = f"/tmp/isochronen_{datetime.now().strftime('%Y%m%d_%H%M%S')}.geojson" output_file = f"/tmp/isochronen_{datetime.now().strftime('%Y%m%d_%H%M%S')}.geojson"
with open(output_file, 'w') as f: with open(output_file, 'w') as f:
json.dump({'auto_20_min': auto_iso, 'fiets_30_min': fiets_iso}, f) json.dump({'auto_20_min': auto_iso, 'fiets_30_min': fiets_iso}, f)
print_line(f"💾 Ruwe isochroondata: `{output_file}`") lines.append("---")
print_line() lines.append("*Onderdelen: geocoding, isochronen, voorzieningen, interactieve kaart*")
print_line("---")
print_line("_Onderdelen: geocoding, isochronen, voorzieningen_")
# Schrijf rapport naar Obsidian rapport_text = "\n".join(lines)
print_line()
md_path = schrijf_naar_obsidian('\n'.join(rapport_lines), locatie['adres']) # Print naar stdout
if md_path: print(rapport_text)
print_line(f"📝 **Opgeslagen in Obsidian:** `{md_path}`")
else: # Sla op in MkDocs
print_line("⚠️ Obsidian upload mislukt") md_filepath, md_filename = schrijf_naar_mkdocs(rapport_text, adres_input, nummer, ext=".md")
print(f"\n📝 Rapport opgeslagen: {md_filepath}")
if __name__ == '__main__': if __name__ == '__main__':
adres = sys.argv[1] if len(sys.argv) > 1 else "Griendvelden 14 Best" adres = sys.argv[1] if len(sys.argv) > 1 else "Griendvelden 14 Best"