CH NEO-ZÜRICH AUSGABE
WETTER · DUNST 12°C
BLEND DES TAGES · 07/ROGUE
EST. 2027
DIE AEC CYBER MORGENZEITUNG

PAZ Kaffi

DESIGN · ABBRUCH · KOFFEIN · DEPESCHE
AUSGABE 1020 · 20 October 2026
SENDUNG 04:42 MEZ
2'400 BOGEN GEDRUCKT
LESEZEIT · 47 MIN
Wählen, nicht tippen: Eine Rhino-8-Schleife nummeriert deine Säulen alle 6 m
Code
FRAME · 07:00
20-10-2026

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

Erste Schritte:

  1. 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 Auswahl None gibt. Teste also mit if crv is None: vor allem anderen. rs.filter.curve (Wert 4) bedeutet, dass nur Kurven angeklickt werden können. Die Werte leben in class filter in 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.
  2. 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. Gib len(pts) aus. Die Teilungen beginnen am Startpunkt der Kurve, daher folgt die Nummerierung der Kurvenrichtung. Wenn C1 am falschen Ende landet, führe Dir oder Flip auf der Achse aus.
  3. 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’s range().

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:

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.

GEMELDET AUS
MIT-UNTERZEICHNER
PAZ Academy
VERTRAUEN
HIGH
NACHDRUCKE
© PAZ - PARAMETRIC ACADEMY ZURICH · ALLE RECHTE VORBEHALTEN

PAZ Kaffi · interdisziplinäre Redaktionsarbeit, geleitet von der PAZ Academy

⚑ FEHLER MELDEN · KORREKTUR EINSENDEN
◂ ZURÜCK ZUR TITELSEITE · PAZ KAFFI

© 2026 PAZ Academy.