Commit Graph
61 Commits
Author SHA1 Message Date
knsoandClaude Sonnet 5 2d8f4e730c fix(extract): Kontraktion zieht jetzt alle anliegenden Kanten mit
_contract_short() ließ Kanten, die schon vorher am überlebenden Knoten
hingen, auf ihrer alten Koordinate stehen - nur die vom eingezogenen
Knoten umgehängten folgten dem neuen Mittelpunkt. Da Kontraktion beidseitig
Grad >= 3 voraussetzt, hat der überlebende Knoten danach immer mindestens
Grad 4, und _merge_chains() fasst nur Grad-2-Knoten an: Der Fehler konnte
sich nie von selbst heilen. Am heutigen Mosaik wirkungslos (die Funktion
greift dort kein einziges Mal), aber real für jeden Ausschnitt mit zwei
nahen Kreuzungen - genau der Fall, den die Funktion behandeln soll.

Dazu zwei Kleinigkeiten: _median_width() deckte den Kurzkanten-Fallback
(unter 2 * WIDTH_MARGIN) bisher nicht ab, und ein Kommentar in
_merge_chains() war ein Zeichen zu weit eingerückt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 01:52:19 +02:00
knsoandClaude Sonnet 5 f809eedf71 feat(extract): Graph säubern, Breite messen, Klasse bestimmen
Sackgassen unter 10 m sind Skelettfransen und fallen weg, Knoten mit nur
noch zwei Kanten lösen sich auf, Kreuzungen näher als 5 m werden eine. Die
Breite kommt aus der Distanztransformation ohne die ersten und letzten 8 m:
dort misst sie die Kreuzung, nicht die Straße.

Der Gegencheck am echten Mosaik deckte zwei Fälle auf, die kein
synthetischer Test zeigt: Ein Rohast ohne Kreuzungsanschluss liefert eine
Kante mit nur einem Stützpunkt (LineString verlangt 0 oder mehr als einen
Punkt), und ein Knoten mit Schleife plus Verbindungskante hat kein zweites
Ende zum Verketten. Beides fängt clean() jetzt ab, mit je einem
Regressionstest.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 01:16:13 +02:00
knsoandClaude Sonnet 5 3fe3cd5c45 feat(extract): Straßennetz als Graph aus dem Skelett
centerlines() verwirft alles unter 15 m und zerlegt das Netz damit an jeder
Kreuzung: von 3.038 Linienenden treffen sich nur 81. Der neue Graph lässt
das Skelett ungefiltert, macht aus den 5.970 Pixeln mit Grad >= 3 durch
Verschmelzen im Umkreis von 8 m die 862 Kreuzungen und hängt die Kanten
dort ein.

_skeleton_graph/_to_world in vectors.py sind jetzt öffentliche Schnittstelle
für roads.py (skeleton_graph/to_world); inpaint.py zieht seinen einzigen
Aufruf von skeleton_graph mit, sonst bräche dessen Import.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 00:36:40 +02:00
knsoandClaude Sonnet 5 505b1969ec feat(assets): Bordstein- und Gehwegtexturen aus dem Kit holen
modular_sidewalk_curb_kit (Just8, CC BY 4.0) liefert 2048er Karten für
Bordstein und Gehweg. Sie werden auf 1024 verkleinert und im Namensschema
der Poly-Haven-Texturen abgelegt, damit createMaterials() sie ohne
Sonderfall lädt. Das Kit selbst bleibt außerhalb des Repos; das Skript
überspringt den Schritt, wenn der Ordner fehlt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-17 00:18:46 +02:00
knsoandClaude Opus 5 3c74202b5e 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>
2026-09-16 13:43:01 +02:00
knsoandClaude Sonnet 5 b736afb7ff feat(world): Parkwege, Felder, Plätze, Pool und Parkplatz als eigene Schichten
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 08:34:43 +02:00
knsoandClaude Sonnet 5 e675e62a16 feat(extract): Minimap zeichnet Parkwege, Felder, Plätze, Pool und Parkplatz
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 08:20:44 +02:00
knsoandClaude Sonnet 5 305572620d fix(extract): Integrationstest hält die bekannte Zufahrt-Warnung fest statt Warnungen pauschal auszuschließen
Die Erwartung "keine Warnung" im Plan war überholt: Task 5 schneidet Sperrflächen
bewusst auch aus Zufahrten aus und warnt dabei, und am echten Stand quert die
Zufahrt zum Parkplatz die Tribuenen-Sperrflaeche. Der Test prueft jetzt die
Warnungsliste wortgenau, damit er weiterhin bei jeder neuen oder anderen
Warnung anschlaegt.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 08:06:17 +02:00
knsoandClaude Sonnet 5 442f5b2ada feat(extract): Flamingo Park in run.py, Parkwege in der Chunk-Ausgabe
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 08:00:07 +02:00
knsoandClaude Sonnet 5 2ef9e6774a feat(extract): Parkanlage in die Welt einsetzen, Palmen neu setzen, Ecken prüfen
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 07:44:48 +02:00
knsoandClaude Sonnet 5 cfc9fc0690 feat(extract): Jefferson Avenue als gerade Straße statt der Gasse
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 07:28:27 +02:00
knsoandClaude Sonnet 5 d756eccd77 fix(extract): Sperrflächen auch aus Zufahrtsflächen ausschneiden und davor warnen
Zufahrtsflächen (highway=service) wurden bisher ungeschnitten ausgegeben und nicht auf
Überschneidung mit Sperrflächen geprüft. Am echten Stand überlappte eine Zufahrt die
Sperrfläche "tribuene" um 42,17 m² ohne Schnitt und ohne Warnung. build_layout wendet
difference(blocked) jetzt auch auf Zufahrten an, die Warnschleife prüft Wege und
Zufahrten getrennt ("Parkweg schneidet ..." / "Zufahrt schneidet ...").

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 07:20:41 +02:00
knsoandClaude Sonnet 5 26aafbbbd5 feat(extract): Parkanlage aus OpenStreetMap mit Wegen, Flächen und Gebäuden
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 07:03:52 +02:00
knsoandClaude Sonnet 5 ad5d0468db feat(extract): Flamingo Park affin in den Spielpark einpassen
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 06:48:26 +02:00
knsoandClaude Sonnet 5 1b0011874e feat(extract): Parkdatei für Flamingo Park lesen und prüfen
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 06:35:15 +02:00
knsoandClaude Sonnet 5 3d4d8380c8 feat(extract): OpenStreetMap-Stand für Flamingo Park abrufen und ablegen
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 06:20:14 +02:00
knsoandClaude Sonnet 5 73a6df7f08 fix(extract): Hüllrechteck ohne Zusatzpunkte auf den Kanten
_sides() und _place_rows() nehmen die ersten vier Ringpunkte eines Rechtecks
als seine Ecken. GEOS setzt nach dem Puffern je nach Plattform zusätzliche
Punkte mitten auf die Kanten (macOS 0, Windows 2), und dann messen beide die
falschen Kanten: ergänzte Gebäude bekamen unter entfernten Beschriftungen eine
falsche Größe und eine falsche Richtung. simplify(0) entfernt genau diese
Punkte und lässt die Form unverändert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 05:54:22 +02:00
knsoandClaude Sonnet 5 aa699b1585 fix(test): zwei plattformabhängige Tests unter Windows neutral
GEOS setzt bei entarteten Eingaben je nach Plattform zusätzliche Punkte auf
eine Kante, und fileURLToPath liefert unter Windows Backslashes. Beide Tests
prüfen jetzt, was sie meinen: die Ecken des Rechtecks und den Ort im Baum.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-16 05:43:43 +02:00
knsoandClaude Opus 5 780e246fe5 Merge branch 'leonida/tribuene'
Tribüne im Park J6 statt des alten Gebäudekastens, mit Materialrollen,
ersetzten Grundrissen beim Chunk-Aufbau und Asset-Test je Ort.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-15 21:26:58 +02:00
knso a55dca5fb6 start 2026-09-15 21:05:18 +02:00
knsoandClaude Sonnet 5 ae0f6106bb feat(world): Materialrollen der Tribüne, Asset-Test je Ort
Fest: Sichtbeton, Estrich, Verkleidung, Stahl, Trapezblech, Riffelblech, Verglasung, utility_box_01. Nahflächen: Sichtbeton, Estrich, Verkleidung, Stahl, Sitzschale. Kabel, Kabeldosen, Wandleuchten und Kästen auf 0,25. Der Asset-Test prüft jede Datei aus PLACES gegen ihre eigene Zeile fester Materialien statt gegen die ganze globale Liste, Bump nur beim Hood Yard.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 20:24:09 +02:00
knsoandClaude Sonnet 5 23a0623898 fix(assets): Zielpfad der Aufbereitung unabhängig vom Arbeitsverzeichnis
places.mjs schrieb bisher nach public/models/places/<id>.glb relativ
zu process.cwd() und nahm jede id ungeprüft an. Die neue, exportierte
placeTarget(id) löst den Pfad stattdessen von import.meta.url ab (egal
von wo das Skript aufgerufen wird) und lehnt IDs außerhalb von
[a-z0-9-]+ ab, bevor daraus ein Pfad wird, der aus public/models/
places/ herausführen könnte.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 13:41:18 +02:00
knsoandClaude Haiku 4.5 6c291c4106 feat(assets): Aufbereitung für Orte mit Texturgrößen je Material und Vereinfachung
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-09-14 10:49:31 +02:00
knsoandClaude Opus 5 0ebe8adb8b feat(assets): EXT_materials_bump für gltf-transform
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-14 10:39:39 +02:00
knsoandClaude Opus 5 dac19fa1ee feat(extract): alle Kartenbeschriftungen entfernt und Welt neu erzeugt
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 20:03:09 +02:00
knsoandClaude Opus 5 f098fe14b7 feat(extract): Beschriftungen suchen, Liste auf Vollständigkeit prüfen, Prüfbilder
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 19:38:14 +02:00
knsoandClaude Opus 5 b219013bbf feat(extract): Beschriftungen in run.py entfernen, Minimap am Ende erzeugen
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 19:30:51 +02:00
knsoandClaude Opus 5 97ff63b2b6 feat(extract): Beschriftungsmasken, Gitternetz und Entfernen mit Bericht
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 19:15:32 +02:00
knsoandClaude Opus 5 ce93e57936 feat(extract): angeschnittene Gebäude schließen und verdeckte Blockteile bebauen
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 19:08:53 +02:00
knsoandClaude Opus 5 368ea90b3a feat(extract): Wiederaufbau von Straßen, Wegen und Flächen unter Beschriftungen
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 18:37:05 +02:00
knsoandClaude Opus 5 c9e0615a88 feat(extract): Chunk-Zuordnung in Python und Beschriftungsliste lesen
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 18:27:33 +02:00
knsoandClaude Opus 5 f76e97b69d feat(world): HDRI-Himmel „Nowhere Road" mit Umgebungslicht und scharfen Kaskaden-Schatten
- Himmel: 4k-HDRI von Poly Haven (CC0, tools/assets/hdri.mjs) statt Sky-Shader. Kuppel zeigt das Foto
  ab 12°, darunter weiches Band und Dunst in Nebelfarbe; Umgebungslicht und Spiegelungen per PMREM;
  Sonne aus dem Bild gekappt und als Licht übernommen (77°, Stärke 2,5)
- Schatten: CSM mit vier Stufen (25/100/350/1000 m, je 2048²), Schutznetz für beleuchtete Materialien,
  Normal-Bias 1,5 Texel je Stufe gegen Streifen auf doppelseitigen Materialien (Figur, Autos)
- Startfigur wirft Schatten, Palmen und Laternen empfangen Schatten, Wasser als ruhige See
- Debug-Panel: Sonne, Himmelslicht, Himmelshelligkeit; Namensnennung um das HDRI ergänzt

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 15:38:44 +02:00
knsoandClaude Sonnet 5 dd5ced505b fix(ui): Landeplatz nur auf ganzem Kollisionsboden, Trackpad-Zoom, Fokus und Ladefehler der Minimap
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 12:47:51 +02:00
knsoandClaude Haiku 4.5 40fc38059a test(extract): Begehbarkeitsmaske je Ebene ohne Land darunter prüfen
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-09-13 10:44:18 +02:00
knsoandClaude Sonnet 5 0b0376e564 feat(extract): Kartenbild, Begehbarkeitsmaske und map.json für die Minimap
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 10:03:29 +02:00
knsoandClaude Haiku 4.5 f0f7692f14 fix(coords): Chunk-Namen korrekt für Float-Indizes und Newlines
- chunk_name: Reject float/bool indices like JavaScript (Number.isInteger)
- parse_chunk_name: Use fullmatch instead of match($) to reject strings with trailing newlines
- Add invalidIndices fixture cases to catch these edge cases in both languages

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-09-13 09:49:53 +02:00
knsoandClaude Haiku 4.5 2f63779363 feat(coords): Chunk-Namen als Planquadrat A1 bis L12
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-09-13 09:26:59 +02:00
knsoandClaude Sonnet 5 30cf64642b fix(extract): Mindestbreite gegen papierdünne und wandartige Gebäudegrundrisse
727 von 2.286 rohen Grundrissen (31,8 %, aber nur 1,8 % der bebauten Fläche) sind
unter 4 m an der kurzen Seite ihres gedrehten Hüllrechtecks — extrudiert werden
daraus Wände, keine Häuser. Eine Mindestbreite allein reicht nicht: einzelne Formen
bleiben bei >= 4 m Breite trotzdem extrem lang und dünn (z.B. 4,27 m x 153 m,
Verhältnis 35,9). MAX_ASPECT_RATIO=12 ergänzt die Mindestbreite MIN_BUILDING_WIDTH=4,
an einer echten Lücke in den gemessenen Verhältnissen festgemacht (größte plausible
große Grundfläche: Verhältnis 10,8 bei 7.196 m²; nächste eindeutig wandartige Form:
Verhältnis 12,0 bei 60,5 m²). Zusammen fallen 766 Grundrisse (33,5 %, 36.986 m² =
3,3 % der Fläche) weg.

Bestehende Fixture in test_small_staircase_building_is_not_dropped vergrößert (4x4-
auf 6x6-Block): ihre kurze Seite lag zufällig bei ~3,7 m, unter der neuen Schwelle,
und hätte den Test sonst für den falschen Grund bestehen lassen (Ruling 74 statt
Ruling 28).

Pipeline neu durchgelaufen: eindeutige Gebäude 2.282 -> 1.520 (-33,4 %), Dreiecke
über alle 144 Chunks 327.181 -> 307.678 (-6,0 %, vollständig aus der Gebäude-Ebene),
public/data/vice-a 2,73 M -> 2,50 M.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 05:14:42 +02:00
knsoandClaude Sonnet 5 d6a2f6d269 fix(world): Laternen vom Fahrbahnrand versetzt, ungenutzte Requisiten entfernt
Ruling 60: vergeLampPoints sucht von 6 bis 16 m nach außen und verwirft eine
Laterne ganz, wenn keiner der sechs Abstände die Straßenpolygone des Chunks
verlässt (Punkt-in-Polygon mit Löchern, pointInPolygon). Ruling 61: die vier
nie platzierten Requisiten (Bank, Mülleimer, Hydrant, Absperrung) fliegen aus
props.mjs und aus dem Repository, ~18 MB auf 1,9 MB im Arbeitsverzeichnis.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 01:28:43 +02:00
knsoandClaude Sonnet 5 9173400caa feat(world): Palmen und Requisiten als Instanzen mit Stammkollision
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 01:05:55 +02:00
knsoandClaude Sonnet 5 fb0d19c2e5 feat(world): Poly-Haven-Materialien, Wasser, Himmel und mitlaufende Schatten
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 22:43:14 +02:00
knsoandClaude Sonnet 5 dce90a2263 feat(world): Geometrie-Baustein für Land, Straßen, Brücken und Gebäude
Normalisiert Ringe vor der Triangulierung: ShapeUtils.triangulateShape
verlangt echte Vector2 (nicht {x,y}-Objekte) wegen des internen
Vector2#equals-Aufrufs, und jeder extrahierte Ring schließt sich selbst
(letzter Punkt == erster). Ohne vorheriges Entfernen dieses Schlusspunkts
verschieben sich ab dem ersten Loch alle Dreiecksindizes um eins gegenüber
der von ShapeUtils intern neu vergebenen Nummerierung — Häuser und Straßen
mit Innenhof bekämen an genau der Stelle falsch verdrahtete Dreiecke, ohne
dass die Dreieckszahl sich ändert. Beide Fehler traten mit den Testquadraten
aus dem Task-Brief nicht auf, weil deren Ringe offen sind; die echten
Chunk-Dateien schließen aber ausnahmslos jeden Ring.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 19:23:30 +02:00
knsoandClaude Sonnet 5 70c35faf86 test(extract): Verschmelzungsfall und Schwellenwert von drop_map_labels absichern
Ruling 43: beruehren sich Schriftzug und echte Flaeche (z.B. eine Mole), bilden sie eine
Komponente und bleiben beide stehen - dieselbe vorsichtige Richtung wie bei Beschriftungen
auf dem Festland, lieber ein Buchstabe zu viel als eine Mole zu wenig.
Ruling 44: ein Tippfehler in LABEL_MAX_NATURAL (0.2 statt 0.02) faellt jetzt in einem Test auf,
der knapp oberhalb der Schwelle liegt.
MAINLAND_MIN_SIZE-Kommentar auf zwei Saetze gekuerzt (Stil wie LAND_REACH_PX/PALM_VERGE),
Wortdopplung im Docstring entfernt. Kein Verhalten geaendert: 41 statt 39 Tests, beide neuen
Tests waren vor jeder Aenderung bereits gruen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 19:22:25 +02:00
knsoandClaude Sonnet 5 f3abb5e803 fix(extract): Kartenbeschriftung nicht mehr als Geometrie ausgeben
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 17:59:54 +02:00
knsoandClaude Opus 5 0bf2c29061 fix: leere Zusicherung und mutierende Ringumkehr
Die Zusicherung im Löcher-Test stand mit "or True" in meiner eigenen
Fix-Vorgabe und prüfte damit nichts; ersetzt durch zwei Zusicherungen,
die die Lage des Lochs im Außenring tatsächlich belegen.

Im Planentwurf zu Task 7 hätte clockwise(hole).reverse() die Eingabe des
Aufrufers verändert, weil clockwise() denselben Array zurückgibt, wenn
der Ring schon passt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 17:41:43 +02:00
knsoandClaude Opus 5 857121e5fb tools: Löcher in der Gesamtansicht korrekt zusammensetzen
Ein Loch mit Wasserfarbe zu übermalen war falsch — der Innenhof eines
Blocks liegt auf Stadtfläche, nicht im Wasser. Die Fläche wird jetzt über
eine Maske eingesetzt, sodass durch die Löcher die Ebene darunter bleibt.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 17:28:35 +02:00
knsoandClaude Sonnet 5 22ac8f530c fix(extract): Polygonlöcher im Chunk-Payload erhalten, split_by_chunk_all abdecken
Ruling 34 (Important, Fix-Runde 1 zu Aufgabe 6): _ring() verwarf jedes Loch
eines Polygons (nur poly.exterior wurde in Weltkoordinaten -> three.js
uebertragen). Vor dem Chunk-Zuschnitt war das meist harmlos, weil das
groesste Loch die Bucht selbst ist und beim Zuschneiden ohnehin herausfaellt
- danach blieb es aber ein echter Datenverlust: ein von Strassen umschlossener
Block wurde zu Asphalt, ein Innenhof zu Gebaeudemasse, ein Teich im Park zu
Wiese. Gemessen an echten Daten: 120 Strassen-Chunk-Stuecke (449.876 m2),
127 Stadtflaechen-Stuecke (208.657 m2 wobei 1 weiteres Park-Stueck), 30
Land-Stuecke (11.402 m2) und mindestens 75 Gebaeude-Stuecke trugen ein
verworfenes Loch.

_ring() wird _rings(): liefert [poly.exterior, *poly.interiors] in derselben
Transformation, Aussenring zuerst. Payload-Schema aendert sich entsprechend
fuer land/surfaces/roads/buildings von einem flachen Ring zu einer Liste von
Ringen; centerlines und palms sind unveraendert (keine Polygone). Task 7s
extrudePolygons() ruft ShapeUtils.triangulateShape(ring, []) bereits mit
einem (bisher leeren) Loecher-Array - die Aenderung passt jetzt durchgehend,
bevor Aufgabe 7 gebaut wird. write_debug_png() zeichnet weiterhin nur den
Aussenring (poly[0]), Loecher werden im Debug-Bild nicht dargestellt.

Neuer Test test_polygon_holes_survive_into_the_payload prueft das direkt an
einem Block mit Loch; die Koordinaten wurden vor dem Festschreiben gegen die
tatsaechliche chunk_payload()-Transformation nachgerechnet (uv run python,
nicht nur von Hand). test_coordinates_are_chunk_local_three_js musste auf
das neue [0]-Aussenring-Indexing angepasst werden.

Ruling 35 (Important): split_by_chunk_all() - die Variante, die run.py
tatsaechlich benutzt, nicht das getestete split_by_chunk() - hatte einen
MultiPolygon-Zweig ohne jede Testabdeckung. Neuer Test mit einer Klammerform
(Steg ausserhalb der Chunk-Zelle, zwei Zinken je einmal hineinreichend)
trifft genau diesen Zweig gezielt; er war schon vor der Aenderung gruen -
bestaetigt als Abdeckungsluecke, nicht als Bug.

uv run pytest -v: 36 passed (34 zuvor + 2 neu).

Pipeline (run.py) am gecachten Mosaik neu durchlaufen: weiterhin 144
Chunk-Dateien, public/data/vice-a/ jetzt 2,7 MB (zuvor 2,5 MB; +0,2 MB fuer
die erhaltenen Loecher). Insgesamt tragen jetzt 415 Chunk-Stuecke mindestens
ein Loch: Land 30/213, Stadtflaechen 127/1145 (+1 Park-Flaeche), Strassen
120/953, Gebaeude 137/2859 (80 global-eindeutige Gebaeude vor
Chunk-Duplizierung). Land/Strassen/Stadtflaechen treffen die oben genannten
Referenzwerte exakt; bei Gebaeuden weicht die Stueckzahl vom Review-Befund
(75) ab. Stichprobe der vier flaechenmaessig groessten Gebaeude-Loecher
(Debug-PNGs chunk_8_0, chunk_2_10, chunk_5_11 sowie ein viertes) zeigt
plausible echte Ring-Bauwerke (ein stadionartiger Rundbau, eine
Wendel-Parkrampe) statt offensichtlicher Fehlklassifikation - die
verbleibende Abweichung duerfte an der bereits im Task-6-Bericht
offengelegten Restunsicherheit der Gebaeude-Ueberlappungsrekonstruktion
liegen (263 vs. 258 spekulative Gebaeude), nicht an dieser Aenderung; im
Fix-Bericht dokumentiert.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 17:23:31 +02:00
knsoandClaude Opus 5 062a9af2fd docs: Task 6b für die Kartenbeschriftung, Löcher in Task 7
Die Sichtprüfung nach Task 6 hat gezeigt, dass die Beschriftungen der
Originalkarte zu Geometrie werden — "VICE CITY (MIAMI)" steht als 1.600 m
breiter Schriftzug in der Bucht. Task 6b entfernt sie, bevor Task 7 daraus
Meshes baut. Der Brief nennt drei gemessene Sackgassen (Buntheit, Farbton,
Zusammenhang nur der Straßenmaske) und den Weg, der trägt: auf Regionenebene
über alle Nicht-Wasser-Klassen, wo die Buchstaben eigene Inseln ohne jedes
natürliche Merkmal bilden.

extrudePolygons und flatPolygons in Task 7 verarbeiten jetzt Ringlisten mit
Löchern statt einzelner Ringe, passend zu Ruling 34.

overview.py rendert den ganzen Ausschnitt aus den Chunk-Dateien; damit ist
der Beschriftungsfehler überhaupt erst aufgefallen.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 17:19:28 +02:00
knsoandClaude Sonnet 5 ce90ea1d5f feat(extract): Chunk-Ausgabe, Manifest und Ablaufsteuerung
Task 6: leonida/emit.py (chunk_box, split_by_chunk, chunk_payload und die
Chunk-lokalen three.js-Koordinaten, write_chunks, write_debug_png) sowie
run.py als Ablaufsteuerung, die alles aus den Tasks 3-5 zu 144 Chunk-Dateien
und einem Manifest unter public/data/vice-a/ zusammenfuehrt.

Zwei Abweichungen vom Referenzcode der Aufgabe, beide durch Gegenrechnen
gegen die dort genannten Realwerte gefunden:

- test_emit.py::test_coordinates_are_chunk_local_three_js gab im Original
  das ungeschnittene BIG (spannt vier Chunks) direkt an chunk_payload();
  chunk_payload() clippt selbst nicht (das tut in run.py split_by_chunk_all
  vorher), darum lag der Rand bei x=300 statt <=250 und der Test schlug mit
  dem gegebenen Code fehl. Fix: BIG vor dem Aufruf mit split_by_chunk auf
  Chunk (0,0) zuschneiden, wie es run.py fuer "land" ohnehin tut.

- run.pys Filter "Gebaeude, die zu >50% in einem Strassenpolygon liegen,
  gelten als Strasse" pruefte im Original ALLE rohen Gebaeude gegen
  road_polygons(labels) direkt. road_polygons() zaehlt "spekulativ" selbst
  zu den Strassenklassen (ROAD_CLASSES) und schliesst zusaetzlich mit
  disk(3) gegen Strassennamen; ein isoliertes "spekulativ"-Gebaeude
  ueberlappt sich darueber praktisch mit sich selbst. Ergebnis am realen
  Mosaik: von 267 rohen spekulativen Gebaeuden ueberlebten nur 3 (statt der
  in der Aufgabe genannten Groessenordnung von 258), und die Schliessung
  riss zusaetzlich 211 gewoehnliche graue Gebaeude mit heraus, die die
  Notiz aus Task 5 ausdruecklich nicht meinte ("die ROTEN Flaechen ...
  werden abgezogen"). Fix: eigenes, unzweideutiges Strassenmass nur aus
  "strasse"/"weg" (ohne "spekulativ", ohne Namens-Schliessung), Pruefung
  nur auf spekulative Kandidaten begrenzt. Ergebnis: 2.348 Gebaeude, davon
  263 spekulativ (Aufgabe: 2.352 bzw. 258) - Wahrzeichenhoehen (68 Stueck,
  31-248 m) und Palmenzahl (2.133) treffen die genannten Referenzwerte exakt.

Pipeline-Lauf am gecachten Mosaik: 144 Chunk-Dateien + Manifest, 2,5 MB
gesamt (Budget 10 MB), groesste Datei chunk_9_1.json/chunk_10_1.json mit
je 40 KB. Alle drei Toleranzgrenzen (wasser/strasse/gebaeude) eingehalten.
Debug-PNGs stichprobenartig gesichtet: Kuestenlinie, Strassennetz
(inklusive Kreuzungen und einer Auffahrt-Rampe) und ein Strand mit
Palmenreihe liegen deckungsgleich auf dem Mosaik; der wasserreine Chunk
(4,10) zeigt korrekt keine Vektoren.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 16:53:18 +02:00
knsoandClaude Opus 5 2c355aa3d8 data(extract): Wahrzeichen und Viertel für den Ausschnitt
skyline.json: die 54 Wahrzeichen im Ausschnitt aus rolux/gtamaplib-vc
(Unlicense, Commit 98b858f), reduziert auf name, id, xyz und height.
Texturen bleiben ausgeschlossen, das sind Spiel-Screenshots.

districts.json ist selbst erstellt — in gtadb gibt es keine Viertel.
Downtown und Ocean Beach sind aus den Wahrzeichen abgeleitet, dazu fünf
Suburbs-Punkte, damit die Vorstadt nicht Downtown-Höhen bekommt.

Der Plan sagte bisher nur "wird hier heruntergeladen", ohne Quelle und
Schema; das ist jetzt dokumentiert, samt korrigierter Lizenzangabe.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 16:31:09 +02:00