Dach: Mansarden-Untertypen (Giebel/Walm/Zelt) + parametrierbarer Knick
Bisher gab es nur die Giebel-Mansarde (2-seitig). Neu über Roof.mansardType: - 'giebel' (Default): Mansard-Satteldach, Giebel an den Enden (wie bisher) - 'walm': allseitige Mansarde (Sockel + oberer Walm, kein Giebel) — 8 Flächen - 'zelt': allseitige Mansarde zur flachen Spitze — 8 Flächen, kein First Knicklage jetzt parametrierbar (Roof.mansardKneeRatio, Default 0.4 der halben Spannweite). Dach-Panel: Mansard-Art-Dropdown + Knicklage-Feld (nur bei Mansarde). +4 Geometrie-Tests (Ratio, Walm-/Zelt-Flächen/Grate). Nebenbei: Fenster-Dialog-Labels klarer als 'Einbaulage ab / Abstand von Kante' (Nutzer: wo sitzt das Fenster in der Aussparung, ab Innen-/Aussenkante + wieviel). 666/666 grün.
This commit is contained in:
@@ -102,6 +102,39 @@ describe("roofGeometry — Formen (6×4, 45°, First entlang X)", () => {
|
|||||||
expect(g.ridgeHeight).toBeGreaterThan(0);
|
expect(g.ridgeHeight).toBeGreaterThan(0);
|
||||||
expect(g.breaks[0][0].y).toBeCloseTo(0 + 2 * 0.4, 6); // yf = y0 + halfD·0.4
|
expect(g.breaks[0][0].y).toBeCloseTo(0 + 2 * 0.4, 6); // yf = y0 + halfD·0.4
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("mansarde giebel: Knick-Ratio parametriert die Knicklinien-Lage", () => {
|
||||||
|
const g = roofGeometry(
|
||||||
|
roof({ shape: "mansarde", mansardType: "giebel", mansardKneeRatio: 0.25 }),
|
||||||
|
E,
|
||||||
|
);
|
||||||
|
// yf = y0 + halfD·ratio = 0 + 2·0.25 = 0.5.
|
||||||
|
expect(g.breaks[0][0].y).toBeCloseTo(0.5, 6);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("mansarde walm: allseitig geknickt -> 8 Flächen, 4 Knicklinien (Rechteck), 8 Grate, keine Giebel", () => {
|
||||||
|
const g = roofGeometry(roof({ shape: "mansarde", mansardType: "walm" }), E);
|
||||||
|
expect(g.planes).toHaveLength(8); // 4 Sockel + 2 Walm-Trapeze + 2 Walm-Dreiecke
|
||||||
|
expect(g.breaks).toHaveLength(4); // inneres Knick-Rechteck
|
||||||
|
expect(g.hips).toHaveLength(8); // 4 Sockel-Grate + 4 obere Walm-Grate
|
||||||
|
expect(g.ridges).toHaveLength(1);
|
||||||
|
expect(g.gables).toHaveLength(0); // Walm hat keine Giebel
|
||||||
|
expect(g.ridgeHeight).toBeGreaterThan(0);
|
||||||
|
// Knick-Höhe < First-Höhe (Sockel endet unter dem First).
|
||||||
|
const kneeZ = g.planes[0].pts[2][2] - E; // z1 - e am inneren Punkt
|
||||||
|
expect(kneeZ).toBeGreaterThan(0);
|
||||||
|
expect(kneeZ).toBeLessThan(g.ridgeHeight);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("mansarde zelt: allseitig geknickt zur Spitze -> 8 Flächen, kein First, 8 Grate", () => {
|
||||||
|
const g = roofGeometry(roof({ shape: "mansarde", mansardType: "zelt" }), E);
|
||||||
|
expect(g.planes).toHaveLength(8); // 4 Sockel + 4 Spitzen-Dreiecke
|
||||||
|
expect(g.breaks).toHaveLength(4);
|
||||||
|
expect(g.hips).toHaveLength(8);
|
||||||
|
expect(g.ridges).toHaveLength(0); // Zelt hat keinen First
|
||||||
|
expect(g.gables).toHaveLength(0);
|
||||||
|
expect(g.ridgeHeight).toBeGreaterThan(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("roofGeometry — First entlang Y (Transponierung)", () => {
|
describe("roofGeometry — First entlang Y (Transponierung)", () => {
|
||||||
|
|||||||
+101
-9
@@ -174,15 +174,22 @@ function computeCanonical(
|
|||||||
}
|
}
|
||||||
|
|
||||||
case "mansarde": {
|
case "mansarde": {
|
||||||
// Sattel mit Knick: steile untere Neigung (pitchDeg) über den äusseren
|
// Mansarde: steile untere Neigung (pitchDeg) bis zur Knicklinie, dann
|
||||||
// Tiefenanteil, dann flache obere (pitchUpperDeg ?? halbe Hauptneigung).
|
// flache obere (pitchUpperDeg ?? halbe Hauptneigung). Untertyp steuert, ob
|
||||||
|
// die Knickform an ZWEI Seiten sitzt (Giebel) oder RINGSUM (Walm/Zelt).
|
||||||
const aLow = a;
|
const aLow = a;
|
||||||
const aUp = Math.max(0, roof.pitchUpperDeg ?? roof.pitchDeg / 2) * DEG;
|
const aUp = Math.max(0, roof.pitchUpperDeg ?? roof.pitchDeg / 2) * DEG;
|
||||||
const d1 = halfD * 0.4; // Knick-Einzug von der Traufe (äussere 40% steil)
|
const ratio = Math.min(0.49, Math.max(0.05, roof.mansardKneeRatio ?? 0.4));
|
||||||
|
const mType = roof.mansardType ?? "giebel";
|
||||||
|
|
||||||
|
if (mType === "giebel") {
|
||||||
|
// Mansard-Satteldach: Knick nur an den beiden Traufseiten, Giebel an den
|
||||||
|
// Enden (bisheriges Verhalten, jetzt mit parametrierbarem Knick).
|
||||||
|
const d1 = halfD * ratio;
|
||||||
const z1 = e + d1 * Math.tan(aLow);
|
const z1 = e + d1 * Math.tan(aLow);
|
||||||
const z2 = z1 + (halfD - d1) * Math.tan(aUp);
|
const z2 = z1 + (halfD - d1) * Math.tan(aUp);
|
||||||
const yf = y0 + d1; // vordere Knicklinie
|
const yf = y0 + d1;
|
||||||
const yb = y1 - d1; // hintere Knicklinie
|
const yb = y1 - d1;
|
||||||
return {
|
return {
|
||||||
eaves,
|
eaves,
|
||||||
ridges: [[P(x0, yc), P(x1, yc)]],
|
ridges: [[P(x0, yc), P(x1, yc)]],
|
||||||
@@ -192,10 +199,10 @@ function computeCanonical(
|
|||||||
[P(x0, yb), P(x1, yb)],
|
[P(x0, yb), P(x1, yb)],
|
||||||
],
|
],
|
||||||
planes: [
|
planes: [
|
||||||
{ pts: [[x0, y0, e], [x1, y0, e], [x1, yf, z1], [x0, yf, z1]] }, // vorn unten
|
{ pts: [[x0, y0, e], [x1, y0, e], [x1, yf, z1], [x0, yf, z1]] },
|
||||||
{ pts: [[x0, yf, z1], [x1, yf, z1], [x1, yc, z2], [x0, yc, z2]] }, // vorn oben
|
{ pts: [[x0, yf, z1], [x1, yf, z1], [x1, yc, z2], [x0, yc, z2]] },
|
||||||
{ pts: [[x0, y1, e], [x1, y1, e], [x1, yb, z1], [x0, yb, z1]] }, // hinten unten
|
{ pts: [[x0, y1, e], [x1, y1, e], [x1, yb, z1], [x0, yb, z1]] },
|
||||||
{ pts: [[x0, yb, z1], [x1, yb, z1], [x1, yc, z2], [x0, yc, z2]] }, // hinten oben
|
{ pts: [[x0, yb, z1], [x1, yb, z1], [x1, yc, z2], [x0, yc, z2]] },
|
||||||
],
|
],
|
||||||
gables: [
|
gables: [
|
||||||
[[x0, y0, e], [x0, yf, z1], [x0, yc, z2], [x0, yb, z1], [x0, y1, e]],
|
[[x0, y0, e], [x0, yf, z1], [x0, yc, z2], [x0, yb, z1], [x0, y1, e]],
|
||||||
@@ -205,6 +212,91 @@ function computeCanonical(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allseitige Mansarde (Walm/Zelt): steiler Sockel ringsum bis zur
|
||||||
|
// Knicklinie (inneres Rechteck), darüber flacher Walm bzw. flache Spitze.
|
||||||
|
const dLow = Math.min(halfW, halfD) * ratio;
|
||||||
|
const z1 = e + dLow * Math.tan(aLow);
|
||||||
|
const ix0 = x0 + dLow;
|
||||||
|
const iy0 = y0 + dLow;
|
||||||
|
const ix1 = x1 - dLow;
|
||||||
|
const iy1 = y1 - dLow;
|
||||||
|
const ihalfD = (iy1 - iy0) / 2;
|
||||||
|
const ihalfW = (ix1 - ix0) / 2;
|
||||||
|
// Sockel-Trapeze (4 Seiten, steil) + Sockel-Grate (Ecken aussen→innen) +
|
||||||
|
// Knicklinie (inneres Rechteck) sind beiden allseitigen Formen gemein.
|
||||||
|
const socketPlanes = [
|
||||||
|
{ pts: [[x0, y0, e], [x1, y0, e], [ix1, iy0, z1], [ix0, iy0, z1]] as Vec3[] },
|
||||||
|
{ pts: [[x1, y1, e], [x0, y1, e], [ix0, iy1, z1], [ix1, iy1, z1]] as Vec3[] },
|
||||||
|
{ pts: [[x0, y1, e], [x0, y0, e], [ix0, iy0, z1], [ix0, iy1, z1]] as Vec3[] },
|
||||||
|
{ pts: [[x1, y0, e], [x1, y1, e], [ix1, iy1, z1], [ix1, iy0, z1]] as Vec3[] },
|
||||||
|
];
|
||||||
|
const socketHips: [Vec2, Vec2][] = [
|
||||||
|
[P(x0, y0), P(ix0, iy0)],
|
||||||
|
[P(x1, y0), P(ix1, iy0)],
|
||||||
|
[P(x1, y1), P(ix1, iy1)],
|
||||||
|
[P(x0, y1), P(ix0, iy1)],
|
||||||
|
];
|
||||||
|
const kneeBreaks: [Vec2, Vec2][] = [
|
||||||
|
[P(ix0, iy0), P(ix1, iy0)],
|
||||||
|
[P(ix1, iy0), P(ix1, iy1)],
|
||||||
|
[P(ix1, iy1), P(ix0, iy1)],
|
||||||
|
[P(ix0, iy1), P(ix0, iy0)],
|
||||||
|
];
|
||||||
|
|
||||||
|
if (mType === "walm") {
|
||||||
|
// Oberer Walm auf dem inneren Rechteck (First entlang X).
|
||||||
|
const z2 = z1 + ihalfD * Math.tan(aUp);
|
||||||
|
let ra = ix0 + ihalfD;
|
||||||
|
let rb = ix1 - ihalfD;
|
||||||
|
if (ra > rb) ra = rb = xc;
|
||||||
|
return {
|
||||||
|
eaves,
|
||||||
|
ridges: [[P(ra, yc), P(rb, yc)]],
|
||||||
|
hips: [
|
||||||
|
...socketHips,
|
||||||
|
[P(ix0, iy0), P(ra, yc)],
|
||||||
|
[P(ix1, iy0), P(rb, yc)],
|
||||||
|
[P(ix1, iy1), P(rb, yc)],
|
||||||
|
[P(ix0, iy1), P(ra, yc)],
|
||||||
|
],
|
||||||
|
breaks: kneeBreaks,
|
||||||
|
planes: [
|
||||||
|
...socketPlanes,
|
||||||
|
{ pts: [[ix0, iy0, z1], [ix1, iy0, z1], [rb, yc, z2], [ra, yc, z2]] },
|
||||||
|
{ pts: [[ix1, iy1, z1], [ix0, iy1, z1], [ra, yc, z2], [rb, yc, z2]] },
|
||||||
|
{ pts: [[ix0, iy1, z1], [ix0, iy0, z1], [ra, yc, z2]] },
|
||||||
|
{ pts: [[ix1, iy0, z1], [ix1, iy1, z1], [rb, yc, z2]] },
|
||||||
|
],
|
||||||
|
gables: [],
|
||||||
|
ridgeHeight: z2 - e,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// "zelt": flache Spitze über der Mitte des inneren Rechtecks.
|
||||||
|
const z2 = z1 + Math.min(ihalfW, ihalfD) * Math.tan(aUp);
|
||||||
|
return {
|
||||||
|
eaves,
|
||||||
|
ridges: [],
|
||||||
|
hips: [
|
||||||
|
...socketHips,
|
||||||
|
[P(ix0, iy0), P(xc, yc)],
|
||||||
|
[P(ix1, iy0), P(xc, yc)],
|
||||||
|
[P(ix1, iy1), P(xc, yc)],
|
||||||
|
[P(ix0, iy1), P(xc, yc)],
|
||||||
|
],
|
||||||
|
breaks: kneeBreaks,
|
||||||
|
planes: [
|
||||||
|
...socketPlanes,
|
||||||
|
{ pts: [[ix0, iy0, z1], [ix1, iy0, z1], [xc, yc, z2]] },
|
||||||
|
{ pts: [[ix1, iy0, z1], [ix1, iy1, z1], [xc, yc, z2]] },
|
||||||
|
{ pts: [[ix1, iy1, z1], [ix0, iy1, z1], [xc, yc, z2]] },
|
||||||
|
{ pts: [[ix0, iy1, z1], [ix0, iy0, z1], [xc, yc, z2]] },
|
||||||
|
],
|
||||||
|
gables: [],
|
||||||
|
ridgeHeight: z2 - e,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
case "zelt": {
|
case "zelt": {
|
||||||
// Allseitig zur Spitze über der Mitte.
|
// Allseitig zur Spitze über der Mitte.
|
||||||
const hz = Math.min(halfW, halfD) * tan;
|
const hz = Math.min(halfW, halfD) * tan;
|
||||||
|
|||||||
+7
-2
@@ -300,6 +300,11 @@ export const de = {
|
|||||||
"objinfo.roof.ridgeAxis.y": "entlang Y",
|
"objinfo.roof.ridgeAxis.y": "entlang Y",
|
||||||
"objinfo.roof.pitch": "Neigung (°)",
|
"objinfo.roof.pitch": "Neigung (°)",
|
||||||
"objinfo.roof.pitchUpper": "Obere Neigung (°)",
|
"objinfo.roof.pitchUpper": "Obere Neigung (°)",
|
||||||
|
"objinfo.roof.mansardType": "Mansard-Art",
|
||||||
|
"objinfo.roof.mansard.giebel": "Giebel-Mansarde",
|
||||||
|
"objinfo.roof.mansard.walm": "Walm-Mansarde",
|
||||||
|
"objinfo.roof.mansard.zelt": "Zelt-Mansarde",
|
||||||
|
"objinfo.roof.mansardKnee": "Knicklage (% Spannweite)",
|
||||||
"objinfo.roof.width": "Breite (m)",
|
"objinfo.roof.width": "Breite (m)",
|
||||||
"objinfo.roof.depth": "Tiefe (m)",
|
"objinfo.roof.depth": "Tiefe (m)",
|
||||||
"objinfo.roof.overhang": "Überstand (m)",
|
"objinfo.roof.overhang": "Überstand (m)",
|
||||||
@@ -382,8 +387,8 @@ export const de = {
|
|||||||
"oed.cat.tuerblatt": "Türblatt",
|
"oed.cat.tuerblatt": "Türblatt",
|
||||||
"oed.f.kind": "Öffnungsart",
|
"oed.f.kind": "Öffnungsart",
|
||||||
"oed.f.glazing": "Verglasung",
|
"oed.f.glazing": "Verglasung",
|
||||||
"oed.f.insetFace": "Schichteinzug ab",
|
"oed.f.insetFace": "Einbaulage ab",
|
||||||
"oed.f.insetFromFace": "Schichteinzug (m)",
|
"oed.f.insetFromFace": "Abstand von Kante (m)",
|
||||||
"oed.f.width": "Breite (m)",
|
"oed.f.width": "Breite (m)",
|
||||||
"oed.f.height": "Höhe (m)",
|
"oed.f.height": "Höhe (m)",
|
||||||
"oed.f.sillHeight": "Brüstungshöhe (m)",
|
"oed.f.sillHeight": "Brüstungshöhe (m)",
|
||||||
|
|||||||
+7
-2
@@ -299,6 +299,11 @@ export const en: Record<TranslationKey, string> = {
|
|||||||
"objinfo.roof.ridgeAxis.y": "along Y",
|
"objinfo.roof.ridgeAxis.y": "along Y",
|
||||||
"objinfo.roof.pitch": "Pitch (°)",
|
"objinfo.roof.pitch": "Pitch (°)",
|
||||||
"objinfo.roof.pitchUpper": "Upper pitch (°)",
|
"objinfo.roof.pitchUpper": "Upper pitch (°)",
|
||||||
|
"objinfo.roof.mansardType": "Mansard type",
|
||||||
|
"objinfo.roof.mansard.giebel": "Gable mansard",
|
||||||
|
"objinfo.roof.mansard.walm": "Hip mansard",
|
||||||
|
"objinfo.roof.mansard.zelt": "Pavilion mansard",
|
||||||
|
"objinfo.roof.mansardKnee": "Knee position (% span)",
|
||||||
"objinfo.roof.width": "Width (m)",
|
"objinfo.roof.width": "Width (m)",
|
||||||
"objinfo.roof.depth": "Depth (m)",
|
"objinfo.roof.depth": "Depth (m)",
|
||||||
"objinfo.roof.overhang": "Overhang (m)",
|
"objinfo.roof.overhang": "Overhang (m)",
|
||||||
@@ -382,8 +387,8 @@ export const en: Record<TranslationKey, string> = {
|
|||||||
"oed.cat.tuerblatt": "Leaf",
|
"oed.cat.tuerblatt": "Leaf",
|
||||||
"oed.f.kind": "Opening type",
|
"oed.f.kind": "Opening type",
|
||||||
"oed.f.glazing": "Glazing",
|
"oed.f.glazing": "Glazing",
|
||||||
"oed.f.insetFace": "Inset from",
|
"oed.f.insetFace": "Position from",
|
||||||
"oed.f.insetFromFace": "Layer inset (m)",
|
"oed.f.insetFromFace": "Distance from edge (m)",
|
||||||
"oed.f.width": "Width (m)",
|
"oed.f.width": "Width (m)",
|
||||||
"oed.f.height": "Height (m)",
|
"oed.f.height": "Height (m)",
|
||||||
"oed.f.sillHeight": "Sill height (m)",
|
"oed.f.sillHeight": "Sill height (m)",
|
||||||
|
|||||||
@@ -1034,6 +1034,19 @@ export interface Roof {
|
|||||||
pitchDeg: number;
|
pitchDeg: number;
|
||||||
/** Nur Mansarde: obere (flachere) Neigung in Grad; fehlt ⇒ halbe Hauptneigung. */
|
/** Nur Mansarde: obere (flachere) Neigung in Grad; fehlt ⇒ halbe Hauptneigung. */
|
||||||
pitchUpperDeg?: number;
|
pitchUpperDeg?: number;
|
||||||
|
/**
|
||||||
|
* Nur Mansarde: Untertyp der Mansardform. "giebel" = Mansard-Satteldach
|
||||||
|
* (steile untere + flache obere Neigung nur an zwei Seiten, Giebel an den
|
||||||
|
* Enden — Default), "walm" = Mansard-Walmdach (allseitige Mansarde, auch die
|
||||||
|
* Stirnseiten geknickt, kein Giebel), "zelt" = Mansard-Zeltdach (allseitig
|
||||||
|
* zur Spitze, geknickt). Fehlt ⇒ "giebel".
|
||||||
|
*/
|
||||||
|
mansardType?: "giebel" | "walm" | "zelt";
|
||||||
|
/**
|
||||||
|
* Nur Mansarde: Lage der Knicklinie als Anteil der halben Spannweite (0..0.5),
|
||||||
|
* gemessen von der Traufe. Kleiner ⇒ steiler Sockel kürzer; fehlt ⇒ 0.4.
|
||||||
|
*/
|
||||||
|
mansardKneeRatio?: number;
|
||||||
/** Dachüberstand an der Traufe (Meter, ringsum); 0 = bündig mit dem Umriss. */
|
/** Dachüberstand an der Traufe (Meter, ringsum); 0 = bündig mit dem Umriss. */
|
||||||
overhang: number;
|
overhang: number;
|
||||||
/** Firstrichtung (Sattel/Walm/Mansarde/Pult): entlang der X- oder Y-Achse. */
|
/** Firstrichtung (Sattel/Walm/Mansarde/Pult): entlang der X- oder Y-Achse. */
|
||||||
|
|||||||
@@ -523,6 +523,29 @@ export function RoofSection({
|
|||||||
numField("objinfo.roof.pitchUpper", roof.pitchUpperDeg ?? roof.pitchDeg / 2, 1, (v) =>
|
numField("objinfo.roof.pitchUpper", roof.pitchUpperDeg ?? roof.pitchDeg / 2, 1, (v) =>
|
||||||
host.onSetRoofPatch({ pitchUpperDeg: Math.max(0, Math.min(85, v)) }),
|
host.onSetRoofPatch({ pitchUpperDeg: Math.max(0, Math.min(85, v)) }),
|
||||||
)}
|
)}
|
||||||
|
{/* Mansarde-Untertyp (Giebel/Walm/Zelt) + Knicklage. */}
|
||||||
|
{roof.shape === "mansarde" && (
|
||||||
|
<div className="objinfo-field">
|
||||||
|
<span className="objinfo-flabel">{t("objinfo.roof.mansardType")}</span>
|
||||||
|
<Dropdown
|
||||||
|
value={roof.mansardType ?? "giebel"}
|
||||||
|
onChange={(v) =>
|
||||||
|
host.onSetRoofPatch({ mansardType: v as "giebel" | "walm" | "zelt" })
|
||||||
|
}
|
||||||
|
options={[
|
||||||
|
{ value: "giebel", label: t("objinfo.roof.mansard.giebel") },
|
||||||
|
{ value: "walm", label: t("objinfo.roof.mansard.walm") },
|
||||||
|
{ value: "zelt", label: t("objinfo.roof.mansard.zelt") },
|
||||||
|
]}
|
||||||
|
title={t("objinfo.roof.mansardType")}
|
||||||
|
width={130}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{roof.shape === "mansarde" &&
|
||||||
|
numField("objinfo.roof.mansardKnee", (roof.mansardKneeRatio ?? 0.4) * 100, 1, (v) =>
|
||||||
|
host.onSetRoofPatch({ mansardKneeRatio: Math.max(5, Math.min(49, v)) / 100 }),
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Grundriss-Masse (Breite/Tiefe): das Umriss-Rechteck neu bilden, die
|
{/* Grundriss-Masse (Breite/Tiefe): das Umriss-Rechteck neu bilden, die
|
||||||
untere/linke Ecke (minX/minY) bleibt fix. */}
|
untere/linke Ecke (minX/minY) bleibt fix. */}
|
||||||
|
|||||||
@@ -80,6 +80,10 @@ export interface RoofInfo {
|
|||||||
pitchDeg: number;
|
pitchDeg: number;
|
||||||
/** Obere Neigung (Grad) — nur Mansarde relevant. */
|
/** Obere Neigung (Grad) — nur Mansarde relevant. */
|
||||||
pitchUpperDeg?: number;
|
pitchUpperDeg?: number;
|
||||||
|
/** Mansarde-Untertyp (Giebel/Walm/Zelt) — nur Mansarde relevant. */
|
||||||
|
mansardType?: "giebel" | "walm" | "zelt";
|
||||||
|
/** Mansarde-Knicklage (0..0.5 der halben Spannweite) — nur Mansarde relevant. */
|
||||||
|
mansardKneeRatio?: number;
|
||||||
/** Dachüberstand an der Traufe (Meter). */
|
/** Dachüberstand an der Traufe (Meter). */
|
||||||
overhang: number;
|
overhang: number;
|
||||||
/** Firstrichtung entlang X oder Y. */
|
/** Firstrichtung entlang X oder Y. */
|
||||||
@@ -626,6 +630,8 @@ function roofSelection(project: Project, roof: Roof): Selection {
|
|||||||
shape: roof.shape,
|
shape: roof.shape,
|
||||||
pitchDeg: roof.pitchDeg,
|
pitchDeg: roof.pitchDeg,
|
||||||
pitchUpperDeg: roof.pitchUpperDeg,
|
pitchUpperDeg: roof.pitchUpperDeg,
|
||||||
|
mansardType: roof.mansardType,
|
||||||
|
mansardKneeRatio: roof.mansardKneeRatio,
|
||||||
overhang: roof.overhang,
|
overhang: roof.overhang,
|
||||||
ridgeAxis: roof.ridgeAxis,
|
ridgeAxis: roof.ridgeAxis,
|
||||||
thickness: roof.thickness,
|
thickness: roof.thickness,
|
||||||
|
|||||||
Reference in New Issue
Block a user