From f29ed5abfa03ffa3c0cacac74613c27017fe8243 Mon Sep 17 00:00:00 2001 From: Moirtz Wagner Date: Fri, 4 Sep 2026 21:09:48 +0200 Subject: [PATCH] Wandflaechen von hinten nach vorn malen, nicht in Kantenreihenfolge Der OG-Carport sah aus wie ein Tisch auf vier Beinen: seine Westwand fehlte scheinbar, man schaute an ihrer Stelle in den Innenraum. Gezeichnet wurde sie die ganze Zeit - die Kennungen der Flaechen zeigen sie als "Wand W aussen". Der Fehler lag in der Reihenfolge. Die Flaechen einer Wand entstehen in Kantenreihenfolge, und die Nordwand ist Kante 3, die Westwand Kante 2. Die Innenseite der hinteren Nordwand wurde damit nach der Aussenseite der vorderen Westwand gemalt und uebermalte sie. Bei einem geschlossenen Koerper faellt das nie auf, weil dort keine Innenseiten sichtbar sind; erst mit Oeffnungen und Wandstaerke kam es heraus. Jetzt werden die Wandflaechen eines Koerpers gesammelt, nach Tiefe sortiert und dann gemalt. Das Tiefenmass ist die Projektion des Flaechenmittelpunkts auf die Blickrichtung - bei dieser Projektion faellt genau eine Raumrichtung auf einen Bildpunkt zusammen, ihre Komponenten sind sin(Winkel), cos(Winkel) und Stauchung/Ueberhoehung. Die projizierte Y-Koordinate taugt dafuer nicht: in ihr steckt auch die Hoehe, ein hoher Punkt saehe damit weiter hinten aus. Boden und Dach bleiben ausserhalb der Sortierung - der eine liegt immer unten, das andere immer oben. Dazu tragen die Flaechen jetzt eine Kennung ("Carport OG: Wand W aussen"). aussenSvg() liest sie nicht, sie kostet also nichts und macht die Fehlersuche moeglich, ohne den Zeichner umzubauen - ohne sie waere dieser Fehler Farbraten geblieben. Die Schnittkanten sind nebenbei von 0,84 auf 0,66 abgedunkelt. Heller als die Wand liessen sie die Ecken wie Pfosten aussehen, was den Tischeindruck noch verstaerkt hat. Co-Authored-By: Claude Opus 5 --- restricted/aussenplan.php | 117 +++++++++++++++++++++++++------------- 1 file changed, 76 insertions(+), 41 deletions(-) diff --git a/restricted/aussenplan.php b/restricted/aussenplan.php index bc8a243..74b5e4d 100644 --- a/restricted/aussenplan.php +++ b/restricted/aussenplan.php @@ -264,6 +264,27 @@ function aussenPunkt($einpassung, $x, $y, $z) $Y * $einpassung["massstab"] + $einpassung["dy"]]; } +/** + * Wie nah eine Flaeche am Betrachter liegt. Groesser heisst naeher. + * + * Bei dieser Projektion faellt genau eine Raumrichtung auf einen Bildpunkt + * zusammen; ihre Komponenten sind sin(Winkel), cos(Winkel) und + * Stauchung/Ueberhoehung. Ein Punkt darauf projiziert ist das Tiefenmass. + * + * Die projizierte Y-Koordinate taugt dafuer nicht: in ihr steckt auch die + * Hoehe, ein hoher Punkt saehe damit weiter hinten aus. + */ +function aussenTiefe($welt) +{ + $w = deg2rad(PLAN_WINKEL); + $summe = 0.0; + foreach ($welt as $p) { + $summe += $p[0] * sin($w) + $p[1] * cos($w) + + $p[2] * (PLAN_STAUCHUNG / PLAN_UEBERHOEHUNG); + } + return $summe / max(1, count($welt)); +} + /** Mittelwert einer Punktliste - gut genug als Ankerpunkt einer Fläche. */ function aussenMitte($punkte) { @@ -469,10 +490,12 @@ function aussenZeichnung() foreach ($ecken as $pkt) { $boden[] = aussenPunkt($einpassung, $pkt[0], $pkt[1], $z); } - $polygone[] = ["punkte" => $boden, "farbe" => aussenSchatten($farbe, 0.55)]; + $polygone[] = ["punkte" => $boden, "farbe" => aussenSchatten($farbe, 0.55), + "was" => "Boden"]; } // --- Waende ------------------------------------------------------ + $waende = []; if ($wand > 0) { foreach ($kanten as $k) { if (in_array($k["richtung"], $offen, true)) { @@ -513,50 +536,48 @@ function aussenZeichnung() $innenBis = [$bis[0] - $k["nx"] * $dicke, $bis[1] - $k["ny"] * $dicke]; $seiten = []; + $viereck = function ($a, $za, $b, $zb, $c, $zc, $d, $zd) { + return [[$a[0], $a[1], $za], [$b[0], $b[1], $zb], + [$c[0], $c[1], $zc], [$d[0], $d[1], $zd]]; + }; // Aussenseite - $seiten[] = [[ - aussenPunkt($einpassung, $von[0], $von[1], $z), - aussenPunkt($einpassung, $bis[0], $bis[1], $z), - aussenPunkt($einpassung, $bis[0], $bis[1], $zBis), - aussenPunkt($einpassung, $von[0], $von[1], $zVon), - ], 0.72]; + $seiten[] = [$viereck($von, $z, $bis, $z, $bis, $zBis, $von, $zVon), + 0.72, "Wand " . $k["richtung"] . " aussen"]; if ($dicke > 0) { // Innenseite - umgekehrter Umlauf, damit sie zaehlt, wenn // man durch die Oeffnung hineinsieht. - $seiten[] = [[ - aussenPunkt($einpassung, $innenBis[0], $innenBis[1], $z), - aussenPunkt($einpassung, $innenVon[0], $innenVon[1], $z), - aussenPunkt($einpassung, $innenVon[0], $innenVon[1], $zVon), - aussenPunkt($einpassung, $innenBis[0], $innenBis[1], $zBis), - ], 0.60]; + $seiten[] = [$viereck($innenBis, $z, $innenVon, $z, + $innenVon, $zVon, $innenBis, $zBis), + 0.60, "Wand " . $k["richtung"] . " innen"]; // Oberkante - $seiten[] = [[ - aussenPunkt($einpassung, $von[0], $von[1], $zVon), - aussenPunkt($einpassung, $bis[0], $bis[1], $zBis), - aussenPunkt($einpassung, $innenBis[0], $innenBis[1], $zBis), - aussenPunkt($einpassung, $innenVon[0], $innenVon[1], $zVon), - ], 0.86]; + $seiten[] = [$viereck($von, $zVon, $bis, $zBis, + $innenBis, $zBis, $innenVon, $zVon), + 0.86, "Wand " . $k["richtung"] . " Oberkante"]; // Die beiden Schnittkanten an den Enden der Wand - $seiten[] = [[ - aussenPunkt($einpassung, $innenVon[0], $innenVon[1], $z), - aussenPunkt($einpassung, $von[0], $von[1], $z), - aussenPunkt($einpassung, $von[0], $von[1], $zVon), - aussenPunkt($einpassung, $innenVon[0], $innenVon[1], $zVon), - ], 0.84]; - $seiten[] = [[ - aussenPunkt($einpassung, $bis[0], $bis[1], $z), - aussenPunkt($einpassung, $innenBis[0], $innenBis[1], $z), - aussenPunkt($einpassung, $innenBis[0], $innenBis[1], $zBis), - aussenPunkt($einpassung, $bis[0], $bis[1], $zBis), - ], 0.84]; + $seiten[] = [$viereck($innenVon, $z, $von, $z, $von, $zVon, $innenVon, $zVon), + 0.66, "Wand " . $k["richtung"] . " Schnitt A"]; + $seiten[] = [$viereck($bis, $z, $innenBis, $z, $innenBis, $zBis, $bis, $zBis), + 0.66, "Wand " . $k["richtung"] . " Schnitt B"]; } $etwasSichtbar = false; foreach ($seiten as $seite) { - if (aussenSichtbar($seite[0])) { - $polygone[] = ["punkte" => $seite[0], - "farbe" => aussenSchatten($farbe, $seite[1])]; - $etwasSichtbar = true; + $projiziert = []; + foreach ($seite[0] as $pkt) { + $projiziert[] = aussenPunkt($einpassung, $pkt[0], $pkt[1], $pkt[2]); } + if (!aussenSichtbar($projiziert)) { + continue; + } + // Erst sammeln - gemalt wird nach der Schleife, von hinten + // nach vorn. In Kantenreihenfolge gemalt uebermalte die + // Innenseite der hinteren Wand die Aussenseite der + // vorderen, und der Koerper sah aus wie ein Tisch, durch + // den man hindurchschaut. + $waende[] = ["tiefe" => aussenTiefe($seite[0]), + "punkte" => $projiziert, + "farbe" => aussenSchatten($farbe, $seite[1]), + "was" => ($f["raum"] ?? "?") . ": " . $seite[2]]; + $etwasSichtbar = true; } if (!$etwasSichtbar) { continue; @@ -570,16 +591,30 @@ function aussenZeichnung() $b = 0.8; $pa = [$von[0] + ($bis[0] - $von[0]) * $a, $von[1] + ($bis[1] - $von[1]) * $a]; $pb = [$von[0] + ($bis[0] - $von[0]) * $b, $von[1] + ($bis[1] - $von[1]) * $b]; - $polygone[] = ["punkte" => [ - aussenPunkt($einpassung, $pa[0], $pa[1], $z), - aussenPunkt($einpassung, $pb[0], $pb[1], $z), - aussenPunkt($einpassung, $pb[0], $pb[1], $z + $torHoch), - aussenPunkt($einpassung, $pa[0], $pa[1], $z + $torHoch), - ], "farbe" => aussenSchatten($farbe, 0.52)]; + $torWelt = [[$pa[0], $pa[1], $z], [$pb[0], $pb[1], $z], + [$pb[0], $pb[1], $z + $torHoch], [$pa[0], $pa[1], $z + $torHoch]]; + $torPunkte = []; + foreach ($torWelt as $pkt) { + $torPunkte[] = aussenPunkt($einpassung, $pkt[0], $pkt[1], $pkt[2]); + } + // Ein Haar naeher als seine Wand, damit es auf ihr liegt + // und nicht neben ihr einsortiert wird. + $waende[] = ["tiefe" => aussenTiefe($torWelt) + 0.001, + "punkte" => $torPunkte, + "farbe" => aussenSchatten($farbe, 0.52), + "was" => ($f["raum"] ?? "?") . ": Tor"]; } } } + // Von hinten nach vorn, innerhalb dieses Koerpers. + usort($waende, function ($a, $b) { + return $a["tiefe"] <=> $b["tiefe"]; + }); + foreach ($waende as $wandflaeche) { + $polygone[] = $wandflaeche; + } + // --- Dach -------------------------------------------------------- if ($dach && $dach["art"] === "sattel" && count($ecken) === 4) { // Der First laeuft entlang der laengeren Gebaeudeachse, wenn nichts