My housemate Moon Duchin is interested in 3D printing these shapes that she studies. (She’s a mathematician.) The technical name for the shapes would be spheres of radius 1,2,3 in the Carnot-Carathéodory metric on the real Heisenberg group induced by a hexagonal norm. It’s a mouthful. I’ll probably do another post describing how to come up with the shapes.
Anyway, she’s actually already had two 3D printed by Shapeways, but I thought it would be a fun project to code the shapes from scratch and see what I could do with it on a Makerbot. This post is about how I coded the shape.
Here is a description of how to generate the base shape: Take a hexagon of given dimensions. Split it into 24 quadrangles of specific coordinates within the hexagon. For each quadrangle, use a given x-y polynomial to generate the z value. This gives you a curve. Thicken the curve and this gives you the shape. (Well, this gives you half the shape — reflect it across the x-y plane and that’s the whole shape, but I plan to print it in halves so for the sake of this post that is the whole shape.)
I hummed and hawed for a long time about which program to use to code this. I wanted to code it in python, since I am very familiar with that language, so I looked into a lot of free programs that use python to generate 3D models. Most of what I found followed in the footsteps of traditional mechanical engineering 3D CAD software: you generate 2D sketches from which you create 3D features. For this shape, what I really wanted to do was generate a set of points in space and then somehow use those points to generate a curve. Traditional mechE software isn’t very good at this.
Luckily, architects are really into this kind of stuff. I talked with a friend of mine who’s studying architecture and he recommended Rhinoscripting, which is a way to use python scripts to generate objects in Rhino, a 3D modeling software generally used by architects. Rhino is free, or at least the beta Mac version is free, and the scripting integration is dead easy. Just use the command _RunPythonScript and you can run a number of example scripts that come with the program.
There is a lot of documentation for Rhinoscripting, but it is mostly for people who know how to use Rhino and don’t know how to program in python. I was the opposite — super comfortable in python, clueless about Rhino. If you’re in that camp, I recommend figuring out what you need to do in Rhino first, without worrying about the scripting part. Rhino is a command line based program, so mess around with it and look on the internet to figure out which commands you need.
Once you’re ready for scripting, pick one of the default example scripts to find the syntax for importing the Rhino library and running Rhino commands. Everything else will be easy, because it really is just a python script using the Rhinoscripting library to interface with Rhino.
Luckily there were really only two commands I ended up needing: AddPoint, which takes a tuple of the x, y, z coordinates, and AddLine, which takes two tuples of coordinates, the start and stop points of the line.
You can download my code on gitHub here. It should be fairly easy to follow, but I basically make it exactly how I describe it: I generate a set of points within the large hexagon. I determine which points are in which quadrangles. For each quadrangle I use its polynomial to find the point of the curve, then push all of the points on the curve into Rhino.
Once I’m in Rhino I use the _Patch command, which magically patches all of my points together into a curve. The I use the original hexagon to _Trim the curve, Solid Extrude (Straight) to thicken it, and I’m done!
Actually not quite, Moon wanted the shape in radius 1, 2, and 3 — it expands by a factor of a in the x and y directions and a factor of a^2 in the z direction. This is also pretty easy in Rhino, which has a non-linear scale function.
The last thing I do is export it to an .STL file for printing. Most of what I did I actually did natively in Rhino. The scripting really just allowed me to generate that first set of points that I could patch into a curve. I think I could have done everything else in the script also, but I didn’t really see the point. It was faster to work in Rhino than figure out the right syntax for using the Rhino commands properly (with the dialog boxes and all) in the script.