algorithmic modeling for Rhino

Enticed by an old thread featuring a way to derive the medial axis of closed outlines by Daniel Piker:

I set about understanding his script and after tweaking it, started playing around with raising the medial axis points according to their distance from the outer edge and then played with frustrating data tree dilemmas as to how to get it to loft or patch a surface onto each of these sets of curves and height raised axes independently, but then realized I could just patch the entire bounding box of various objects all at once.

Starting with surfaces with optional holes:

It can make ArtCAM or RhinoEmboss type puffing surfaces, as single trimmed NURBS surfaces:

I used two offset curves out from each edge to help mellow out a patch surface and guide it to be plump but not too steep, with the offset curves set down below the plane too, the outer one more than the first one. I then included the bounding rectangle too to make it much better behaved still, also a bit below the construction plane for a clean cut later to isolate the hills. When I do split it with a ground plane I get objects that can be capped into solids in Rhino.

The main setting are the resolution and stiffness of the patch component.

Zebra is happy enough:

The initial determination of the medial axis is done by creating points along each curve, making a Voronoi diagram within an ample bounding box, then exploding all cells into lines and cleaning up to keep only those fully contained on a surface.

The Voronoi diagram gives the medial axis since the cells refuse to overlap each other so they finally crash into each other and form new border lines between them.

Views: 15735

Replies to This Discussion

To create starting surfaces from black and white artwork I posted a script to do just that using the free little program potrace.exe you can download and then it's automatically used by a Grasshopper Python script:

There's one bug where my outline curves were not joined and I just got lucky with my original test surfaces that were smooth curves instead of polylines, so just join the curves at the beginning:However, in debugging this I was still getting some output without the entire vast Voronoi bureaucracy even working, just from my offset/lowered edge curves. And they come out smoother, especially when more complex curves lead to lots and lots of Voronoi branches that then emulate a mere boring beveled edge.

Whereas with distinct-raised medial axes:

There was another bug in that I had cheated in finding the closest point to the outline, by only considering the outermost silhouette since I had so much trouble with data tree hassles trying to find the closest point to one of a collection of outer edges and the locally associated hole edges too.

Because of these failure modes and the hassles of a huge script, I'm abandoning Voronoi determined medial axes in favor of offset pilot curve tweaking:

No more data tree crap with the Path Mapper that makes me miss Python!

It's now robust since it won't break randomly during rough preview (low patch surface spans count):

So, can I do a whole huge array finally? Feeding in dozens of surfaces from an image trace, at the same very low patch resolution (30)...fairly just a flat patch since it's being overloaded with nearly equal height pilot curves:

Tiny holes won't offset and leave open curves so I'll filter those out. Yet so do very sharp concave outer edge curve areas:

Since we are just lowering an overall patch onto these, it's not an error, just feature loss here and there.

Trying it at patch spans 100 memory crashed Rhino, thankfully quickly, but no, it is not going to work on a huge patch, memory-wise, my having 24GB.

Will the Rhino patch command do it with baked curves? Rhino exists gracefully from the command. My test file is way too ambitious and this strategy is no match for ArtCAM at this crazy high detail level. A smaller geometry selection maxes out at 225 X 225 spans in Rhino, failing to capture much detail:

Ah! This should be done one item at a time then, and the patches will trim themselves. Possibly using Python to achieve parallel processing if there's a Rhinocommon Patch command. Is there? Yes there is!

So from a very complicated system I'm now at merely two offset curves moved down in Z.

Taking curves form a surface seems to give them directions that make them offset away from the surface every time, conveniently.

It may not work well for closed curve forms that span the whole diagonal of the collection since that's again having to deal with the whole XY bounding box of the area, for memory.

Simple little script now:

The original script is still useful for the medial axis part!


Doing simple offset pilot curve puffing via patch comparison between all at once, a whole bounding box frame and doing each one individually, scaling the number of patch spans for about the same resolution everywhere:

The time is about the same a bit over 20 seconds for the patch(es). No time hit, but there may be a memory survival advantage to independent grids. Data tree maintenance was needed via Unflatten Tree.


Yes, major memory advantage to separate item processing. For the same resolution using one blanket for the patch, the same patch spans per part would require over 550 spans, whereas merely 200 blew up the memory immediately.

Much faster with Python parallel processing, now that I am processing each item independently with its own local patch. With preview meshing in Grasshopper turned off, this took 17 seconds, with the Python patching via Rhinocommon CreatePatch being 7 of those seconds.

Currently, to avoid failed splits to remove the backgrounds, due to super shallow areas in skinny features that kiss the construction plane, I'm plane cutting a small amount below that construction plane, then moving the result back up.

I'm not using a Patch starting surface, as you can play with in the normal Rhino command, since it just sort of squashes broad curved mounds in ugly fashion, or else pulls them down to make ugly doughnuts everywhere around the input curves.

Details on how to use the CreateSurface command of Rhinocommon, hassles solved, is discussed here, with great all hours help from Peter Fotiadis, and I also discovered some clues from Djordje via Google, where he was massaging points into proper format:

The highest level CreatePatch command doesn't accept a normal Python list of objects in a variable like the two more simple versions of the same command does. You have to regather them into a Rhino container, which is really a .NET container. I still don't know yet how to upgrade the Python parallel patch component to input the whole panoply of objects you can patch over in Rhino because I don't know what container exists to hold them all that won't break the command.

The point of this overall script is to now be able to arrange lots of mere flat surfaces, surfaces because those can define holes versus borders easily, and create real 3D single surface NURBS geometry that can then be surface morphed (equivalent of Rhino Flow Along Surface) onto other 3D models.



Thank you so much for this script. However, for some reason, the parallel processing patch (Python_sdiff) box is red and not working. 

I open the Grasshopper Python Script Editior and when I test it, this error comes up:

"Runtime error (NullReferenceException): Object reference not set to an instance of an object.

line 12, in patch_them, "<string>"
line 21, in helper, "C:\Users\Jsoe\AppData\Roaming\McNeel\Rhinoceros\5.0\Plug-ins\IronPython (814d908a-e25c-493d-97e9-ee3861957f49)\settings\lib\ghpythonlib\"
line 25, in run, "C:\Users\Jsoe\AppData\Roaming\McNeel\Rhinoceros\5.0\Plug-ins\IronPython (814d908a-e25c-493d-97e9-ee3861957f49)\settings\lib\ghpythonlib\"
line 24, in script" 

Would you happen to know why its not working? I tried all the other codes that have this python script and none of them work. 

Thank you in advance.


Please isolate the problem by right click internalizing the input curves at the curve component and deleting the rest of the script, and upload the Grasshopper file.

Also list here your Rhino version, Windows 64 vs. 32 bit, and Grasshopper version.

I tucked my image tracer script onto this canvas too, that uses the free little helper program potrace.exe, and now works with spaces in the file path:

A faster sorting of mounds from background after plane splitting is included after also flipping of all surfaces upwards to tidy up after Rhinocommon CreatePatch behaves drunkenly. This array took total 17 seconds with Grasshopper preview mesh disabled.


I'm wondering if you see your Puffing script working to create Tile Patterns, such as shown below?

Pulling the background down to a starting surface with raised curves might indeed afford these types of structures.

In order to test it though, in Rhino itself, you must rebuild the starting surface to increase it's UV count, or else massive confusion results in a lack of elasticity since there are simply no control points for Patch to move after it locks onto the starting surface UV system instead of creating its own UV spans. This is untrimmed, thus the overall rectangle:

I tweaked offset pilot curve patch puffing by adding another Python script to invoke the full power of Rhinocommon's offset curve command, to avoid Grasshopper offset curve failures.

I also added controllable curve loop smoothing via simply arraying evenly spaced points along each loop curve and then creating a control point curve through them, to kill sharp corners that destroy offsets.

That's traced with the included potrace.exe utility.







  • Add Photos
  • View All


  • Add Videos
  • View All

© 2022   Created by Scott Davidson.   Powered by

Badges  |  Report an Issue  |  Terms of Service