Ebenen: Plangrafik 60 → 80, RAEUME/GF/AGF auf 60/61/62

Doppelbelegung Code 60: alte Konvention "Plangrafik" steht im Weg fuer
die neuen Raum-Layer (RAEUME 60, GF 61, AGF 62). Wenn ein Doc beides
hat, fiel die Auto-Add-Logik in _find_ebene_sublayer_name aus → Raeume
landeten auf Rhino-Layer "60_RAEUME" der aber im Dossier-Ebenen-Panel
nie auftauchte (dort stand 60 = Plangrafik).

Fix in zwei Teilen:

1) Frontend-Default-Schema (App.jsx INITIAL_EBENEN):
   - 60: RAEUME (neu, fuer HNF/NNF/VF/FF)
   - 61: GF (Geschossflaeche)
   - 62: AGF (Aussengeschossflaeche)
   - 80: Plangrafik (verschoben von 60)

2) One-shot Migration in elemente._migrate_plangrafik_60_to_80_once():
   - Detect: dossier_ebenen hat code=60 + name=Plangrafik
   - Action: code 60 → 80, RAEUME/GF/AGF auf 60/61/62 hinzufuegen
   - Rhino-Layer rename: alle "60_Plangrafik" Layer → "80_Plangrafik"
   - build_layers + broadcast_state → Ebenen-Manager UI aktualisiert
   - Sticky-Flag verhindert Re-Run

Plus kleinerer UX-Fix: Skala-Dropdown-Labels gekuerzt
("fix (m)" / "massstaeblich (mm)" statt langer Beschreibungen).
This commit is contained in:
2026-05-27 01:00:33 +02:00
parent 2a838aee93
commit 1c3b0f3919
3 changed files with 111 additions and 3 deletions
+98
View File
@@ -297,6 +297,7 @@ _KEY_RAUM_TXT_H = "dossier_raum_txt_h" # Texthoehe in m
_KEY_RAUM_ALIGN = "dossier_raum_align" # "links"|"mid"|"rechts" _KEY_RAUM_ALIGN = "dossier_raum_align" # "links"|"mid"|"rechts"
_KEY_RAUM_SIA = "dossier_raum_sia" # "" | "hnf" | "nnf" | "vf" | "ff" _KEY_RAUM_SIA = "dossier_raum_sia" # "" | "hnf" | "nnf" | "vf" | "ff"
_KEY_RAUM_FUELL = "dossier_raum_fuellung" # "" (keine) | "Solid" | Pattern-Name | "ByLayer" _KEY_RAUM_FUELL = "dossier_raum_fuellung" # "" (keine) | "Solid" | Pattern-Name | "ByLayer"
_KEY_RAUM_PERSONEN = "dossier_raum_personen" # int — Anzahl Personen (SIA Personen-Belegung)
# Stempel-Typografie (per-Raum-Override) — leer = Doc-Default-Font, Defaults siehe _read_meta # Stempel-Typografie (per-Raum-Override) — leer = Doc-Default-Font, Defaults siehe _read_meta
_KEY_RAUM_TXT_FONT = "dossier_raum_txt_font" # Font-Quartet-Name (z.B. "DM Mono", "Helvetica") _KEY_RAUM_TXT_FONT = "dossier_raum_txt_font" # Font-Quartet-Name (z.B. "DM Mono", "Helvetica")
_KEY_RAUM_TXT_BOLD = "dossier_raum_txt_bold" # "0"|"1" _KEY_RAUM_TXT_BOLD = "dossier_raum_txt_bold" # "0"|"1"
@@ -2707,6 +2708,7 @@ def _attach_meta(obj_attrs, wall_id, type_, geschoss, dicke, uk_over, ok_over,
raum_name=None, raum_nummer=None, raum_funktion=None, raum_name=None, raum_nummer=None, raum_funktion=None,
raum_rundung=None, raum_txt_h=None, raum_rundung=None, raum_txt_h=None,
raum_align=None, raum_sia=None, raum_fuellung=None, raum_align=None, raum_sia=None, raum_fuellung=None,
raum_personen=None,
raum_txt_font=None, raum_txt_bold=None, raum_txt_italic=None, raum_txt_font=None, raum_txt_bold=None, raum_txt_italic=None,
raum_show_nummer=None, raum_show_name=None, raum_show_nummer=None, raum_show_name=None,
raum_show_funktion=None, raum_show_area=None, raum_show_funktion=None, raum_show_area=None,
@@ -2886,6 +2888,12 @@ def _attach_meta(obj_attrs, wall_id, type_, geschoss, dicke, uk_over, ok_over,
else: else:
v = str(raum_fuellung) v = str(raum_fuellung)
obj_attrs.SetUserString(_KEY_RAUM_FUELL, v) obj_attrs.SetUserString(_KEY_RAUM_FUELL, v)
if raum_personen is not None:
try:
n = int(raum_personen)
if n < 0: n = 0
obj_attrs.SetUserString(_KEY_RAUM_PERSONEN, str(n))
except Exception: pass
# Stempel-Typografie + Sichtbarkeit (per-Raum-Override) # Stempel-Typografie + Sichtbarkeit (per-Raum-Override)
if raum_txt_font is not None: if raum_txt_font is not None:
obj_attrs.SetUserString(_KEY_RAUM_TXT_FONT, str(raum_txt_font)) obj_attrs.SetUserString(_KEY_RAUM_TXT_FONT, str(raum_txt_font))
@@ -3136,6 +3144,10 @@ def _read_meta(obj):
if r_fuell_raw == "1": r_fuell = "Solid" if r_fuell_raw == "1": r_fuell = "Solid"
elif r_fuell_raw == "0": r_fuell = "" elif r_fuell_raw == "0": r_fuell = ""
else: r_fuell = r_fuell_raw or "" else: r_fuell = r_fuell_raw or ""
# Personen-Belegung (int, default 0 = nicht erfasst)
try: r_personen = int(a.GetUserString(_KEY_RAUM_PERSONEN) or "0")
except Exception: r_personen = 0
if r_personen < 0: r_personen = 0
# Stempel-Typografie (Defaults: leer = Doc-Default-Font, bold/italic off) # Stempel-Typografie (Defaults: leer = Doc-Default-Font, bold/italic off)
r_font = a.GetUserString(_KEY_RAUM_TXT_FONT) or "" r_font = a.GetUserString(_KEY_RAUM_TXT_FONT) or ""
r_bold = (a.GetUserString(_KEY_RAUM_TXT_BOLD) == "1") r_bold = (a.GetUserString(_KEY_RAUM_TXT_BOLD) == "1")
@@ -12518,6 +12530,89 @@ def _sync_orphan_grips(doc):
sc.sticky[_SELECT_BUSY] = False sc.sticky[_SELECT_BUSY] = False
def _migrate_plangrafik_60_to_80_once(doc):
"""One-shot pro Doc: alte Ebenen-Konvention 'code 60 = Plangrafik'
auf neue Konvention umstellen (60 ist jetzt RAEUME, Plangrafik wandert
auf 80). Konkret:
- dossier_ebenen JSON: code '60'+name 'Plangrafik' code '80'
- Rhino-Layer 'EG::60_Plangrafik' '80_Plangrafik' (ueber alle
Geschosse)
Sticky-Flag verhindert Re-Run pro Doc-Session."""
if doc is None: return
try: key = "_dossier_plangrafik_migration_" + str(doc.RuntimeSerialNumber)
except Exception: key = "_dossier_plangrafik_migration_default"
if sc.sticky.get(key): return
sc.sticky[key] = True
raw = doc.Strings.GetValue("dossier_ebenen")
if not raw: return
try:
ebenen = json.loads(raw)
except Exception: return
if not isinstance(ebenen, list): return
changed = False
for e in ebenen:
if not isinstance(e, dict): continue
if e.get("code") == "60" and (e.get("name") or "").lower() == "plangrafik":
print("[ELEMENTE] Migration: Plangrafik von Code 60 → 80")
e["code"] = "80"
changed = True
break
# RAEUME / GF / AGF proaktiv eintragen wenn noch nicht vorhanden — damit
# sie im Ebenen-Manager sichtbar sind ohne erst einen Raum erstellen zu
# muessen.
existing_codes = {e.get("code") for e in ebenen if isinstance(e, dict)}
raum_defaults = [
("60", "RAEUME", "#7a8a9a", 0.13),
("61", "GF", "#a0a0a0", 0.18),
("62", "AGF", "#90b090", 0.13),
]
for code, name, color, lw in raum_defaults:
if code not in existing_codes:
ebenen.append({
"code": code, "name": name,
"color": color, "lw": lw,
"visible": True, "locked": False,
})
print("[ELEMENTE] Migration: Ebene '{}_{}' hinzugefuegt".format(
code, name))
changed = True
if not changed: return
# Speichern + Rhino-Layer umbenennen
try:
doc.Strings.SetString("dossier_ebenen",
json.dumps(ebenen, ensure_ascii=False))
except Exception as ex:
print("[ELEMENTE] Plangrafik-Migration save:", ex)
return
# Rhino-Layer umbenennen: <geschoss>::60_Plangrafik → 80_Plangrafik
n_renamed = 0
try:
for layer in list(doc.Layers):
try:
if layer.IsDeleted: continue
if layer.Name == "60_Plangrafik":
layer.Name = "80_Plangrafik"
n_renamed += 1
except Exception: pass
except Exception as ex:
print("[ELEMENTE] Plangrafik-Migration rename:", ex)
if n_renamed > 0:
print("[ELEMENTE] {} Rhino-Layer 60_Plangrafik → 80_Plangrafik umbenannt".format(
n_renamed))
# build_layers + broadcast damit Ebenen-Manager UI nachzieht
try:
import layer_builder as _lb
z_raw = doc.Strings.GetValue("dossier_zeichnungsebenen")
zlist = json.loads(z_raw) if z_raw else []
if zlist: _lb.build_layers(doc, zlist, ebenen)
except Exception as ex:
print("[ELEMENTE] build_layers nach Plangrafik-Migration:", ex)
try:
import rhinopanel as _rp
_rp._broadcast_state(doc)
except Exception: pass
def _migrate_referenz_layer_once(doc): def _migrate_referenz_layer_once(doc):
"""One-shot pro Doc-Session: wand_axis + oeffnung_point auf den """One-shot pro Doc-Session: wand_axis + oeffnung_point auf den
neuen Referenzlinien-Sublayer migrieren, und alle versehentlich neuen Referenzlinien-Sublayer migrieren, und alle versehentlich
@@ -12683,6 +12778,9 @@ def _on_idle_selection(sender, e):
# versteckten wieder zeigen (Cleanup nach der abgebrochenen # versteckten wieder zeigen (Cleanup nach der abgebrochenen
# Hide-on-Select-Implementation). # Hide-on-Select-Implementation).
_migrate_referenz_layer_once(doc) _migrate_referenz_layer_once(doc)
# One-shot: Plangrafik von Code 60 auf 80 umziehen (Code 60 ist jetzt
# fuer RAEUME reserviert)
_migrate_plangrafik_60_to_80_once(doc)
# Oeffnungen-Tree in dossier_ebenen anlegen falls noch nicht vorhanden # Oeffnungen-Tree in dossier_ebenen anlegen falls noch nicht vorhanden
# (sonst erscheinen die neuen Sublayer nicht im Ebenen-Panel). # (sonst erscheinen die neuen Sublayer nicht im Ebenen-Panel).
_ensure_oeff_ebenen_once(doc) _ensure_oeff_ebenen_once(doc)
+7 -1
View File
@@ -23,7 +23,13 @@ const INITIAL_EBENEN = [
{ code: '31', name: 'Dächer', color: '#7a4a3a', lw: 0.35, visible: true, locked: false }, { code: '31', name: 'Dächer', color: '#7a4a3a', lw: 0.35, visible: true, locked: false },
{ code: '35', name: 'Träger', color: '#a87858', lw: 0.50, visible: true, locked: false }, { code: '35', name: 'Träger', color: '#a87858', lw: 0.50, visible: true, locked: false },
{ code: '50', name: 'Text', color: '#d0d0d0', lw: 0.13, visible: true, locked: false }, { code: '50', name: 'Text', color: '#d0d0d0', lw: 0.13, visible: true, locked: false },
{ code: '60', name: 'Plangrafik', color: '#c0a040', lw: 0.13, visible: true, locked: false }, // Raum-Familie: RAEUME (Nutzflaechen HNF/NNF/VF/FF) + GF (Geschossflaeche
// gross) + AGF (Aussengeschossflaeche). Wird vom Elemente-Modul auto-
// erzeugt sobald der erste Raum mit entsprechendem SIA-Tag entsteht.
{ code: '60', name: 'RAEUME', color: '#7a8a9a', lw: 0.13, visible: true, locked: false },
{ code: '61', name: 'GF', color: '#a0a0a0', lw: 0.18, visible: true, locked: false },
{ code: '62', name: 'AGF', color: '#90b090', lw: 0.13, visible: true, locked: false },
{ code: '80', name: 'Plangrafik', color: '#c0a040', lw: 0.13, visible: true, locked: false },
{ code: '90', name: 'Referenzen', color: '#585860', lw: 0.13, visible: true, locked: false }, { code: '90', name: 'Referenzen', color: '#585860', lw: 0.13, visible: true, locked: false },
{ code: '99', name: 'Konstruktion', color: '#404048', lw: 0.13, visible: true, locked: false }, { code: '99', name: 'Konstruktion', color: '#404048', lw: 0.13, visible: true, locked: false },
] ]
+6 -2
View File
@@ -1109,8 +1109,12 @@ function RaumProperties({ raum, geschosse, onUpdate, onDelete, hatchPatterns, fo
onChange={(e) => onUpdate({ txtModus: e.target.value })} onChange={(e) => onUpdate({ txtModus: e.target.value })}
title="fix: Hoehe in m via Oberleiste · masstab: Paper-mm via Massstab" title="fix: Hoehe in m via Oberleiste · masstab: Paper-mm via Massstab"
style={{ flex: 1, fontSize: 11 }}> style={{ flex: 1, fontSize: 11 }}>
<option value="fix">fix · Hoehe = Oberleiste-Wert (m)</option> <option value="fix" title="Texthöhe in Meter via Oberleiste">
<option value="masstab">masstab · skaliert mit Plan-Massstab</option> fix (m)
</option>
<option value="masstab" title="Texthöhe als Paper-mm, skaliert mit aktivem Plan-Massstab">
massstäblich (mm)
</option>
</select> </select>
</div> </div>