From 3609236da9cb4029b24fa42a181877e7fa808dea Mon Sep 17 00:00:00 2001 From: karim Date: Sun, 31 May 2026 11:45:53 +0200 Subject: [PATCH] =?UTF-8?q?dJoin:=20T-Join=20Ergaenzung=20=E2=80=94=20Endp?= =?UTF-8?q?unkt=20einer=20Wand=20mitten=20auf=20andere=20snappen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bisher konnte dJoin nur L-Verbindungen herstellen (zwei Endpunkte zum Schnittpunkt der verlaengerten Tangenten ziehen). Neu auch T-Verbindungen: _t_join_attempt: pro Endpunkt-Kombination wird der naechste Punkt auf der ANDEREN Curve gesucht. Wenn distance < 20cm UND nicht nahe deren Endpunkt (= waere L-Sache) → snap diesen Endpunkt exakt auf die Curve. Die andere Curve bleibt unveraendert (= Through-Wand stays). _run: T-Join wird ZUERST probiert (spezifischer), L-Join als Fallback. UX: User selektiert 2 Waende die fast aber nicht ganz verbinden → Cmd+J (dJoin) → System erkennt T- oder L-Konfig und snappt entsprechend. Predictable + intentional, kein auto-snap-Magic mehr. --- rhino/aliases/cmd/smart_join.py | 66 +++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 3 deletions(-) diff --git a/rhino/aliases/cmd/smart_join.py b/rhino/aliases/cmd/smart_join.py index ff5e1b2..8bbcb33 100644 --- a/rhino/aliases/cmd/smart_join.py +++ b/rhino/aliases/cmd/smart_join.py @@ -124,6 +124,58 @@ def _walls_and_curves_from_sel(doc, sel): return axes, generic +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 + Endpunkten). Schiebt diesen Endpunkt exakt auf die andere Kurve. + Die andere Kurve bleibt unveraendert. + + 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) == 0 and len(generic) == 2: + o1, o2 = generic[0], generic[1] + else: + return False + c1 = o1.Geometry; c2 = o2.Geometry + if not (isinstance(c1, rg.Curve) and isinstance(c2, rg.Curve)): + return False + if c1.IsClosed or c2.IsClosed: return False + tol_snap = 0.20 # 20 cm Snap-Radius fuer T-Verbindung + end_tol = 0.05 # 5cm: wenn closest-point nahe Endpunkt → eigentlich L + candidates = [] + # Pro Endpunkt der einen Kurve: ClosestPoint auf der ANDEREN Kurve + for (a_obj, ac, b_obj, bc) in ((o1, c1, o2, c2), (o2, c2, o1, c1)): + for end in (0, 1): + ep = ac.PointAtStart if end == 0 else ac.PointAtEnd + try: + rc, t = bc.ClosestPoint(ep) + if not rc: continue + cp = bc.PointAt(t) + d = cp.DistanceTo(ep) + # Skip wenn schon snapped oder zu weit + if d < 1e-6 or d > tol_snap: continue + # Skip wenn cp nahe einem Endpunkt von bc — das ist L-Join Territory + ps = bc.PointAtStart; pe = bc.PointAtEnd + if cp.DistanceTo(ps) < end_tol or cp.DistanceTo(pe) < end_tol: + continue + candidates.append((d, a_obj, ac, end, cp)) + except Exception: continue + if not candidates: return False + # Naechster Endpunkt → der wird gesnappt + candidates.sort(key=lambda x: x[0]) + _d, a_obj, ac, end, cp = candidates[0] + new_c = _replace_curve_endpoint(ac, end, cp) + if new_c is None: return False + ur = doc.BeginUndoRecord("DOSSIER T-Join") + try: + ok = doc.Objects.Replace(a_obj.Id, new_c) + return bool(ok) + finally: + doc.EndUndoRecord(ur) + + def _l_join_attempt(doc, sel): """Wenn genau 2 OFFENE Kurven (Wand-Achsen oder generische Lines) selektiert sind, deren End-Tangenten sich in einem Punkt schneiden → @@ -187,9 +239,17 @@ def _run(): if not sel: Rhino.RhinoApp.RunScript("_Join", False); return - # L-Join: genau 2 offene Kurven die sich (verlaengert) treffen wuerden. - # Walls werden via ihrer Achse automatisch regenert (Replace-Listener). - if len(sel) == 2: + # T-Join: Endpunkt der einen Curve trifft mitten auf die andere → snap. + # L-Join: beide Endpunkte werden zum Schnittpunkt der verlaengerten Linien + # gezogen. T zuerst probieren (= spezifischer), dann L als Fallback. + if len(sel) >= 2: + try: + if _t_join_attempt(doc, sel): + doc.Views.Redraw() + print("[SMART-JOIN] T-Join: Endpunkt auf Achse gesnappt") + return + except Exception as ex: + print("[SMART-JOIN] T-Join error:", ex) try: if _l_join_attempt(doc, sel): doc.Views.Redraw()