T-Join 1-Wand-Modus: nur die zu snappende Wand selektieren reicht

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).
This commit is contained in:
2026-05-31 13:44:40 +02:00
parent e50134ce32
commit 9cce8199c3
+55 -6
View File
@@ -124,16 +124,66 @@ def _walls_and_curves_from_sel(doc, sel):
return axes, generic 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): def _t_join_attempt(doc, sel):
"""T-Join: 2 OFFENE Kurven wobei der EINE Endpunkt der einen Kurve """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. Endpunkten). Schiebt diesen Endpunkt exakt auf die andere Kurve.
Die andere Kurve bleibt unveraendert. 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.""" Liefert True wenn ausgefuehrt."""
axes, generic = _walls_and_curves_from_sel(doc, sel) axes, generic = _walls_and_curves_from_sel(doc, sel)
if len(axes) == 2 and len(generic) == 0: if len(axes) == 2 and len(generic) == 0:
o1, o2 = axes[0], axes[1] 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: elif len(axes) == 0 and len(generic) == 2:
o1, o2 = generic[0], generic[1] o1, o2 = generic[0], generic[1]
else: else:
@@ -252,16 +302,15 @@ def _run():
sel = list(doc.Objects.GetSelectedObjects(False, False)) sel = list(doc.Objects.GetSelectedObjects(False, False))
if not sel: if not sel:
Rhino.RhinoApp.RunScript("_Join", False); return 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 n_wand_axes = sum(1 for o in sel
if (o.Attributes.GetUserString("dossier_element_type") if (o.Attributes.GetUserString("dossier_element_type")
or "") == "wand_axis") or "") == "wand_axis")
if n_wand_axes < 2 and any( if n_wand_axes == 0 and any(
(o.Attributes.GetUserString("dossier_element_type") or "") (o.Attributes.GetUserString("dossier_element_type") or "")
.startswith("wand_") for o in sel): .startswith("wand_") for o in sel):
print("[SMART-JOIN] nur {} Wand-Achse(n) selektiert — fuer T/L-Join " print("[SMART-JOIN] keine Wand-Achse in Selection — selektiere die "
"GENAU 2 Waende selektieren (Click Wand + Shift+Click 2. Wand)." "Wand-Linie oder das Wand-Volumen.")
.format(n_wand_axes))
# T-Join: Endpunkt der einen Curve trifft mitten auf die andere → snap. # T-Join: Endpunkt der einen Curve trifft mitten auf die andere → snap.
# L-Join: beide Endpunkte werden zum Schnittpunkt der verlaengerten Linien # L-Join: beide Endpunkte werden zum Schnittpunkt der verlaengerten Linien