Files
DOSSIER/rhino/curve_vertex_dots.py
T
karim b9a2124026 Rename all log tags to match English module names
[EBENEN] → [LAYERS], [EBENEN-BE] → [LAYERS-BE]
[ZEICHNUNGSEBENEN] → [DRAWING-LEVELS]
[GESTALTUNG] → [STYLES]
[OBERLEISTE] → [TOOLBAR]
[WERKZEUGE] → [TOOLS]
[DIMENSIONEN] → [DIMENSIONS]
[AUSSCHNITTE] → [VIEWPORTS]
[MASSSTAB] → [SCALE]
[SCHNITT] → [SECTION], [SCHNITT_GRIPS] → [SECTION-GRIPS]
[WAND_GRIPS] → [WALL-GRIPS], [TREPPE_GRIPS] → [STAIR-GRIPS]
[CURVE_DOTS] → [CURVE-DOTS]
[panel_base] → [CORE]
[ALIAS-LOADER] → [ALIASES]
[BEGIN-CMD] → [CMD-HOOK]
2026-06-06 12:48:27 +02:00

162 lines
5.8 KiB
Python

#! python3
# -*- coding: utf-8 -*-
# SPDX-License-Identifier: AGPL-3.0-or-later
# Copyright (C) 2026 Karim Gabriele Varano
"""
curve_vertex_dots.py
Display-only Vertex-Dots fuer GENERISCHE Curves (Polylinen, Linien,
Rectangles, NurbsCurves etc). Zeigt gruene Punkte an allen Vertices
selektierter Curves — hilft beim Visuell-Finden von Grip-Positionen
wenn die Curve eine Fuellung (Hatch) hat und schwer per Klick auf
einen einzelnen Vertex zu treffen ist.
Display-only — kein eigener Drag-Handler. User editiert Vertices via
Rhino's native _Grips (Punkte sichtbar machen + Standard-Drag) oder
direktes Object-Snapping waehrend Drag.
Skipt dossier-managed Curves (wand_axis, treppe_axis, schnitt_axis,
wand_outline, wand_centerline, raum_polylinie etc) — die haben ihre
eigenen Conduits oder duerfen nicht via Vertex editiert werden.
"""
import Rhino
import Rhino.Display as rd
import Rhino.Geometry as rg
import scriptcontext as sc
import System.Drawing as SD
# --- Konstanten ------------------------------------------------------------
_MARKER_RADIUS_PX = 6
_MARKER_FILL = SD.Color.FromArgb(200, 95, 168, 150) # accent-gruen
_MARKER_BORDER = SD.Color.FromArgb(255, 47, 93, 84)
# Dossier-managed Element-Types die NICHT mit generic dots versehen werden
# (= haben eigene Conduits oder sind nicht editierbar via Vertex-Click).
_SKIP_TYPES = {
"wand_axis", "wand_centerline", "wand_outline", "wand_volume",
"treppe_axis", "treppe_outline", "treppe_volume",
"schnitt_axis", "schnitt_outline",
"raum_polylinie", "raum_stempel",
"ausschnitt_polylinie",
"decke_polylinie", "decke_volume",
"dach_polylinie", "dach_volume",
}
# --- Helpers --------------------------------------------------------------
def _is_dossier_managed(obj):
"""True wenn obj ein dossier-managed Element ist (= Skip)."""
if obj is None or obj.IsDeleted: return True
try:
t = obj.Attributes.GetUserString("dossier_element_type") or ""
return t in _SKIP_TYPES
except Exception:
return False
def _curve_vertices(curve):
"""Liefert Liste von rg.Point3d fuer alle relevanten Vertices der
Curve. Verschiedene Curve-Types haben verschiedene Vertices:
- LineCurve: 2 Endpunkte
- PolylineCurve: alle Polyline-Punkte (deduplizert wenn closed)
- PolyCurve: rekursiv Segmente
- NurbsCurve/sonst: Start + End (control points nicht — zu viele)"""
pts = []
if curve is None: return pts
try:
if isinstance(curve, rg.PolylineCurve):
ok, pline = curve.TryGetPolyline()
if ok and pline is not None:
n = pline.Count
# Deduplizieren wenn closed (letzter Punkt = erster)
last = n
try:
if (n >= 2
and pline[0].DistanceTo(pline[n - 1]) < 1e-6):
last = n - 1
except Exception: pass
for i in range(last):
pts.append(rg.Point3d(pline[i]))
return pts
if isinstance(curve, rg.LineCurve):
pts.append(curve.PointAtStart)
pts.append(curve.PointAtEnd)
return pts
if isinstance(curve, rg.PolyCurve):
for i in range(curve.SegmentCount):
seg = curve.SegmentCurve(i)
if seg is None: continue
# Nur Start jedes Segments (End ist Start des naechsten)
pts.append(seg.PointAtStart)
# Letztes Segment-End anhaengen
try:
pts.append(curve.PointAtEnd)
except Exception: pass
return pts
# Generic Curve: nur Start + End
try:
pts.append(curve.PointAtStart)
pts.append(curve.PointAtEnd)
except Exception: pass
except Exception:
pass
return pts
# --- Conduit -------------------------------------------------------------
class _VertexDotConduit(rd.DisplayConduit):
"""Zeichnet bei jeder selektierten generischen Curve gruene Punkte
an allen Vertices."""
def DrawForeground(self, e):
try:
doc = Rhino.RhinoDoc.ActiveDoc
if doc is None: return
try:
sel = list(doc.Objects.GetSelectedObjects(False, False))
except Exception: return
seen_curve_ids = set()
for obj in sel:
if _is_dossier_managed(obj): continue
try:
cid = str(obj.Id)
except Exception: continue
if cid in seen_curve_ids: continue
seen_curve_ids.add(cid)
geom = obj.Geometry
if not isinstance(geom, rg.Curve): continue
for pt in _curve_vertices(geom):
try:
e.Display.DrawPoint(
pt, rd.PointStyle.RoundControlPoint,
_MARKER_RADIUS_PX, _MARKER_FILL)
except Exception:
try: e.Display.DrawDot(
pt, "·", _MARKER_FILL, _MARKER_BORDER)
except Exception: pass
except Exception as ex:
print("[CURVE-DOTS] DrawForeground:", ex)
# --- Install -------------------------------------------------------------
_STICKY_CONDUIT = "_dossier_curve_vertex_dots_conduit"
def install_curve_vertex_dots():
"""Idempotent: alten Conduit disable, neuen installieren."""
try:
old = sc.sticky.get(_STICKY_CONDUIT)
if old is not None:
try: old.Enabled = False
except Exception: pass
conduit = _VertexDotConduit()
conduit.Enabled = True
sc.sticky[_STICKY_CONDUIT] = conduit
print("[CURVE-DOTS] Vertex dot conduit active")
except Exception as ex:
print("[CURVE-DOTS] install:", ex)