# 3D printing cardioid

I am hoping to 3D print some simple cardioid pictures, like the following:

myplot2[k_: 2, n_: 60] := With[    {a = Exp[2 Pi*I*Range@n/n]},    Graphics[     GraphicsComplex[      Dynamic@       ReIm[I*Join[a, a^k]], {Line@Transpose@Partition[Range[2 n], n],       Thick, Circle[]}]]    ];
test = myplot2[2, 60 ]

extrudeImage[image_] :=   Block[{res, img},img = DeleteSmallComponents[Binarize[image, 0.7], 500];    res = ImageMesh[ColorNegate[img]];    RegionProduct[res, Line[{{0.}, {50.}}]]];
testfor3d = extrudeImage[test]
Printout3D[testfor3d]


This seem like a bad output.

Using the solution here,

img = test;
g = MorphologicalGraph[img // MorphologicalBinarize,
VertexCoordinates -> Automatic, EdgeWeight -> Automatic];
edges = EdgeList[g];

vertices =   Thread[Rule[VertexList[g], PropertyValue[g, VertexCoordinates]]]; lines = ((edges /. vertices) /.     UndirectedEdge[a_, b_] :> Line[{a, b}]);
Graphics[lines]

Graphics3D[  Tube[#] & /@ (lines /. {x_?NumericQ, y_?NumericQ} :> {x, 0, y})]


This then looks like just had a plastic surgery.

Any good workaround?

• FWIW, you can drop the Dynamic@ from the first argument of the GraphicsComplex in myPlot. That was included for the Manipulate in the other post. (Won't fix the problem.) Jul 23, 2018 at 22:29
• If you remove the Dynamic@, does this work for you?: Graphics3D[First@test /. GraphicsComplex[p_, g_, o___] :> GraphicsComplex[PadRight[p, {Automatic, 3}], g /. {Line -> Tube, c_Circle -> Tube[Range@60 ~Append~ 1]}]] -- I'm not real sure what works on a 3D printer or if you require each line to become a cuboid instead of a tube. Jul 23, 2018 at 22:33

It seems your MeshRegion has degenerate Prism objects that aren't able to export. We can take the boundary instead and skip the repair phase.

Printout3D[RegionBoundary[testfor3d], Method -> "SkipModelRepair"]


First I'll turn the 2D graphic into a BoundaryMeshRegion by thickening the lines and joining them with a discretized Annulus.

lines = With[{k = 2, n = 60},
With[{a = Exp[2. Pi*I*Range@n/n]},
First@Normal[
GraphicsComplex[ReIm[I*Join[a, a^k]],
Line@Transpose@Partition[Range[2 n], n]]]]
];

thickenLine[Line[{p1_, p2_}], Δ_: .004] := Block[{p},
p = Δ {1, -1} Reverse[Normalize[p2 - p1]];
BoundaryMeshRegion[{p1 - p, p1 + p, p2 + p, p2 - p}, Line[{1, 2, 3, 4, 1}]]
]

envelope = RegionUnion @@ thickenLine /@ Most[lines];

boundary = BoundaryDiscretizeRegion[Annulus[{0, 0}, {.99, 1.01}], MaxCellMeasure -> .01];

cardioid2D = RegionUnion[boundary, envelope]


Next we go 3D with RegionProduct:

cardioid3D = RegionBoundary[RegionProduct[cardioid2D, Line[{{0.}, {.25}}]]]


And finally print:

Printout3D[cardioid3D]


This is just the start of an approach, but I have to admit, I got stuck.

radius = 0.03;
Graphics3D@
MeshPrimitives[DiscretizeGraphics[test], 1] /. {Line[pts_] :>

Import@Export does a nice job at generating a mesh (whereas DiscretizeGraphics does not, and I don't know why. You will have to play with a TransformedRegion and ScalingTransform in order to obtain an object of suitable dimensions for printing. This question on capped tubes will make the ends a bit nicer and you'll have to think about how to hand the gap, because the answer eludes me.