Files
gta6/docs/superpowers/specs/2026-09-16-strassen-design.md
T
knso 349212fedf test(extract): festgehaltene Zahlen auf den Fixwelle-Stand gebracht, Markierung-auf-Fahrbahn abgesichert
Befund 9: Nach dem Pipeline-Lauf mit den Befunden 3-8 geänderte Zahlen in
test_committed_roads.py eingetragen (Restflächen 169 statt 171,
Markierungsstücke haltelinie 1.555/zebra 14.846 statt 1.553/14.832,
Flächen Gehweg 0,2987/Restflächen 0,0967 statt 0,2982/0,0972 km² -
Bordstein, Fahrbahn und Kantenstücke je Klasse bleiben unverändert, weil
keiner der Befunde am Graphen oder an carriageway/curb rührt) sowie den
Messwerte-Absatz „Gemessen nach der Fixwelle" im Entwurf ergänzt. Beide
Abnahmen erneut bestanden: zweiter Lauf ändert keine Datei, beide Suiten
grün.

Befund 10: Neuer Test test_markierung_liegt_nicht_wesentlich_ausserhalb_
der_fahrbahn haelt fest, wie viel Markierungsflaeche ausserhalb der
Fahrbahn liegt. Rechnerisch gegen die Daten vor der Fixwelle nachgewiesen,
dass er vor Befund 3 mit 452,65 m² weit über jeder sinnvollen Schranke rot
gewesen waere. Die Schranke (130 m²) ist kein reiner Rundungswert: Befund
3 senkt den echten Wert auf 110,06 m² (0,25 % von 43.906 m²), behebt das
Problem aber nicht vollständig - ein Bogen kann zwischen reach und
reach + STOP_SETBACK + STOP_DEPTH noch einmal abknicken, was die
umgesetzte Korrektur nicht auffängt. Das ist im Test-Docstring und im
Fixwelle-Bericht offengelegt, nicht stillschweigend toleriert.
2026-09-18 07:55:55 +02:00

27 KiB
Raw Blame History

Straßen mit Bordstein, Gehweg und amerikanischer Markierung — Entwurf

Datum: 2026-09-16 Zusammenhang: Teil 2 der Arbeit, die der Nutzer im selben Auftrag wie Flamingo Park bestellt hat: „dass die Straßen die bereits existieren gerade Linien haben und richtig wie Straßen aussehen nicht wie abgehackte Stücke", dazu Bordsteine und „richtig schöne amerikanische Straßenmarkierungen". Teil 1 (2026-09-15-flamingo-park-design.md) ist auf main gemergt. Baut auf: 2026-09-12-leonida-vice-slice-design.md (Extraktion, Chunk-Format), 2026-09-13-minimap-design.md (overview.py), 2026-09-15-flamingo-park-design.md (Parkwege, normalisierte Chunk-Ausgabe).

Ziel

Jede Straße im Spiel hat gerade Kanten, einen Bordstein und einen Gehweg, und auf der Fahrbahn stehen die Markierungen, die eine amerikanische Stadt ausmachen. Die Straßen entstehen dafür nicht mehr als nachgezeichnete Rasterkontur, sondern aus einem Graphen mit Mittellinie, Breite und Klasse. Der Stadtgrundriss bleibt, wo er ist; Kollision, Minimap, Laternen und Palmen ziehen mit.

Befund (gemessen)

Warum die Straßen abgehackt aussehen

road_polygons() in tools/extract/leonida/vectors.py baut eine Maske aus den Klassen strasse, weg und spekulativ, schließt sie mit disk(3), verfolgt die Kontur auf dem 1-px/m-Raster und vereinfacht um 0,8 m. Jede schräge Kante wird dabei zur Treppe. Am Ergebnis hängt alles Weitere: Kollision, Minimap, Palmenabstand.

Das Netz heute

Größe Wert
Straßenfläche 1,332 km² (15 % der Karte), 335 Polygone, davon 11 Brücken
centerlines() 1.519 Linien, 88,74 km, Median 35,1 m, p90 119,7 m, längste 756,3 m
Stützpunkte 5.041 gesamt, Median 3 je Linie
Krummheit (Länge ÷ Luftlinie) Median 1,0104, p90 1,0985; 584 Linien über 1,02, 150 über 1,10
Breite entlang der Mittellinie Median 13,42 m, Mittel 13,64 m, p10 4,0 m, p90 24,0 m, größte 62,59 m

Zwei Befunde daraus:

  • Die Mittellinien sind bereits gerade. Das Zackige steckt ausschließlich in den Rändern. Wer die Ränder neu baut, statt sie zu glätten, bekommt gerade Straßen fast geschenkt.
  • Die Breite hat zwei Häufungen: 2–8 m (569 Linien: Gassen und Zufahrten) und 12–18 m (597 Linien: normale Straßen). Alles über 24 m sind Kreuzungsflächen und Parkplätze.

Das Netz ist heute kein Netz

Von den 3.038 Enden der 1.519 Mittellinien treffen sich nur 81 zu Kreuzungen (2.259 Enden stehen allein, 268 treffen sich zu zweit). Ursache ist der Filter length >= 15 in centerlines(): Er wirft an jeder Kreuzung die kurzen Stummel weg, und das Netz zerfällt. Für Laternen reicht das, als Straßennetz ist es unbrauchbar.

Das ungefilterte Skelett sieht anders aus:

Größe Wert
Skelettpixel 109.584
Rohäste 12.472 (Median 2 px, p90 19 px — der Rest sind Fransen)
Äste ab 3 / 5 / 10 / 15 / 25 m 4.375 / 3.274 / 2.159 / 1.531 / 990
Pixel nach Grad 1: 5.980, 2: 94.073, 3: 4.982, 4: 930, 5: 54, 6: 4
Kreuzungspixel (Grad ≥ 3) 5.970, zu 862 Knoten verschmolzen (8 m Radius)

Was ein Neubau aus Mittellinien abdeckt

Bänder aus den 1.519 Mittellinien, Breite auf 6/12/18/24 m gerundet:

Größe Wert
Straßenfläche heute 1,318 km² (als Polygone gemessen)
Bänder 1,143 km², davon 1,067 km² innerhalb der heutigen Straße
Heute Straße, von keinem Band gedeckt 0,250 km² = 19,0 %, in 3.434 Stücken
davon Splitter unter 200 m² 3.129 Stücke, zusammen 68.299 m²
Größte Reststücke 3.916 / 3.516 / 3.462 / 3.193 / 2.750 m²

Die Splitter sind genau die Zacken, die wegsollen. Die großen Reststücke sind echte Flächen: Parkplätze, Kreuzungsvorplätze, Rampen.

Was die Kapsel erklimmt (im Browser gemessen, 2026-09-16)

Größe Wert
Kapselradius 0,15 m
Segmentlänge 0,40 m
Bodenfreiheit (rideHeight) 0,20 m
Standhöhe snapH / maxH 0,75 m / 0,95 m
minFloorNormalY 0,99027, entspricht 8,0° Grenzsteigung

Gehversuch über drei Stufen, jeweils mit fertigem Collider:

Stufe Ergebnis
0,15 m erklommen, ohne Halt: y 0,75 → 0,79 → 0,90 innerhalb einer Probe an der Kante
0,25 m erklommen, +0,25 m
0,40 m blockiert, Kapsel bleibt an der Kante stehen (z −773,9 bei Kante −774), y unverändert

Ein 15-cm-Bordstein hält den Spieler also nicht auf, er ist eine Stufe. Fahrzeuge fahren auf Raycast-Rädern mit Federung (VehicleSystem, registerWheelSpheres); ihr Aufbau schwebt über 15 cm. Das wird beim Bau trotzdem nachgefahren.

Die beiden Kits

modular_sidewalk_curb_kit modular_city_road_pack__game_ready
Urheber, Lizenz Just8, CC BY 4.0 Salah3D, CC BY 4.0
Teile / Punkte 16 / 351 42 / 13.505
Maßeinheit Zentimeter Meter
Kernmaß Bordstein 84,79 × 14,87 cm, Module 300 cm Fahrbahnstücke 4,2 m breit
Texturen 3 Materialien, alle 2048², mit Normal- und MetallicRoughness-Karte 9 Materialien, 512–1024, Markierungen fest eingebacken
Brauchbar als Profil und Texturen für Bordstein und Gehweg später Schilder, Masten, Geländer

Zwei Dinge liegen damit fest. Erstens: Das Straßen-Kit taugt nicht für die Fahrbahn — 4,2 m gegen 13,4 m gemessene Korridorbreite, und seine Markierungen sind europäisch (gelbe Randlinien, weiße gestrichelte Mitte), also das Gegenteil des amerikanischen Schemas. Zweitens: Das Bordstein-Kit besteht aus 16 Kästen mit zusammen 351 Punkten; seine Substanz sind die Texturen, nicht die Geometrie. 177 km Bordsteinkante wären in 3-m-Modulen rund 59.000 Einzelteile.

Entscheidungen des Nutzers

Frage Entscheidung
Umfang die ganze Karte, alle 88,74 km
Restflächen (19 %) Stücke ab 200 m² bleiben als Asphaltfläche, die 3.129 Splitter fallen weg
Kollision Bordstein und Fahrbahn kollidieren
Platz für den Gehweg aus dem heutigen Korridor, der Stadtgrundriss bleibt unberührt
Markierung volles Standardbild: Mittellinie, Spurtrenner, Randlinien, Haltelinien, Zebrastreifen
Kits Texturen und Profil aus dem Bordstein-Kit, Geometrie selbst gebaut
Ansatz alles in der Extraktion, Markierungen als Geometrie

Das Netz (tools/extract/leonida/roads.py, neu)

  1. Skelett der Straßenmaske wie heute (skeletonize(road_mask(labels))), aber der Pixelgraph wird behalten statt verworfen.
  2. Kreuzungen verschmelzen: Pixel mit Grad ≥ 3, um 8 m gewachsen, dann Zusammenhangskomponenten — 5.970 Pixel werden zu 862 Knoten. Der Knotenpunkt ist der Schwerpunkt seiner Pixel.
  3. Kanten sind die Pfade zwischen zwei Knoten oder zwischen Knoten und Sackgassenende, ohne Längenfilter.
  4. Haare abschneiden: Sackgassenkanten unter 10 m fallen weg. Danach wird neu verschmolzen — ein Knoten, der dadurch nur noch zwei Kanten trägt, verschwindet, und seine beiden Kanten werden eine.
  5. Kurze Verbindungen zusammenziehen: Kanten unter 5 m zwischen zwei Knoten werden zu einem Knoten zusammengezogen. Das fängt die sternförmigen Ausfransungen an breiten Flächen ab.
  6. Gerade ziehen: Douglas-Peucker mit 1,0 m je Kante.
  7. Breite messen: Median aus 2 × Distanztransformation, alle 5 m entlang der Kante abgetastet — ohne die ersten und letzten 8 m, weil die Distanztransformation im Kreuzungsbereich die Breite der Kreuzung misst, nicht die der Straße.
  8. Klasse: die nächstliegende der vier Regelbreiten.

Der Graph ist danach das, was der Rest der Pipeline benutzt: Knoten mit Lage und Grad, Kanten mit Stützpunkten, Breite und Klasse.

Querschnitte

Regelmaße: Fahrspur 3,5 m, Längsparkspur 2,0–2,5 m, Gehweg 2,5–3,0 m, Bordstein 15 cm hoch.

Klasse Korridor Fahrbahn Aufteilung Gehweg je Seite Bordstein gemessener Bestand
Gasse 6 m 6,0 m eine Fahrgasse — nein 558 Kanten, 28,0 km
Wohnstraße 12 m 7,0 m 2 × 3,5 m 2,5 m ja 369 Kanten, 25,5 km
Hauptstraße 18 m 12,0 m 2 × 3,5 m + 2 × 2,5 m Parkspur 3,0 m ja 378 Kanten, 21,1 km
Boulevard 24 m 18,0 m 4 × 3,5 m + 2 × 2,0 m Parkspur 3,0 m ja 214 Kanten, 14,1 km

Die Zahlen des Bestands stammen aus den 1.519 heutigen Mittellinien; der neue Graph hat mehr Kanten, die Verteilung bleibt.

Die Gasse bekommt weder Bordstein noch Gehweg noch Markierung — so sind die Hinterhofgassen zwischen den Blöcken in Miami Beach auch.

Geometrie

Die Mulde

Die Fahrbahn liegt 15 cm unter dem Boden, nicht der Gehweg darüber. Der Grund: Läge der Gehweg höher, hätte er überall dort eine Kante ins Nichts, wo kein Haus anschließt — an jedem Park, jeder Baulücke, jedem Strandzugang. Mit der Mulde bleibt die Welt auf y = 0, und der Bordstein ist, was er in Wirklichkeit ist: die Wand zwischen Gehweg und Fahrbahn.

Je Chunk entsteht damit:

  • Loch in der Bodenplatte in Form der Fahrbahn. land ist schon heute ein Polygon mit Löchern (Wasser); das ist derselbe Mechanismus. Die Beläge (urban, park, sand und die Parkschichten aus Teil 1) werden am selben Rand beschnitten, damit nichts über dem Loch schwebt.

  • Fahrbahn als flache Fläche bei y = −0,15, mit Kollision.

  • Bordstein entlang des Lochrands: eine senkrechte Wand von y = −0,15 auf y = 0, dazu ein 20 cm breiter Streifen ihrer Oberkante, damit die Kante von oben als Beton liest und nicht als Messerschneide. Mit Kollision. Rund 176 km Kante; bei geraden Abschnitten von im Mittel 20 m sind das etwa 17.600 Vierecke, also 35.200 Dreiecke für die ganze Karte.

    Die Wand hat keine Grundfläche: Loch und Fahrbahn haben denselben Umriss. Die 84,79 cm Profilbreite des Kits enthalten die Rinne; die gehört hier zur Fahrbahn und bleibt Asphalt. Die Textur der Wand nimmt den Streifen der Bordsteinfläche aus der Kit-Textur, nicht das ganze Modul.

  • Gehweg als Belag auf der Bodenplatte zwischen Bordsteinkante und Blockrand. Kein eigener Körper, keine Stufe, keine zusätzliche Kollision.

Kreuzungen

An jedem Knoten werden die Fahrbahnbänder bis zum Abstand max(halbe Breite der anliegenden Kanten) + 2 m zurückgeschnitten und die Fläche dazwischen gefüllt. Die einspringenden Ecken bekommen den amerikanischen Eckradius von 6 m (20 ft), erzeugt durch Schließen (buffer(+6).buffer(−6)) nur innerhalb einer Scheibe um den Knoten — global angewandt würde dieselbe Operation zwei parallele Straßen im Abstand unter 12 m zu einer Fläche verschmelzen.

Der Bordstein läuft um diese Radien herum, statt an der Kreuzung abzubrechen.

Brücken

Die 11 Brückenstücke behalten ihre heutige Konstruktion mit Deck und Seitenwangen (geometry.js, BRIDGE-Kommentar). Sie bekommen die neue Fahrbahn und die Markierungen obenauf, aber keinen Bordstein und keinen Gehweg: Eine Brücke hat eine Brüstung, und die ist eine eigene Aufgabe.

Restflächen

Was von der heutigen Straßenfläche kein Band und keine Kreuzung abdeckt, wird nach Größe getrennt: Stücke ab 200 m² bleiben als Asphaltfläche lots auf Bodenhöhe liegen (Parkplätze, Vorplätze, Rampen), alles darunter fällt weg. Nach der Messung sind das 305 Flächen mit zusammen rund 182.000 m² gegen 3.129 Splitter mit 68.299 m².

Kollision

Die Bodenplatte trägt wie heute, jetzt mit Löchern. Dazu kommen Fahrbahn und Bordsteinwände in den Kollisionskörper des Chunks. Gehweg, Markierungen und Restflächen bleiben reine Auflagen.

Belegt ist das durch die Messung oben: 15 cm werden ohne Halt erklommen, blockiert wird erst bei 40 cm. Die Grenzsteigung von 8,0° betrifft nur schiefe Flächen, nicht Stufen.

Markierungen

Alles nach US-Regelmaß, Linienbreite 10 cm (4 in):

Element Klasse Maß
Gelbe Mitte, gestrichelt Wohnstraße 3 m Strich, 9 m Lücke
Gelbe Mitte, doppelt durchgezogen Hauptstraße, Boulevard zwei Linien, 10 cm Abstand
Weiße Spurtrenner, gestrichelt Boulevard 3 m Strich, 9 m Lücke, zwischen den gleichgerichteten Spuren
Weiße Randlinie Hauptstraße, Boulevard durchgezogen, an der Grenze zur Parkspur
Haltelinie jede Kreuzungszufahrt ab Wohnstraße 60 cm tief, über die rechte Fahrbahnhälfte, 4,2 m vor dem Kreuzungsrand
Zebrastreifen Kreuzungen mit mindestens zwei Armen ab 12 m Balken 60 cm, Lücke 60 cm, 3 m tief, unmittelbar am Kreuzungsrand

Regeln dazu:

  • Längsmarkierungen laufen vom Kreuzungsrand zum Kreuzungsrand und enden dort — in der Kreuzung selbst steht nichts, wie in Wirklichkeit.
  • Das Strichmuster beginnt am Kantenanfang; die Phase wird nicht über Kreuzungen hinweg fortgesetzt.
  • Rechtsverkehr: Die Haltelinie deckt die Fahrbahnhälfte rechts der Mittellinie, aus Sicht der Zufahrt.
  • Gassen bekommen nichts.
  • Arme, die Gassen sind, bekommen keinen Zebrastreifen.

Alle Markierungen sind flache Vierecke 1 cm über der Fahrbahn (y = −0,14) in einem Material mit Vertexfarben, gelb und weiß in einem Zeichenaufruf. Geschätzter Umfang für die ganze Karte: rund 80.000 Dreiecke, etwa 550 je Chunk — gegen 1.191.562 Dreiecke, die heute in der Draufsicht aus 450 m stehen.

Texturen aus dem Kit

Ein neuer Schritt in tools/assets/textures.mjs holt aus modular_sidewalk_curb_kit/textures/ (2048², nicht versioniert, gehört dem Nutzer) die drei Karten heraus, verkleinert sie auf 1024² wie die übrigen Texturen und legt sie im bestehenden Namensschema ab:

Ziel in public/textures/ Quelle
curb_Diffuse.jpg CurbMat_baseColor.jpeg
curb_nor_gl.jpg CurbMat_normal.png (glTF-Normalen sind OpenGL-Konvention, passt)
curb_arm.jpg CurbMat_metallicRoughness.png (glTF packt Rauheit nach G, Metall nach B — dasselbe Schema wie arm)
sidewalk_Diffuse.jpg sidewalk_baseColor.jpeg

Der Schritt überspringt still, was schon da ist, und meldet verständlich, wenn der Kit-Ordner fehlt — er ist nicht im Repo, und das Skript darf deshalb nicht davon abhängen. Die erzeugten Dateien werden versioniert, wie die Poly-Haven-Texturen auch.

sidewalk_metallicRoughness.png ist eine 605 Byte große Einfarbfläche und wird nicht übernommen; eine Normal-Map für den Gehweg liefert das Kit nicht.

Namensnennung: manifest.json und die Zeile im Spiel bekommen „Bordstein und Gehweg: Just8 (Sketchfab, CC BY 4.0)". Das Straßen-Kit wird in dieser Arbeit nicht benutzt und deshalb auch nicht genannt.

Chunk-Format

Neue und geänderte Schlüssel:

{
  "land": [[ring, loch, loch, ...]],
  "carriageway": [{ "poly": [ring, ...] }],
  "curb": [{ "line": [[x, z], ...] }],
  "sidewalk": [{ "poly": [ring, ...] }],
  "markings": [{ "poly": [ring], "art": "gelb_doppelt" }],
  "lots": [{ "poly": [ring, ...] }],
  "edges": [{ "line": [[x, z], ...], "klasse": "hauptstrasse", "breite": 18.0 }],
  "bridges": [...]
}
  • roads entfällt und wird durch carriageway und lots ersetzt.
  • carriageway trägt keine Klasse (Fixwelle, Befund 6): Ein Eintrag ist eine Zusammenhangskomponente des ganzen Straßennetzes und bekäme damit nur die breiteste Klasse irgendeiner enthaltenen Straße zugewiesen — am echten Netz 91,2 % der Fläche „boulevard", unabhängig davon, was dort tatsächlich liegt. Die Klasse je Straße steht in edges; kein Verbraucher las carriageway[].klasse.
  • centerlines wird zu edges — dieselben Linien, aber mit Klasse und Breite. Laternen, Palmenabstand und später der Verkehr lesen daraus.
  • curb ist eine Liste von Linienzügen entlang des Fahrbahnrands — die Stücke, die einen Bordstein tragen. Gassen und Brücken liefern hier nichts. Die Wand und ihre Oberkante entstehen daraus im Browser; ein Polygon wäre falsch, weil die Wand keine Grundfläche hat.
  • land behält seine Form, bekommt aber die Fahrbahnlöcher.

Die Ausgabe bleibt normalisiert und sortiert (Fixrunde 3 aus Teil 1): shapely.normalize je Fläche, Sortierung nach der Ausgabestruktur. Das gilt auch für die neuen Schlüssel.

Darstellung im Browser

  • src/world/geometry.js: neue Teile carriageway, sidewalk, markings, lots als flache Flächen, curb als Wand von −0,15 auf 0 mit 20 cm Oberkante, gebaut aus den Linienzügen.

  • src/world/materials.js: vier neue Materialien.

    Schlüssel Material
    carriageway asphalt_02 mit ROAD_TINT, wie die heutige Straße
    curb curb aus dem Kit, mit Normal- und ARM-Karte
    sidewalk sidewalk aus dem Kit
    markings unbeleuchtet, Vertexfarben, ohne Textur
  • Tiefenpuffer: POLYGON_OFFSET_ORDER bekommt sidewalk und lots zwischen den Belägen und markings ganz vorn. carriageway und curb brauchen keinen Versatz — sie liegen 15 cm tiefer und sind echte Geometrie, keine Auflage.

  • src/world/streaming.js: DECALS bekommt sidewalk, markings und lots. carriageway und curb gehören in den Kollisionskörper.

  • src/world/props.js: Laternen stehen künftig auf dem Gehweg, in festem Abstand zur Bordsteinkante, und wählen ihre Seite aus der Kantenrichtung statt aus der Listenreihenfolge. Damit entfällt die Abhängigkeit, die in Teil 1 die Sortierung der Mittellinien verhindert hat — edges darf danach normal sortiert werden.

Minimap (tools/extract/overview.py)

  • Fahrbahn im heutigen Straßenton, Gehweg hell, lots im Straßenton.
  • Markierungen werden nicht gezeichnet: bei 1 px je 3 m wären 10-cm-Linien Rauschen.
  • In map-walkable.png zählt der Gehweg künftig als begehbar, die Fahrbahn nicht.

Zusammenspiel mit Teil 1

Flamingo Park greift an drei Stellen in dieselben Daten:

  • Die Jefferson Avenue. apply_street() in park.py legt heute ein eigenes Straßenpolygon und eine Mittellinie an. Im neuen Aufbau gibt es keine Straßenpolygone mehr: Der Park liefert stattdessen eine Kante an den Graphen (von [1516,5 | 664,0] nach [1545,2 | 334,2], Breite 12 m, also Wohnstraße) und bekommt damit automatisch Bordstein, Gehweg und die gestrichelte gelbe Mitte. Alles andere an apply_street() bleibt: die Gebäude auf der Trasse fallen weg, die alte Gasse wird herausgeschnitten.
  • Die Reihenfolge. Der Park muss seine Kante liefern, bevor der Straßenbau läuft. Heute läuft apply_flamingo_park() nach road_polygons(); künftig wird zuerst der Graph gebaut, die Parkkante eingehängt, und erst dann die Fahrbahn erzeugt. Die übrigen Eingriffe des Parks (Flächen, Gebäude, Wege) bleiben, wo sie sind.
  • Die Eckenprüfung. check_corners() prüft, dass die vier Ecken des Spielparks in der Straßenfläche liegen, mit 2,5 m Toleranz gegen den Rand (Fixrunde 3). Die Fahrbahn wird schmaler als der heutige Korridor — bei einer 15-m-Straße bleiben 7 m Fahrbahn statt 15 m Belag. Die Prüfung muss deshalb künftig gegen den Korridor messen, nicht gegen die Fahrbahn, sonst schlägt sie bei der ersten Ausführung falsch an. Das ist der wahrscheinlichste Stolperstein der ganzen Arbeit.

Die Parkwege (paths) bleiben unberührt — das sind Fußwege, keine Straßen. Der Park gewinnt nebenbei: Seine Kanten grenzen künftig mit echtem Bordstein an die vier Straßen ringsum.

Ablauf

  1. Graph bauen, Kanten klassifizieren.
  2. Bänder und Kreuzungsflächen bilden, zur Fahrbahn vereinigen.
  3. Fahrbahn aus Bodenplatte und Belägen herausschneiden.
  4. Bordsteinbänder und Gehwegflächen aus Fahrbahnrand und Korridorbreite ableiten.
  5. Markierungen je Kante und je Kreuzung erzeugen.
  6. Restflächen trennen, Splitter verwerfen.
  7. Palmen und Laternen neu setzen.
  8. Chunks schreiben, Karten zeichnen.

Tests

pytest (tools/extract/tests/test_roads_*.py)

  • Graph: Kreuzungen im Umkreis von 8 m werden ein Knoten; Sackgassen unter 10 m fallen weg; ein Knoten mit nur noch zwei Kanten verschwindet und verbindet sie; Kanten unter 5 m zwischen zwei Knoten werden zusammengezogen.
  • Breite: die ersten und letzten 8 m gehen nicht in den Median ein — mit einem künstlichen Fall, bei dem eine breite Kreuzung an einer schmalen Straße hängt und die Messung ohne diese Regel die falsche Klasse liefert.
  • Querschnitt: Fahrbahn plus zweimal Gehweg ergibt für jede Klasse genau den Korridor.
  • Kreuzung: Der Eckradius wird nur um den Knoten angewandt; zwei parallele Straßen im Abstand von 10 m bleiben getrennt.
  • Markierung: Längsmarkierungen enden am Kreuzungsrand; die Haltelinie liegt rechts der Mittellinie; Gassen bekommen nichts; ein Kreuzungsarm, der eine Gasse ist, bekommt keinen Zebrastreifen.
  • Mulde: Die Fahrbahn liegt vollständig im Loch der Bodenplatte, und das Loch ist nirgends größer als die Fahrbahn.
  • Integrationslauf auf den echten Daten, der Kantenzahl je Klasse, Kreuzungszahl, Markierungszahl und Restflächenzahl festhält.

vitest

  • geometry.js baut aus curb eine Wand von −0,15 auf 0 und aus carriageway eine Fläche auf −0,15.
  • Markierungen tragen die richtige Farbe je Art.
  • DECALS enthält Gehweg, Markierung und Restflächen, aber nicht Fahrbahn und Bordstein.
  • Alte Chunks ohne die neuen Schlüssel laden weiter.

Sichtprüfung

Vier Blicke im Browser: eine Kreuzung von oben, eine Straße auf Augenhöhe, ein Gehweg aus Fußgängersicht, ein Zebrastreifen aus der Nähe. Dazu einmal zu Fuß über den Bordstein und einmal mit dem Auto darüber. Draw Calls und Bildzeit werden gegen den heutigen Stand gehalten (1.097 Calls, 1.191.562 Dreiecke, 8,8 ms in der Draufsicht aus 450 m).

Fehlerfälle und Risiken

  • Die gelöcherte Bodenplatte. 88 km Lochrand je Karte; ShapeUtils.triangulateShape im Browser ist damit noch nie belastet worden. Das wird als Erstes gemessen, an einem einzelnen Chunk, bevor irgendetwas anderes gebaut wird. Bricht es, ist der Ausweg, die Bodenplatte je Chunk in Streifen zu zerlegen.
  • Das Auto in der Mulde. Raycast-Räder sollten 15 cm nehmen. Wenn nicht, wird der Bordstein an Zufahrten abgesenkt oder die Mulde flacher.
  • 862 „Kreuzungen" sind nicht alle Kreuzungen. An Parkplatzflächen franst das Skelett sternförmig aus. Klassenregel und Restflächen fangen das ab, Einzelfälle bleiben.
  • Alle 144 Chunks ändern sich. Diesmal ist das gewollt. Die Abnahme aus Fixrunde 3 bleibt die Messlatte: Ein zweiter Lauf darf keine einzige Datei mehr ändern.
  • Der Kit-Ordner fehlt. Die Texturen sind nach dem ersten Lauf versioniert; das Importskript muss ohne den Ordner durchlaufen und das sagen, statt abzubrechen.
  • Z-Fighting auf der Fahrbahn. Markierungen liegen 1 cm über der Fahrbahn und bekommen zusätzlich die vorderste Versatzstufe.
  • Gemessen im Spiel (Task 16, run.py auf der ganzen Karte, Ausgabe wörtlich): „Straßennetz: 1.537 Knoten, 1.790 Kanten"; „Straßen: 830 Bordsteinstücke, 171 Restflächen, 22.394 Markierungen {gelb_doppelt 974, gelb_gestrichelt 2.341, haltelinie 1.496, weiss_gestrichelt 2.040, weiss_rand 974, zebra 14.569}, 56 Palmen an der Fahrbahn entfernt"; „Flamingo Park: 2 Wegflächen, 14 Flächen, 11 Gebäude, Jefferson Avenue 12 m breit"; genau eine Warnung, „Zufahrt schneidet die Sperrfläche tribuene". Nachgemessen mit dem Skript aus Task 12: Fahrbahn 0,9076 km² (Erwartung 0,9084, Abweichung 0,088 %), Gehweg 0,2982 km² (0,2983, 0,034 %), Restflächen 0,0972 km² (0,0973, 0,103 %), Bordstein 120,28 km (120,61, 0,274 %) — alle vier unter der 1-%-Toleranz. Je Chunk gezählt: 479 Fahrbahn-, 1.322 Gehweg-, 282 Restflächen-, 1.415 Bordstein-, 2.218 Kantenstücke, 23.256 Markierungsstücke; Kantenstücke je Klasse boulevard 270, wohnstrasse 537, gasse 1.010, hauptstrasse 401 (alle vier Klassen besetzt); Markierungsstücke je Art gelb_doppelt 1.216, gelb_gestrichelt 2.370, haltelinie 1.553, weiss_gestrichelt 2.066, weiss_rand 1.219, zebra 14.832 (alle sechs über der „Straßen:"-Zeile des Laufs, keine 0); 0 Palmen auf der Fahrbahn. Beide Abnahmen bestanden: ein zweiter, unveränderter Lauf ändert keine einzige Datei unter public/data/vice-a (Risiko „Alle Chunks ändern sich" oben), und mit den neu erzeugten Chunks laufen sowohl der bis dahin übersprungene Minimap-Abgleich (test_committed_map_files_match_the_committed_chunks) als auch tests/placesSite.test.js grün — beide prüfen jetzt zum ersten Mal echt gegen Fahrbahn, Gehweg, Restflächen und chunkLampPoints. Das Risiko „gelöcherte Bodenplatte" (oben, Task 1) blieb entschärft: 100 Löcher in 3,98–4,52 ms trianguliert, weit unter der 50-ms-Grenze. tests/parkData.test.js prüfte die vier Fahrzeug-Startpunkte anfangs noch gegen den alten Schlüssel c.roads; in diesem Branch mit Commit 05e2914 auf carriageway umgestellt und grün.
  • Gemessen nach der Fixwelle (2026-09-18, run.py erneut auf der ganzen Karte, nach den Befunden 3–8 der Abschlussprüfung): „Straßennetz: 1.537 Knoten, 1.790 Kanten" (unverändert — keiner der Befunde rührt am Graphen); „Straßen: 830 Bordsteinstücke, 169 Restflächen, 22.393 Markierungen {gelb_doppelt 974, gelb_gestrichelt 2.341, haltelinie 1.496, weiss_gestrichelt 2.040, weiss_rand 973, zebra 14.569}, 56 Palmen an der Fahrbahn entfernt"; dieselbe eine Warnung wie oben. Nachgemessen mit demselben Skript: Fahrbahn 0,9076 km² (unverändert) und Bordstein 120,28 km (unverändert) — beide Befunde (5, 6) ändern hier nichts Messbares. Gehweg 0,2987 km² (statt 0,2982, +0,17 %) und Restflächen 0,0967 km² (statt 0,0972, −0,51 %): Befund 7 schließt die Gehweglücke an gewöhnlichen Kreuzungsecken, der Gehweg wächst entsprechend, die Restfläche schrumpft — beide weiterhin unter der 1-%-Toleranz gegen die ursprüngliche Erwartung. Je Chunk gezählt: 479 Fahrbahn-, 1.322 Gehweg-, 279 Restflächen- (statt 282), 1.415 Bordstein-, 2.218 Kantenstücke (alle vier unverändert bis auf Restflächen), 23.272 Markierungsstücke (statt 23.256 — die neue Position der Markierungen aus den Befunden 3 und 8 schneidet an den Chunkgrenzen geringfügig anders zu); Kantenstücke je Klasse unverändert; Markierungsstücke je Art gelb_doppelt 1.216, gelb_gestrichelt 2.370, haltelinie 1.555, weiss_gestrichelt 2.066, weiss_rand 1.219, zebra 14.846 (nur haltelinie und zebra ändern sich, um 2 bzw. 14 Stücke); 0 Palmen auf der Fahrbahn (unverändert). Beide Abnahmen erneut bestanden: ein zweiter Lauf nach dem Commit der Daten ändert keine einzige Datei unter public/data/vice-a, und test_committed_map_files_match_the_committed_chunks sowie tests/placesSite.test.js bleiben grün. Zusätzlich zu Befund 3 gemessen (Fläche von markings außerhalb von carriageway, über alle Chunks summiert): 452,65 m² vor der Korrektur (1,03 % von 43.906 m² Markierungsfläche, rechnerisch gegen die vor der Fixwelle ausgelieferten Daten nachgewiesen), 110,06 m² danach (0,25 %) — eine Verbesserung um 75,7 %, aber keine vollständige Behebung; der Rest sind Bögen, die zwischen der Streckenlänge reach und reach + STOP_SETBACK + STOP_DEPTH noch einmal abknicken, was ein einzelner Richtungsstrahl nicht mehr auffängt (die vom Befund selbst genannte größere Alternative, „die Markierung entlang der tatsächlichen Kante aufbauen", setzt diese Fixwelle nicht um). Einzelheiten im Fixwelle-Bericht (.superpowers/sdd/2026-09-16-strassen/fixwelle-report.md).

Nicht Teil dieser Arbeit

  • Ampeln, Schilder, Abbiegepfeile, Parkbuchtmarkierung, Radwege, Brückenbrüstungen.
  • Fahrender Verkehr und Fußgänger auf den Gehwegen.
  • Das Straßen-Kit modular_city_road_pack__game_ready: seine Schilder, Masten und Geländer sind ein eigener, späterer Schritt.
  • Die allgemeine Feinkalibrierung (corrections.toml).