Automatically Colour Rhino Curves by Degree

Automatically Colour Rhino Curves by Degree
Quick look Lines become black, arcs blue, cubic curves red… all without pressing a button. This guide shows you how to drop a tiny Python script into Rhino so every new curve auto‑colours itself based on its degree (1–11).
Why bother?
- Instant visual feedback – spot stray lines or high‑degree NURBS at a glance.
- Fewer manual steps – no more Select → Run Script → … every time you draw.
- Custom palette – tweak colours to match your studio standard or print style.
Prerequisites
You needVersionRhino for WindowsormacOS6,7 or8 (tested)Basic familiarity with running a RhinoPython script–
Note for Mac users: Rhino 8 ships with CPython 3.x. The script below works in both IronPython 2.7 (Win/macOS ≤7) and CPython 3.x (Rhino 8) with no edits.
Step 1 — Copy the script
Open Rhino. In the command bar write EditPythonScript and paste in the code block below. Save the file as AutoCurveColours.py and
press
Play
.
The only part you’ll ever edit is the colour palette at the top.
# -*- coding: utf-8 -*-
# -----------------------------------------------------------------------------
# Auto Curve‑Colourer for Rhino 6/7/8 (toggle + revert)
# -----------------------------------------------------------------------------
# • Colours EVERY curve (existing + newly‑created) by its degree (1‑11).
# • One alias = ON / OFF. When OFF, all curves return to their original colour.
# • Works in IronPython 2.7 (Rhino ≤7) and CPython 3.x (Rhino 8).
# -----------------------------------------------------------------------------
# Part of the Rhino Masterclass at Cademy.xyz – 2025
# -----------------------------------------------------------------------------
import Rhino
import scriptcontext as sc
import System.Drawing as sd
# ────────────────────────────────────────────────────────────
# USER PALETTE – edit the swatches to your preference
# ────────────────────────────────────────────────────────────
COLOR_MAP = {
1: sd.Color.Black, # lines (deg‑1)
2: sd.Color.Blue, # arcs (deg‑2)
3: sd.Color.Red, # cubic NURBS (deg‑3)
4: sd.Color.Orange,
5: sd.Color.LimeGreen,
6: sd.Color.Turquoise,
7: sd.Color.Cyan,
8: sd.Color.RoyalBlue,
9: sd.Color.Indigo,
10: sd.Color.Violet,
11: sd.Color.Brown,
}
DEFAULT_COLOR = sd.Color.LightGray # degree > 11
# ────────────────────────────────────────────────────────────
# ---------------------------------------------------------------------------
# INTERNAL KEY NAMES (all stored in scriptcontext.sticky)
# ---------------------------------------------------------------------------
_handlers_key = "cademy_curve_colour_handlers" # {doc_id: handler}
_enabled_key = "cademy_curve_colour_enabled" # {doc_id: bool}
_state_key = "cademy_curve_colour_state" # {doc_id: {guid: (src,col)}}
# ---------------------------------------------------------------------------
# ===========================================================================
# CORE COLOUR + RESTORE FUNCTIONS
# ===========================================================================
def _colour_curve(rh_obj):
"""Apply the degree‑based colour to a single curve object."""
geo = rh_obj.Geometry
if not isinstance(geo, Rhino.Geometry.Curve):
return False
deg = geo.Degree
col = COLOR_MAP.get(deg, DEFAULT_COLOR)
attr = rh_obj.Attributes
attr.ColorSource = Rhino.DocObjects.ObjectColorSource.ColorFromObject
attr.ObjectColor = col
rh_obj.CommitChanges()
return True
def _record_and_colour_all(doc, state_dict):
"""Store current colours for *every* curve then recolour them."""
for rh_obj in doc.Objects:
geo = rh_obj.Geometry
if not isinstance(geo, Rhino.Geometry.Curve):
continue
attr = rh_obj.Attributes
# Save original colour once (idempotent)
state_dict[rh_obj.Id] = (attr.ColorSource, attr.ObjectColor)
_colour_curve(rh_obj)
def _restore_all(doc, state_dict):
"""Revert curves to their saved colour source & colour."""
for guid, (src, col) in state_dict.items():
rh_obj = doc.Objects.FindId(guid)
if not rh_obj: # object was deleted
continue
attr = rh_obj.Attributes
attr.ColorSource = src
attr.ObjectColor = col
rh_obj.CommitChanges()
# ===========================================================================
# MAIN TOGGLE (alias runs this file once to flip state per document)
# ===========================================================================
def toggle_auto_colour():
"""Enable or disable auto‑colouring for the ACTIVE Rhino document."""
doc = Rhino.RhinoDoc.ActiveDoc
doc_id = doc.RuntimeSerialNumber
# Retrieve or create our three per‑session dictionaries.
handlers = sc.sticky.get(_handlers_key, {})
enabled = sc.sticky.get(_enabled_key, {})
all_state = sc.sticky.get(_state_key, {}) # {doc_id: state_dict}
state = all_state.get(doc_id, {}) # per‑doc colour cache
# -------- DISABLE ------------------------------------------------------
if enabled.get(doc_id, False):
enabled[doc_id] = False
_restore_all(doc, state)
print("Auto curve‑colouring DISABLED – Cademy.xyz")
sc.sticky[_enabled_key] = enabled
sc.sticky[_state_key] = all_state
return
# -------- ENABLE -------------------------------------------------------
# 1. Create handler once per document, if not already present
if doc_id not in handlers:
def _handler(sender, e, this_doc_id=doc_id):
if not sc.sticky.get(_enabled_key, {}).get(this_doc_id, False):
return # feature is OFF
# Save original colour if we never saw this curve before
state_dict = sc.sticky.get(_state_key, {}).get(this_doc_id, {})
rh_obj = e.TheObject
if rh_obj and rh_obj.Id not in state_dict:
attr = rh_obj.Attributes
state_dict[rh_obj.Id] = (attr.ColorSource, attr.ObjectColor)
sc.sticky[_state_key][this_doc_id] = state_dict
_colour_curve(rh_obj)
doc.AddRhinoObject += _handler
handlers[doc_id] = _handler
sc.sticky[_handlers_key] = handlers
# 2. Mark as enabled
enabled[doc_id] = True
sc.sticky[_enabled_key] = enabled
# 3. Colour every existing curve & cache originals
if doc_id not in all_state:
all_state[doc_id] = {}
_record_and_colour_all(doc, all_state[doc_id])
sc.sticky[_state_key] = all_state
print("🟢 Auto curve‑colouring ENABLED — Cademy.xyz (run again to disable)")
# ---------------------------------------------------------------------------
if __name__ == "__main__":
toggle_auto_colour()
Re-Run the script to disable
We tag the handler with the document’s runtime serial number. When you open a second Rhino file, it gets its own independent watcher. And because we keep the exact same function instance in sc.sticky
, removing it with -=
always succeeds—even after the script has been re‑run.
How the magic works
on_add_object
is registered toRhinoDoc.AddRhinoObject
— Rhino calls it for every new object.- The handler filters out anything that isn’t a curve.
- For curves, it looks up the degree in
COLOR_MAP
and switches the object’s colour source to By Object. - The sticky dictionary (
sc.sticky
) remembers the handler between runs so the same script acts as both ON and OFF toggle.
Step 2 — Add a Rhino alias (one‑click toggle)
- Rhino > Options > Aliases (Preferences > Aliases on macOS)
- Click New, give it a short name like
AutoColours
. - Command field:
_-RunPythonScript "AutoCurveColours.py"
- OK. Done!
Now type AutoColours
in the command line once to turn the watcher on. Type it again to turn it off.
Step 3 — Test drive
- Enable the alias.
- Draw a Line → should turn black instantly.
- Draw an Arc → blue.
- Draw a free Curve (default degree 3) → red.
(Sketch a few higher‑degree curves with the ChangeDegree command if you want to see the rest of the rainbow.)
Don’t miss out, enroll today.
