I made a Grasshopper component for helping make Space-Frames. It’s fairly limited in what it can do, but I thought I would share it anyways.
Suppose, like me, you are a hobbyist who wants to build a space-frame out of PVC pipe. For example, something like this:
What I need was a semi-automated way to generate the custom joints of a space-frame. You can think of these as custom PVC pipe fittings. (I will be 3d-printing the custom pipe-fittings.) The input would be a network of lines.
From there, the script would find line intersections and vertices and build a connectivity graph. then it would use Solid Boolean operations on cylinders and spheres to make the shapes.
So that’s the overall idea. Below are more details if this interests you.
There are a couple of oddities about this tool, and I need to explain them. Each vertex of the space-frame is generated by many dozens of Solid Boolean operations. And in theory they are easy to construct. However, in practice, Rhino booleans can fail. If the seam of a cylinder lands close to the seam of a sphere, but not exactly, then Rhino can get confused by the tiny edges and NURBS patches generated. In a network with say 30 vertices, and say 30 boolean operations per vertex, that’s 900 boolean operations, and if say, 3% of the booleans fail, then that’s 27 failures which are a pain to fix by hand.
So the project turned out to be three times more difficult than I expected. One third was the normal stuff of laying out the geometry. Another third was wrangling Data Trees (which still confuse me at times). And the last third was avoiding problems with Solid Boolean operations.
Briefly, here are some workarounds I used to avoid problems with Boolean Operations:
(1) Each “branch” of a pipe-fitting is pre-cut by a Voronoi cell. (Voronoi-cells of points-on-a-sphere.) This allows each pipe-fitting to be constructed by a union of parts, where each part touches other parts along a plane. This saves Rhino from having to do complicated off-axis cylinder-on-cylinder Booleans.
(2) Seams of spheres and cylinders are randomized. This is why a Random Seed is part of the input. If you get unlucky, you can try a different Random Seed.
(3) I want to have fillets between the branches of pipe-fittings. This is mostly for structural reasons (to avoid weak spots caused by stress-concentrations). I found doing complex fillets in Rhino to be problematic. So instead, I compute my own approximate fillets. I call them pseudo-fillets because they are not G1 in smoothness. In fact, each pseudo-fillet is returned as a solid fragment, andht then at the end you can manually union them all together. These are mainly structural, while not being totally ugly from an aesthetic sense. The pseudo-fillets are not G1 (tangent-continuous) with cylinders or other pseudo-fillets. But they are visually not too bad, if your surface is matt (non-glossy). Lots of work here, that I won’t go into, unless you are curious.
The fillets themselves are complex shapes, so Solid Boolean operations on them can fail. So we return each fillet as a separate solid-fragment (Brep). And then leave it to the user to Union the fillets together with the pipe-fittings. If the Union fails, the user can try unioning them one-by-one in a different order, or in the worst case you can do “NURBS Surgery™” by manually splitting individual patches and then joining things back together.
If you have better luck than me, you can tell the script to not compute fillets, and then manually fillet edges by yourself, or by modifying the script with your own automated fillets.
Back to using the script:
So the input is a network of lines. The output is a collection of solid parts. For example, at one vertex, the pipe fitting looks like this.
Orange are the pipes. Green is the joint (pipe-fitting) without fillets. Dark-Green are the pseudo-fillets.
After manual Solid-Union, you get the following. As you can see, the pseudo-fillets are obviously not G1.
If this is all you want, then we’re done. However, I usually want to fillet the outer-edges of the pipe-fitting. To make that as simple-as-possible for Rhino, we intersect the pipe-fitting with a single sphere. This simplifies the geometry, especially for highly-complex fittings with many incoming pipes. Here’s the sphere which is automatically computed:
And here is the result after the solid-intersection.
As you can see, the intersection removed several faces and patches, which means Rhino is more likely to succeed when calculating the fillet. After a manual fillet, we have this:
Those of you who are looking closely realize that the two orange pipes on the right actually overlap. This causes the fitting to have an additional “hole” which is partially highlighted by the yellow edge.
The overlap happens because two pipes enter the joint at almost the same angle. To make this joint work, you would have to physically cut-away parts of each pipe. And for my application, I will be cutting away parts of the pipe to make it fit with the other ones. Alternatively, you can increase the size of the pipe-fitting, so that none of the pipes get close to each other. But often that is not practical. Here’s a view of the overlap from a different angle.
The overlapped volume is in red.
So after manual solid-union of fillets and fittings, followed by additional fillets, we get the final result.
Just a reminder that our input was a network of lines:
The script is fairly “dumb” and “simple” and doesn’t always give pretty results. Here’s a complex joint that I will have to “tidy up” to make it pretty.
The highlighted patches in yellow are a “dimple” caused by the union of many fillets that partially overlap. And it looks ugly, so I will be doing some manual post-processing to smooth it over. (Say with spherical patches, and possibly using XNurbs or the new Patch/FillSurf in Rhino v9.)
If you actually want to use this tool, you’ll need some terminology. Here is my informal terminology for various inputs. I’m not an architect, nor an engineer, so I don’t know what “official” terms are used for the various dimensions.
Not mentioned is an additional input called “Chamfer Allowance” which actually should be named “Fillet Allowance.” The fillet-allowance is a measure of how much approximation is used in the fillet geometry. In theory, if the fillet-allowance is set to a distance of zero, then it computes the “exactly correct” fillet, and would be G1 (tangent continuous). However, that usually has some failures, so I’m using a allowance of 0.025mm which is about half the thickness of office-paper. If fillets fail or go missing, then try increasing this. Basically, what the script does is a “rolling-ball” style of fillet. But it uses a slightly larger ball, while forcing the ball to travel the same path as the smaller ball. This guarantees an “easy” intersection for Rhino to find (the intersection is not tangent and almost-not-touching, but an “obvious” non-tangent penetration).
WARNING: This script is SLOW. We are performing many dozens of Solid-Boolean operations per vertex. (I haven’t counted, but I wouldn’t be surprised if it was around 50 Booleans for complex joints. Maybe half of those are spent brute-force computing the spherical Voronoi-cells.) On my machine, it takes about 8 seconds per vertex. The above example has around 18 pipe fittings, and takes THREE MINUTES to run on my machine (AMD 5800X, 3Ghz, 64 GB RAM). More than half the time is spent calculating the pseudo-fillets (which I mistakenly call pseud-chamfers in the script). I recommend playing with small examples to understand how it works, and then later disabling the Grasshopper solver and using “Recompute” when you’re ready with a complex input.
The Grasshopper script, and an example .3dm file are here. I’m releasing the script under an MIT License, which is quite open and permissive.
ChiralSym Space-Frame Generator (1.6.7).zip (16.6 MB)
Let me know if you have comments and/or suggestions. I’m a bit too busy to work on this much more, but I will consider any thoughts and/or questions you may have.
Sincerely,
–Anthony Yan


















