Fenster-Grundriss: keine separate Trennlinie mehr neben dem Rahmenblock am Flügelstoss

Der Rahmenblock (voller Profilquerschnitt) und eine dünne window-mullion-
Linie lagen an derselben Stelle übereinander — überflüssig, der Block markiert
den Stoss bereits vollständig. Nur noch für Alt-Fenster ohne Typ (kein Block
verfügbar) bleibt die Linie bestehen.
This commit is contained in:
2026-07-12 18:20:28 +02:00
parent ce7454039f
commit 4a01754b4d
2 changed files with 34 additions and 21 deletions
+3 -3
View File
@@ -433,11 +433,11 @@ export function windowSymbol(
// Flügel-Trennlinien (Mittelpfosten) an den inneren Segmentgrenzen + // Flügel-Trennlinien (Mittelpfosten) an den inneren Segmentgrenzen +
// Stulp-Block: mittel 1, fein 2 (die beiden zusammenstossenden Profile) — // Stulp-Block: mittel 1, fein 2 (die beiden zusammenstossenden Profile) —
// je über die volle Rahmentiefe. // je über die volle Rahmentiefe. KEINE zusätzliche dünne Trennlinie mehr
// daneben (Nutzer-Feedback: „keine vertikale Trennlinie, sondern ein
// Rechteck") — der Block selbst markiert den Stoss.
for (let i = 0; i < segs.length - 1; i++) { for (let i = 0; i < segs.length - 1; i++) {
const uPos = segs[i].to; const uPos = segs[i].to;
const onAxis = along(jambStart, jambEnd, uPos);
mullionLines.push([add(onAxis, scale(n, frameOuterN)), add(onAxis, scale(n, frameInnerN))]);
if (fein) { if (fein) {
meetingMarks.push(frameBlock(uPos - fw / 2, fw / 2), frameBlock(uPos + fw / 2, fw / 2)); meetingMarks.push(frameBlock(uPos - fw / 2, fw / 2), frameBlock(uPos + fw / 2, fw / 2));
} else { } else {
+31 -18
View File
@@ -98,15 +98,30 @@ function linesOfClass(p: Project, cls: string, detail: "grob" | "mittel" | "fein
); );
} }
/** Mittelpunkt (x) jedes Rahmenblocks (4 Linien = ein Rechteck, s. windowSymbol
* meetingMarks) unter den `window-stulp`-Primitiven, sortiert. */
function stulpBlockCenters(p: Project, detail: "grob" | "mittel" | "fein" = "mittel"): number[] {
const lines = linesOfClass(p, "window-stulp", detail);
const centers: number[] = [];
for (let i = 0; i < lines.length; i += 4) {
const group = lines.slice(i, i + 4);
const xs = group.flatMap((pr) => (pr.kind === "line" ? [pr.a.x, pr.b.x] : []));
centers.push((Math.min(...xs) + Math.max(...xs)) / 2);
}
return centers.sort((a, b) => a - b);
}
describe("generatePlan — Flügeleinteilung aus sashes (Item 1)", () => { describe("generatePlan — Flügeleinteilung aus sashes (Item 1)", () => {
it("Alt-Fall (kein typeId/sashes, nur wingCount=3) erzeugt genau 2 Pfostenlinien — Regression", () => { it("Alt-Fall (kein typeId/sashes, nur wingCount=3) erzeugt genau 2 Pfostenlinien — Regression", () => {
const p = project({ ...baseWindow, wingCount: 3 }); const p = project({ ...baseWindow, wingCount: 3 });
expect(linesOfClass(p, "window-mullion").length).toBe(2); expect(linesOfClass(p, "window-mullion").length).toBe(2);
}); });
it("WindowType MIT sashes (3 feste Flügelbreiten 0.4 m) erzeugt Pfostenlinien exakt an den Flügelgrenzen", () => { it("WindowType MIT sashes (3 feste Flügelbreiten 0.4 m) erzeugt Rahmenblöcke (keine Linie mehr) exakt an den Flügelgrenzen", () => {
// Öffnung 1.2 m breit, jambStart bei x=1.0 (position 1.0) -> jambEnd x=2.2. // Öffnung 1.2 m breit, jambStart bei x=1.0 (position 1.0) -> jambEnd x=2.2.
// 3 Flügel à 0.4 m (autoWidth:false) -> Grenzen bei x=1.4 und x=1.8. // 3 Flügel à 0.4 m (autoWidth:false) -> Stoss-Blöcke bei x=1.4 und x=1.8.
// KEINE separate window-mullion-Linie mehr (Nutzer-Feedback: nur der Block
// markiert den Stoss, keine zusätzliche dünne Trennlinie daneben).
const wt: WindowType = { const wt: WindowType = {
...baseWindowType, ...baseWindowType,
sashes: [ sashes: [
@@ -116,28 +131,26 @@ describe("generatePlan — Flügeleinteilung aus sashes (Item 1)", () => {
], ],
}; };
const p = project({ ...baseWindow, typeId: "wt1" }, [wt]); const p = project({ ...baseWindow, typeId: "wt1" }, [wt]);
const mullions = linesOfClass(p, "window-mullion"); expect(linesOfClass(p, "window-mullion").length).toBe(0);
expect(mullions.length).toBe(2); // 2 Laibungs-Blöcke (Enden, nahe x=1.0/2.2) + 2 Flügelstoss-Blöcke (1.4/1.8).
const xs = mullions const junctionCenters = stulpBlockCenters(p, "mittel").filter((x) => x > 1.2 && x < 2.0);
.map((pr) => (pr.kind === "line" ? pr.a.x : NaN)) expect(junctionCenters.length).toBe(2);
.sort((a, b) => a - b); expect(junctionCenters[0]).toBeCloseTo(1.4, 6);
expect(xs[0]).toBeCloseTo(1.4, 6); expect(junctionCenters[1]).toBeCloseTo(1.8, 6);
expect(xs[1]).toBeCloseTo(1.8, 6);
}); });
it("WindowType MIT sashes, aber alle autoWidth (kein fixes width/pfosten) -> identische Grenzen wie die alte wingCount-Gleichverteilung", () => { it("WindowType MIT sashes, aber alle autoWidth (kein fixes width/pfosten) -> Rahmenblöcke an denselben Positionen wie die alte wingCount-Gleichverteilung", () => {
// 3 gleichmässige Flügel über sashesOfWindowType (kein `sashes` am Typ, // 3 gleichmässige Flügel über sashesOfWindowType (kein `sashes` am Typ,
// nur `wingCount: 3`) müssen exakt dieselben Pfosten liefern wie der // nur `wingCount: 3`) müssen an denselben Achspositionen einen Stoss haben
// Alt-Fall ohne Typ (Regressionssicherheit der Ableitung). // wie der Alt-Fall ohne Typ (Regressionssicherheit der Ableitung) — der
// Alt-Fall zeigt sie weiterhin als Linie, der typisierte Pfad als Block.
const wt: WindowType = { ...baseWindowType, wingCount: 3 }; const wt: WindowType = { ...baseWindowType, wingCount: 3 };
const withType = project({ ...baseWindow, typeId: "wt1" }, [wt]); const withType = project({ ...baseWindow, typeId: "wt1" }, [wt]);
const withoutType = project({ ...baseWindow, wingCount: 3 }); const withoutType = project({ ...baseWindow, wingCount: 3 });
const linesOf = (p: Project) => const a = stulpBlockCenters(withType, "mittel").filter((x) => x > 1.2 && x < 2.0);
linesOfClass(p, "window-mullion") const b = linesOfClass(withoutType, "window-mullion")
.map((pr) => (pr.kind === "line" ? pr.a.x : NaN)) .map((pr) => (pr.kind === "line" ? pr.a.x : NaN))
.sort((a, b) => a - b); .sort((x, y) => x - y);
const a = linesOf(withType);
const b = linesOf(withoutType);
expect(a.length).toBe(b.length); expect(a.length).toBe(b.length);
a.forEach((v, i) => expect(v).toBeCloseTo(b[i], 9)); a.forEach((v, i) => expect(v).toBeCloseTo(b[i], 9));
}); });