From 3c28d2e29c85652d2770f777acf0e35e886aed13 Mon Sep 17 00:00:00 2001 From: karim Date: Tue, 26 May 2026 23:20:00 +0200 Subject: [PATCH] Elemente-Uebersicht: SIA-416 Bilanz pro Geschoss Aggregiert alle raum_outline-Flaechen nach raum_sia-Klassifikation (hnf/nnf/vf/ff) und zeigt sie als kompakte Mini-Tabelle direkt unter dem Geschoss-Header in der Project-Browser-Uebersicht. Backend (_build_overview): - Neuer Returnschluessel siaBilanz: {geschossId: {hnf, nnf, vf, ff, ohne, nf, total, count}} in m^2 - NF = HNF + NNF (Nutzflaeche nach SIA 416) - Raeume ohne SIA-Tag landen in "ohne" Frontend (ElementeUebersichtApp): - Direkt unter dem Geschoss-Header eine Inline-Tabelle mit nur den Klassen die > 0 sind (kein Spam wenn nichts klassifiziert ist) - NF separat hervorgehoben (Accent-Farbe) als wichtigste Kennzahl - Read-only, aktualisiert sich mit jedem state-emit (Raum-Aenderung, SIA-Tag setzen, neue Raeume) automatisch --- rhino/elemente_uebersicht.py | 31 ++++++++++++++++++++++- src/ElementeUebersichtApp.jsx | 47 +++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/rhino/elemente_uebersicht.py b/rhino/elemente_uebersicht.py index 06280dc..b108681 100644 --- a/rhino/elemente_uebersicht.py +++ b/rhino/elemente_uebersicht.py @@ -116,7 +116,36 @@ def _build_overview(doc): out_geschosse.append({ "id": "__keingeschoss__", "name": "(kein Geschoss)", "okff": None, }) - return {"geschosse": out_geschosse, "items": items} + + # SIA-416 Bilanz pro Geschoss: aggregiert alle raum_outline-Flaechen + # nach raum_sia-Klassifikation. Räume ohne SIA-Tag landen in "ohne". + # NF = HNF + NNF (Nutzflaeche). Wird im Frontend als Tabelle gerendert. + sia_bilanz = {} # {geschossId: {hnf, nnf, vf, ff, ohne, nf, total, count}} + for obj in doc.Objects: + meta = _elm._read_meta(obj) + if meta is None: continue + if meta.get("type") != "raum_outline": continue + try: + area, _, _ = _elm._raum_amp(obj.Geometry) + except Exception: continue + if not area or area <= 0: continue + g_id = meta.get("geschoss") or "__keingeschoss__" + sia = (meta.get("raum_sia") or "").lower() + if sia not in ("hnf", "nnf", "vf", "ff"): + sia = "ohne" + b = sia_bilanz.setdefault(g_id, { + "hnf": 0.0, "nnf": 0.0, "vf": 0.0, "ff": 0.0, + "ohne": 0.0, "count": 0, + }) + b[sia] += float(area) + b["count"] += 1 + # NF + Total ableiten + for b in sia_bilanz.values(): + b["nf"] = b["hnf"] + b["nnf"] + b["total"] = b["hnf"] + b["nnf"] + b["vf"] + b["ff"] + b["ohne"] + + return {"geschosse": out_geschosse, "items": items, + "siaBilanz": sia_bilanz} class ElementeUebersichtBridge(panel_base.BaseBridge): diff --git a/src/ElementeUebersichtApp.jsx b/src/ElementeUebersichtApp.jsx index 14f3f55..846548a 100644 --- a/src/ElementeUebersichtApp.jsx +++ b/src/ElementeUebersichtApp.jsx @@ -40,6 +40,7 @@ export default function ElementeUebersichtApp() { const items = state.items || [] const geschosse = state.geschosse || [] + const siaBilanz = state.siaBilanz || {} const filtered = useMemo(() => { let r = items @@ -163,6 +164,7 @@ export default function ElementeUebersichtApp() { const total = Object.values(groupForG).reduce((s, arr) => s + arr.length, 0) if (total === 0) return null const gOpen = expanded[g.id] !== false // default: open + const bilanz = siaBilanz[g.id] return (
toggle(g.id)} @@ -192,6 +194,51 @@ export default function ElementeUebersichtApp() { fontFamily: 'DM Mono, monospace', }}>{total}
+ {/* SIA-416 Bilanz pro Geschoss — read-only Mini-Tabelle, + nur angezeigt wenn mindestens ein klassifizierter Raum */} + {gOpen && bilanz && (bilanz.hnf + bilanz.nnf + bilanz.vf + bilanz.ff) > 0 && ( +
+ {bilanz.hnf > 0 && ( + + HNF {bilanz.hnf.toFixed(1)} m² + + )} + {bilanz.nnf > 0 && ( + + NNF {bilanz.nnf.toFixed(1)} m² + + )} + {bilanz.vf > 0 && ( + + VF {bilanz.vf.toFixed(1)} m² + + )} + {bilanz.ff > 0 && ( + + FF {bilanz.ff.toFixed(1)} m² + + )} + {bilanz.nf > 0 && ( + + NF {bilanz.nf.toFixed(1)} m² + + )} + {bilanz.ohne > 0 && ( + + — {bilanz.ohne.toFixed(1)} m² + + )} +
+ )} {gOpen && KIND_ORDER.map(k => { const arr = groupForG[k] if (!arr || arr.length === 0) return null