Stale-Detection bei Project-Settings: nur betroffene Waende regenen

Bisher: bei jedem Project-Settings-Save wurden ALLE wand_axis im Doc regenert
(auch wenn nichts wand-relevantes geaendert wurde, z.B. nur ein Default-Wert
oder ein Library-Eintrag).

Jetzt: Diff der wand_styles + materials vor/nach Save. Sammle nur die Waende
die einen geaenderten Style nutzen ODER ein geaendertes Material (direkt via
Style oder als Schicht in layered Wand). Regen nur diese.

Plus: Joint-Cache-Batch-Flag waehrend des Regens setzen (war im sync-Pfad
sonst pro Regen invalidiert worden → unnoetiger Overhead).

Log zeigt jetzt z.B. "3 Waende regenert (1 Stile, 2 Materials geaendert)"
statt blind "N Waende regenert".
This commit is contained in:
2026-05-30 23:45:45 +02:00
parent 0cc06364e8
commit 5fdad504da
+59 -11
View File
@@ -1080,6 +1080,8 @@ class EbenenBridge(panel_base.BaseBridge):
def on_save(updated): def on_save(updated):
doc2 = Rhino.RhinoDoc.ActiveDoc doc2 = Rhino.RhinoDoc.ActiveDoc
if doc2 is None: return if doc2 is None: return
# Snapshot OLD settings VOR dem Save fuer Stale-Detection
old_settings = load_project_settings(doc2) or {}
new_settings = { new_settings = {
"defaults": updated.get("defaults", {}), "defaults": updated.get("defaults", {}),
"materials": updated.get("materials", []), "materials": updated.get("materials", []),
@@ -1102,33 +1104,79 @@ class EbenenBridge(panel_base.BaseBridge):
if eb is not None: eb._send_state() if eb is not None: eb._send_state()
except Exception as ex: except Exception as ex:
print("[PROJECT-SETTINGS] elemente refresh:", ex) print("[PROJECT-SETTINGS] elemente refresh:", ex)
# Alle wand_axis im Doc regenen damit Material-Aenderungen # Stale-Detection: welche Wand-Styles oder Materials haben sich
# (PBR/Texturen/Hatch) auf existing Waende durchschlagen. # geaendert? Nur betroffene Waende regenen (statt alle).
try: try:
import elemente import elemente
undo_serial = doc2.BeginUndoRecord("Material-Update Regen") old_styles = {s.get("id"): s for s in
prev_redraw = doc2.Views.RedrawEnabled (old_settings.get("wand_styles") or [])
doc2.Views.RedrawEnabled = False if isinstance(s, dict) and s.get("id")}
new_styles = {s.get("id"): s for s in
(new_settings.get("wand_styles") or [])
if isinstance(s, dict) and s.get("id")}
changed_style_ids = set()
for sid in (set(old_styles) | set(new_styles)):
if old_styles.get(sid) != new_styles.get(sid):
changed_style_ids.add(sid)
old_mats = {m.get("name"): m for m in
(old_settings.get("materials") or [])
if isinstance(m, dict) and m.get("name")}
new_mats = {m.get("name"): m for m in
(new_settings.get("materials") or [])
if isinstance(m, dict) and m.get("name")}
changed_material_names = set()
for n in (set(old_mats) | set(new_mats)):
if old_mats.get(n) != new_mats.get(n):
changed_material_names.add(n)
# Welche Waende sind betroffen?
wall_ids = [] wall_ids = []
seen = set()
for obj in doc2.Objects: for obj in doc2.Objects:
m = elemente._read_meta(obj) m = elemente._read_meta(obj)
if m and m.get("type") == "wand_axis": if not m or m.get("type") != "wand_axis": continue
wall_ids.append(m["id"]) wid = m["id"]
# Chain-Anchor regent automatisch alle members — wir koennen if wid in seen: continue
# trotzdem alle einzeln triggern, _REGEN_BUSY-Guard verhindert affected = False
# Doppel-Arbeit. Einfacher als Anchor-Election hier. sid = (m.get("wand_style_id") or "").strip()
if sid and sid in changed_style_ids:
affected = True
if not affected and m.get("wand_layered"):
for layer in (m.get("wand_layers") or []):
if isinstance(layer, dict) and layer.get("material") \
in changed_material_names:
affected = True; break
if not affected and sid and changed_material_names:
# Solid-Wand mit Style: Material-Aenderung des
# Style-referenzierten Materials trifft sie
st = new_styles.get(sid) or old_styles.get(sid)
if st and st.get("material") in changed_material_names:
affected = True
if affected:
wall_ids.append(wid); seen.add(wid)
if not wall_ids:
print("[PROJECT-SETTINGS] keine wand-relevanten Aenderungen")
return
undo_serial = doc2.BeginUndoRecord(
"Stil-Update Regen ({})".format(len(wall_ids)))
prev_redraw = doc2.Views.RedrawEnabled
doc2.Views.RedrawEnabled = False
try: try:
sc.sticky["_dossier_regen_batch_active"] = True
for wid in wall_ids: for wid in wall_ids:
try: elemente._regenerate_element(doc2, wid) try: elemente._regenerate_element(doc2, wid)
except Exception as ex: except Exception as ex:
print("[PROJECT-SETTINGS] regen", wid, ex) print("[PROJECT-SETTINGS] regen", wid, ex)
finally: finally:
sc.sticky["_dossier_regen_batch_active"] = False
doc2.Views.RedrawEnabled = prev_redraw doc2.Views.RedrawEnabled = prev_redraw
try: doc2.EndUndoRecord(undo_serial) try: doc2.EndUndoRecord(undo_serial)
except Exception: pass except Exception: pass
try: doc2.Views.Redraw() try: doc2.Views.Redraw()
except Exception: pass except Exception: pass
print("[PROJECT-SETTINGS] {} Waende regenert".format(len(wall_ids))) print("[PROJECT-SETTINGS] {} Waende regenert ({} Stile, "
"{} Materials geaendert)".format(
len(wall_ids), len(changed_style_ids),
len(changed_material_names)))
except Exception as ex: except Exception as ex:
print("[PROJECT-SETTINGS] wall regen:", ex) print("[PROJECT-SETTINGS] wall regen:", ex)
# Custom-Bridge fuer Project-Settings: handelt SAVE/CANCEL + # Custom-Bridge fuer Project-Settings: handelt SAVE/CANCEL +