Python for Rhino/Grasshopper · Quick Reference · Save or Print
# Standard — Rhino commands import rhinoscriptsyntax as rs # RhinoCommon geometry kernel import Rhino.Geometry as rg # Grasshopper types import Grasshopper as gh import ghpythonlib.components as ghcomp # Math and system import math import System.Drawing as sd # colors # GHPython template import rhinoscriptsyntax as rs import Rhino.Geometry as rg x = ... # output
# Naming conventions (Rutten/McNeel style) bln_closed = True # bool int_count = 10 # int dbl_length = 3.14 # float str_name = "column_01" # str arr_points = [] # list id_curve = None # guid # Type checking type(x) # → <class 'int'> isinstance(x, float) # → True/False # Type conversion int(3.9) # → 3 float(3) # → 3.0 str(42) # → "42" bool(0) # → False
10 + 3 # 13 Addition 10 - 3 # 7 Subtraction 10 * 3 # 30 Multiplication 10 / 3 # 3.333 Division 10 // 3 # 3 Floor division 10 % 3 # 1 Modulo 10 ** 3 # 1000 Power
x == y x != y x < y x > y x <= y x >= y and or not in is is not
if length > 10: print("Long") elif length > 5: print("Medium") else: print("Short") # Inline (ternary) label = "big" if x > 5 else "small" # None check (important in Rhino!) if obj is not None: rs.DeleteObject(obj) # Compound conditions if x > 0 and y > 0: print("First quadrant")
# range(stop) / range(start, stop, step) for i in range(10): # 0..9 rs.AddPoint([i, 0, 0]) for i in range(0, 20, 2): # 0,2,4..18 rs.AddPoint([i, 0, 0]) # Iterate list for pt in points: rs.AddPoint(pt) # enumerate = index + value for i, pt in enumerate(points): rs.ObjectName(rs.AddPoint(pt), f"pt_{i}") # zip = parallel lists for a, b in zip(list_a, list_b): rs.AddLine(a, b) # break / continue for obj in objects: if rs.CurveLength(obj) > 100: break if rs.CurveLength(obj) < 0.1: continue
# Basic while count = 0 while count < 10: rs.AddPoint([count, 0, 0]) count += 1 # Condition-driven (Rhino example) goal = target_len * 0.5 while rs.CurveLength(crv) > goal: pts = rs.CurvePoints(crv) for i, pt in enumerate(pts): pts[i] = rs.PointAdd(pt, direction) # update curve... # while True + break while True: val = rs.GetNumber("Radius (0 to quit)") if val is None or val == 0: break rs.AddCircle([0,0,0], val)
# Create pts = [] # empty pts = [[0,0,0],[1,1,0]] # with items # Access pts[0] # first item pts[-1] # last item pts[1:4] # slice index 1..3 pts[::2] # every other item # Modify pts.append([5,5,0]) # add to end pts.insert(0, [-1,0,0]) # insert at index pts.remove([0,0,0]) # remove value pts.pop(2) # remove by index pts.sort() # sort in-place pts.reverse() # reverse len(pts) # count # List comprehension zs = [pt[2] for pt in pts] hi = [pt for pt in pts if pt[2] > 5]
# Tuple — immutable t = (1, 2, 3) t[0] # → 1 a, b, c = t # unpack color = (255, 0, 0) # RGB tuple # Dictionary — key:value mat = { "name": "concrete", "density": 2400, "color": (180,180,180) } mat["name"] # → "concrete" mat["E"] = 30e9 # add key "density" in mat # → True mat.get("E", 0) # safe get for k, v in mat.items(): print(f"{k}: {v}")
# Define def make_tower(base_pt, height, count): """Creates stacked circles.""" step = height / count floors = [] for i in range(count): z = base_pt[2] + i * step ctr = [base_pt[0], base_pt[1], z] rad = 5 - i * (5 / count) floors.append(rs.AddCircle(ctr, rad)) return floors # Default arguments def add_grid(rows=5, cols=5, spacing=2.0): pts = [] for r in range(rows): for c in range(cols): pts.append([c*spacing, r*spacing, 0]) return pts # Call grid = add_grid(cols=10)
| Bracket | Use | Example |
|---|---|---|
| ( ) | Call / Math / Tuple | rs.AddLine(p1, p2) |
| [ ] | List / Index / Slice | pts[0] / [x,y,z] |
| { } | Dict / Set | {"key": val} |
| f"{ }" | f-string embed | f"val={x:.2f}" |
# ( ) — function call result = rs.CurveLength(crv_id) # [ ] — list literal + index pt = [0, 0, 0] z = pt[2] # { } — dictionary d = {"a": 1, "b": 2} # f"{ }" — formatted string msg = f"Length = {result:.3f} mm"
import rhinoscriptsyntax as rs # Points rs.AddPoint([x, y, z]) rs.AddPoints(list_of_pts) # Curves rs.AddLine(pt_start, pt_end) rs.AddPolyline(pts) rs.AddCurve(pts, degree=3) rs.AddInterpCurve(pts, degree=3) rs.AddCircle(center, radius) rs.AddArc(plane, radius, degrees) rs.AddEllipse(plane, r_x, r_y) # Surfaces rs.AddSphere(center, radius) rs.AddPlaneSurface(plane, uv, uv) rs.AddLoftSrf([crv1, crv2, ...]) rs.AddNurbsSurface(size, pts, ...) # Mesh rs.AddMesh(vertices, face_indices)
import rhinoscriptsyntax as rs # Curves rs.CurveLength(id) rs.CurveDomain(id) # [t0, t1] rs.CurveStartPoint(id) rs.CurveEndPoint(id) rs.CurveTangent(id, t) rs.EvaluateCurve(id, t) # → point rs.DivideCurve(id, N) # N pts rs.DivideCurveLength(id, d) # by dist # Surfaces rs.SurfaceDomain(id, 0) # U domain rs.EvaluateSurface(id,u,v) # → point rs.SurfaceNormal(id,[u,v]) # → vector rs.SurfaceFrame(id,[u,v]) # → plane rs.SurfaceClosestPoint(id,pt) # → [u,v] # General rs.Distance(pt1, pt2) rs.BrepClosestPoint(id, pt)
import rhinoscriptsyntax as rs a = [1,0,0] b = [0,1,0] rs.VectorAdd(a, b) # [1,1,0] rs.VectorSubtract(a, b) # [1,-1,0] rs.VectorScale(a, 5) # [5,0,0] rs.VectorUnitize(a) # unit vector rs.VectorLength(a) # magnitude rs.VectorCrossProduct(a,b) # [0,0,1] rs.VectorDotProduct(a,b) # 0.0 rs.VectorRotate(a,90,[0,0,1]) # rotate rs.VectorCreate(pt1, pt2) # pt2-pt1 rs.IsVectorParallelTo(a,b) # 1/-1/0 # Point arithmetic rs.PointAdd(pt, vec) rs.PointSubtract(pt, vec)
import rhinoscriptsyntax as rs # Pick objects obj = rs.GetObject("msg", rs.filter.curve) objs = rs.GetObjects("msg", rs.filter.surface) srf, uv, pt = rs.GetSurfaceObject("msg") # Pick point / number / string pt = rs.GetPoint("Pick point") n = rs.GetNumber("Value", 1.0) k = rs.GetInteger("Count", 5) s = rs.GetString("Name") # Dialogs rs.MessageBox("Done!") choice = rs.ListBox(items, "title") color = rs.GetColor() # Filter constants rs.filter.curve # 4 rs.filter.surface # 8 rs.filter.mesh # 32 rs.filter.point # 1
import rhinoscriptsyntax as rs # Name / Layer / Color rs.ObjectName(id, "ColumnA1") rs.ObjectLayer(id, "Structure") rs.ObjectColor(id, (255,0,0)) # RGB # Layers rs.AddLayer("Structure::Beams") # nested rs.LayerColor("Beams", (0,100,255)) # Delete / select rs.DeleteObject(id) rs.DeleteObjects(id_list) rs.SelectObject(id) rs.ObjectsByType(rs.filter.curve) # Type checks rs.IsCurve(id) rs.IsCurveClosed(id) rs.IsBlock(id)
import rhinoscriptsyntax as rs # ✅ Always disable redraw for batch ops rs.EnableRedraw(False) results = [] for i in range(500): results.append(rs.AddPoint([i,0,0])) rs.EnableRedraw(True) rs.ZoomExtents() # ✅ Batch delete rs.DeleteObjects(list_of_ids) # fast # ❌ not: for id in list: rs.DeleteObject(id) # ✅ Tolerance-aware checks tol = rs.UnitAbsoluteTolerance() if length < tol: print("zero-length") # ✅ Always check None returns crv = rs.GetObject("Pick") if crv is None: exit() # user hit Esc
# Standard GHPython header import rhinoscriptsyntax as rs import Rhino.Geometry as rg import System.Drawing as sd # Inputs: x, y (from GH wires) # Outputs: a, b, c (assigned to GH params) # Point grid output pts = [] for i in range(rows): for j in range(cols): pts.append(rg.Point3d(i,j,0)) a = pts # output list # Color by value if length < threshold: col = sd.Color.FromArgb(30,100,255) else: col = sd.Color.FromArgb(255,80,30) b = col # → GH Custom Preview # rg vs rs # rg = geometry objects only (no document) # rs = document commands (adds to Rhino)
| Error | Fix |
|---|---|
| IndentationError | Use 4 spaces, no tabs |
| NameError | Variable not defined yet |
| TypeError: NoneType | Check if obj is None first |
| IndexError | list index out of range → check len() |
| AttributeError | Wrong type, check isinstance() |
| Script too slow | EnableRedraw(False) in loop |
# Safe pattern obj = rs.GetObject("Select") if obj is None: print("Cancelled") else: # safe to use obj here length = rs.CurveLength(obj)
import math math.pi # 3.14159… math.e # 2.71828… math.sqrt(16) # 4.0 math.pow(2, 10) # 1024.0 math.sin(math.pi/2) # 1.0 math.cos(0) # 1.0 math.tan(math.pi/4) # 1.0 math.atan2(y, x) # angle in rad math.degrees(rad) # rad → deg math.radians(deg) # deg → rad math.floor(3.9) # 3 math.ceil(3.1) # 4 math.fabs(-5) # 5.0 (abs) round(3.14159, 2) # 3.14 min(3,1,4) max(3,1,4) # 1, 4
s = " Hello Rhino " s.strip() # "Hello Rhino" s.upper() # " HELLO RHINO " s.lower() # " hello rhino " s.replace("Rhino","GH") s.split(" ") # list of words " | ".join(["a","b"]) # "a | b" s.find("Rhino") # index or -1 s.startswith("H") # True/False s.endswith("o") # True/False s.count("o") # occurrences "42".zfill(5) # "00042"
n = 3.14159 i = 42 f"Value: {n:.2f}" # "Value: 3.14" f"{n:8.2f}" # " 3.14" (width 8) f"{i:04d}" # "0042" f"{i:b}" # "101010" (binary) f"{n:e}" # "3.14e+00" (sci) f"{2**10}" # "1024" (expr) # String slice s = "Rhinoceros" s[:5] # "Rhino" s[-1] # "s" s[::-1] # reversed
try: val = int(user_input) result = 100 / val except ValueError: print("Not a number!") except ZeroDivisionError: result = 0 except Exception as e: print(f"Error: {e}") # catch-all else: print("No errors!") # only if no exception finally: file.close() # always runs # Raise your own raise ValueError("Bad input")
# Write with open("data.txt", "w") as f: f.write("Hello\n") # Read all at once with open("data.txt", "r") as f: text = f.read() # string lines = f.readlines() # list of lines # JSON import json with open("d.json","w") as f: json.dump(data, f, indent=2) with open("d.json","r") as f: data = json.load(f) # Safe load (try/except) try: with open("cfg.txt") as f: cfg = f.read() except FileNotFoundError: cfg = "" # default
# lambda: inline one-liner function sq = lambda x: x**2 # sq(5) → 25 mid = lambda a,b: (a+b)/2 # midpoint # sorted with key curves_by_len = sorted( curves, key=lambda c: rs.CurveLength(c)) longest = max(curves, key=lambda c: rs.CurveLength(c)) # filter — keep matching items long = list(filter( lambda c: rs.CurveLength(c) > 5, curves)) # map — transform all items lengths = list(map(rs.CurveLength, curves)) # Equivalent list comprehensions long = [c for c in curves if rs.CurveLength(c)>5] lengths = [rs.CurveLength(c) for c in curves]
# *args — any number of positional args def add_pts(*points): for pt in points: rs.AddPoint(pt) add_pts([0,0,0], [1,0,0], [2,0,0]) # **kwargs — keyword arguments as dict def tag(obj, **attrs): if "name" in attrs: rs.ObjectName(obj, attrs["name"]) if "color" in attrs: rs.ObjectColor(obj, attrs["color"]) tag(obj, name="Beam_1", color=(255,0,0)) # Unpack list/dict into call coords = [1,2,3] rs.AddPoint(*coords) # splat list tag(obj, **my_dict) # splat dict
# Generator — lazy, memory-efficient def grid_pts(rows, cols, sp): for r in range(rows): for c in range(cols): yield [c*sp, r*sp, 0] for pt in grid_pts(10,10,2): rs.AddPoint(pt) # one at a time # Generator expression ( ) not [ ] total = sum(rs.CurveLength(c) for c in curves) minL = min(rs.CurveLength(c) for c in curves) # any / all any(rs.IsCurveClosed(c) for c in curves) all(rs.IsCurve(c) for c in curves)
import Rhino.Geometry as rg # Points & Vectors p = rg.Point3d(0,0,0) v = rg.Vector3d(1,0,0) rg.Vector3d.XAxis # (1,0,0) rg.Vector3d.CrossProduct(v1,v2) p.DistanceTo(p2) # Plane rg.Plane.WorldXY # standard XY rg.Plane(origin, normal) # NurbsCurve nc = rg.NurbsCurve.CreateFromPoints(pts, 3) nc.GetLength() nc.PointAt(t) nc.TangentAt(t) # Transforms xf = rg.Transform.Translation(5,0,0) xf = rg.Transform.Rotation(angle, axis, pt) pt.Transform(xf) # Brep booleans rg.Brep.CreateBooleanUnion(breps, tol)
# Normalize: map 0→n to 0→1 t = i / (n - 1) # t ∈ [0,1] # Linear interpolation (lerp) val = a + (b - a) * t # between a and b # Remap from [src0,src1] to [dst0,dst1] t = (v - src0) / (src1 - src0) out = dst0 + t * (dst1 - dst0) # Attractor influence (inverse distance) d = rs.Distance(pt, attractor) scale = 1 / (d + 0.001) # avoid /0 # Grid to flat index idx = row * cols + col # Flat index to row/col row = idx // cols col = idx % cols # Polar coordinates x = r * math.cos(angle) y = r * math.sin(angle)