some days ago I had a chat with a family member about objects and their projections in lower dimensions. For example, a cylinder in 3D can look either like a circle or a rectangle in 2D when projected along the main axes. So we wondered if there was an object which 2D projections look like a circle along all three axes, but which isn’t a sphere. We came up with an intersection of three cylinders of equal radius along the main axes. Turns out such an object is called Tricylinder.
Intersecting three cylinders with the boolean function in Blender leaves the resulting mesh a bit messy, so I though I’ll try to generate such an object a bit cleaner with Python. This is my first script of this kind, I learned quite a bit, it 's a fun object, so I thought maybe I should share it.
It’s found in the “Add” menu of the scripts window. If you want to have it showing up in the Add Mesh menu, change Line 5 from “Group: ‘Add’” to “Group: ‘AddMesh’”. I didn’t put it in by default, because I don’t want to clutter people’s menu.
And here’s the script:
#!BPY """ Name: 'Tricylinder' Blender: 245 Group: 'Add' Tooltip: 'Add a Tricylinder object' """ __author__ = 'Sanne' __version__ = '0.1' __bpydoc__ = """\ A Tricylinder is a Steinmetz Solid, an intersection of three cylinders of equal radii intersecting at right angles. """ import Blender from Blender import Scene, Object, Mesh from math import cos, sin, radians def makeSegment(me, SUBDIVISION, RADIUS): """Generate 1/24th segment of the tricylinder """ verts =  faces =  alpha = 45.0/(SUBDIVISION + 1.0) v1 = 0 for n in range(SUBDIVISION + 1): # not needed, keep for reference #a1 = sin(n * radians(alpha)) #b1 = cos(n * radians(alpha)) a2 = sin((n + 1) * radians(alpha)) * RADIUS b2 = cos((n + 1) * radians(alpha)) * RADIUS if n > 0: # not needed, keep for reference #verts.append([a1, a1, b1]) #verts.append([a1, -a1, b1]) verts.append([a2, -a2, b2]) verts.append([a2, a2, b2]) v2 = v1 + 1 v3 = v1 + 2 v4 = v1 + 3 faces.append([v2, v1, v3, v4]) v1 += 2 else: verts.append([0, 0, RADIUS] ) verts.append([a2, -a2, b2]) verts.append([a2, a2, b2]) v2 = v1 + 1 v3 = v1 + 2 faces.append([v1, v2, v3]) v1 += 1 me.verts.extend(verts) me.faces.extend(faces) def makeTop(scn, ob): """ Generate the top side (1/6th) of the tricylinder out of four segments The newly generated tricylinder segment is the currently selected onject. The for loop generates three copies of this segment, rotates and joins them, thusly building the top of the tricylinder. """ oblist =  for i in range(3): Object.Duplicate(mesh=1) tmpob = Object.GetSelected() tmpob.RotZ += radians(90) oblist.append(tmpob) # join temporary objects with the original segment # and delete the temporary objects from the scene ob.join(oblist) for item in oblist: scn.unlink(item) ob.select(1) def makeBody(scn, ob): """Generate the whole body of the tricylinder out of the top side""" # rotate top 180 degrees around x Object.Duplicate(mesh=1) tmpob = Object.GetSelected() tmpob.RotX += radians(180) ob.join([tmpob]) # newob1 scn.unlink(tmpob) ob.select(1) # rotate joined object 90 degrees around x Object.Duplicate(mesh=1) tmpob = Object.GetSelected() tmpob.RotX += radians(90) # rotate last tmpob 90 degrees around Z Object.Duplicate(mesh=1) tmpob2 = Object.GetSelected() tmpob2.RotZ += radians(90) # join all objects and clean up ob.join([tmpob, tmpob2]) scn.unlink(tmpob) scn.unlink(tmpob2) ob.select(1) def addTricylinder(SUBDIVISION, RADIUS): """Generate the whole mesh""" limit = 0.001 scn = Scene.GetCurrent() scn.objects.selected =  me = Mesh.New("Tricylinder") makeSegment(me, SUBDIVISION, RADIUS) ob = scn.objects.new(me, 'Tricylinder') makeTop(scn, ob) me.remDoubles(limit) makeBody(scn, ob) me.remDoubles(limit) Blender.Redraw() def main(): """GUI function""" PREF_SUBDIVISION = Blender.Draw.Create(3) PREF_RADIUS = Blender.Draw.Create(1.0) # list for popup content block =  # inputs: title, button, min/max values, tooltip block.append(("Subdivision: ", PREF_SUBDIVISION, 0, 50, "Subdivision of 1/24th tricylinder segment")) block.append(("Radius: ", PREF_RADIUS, 0.01, 100, "Radius of intersecting cylinders")) if not Blender.Draw.PupBlock("Add Tricylinder",block): return addTricylinder(PREF_SUBDIVISION.val, PREF_RADIUS.val) # ---------- main program -------------------- main()