Tür: Teilverglasung (glazingRatio) im 3D wirksam
DoorType.glazingRatio wurde bisher von keinem Renderer gelesen (Designdoc). Bei Glasblatt (leafStyle 'glas') füllt das Glas jetzt nur den oberen glazingRatio-Anteil des Hauptfelds; darunter bleibt ein blindes Blattfeld (z. B. Tür mit Oberglas). Fenster unberührt (glazedFraction = 1). +1 Test (Halbglas: Unterkante angehoben, Oberkante am Sturz). 673/673 grün.
This commit is contained in:
@@ -604,6 +604,52 @@ describe("Rahmen-/Sprossen-Riegel typisierter Öffnungen (emitOpeningFrames)", (
|
||||
expect(operableCount).toBe(8); // + 4 Flügelrahmen-Riegel
|
||||
});
|
||||
|
||||
it("Glastür mit glazingRatio < 1: Glas nur im oberen Blattanteil (Teilverglasung)", () => {
|
||||
const glassDoor = (glazingRatio?: number): Project => ({
|
||||
...sampleProject,
|
||||
doorTypes: [
|
||||
{
|
||||
id: "dt-glass",
|
||||
name: "Glastür Test",
|
||||
kind: "dreh",
|
||||
leafCount: 1,
|
||||
leafStyle: "glas",
|
||||
glazingRatio,
|
||||
frameThickness: 0.06,
|
||||
frameWidth: 0.06,
|
||||
defaultWidth: 0.9,
|
||||
defaultHeight: 2.0,
|
||||
},
|
||||
],
|
||||
openings: [
|
||||
{
|
||||
id: "DG",
|
||||
type: "opening",
|
||||
hostWallId: "W1",
|
||||
categoryCode: "21",
|
||||
kind: "door",
|
||||
typeId: "dt-glass",
|
||||
position: 3.0,
|
||||
width: 0.9,
|
||||
height: 2.0,
|
||||
sillHeight: 0,
|
||||
},
|
||||
],
|
||||
doors: [],
|
||||
context: [],
|
||||
});
|
||||
// Vollglas (ratio 1 / fehlt): Glas über (fast) die ganze Blatthöhe.
|
||||
const full = projectToModel3d(glassDoor(1)).meshes.filter(isGlass);
|
||||
expect(full.length).toBe(1);
|
||||
const fullR = zRange(full[0]);
|
||||
// Halbglas (ratio 0.5): Glas nur in der oberen Hälfte -> Unterkante deutlich höher.
|
||||
const half = projectToModel3d(glassDoor(0.5)).meshes.filter(isGlass);
|
||||
expect(half.length).toBe(1);
|
||||
const halfR = zRange(half[0]);
|
||||
expect(halfR.max).toBeCloseTo(fullR.max, 6); // Oberkante gleich (an OK/Sturz)
|
||||
expect(halfR.min).toBeGreaterThan(fullR.min + 0.5); // Unterkante klar angehoben
|
||||
});
|
||||
|
||||
it("insetFromFace verschiebt Rahmen-Position entlang der Wand-Normalen gegenüber bündig (kein Einzug)", () => {
|
||||
// W1-Achse (0,0)->(5,0): u=(1,0) -> Normale n=(0,-1); der Quer-Versatz
|
||||
// bildet sich rein in der Y-Koordinate ab (y = -t). insetFromFace 0.1 muss
|
||||
|
||||
+20
-3
@@ -1942,6 +1942,13 @@ interface OpeningFrameParams {
|
||||
* {@link glassPanesForOpening}.
|
||||
*/
|
||||
glazingPanes: 1 | 2 | 3;
|
||||
/**
|
||||
* Verglasungs-Anteil des HAUPTFELDS (0..1, von OBEN gemessen): 1 = voll
|
||||
* verglast (Fenster, Ganzglastür), < 1 = nur der obere Anteil ist Glas, unten
|
||||
* bleibt ein blindes Feld (z. B. Tür mit Oberglas, `DoorType.glazingRatio`).
|
||||
* Fenster: immer 1.
|
||||
*/
|
||||
glazedFraction: number;
|
||||
/**
|
||||
* Flügeleinteilung ({@link sashesOfWindowType}) — je ÖFFENBAREM Flügel wird im
|
||||
* 3D ein Flügelrahmen (Rahmen-Riegel innerhalb des Blendrahmens) erzeugt
|
||||
@@ -1975,6 +1982,8 @@ function resolveOpeningFrame(project: Project, wall: Wall, op: Opening): Opening
|
||||
mullionRows: 1,
|
||||
glazed: dt.leafStyle === "glas",
|
||||
glazingPanes: 1,
|
||||
// Teilverglasung: glazingRatio (Glasanteil oben) bei Glasblatt; sonst voll.
|
||||
glazedFraction: Math.max(0.05, Math.min(1, dt.glazingRatio ?? 1)),
|
||||
sashes: [],
|
||||
};
|
||||
}
|
||||
@@ -2014,6 +2023,7 @@ function resolveOpeningFrame(project: Project, wall: Wall, op: Opening): Opening
|
||||
mullionRows: Math.max(1, Math.round(wt.mullionRows ?? 1)),
|
||||
glazed: true,
|
||||
glazingPanes: glazingPanesOf(wt),
|
||||
glazedFraction: 1,
|
||||
sashes,
|
||||
};
|
||||
}
|
||||
@@ -2184,12 +2194,19 @@ function glassPanesForOpening(
|
||||
if (n1 <= params.nMin) break;
|
||||
}
|
||||
};
|
||||
// Teilverglasung (Türen mit glazingRatio < 1): das HAUPTFELD ist nur im oberen
|
||||
// `glazedFraction`-Anteil Glas; darunter bleibt ein blindes Blattfeld. Von der
|
||||
// OBERKANTE des Hauptbands gemessen. Fenster: glazedFraction = 1 (voll).
|
||||
const frac = Math.max(0.05, Math.min(1, params.glazedFraction));
|
||||
const glazedBottom = (bBottom: number, bTop: number) =>
|
||||
bTop - frac * (bTop - bBottom);
|
||||
if (params.transomHeight > EPS) {
|
||||
const splitZ = clampRange(vert.zTop - params.transomHeight, sashBottom, sashTopFull);
|
||||
push(sashBottom, splitZ - fw / 2); // Hauptscheibe/-blatt unterhalb des Kämpfers.
|
||||
push(splitZ + fw / 2, sashTopFull); // Oberlicht-Scheibe oberhalb des Kämpfers.
|
||||
const mainTop = splitZ - fw / 2;
|
||||
push(glazedBottom(sashBottom, mainTop), mainTop); // Hauptglas (ggf. nur oben).
|
||||
push(splitZ + fw / 2, sashTopFull); // Oberlicht-Scheibe (immer voll).
|
||||
} else {
|
||||
push(sashBottom, sashTopFull);
|
||||
push(glazedBottom(sashBottom, sashTopFull), sashTopFull);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user