3

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.

enter image description here

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?

Chen Stats Yu
  • 4,986
  • 2
  • 24
  • 50
  • 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.) – Michael E2 Jul 23 '18 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. – Michael E2 Jul 23 '18 at 22:33

2 Answers2

7

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"]

enter image description here


Instead, here's a manual approach to construct your region.

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]

enter image description here

Next we go 3D with RegionProduct:

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

enter image description here

And finally print:

Printout3D[cardioid3D]

enter image description here

Greg Hurst
  • 35,921
  • 1
  • 90
  • 136
1

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_] :> 
    Cylinder[PadRight[#, 3] & /@ pts, radius]};
obj = Import[Export["temp.stl", %]]

enter image description here

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.

bobthechemist
  • 19,693
  • 4
  • 52
  • 138