From 9cce8199c3c37a29a9d431ea571462f9afeac074 Mon Sep 17 00:00:00 2001 From: karim Date: Sun, 31 May 2026 13:44:40 +0200 Subject: [PATCH] T-Join 1-Wand-Modus: nur die zu snappende Wand selektieren reicht MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit UX-Verbesserung: User-Frage "muss ich nur das Element anwaehlen das ich snappen moechte?" — jetzt ja. Wenn nur 1 wand_axis in der Selection ist, sucht T-Join automatisch die naechste andere Wand-Achse im Doc (innerhalb 1m) und snappt die selektierte Wand auf jene. Die andere bleibt unangetastet — wie bei klassischem T-Stem gegen Through-Wand. 2-Wand-Modus bleibt: dann werden GENAU die beiden selektierten betrachtet (z.B. wenn 3+ Waende in der Nähe sind und User exakt eine andere meinen will). Selection-Hint vereinfacht: nur noch warnen wenn 0 Wand-Achsen aber wand- Objekte vorhanden (z.B. nur Volumen selektiert, wo Axis nicht mitkam). --- rhino/aliases/cmd/smart_join.py | 61 +++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 6 deletions(-) diff --git a/rhino/aliases/cmd/smart_join.py b/rhino/aliases/cmd/smart_join.py index d1b8ed0..0f5b027 100644 --- a/rhino/aliases/cmd/smart_join.py +++ b/rhino/aliases/cmd/smart_join.py @@ -124,16 +124,66 @@ def _walls_and_curves_from_sel(doc, sel): return axes, generic +def _find_nearest_other_wand_axis(doc, my_axis_obj, my_id, tol=1.0): + """Findet die naechste andere wand_axis im Doc (innerhalb tol). + Return das axis Object oder None.""" + if my_axis_obj is None: return None + g = my_axis_obj.Geometry + if not isinstance(g, rg.Curve): return None + bb = g.GetBoundingBox(True) + if not bb.IsValid: return None + best = None; best_d = tol + for obj in doc.Objects: + try: + if obj.Attributes.GetUserString("dossier_element_type") != "wand_axis": + continue + wid = obj.Attributes.GetUserString("dossier_element_id") or "" + if wid == my_id or not wid: continue + except Exception: continue + og = obj.Geometry + if not isinstance(og, rg.Curve): continue + try: + # Mindest-Distanz: Endpunkte gegeneinander UND ClosestPoint + d_min = float('inf') + for ep in (g.PointAtStart, g.PointAtEnd): + rc, t = og.ClosestPoint(ep) + if rc: + d = og.PointAt(t).DistanceTo(ep) + if d < d_min: d_min = d + for ep in (og.PointAtStart, og.PointAtEnd): + rc, t = g.ClosestPoint(ep) + if rc: + d = g.PointAt(t).DistanceTo(ep) + if d < d_min: d_min = d + if d_min < best_d: + best_d = d_min; best = obj + except Exception: continue + return best + + def _t_join_attempt(doc, sel): """T-Join: 2 OFFENE Kurven wobei der EINE Endpunkt der einen Kurve - nahe (< 20cm) auf der ANDEREN Kurve mitten landet (zwischen deren + nahe (< 1m) auf der ANDEREN Kurve mitten landet (zwischen deren Endpunkten). Schiebt diesen Endpunkt exakt auf die andere Kurve. Die andere Kurve bleibt unveraendert. + Auch 1-Wand-Modus: wenn nur 1 wand_axis selektiert, sucht automatisch + die naechste andere Wand und snappt diese eine. + Liefert True wenn ausgefuehrt.""" axes, generic = _walls_and_curves_from_sel(doc, sel) if len(axes) == 2 and len(generic) == 0: o1, o2 = axes[0], axes[1] + elif len(axes) == 1 and len(generic) == 0: + # 1-Wand-Modus: finde naechste andere wand_axis im Doc + my_id = axes[0].Attributes.GetUserString("dossier_element_id") or "" + other = _find_nearest_other_wand_axis(doc, axes[0], my_id, tol=1.0) + if other is None: + print("[SMART-JOIN] 1-Wand T-Join: keine Nachbar-Wand " + "innerhalb 1m gefunden") + return False + o1 = axes[0]; o2 = other + print("[SMART-JOIN] 1-Wand T-Join: snappe an Nachbar-Wand") elif len(axes) == 0 and len(generic) == 2: o1, o2 = generic[0], generic[1] else: @@ -252,16 +302,15 @@ def _run(): sel = list(doc.Objects.GetSelectedObjects(False, False)) if not sel: Rhino.RhinoApp.RunScript("_Join", False); return - # Hint wenn zu wenig Wand-Objekte selektiert + # Info-Hint (T-Join unterstuetzt 1-Wand-Modus, L-Join braucht 2) n_wand_axes = sum(1 for o in sel if (o.Attributes.GetUserString("dossier_element_type") or "") == "wand_axis") - if n_wand_axes < 2 and any( + if n_wand_axes == 0 and any( (o.Attributes.GetUserString("dossier_element_type") or "") .startswith("wand_") for o in sel): - print("[SMART-JOIN] nur {} Wand-Achse(n) selektiert — fuer T/L-Join " - "GENAU 2 Waende selektieren (Click Wand + Shift+Click 2. Wand)." - .format(n_wand_axes)) + print("[SMART-JOIN] keine Wand-Achse in Selection — selektiere die " + "Wand-Linie oder das Wand-Volumen.") # T-Join: Endpunkt der einen Curve trifft mitten auf die andere → snap. # L-Join: beide Endpunkte werden zum Schnittpunkt der verlaengerten Linien