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 <noreply@anthropic.com>
This commit is contained in:
2026-09-04 21:09:48 +02:00
co-authored by Claude Opus 5
parent bcc685dcfa
commit f29ed5abfa
+76 -41
View File
@@ -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