Ansicht: Kämpfer-/Sprossen-Zeilen (mullionRows) im Fenster

Die 2D-Ansicht teilte das Glasfeld nur vertikal (Flügel) und beim Oberlicht,
ignorierte aber mullionRows — ein Fenster mit horizontaler Sprossenteilung sah
in der Ansicht ungeteilt aus, im 3D dagegen geteilt. Jetzt splittet die Ansicht
das Glasfeld je Flügel in mullionRows Zeilen mit Trennlinien, konsistent zum 3D.
This commit is contained in:
2026-07-11 13:21:52 +02:00
parent f98c962ba3
commit 3ecb8c45de
2 changed files with 59 additions and 1 deletions
+46
View File
@@ -398,6 +398,52 @@ describe("toElevation — Öffnungen: Verdeckung + Reveal-Schatten", () => {
expect(symCount("drehkipp")).toBe(4); // Dreh (2) + Kipp (2)
});
it("Kämpfer-Zeilen (mullionRows): teilen das Glasfeld horizontal (Glas + Trennlinien)", () => {
const base = elevationProject({ overhang: false });
const mk = (mullionRows: number): Project =>
({
...base,
windowTypes: [
{
id: "wt",
name: "F",
kind: "fest",
wingCount: 1,
glazing: "einfach",
frameWidth: 0.06,
mullionRows,
defaultSillHeight: 0.9,
defaultWidth: 1,
defaultHeight: 1.2,
},
],
openings: [
{
id: "op",
type: "opening",
hostWallId: "NEAR",
categoryCode: "21",
kind: "window",
typeId: "wt",
position: 1.5,
width: 1,
height: 1.2,
sillHeight: 0.9,
},
],
}) as unknown as Project;
const glassCount = (rows: number): number => {
const p = mk(rows);
const plan = generateElevationPlan(p, p.drawingLevels[1])!;
// Glasflächen = weiss/blau gefüllte Polygone mit Kontur, keine Öffnung/Rahmen.
return plan.primitives.filter(
(pr) => pr.kind === "polygon" && pr.fill === "#9fc2d9",
).length;
};
expect(glassCount(1)).toBe(1); // fest, 1 Feld
expect(glassCount(3)).toBe(3); // in 3 Zeilen geteilt
});
it("Reveal-Schatten: shadows=true erzeugt Öffnungs-Schattenbänder, false keine", () => {
const project = openingProject();
const level = project.drawingLevels[1];
+13 -1
View File
@@ -772,8 +772,20 @@ function collectOpenings(project: Project, frame: ElevationFrame): ProjectedOpen
const gB = fa1 - gU;
const gz0 = fz + gV;
const gz1 = fieldTop - gV;
// Kämpfer-/Sprossen-Zeilen (mullionRows): das Glasfeld wird in `rows`
// horizontale Scheiben geteilt (analog zum 3D, s. toWalls3d), mit einer
// Trennlinie je Zeilengrenze über die Glasbreite. 1 = ungeteilt (bisher).
const rows = Math.max(1, Math.round(wt?.mullionRows ?? 1));
if (gB - gA > 1e-6 && gz1 - gz0 > 1e-6) {
pr.glass.push(rect(pr.pts, gA, gB, gz0, gz1));
for (let r = 0; r < rows; r++) {
const rz0 = gz0 + ((gz1 - gz0) * r) / rows + (r > 0 ? gV / 2 : 0);
const rz1 = gz0 + ((gz1 - gz0) * (r + 1)) / rows - (r < rows - 1 ? gV / 2 : 0);
if (rz1 - rz0 > 1e-6) pr.glass.push(rect(pr.pts, gA, gB, rz0, rz1));
}
for (let r = 1; r < rows; r++) {
const rz = gz0 + ((gz1 - gz0) * r) / rows;
pr.divisions.push([quadAt(pr.pts, gA, rz), quadAt(pr.pts, gB, rz)]);
}
}
// Trennlinie zum nächsten Feld (ausser am Rand).
if (fa1 < 1 - fa - 1e-6) {