Decken-Panel: Aussparungen anzeigen + einzeln entfernen

Die Decken-Sektion listet die Aussparungen (BBox-Masse je Loch) mit
Entfernen-Knopf; Anlegen über den Befehl 'Deckenloch'. CeilingInfo.openings,
host.onRemoveCeilingOpening + App-Routing. 684/684 grün.
This commit is contained in:
2026-07-10 18:44:13 +02:00
parent aee884639e
commit 83dcdd0501
6 changed files with 48 additions and 0 deletions
+8
View File
@@ -3238,6 +3238,14 @@ export default function App() {
if (selection?.kind === "ceiling")
setCeilingThickness(selection.id, thickness);
},
onRemoveCeilingOpening: (index) => {
if (selection?.kind !== "ceiling") return;
const c = (project.ceilings ?? []).find((x) => x.id === selection.id);
if (!c?.openings || index < 0 || index >= c.openings.length) return;
updateCeiling(selection.id, {
openings: c.openings.filter((_, i) => i !== index),
});
},
onSetCeilingTop: (anchor) => {
if (selection?.kind === "ceiling")
updateCeiling(selection.id, { top: anchor ?? undefined });
+2
View File
@@ -366,6 +366,8 @@ export const de = {
"objinfo.ceiling.top": "Oberkante (OK)",
"objinfo.ceiling.bottom": "Unterkante (UK)",
"objinfo.ceiling.height": "Dicke (OKUK)",
"objinfo.ceiling.openings": "Aussparungen",
"objinfo.ceiling.removeOpening": "Aussparung entfernen",
"objinfo.ceiling.area": "Fläche",
"objinfo.ceiling.anchorFloor": "Gebunden",
"objinfo.ceiling.anchorCustom": "Eigene",
+2
View File
@@ -366,6 +366,8 @@ export const en: Record<TranslationKey, string> = {
"objinfo.ceiling.top": "Top (OK)",
"objinfo.ceiling.bottom": "Bottom (UK)",
"objinfo.ceiling.height": "Thickness (OKUK)",
"objinfo.ceiling.openings": "Openings",
"objinfo.ceiling.removeOpening": "Remove opening",
"objinfo.ceiling.area": "Area",
"objinfo.ceiling.anchorFloor": "Bound",
"objinfo.ceiling.anchorCustom": "Custom",
+27
View File
@@ -1050,6 +1050,33 @@ export function CeilingSection({
<span className="objinfo-fval">{ceiling.volume.toFixed(2)} m³</span>
</div>
{/* Aussparungen (Treppenauge/Schacht) — Liste mit Entfernen je Loch.
Anlegen über den Befehl „Deckenloch" (BIM-Ribbon). */}
{ceiling.openings.length > 0 && (
<>
<div className="objinfo-field">
<span className="objinfo-flabel">{t("objinfo.ceiling.openings")}</span>
<span className="objinfo-fval">{ceiling.openings.length}</span>
</div>
{ceiling.openings.map((o, i) => (
<div className="objinfo-field" key={i}>
<span className="objinfo-flabel objinfo-muted">
{`${i + 1}: ${o.width.toFixed(2)} × ${o.depth.toFixed(2)} m`}
</span>
<button
type="button"
className="objinfo-typebtn"
title={t("objinfo.ceiling.removeOpening")}
aria-label={t("objinfo.ceiling.removeOpening")}
onClick={() => host.onRemoveCeilingOpening(i)}
>
×
</button>
</div>
))}
</>
)}
<div className="objinfo-sep" />
{/* OK der Decke: an Geschoss gebunden ODER eigene Höhe. */}
+2
View File
@@ -275,6 +275,8 @@ export interface PanelHostValue {
onSetCeilingType: (ceilingTypeId: string) => void;
/** Setzt die Gesamtdicke der Decke (Meter, thickness-Übersteuerung). */
onSetCeilingThickness: (thickness: number) => void;
/** Entfernt die Aussparung mit Index `index` der selektierten Decke. */
onRemoveCeilingOpening: (index: number) => void;
/** Setzt/entfernt die OK-Bindung der Decke (`null` = Geschoss-Oberkante). */
onSetCeilingTop: (anchor: VerticalAnchor | null) => void;
/**
+7
View File
@@ -196,6 +196,8 @@ export interface CeilingInfo {
/** Aufgelöste absolute UK/OK (Meter). */
zBottom: number;
zTop: number;
/** Aussparungen (Treppenauge/Schacht) als BBox-Masse, Reihenfolge = Modell. */
openings: { width: number; depth: number }[];
}
/**
@@ -606,6 +608,11 @@ function ceilingSelection(project: Project, ceiling: Ceiling): Selection {
bottom: ceiling.bottom,
zBottom,
zTop,
// Aussparungen als anzeigefertige BBox-Masse (Breite × Tiefe je Loch).
openings: (ceiling.openings ?? []).map((hole) => {
const bb = outlineBBox(hole);
return { width: bb.maxX - bb.minX, depth: bb.maxY - bb.minY };
}),
};
return {
kind: "ceiling",