From 7cfdf59c29ed72ffe4f9b4b8a7380d58dc24d604 Mon Sep 17 00:00:00 2001 From: Karim Date: Fri, 10 Jul 2026 00:30:21 +0200 Subject: [PATCH] =?UTF-8?q?Dach:=20Traufh=C3=B6he=20editierbar=20+=20Abw?= =?UTF-8?q?=C3=A4hlen=20an=20allen=20Reset-Stellen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - RoofSection bekommt ein Traufhöhe-Feld (Roof.baseElevation, absolutes Z) — z. B. um das Dach für einen Kniestock über die Geschoss-Oberkante zu heben. RoofInfo.baseElevation trägt den aufgelösten Wert (Override oder Default). - Dach-Auswahl wird jetzt an ALLEN Selektions-Reset-Stellen mitgeleert (Kontextmenü-/Ebenen-Operationen), nicht nur bei Klick/Geschosswechsel/ Marquee/Delete — kein Geister-Dach mehr in der Auswahl. tsc + vitest grün. --- src/App.tsx | 11 +++++++++++ src/i18n/de.ts | 1 + src/i18n/en.ts | 1 + src/panels/ObjectInfoPanel.tsx | 4 ++++ src/state/selectionInfo.ts | 3 +++ 5 files changed, 20 insertions(+) diff --git a/src/App.tsx b/src/App.tsx index f4615c2..40aaf2b 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -3289,6 +3289,7 @@ export default function App() { setSelectedRoomIds([]); setSelectedExtrudedSolidIds([]); setSelectedColumnIds([]); + setSelectedRoofIds([]); switch (kind) { case "Wand": setSelectedWallIds([id]); @@ -4144,6 +4145,7 @@ export default function App() { setSelectedStairIds([]); setSelectedExtrudedSolidIds([]); setSelectedColumnIds([]); + setSelectedRoofIds([]); setStampEditorRoomId(roomId); }; // Doppelklick auf ein Text-2D-Element: selektieren + Inhalts-Editor öffnen. @@ -4158,6 +4160,7 @@ export default function App() { setSelectedRoomIds([]); setSelectedExtrudedSolidIds([]); setSelectedColumnIds([]); + setSelectedRoofIds([]); setEditTextId(drawingId); }; // Bearbeiteten Text-Inhalt übernehmen (immutabel; nur bei Text-Geometrie). @@ -4334,6 +4337,7 @@ export default function App() { setSelectedRoomIds([]); setSelectedExtrudedSolidIds([]); setSelectedColumnIds([]); + setSelectedRoofIds([]); } }; // Links-Klick im 3D: per Raycast getroffene Treppe wählen (Einzelauswahl). @@ -4347,6 +4351,7 @@ export default function App() { setSelectedRoomIds([]); setSelectedExtrudedSolidIds([]); setSelectedColumnIds([]); + setSelectedRoofIds([]); } }; // Links-Klick im 3D: per Raycast getroffene Decke wählen (Einzelauswahl). @@ -4360,6 +4365,7 @@ export default function App() { setSelectedRoomIds([]); setSelectedExtrudedSolidIds([]); setSelectedColumnIds([]); + setSelectedRoofIds([]); } }; // Links-Klick im 3D: per Raycast getroffene Öffnung wählen (Einzelauswahl). @@ -4373,6 +4379,7 @@ export default function App() { setSelectedRoomIds([]); setSelectedExtrudedSolidIds([]); setSelectedColumnIds([]); + setSelectedRoofIds([]); } }; // Links-KLICK im Nordstern-3D-Viewport (WASM, TS-Raycast): getroffenes Bauteil @@ -4391,6 +4398,7 @@ export default function App() { setSelectedRoomIds([]); setSelectedExtrudedSolidIds([]); setSelectedColumnIds([]); + setSelectedRoofIds([]); return; } // Öffnung (Fenster/Tür) und Treppe sind jetzt auch im WASM-Viewport pickbar @@ -4405,6 +4413,7 @@ export default function App() { setSelectedRoomIds([]); setSelectedExtrudedSolidIds([]); setSelectedColumnIds([]); + setSelectedRoofIds([]); return; } if (hit.kind === "stair") { @@ -4416,6 +4425,7 @@ export default function App() { setSelectedRoomIds([]); setSelectedExtrudedSolidIds([]); setSelectedColumnIds([]); + setSelectedRoofIds([]); return; } if (hit.kind === "wall") { @@ -4435,6 +4445,7 @@ export default function App() { setSelectedRoomIds([]); setSelectedExtrudedSolidIds([]); setSelectedColumnIds([]); + setSelectedRoofIds([]); }; // Rechts-Klick im 3D: Wand-Kontextmenü an der Cursorposition. const onViewportContextMenu = (info: ViewportContextInfo) => { diff --git a/src/i18n/de.ts b/src/i18n/de.ts index 4ff6864..87721bf 100644 --- a/src/i18n/de.ts +++ b/src/i18n/de.ts @@ -302,6 +302,7 @@ export const de = { "objinfo.roof.pitchUpper": "Obere Neigung (°)", "objinfo.roof.overhang": "Überstand (m)", "objinfo.roof.thickness": "Dachdicke (m)", + "objinfo.roof.baseElevation": "Traufhöhe (m)", "objinfo.roof.ridgeHeight": "Firsthöhe", "objinfo.roof.area": "Grundfläche", // ── Stützen-Attribute (Object-Info-Panel) ─────────────────────────────── diff --git a/src/i18n/en.ts b/src/i18n/en.ts index 8f5005e..cf4764f 100644 --- a/src/i18n/en.ts +++ b/src/i18n/en.ts @@ -301,6 +301,7 @@ export const en: Record = { "objinfo.roof.pitchUpper": "Upper pitch (°)", "objinfo.roof.overhang": "Overhang (m)", "objinfo.roof.thickness": "Roof thickness (m)", + "objinfo.roof.baseElevation": "Eaves height (m)", "objinfo.roof.ridgeHeight": "Ridge height", "objinfo.roof.area": "Footprint area", // ── Column attributes (object info panel) ──────────────────────────────── diff --git a/src/panels/ObjectInfoPanel.tsx b/src/panels/ObjectInfoPanel.tsx index 86c1672..65fb2c6 100644 --- a/src/panels/ObjectInfoPanel.tsx +++ b/src/panels/ObjectInfoPanel.tsx @@ -521,6 +521,10 @@ export function RoofSection({ {numField("objinfo.roof.thickness", roof.thickness, 0.02, (v) => host.onSetRoofPatch({ thickness: Math.max(0.01, v) }), )} + {/* Traufhöhe (absolutes Z) — z. B. für einen Kniestock übers Geschoss anheben. */} + {numField("objinfo.roof.baseElevation", roof.baseElevation, 0.1, (v) => + host.onSetRoofPatch({ baseElevation: v }), + )} {/* Abgeleitete Werte (read-only). */}
diff --git a/src/state/selectionInfo.ts b/src/state/selectionInfo.ts index a90731b..d6fe9fc 100644 --- a/src/state/selectionInfo.ts +++ b/src/state/selectionInfo.ts @@ -86,6 +86,8 @@ export interface RoofInfo { ridgeAxis: "x" | "y"; /** Dachdicke (Meter). */ thickness: number; + /** Traufhöhe (absolutes Z, Meter) — aufgelöst (Override ODER Geschoss-Oberkante). */ + baseElevation: number; /** Firsthöhe über der Traufe (Meter, abgeleitet). */ ridgeHeight: number; /** Grundfläche des Umriss-Rechtecks (m², ohne Überstand). */ @@ -618,6 +620,7 @@ function roofSelection(project: Project, roof: Roof): Selection { overhang: roof.overhang, ridgeAxis: roof.ridgeAxis, thickness: roof.thickness, + baseElevation: eavesZ, ridgeHeight: g.ridgeHeight, footprintArea, };