Files
DOSSIER-STANDALONE/src/plan/generatePlan.openings.test.ts
T
karim 26fbd11b73 Bauteile Gruppe A (4-6): Treppe-Referenz, Fenster-Fluegel, Tuer-wandoeffnung
- Treppe referenz links/mitte/rechts (Stair.referenz, Default mitte): Perp-Versatz
  referenzMidShift auf start/center, Lauflinie/Pfeil bleiben visuell zentriert.
- Fenster Fluegel-Mittelpfosten (Opening.wingCount 1-4, Default 1): wingCount-1
  Querlinien im Rahmen (window-mullion), nur mittel/fein.
- Tuer-Typ wandoeffnung (Opening.doorType, Default normal): ueberspringt
  Tuerblatt + Schwenkbogen, Laibung/Sturz bleiben.
- Alle Modellfelder optional/rueckwaertskompatibel. 17 neue Tests.
  vitest 292/292, tsc sauber.
2026-07-05 02:33:48 +02:00

150 lines
5.2 KiB
TypeScript

/**
* Unit-Tests für die Öffnungs-Symbole im Grundriss (generatePlan):
* • Item 5 — Fenster Flügel-Mittelpfosten: bei wingCount=3 werden genau 2
* Pfosten-Linien (Querlinien) erzeugt; wingCount=1/undefined ⇒ keine.
* • Item 6 — Tür-Typ „wandoeffnung": kein Türblatt, kein Schwenkbogen (arc);
* „normal" (Default) zeichnet Blatt + Bogen wie bisher.
*/
import { describe, it, expect } from "vitest";
import { generatePlan } from "./generatePlan";
import type { Opening, Project, Wall } from "../model/types";
/** Minimalprojekt mit einer Wand + einer Öffnung, konfigurierbar. */
function projectWithOpening(opening: Opening): Project {
const wall: Wall = {
id: "W1",
type: "wall",
floorId: "eg",
categoryCode: "20",
start: { x: 0, y: 0 },
end: { x: 4, y: 0 },
wallTypeId: "aw",
height: 2.6,
};
return {
id: "t",
name: "T",
lineStyles: [{ id: "thin", name: "d", weight: 0.13, color: "#111", dash: null }],
hatches: [{ id: "none", name: "Ohne", pattern: "none", scale: 1, angle: 0, color: "#111" }],
components: [{ id: "a", name: "A", color: "#d8d2c7", hatchId: "none", joinPriority: 10 }],
wallTypes: [{ id: "aw", name: "AW", layers: [{ componentId: "a", thickness: 0.3 }] }],
drawingLevels: [
{ id: "eg", name: "EG", kind: "floor", visible: true, locked: false, floorHeight: 2.6, cutHeight: 1.0, baseElevation: 0 },
],
layers: [
{ code: "20", name: "Wände", color: "#0a0a0a", lw: 0.5, visible: true, locked: false },
{ code: "21", name: "Öffnungen", color: "#0a0a0a", lw: 0.3, visible: true, locked: false },
],
walls: [wall],
doors: [],
openings: [opening],
ceilings: [],
stairs: [],
rooms: [],
drawings2d: [],
context: [],
};
}
const visible = new Set(["20", "21"]);
/** Basis-Fenster (Brüstung 0, damit keine Sill-Linie mitzählt). */
const baseWindow: Opening = {
id: "F1",
type: "opening",
hostWallId: "W1",
categoryCode: "21",
kind: "window",
position: 1.0,
width: 1.6,
height: 1.2,
sillHeight: 0,
};
/** Basis-Tür. */
const baseDoor: Opening = {
id: "T1",
type: "opening",
hostWallId: "W1",
categoryCode: "21",
kind: "door",
position: 1.0,
width: 0.9,
height: 2.0,
sillHeight: 0,
swing: "left",
hinge: "start",
};
/** Zählt Mittelpfosten-Linien (cls "window-mullion") im Plan. */
const mullionCount = (p: Project) =>
generatePlan(p, "eg", visible, undefined, "mittel").primitives.filter(
(pr) => pr.kind === "line" && pr.cls === "window-mullion",
).length;
describe("generatePlan — Fenster Flügel-Mittelpfosten (Item 5)", () => {
it("wingCount=3 erzeugt genau 2 Pfosten-Linien", () => {
expect(mullionCount(projectWithOpening({ ...baseWindow, wingCount: 3 }))).toBe(2);
});
it("wingCount=1 erzeugt keine Pfosten", () => {
expect(mullionCount(projectWithOpening({ ...baseWindow, wingCount: 1 }))).toBe(0);
});
it("ohne wingCount (Default) keine Pfosten — rückwärtskompatibel", () => {
expect(mullionCount(projectWithOpening({ ...baseWindow }))).toBe(0);
});
it("wingCount=4 erzeugt 3 Pfosten", () => {
expect(mullionCount(projectWithOpening({ ...baseWindow, wingCount: 4 }))).toBe(3);
});
it("Pfosten sind reine Linien ohne Strichmuster (kein dash)", () => {
const plan = generatePlan(projectWithOpening({ ...baseWindow, wingCount: 3 }), "eg", visible, undefined, "mittel");
const mullions = plan.primitives.filter(
(pr) => pr.kind === "line" && pr.cls === "window-mullion",
);
for (const m of mullions) {
expect((m as { dash?: number[] | null }).dash ?? null).toBeNull();
}
});
it("bei grob keine Pfosten (nur mittel/fein)", () => {
const plan = generatePlan(projectWithOpening({ ...baseWindow, wingCount: 3 }), "eg", visible, undefined, "grob");
const n = plan.primitives.filter((pr) => pr.kind === "line" && pr.cls === "window-mullion").length;
expect(n).toBe(0);
});
});
describe("generatePlan — Tür-Typ wandoeffnung (Item 6)", () => {
/** Zählt Bögen (arc-Primitive) im Plan. */
const arcCount = (p: Project, detail: "grob" | "mittel" | "fein" = "mittel") =>
generatePlan(p, "eg", visible, undefined, detail).primitives.filter((pr) => pr.kind === "arc").length;
/** Zählt Türblatt-Linien (cls "door-leaf"). */
const leafCount = (p: Project) =>
generatePlan(p, "eg", visible, undefined, "mittel").primitives.filter(
(pr) => pr.kind === "line" && pr.cls === "door-leaf",
).length;
it("wandoeffnung erzeugt KEINE Bögen (arc)", () => {
expect(arcCount(projectWithOpening({ ...baseDoor, doorType: "wandoeffnung" }))).toBe(0);
});
it("wandoeffnung erzeugt KEIN Türblatt", () => {
expect(leafCount(projectWithOpening({ ...baseDoor, doorType: "wandoeffnung" }))).toBe(0);
});
it("normal (Default) erzeugt Türblatt + Schwenkbogen", () => {
const normal = projectWithOpening({ ...baseDoor, doorType: "normal" });
expect(leafCount(normal)).toBe(1);
expect(arcCount(normal)).toBe(1);
});
it("ohne doorType (Default) verhält sich wie normal — rückwärtskompatibel", () => {
const def = projectWithOpening({ ...baseDoor });
expect(leafCount(def)).toBe(1);
expect(arcCount(def)).toBe(1);
});
});