Wählen, nicht tippen: Eine Rhino-8-Schleife nummeriert deine Säulen alle 6 m
Teil 2 der PAZ-Serie: Gitterachse wählen, alle 6 m mit rhinoscriptsyntax teilen, nummerierte Säulenmarker platzieren.
Teil 1 dieser Serie, Zehn Minuten in Rhino 8’s ScriptEditor: Dein erstes Python Point, Line und Circle, endete mit einem Kompromiss: hardcodierte Koordinaten bewegen sich nicht, wenn sich der Entwurf bewegt. Der nächste Schritt ist, Eingaben aus dem Modell zu lesen, anstatt sie zu tippen. Das Script aus Teil 1 schleift bereits fünf konzentrische Kreise mit for i in range(1, 6). Teil 2 beginnt mit diesen zwei Lektionen. Du zeichnest eine Gitterachse, führst place_columns.py aus, klickst auf die Achse, und das Script teilt sie alle 6 m. An jedem Punkt platziert es eine flache 0,2-m-Säulenmarkierung und einen nummerierten Punkt (C1, C2 …), ordnet alles in seine eigene Schicht ein und gibt eine Zusammenfassung aus.
Die Engine ist rhinoscriptsyntax, die anfängerfreundliche Python-Schicht über RhinoCommon. McNeel verwaltet sie offen auf github.com/mcneel/rhinoscriptsyntax, und sie entstand aus Steve Baers RhinoPython-Arbeit. Das ist wichtig für dieses Tutorial: Wenn die API-Referenz schweigt, kannst du die Quelle lesen. Das machen wir zweimal unten.
Das Werkzeug: Rhino 8’s ScriptEditor mit CPython 3 und rhinoscriptsyntax, erstellt und gepflegt von Robert McNeel & Associates. Es lohnt sich einen Nachmittag, weil jede Funktion eine lesbare Zeile ist, die Quelle öffentlich ist, und die .py-Datei, die du heute speicherst, ist einfacher Text. Jemand, der sie 2070 öffnet, braucht nur einen Text-Editor, keinen Lizenzserver.
Vorbereitung:
# 1. In Rhino 8 (Meter-Vorlage), zeichne eine 30-m-Linie: _Line 0,0,0 30,0,0
# 2. Gib ScriptEditor ein → Neu → Python 3
# 3. Füge ein und drücke F5:
#! python 3
import rhinoscriptsyntax as rs
print(rs.UnitSystemName(abbreviate=True)) # erwartet: mErste Schritte:
- Wählen und respektiere Esc. Laut der RhinoScriptSyntax-API-Referenz gibt
rs.GetObject„None: if user did not pick an object” zurück. McNeels rhino-8.x-Quelle zeigt, dass auch das Drücken von Esc oder Enter ohne AuswahlNonegibt. Teste also mitif crv is None:vor allem anderen.rs.filter.curve(Wert 4) bedeutet, dass nur Kurven angeklickt werden können. Die Werte leben inclass filterin McNeels selection.py (point = 1, curve = 4, surface = 8, polysurface = 16, textdot = 8192), und sie addieren sich:rs.filter.curve | rs.filter.surface(12) akzeptiert beide, genau wie das Beispiel der Referenz selbst. - Teile und zähle.
rs.DivideCurveLength(crv, spacing)„teilt ein Kurvenobjekt in Segmente einer bestimmten Länge ein”, in den Worten der Referenz. Sie gibt eine Liste von Punkten zurück und fügt mit den Standardwerten (create_points=False) nichts zum Modell hinzu. Giblen(pts)aus. Die Teilungen beginnen am Startpunkt der Kurve, daher folgt die Nummerierung der Kurvenrichtung. Wenn C1 am falschen Ende landet, führeDiroderFlipauf der Achse aus. - Schleife mit enumerate.
for i, pt in enumerate(pts, 1):gibt dir die Nummer und den Punkt zusammen. Das ist der Schritt nach vorne von Teil 1’srange().
Jetzt die drei Fallstricke, die ein Demo von einem Büro-Script unterscheiden.
Einheiten. Jede rhinoscriptsyntax-Zahl ist in Modelleinheiten, also 6 m ist 6 in einer Meter-Vorlage und 6000 in einer Millimeter-Vorlage. rs.UnitSystem() gibt einen Code aus der Referenztabelle zurück: 2 für Millimeter (1,0e-3 Meter), 3 für Zentimeter, 4 für Meter. Die UnitScale-Seite’s eigenes Beispiel, rs.UnitScale(3, 4), gibt 100,0 zurück, Meter zu Zentimeter. Eine Zeile handhabt den Rest: m = rs.UnitScale(rs.UnitSystem(), 4) gibt Modelleinheiten pro Meter (1,0, 100,0 oder 1000,0). Danach funktioniert 6.0 * m in jeder Vorlage.
Die Endsäule. Die RhinoCommon-Dokumente für Curve.DivideByLength sagen, dass die Segmentlänge auf „jedes einzelne Segment (ausser möglicherweise das letzte)” angewendet wird und nur den Startpunkt garantieren. Ob der Endpunkt bei einem genauen Vielfachen zurückgegeben wird, ist nicht dokumentiert. Benutzer in einem 2025-McNeel-Forum-Thread berichteten, dass Grasshopper’s Divide Length 10 Punkte auf einer 100 mm / 10 Linie in Rhino 7 und 11 in Rhino 8 gab. Das Script rät nicht. Es vergleicht den letzten Punkt mit rs.CurveEndPoint(crv) und fügt das Ende an, wenn die Lücke grösser ist als rs.UnitAbsoluteTolerance(). Der Kompromiss: Auf einer 32-m-Achse bekommst du eine Säule am Ende und ein 2-m-Restfeld, was für eine Gitterachse korrekt ist und für einen Säulenrhythmus falsch. Wenn du stattdessen gleiche Felder möchtest, verwende rs.DivideCurve(crv, n).
Flache Kreise. Übergib einen Point3d an rs.AddCircle und der Kreis landet auf der Konstruktionsebene des aktiven Viewports. Führe das Script mit Front aktiv aus und deine Säulen stehen wie Münzen auf ihrer Kante. (Jedes Büro findet das am Freitag heraus.) Baue die Ebene selbst mit rs.PlaneFromNormal(pt, (0, 0, 1)) und die Markierungen liegen immer flach im Plan.
Das vollständige Script:
#! python 3
import rhinoscriptsyntax as rs
m = rs.UnitScale(rs.UnitSystem(), 4) # Modelleinheiten pro Meter
spacing = 6.0 * m
radius = 0.2 * m
crv = rs.GetObject("Wähle eine Gitterachse", rs.filter.curve, preselect=True)
if crv is None:
print("Nichts gewählt - keine Säulen platziert.")
else:
pts = rs.DivideCurveLength(crv, spacing)
if not pts:
print("Achse kürzer als der Abstand - nichts platziert.")
else:
end = rs.CurveEndPoint(crv)
if rs.Distance(pts[-1], end) > rs.UnitAbsoluteTolerance():
pts.append(end)
layer = rs.AddLayer("S_Columns", (200, 30, 30))
rs.EnableRedraw(False)
new_ids = []
for i, pt in enumerate(pts, 1):
plane = rs.PlaneFromNormal(pt, (0, 0, 1))
new_ids.append(rs.AddCircle(plane, radius))
new_ids.append(rs.AddTextDot("C{}".format(i), pt))
rs.ObjectLayer(new_ids, layer)
rs.EnableRedraw(True)
print("{} Säulen, {} Felder, Abstand {:.0f} {}".format(
len(pts), len(pts) - 1, spacing,
rs.UnitSystemName(abbreviate=True)))Trockenlauf auf der 30-m-Achse: sechs Säulen, C1 bis C6, fünf Felder, und das Terminal gibt 6 Säulen, 5 Felder, Abstand 6 m aus. Wechsle zu einer Millimeter-Vorlage, zeichne die gleiche Linie als 30000, und das Script verwendet 6000 und 200, ohne dass du etwas änderst. Führe es zweimal aus und du erhältst immer noch eine Schicht: Im rhino-8.x-Source findet AddLayer den bestehenden Namen und gibt ihn zurück. rs.ObjectLayer nimmt die ganze Liste der IDs auf einmal, daher wird die aktuelle Schicht des Benutzers nie berührt. Text-Punkte bleiben auf dem Bildschirm in jeder Zoomstufe gleich gross, daher passen sie zu Säulen-Tags.
←HEUTE: Ein Klick auf eine 30-m-Achse gibt sechs flache, nummerierte, geschichtete Säulenmarkierungen in jeder Unit-Vorlage. →3012: Gitterlogik lebt als lesbare Regeln neben dem Modell, nicht als Klicks, die niemand merkt. Drehpunkt: Das Wählen von Geometrie anstelle von Koordinaten zu tippen ist das, was eine Zeichnung in eine Regel verwandelt.
Atelier: In einem kleinen Schweizer Studio bewegt sich das Tragwerk in jedem Vorprojekt und jede Bewegung kostet jemandem einen Nachmittag zum Umnummerieren. Ein Script, das die Achse liest, hält die Nummerierung mit dem Entwurf in Schritt, und eine einfache .py-Datei kann wie jeder andere Büro-Standard überprüft werden. Montag-Bewegung: Lege place_columns.py in einen gemeinsamen Büro-Script-Ordner und einige dich auf einen Schicht-Namen (S_Columns oder deinen eigenen), den jedes Projekt verwendet.
Hack: Beschrifte jedes Feld mit ihrer echten Länge, damit ein Restfeld aus einer Achse mit ungerade Länge vor dem Ingenieur zu finden ist. Füge diese Zeilen nach der Hauptschleife hinzu, immer noch innerhalb des else-Blocks:
for a, b in zip(pts, pts[1:]):
mid = (a + b) / 2 # Point3d-Arithmetik
rs.AddTextDot("{:.2f} m".format(rs.Distance(a, b) / m), mid)zip(pts, pts[1:]) paart jede Säule mit ihrer Nachbarin. Das Dividieren durch m verwandelt die Entfernung zurück in Meter, daher liest das Label 6,00 m in einer mm-Vorlage auch. Auf einer 32-m-Achse sagt der letzte Punkt 2,00 m, und niemand argumentiert mit einem Punkt.
PAZ arbeitet an diesem Faden mit Büros. Wie unsere PAZ-Rhino-Ankündigung es sagte, ist der Ausgangspunkt die Rhino-Aufgabe, die dein Büro jede Woche wiederholt. Säulennummerierung ist ein Klassiker. PAZ Academy lehrt diesen Weg vom ersten Script bis Grasshopper 2, und es verkauft auch Rhino 8-Lizenzen.
Lernmaterial:
- McNeel: RhinoScriptSyntax API-Referenz: developer.rhino3d.com/api/RhinoScriptSyntax/
- McNeel: Benutzereingabe in Python (GetObject und Freunde): developer.rhino3d.com/guides/rhinopython/python-user-input/
- McNeel: Schleifen in Python: developer.rhino3d.com/guides/rhinopython/python-looping/
- McNeel: Der ScriptEditor-Befehl: developer.rhino3d.com/guides/scripting/scripting-command/
- McNeel: Python 3 in Rhino 8: developer.rhino3d.com/guides/rhinopython/python-3-in-rhino/
- McNeels rhinoscriptsyntax-Quelle (Branch rhino-8.x), der Ort, um Verhalten zu überprüfen, das die Dokumente aussparen: github.com/mcneel/rhinoscriptsyntax
- PAZ-Kontext, bringt deine wiederholte Rhino-Aufgabe zur Gruppe: PAZ-Rhino on 6 October
- Persönliche Anmerkung: öffne
selection.pyin jenem Repo, findeclass filter, und du hast jeden Pick-Filter-Wert auf einem Bildschirm.
Zeichne heute eine Achse, führe das Script aus, klicke dann die Achse und führe es erneut aus. Beobachte, wie C1 die Enden wechselt.
PAZ Kaffi · interdisziplinäre Redaktionsarbeit, geleitet von der PAZ Academy