DOSSIER Multi-Phase: C#-Plugin + Yak + Wandstile + UX-Polish
- C#-Plugin "DOSSIER" mit 23 nativen Commands (dWall, dDoor, ..., dSection)
- Native Command-Namen + Autocomplete + saubere History
- Idle-Defer + RhinoCode-API → kein _-RunPythonScript-Echo
- Yak-Paket via build.sh, Install in ~/Library/.../packages/8.0/
- Launcher (Tauri):
- dossier_init Tauri-Command + Setup-Tab in Settings
- Yak-Install + StartupCommands-XML + Window-Layout in einem Schritt
- clean-rhino.sh fuer reproduzierbare Resets
- check_dossier_initialized triggert Auto-Open-Setup beim ersten Start
- Wand-Architektur:
- Chain-Logik DEAKTIVIERT → jede Wand baut eigenes Volume (individuell
anwaehlbar, einzeln loeschbar)
- Polyline-Wand: jedes Segment = eigene Wand
- Smart-Split fuer wand_axis/decke/dach/raum/aussparung/traeger
- Auto-Group axis+volume → kein ChooseOne-Dialog, Delete loescht beides
- Stale-Mitre-Fix: Joint-Cache wird vor jedem Wand-Regen invalidiert
- T-Junction-Tolerance auf 1mm (war 1cm, lieferte falsche T-Mitres)
- Wand-Stile:
- Schema in dossier_project_settings.wand_styles (Material + Prio +
Default-Dicke + Referenz, oder Layered mit Schichten)
- dWall-Command Stil-Picker
- ProjectSettingsDialog: Sidebar-Layout (Pill-Selection) +
Wandstile-Tab mit Liste/Editor
- _wand_chain_compat benutzt style_id
- Prio-Dominanz: hoehere Prio gewinnt Eckverbindung, niedrigere wird
T-mitered (siehe _resolve_corner_miter)
- Cmd+G fuer Group (Geschoss-Up auf Alias 'gu')
- Welcome + Cheatsheet borderless mit X/Back-Buttons
- BeginCommand-Hook fuer Gestaltung-Panel-Auto-Open
- panel_base: Python.NET-Enum-Fix fuer Material-Render
This commit is contained in:
+98
-6
@@ -309,6 +309,47 @@ _PROJECT_SETTINGS_DEFAULTS = {
|
||||
"unit": "meters", # "meters" | "millimeters" | "centimeters"
|
||||
},
|
||||
"materials": [],
|
||||
# Wand-Stile: Wand-Typ-Templates mit Prio fuer Joint-Dominanz.
|
||||
#
|
||||
# SOLID-Style (layered=False):
|
||||
# material = Material-Identitaet (driver fuer Section-Hatch)
|
||||
# dicke = DEFAULT bei Erstellung — User kann pro Wand ueberschreiben
|
||||
# referenz = DEFAULT
|
||||
#
|
||||
# LAYERED-Style (layered=True):
|
||||
# layers = fixe Schicht-Komposition mit Material+Dicke pro Layer
|
||||
# dicke = ignoriert (kommt aus Summe der Layers)
|
||||
#
|
||||
# PRIO (1-999, 999=dominant): zwei Wand-Stile koennen das gleiche Material
|
||||
# haben aber verschiedene Prios (z.B. Beton tragend prio=800,
|
||||
# Beton innen prio=400). Bei Joints zwischen verschiedenen Stilen gewinnt
|
||||
# der mit hoeherer Prio die Ecke (Phase 3, noch nicht implementiert).
|
||||
#
|
||||
# SECTION-MERGE (Phase 2, noch nicht implementiert): Hatches mergen visuell
|
||||
# an Joints zwischen Waenden mit GLEICHEM Material — egal ob gleicher Stil.
|
||||
# So sind „Beton tragend" und „Beton innen" im Schnitt verbunden.
|
||||
"wand_styles": [
|
||||
{"id": "style_beton_tragend", "name": "Beton tragend",
|
||||
"prio": 800, "dicke": 0.25, "referenz": "mid",
|
||||
"layered": False, "material": "Stahlbeton", "layers": []},
|
||||
{"id": "style_beton_innen", "name": "Beton innen",
|
||||
"prio": 400, "dicke": 0.15, "referenz": "mid",
|
||||
"layered": False, "material": "Stahlbeton", "layers": []},
|
||||
{"id": "style_gips", "name": "Gipswand",
|
||||
"prio": 200, "dicke": 0.10, "referenz": "mid",
|
||||
"layered": False, "material": "Putz", "layers": []},
|
||||
{"id": "style_mauerwerk", "name": "Mauerwerk",
|
||||
"prio": 300, "dicke": 0.12, "referenz": "mid",
|
||||
"layered": False, "material": "Mauerwerk", "layers": []},
|
||||
{"id": "style_aussen30", "name": "Aussenwand 30 cm gedaemmt",
|
||||
"prio": 900, "dicke": 0.30, "referenz": "left",
|
||||
"layered": True, "material": "",
|
||||
"layers": [
|
||||
{"material": "Stahlbeton", "dicke": 0.18},
|
||||
{"material": "Daemmung", "dicke": 0.10},
|
||||
{"material": "Putz", "dicke": 0.02},
|
||||
]},
|
||||
],
|
||||
"project": {
|
||||
"name": "",
|
||||
"number": "",
|
||||
@@ -379,6 +420,48 @@ def _normalize_project_meta(p):
|
||||
}
|
||||
|
||||
|
||||
def _normalize_wand_style(s):
|
||||
"""Garantiert Wand-Style-Schema. Stil = Bundle aus Geometrie + Prio.
|
||||
Felder:
|
||||
- id (str, kebab-case empfohlen), name (str)
|
||||
- prio (int 1-999): bei Joints zwischen verschiedenen Stilen wins der hoehere
|
||||
- dicke (float, Meter)
|
||||
- referenz ('mid'|'left'|'right')
|
||||
- layered (bool): wenn True, layers definieren die Schichten
|
||||
- material (str): bei layered=False der Material-Name
|
||||
- layers (list of {material, dicke}): bei layered=True"""
|
||||
if not isinstance(s, dict): return None
|
||||
sid = str(s.get("id") or "").strip()
|
||||
if not sid: return None
|
||||
try: prio = int(s.get("prio", 500))
|
||||
except Exception: prio = 500
|
||||
prio = max(1, min(999, prio))
|
||||
try: dicke = float(s.get("dicke", 0.25))
|
||||
except Exception: dicke = 0.25
|
||||
ref = str(s.get("referenz") or "mid")
|
||||
if ref not in ("mid", "left", "right"): ref = "mid"
|
||||
layered = bool(s.get("layered"))
|
||||
layers = []
|
||||
if layered and isinstance(s.get("layers"), list):
|
||||
for ly in s["layers"]:
|
||||
if not isinstance(ly, dict): continue
|
||||
try: ld = float(ly.get("dicke", 0))
|
||||
except Exception: ld = 0.0
|
||||
if ld <= 0: continue
|
||||
layers.append({"material": str(ly.get("material") or ""),
|
||||
"dicke": ld})
|
||||
return {
|
||||
"id": sid,
|
||||
"name": str(s.get("name") or sid),
|
||||
"prio": prio,
|
||||
"dicke": dicke,
|
||||
"referenz": ref,
|
||||
"layered": layered,
|
||||
"material": str(s.get("material") or ""),
|
||||
"layers": layers,
|
||||
}
|
||||
|
||||
|
||||
def _normalize_material(m):
|
||||
"""Garantiert Material-Schema. Material ist REIN 3D — Section-Hatch
|
||||
(2D-Schnitt) wird via Ebenen-Settings am Layer konfiguriert.
|
||||
@@ -440,9 +523,10 @@ def load_project_settings(doc):
|
||||
try: raw = doc.Strings.GetValue(_PROJECT_SETTINGS_KEY) if doc else None
|
||||
except Exception: raw = None
|
||||
out = {
|
||||
"defaults": dict(_PROJECT_SETTINGS_DEFAULTS["defaults"]),
|
||||
"materials": list(_PROJECT_SETTINGS_DEFAULTS["materials"]),
|
||||
"project": dict(_PROJECT_SETTINGS_DEFAULTS["project"]),
|
||||
"defaults": dict(_PROJECT_SETTINGS_DEFAULTS["defaults"]),
|
||||
"materials": list(_PROJECT_SETTINGS_DEFAULTS["materials"]),
|
||||
"wand_styles": [dict(s) for s in _PROJECT_SETTINGS_DEFAULTS["wand_styles"]],
|
||||
"project": dict(_PROJECT_SETTINGS_DEFAULTS["project"]),
|
||||
}
|
||||
if raw:
|
||||
try:
|
||||
@@ -458,6 +542,12 @@ def load_project_settings(doc):
|
||||
_normalize_material(x) for x in m
|
||||
if _normalize_material(x) is not None
|
||||
]
|
||||
ws = data.get("wand_styles")
|
||||
if isinstance(ws, list):
|
||||
out["wand_styles"] = [
|
||||
_normalize_wand_style(s) for s in ws
|
||||
if _normalize_wand_style(s) is not None
|
||||
]
|
||||
pr = data.get("project")
|
||||
if isinstance(pr, dict):
|
||||
out["project"] = _normalize_project_meta(pr)
|
||||
@@ -976,6 +1066,7 @@ class EbenenBridge(panel_base.BaseBridge):
|
||||
"defaults": current.get("defaults", {}),
|
||||
"project": current.get("project", {}),
|
||||
"materials": current.get("materials", []),
|
||||
"wandStyles": current.get("wand_styles", []),
|
||||
"builtinMaterials": built_in,
|
||||
"hatchPatterns": _hatch_pattern_names(doc),
|
||||
"hatchPatternsFull": _list_hatch_patterns_full(doc),
|
||||
@@ -990,9 +1081,10 @@ class EbenenBridge(panel_base.BaseBridge):
|
||||
doc2 = Rhino.RhinoDoc.ActiveDoc
|
||||
if doc2 is None: return
|
||||
new_settings = {
|
||||
"defaults": updated.get("defaults", {}),
|
||||
"materials": updated.get("materials", []),
|
||||
"project": updated.get("project", {}),
|
||||
"defaults": updated.get("defaults", {}),
|
||||
"materials": updated.get("materials", []),
|
||||
"wand_styles": updated.get("wandStyles", []),
|
||||
"project": updated.get("project", {}),
|
||||
}
|
||||
save_project_settings(doc2, new_settings)
|
||||
_broadcast_state(doc2)
|
||||
|
||||
Reference in New Issue
Block a user