#! python 3 # -*- coding: utf-8 -*- """ mass_style.py Globale Mass-Stil-Presets fuer Dossier — speichert pro Dokument benannte Konfigurationen fuer: - Raum-Flaechen-Rundung - Mass-Linien-Dezimalstellen - (erweiterbar) Persistiert als JSON in doc.Strings["dossier_mass_styles"] (Liste) und doc.Strings["dossier_mass_style_active"] (aktive ID). Ein Mass-Style wird als globale Vorgabe gelesen. Per-Element-Override (z.B. raum_rundung UserString am einzelnen Raum) hat Vorrang wenn gesetzt. """ import json import uuid import Rhino _KEY_STYLES = "dossier_mass_styles" _KEY_ACTIVE = "dossier_mass_style_active" _RAUM_RUNDUNGEN = ("exakt", "0.01", "0.1", "0.5", "1") _DIM_DEZIMALSTELLEN = (0, 1, 2, 3, 4) _DIM_EINHEITEN = ("m", "cm", "mm") # --------------------------------------------------------------------------- # Default-Presets — werden lazy beim ersten Lesen erzeugt wenn das Doc # noch keine Mass-Styles kennt. Decken die gaengigen Massstaebe ab. _DEFAULT_PRESETS = [ { "name": "Plan 1:50", "raumRundung": "0.1", "dimDezimalstellen": 2, "dimEinheit": "m", "default": True, }, { "name": "Plan 1:100", "raumRundung": "0.5", "dimDezimalstellen": 2, "dimEinheit": "m", "default": False, }, { "name": "Übersicht 1:500", "raumRundung": "1", "dimDezimalstellen": 1, "dimEinheit": "m", "default": False, }, ] def _normalize(preset): """Validiert + bereinigt einen Preset-Eintrag (Defaults setzen, nicht-erlaubte Werte korrigieren).""" if not isinstance(preset, dict): preset = {} rr = preset.get("raumRundung") or "0.1" if rr not in _RAUM_RUNDUNGEN: rr = "0.1" try: dd = int(preset.get("dimDezimalstellen", 2)) except (TypeError, ValueError): dd = 2 if dd not in _DIM_DEZIMALSTELLEN: dd = 2 de = preset.get("dimEinheit") or "m" if de not in _DIM_EINHEITEN: de = "m" return { "id": preset.get("id") or ("ms_" + uuid.uuid4().hex[:8]), "name": preset.get("name") or "Unbenannt", "raumRundung": rr, "dimDezimalstellen": dd, "dimEinheit": de, } def list_presets(doc): if doc is None: return [] try: raw = doc.Strings.GetValue(_KEY_STYLES) if not raw: # Erst-Initialisierung: Default-Liste schreiben items = [_normalize(p) for p in _DEFAULT_PRESETS] _save_all(doc, items) # Default-Aktiv setzen falls noch nichts gesetzt if not doc.Strings.GetValue(_KEY_ACTIVE): doc.Strings.SetString(_KEY_ACTIVE, items[0]["id"]) return items parsed = json.loads(raw) if not isinstance(parsed, list): return [] return [_normalize(p) for p in parsed] except Exception as ex: print("[MASS_STYLE] list:", ex) return [] def _save_all(doc, items): try: doc.Strings.SetString(_KEY_STYLES, json.dumps(items)) except Exception as ex: print("[MASS_STYLE] save:", ex) def get_active_id(doc): if doc is None: return None try: v = doc.Strings.GetValue(_KEY_ACTIVE) return v or None except Exception: return None def set_active_id(doc, preset_id): if doc is None: return items = list_presets(doc) if preset_id and not any(p["id"] == preset_id for p in items): return # Unbekannte ID — nicht setzen try: doc.Strings.SetString(_KEY_ACTIVE, preset_id or "") except Exception as ex: print("[MASS_STYLE] set active:", ex) def get_active(doc): """Liefert das aktive Preset (dict) oder None.""" items = list_presets(doc) aid = get_active_id(doc) if aid: for p in items: if p["id"] == aid: return p # Fallback: erstes Preset (oder None wenn leer) return items[0] if items else None def save_preset(doc, preset): """Speichert/aktualisiert ein Preset. Wenn `id` im preset existiert und in der Liste ist → Update, sonst Append. Returns die finale ID.""" if doc is None: return None items = list_presets(doc) norm = _normalize(preset) pid = preset.get("id") if isinstance(preset, dict) else None if pid: replaced = False for i, p in enumerate(items): if p["id"] == pid: norm["id"] = pid items[i] = norm replaced = True break if not replaced: items.append(norm) else: items.append(norm) _save_all(doc, items) return norm["id"] def delete_preset(doc, preset_id): if doc is None or not preset_id: return items = [p for p in list_presets(doc) if p["id"] != preset_id] _save_all(doc, items) # Wenn aktives Preset geloescht: auf erstes uebriges umschalten if get_active_id(doc) == preset_id: set_active_id(doc, items[0]["id"] if items else "") # --------------------------------------------------------------------------- # Convenience: Defaults fuer Module die das Preset einlesen def raum_rundung_default(doc): """Default-Rundung fuer Raum-Stempel wenn keine per-Raum-Override gesetzt ist.""" p = get_active(doc) return p["raumRundung"] if p else "0.1" def dim_dezimalstellen_default(doc): p = get_active(doc) return p["dimDezimalstellen"] if p else 2 def dim_einheit_default(doc): p = get_active(doc) return p["dimEinheit"] if p else "m" # --------------------------------------------------------------------------- # Cross-Module: Raum-Stempel beim Preset-Wechsel mit-aktualisieren. def regen_all_rooms(doc): """Queued ein Regen fuer ALLE raum_outline-Objekte. Aufruf bei Preset- Wechsel/Save/Delete damit Stempel-Flaechen in der neuen Rundung neu rendern.""" if doc is None: return try: import elemente except Exception as ex: print("[MASS_STYLE] elemente import:", ex); return for obj in doc.Objects: try: m = elemente._read_meta(obj) if m and m.get("type") == "raum_outline": elemente._queue_regen(m["id"]) except Exception: pass