Tür/Fenster 2D: Rahmenband, Blockrahmen, Schichteinzug, Oberlicht-Linie
Setzt die vertieften Tür-/Fensterparameter im Grundriss-Schnitt um: - opening-frame: Rahmenprofil als Band der Breite frameWidth in der Laibung; Blockrahmen (Tür) als kräftigeres, vor die Laibung gesetztes Profil, Zarge als schmales Laibungsband. - Schichteinzug: die gewählte Fläche (aussen/innen) wird um insetFromFace nach innen versetzt (Nahkante wandert, Fernkante bleibt). - opening-transom: gestrichelte Überkopf-Linie über der Öffnung, wenn transomHeight > 0. Typlose Öffnungen zeichnen unverändert (Rückwärtskompatibilität getestet). +5 Tests. tsc sauber, vitest grün.
This commit is contained in:
@@ -0,0 +1,212 @@
|
|||||||
|
/**
|
||||||
|
* Unit-Tests für die Tür-/Fenstertyp-Rahmenparameter im Grundriss
|
||||||
|
* (generatePlan): Rahmenband (Zarge/Blockrahmen), Schichteinzug (insetFromFace/
|
||||||
|
* insetFace), Oberlicht (transomHeight). `mullionRows` bleibt bewusst ungetestet
|
||||||
|
* — Kämpfer-Zeilen sind im Grundriss-Schnitt unsichtbar (3D-Sache).
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { describe, it, expect } from "vitest";
|
||||||
|
import { generatePlan } from "./generatePlan";
|
||||||
|
import type { DoorType, Opening, Project, Wall, WindowType } from "../model/types";
|
||||||
|
|
||||||
|
/** Minimalprojekt: eine Wand (Dicke 0.3 m, Achse mittig) + Öffnungen und
|
||||||
|
* optionale Tür-/Fenstertyp-Bibliotheken, konfigurierbar je Test. */
|
||||||
|
function project(
|
||||||
|
openings: Opening[],
|
||||||
|
opts: { doorTypes?: DoorType[]; windowTypes?: WindowType[] } = {},
|
||||||
|
): 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 }] }],
|
||||||
|
doorTypes: opts.doorTypes,
|
||||||
|
windowTypes: opts.windowTypes,
|
||||||
|
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,
|
||||||
|
ceilings: [],
|
||||||
|
stairs: [],
|
||||||
|
rooms: [],
|
||||||
|
drawings2d: [],
|
||||||
|
context: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const visible = new Set(["20", "21"]);
|
||||||
|
|
||||||
|
/** Basis-Fenster, jenseits der Tür auf derselben Wandachse. */
|
||||||
|
const baseWindow: Opening = {
|
||||||
|
id: "F1",
|
||||||
|
type: "opening",
|
||||||
|
hostWallId: "W1",
|
||||||
|
categoryCode: "21",
|
||||||
|
kind: "window",
|
||||||
|
position: 2.0,
|
||||||
|
width: 1.2,
|
||||||
|
height: 1.2,
|
||||||
|
sillHeight: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Basis-Tür. */
|
||||||
|
const baseDoor: Opening = {
|
||||||
|
id: "T1",
|
||||||
|
type: "opening",
|
||||||
|
hostWallId: "W1",
|
||||||
|
categoryCode: "21",
|
||||||
|
kind: "door",
|
||||||
|
position: 0.2,
|
||||||
|
width: 0.9,
|
||||||
|
height: 2.0,
|
||||||
|
sillHeight: 0,
|
||||||
|
swing: "left",
|
||||||
|
hinge: "start",
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Fenstertyp mit Rahmen, Schichteinzug (aussen) und Oberlicht. */
|
||||||
|
const windowType: WindowType = {
|
||||||
|
id: "wt1",
|
||||||
|
name: "Fenstertyp Test",
|
||||||
|
kind: "dreh",
|
||||||
|
wingCount: 1,
|
||||||
|
glazing: "zweifach",
|
||||||
|
frameThickness: 0.06,
|
||||||
|
frameWidth: 0.05,
|
||||||
|
insetFromFace: 0.05,
|
||||||
|
insetFace: "aussen",
|
||||||
|
transomHeight: 0.3,
|
||||||
|
defaultSillHeight: 0.8,
|
||||||
|
defaultWidth: 1.2,
|
||||||
|
defaultHeight: 1.2,
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Türtyp mit Blockrahmen, Schichteinzug (innen) und Oberlicht. */
|
||||||
|
const doorType: DoorType = {
|
||||||
|
id: "dt1",
|
||||||
|
name: "Türtyp Test",
|
||||||
|
kind: "dreh",
|
||||||
|
leafCount: 1,
|
||||||
|
leafStyle: "glatt",
|
||||||
|
frameThickness: 0.06,
|
||||||
|
frameKind: "blockrahmen",
|
||||||
|
frameWidth: 0.06,
|
||||||
|
insetFromFace: 0.04,
|
||||||
|
insetFace: "innen",
|
||||||
|
transomHeight: 0.4,
|
||||||
|
defaultWidth: 0.9,
|
||||||
|
defaultHeight: 2.0,
|
||||||
|
};
|
||||||
|
|
||||||
|
type LinePrim = Extract<ReturnType<typeof generatePlan>["primitives"][number], { kind: "line" }>;
|
||||||
|
|
||||||
|
function linesOfClass(p: Project, cls: string, openingId?: string): LinePrim[] {
|
||||||
|
return generatePlan(p, "eg", visible, undefined, "mittel").primitives.filter(
|
||||||
|
(pr): pr is LinePrim =>
|
||||||
|
pr.kind === "line" && pr.cls === cls && (!openingId || pr.openingId === openingId),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe("generatePlan — Tür-/Fenstertyp-Rahmenband (opening-frame)", () => {
|
||||||
|
it("erzeugt Rahmenband-Primitive für Tür UND Fenster mit referenziertem Typ", () => {
|
||||||
|
const p = project(
|
||||||
|
[
|
||||||
|
{ ...baseWindow, typeId: "wt1" },
|
||||||
|
{ ...baseDoor, typeId: "dt1" },
|
||||||
|
],
|
||||||
|
{ doorTypes: [doorType], windowTypes: [windowType] },
|
||||||
|
);
|
||||||
|
expect(linesOfClass(p, "opening-frame").length).toBeGreaterThan(0);
|
||||||
|
// Je Öffnung ein geschlossenes Rechteck aus 4 Kanten.
|
||||||
|
expect(linesOfClass(p, "opening-frame", "F1").length).toBe(4);
|
||||||
|
expect(linesOfClass(p, "opening-frame", "T1").length).toBe(4);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("Blockrahmen (Tür) zeichnet eine kräftigere Linie als die Zargen-Optik (Fenster)", () => {
|
||||||
|
const p = project(
|
||||||
|
[
|
||||||
|
{ ...baseWindow, typeId: "wt1" },
|
||||||
|
{ ...baseDoor, typeId: "dt1" },
|
||||||
|
],
|
||||||
|
{ doorTypes: [doorType], windowTypes: [windowType] },
|
||||||
|
);
|
||||||
|
const doorWeight = linesOfClass(p, "opening-frame", "T1")[0].weightMm;
|
||||||
|
const windowWeight = linesOfClass(p, "opening-frame", "F1")[0].weightMm;
|
||||||
|
expect(doorWeight).toBeGreaterThan(windowWeight);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("generatePlan — Oberlicht (opening-transom)", () => {
|
||||||
|
it("erscheint genau dann, wenn transomHeight > 0", () => {
|
||||||
|
const withTransom = project([{ ...baseWindow, typeId: "wt1" }], { windowTypes: [windowType] });
|
||||||
|
const transomLines = linesOfClass(withTransom, "opening-transom", "F1");
|
||||||
|
expect(transomLines.length).toBe(1);
|
||||||
|
expect(Array.isArray(transomLines[0].dash) && transomLines[0].dash!.length).toBeGreaterThan(0);
|
||||||
|
|
||||||
|
const noTransomType: WindowType = { ...windowType, id: "wt2", transomHeight: 0 };
|
||||||
|
const withoutTransom = project([{ ...baseWindow, typeId: "wt2" }], { windowTypes: [noTransomType] });
|
||||||
|
expect(linesOfClass(withoutTransom, "opening-transom", "F1").length).toBe(0);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("generatePlan — Schichteinzug (insetFromFace/insetFace)", () => {
|
||||||
|
it("verschiebt die Rahmen-Nahfläche um den Einzugsbetrag, die Gegenfläche bleibt unverändert", () => {
|
||||||
|
const flushType: WindowType = { ...windowType, id: "wt-flush", insetFromFace: 0 };
|
||||||
|
const inset = project([{ ...baseWindow, typeId: "wt1" }], { windowTypes: [windowType] });
|
||||||
|
const flush = project([{ ...baseWindow, typeId: "wt-flush" }], { windowTypes: [flushType] });
|
||||||
|
|
||||||
|
// Die Wandachse ist horizontal (u=(1,0)) ⇒ Wandnormale n=(0,1); die
|
||||||
|
// y-Koordinate der Rahmenband-Punkte entspricht direkt dem Offset quer zur
|
||||||
|
// Wand. Die "aussen"-Fläche liegt bei +n — ihr Rahmenrand muss um genau
|
||||||
|
// `insetFromFace` (0.05 m) nach innen (kleineres y) rücken; die
|
||||||
|
// gegenüberliegende ("innen"-)Fläche bleibt unverändert.
|
||||||
|
const insetYs = linesOfClass(inset, "opening-frame", "F1").flatMap((l) => [l.a.y, l.b.y]);
|
||||||
|
const flushYs = linesOfClass(flush, "opening-frame", "F1").flatMap((l) => [l.a.y, l.b.y]);
|
||||||
|
|
||||||
|
expect(Math.max(...flushYs) - Math.max(...insetYs)).toBeCloseTo(0.05, 9);
|
||||||
|
expect(Math.min(...insetYs)).toBeCloseTo(Math.min(...flushYs), 9);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe("generatePlan — Rückwärtskompatibilität (Öffnung ohne typeId)", () => {
|
||||||
|
it("liefert exakt dieselben Primitive, ob Typ-Bibliotheken im Projekt existieren oder nicht", () => {
|
||||||
|
const withResources = project([{ ...baseWindow }, { ...baseDoor }], {
|
||||||
|
doorTypes: [doorType],
|
||||||
|
windowTypes: [windowType],
|
||||||
|
});
|
||||||
|
const withoutResources = project([{ ...baseWindow }, { ...baseDoor }]);
|
||||||
|
|
||||||
|
const a = generatePlan(withResources, "eg", visible, undefined, "mittel").primitives;
|
||||||
|
const b = generatePlan(withoutResources, "eg", visible, undefined, "mittel").primitives;
|
||||||
|
expect(a).toEqual(b);
|
||||||
|
expect(a.some((pr) => pr.kind === "line" && pr.cls === "opening-frame")).toBe(false);
|
||||||
|
expect(a.some((pr) => pr.kind === "line" && pr.cls === "opening-transom")).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -28,10 +28,12 @@ import {
|
|||||||
flattenCategories,
|
flattenCategories,
|
||||||
getCeilingType,
|
getCeilingType,
|
||||||
getComponent,
|
getComponent,
|
||||||
|
getDoorType,
|
||||||
getHatch,
|
getHatch,
|
||||||
getLayerCategory,
|
getLayerCategory,
|
||||||
getLineStyle,
|
getLineStyle,
|
||||||
getWallType,
|
getWallType,
|
||||||
|
getWindowType,
|
||||||
openingLabel,
|
openingLabel,
|
||||||
openingsOfWall,
|
openingsOfWall,
|
||||||
roomsOfFloor,
|
roomsOfFloor,
|
||||||
@@ -1863,6 +1865,166 @@ function addDoorSymbol(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Aufgelöste Rahmen-Parameter (Typ-Bibliothek) einer Tür-/Fenster-Öffnung —
|
||||||
|
* nur vorhanden, wenn die Öffnung einen Bauteil-Typ referenziert (`typeId`).
|
||||||
|
* Fehlt der Typ, bleibt das heutige Inline-Verhalten unverändert (kein
|
||||||
|
* Rahmenband, kein Oberlicht) — siehe `resolveOpeningFrameSpec`.
|
||||||
|
*/
|
||||||
|
interface OpeningFrameSpec {
|
||||||
|
frameWidth: number;
|
||||||
|
/** Nur bei Türen relevant; Fenster zeichnen stets die schmale Zargen-Optik. */
|
||||||
|
frameKind: "zarge" | "blockrahmen";
|
||||||
|
insetFromFace: number;
|
||||||
|
insetFace: "aussen" | "innen";
|
||||||
|
transomHeight: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Löst die Rahmen-Parameter aus dem referenzierten Tür-/Fenstertyp auf (samt
|
||||||
|
* Defaults); `undefined`, wenn kein Typ referenziert/auflösbar ist — die
|
||||||
|
* Öffnung bleibt dann beim heutigen Inline-Verhalten (rückwärtskompatibel).
|
||||||
|
*/
|
||||||
|
function resolveOpeningFrameSpec(project: Project, o: Opening): OpeningFrameSpec | undefined {
|
||||||
|
if (o.kind === "door") {
|
||||||
|
const t = getDoorType(project, o);
|
||||||
|
if (!t) return undefined;
|
||||||
|
return {
|
||||||
|
frameWidth: t.frameWidth ?? 0.06,
|
||||||
|
frameKind: t.frameKind ?? "zarge",
|
||||||
|
insetFromFace: t.insetFromFace ?? 0,
|
||||||
|
insetFace: t.insetFace ?? "aussen",
|
||||||
|
transomHeight: t.transomHeight ?? 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const t = getWindowType(project, o);
|
||||||
|
if (!t) return undefined;
|
||||||
|
return {
|
||||||
|
frameWidth: t.frameWidth ?? 0.06,
|
||||||
|
frameKind: "zarge",
|
||||||
|
insetFromFace: t.insetFromFace ?? 0,
|
||||||
|
insetFace: t.insetFace ?? "aussen",
|
||||||
|
transomHeight: t.transomHeight ?? 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rahmenband + Oberlicht-Andeutung einer Tür-/Fenstertyp-Öffnung im
|
||||||
|
* Grundriss-Schnitt. Nur aufgerufen, wenn `resolveOpeningFrameSpec` einen Typ
|
||||||
|
* liefert — sonst bleibt die Darstellung exakt wie zuvor (kein neues Primitiv).
|
||||||
|
*
|
||||||
|
* • Zarge — schmales Umlauf-Rahmenband, ringsum um `frameWidth`
|
||||||
|
* von der vollen Öffnung (Pfosten × Wanddicke) nach innen eingezogen.
|
||||||
|
* • Blockrahmen (Tür) — kräftiges Rechteckprofil, sitzt PROUD an der
|
||||||
|
* gewählten Fläche (kein Einzug an den Pfosten, nur eine Tiefenscheibe von
|
||||||
|
* `frameWidth` ab der Nah-Fläche), kräftigere Linie.
|
||||||
|
* • Schichteinzug — verschiebt die Nah-Fläche des Rahmens um
|
||||||
|
* `insetFromFace` von der gewählten Wandfläche nach innen; die Gegenfläche
|
||||||
|
* bleibt unverändert (der Rahmen reicht weiterhin bis dorthin).
|
||||||
|
* • Oberlicht — Überkopf-Andeutung (gestrichelte Linie quer über die
|
||||||
|
* Öffnung), nur wenn `transomHeight > 0`.
|
||||||
|
*/
|
||||||
|
function addOpeningFrameBand(
|
||||||
|
out: Primitive[],
|
||||||
|
project: Project,
|
||||||
|
wall: Wall,
|
||||||
|
o: Opening,
|
||||||
|
spec: OpeningFrameSpec,
|
||||||
|
greyed: boolean,
|
||||||
|
): void {
|
||||||
|
const jambs = openingJambs(wall, o);
|
||||||
|
if (!jambs) return;
|
||||||
|
const { n } = wallAxisFrame(wall);
|
||||||
|
const total = wallTypeThickness(getWallType(project, wall));
|
||||||
|
const refOff = wallReferenceOffset(wall, total);
|
||||||
|
const outerFace = refOff + total / 2; // "aussen"-Fläche (+n)
|
||||||
|
const innerFace = refOff - total / 2; // "innen"-Fläche (−n)
|
||||||
|
|
||||||
|
// Schichteinzug: die GEWÄHLTE Fläche rückt um `insetFromFace` nach innen; die
|
||||||
|
// gegenüberliegende Fläche bleibt unverändert (der Rahmen reicht weiterhin
|
||||||
|
// bis dorthin) — vgl. DoorType.insetFromFace/WindowType.insetFromFace.
|
||||||
|
const clampedInset = Math.max(0, Math.min(spec.insetFromFace, total));
|
||||||
|
const nearIsAussen = spec.insetFace !== "innen";
|
||||||
|
const faceNear = nearIsAussen ? outerFace - clampedInset : innerFace + clampedInset;
|
||||||
|
const faceFar = nearIsAussen ? innerFace : outerFace;
|
||||||
|
const lo = Math.min(faceNear, faceFar);
|
||||||
|
const hi = Math.max(faceNear, faceFar);
|
||||||
|
|
||||||
|
const { jambStart, jambEnd } = jambs;
|
||||||
|
const frameWidth = Math.max(0, spec.frameWidth);
|
||||||
|
const isBlock = o.kind === "door" && spec.frameKind === "blockrahmen";
|
||||||
|
const color = o.color ?? POCHE_STROKE;
|
||||||
|
|
||||||
|
let bandLo: number;
|
||||||
|
let bandHi: number;
|
||||||
|
let jStart: Vec2;
|
||||||
|
let jEnd: Vec2;
|
||||||
|
let weightMm: number;
|
||||||
|
if (isBlock) {
|
||||||
|
// Blockrahmen: volle Öffnungsbreite (kein Pfosten-Einzug), nur eine
|
||||||
|
// Tiefenscheibe von frameWidth ab der Nah-Fläche — sitzt proud VOR/auf der
|
||||||
|
// Laibung, statt schmal darin zu verschwinden (Zargen-Optik).
|
||||||
|
const depth = Math.min(frameWidth, hi - lo);
|
||||||
|
bandLo = nearIsAussen ? hi - depth : lo;
|
||||||
|
bandHi = nearIsAussen ? hi : lo + depth;
|
||||||
|
jStart = jambStart;
|
||||||
|
jEnd = jambEnd;
|
||||||
|
weightMm = SYMBOL_HAIRLINE_MM * 2.2;
|
||||||
|
} else {
|
||||||
|
// Zarge: ringsum um frameWidth von der vollen Öffnung eingezogenes,
|
||||||
|
// schmales Rahmenband (Laibungs-Anschlaglinie).
|
||||||
|
const jambSpan = Math.hypot(jambEnd.x - jambStart.x, jambEnd.y - jambStart.y);
|
||||||
|
const jambInset = Math.min(frameWidth, jambSpan / 2);
|
||||||
|
jStart = along(jambStart, jambEnd, jambInset);
|
||||||
|
jEnd = along(jambEnd, jambStart, jambInset);
|
||||||
|
const depthInset = Math.min(frameWidth, (hi - lo) / 2);
|
||||||
|
bandLo = lo + depthInset;
|
||||||
|
bandHi = hi - depthInset;
|
||||||
|
weightMm = SYMBOL_HAIRLINE_MM;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Geschlossenes Rechteck aus 4 Kanten (Primitive "line", nicht "polygon" —
|
||||||
|
// so bleibt das Band per `cls` selektierbar/testbar wie die übrigen Symbole).
|
||||||
|
const p1 = add(jStart, scale(n, bandLo));
|
||||||
|
const p2 = add(jEnd, scale(n, bandLo));
|
||||||
|
const p3 = add(jEnd, scale(n, bandHi));
|
||||||
|
const p4 = add(jStart, scale(n, bandHi));
|
||||||
|
const edges: [Vec2, Vec2][] = [
|
||||||
|
[p1, p2],
|
||||||
|
[p2, p3],
|
||||||
|
[p3, p4],
|
||||||
|
[p4, p1],
|
||||||
|
];
|
||||||
|
for (const [a, b] of edges) {
|
||||||
|
out.push({
|
||||||
|
kind: "line",
|
||||||
|
a,
|
||||||
|
b,
|
||||||
|
cls: "opening-frame",
|
||||||
|
weightMm,
|
||||||
|
color,
|
||||||
|
greyed,
|
||||||
|
openingId: o.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Oberlicht (Überkopf-Andeutung): eine gestrichelte Linie quer über die
|
||||||
|
// Öffnung auf der Wandachse — nur wenn der Typ ein Oberlicht definiert.
|
||||||
|
if (spec.transomHeight > 0) {
|
||||||
|
out.push({
|
||||||
|
kind: "line",
|
||||||
|
a: jambStart,
|
||||||
|
b: jambEnd,
|
||||||
|
cls: "opening-transom",
|
||||||
|
weightMm: SYMBOL_HAIRLINE_MM,
|
||||||
|
dash: OVERHEAD_DASH,
|
||||||
|
color,
|
||||||
|
greyed,
|
||||||
|
openingId: o.id,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Öffnungs-Symbol (Fenster/Tür) je Detailgrad. Anders als das Legacy-`addDoorSymbol`
|
* Öffnungs-Symbol (Fenster/Tür) je Detailgrad. Anders als das Legacy-`addDoorSymbol`
|
||||||
* arbeitet diese Funktion über die reinen Geometrie-Helfer (opening.ts) und taggt
|
* arbeitet diese Funktion über die reinen Geometrie-Helfer (opening.ts) und taggt
|
||||||
@@ -1953,6 +2115,10 @@ function addOpeningSymbol(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Rahmenband (Zarge/Blockrahmen) + Oberlicht-Andeutung — nur wenn die
|
||||||
|
// Öffnung einen Türtyp referenziert (siehe `resolveOpeningFrameSpec`).
|
||||||
|
const doorFrameSpec = resolveOpeningFrameSpec(project, o);
|
||||||
|
if (doorFrameSpec) addOpeningFrameBand(out, project, wall, o, doorFrameSpec, greyed);
|
||||||
// Sturzlinien (SIA, gestrichelt) — Überkopf-Projektion des Sturzes quer über
|
// Sturzlinien (SIA, gestrichelt) — Überkopf-Projektion des Sturzes quer über
|
||||||
// die Öffnung an der Wand-Innen-/Aussenkante. Entspricht `_make_tuer_sturz_curves`
|
// die Öffnung an der Wand-Innen-/Aussenkante. Entspricht `_make_tuer_sturz_curves`
|
||||||
// im Rhino-Plugin. Default „beide" wenn nicht explizit gesetzt.
|
// im Rhino-Plugin. Default „beide" wenn nicht explizit gesetzt.
|
||||||
@@ -2065,6 +2231,11 @@ function addOpeningSymbol(
|
|||||||
openingId: o.id,
|
openingId: o.id,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// Rahmenband (Zarge) + Oberlicht-Andeutung — nur wenn die Öffnung einen
|
||||||
|
// Fenstertyp referenziert (siehe `resolveOpeningFrameSpec`). Kämpfer-Zeilen
|
||||||
|
// (`mullionRows`) bleiben im Grundriss-Schnitt unsichtbar (3D-Sache).
|
||||||
|
const windowFrameSpec = resolveOpeningFrameSpec(project, o);
|
||||||
|
if (windowFrameSpec) addOpeningFrameBand(out, project, wall, o, windowFrameSpec, greyed);
|
||||||
// fein: Anschlag-/Laibungsstriche an beiden Pfosten (kurz quer zur Wand) —
|
// fein: Anschlag-/Laibungsstriche an beiden Pfosten (kurz quer zur Wand) —
|
||||||
// analog zur Tür, damit Fenster im Detailplan gleich „fertig" wirken (bisher
|
// analog zur Tür, damit Fenster im Detailplan gleich „fertig" wirken (bisher
|
||||||
// hatten nur Türen sie). Haarlinie, 6 cm Andeutung je Seite.
|
// hatten nur Türen sie). Haarlinie, 6 cm Andeutung je Seite.
|
||||||
|
|||||||
Reference in New Issue
Block a user