"Great customer service. The folks at Novedge were super helpful in navigating a somewhat complicated order including software upgrades and serial numbers in various stages of inactivity. They were friendly and helpful throughout the process.."
Ruben Ruckmark
"Quick & very helpful. We have been using Novedge for years and are very happy with their quick service when we need to make a purchase and excellent support resolving any issues."
Will Woodson
"Scott is the best. He reminds me about subscriptions dates, guides me in the correct direction for updates. He always responds promptly to me. He is literally the reason I continue to work with Novedge and will do so in the future."
Edward Mchugh
"Calvin Lok is “the man”. After my purchase of Sketchup 2021, he called me and provided step-by-step instructions to ease me through difficulties I was having with the setup of my new software."
Mike Borzage
December 03, 2025 2 min read

Turn Grasshopper scripts into reusable, shareable tools with GhPython.
# GhPython template: robust, cache-aware, tree-friendly
import Rhino
import scriptcontext as sc
import ghpythonlib.treehelpers as th
from Grasshopper import Kernel as ghk
def compute(crvs, dist):
tol = Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance
valid = [c for c in crvs if c and c.IsValid]
if not valid:
ghenv.Component.AddRuntimeMessage(
ghk.GH_RuntimeMessageLevel.Error, "No valid curves supplied."
)
return []
results = []
for c in valid:
# Simple example: planar offset (if planar)
ok, plane = c.TryGetPlane()
if not ok:
ghenv.Component.AddRuntimeMessage(
ghk.GH_RuntimeMessageLevel.Warning, "Non-planar curve skipped."
)
continue
offs = c.Offset(plane, dist, tol, Rhino.Geometry.CurveOffsetCornerStyle.Sharp)
if offs: results.extend(offs)
return results
# Input handling: supports list or tree
crv_list = th.tree_to_list(Curves, purge_empty=True) if hasattr(Curves, "Branches") else Curves
# Simple cache key
key = (len(crv_list), round(Distance, 6))
if sc.sticky.get("ghp_offset_key") == key:
OUT = sc.sticky.get("ghp_offset_val")
else:
OUT = compute(crv_list, Distance)
sc.sticky["ghp_offset_key"] = key
sc.sticky["ghp_offset_val"] = OUT
ghenv.Component.Message = "v1.0 GhPy"
Need Rhino + Grasshopper licenses, plugins, or training? Explore NOVEDGE. For Rhino upgrades and add-ons, check NOVEDGE’s Rhino catalog. Looking for renderers or analysis tools to pair with your components? Browse NOVEDGE’s Grasshopper ecosystem.
You can find all the Rhino products on the NOVEDGE web site at this page.

December 03, 2025 2 min read
Read More
December 03, 2025 2 min read
Read MoreSign up to get the latest on sales, new releases and more …