fix(extract): Chunk-Ausgabe lauf-stabil, Eckenprüfung in beide Richtungen
emit.py normalisiert jede ausgegebene Fläche und sortiert die Listen nach der Ausgabestruktur selbst. unary_union() in apply_street() gab das kartenweite Straßenpolygon mit anderem Ringstartpunkt und an anderer Listenstelle zurück und änderte damit 88 Chunkdateien, in denen sich geometrisch nichts bewegt hatte (symmetrische Differenz 0,00 m²). Belagsarten und Mittellinien behalten ihre Reihenfolge: overview.py malt die Beläge in Listenreihenfolge übereinander, und vergeLampPoints() hängt an Reihenfolge und Laufrichtung der Mittellinien — Sortieren verschöbe dort 1.848 von 3.921 Laternen auf die andere Straßenseite. check_corners() misst gegen den Straßenrand statt gegen die Straßenfläche. Alle vier Ecken liegen in der Fahrbahn, ihr Flächenabstand ist 0,000 m; die alte Prüfung schlug deshalb nur an, wenn eine Straße sich zurückzieht. Eine nach innen verbreiterte Straße hätte apply_park() still auf das veraltete Viereck zurückgeschnitten. Die Parkwege werden am Parkviereck abgeschnitten — die runden Kappen von LineString.buffer() lagen mit 95,96 m² darüber hinaus, rund 41 m² davon sichtbar als Betonzungen auf den umgebenden Belägen. load_elements() prüft den OSM-Abzug so streng wie die Parkdatei, mit Dateiname statt nacktem KeyError. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a3504df43d
commit
3c74202b5e
10 files changed
+333
-102
No files matched your search
@@ -99,7 +99,7 @@ Bei D bleibt östlich der Anlage ein 37 m breiter Rasenstreifen.
|
||||
### OSM-Abruf (`tools/extract/osm.py`)
|
||||
|
||||
- Neues Skript, das von Hand aufgerufen wird: `cd tools/extract && uv run python osm.py`.
|
||||
- Es fragt die Overpass-API (`https://overpass-api.de/api/interpreter`, POST, User-Agent wie `tiles.py`) für den Kasten 25,7765–25,7885° N, −80,1425 bis −80,1325° O ab. Abgefragt werden Wege mit `highway`, `leisure`, `amenity=parking` und `building`, jeweils mit Geometrie.
|
||||
- Es fragt die Overpass-API (`https://overpass-api.de/api/interpreter`, POST, User-Agent wie `tiles.py`) für den Kasten 25,7812–25,7872° N, −80,1392 bis −80,1358° O ab (`BBOX` in `osm.py`; der ursprünglich hier genannte, größere Kasten holte weit über den Park hinaus). Abgefragt werden Wege mit `highway`, `leisure`, `amenity=parking` und `building`, jeweils mit Geometrie.
|
||||
- Es behält nur, was der Park braucht, und schreibt `tools/extract/data/osm/flamingo-park.json`:
|
||||
|
||||
```json
|
||||
@@ -184,7 +184,7 @@ alley_cut = [[1470, 644], [1496, 644], [1500, 600], [1506, 540], [1514, 460], [1
|
||||
|
||||
**Zeitpunkt:** in `run.py` nach Land, Belägen, Straßen, Mittellinien, Gebäuden mit Höhen und Palmen, vor den Chunk-Nutzlasten. So sehen Chunk-Dateien, Kollision, Minimap und Landemaske das Ergebnis.
|
||||
|
||||
**Sicherheitsprüfung vorab:** Jede Spielecke aus der Parkdatei muss höchstens 2 m neben einer Straßenfläche liegen. Sonst hat sich die Extraktion geändert, und der Lauf bricht mit einer Meldung ab.
|
||||
**Sicherheitsprüfung vorab:** Jede Spielecke aus der Parkdatei muss höchstens 2,5 m vom **Rand** einer Straßenfläche liegen. Sonst hat sich die Extraktion geändert, und der Lauf bricht mit einer Meldung ab. Gegen den Rand und nicht gegen die Fläche, weil alle vier Ecken heute in der Fahrbahn liegen (Flächenabstand 0,000 m): eine Prüfung auf die Fläche schlüge nur an, wenn eine Straße sich zurückzieht, und ließe eine nach innen verbreiterte Straße stillschweigend auf das veraltete Viereck zurückschneiden. Gemessen am Referenzstand `f32ea27`: 0,45 m (sw), 0,14 m (se), 1,46 m (ne), 1,14 m (nw).
|
||||
|
||||
### Schritt 1: Jefferson Avenue
|
||||
|
||||
@@ -286,7 +286,9 @@ Das Parkpolygon ist das Viereck aus den Spielecken.
|
||||
|
||||
## Tests
|
||||
|
||||
### pytest (`tools/extract/tests/test_park.py`)
|
||||
### pytest (`tools/extract/tests/test_park_config.py`, `test_park_fit.py`, `test_park_layout.py`, `test_park_street.py`, `test_park_apply.py`)
|
||||
|
||||
Die Umsetzung hat die hier als eine Datei geplanten Tests auf fünf aufgeteilt, eine je Abschnitt.
|
||||
|
||||
- **Einpassung:**
|
||||
- Die echte SW-Ecke landet `offset_u` Meter östlich der Spiel-SW-Ecke auf der Südkante, die echte NW-Ecke ebenso weit östlich der Spiel-NW-Ecke.
|
||||
@@ -307,8 +309,9 @@ Das Parkpolygon ist das Viereck aus den Spielecken.
|
||||
- Die Straße ist mit Mittellinie da, die beiden Gebäude sind weg.
|
||||
- `alley_cut` gehört nicht mehr zur Straßenfläche, die Fahrbahnen der Querstraßen bleiben unversehrt.
|
||||
- Frei gewordene Flächen sind `urban`.
|
||||
- **Parkdatei:** Jeder Formfehler bricht mit Dateiname und Feld ab. Liegt eine Spielecke weiter als 2 m von einer Straße, bricht der Lauf ab.
|
||||
- **`test_emit.py`:** Das Schema enthält `paths` und die neuen Flächenarten.
|
||||
- **Parkdatei:** Jeder Formfehler bricht mit Dateiname und Feld ab. Liegt eine Spielecke weiter als 2,5 m vom Rand jeder Straße, bricht der Lauf ab.
|
||||
- **OSM-Stand:** Fehlt `elements`, ist die Datei kein gültiges JSON oder fehlt einem Element `tags` oder `geometry`, bricht der Lauf mit demselben `ParkError` ab — mit Dateiname und dem Hinweis auf `osm.py`, statt mit einem nackten `KeyError`.
|
||||
- **`test_emit.py`:** Das Schema enthält `paths` und die neuen Flächenarten. Dieselbe Welt in anderer Listenreihenfolge und mit anderem Ringstartpunkt ergibt dieselbe Ausgabe; die Arten der Beläge und die Mittellinien behalten dabei ihre Reihenfolge.
|
||||
- **`test_overview.py`:** Wege und neue Flächenarten erscheinen im Kartenbild, die eingecheckten Kartendateien passen zu den eingecheckten Chunks.
|
||||
|
||||
### vitest
|
||||
@@ -336,8 +339,8 @@ Das Parkpolygon ist das Viereck aus den Spielecken.
|
||||
- **Farben und Tönung passen nicht:** Das wird im Browser abgestimmt, nicht still.
|
||||
- **Gemessen im Spiel** (Lauf am 2026-09-16):
|
||||
- Pipeline: 2 Wegflächen, 14 Flächen, 11 Gebäude, Jefferson Avenue 12 m breit; genau eine Warnung (`Zufahrt schneidet die Sperrfläche tribuene`, bekannt und gewollt).
|
||||
- Geänderte Chunks: nur die acht erwarteten `chunk_9_5`, `chunk_10_5`, `chunk_9_6`, `chunk_10_6`, `chunk_9_7`, `chunk_10_7`, `chunk_9_8`, `chunk_10_8`.
|
||||
- Tests: pytest 174 bestanden, vitest 199 bestanden / 3 übersprungen (der replaces-Test läuft jetzt für beide Orte nicht mehr, siehe `src/world/places.js`).
|
||||
- Geänderte Chunks: geometrisch nur die acht erwarteten `chunk_9_5`, `chunk_10_5`, `chunk_9_6`, `chunk_10_6`, `chunk_9_7`, `chunk_10_7`, `chunk_9_8`, `chunk_10_8` — auf Dateiebene dagegen alle 144. Das lag nicht an der Geometrie: `unary_union()` in `apply_street()` fasst das kartenweite Straßenpolygon neu zusammen, und GEOS gab es mit anderem Ringstartpunkt und an anderer Listenstelle zurück. In 88 Chunks änderte sich dadurch der Text von `roads`, ohne dass sich die Fläche bewegte (symmetrische Differenz 0,00 m²), in 48 weiteren kam nur der leere Schlüssel `"paths":[]` hinzu. Seit Fixrunde 3 normalisiert `emit.py` jede ausgegebene Fläche (`shapely.normalize`) und sortiert jede Liste nach der Ausgabestruktur selbst; die Chunkdateien ändern sich dadurch einmalig alle, danach nur noch die, in denen sich wirklich etwas ändert. Zwei Listen bleiben bewusst unsortiert bzw. unnormalisiert: die Belagsarten untereinander (`overview.py` malt sie in Listenreihenfolge übereinander) und die Mittellinien (`vergeLampPoints()` in `src/world/props.js` hängt an Reihenfolge und Laufrichtung).
|
||||
- Tests: pytest 174 bestanden (nach Fixrunde 3: 186), vitest 199 bestanden / 3 übersprungen (der replaces-Test läuft jetzt für beide Orte nicht mehr, siehe `src/world/places.js`).
|
||||
- Browser (1280 × 800, Debug-Seite mit sichtbarem Fenster, Median aus 31 Bildern):
|
||||
|
||||
| Blick | Draw Calls | Dreiecke | Bild | davon neue Schichten |
|
||||
|
||||
Reference in new issue
Block a user