SIA-Bilanz CSV-Export aus Elemente-Uebersicht

Download-Button (file_download Icon) neben den Expand/Collapse-Buttons
in der Toolbar. Klick → SaveFileDialog (Default 'sia_bilanz.csv') →
schreibt Excel-kompatible CSV.

Backend (elemente_uebersicht._export_bilanz):
- Wide-Format: Spalten = Kategorie + ein Geschoss + Total
- Zeilen: HNF, NNF, NF, VF, FF, NGF, GF, AGF, Räume (count), Personen
- Werte via _elm.compute_sia_bilanz fuer jeden Scope (gleiche Logik
  wie Bilanz-Stempel + Uebersicht — single source of truth)
- Format: Semikolon-Separator + UTF-8 BOM + Komma als Dezimaltrenner
  (Excel CH/DE-kompatibel, oeffnet ohne Umweg)
- Flaechen mit 2 Nachkommastellen, Raume/Personen als int
This commit is contained in:
2026-05-27 01:13:08 +02:00
parent e2d66a5d64
commit 61923e1b2b
2 changed files with 85 additions and 0 deletions
+82
View File
@@ -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():