Stempel-Element: SIA-Bilanz als platzierbares Viewport-Objekt
Neuer Element-Type "stempel" — TextEntity die automatisch eine SIA-416
Bilanz aggregiert und im Plan platziert wird. Re-rendert sich live wenn
sich Raeume im Scope aendern.
Backend (elemente.py):
- Neue SIA-Tags: GF (Geschossflaeche), AGF (Aussengeschossflaeche)
mit eigenen Labels + Pastell-Farben in _SIA_COLORS_HEX
- "stempel" als SOURCE_TYPE; eigene UserStrings:
- stempel_scope: "total" | "geschoss:<gid>"
- stempel_txt_h, stempel_font, stempel_bold, stempel_italic
- compute_sia_bilanz(doc, scope): aggregiert nach SIA-Tags, liefert
HNF/NNF/VF/FF/GF/AGF + abgeleitet NF/NGF/count + Scope-Label
- _format_bilanz_lines: kompakte Stempel-Textzeilen ("HNF 120.5 m²"),
Trennlinien + nur Kategorien > 0
- _make_stempel_text: TextEntity-Builder mit Header "Nutzflächen · {Scope}"
- _regenerate_element_body "stempel"-Branch: in-place Replace mit
aktualisiertem Text (Position bleibt aus alter Geometrie)
- _regenerate_stempel_for_geschoss: regennt alle Stempel im selben
Geschoss + alle "total"-Stempel
- Auto-Cascade: raum_outline-Regen setzt sticky-marker; nach REGEN_BUSY-
Release wird _regenerate_stempel_for_geschoss aufgerufen
- _cmd_create_stempel: GetPoint im Viewport, layer = aktives Geschoss
Raum-Sublayer, default-Scope = aktives Geschoss
- _update_wall "stempel"-Branch: scope/txtH/font/bold/italic via patch
- elemente_uebersicht: SIA-Bilanz um gf/agf/ngf erweitert; "stempel"
als KIND-Eintrag
Frontend:
- createStempel-Bridge-Export
- "Stempel"-Pill-Button in der "Raeume"-PillGroup
- StempelProperties-Component: Scope-Dropdown (Total + alle Geschosse),
Bilanz-Vorschau mit Hervorhebung der NF (Accent-Farbe)
- KIND_META + RAUM_SIA_KINDS um GF/AGF erweitert
Workflow: Pill "Stempel" klicken → Punkt im Viewport → Stempel erscheint
mit Header "Nutzflächen · EG" + Bilanz. Properties: Scope auf Total
umstellen oder anderes Geschoss waehlen. Neue Raeume taggen mit SIA-
Tag → Stempel aktualisiert sich automatisch.
This commit is contained in:
+327
-4
@@ -408,18 +408,23 @@ def _resolve_raum_rundung(meta, doc=None):
|
||||
|
||||
|
||||
_RAUM_ALIGN = ("links", "mid", "rechts")
|
||||
_RAUM_SIA_KINDS = ("", "hnf", "nnf", "vf", "ff")
|
||||
_RAUM_SIA_KINDS = ("", "hnf", "nnf", "vf", "ff", "gf", "agf")
|
||||
_RAUM_FUNKTIONEN = (
|
||||
"wohnen", "schlafen", "bad", "kueche", "essen", "flur", "diele",
|
||||
"buero", "atelier", "lager", "technik", "balkon", "terrasse",
|
||||
"sonstiges",
|
||||
)
|
||||
# SIA-416 Farbpalette nach CH-Buero-Konvention (helle, kraeftige Pastelltoene).
|
||||
# GF/AGF: dezente Grau-Toene weil sie meist als Hintergrund-Outline um andere
|
||||
# klassifizierte Raeume gezeichnet werden (Doppelung wird vom Stempel
|
||||
# erkannt: GF/AGF separat aggregiert).
|
||||
_SIA_COLORS_HEX = {
|
||||
"hnf": "#e8a8a8", # Hauptnutzflaeche — Rot
|
||||
"nnf": "#e8c498", # Nebennutzflaeche — Orange
|
||||
"vf": "#e8d878", # Verkehrsflaeche — Gelb
|
||||
"ff": "#a8c8e0", # Funktionsflaeche — Hellblau
|
||||
"gf": "#d0d0d0", # Geschossflaeche (gross) — Grau
|
||||
"agf": "#c0d8c0", # Aussengeschossflaeche — Hellgruen
|
||||
}
|
||||
_SIA_LABELS = {
|
||||
"": "—",
|
||||
@@ -427,6 +432,8 @@ _SIA_LABELS = {
|
||||
"nnf": "NNF",
|
||||
"vf": "VF",
|
||||
"ff": "FF",
|
||||
"gf": "GF",
|
||||
"agf": "AGF",
|
||||
}
|
||||
|
||||
# Cross-Doc Preset-Name fuer Override-Engine. Steuert auch das siaFillMode-
|
||||
@@ -2676,6 +2683,8 @@ def _attach_meta(obj_attrs, wall_id, type_, geschoss, dicke, uk_over, ok_over,
|
||||
raum_show_sia=None,
|
||||
raum_stamp_dx=None, raum_stamp_dy=None,
|
||||
raum_layout=None, raum_txt_modus=None,
|
||||
stempel_scope=None, stempel_txt_h=None,
|
||||
stempel_font=None, stempel_bold=None, stempel_italic=None,
|
||||
wand_layered=None, wand_layers=None, wand_layer_idx=None,
|
||||
wand_chain_members=None,
|
||||
aussp_parent=None):
|
||||
@@ -2880,6 +2889,21 @@ def _attach_meta(obj_attrs, wall_id, type_, geschoss, dicke, uk_over, ok_over,
|
||||
print("[ELEMENTE] raum_layout set:", ex)
|
||||
if raum_txt_modus is not None and raum_txt_modus in ("fix", "masstab"):
|
||||
obj_attrs.SetUserString(_KEY_RAUM_TXT_MODUS, raum_txt_modus)
|
||||
# Stempel-Felder
|
||||
if stempel_scope is not None:
|
||||
obj_attrs.SetUserString(_KEY_STEMPEL_SCOPE, str(stempel_scope))
|
||||
if stempel_txt_h is not None:
|
||||
try: obj_attrs.SetUserString(_KEY_STEMPEL_TXT_H,
|
||||
"{:.4f}".format(float(stempel_txt_h)))
|
||||
except Exception: pass
|
||||
if stempel_font is not None:
|
||||
obj_attrs.SetUserString(_KEY_STEMPEL_FONT, str(stempel_font))
|
||||
if stempel_bold is not None:
|
||||
obj_attrs.SetUserString(_KEY_STEMPEL_BOLD,
|
||||
"1" if bool(stempel_bold) else "0")
|
||||
if stempel_italic is not None:
|
||||
obj_attrs.SetUserString(_KEY_STEMPEL_ITAL,
|
||||
"1" if bool(stempel_italic) else "0")
|
||||
# Wand-Schichten
|
||||
if wand_layered is not None:
|
||||
obj_attrs.SetUserString(_KEY_WAND_LAYERED,
|
||||
@@ -3080,6 +3104,13 @@ def _read_meta(obj):
|
||||
if r_txt_modus not in ("fix", "masstab"): r_txt_modus = "fix"
|
||||
# Aktiver Stempel-Stil (id des zuletzt applizierten Stils)
|
||||
r_stil_id = a.GetUserString(_KEY_RAUM_STIL_ID) or ""
|
||||
# Stempel-Felder
|
||||
st_scope = a.GetUserString(_KEY_STEMPEL_SCOPE) or "total"
|
||||
try: st_th = float(a.GetUserString(_KEY_STEMPEL_TXT_H) or "0.20")
|
||||
except Exception: st_th = 0.20
|
||||
st_font = a.GetUserString(_KEY_STEMPEL_FONT) or ""
|
||||
st_bold = (a.GetUserString(_KEY_STEMPEL_BOLD) == "1")
|
||||
st_ital = (a.GetUserString(_KEY_STEMPEL_ITAL) == "1")
|
||||
# Field-Layout — parsed JSON list of rows
|
||||
r_layout_raw = a.GetUserString(_KEY_RAUM_LAYOUT) or ""
|
||||
r_layout = []
|
||||
@@ -3202,6 +3233,11 @@ def _read_meta(obj):
|
||||
"raum_layout": r_layout,
|
||||
"raum_txt_modus": r_txt_modus,
|
||||
"raum_stil_id": r_stil_id,
|
||||
"stempel_scope": st_scope,
|
||||
"stempel_txt_h": st_th,
|
||||
"stempel_font": st_font,
|
||||
"stempel_bold": st_bold,
|
||||
"stempel_italic": st_ital,
|
||||
"wand_layered": w_layered,
|
||||
"wand_layers": w_layers,
|
||||
"wand_layer_idx": w_layer_idx,
|
||||
@@ -3808,11 +3844,24 @@ def _make_oeffnung_pieces(axis_curve, point_on_axis, wall_dicke, oeff_meta, base
|
||||
SOURCE_TYPES = ("wand_axis", "decke_outline", "dach_outline",
|
||||
"oeffnung_point", "treppe_axis",
|
||||
"stuetze_point", "traeger_axis",
|
||||
"raum_outline", "decke_aussparung_outline")
|
||||
"raum_outline", "decke_aussparung_outline",
|
||||
# Stempel: SIA-Bilanz-TextEntity. Source-only (kein Volume),
|
||||
# die TextEntity selber IST die Source-Geometrie. Regennt
|
||||
# automatisch wenn raeume im Scope sich aendern.
|
||||
"stempel")
|
||||
VOLUME_TYPES = ("wand_volume", "decke_volume", "dach_volume",
|
||||
"oeffnung_volume", "oeffnung_swing", "oeffnung_sturz",
|
||||
"treppe_volume", "stuetze_volume", "traeger_volume",
|
||||
"raum_stamp", "raum_fill")
|
||||
|
||||
# Stempel-Scope-Werte:
|
||||
# "total" → alle Raeume im Doc
|
||||
# "geschoss:<id>" → nur Raeume im genannten Geschoss
|
||||
_KEY_STEMPEL_SCOPE = "dossier_stempel_scope"
|
||||
_KEY_STEMPEL_TXT_H = "dossier_stempel_txt_h" # Texthoehe in m
|
||||
_KEY_STEMPEL_FONT = "dossier_stempel_font"
|
||||
_KEY_STEMPEL_BOLD = "dossier_stempel_bold"
|
||||
_KEY_STEMPEL_ITAL = "dossier_stempel_italic"
|
||||
# Oeffnungs-Cutout: Boolean-Difference aus Wand. Zusaetzlich kriegt die
|
||||
# Oeffnung ihr eigenes Volumen (Rahmen + Sims + Glas) als Sub-Element.
|
||||
|
||||
@@ -4938,6 +4987,144 @@ def _make_raum_stamp_text(centroid, name, nummer, funktion, area, rundung,
|
||||
return None
|
||||
|
||||
|
||||
def compute_sia_bilanz(doc, scope="total"):
|
||||
"""Aggregiert raum_outline-Flaechen nach raum_sia-Klassifikation.
|
||||
scope = "total" → alle Raeume
|
||||
scope = "geschoss:<id>" → nur Raeume mit raum_geschoss == id
|
||||
Liefert dict {hnf, nnf, vf, ff, gf, agf, nf, ngf, count, scope, geschossName}.
|
||||
NF = HNF + NNF (Nutzflaeche). NGF = NF + VF + FF (Nettogeschossflaeche
|
||||
laut SIA 416).
|
||||
"""
|
||||
out = {"hnf": 0.0, "nnf": 0.0, "vf": 0.0, "ff": 0.0,
|
||||
"gf": 0.0, "agf": 0.0, "count": 0,
|
||||
"scope": scope, "geschossName": ""}
|
||||
if doc is None: return out
|
||||
target_gid = None
|
||||
if isinstance(scope, str) and scope.startswith("geschoss:"):
|
||||
target_gid = scope.split(":", 1)[1]
|
||||
g = _geschoss_by_id(doc, target_gid)
|
||||
if g: out["geschossName"] = g.get("name") or ""
|
||||
for obj in doc.Objects:
|
||||
try:
|
||||
m = _read_meta(obj)
|
||||
if not m or m.get("type") != "raum_outline": continue
|
||||
if target_gid is not None and m.get("geschoss") != target_gid:
|
||||
continue
|
||||
try: area, _, _ = _raum_amp(obj.Geometry)
|
||||
except Exception: continue
|
||||
if not area or area <= 0: continue
|
||||
sia = (m.get("raum_sia") or "").lower()
|
||||
if sia not in ("hnf", "nnf", "vf", "ff", "gf", "agf"): continue
|
||||
out[sia] += float(area)
|
||||
out["count"] += 1
|
||||
except Exception: pass
|
||||
out["nf"] = out["hnf"] + out["nnf"]
|
||||
out["ngf"] = out["nf"] + out["vf"] + out["ff"]
|
||||
return out
|
||||
|
||||
|
||||
def _format_bilanz_lines(bilanz, rundung="0.1"):
|
||||
"""Baut die Stempel-Textzeilen aus einer Bilanz. Zeigt nur Kategorien
|
||||
mit Flaeche > 0. Format kompakt: 'HNF 120.5 m²'."""
|
||||
lines = []
|
||||
def _row(label, val):
|
||||
return "{} {} m²".format(label.ljust(4), _format_area(val, rundung))
|
||||
# Nutzflaechen-Block
|
||||
has_nf = bilanz["hnf"] > 0 or bilanz["nnf"] > 0
|
||||
if bilanz["hnf"] > 0: lines.append(_row("HNF", bilanz["hnf"]))
|
||||
if bilanz["nnf"] > 0: lines.append(_row("NNF", bilanz["nnf"]))
|
||||
if has_nf:
|
||||
lines.append("────────────")
|
||||
lines.append(_row("NF", bilanz["nf"]))
|
||||
# VF/FF
|
||||
if bilanz["vf"] > 0: lines.append(_row("VF", bilanz["vf"]))
|
||||
if bilanz["ff"] > 0: lines.append(_row("FF", bilanz["ff"]))
|
||||
# NGF wenn was zusammenkommt
|
||||
if bilanz["ngf"] > 0 and (bilanz["vf"] > 0 or bilanz["ff"] > 0):
|
||||
lines.append("────────────")
|
||||
lines.append(_row("NGF", bilanz["ngf"]))
|
||||
# Gross-Flaechen separat
|
||||
if bilanz["gf"] > 0 or bilanz["agf"] > 0:
|
||||
lines.append("────────────")
|
||||
if bilanz["gf"] > 0: lines.append(_row("GF", bilanz["gf"]))
|
||||
if bilanz["agf"] > 0: lines.append(_row("AGF", bilanz["agf"]))
|
||||
return lines
|
||||
|
||||
|
||||
def _make_stempel_text(pos, scope, doc, text_height=0.20, z=0.0,
|
||||
font=None, bold=False, italic=False):
|
||||
"""Baut die Stempel-TextEntity fuer einen Scope ("total" oder
|
||||
"geschoss:<id>"). Header = "Nutzflächen · {Scope-Label}"."""
|
||||
try:
|
||||
bilanz = compute_sia_bilanz(doc, scope)
|
||||
if scope == "total":
|
||||
scope_label = "Total"
|
||||
elif bilanz["geschossName"]:
|
||||
scope_label = bilanz["geschossName"]
|
||||
else:
|
||||
scope_label = "—"
|
||||
header = "Nutzflächen · {}".format(scope_label)
|
||||
body = _format_bilanz_lines(bilanz)
|
||||
if not body:
|
||||
body = ["(keine klassifizierten Räume)"]
|
||||
text = "\n".join([header, "════════════"] + body)
|
||||
te = rg.TextEntity()
|
||||
te.Text = text
|
||||
plane = rg.Plane(rg.Point3d(pos.X, pos.Y, float(z)),
|
||||
rg.Vector3d.ZAxis)
|
||||
te.Plane = plane
|
||||
try: te.TextHeight = float(text_height)
|
||||
except Exception: te.TextHeight = 0.20
|
||||
try:
|
||||
te.Justification = rg.TextJustification.MiddleLeft
|
||||
except Exception: pass
|
||||
# Font/Style optional
|
||||
if doc is not None and font:
|
||||
try:
|
||||
f = Rhino.DocObjects.Font.FromQuartetProperties(
|
||||
str(font), bool(bold), bool(italic))
|
||||
if f is not None:
|
||||
idx = doc.Fonts.FindOrCreate(f.QuartetName,
|
||||
bool(bold), bool(italic))
|
||||
if idx >= 0:
|
||||
try: te.FontIndex = idx
|
||||
except Exception: pass
|
||||
except Exception: pass
|
||||
return te
|
||||
except Exception as ex:
|
||||
print("[ELEMENTE] _make_stempel_text:", ex)
|
||||
return None
|
||||
|
||||
|
||||
def _regenerate_stempel_for_geschoss(doc, geschoss_id):
|
||||
"""Regennt alle Stempel die diesen Geschoss-Scope (oder 'total') haben.
|
||||
Wird nach jedem raum_outline-Regen aufgerufen damit Bilanzen aktuell
|
||||
bleiben. Idempotent + safe gegen Endless-Loops via _REGEN_BUSY-Check."""
|
||||
if doc is None: return
|
||||
if sc.sticky.get(_REGEN_BUSY): return
|
||||
target_scopes = {"total"}
|
||||
if geschoss_id:
|
||||
target_scopes.add("geschoss:{}".format(geschoss_id))
|
||||
ids = []
|
||||
for obj in doc.Objects:
|
||||
try:
|
||||
m = _read_meta(obj)
|
||||
if not m or m.get("type") != "stempel": continue
|
||||
if m.get("stempel_scope") in target_scopes:
|
||||
ids.append(m["id"])
|
||||
except Exception: pass
|
||||
if not ids: return
|
||||
_was = sc.sticky.get(_REGEN_BUSY, False)
|
||||
sc.sticky[_REGEN_BUSY] = True
|
||||
try:
|
||||
for sid in ids:
|
||||
try: _regenerate_element(doc, sid)
|
||||
except Exception as ex:
|
||||
print("[ELEMENTE] stempel-regen", sid, ":", ex)
|
||||
finally:
|
||||
sc.sticky[_REGEN_BUSY] = _was
|
||||
|
||||
|
||||
def _make_raum_hatch(outline_curve, z_uk, doc, pattern_name="Solid"):
|
||||
"""Erzeugt einen Hatch unter der Raum-Outline am Z=z_uk + 1 mm mit
|
||||
gegebenem Pattern. Color = ByObject (default hell). Override-System
|
||||
@@ -5572,10 +5759,22 @@ def _regenerate_element(doc, element_id):
|
||||
_was_busy = sc.sticky.get(_REGEN_BUSY, False)
|
||||
sc.sticky[_REGEN_BUSY] = True
|
||||
try:
|
||||
return _regenerate_element_body(doc, element_id, src_obj, meta,
|
||||
geom, geschoss_name)
|
||||
result = _regenerate_element_body(doc, element_id, src_obj, meta,
|
||||
geom, geschoss_name)
|
||||
finally:
|
||||
sc.sticky[_REGEN_BUSY] = _was_busy
|
||||
# Wenn ein raum_outline-Regen einen Stempel-Dirty-Marker gesetzt hat
|
||||
# (oder generell raeumlich-Aenderungen), Stempel im selben Geschoss
|
||||
# (+ Total) neu rechnen. Lauft AUSSERHALB des REGEN_BUSY-Blocks damit
|
||||
# die Stempel selber regen koennen.
|
||||
try:
|
||||
dirty_gid = sc.sticky.get("_dossier_stempel_dirty")
|
||||
if dirty_gid is not None:
|
||||
sc.sticky["_dossier_stempel_dirty"] = None
|
||||
_regenerate_stempel_for_geschoss(doc, dirty_gid)
|
||||
except Exception as ex:
|
||||
print("[ELEMENTE] stempel-cascade:", ex)
|
||||
return result
|
||||
|
||||
|
||||
def _regenerate_element_body(doc, element_id, src_obj, meta, geom, geschoss_name):
|
||||
@@ -6321,6 +6520,40 @@ def _regenerate_element_body(doc, element_id, src_obj, meta, geom, geschoss_name
|
||||
raum_txt_modus=meta.get("raum_txt_modus"))
|
||||
try: doc.Objects.AddText(te, attrs)
|
||||
except Exception as ex: print("[ELEMENTE] Raum AddText:", ex)
|
||||
# Stempel im selben Geschoss + Total-Stempel regennen, damit ihre
|
||||
# SIA-Bilanz sich aktualisiert. Deferred via Sticky-Marker damit
|
||||
# das nicht im aktuellen _REGEN_BUSY-Zyklus laeuft.
|
||||
try:
|
||||
sc.sticky["_dossier_stempel_dirty"] = (
|
||||
meta.get("geschoss") or "")
|
||||
except Exception: pass
|
||||
return True
|
||||
elif meta["type"] == "stempel":
|
||||
# Stempel re-renderet sich SELBER (kein separates Volume) — wir
|
||||
# ersetzen die TextEntity in-place. Position bleibt aus der alten
|
||||
# Geometrie erhalten.
|
||||
if not isinstance(geom, rg.TextEntity):
|
||||
print("[ELEMENTE] stempel regen: geom ist keine TextEntity")
|
||||
return False
|
||||
try:
|
||||
pos = geom.Plane.Origin
|
||||
except Exception:
|
||||
pos = rg.Point3d(0, 0, 0)
|
||||
scope = meta.get("stempel_scope") or "total"
|
||||
txt_h = float(meta.get("stempel_txt_h", 0.20))
|
||||
font = meta.get("stempel_font", "") or ""
|
||||
bold = bool(meta.get("stempel_bold", False))
|
||||
italic = bool(meta.get("stempel_italic", False))
|
||||
new_te = _make_stempel_text(pos, scope, doc, text_height=txt_h,
|
||||
z=pos.Z, font=font, bold=bold,
|
||||
italic=italic)
|
||||
if new_te is None: return False
|
||||
# In-place replace
|
||||
try:
|
||||
doc.Objects.Replace(src_obj.Id, new_te)
|
||||
except Exception as ex:
|
||||
print("[ELEMENTE] stempel Replace:", ex)
|
||||
return False
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@@ -6422,6 +6655,7 @@ class ElementeBridge(panel_base.BaseBridge):
|
||||
elif t == "CREATE_STUETZE": self._cmd_create_stuetze(p)
|
||||
elif t == "CREATE_TRAEGER": self._cmd_create_traeger(p)
|
||||
elif t == "CREATE_RAUM": self._cmd_create_raum(p)
|
||||
elif t == "CREATE_STEMPEL": self._cmd_create_stempel(p)
|
||||
elif t == "EXPORT_RAEUME": self._cmd_export_raeume(p)
|
||||
elif t == "LIST_LIBRARY": self._cmd_list_library(p)
|
||||
elif t == "CREATE_SYMBOL": self._cmd_create_symbol(p)
|
||||
@@ -6678,6 +6912,23 @@ class ElementeBridge(panel_base.BaseBridge):
|
||||
"areaFmt": _format_area(area, rnd_eff),
|
||||
"umfang": perim,
|
||||
})
|
||||
elif meta["type"] == "stempel":
|
||||
# Aggregierter Bilanz-Stempel (SIA 416). Scope = "total" oder
|
||||
# "geschoss:<gid>". Liefert direkt die berechneten Werte fuer
|
||||
# ein evtl. Properties-Panel.
|
||||
scope = meta.get("stempel_scope") or "total"
|
||||
bilanz = compute_sia_bilanz(doc, scope)
|
||||
base.update({
|
||||
"kind": "stempel",
|
||||
"scope": scope,
|
||||
"scopeLabel": ("Total" if scope == "total"
|
||||
else (bilanz.get("geschossName") or "—")),
|
||||
"txtH": meta.get("stempel_txt_h", 0.20),
|
||||
"font": meta.get("stempel_font", "") or "",
|
||||
"bold": bool(meta.get("stempel_bold", False)),
|
||||
"italic": bool(meta.get("stempel_italic", False)),
|
||||
"bilanz": bilanz,
|
||||
})
|
||||
elif meta["type"] in ("stuetze_point", "traeger_axis"):
|
||||
# Tragwerk: Stuetze (Punkt) oder Traeger/Unterzug (Achse)
|
||||
gs = _geschoss_by_id(doc, meta["geschoss"])
|
||||
@@ -8415,6 +8666,55 @@ class ElementeBridge(panel_base.BaseBridge):
|
||||
print("[ELEMENTE] Raum erzeugt: {} ({})".format(name, raum_id))
|
||||
self._send_state()
|
||||
|
||||
def _cmd_create_stempel(self, p):
|
||||
"""Erzeugt einen SIA-Bilanz-Stempel (TextEntity) an einem User-
|
||||
gepickten Punkt. Default-Scope = aktives Geschoss (oder 'total'
|
||||
wenn p.scope='total' gepasst wird). Stempel re-rendert sich
|
||||
automatisch wenn sich Raeume im Scope aendern."""
|
||||
doc = Rhino.RhinoDoc.ActiveDoc
|
||||
if doc is None: return
|
||||
scope = p.get("scope") or ""
|
||||
if not scope:
|
||||
# Default: aktives Geschoss, sonst total
|
||||
gid = _active_geschoss_id(doc)
|
||||
scope = "geschoss:{}".format(gid) if gid else "total"
|
||||
try: txt_h = float(p.get("txtH") or _last("stempel_txt_h", 0.20))
|
||||
except Exception: txt_h = 0.20
|
||||
try:
|
||||
import Rhino.Input.Custom as ric
|
||||
from Rhino.Input import GetResult
|
||||
except Exception as ex:
|
||||
print("[ELEMENTE] CREATE_STEMPEL imports:", ex); return
|
||||
gp = ric.GetPoint()
|
||||
gp.SetCommandPrompt("Stempel platzieren ({})".format(scope))
|
||||
res = gp.Get()
|
||||
if res != GetResult.Point: return
|
||||
pos = gp.Point()
|
||||
# Element-ID + Layer
|
||||
stempel_id = "stempel_" + uuid.uuid4().hex[:10]
|
||||
# Layer: nutze Raeume-Sublayer des AKTIVEN Geschosses (oder ersten),
|
||||
# damit Stempel beim CPlane-Clipping auf derselben Ebene sitzt wie
|
||||
# die Raeume
|
||||
active_g_name = _active_geschoss_name(doc) or "EG"
|
||||
layer = _ensure_layer(doc, _layer_path_raum(doc, active_g_name))
|
||||
# TextEntity bauen
|
||||
te = _make_stempel_text(pos, scope, doc, text_height=txt_h, z=pos.Z)
|
||||
if te is None:
|
||||
print("[ELEMENTE] CREATE_STEMPEL: Text-Build failed"); return
|
||||
attrs = Rhino.DocObjects.ObjectAttributes()
|
||||
attrs.LayerIndex = layer
|
||||
_attach_meta(attrs, stempel_id, "stempel",
|
||||
_active_geschoss_id(doc) or "",
|
||||
0.0, "", "", "mid",
|
||||
stempel_scope=scope, stempel_txt_h=txt_h)
|
||||
new_id = doc.Objects.AddText(te, attrs)
|
||||
if new_id == System.Guid.Empty:
|
||||
print("[ELEMENTE] Stempel AddText fehlgeschlagen"); return
|
||||
_save_last(stempel_txt_h=txt_h)
|
||||
doc.Views.Redraw()
|
||||
print("[ELEMENTE] Stempel erzeugt: {} (scope={})".format(stempel_id, scope))
|
||||
self._send_state()
|
||||
|
||||
def _cmd_export_raeume(self, p):
|
||||
"""Schreibt CSV mit allen Raeumen: Nummer, Name, Geschoss,
|
||||
Funktion, SIA, Flaeche, Umfang. Datei via SaveFileDialog."""
|
||||
@@ -10402,6 +10702,29 @@ class ElementeBridge(panel_base.BaseBridge):
|
||||
doc.Views.Redraw()
|
||||
self._send_state()
|
||||
return
|
||||
# Stempel: scope / txtH / font / bold / italic
|
||||
if old_meta["type"] == "stempel":
|
||||
scope = p.get("scope", old_meta.get("stempel_scope", "total"))
|
||||
if not (scope == "total" or scope.startswith("geschoss:")):
|
||||
scope = "total"
|
||||
try: st_th = float(p.get("txtH", old_meta.get("stempel_txt_h", 0.20)))
|
||||
except Exception: st_th = 0.20
|
||||
st_font = p.get("font", old_meta.get("stempel_font", "") or "")
|
||||
st_bold = bool(p.get("bold", old_meta.get("stempel_bold", False)))
|
||||
st_ital = bool(p.get("italic", old_meta.get("stempel_italic", False)))
|
||||
attrs = axis_obj.Attributes
|
||||
_attach_meta(attrs, wall_id, "stempel",
|
||||
old_meta.get("geschoss", ""), 0.0, "", "", "mid",
|
||||
stempel_scope=scope, stempel_txt_h=st_th,
|
||||
stempel_font=st_font, stempel_bold=st_bold,
|
||||
stempel_italic=st_ital)
|
||||
axis_obj.Attributes = attrs
|
||||
axis_obj.CommitChanges()
|
||||
_save_last(stempel_txt_h=st_th)
|
||||
_regenerate_element(doc, wall_id)
|
||||
doc.Views.Redraw()
|
||||
self._send_state()
|
||||
return
|
||||
# Treppe: Breite/Anzahl Stufen/Referenz/Zielgeschoss
|
||||
if old_meta["type"] == "treppe_axis":
|
||||
try: tb = float(p.get("breite", old_meta.get("treppe_breite", 1.0)))
|
||||
|
||||
Reference in New Issue
Block a user