18d6d98e07
- 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
158 lines
5.6 KiB
Python
158 lines
5.6 KiB
Python
#! python3
|
|
# -*- coding: utf-8 -*-
|
|
# Smart-Join: bei geschlossenen Curves → BooleanUnion (innere Linien weg),
|
|
# bei offenen Curves → normales _Join (Endpunkt-Verbindung).
|
|
# Sicherheits-Filter:
|
|
# A) Group by Layer + Object-Overrides (Color/Linetype/PlotWeight) + Fill —
|
|
# nur Curves mit IDENTISCHEN visuellen Attributen werden gemerged.
|
|
# C) Pre-Check Overlap — BooleanUnion liefert genauso viele Outputs wie
|
|
# Inputs wenn nichts overlapt → dann KEINE Aktion, Curves bleiben.
|
|
# Kombinierter Effekt: nur visuell zusammengehoerige UND tatsaechlich
|
|
# ueberlappende Curves werden zu einer Outline vereint.
|
|
import scriptcontext as sc
|
|
import Rhino
|
|
import Rhino.Geometry as rg
|
|
import Rhino.DocObjects as rdoc
|
|
|
|
|
|
def _attr_key(obj):
|
|
"""Tuple das definiert ob 2 Curves visuell identisch sind. Layer +
|
|
Per-Object-Overrides (alles was ByObject nicht ByLayer ist) + Fill-
|
|
State (Hatch-ID + No-Fill-Flag)."""
|
|
a = obj.Attributes
|
|
layer_idx = a.LayerIndex
|
|
|
|
# Color: nur Object-Override unterscheidend, ByLayer ist gleich.
|
|
col_key = ("layer",)
|
|
try:
|
|
if a.ColorSource == rdoc.ObjectColorSource.ColorFromObject:
|
|
col_key = ("obj", a.ObjectColor.ToArgb())
|
|
except Exception: pass
|
|
|
|
# Linetype
|
|
lt_key = ("layer",)
|
|
try:
|
|
if a.LinetypeSource == rdoc.ObjectLinetypeSource.LinetypeFromObject:
|
|
lt_key = ("obj", a.LinetypeIndex)
|
|
except Exception: pass
|
|
|
|
# PlotWeight
|
|
pw_key = ("layer",)
|
|
try:
|
|
if a.PlotWeightSource == rdoc.ObjectPlotWeightSource.PlotWeightFromObject:
|
|
pw_key = ("obj", float(a.PlotWeight))
|
|
except Exception: pass
|
|
|
|
# Fill / Hatch via gestaltung-UserStrings
|
|
fill_hatch = ""
|
|
fill_source = ""
|
|
no_fill = ""
|
|
try:
|
|
fill_hatch = a.GetUserString("ebenen_fill_hatch_id") or ""
|
|
fill_source = a.GetUserString("ebenen_fill_source") or ""
|
|
no_fill = a.GetUserString("ebenen_no_fill") or ""
|
|
except Exception: pass
|
|
# Fuer Gruppierung zaehlt: "hatte Fill ja/nein" + Quelle + No-Fill-Flag.
|
|
fill_key = (bool(fill_hatch), fill_source, no_fill)
|
|
|
|
return (layer_idx, col_key, lt_key, pw_key, fill_key)
|
|
|
|
|
|
def _run():
|
|
doc = Rhino.RhinoDoc.ActiveDoc
|
|
if doc is None: return
|
|
sel = list(doc.Objects.GetSelectedObjects(False, False))
|
|
if not sel:
|
|
Rhino.RhinoApp.RunScript("_Join", False); return
|
|
|
|
# Curves nach Closed/Open trennen
|
|
closed_objs = []
|
|
has_non_closed = False
|
|
for obj in sel:
|
|
g = obj.Geometry
|
|
if isinstance(g, rg.Curve) and g.IsClosed:
|
|
closed_objs.append(obj)
|
|
else:
|
|
has_non_closed = True
|
|
|
|
# Wenn nicht ALLE closed sind → einfach Standard-Join
|
|
if has_non_closed or len(closed_objs) < 2:
|
|
Rhino.RhinoApp.RunScript("_Join", False); return
|
|
|
|
# Gruppieren nach (Layer + Attrs + Fill)
|
|
groups = {} # key → [obj, obj, ...]
|
|
for obj in closed_objs:
|
|
try:
|
|
k = _attr_key(obj)
|
|
except Exception:
|
|
k = ("ungroup", id(obj))
|
|
groups.setdefault(k, []).append(obj)
|
|
|
|
# gestaltung fuer Fill-Re-Apply
|
|
_g = None
|
|
try:
|
|
import gestaltung as _gmod; _g = _gmod
|
|
except Exception as iex:
|
|
print("[SMART-JOIN] gestaltung import:", iex)
|
|
|
|
tol = doc.ModelAbsoluteTolerance
|
|
ur = doc.BeginUndoRecord("DOSSIER Smart-Join (gruppiert)")
|
|
n_merged_total = 0
|
|
n_groups_ops = 0
|
|
try:
|
|
for key, objs in groups.items():
|
|
if len(objs) < 2: continue # einzelne Curve → nichts zu mergen
|
|
try:
|
|
curves = [o.Geometry for o in objs]
|
|
result = rg.Curve.CreateBooleanUnion(curves, tol)
|
|
except Exception as ex:
|
|
print("[SMART-JOIN] BooleanUnion in Gruppe fehlgeschlagen:", ex)
|
|
continue
|
|
if not result: continue
|
|
# C) Pre-Check Overlap: wenn result-Anzahl gleich input-Anzahl
|
|
# ist, gab's keinen tatsaechlichen Overlap → Gruppe nicht
|
|
# anfassen.
|
|
if len(result) >= len(objs):
|
|
continue
|
|
# Tatsaechlich gemerged → replace
|
|
attrs_template = objs[0].Attributes.Duplicate()
|
|
# Fill-Key clearen damit _apply_ebene_fill nicht "schon gefuellt"
|
|
# zurueckgibt
|
|
try:
|
|
attrs_template.SetUserString("ebenen_fill_hatch_id", "")
|
|
except Exception: pass
|
|
|
|
any_had_fill = bool(key[4][0]) # fill_key[0] = had-fill bool
|
|
|
|
new_ids = []
|
|
for crv in result:
|
|
nid = doc.Objects.AddCurve(crv, attrs_template)
|
|
if nid: new_ids.append(nid)
|
|
for o in objs:
|
|
try: doc.Objects.Delete(o.Id, True)
|
|
except Exception: pass
|
|
# Fill nachziehen wenn Inputs welche hatten
|
|
if any_had_fill and _g is not None:
|
|
for nid in new_ids:
|
|
try:
|
|
nobj = doc.Objects.FindId(nid)
|
|
if nobj is not None:
|
|
_g._apply_ebene_fill(doc, nobj)
|
|
except Exception as fex:
|
|
print("[SMART-JOIN] fill-apply:", fex)
|
|
n_merged_total += (len(objs) - len(result))
|
|
n_groups_ops += 1
|
|
finally:
|
|
doc.EndUndoRecord(ur)
|
|
|
|
if n_groups_ops == 0:
|
|
print("[SMART-JOIN] Nichts zu mergen — keine Curves overlappen "
|
|
"(oder verschiedene Attribute/Layer)")
|
|
else:
|
|
doc.Views.Redraw()
|
|
print("[SMART-JOIN] {} Gruppe(n) bearbeitet, {} Curve(s) zu Union vereint"
|
|
.format(n_groups_ops, n_merged_total))
|
|
|
|
|
|
_run()
|