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:
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user