Given the ongoing improvements in 3D mesh generation (currently using 11.3), I'm trying to find a robust means for producing a "thickened wireframe" of a given mesh, where the faces are ignored and the edges are thickened into struts. My primary interest is doing this for the models in PolyhedronData, i.e., for small inputs, with the goal of producing a high quality, watertight mesh.
A quick and dirty method is to render a GraphicsComplex of the edges using a Tube of fixed radius for each edge, then applying DiscretizeGraphics to the result. This results in overlapping faces when multiple Tubes meet at a vertex, and when two edges cross or come sufficiently close to each other. But most slicing software can deal with the STL it produces, so it's workable for FDM printing.
Here is an only slightly more intricate method that works nicely for inputs that have just a few edges: Place a (solid) Ball at each vertex, and a (solid) Cylinder at each edge. Apply RegionUnion to the list of balls and cylinders, Discretize the result, and finally, take the RegionBoundary.
For instance:
v = PolyhedronData["TetrahedronFiveCompound", "Vertices"];
e = PolyhedronData["TetrahedronFiveCompound", "Edges"];
mesh = MeshRegion[10 v, Line[e]]
(Note that I multiplied v by 10 to increase the scale of the object.)
With[{radius = .4},
balls = Ball[#, radius] & /@ MeshCoordinates[mesh];
cylinders =
MeshPrimitives[mesh, 1] /. Line[pts_] :> Cylinder[pts, radius];
]
Then discretize and extract the boundary surface:
RegionBoundary[
DiscretizeRegion[RegionUnion @@ Join[cylinders, balls],
MaxCellMeasure -> {"Length" -> .3}]]
In an effort to produce a high-res discretization, I've had the most luck by using the MaxCellMeasure option, keeping the length small. But too small results in a failure of DiscretizeRegion. I'm seeking a resolution that's slightly better than the output above.
I wrote a program a few years ago (before RegionUnion could handle 3D objects) that would replace each face in a GraphicsComplex with a bunch of triangles to frame in the struts explicitly. It used VertexNormals to determine the axis for the depth dimension, so the struts between adjacent faces would fit together nicely. It works fine, and I'm happy to share the code if anyone is interested. But I'm wondering now if a simpler process, like that laid out above, can be refined to do something similar.