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
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