Folium-Karten: die Blockade war eine falsche Alternative

Der einzige Punkt, der in diesem Projekt je als "blockiert" gefuehrt wurde,
ist erledigt. Die Begruendung lautete: Die VRP-Instanz sei ein synthetisches
100 x 100-km-Raster ohne Geokoordinaten, eine echte Karte verlange also
ENTWEDER eine neue Instanz (und damit zwei Dutzend neue abgedruckte Zahlen)
ODER eine willkuerliche Verankerung.

Es gibt einen dritten Weg, und er ist exakt. Eine azimutal-aequidistante
Projektion um den Schwerpunkt des Rasters bildet die 17 Punkte so auf Laenge
und Breite ab, dass die Grosskreisdistanzen mit den Rasterdistanzen
uebereinstimmen:

  festes cos(Breite)        Median 0,360 %   Maximum 2,003 %
  cos der eigenen Breite    Median 0,351 %   Maximum 0,908 %
  azimutal-aequidistant     Median 0,000 %   Maximum 0,001 %

Ein Meter auf hundert Kilometer. Kein abgedruckter Wert aendert sich, die
Gesamtstrecke bleibt bei 619 km, das SVG ist byte-identisch geblieben.

Zwei Befunde stuetzten die Entscheidung: "100 x 100 km Raster" steht nur in
zwei Codekommentaren, nirgends im Fliesstext; und der didaktische Punkt der
Bildunterschrift - die sich kreuzenden Touren, die KEIN Fehler sind - wird auf
einer Karte deutlicher.

erzeuge_vrp_touren.py schreibt jetzt SVG UND Karte aus einem Lauf. Ein zweites
Skript haette erneut geloest, und die Routing-Bibliothek arbeitet heuristisch.
pruefe_projektion() bricht ab, wenn die Verzerrung 0,01 % ueberschreitet - die
Zahl im Buch wird bei jedem Lauf bewiesen.

Neu im Build: die Marke {karte:name}, aufgeloest zu einem <iframe> (Leaflets
Stylesheet soll nicht in die Buchseite greifen), im PDF zum Verweissatz - wie
bei {plotly:}. --check bewacht jetzt beide Markenarten auf Existenz der Datei;
gegengeprueft mit einer absichtlich falschen Marke.

Zwei Vorkehrungen, die ohne Messung nicht aufgefallen waeren:

* Folium vergibt jedem Element eine uuid4 - jeder Lauf erzeugte eine andere
  Datei. normalisiere() ersetzt sie durch fortlaufende Nummern; zwei Laeufe
  liefern jetzt dieselbe Pruefsumme.
* Folium bindet ZEHN CDN-Ressourcen ein (jQuery, Bootstrap, Glyphicons,
  FontAwesome, awesome-markers ...). Gebraucht werden ZWEI. leaflet.js und
  leaflet.css liegen jetzt in web_04/assets/, die uebrigen acht entfallen.
  Nachgeprueft: Die Karte benutzt ausschliesslich L.*-Aufrufe. Ohne Netz
  fehlen nur die Kacheln, Marker und Touren bleiben sichtbar.

Gegenrechnung an vier Strecken: Depot -> K1 misst auf der Karte 27,20 km, die
Distanzmatrix sagt 27 - die Differenz stammt aus deren int(), nicht aus der
Geographie.

Veroeffentlicht: 8 Dateien uebertragen, alle dreizehn HTTP-Proben richtig, die
Karte auf dem Server unter 200 erreichbar.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
dschlueter 2026-09-08 20:38:16 +02:00
commit 5d5bdb6508
19 changed files with 2521 additions and 5 deletions

View file

@ -188,6 +188,31 @@ eine einzige lange Zeile mit eingebetteten Leerzeichenketten, aus der Pandoc son
Codeblock macht. Genau daran waren alle vier Figuren kaputt, bis es die Schlussabnahme fand.
Im PDF steht stattdessen ein Hinweis auf die Website.
## Karten
`{karte:name}` bindet `bilder_04/karten/<name>.html` als `<iframe>` ein — anders als bei
Plotly **nicht** inline, weil Leaflets Stylesheet sonst in die Buchseite hineingriffe. Im PDF
steht wieder ein Hinweis auf die Website. `--check` prüft für beide Markenarten, dass die
Datei existiert.
Erzeugt werden die Karten von demselben `bilder_04/erzeuge_*.py`, das auch das zugehörige SVG
schreibt — **aus einem Lauf**, sonst zeigten die beiden Darstellungen bei einem heuristischen
Solver womöglich verschiedene Lösungen. Zwei Vorkehrungen in `erzeuge_vrp_touren.py` sind
übertragbar:
* **Byte-Reproduzierbarkeit:** Folium vergibt jedem Element eine `uuid4`. `normalisiere()`
ersetzt sie durch fortlaufende Nummern — dieselbe Sorgfalt wie `svg.hashsalt` bei den
matplotlib-Bildern.
* **Netzunabhängigkeit:** Von Foliums zehn CDN-Einbindungen bleiben die zwei gebrauchten,
umgeschrieben auf `../../assets/leaflet.*` (mitgeliefert in `web_04/assets/`); die übrigen
acht entfallen, weil die Karte nur `CircleMarker`, `PolyLine` und `Tooltip` benutzt. Ohne
Netz fehlen nur die Kartenkacheln.
**Die Instanz ist synthetisch und bleibt es.** `projiziere()` legt das 100 × 100-km-Raster
azimutal-äquidistant auf eine reale Region; `pruefe_projektion()` bricht ab, wenn die
Abstände dabei um mehr als 0,01 % verzerrt würden (gemessen: 0,001 %). Kein abgedruckter Wert
ändert sich dadurch — das war die Bedingung, unter der die Karte überhaupt möglich wurde.
---
## Veroeffentlichung