fix(world): openRing() stürzt bei leerem oder fehlendem Außenring nicht mehr ab
Ruling 47 (Fix-Runde 1, Befund A): Die Längenprüfung stand erst im return, destrukturiert wurde davor. extrudePolygons/flatPolygons warfen dadurch bei einem Polygon mit leerem Außenring ([[]]) oder ganz ohne Ringe ([]), statt wie der Rest des Moduls zu null zu degradieren. Längenprüfung nach vorn gezogen und zusätzlich raw[0] am Aufrufort auf [] defaultet, da ein Polygon ganz ohne Ringe openRing() ein undefined statt eines leeren Rings übergibt — die Prüfung allein in openRing() fängt diesen zweiten Fall nicht ab. Dazu Ruling 49: Regressionstest für die Wickelrichtung (Außenwände nach außen, Lochwände nach innen, Dach nach oben) anhand von COURTYARD. Bestand beim ersten Lauf unverändert, keine Anpassung am Modul nötig. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4c82b14a57
commit
962bfef778
2 files changed
+58
-3
No files matched your search
+14
-3
@@ -20,10 +20,17 @@ function buildingTint(poly) {
|
||||
// ab dem ersten Loch um eins gegenüber dieser internen Nummerierung, und Dreiecke zeigen auf
|
||||
// falsche Punkte. Deshalb hier einmal vorab entfernen, bevor irgendetwas anderes mit dem Ring
|
||||
// passiert — Ringe ohne Schlusspunkt (wie in den Tests) bleiben dabei unverändert.
|
||||
//
|
||||
// Ruling 47: Länge zuerst prüfen, dann destrukturieren. Ein Ring mit 0 oder 1 Punkten hat
|
||||
// keinen von "erstem" verschiedenen "letzten" Punkt, den man entdoppeln könnte — vorher
|
||||
// stand die Längenprüfung erst im return, sodass ring[0] bei einem leeren Ring bereits
|
||||
// undefined war und die Destrukturierung warf, statt wie der Rest dieses Moduls zu einem
|
||||
// harmlosen leeren Ergebnis zu degradieren.
|
||||
const openRing = (ring) => {
|
||||
if (ring.length <= 1) return ring;
|
||||
const [x0, z0] = ring[0];
|
||||
const [xn, zn] = ring[ring.length - 1];
|
||||
return ring.length > 1 && x0 === xn && z0 === zn ? ring.slice(0, -1) : ring;
|
||||
return x0 === xn && z0 === zn ? ring.slice(0, -1) : ring;
|
||||
};
|
||||
|
||||
const signedArea = (ring) => ring.reduce((sum, [x0, z0], i) => {
|
||||
@@ -47,7 +54,9 @@ function toGeometry(pos, idx, uv, color) {
|
||||
export function flatPolygons(polygons, { y = 0, uvScale = 8 } = {}) {
|
||||
const pos = [], idx = [], uv = [];
|
||||
for (const raw of polygons) {
|
||||
const outer = clockwise(openRing(raw[0]));
|
||||
// raw[0] fehlt, wenn die Fläche ganz ohne Ringe übergeben wird (raw = []) — dann
|
||||
// wie einen leeren Außenring behandeln, statt in openRing() auf undefined zuzugreifen.
|
||||
const outer = clockwise(openRing(raw[0] ?? []));
|
||||
// clockwise() gibt denselben Array zurueck, wenn der Ring schon passt — deshalb
|
||||
// vor dem Umdrehen kopieren, sonst wird die Eingabe des Aufrufers veraendert.
|
||||
const holes = raw.slice(1).map((hole) => [...clockwise(openRing(hole))].reverse());
|
||||
@@ -71,7 +80,9 @@ export function extrudePolygons(polygons, { base = 0, top = 10, uvScale = 4, tin
|
||||
for (const raw of polygons) {
|
||||
// Jede Fläche ist eine Liste von Ringen: Außenring zuerst, danach die Löcher.
|
||||
// triangulateShape erwartet die Löcher gegenläufig zum Außenring.
|
||||
const outer = clockwise(openRing(raw[0]));
|
||||
// raw[0] fehlt, wenn die Fläche ganz ohne Ringe übergeben wird (raw = []) — dann
|
||||
// wie einen leeren Außenring behandeln, statt in openRing() auf undefined zuzugreifen.
|
||||
const outer = clockwise(openRing(raw[0] ?? []));
|
||||
// clockwise() gibt denselben Array zurueck, wenn der Ring schon passt — deshalb
|
||||
// vor dem Umdrehen kopieren, sonst wird die Eingabe des Aufrufers veraendert.
|
||||
const holes = raw.slice(1).map((hole) => [...clockwise(openRing(hole))].reverse());
|
||||
|
||||
Reference in new issue
Block a user