diff --git a/rhino/elemente_uebersicht.py b/rhino/elemente_uebersicht.py index 82636f6..0df407c 100644 --- a/rhino/elemente_uebersicht.py +++ b/rhino/elemente_uebersicht.py @@ -208,6 +208,88 @@ class ElementeUebersichtBridge(panel_base.BaseBridge): print("[UEBERSICHT] zoom:", ex) except Exception as ex: print("[UEBERSICHT] zoom find:", ex) + elif t == "EXPORT_BILANZ": + self._export_bilanz() + + def _export_bilanz(self): + """Exportiert SIA-416 Bilanz als CSV (Excel-kompatibel: Semikolon- + Separator + UTF-8 BOM + Komma als Dezimaltrenner). Wide-Format: + eine Spalte pro Geschoss + Total-Spalte, Zeilen pro Kategorie. + """ + doc = Rhino.RhinoDoc.ActiveDoc + if doc is None: return + # Geschoss-Liste (geordnet) + Total am Ende + geschosse = _elm._load_geschosse(doc) or [] + gs_list = [g for g in geschosse + if isinstance(g, dict) and g.get("isGeschoss")] + # Bilanz pro Geschoss + Total via compute_sia_bilanz + per_gid = {} # gid → bilanz dict + for g in gs_list: + per_gid[g["id"]] = _elm.compute_sia_bilanz( + doc, "geschoss:" + g["id"]) + total = _elm.compute_sia_bilanz(doc, "total") + # SaveFileDialog + try: + from Rhino.UI import SaveFileDialog + sfd = SaveFileDialog() + sfd.DefaultExt = "csv" + sfd.Filter = "CSV (*.csv)|*.csv" + sfd.FileName = "sia_bilanz.csv" + ok = False + try: ok = sfd.ShowSaveDialog() + except Exception: + try: ok = sfd.ShowDialog() + except Exception: ok = False + if not ok: + print("[UEBERSICHT] Bilanz-Export abgebrochen"); return + path = sfd.FileName + except Exception as ex: + print("[UEBERSICHT] SaveFileDialog:", ex); return + + # Zeilen-Definition: (Label, Bilanz-Key, ist_personen?) + rows = [ + ("HNF (m²)", "hnf", False), + ("NNF (m²)", "nnf", False), + ("NF (m²)", "nf", False), + ("VF (m²)", "vf", False), + ("FF (m²)", "ff", False), + ("NGF (m²)", "ngf", False), + ("GF (m²)", "gf", False), + ("AGF (m²)", "agf", False), + ("Räume", "count", True), + ("Personen", "personen", True), + ] + + def _fmt(val, is_count): + if val is None: return "" + if is_count: return str(int(val)) + return "{:.2f}".format(float(val)).replace(".", ",") + + def _esc(s): + s = str(s) + if ";" in s or '"' in s or "\n" in s: + return '"' + s.replace('"', '""') + '"' + return s + + try: + import io + with io.open(path, "w", encoding="utf-8-sig", newline="") as f: + # Header — Kategorie + Geschoss-Namen + Total + header = ["Kategorie"] + for g in gs_list: header.append(_esc(g.get("name") or "?")) + header.append("Total") + f.write(";".join(header) + "\n") + for label, key, is_count in rows: + line = [_esc(label)] + for g in gs_list: + b = per_gid.get(g["id"], {}) + line.append(_fmt(b.get(key, 0), is_count)) + line.append(_fmt(total.get(key, 0), is_count)) + f.write(";".join(line) + "\n") + print("[UEBERSICHT] SIA-Bilanz exportiert: {} ({} Geschosse + Total)".format( + path, len(gs_list))) + except Exception as ex: + print("[UEBERSICHT] CSV schreiben:", ex) def open_as_window(): diff --git a/src/ElementeUebersichtApp.jsx b/src/ElementeUebersichtApp.jsx index 11e74bc..bd0a9ab 100644 --- a/src/ElementeUebersichtApp.jsx +++ b/src/ElementeUebersichtApp.jsx @@ -128,6 +128,9 @@ export default function ElementeUebersichtApp() { }} /> + send('EXPORT_BILANZ', {})} + title="SIA-416 Bilanz als CSV exportieren (eine Spalte pro Geschoss + Total)" /> {/* Kind-Filter Chips */}