Wand-Grips + Schnitt-Grips + Referenz-Sublayer pro Bauteil + Print-Auto-Hide

Custom-Grip-Overlays via DisplayConduit + MouseCallback:
- wand_grips.py: dicke klickbare Marker an wand_axis-Endpunkten, auch
  wenn die Referenz-Layer ausgeblendet ist. GetPoint mit fixem Anker.
- schnitt_grips.py: 3 Marker pro Schnitt (P1, P2, Mid). Mid translatiert
  ganze Linie, P1/P2 verschieben Endpunkt. Hide Clipping-Planes waehrend
  GetPoint damit kein Verbots-Cursor durch Locked-Edges erscheint.
  skip_view=True bei Re-Activate damit Drag nicht in Section springt.

Referenz-Architektur umgebaut:
- wand_axis + oeffnung_point liegen jetzt unter <Geschoss>::20_Waende::
  20r_Referenz statt eigener top-level 19_Referenzlinien-Ebene.
- Migration v4 zieht existierende Sources auf den neuen Pfad.
- Toggle in Oberleiste keyword-driven: findet alle 'Referenz'-Sub-Ebenen
  rekursiv, toggelt alle Praefixe gemeinsam. Bauteil-uebergreifend.

Oberleiste-Layout:
- Druck-Ansicht-Button hoch neben Massstab-Dropdown (Reihe 1).
- Referenzlinien-Toggle in Reihe 2 neben Zoom-Pill, symmetrisch zum
  Druck-Button. Zoom-Pill auf 3 Buttons reduziert.
- Print-View AN → Referenz-Layer automatisch ausblenden, Snapshot
  restored beim Ausschalten.

Fix: clear_schnitt_clipping respektiert Mode=Locked nicht — vor Delete
auf Normal-Mode wechseln + Modify damit's persistiert. Schnitt-Loeschen
raeumt Clipping-Planes jetzt sauber auf.

Fix: Schnitt-Doppelklick-Handler aktiviert nur bei expliziter Schnitt-
Auswahl, ignoriert andere Selektionen.

Fix: _send_state Selection-Detection mit Source-ODER-Volume-Fallback —
Fenster-Properties erscheinen jetzt auch wenn oeffnung_point auf hidden
Referenz-Layer liegt.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-05-23 20:58:06 +02:00
parent 059cbf8d4d
commit 736325fba1
7 changed files with 1149 additions and 109 deletions
+51 -34
View File
@@ -109,12 +109,21 @@ def find_schnitt_clip_objects(doc):
def clear_schnitt_clipping(doc):
"""Loescht alle Schnitt-Clipping-Planes. Wird beim Wechsel weg vom
Schnitt-Modus aufgerufen (auf Geschoss oder anderen Schnitt)."""
Schnitt-Modus aufgerufen (auf Geschoss oder anderen Schnitt).
Wichtig: die Planes sind Mode=Locked (User soll sie nicht greifen).
doc.Objects.Delete() respektiert das Lock-Flag und schlaegt still
fehl. Deshalb erst auf Normal-Mode wechseln, dann loeschen."""
n = 0
for obj in find_schnitt_clip_objects(doc):
try:
doc.Objects.Delete(obj.Id, True)
n += 1
try:
attrs = obj.Attributes.Duplicate()
attrs.Mode = Rhino.DocObjects.ObjectMode.Normal
doc.Objects.ModifyAttributes(obj, attrs, True)
except Exception: pass
if doc.Objects.Delete(obj.Id, True):
n += 1
except Exception as ex:
print("[SCHNITT] clear: {}".format(ex))
if n:
@@ -144,7 +153,7 @@ def _add_clipping_plane(doc, plane, du, dv, vp_ids, role):
return None
def activate_schnitt(doc, z):
def activate_schnitt(doc, z, skip_view=False):
"""Hauptfunktion: setzt Clipping-Planes + View fuer einen Schnitt-
oder Ansicht-Eintrag.
@@ -160,6 +169,12 @@ def activate_schnitt(doc, z):
View-Logik: Parallel-Projektion, Kamera bei mid - view_dir * dist,
target bei mid. Zoom auf bbox.
skip_view=True: nur Clipping-Planes neu aufbauen, View komplett in
Ruhe lassen. Nutzt der Grip-Drag-Pfad — User editiert die linePts
im Plan, will NICHT dass die View ploetzlich in die Section springt
und re-zoomt. Bei Doppelklick / Panel-Klick bleibt skip_view=False
fuer den vollen Aktivierungs-Effekt.
"""
if z is None: return
pts = z.get("linePts") or []
@@ -232,36 +247,38 @@ def activate_schnitt(doc, z):
obj = _add_clipping_plane(doc, back_plane, du, dv, vp_ids, "back")
if obj is not None: n_planes += 1
# View setzen: Parallel-Projektion, Kamera senkrecht zur Linie
try:
view = doc.Views.ActiveView
if view is None:
for v in doc.Views: view = v; break
if view is not None:
vp = view.ActiveViewport
cam_dist = max(50.0, depth_back * 3 + line_len)
cam_pos = rg.Point3d(
mid.X - view_dir.X * cam_dist,
mid.Y - view_dir.Y * cam_dist,
plane_z)
target = rg.Point3d(
mid.X + view_dir.X * (depth_back * 0.5),
mid.Y + view_dir.Y * (depth_back * 0.5),
plane_z)
vp.ChangeToParallelProjection(True)
vp.SetCameraLocations(target, cam_pos)
vp.CameraUp = rg.Vector3d(0, 0, 1)
# Zoom auf Schnitt-BoundingBox + etwas Rand
bb = rg.BoundingBox(
rg.Point3d(min(p1.X, p2.X) - margin, min(p1.Y, p2.Y) - margin,
h_min - margin),
rg.Point3d(max(p1.X, p2.X) + margin + view_dir.X * depth_back,
max(p1.Y, p2.Y) + margin + view_dir.Y * depth_back,
h_max + margin))
vp.ZoomBoundingBox(bb)
view.Redraw()
except Exception as ex:
print("[SCHNITT] view setup:", ex)
# View setzen: Parallel-Projektion, Kamera senkrecht zur Linie.
# Bei skip_view=True (Grip-Drag-Re-Activate) komplett ueberspringen.
if not skip_view:
try:
view = doc.Views.ActiveView
if view is None:
for v in doc.Views: view = v; break
if view is not None:
vp = view.ActiveViewport
cam_dist = max(50.0, depth_back * 3 + line_len)
cam_pos = rg.Point3d(
mid.X - view_dir.X * cam_dist,
mid.Y - view_dir.Y * cam_dist,
plane_z)
target = rg.Point3d(
mid.X + view_dir.X * (depth_back * 0.5),
mid.Y + view_dir.Y * (depth_back * 0.5),
plane_z)
vp.ChangeToParallelProjection(True)
vp.SetCameraLocations(target, cam_pos)
vp.CameraUp = rg.Vector3d(0, 0, 1)
# Zoom auf Schnitt-BoundingBox + etwas Rand
bb = rg.BoundingBox(
rg.Point3d(min(p1.X, p2.X) - margin, min(p1.Y, p2.Y) - margin,
h_min - margin),
rg.Point3d(max(p1.X, p2.X) + margin + view_dir.X * depth_back,
max(p1.Y, p2.Y) + margin + view_dir.Y * depth_back,
h_max + margin))
vp.ZoomBoundingBox(bb)
view.Redraw()
except Exception as ex:
print("[SCHNITT] view setup:", ex)
kind = "Schnitt" if cut_at_line else "Ansicht"
print("[SCHNITT] {} '{}' aktiviert: {} Plane(s), depthBack={:.1f}m".format(