Ansicht-Fenster im VW-Detail: Flügelrahmen, Sims mit Tropfkante, exakte Symbole
Nutzer-Referenz: drei ablesbare Konturen (Blendrahmen → Flügelprofil → Glas) je Flügel; Fensterbank als zwei seitlich überstehende Bänder (Bank + Tropfkante, Default an, aus bei sillBoard keine/innen); die DIN-Öffnungs- symbole starten/enden jetzt EXAKT auf den Glasfeld-Ecken (Dreh: Spitze am Bandseiten-Mittel des Glasfelds, Kipp: Spitze oben Mitte — wie VW; vorher sassen die Anker auf der Flügelspanne statt dem Glasfeld). 737/737 grün.
This commit is contained in:
+72
-10
@@ -423,7 +423,11 @@ interface ProjectedOpening {
|
|||||||
glass: Array<Array<[number, number]>>;
|
glass: Array<Array<[number, number]>>;
|
||||||
/** Teilungslinien (Pfosten/Kämpfer) über den Rahmen. */
|
/** Teilungslinien (Pfosten/Kämpfer) über den Rahmen. */
|
||||||
divisions: Array<[[number, number], [number, number]]>;
|
divisions: Array<[[number, number], [number, number]]>;
|
||||||
/** Öffnungssymbol (DIN-Ansicht): gestrichelte Linien zum Bandseiten-Mittel. */
|
/** Flügelrahmen-Rechtecke (Kontur je öffenbarem/festem Flügel). */
|
||||||
|
sashRects: Array<Array<[number, number]>>;
|
||||||
|
/** Fensterbank (Sims): Bank + Tropfkante als zwei Bänder unter dem Rahmen. */
|
||||||
|
sill: Array<Array<[number, number]>>;
|
||||||
|
/** Öffnungssymbol (DIN-Ansicht): Linien exakt auf den Glasfeld-Ecken. */
|
||||||
symbol: Array<[[number, number], [number, number]]>;
|
symbol: Array<[[number, number], [number, number]]>;
|
||||||
/** Tür (Blatt-Fläche statt Glas, ausser Glas-Blatt). */
|
/** Tür (Blatt-Fläche statt Glas, ausser Glas-Blatt). */
|
||||||
isDoor: boolean;
|
isDoor: boolean;
|
||||||
@@ -476,7 +480,7 @@ function projectOpeningRect(
|
|||||||
if (depth <= EPS) continue;
|
if (depth <= EPS) continue;
|
||||||
// pts-Reihenfolge: [unten-von, unten-bis, oben-bis, oben-von] — Basis für
|
// pts-Reihenfolge: [unten-von, unten-bis, oben-bis, oben-von] — Basis für
|
||||||
// die (fa, fz)-Interpolation der Flügel-/Glasfelder in collectOpenings.
|
// die (fa, fz)-Interpolation der Flügel-/Glasfelder in collectOpenings.
|
||||||
return { pts, depth, glass: [], divisions: [], symbol: [], isDoor: false };
|
return { pts, depth, glass: [], divisions: [], sashRects: [], sill: [], symbol: [], isDoor: false };
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -575,29 +579,57 @@ function collectOpenings(project: Project, frame: ElevationFrame): ProjectedOpen
|
|||||||
pr.divisions.push([quadAt(pr.pts, fm, fz), quadAt(pr.pts, fm, fieldTop)]);
|
pr.divisions.push([quadAt(pr.pts, fm, fz), quadAt(pr.pts, fm, fieldTop)]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
pr.glass.push(rect(pr.pts, fa0 + fa * 0.3, fa1 - fa * 0.3, fz, fieldTop));
|
// Flügelrahmen (Kontur) + Glas darin eingerückt (VW: Blendrahmen →
|
||||||
|
// Flügelprofil → Glas als drei ablesbare Konturen).
|
||||||
|
pr.sashRects.push(rect(pr.pts, fa0, fa1, fz, fieldTop));
|
||||||
|
const spw = Math.min(0.06, Math.max(0.03, fw)); // Flügelprofil (m)
|
||||||
|
const gU = spw / Math.max(w, 1e-6);
|
||||||
|
const gV = spw / Math.max(h, 1e-6);
|
||||||
|
const gA = fa0 + gU;
|
||||||
|
const gB = fa1 - gU;
|
||||||
|
const gz0 = fz + gV;
|
||||||
|
const gz1 = fieldTop - gV;
|
||||||
|
if (gB - gA > 1e-6 && gz1 - gz0 > 1e-6) {
|
||||||
|
pr.glass.push(rect(pr.pts, gA, gB, gz0, gz1));
|
||||||
|
}
|
||||||
// Trennlinie zum nächsten Feld (ausser am Rand).
|
// Trennlinie zum nächsten Feld (ausser am Rand).
|
||||||
if (fa1 < 1 - fa - 1e-6) {
|
if (fa1 < 1 - fa - 1e-6) {
|
||||||
pr.divisions.push([quadAt(pr.pts, fa1, fz), quadAt(pr.pts, fa1, fieldTop)]);
|
pr.divisions.push([quadAt(pr.pts, fa1, fz), quadAt(pr.pts, fa1, fieldTop)]);
|
||||||
}
|
}
|
||||||
// Öffnungssymbol (DIN-Ansicht, gestrichelt): Spitze am Bandseiten-Mittel.
|
// Öffnungssymbol (DIN): Linien starten/enden EXAKT auf den Glasfeld-
|
||||||
|
// Ecken (Nutzer-Report: Anker waren daneben). Dreh: Spitze am
|
||||||
|
// Bandseiten-Mittel des Glasfelds; Kipp: Spitze oben Mitte (VW).
|
||||||
const kind = sd.opening ?? wt?.kind ?? "fest";
|
const kind = sd.opening ?? wt?.kind ?? "fest";
|
||||||
if (kind === "dreh" || kind === "drehkipp") {
|
if (kind === "dreh" || kind === "drehkipp") {
|
||||||
const hingeLeft = (sd.hingeSide ?? "left") === "left";
|
const hingeLeft = (sd.hingeSide ?? "left") === "left";
|
||||||
const apex = quadAt(pr.pts, hingeLeft ? fa0 : fa1, (fz + fieldTop) / 2);
|
const apex = quadAt(pr.pts, hingeLeft ? gA : gB, (gz0 + gz1) / 2);
|
||||||
|
const farU = hingeLeft ? gB : gA;
|
||||||
pr.symbol.push(
|
pr.symbol.push(
|
||||||
[quadAt(pr.pts, hingeLeft ? fa1 : fa0, fz), apex],
|
[quadAt(pr.pts, farU, gz0), apex],
|
||||||
[quadAt(pr.pts, hingeLeft ? fa1 : fa0, fieldTop), apex],
|
[quadAt(pr.pts, farU, gz1), apex],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (kind === "kipp" || kind === "drehkipp") {
|
if (kind === "kipp" || kind === "drehkipp") {
|
||||||
const apex = quadAt(pr.pts, (fa0 + fa1) / 2, fz);
|
const apex = quadAt(pr.pts, (gA + gB) / 2, gz1);
|
||||||
pr.symbol.push(
|
pr.symbol.push(
|
||||||
[quadAt(pr.pts, fa0, fieldTop), apex],
|
[quadAt(pr.pts, gA, gz0), apex],
|
||||||
[quadAt(pr.pts, fa1, fieldTop), apex],
|
[quadAt(pr.pts, gB, gz0), apex],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Fensterbank (Sims, VW): Bank + Tropfkante als zwei Bänder unter dem
|
||||||
|
// Rahmen, seitlich leicht überstehend. Default AN (sillBoard fehlt),
|
||||||
|
// aus bei "keine"/"innen".
|
||||||
|
const sb = wt?.sillBoard;
|
||||||
|
if (sb !== "keine" && sb !== "innen") {
|
||||||
|
const ov1 = 0.02 / Math.max(w, 1e-6);
|
||||||
|
const ov2 = 0.05 / Math.max(w, 1e-6);
|
||||||
|
const h1 = 0.035 / Math.max(h, 1e-6);
|
||||||
|
const h2 = 0.025 / Math.max(h, 1e-6);
|
||||||
|
pr.sill.push(rect(pr.pts, -ov1, 1 + ov1, -h1, 0));
|
||||||
|
pr.sill.push(rect(pr.pts, -ov2, 1 + ov2, -(h1 + h2), -h1));
|
||||||
|
}
|
||||||
|
|
||||||
// Oberlicht: eigenes Glasfeld + Kämpferlinie.
|
// Oberlicht: eigenes Glasfeld + Kämpferlinie.
|
||||||
if (fTr > 0) {
|
if (fTr > 0) {
|
||||||
pr.glass.push(rect(pr.pts, fa, 1 - fa, fTr + fz / 2, 1 - fz));
|
pr.glass.push(rect(pr.pts, fa, 1 - fa, fTr + fz / 2, 1 - fz));
|
||||||
@@ -969,6 +1001,36 @@ export function generateElevationPlan(
|
|||||||
hatch: NO_HATCH,
|
hatch: NO_HATCH,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
// Sims (Bank + Tropfkante) — weiss gefüllt (verdeckt die Fassade), Kontur.
|
||||||
|
for (const sRect of op.sill) {
|
||||||
|
items.push({
|
||||||
|
depth: d,
|
||||||
|
seq: seq++,
|
||||||
|
prim: {
|
||||||
|
kind: "polygon",
|
||||||
|
pts: toVec(sRect),
|
||||||
|
fill: mono ? "#ffffff" : FRAME_FILL,
|
||||||
|
stroke: EDGE_INK,
|
||||||
|
strokeWidthMm: EDGE_MM,
|
||||||
|
hatch: NO_HATCH,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Flügelrahmen-Konturen (zwischen Blendrahmen und Glas).
|
||||||
|
for (const sRect of op.sashRects) {
|
||||||
|
items.push({
|
||||||
|
depth: d,
|
||||||
|
seq: seq++,
|
||||||
|
prim: {
|
||||||
|
kind: "polygon",
|
||||||
|
pts: toVec(sRect),
|
||||||
|
fill: "none",
|
||||||
|
stroke: EDGE_INK,
|
||||||
|
strokeWidthMm: EDGE_MM,
|
||||||
|
hatch: NO_HATCH,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
for (const g of op.glass) {
|
for (const g of op.glass) {
|
||||||
items.push({
|
items.push({
|
||||||
depth: d,
|
depth: d,
|
||||||
|
|||||||
Reference in New Issue
Block a user