8
$\begingroup$

As a minimal example, consider:

annuli = {Annulus[{0, 0}, {0.8`, 1}, {1.3681023133518435`, 
    6.255024218935966`}], 
  Annulus[{0, 0}, {1.8`, 2}, {2.9394676092071563`, 
    8.524521215589012`}], 
  Annulus[{0, 0}, {2.8`, 3}, {5.390068220020829`, 
    11.207832393335261`}], 
  Annulus[{0, 0}, {3.8`, 4}, {1.847790960182163`, 
    7.781910416962884`}], 
  Annulus[{0, 0}, {4.8`, 5}, {5.369176063296676`, 
    11.373108690157169`}]}

regU = RegionUnion@(RegionProduct[annuli[[#]] , 
      Line[{{0}, {0.8}}]] & /@ Range[Length@annuli])

Region[RegionUnion[
  regU
  , Cylinder[{{0, 0, 0.2}, {0, 0, -0.75}}, 5.8]
  , Cylinder[{{0, 0, -0.75}, {0, 0, -1.5}}, 6.0]
  ]
 , Boxed -> True
 , BoxRatios -> Automatic
 , Axes -> True
 , PlotRange -> {{-7, 7}, {-7, 7}, {-2, 2}}
 , ImageSize -> Medium
 ]

enter image description here

Using Show, a better rendering is generated for annuli on top.

Show[Region /@ (RegionProduct[annuli[[#]] , Line[{{0}, {0.8}}]] & /@ 
    Range[Length@annuli])]

enter image description here

Question: I want to generate a STL file from this. How can I improve the resolution of the structure shown in the first graphic?

Any suggestions, tips, improvements will be gratefully received.

$\endgroup$
12
  • 2
    $\begingroup$ Removing PlotRange seems to do it. $\endgroup$ Commented Jun 10, 2022 at 16:56
  • 1
    $\begingroup$ (2) use the CSGRegion functions (but unfortunately it looks like they don't handle the Product that you use to create the extruded annuli)... $\endgroup$
    – lericr
    Commented Jun 10, 2022 at 17:11
  • 1
    $\begingroup$ @lericr, why would you use an external CAD system when Mathematica ships with it's own? $\endgroup$
    – user21
    Commented Jun 10, 2022 at 20:09
  • 2
    $\begingroup$ @user21 I guess I don't know what CAD system you're referring to. All I can say is that the functions that seem most amenable to generating printable object, i.e. the Region* functions, just don't perform well compared to other programs that are special-built for that purpose. The new CSGRegion* functions are much better. $\endgroup$
    – lericr
    Commented Jun 10, 2022 at 20:44
  • 1
    $\begingroup$ @user21 Just saw your answer with a link to OpenCascadeLink. I wasn't aware of this. Where have you been for the last 10 years as I desperately looked for a Mathematica-only solution for my printing projects? $\endgroup$
    – lericr
    Commented Jun 10, 2022 at 20:48

3 Answers 3

10
$\begingroup$

Using OpenCascadeLink, which comes with Mathematica, will give you excellent results. We start by loading the package and writing a little helper function to convert the annuli to polygons in 3D space which we then rotate in 3D.

Needs["OpenCascadeLink`"]
f[\[Theta]_, r_] := Sequence[r*Cos[\[Theta]], r*Sin[\[Theta]]]
makePoly[\[Theta]_, {rin_, rout_}, {h1_, h2_}] := 
 Polygon[{{f[\[Theta], rin], h1}, {f[\[Theta], rout], 
    h1}, {f[\[Theta], rout], h2}, {f[\[Theta], rin], h2}}]

Create the polygon and visualize:

poly = makePoly @@@ 
   Transpose[{annuli[[All, 3, 1]], annuli[[All, 2]], 
     ConstantArray[{0, 0.8}, Length[annuli]]}];

Graphics3D[poly]

Convert the polygon to OpenCascade shapes and rotate them by the given amount:

shapes = OpenCascadeShape /@ poly;
axis = {{0, 0, 0}, {0, 0, 1}};
sweeps = 
  MapThread[
   OpenCascadeShapeRotationalSweep[#1, axis, #2] &, {shapes, 
    Subtract @@@ annuli[[All, 3]][[All, {2, 1}]]}];

Create the two cylinders and make a union of all of it:

cyls = OpenCascadeShape /@ {Cylinder[{{0, 0, 0.2}, {0, 0, -0.75}}, 
     5.8], Cylinder[{{0, 0, -0.75}, {0, 0, -1.5}}, 6.0]};
union = OpenCascadeShapeUnion[Flatten[{cyls, sweeps}]];

If you want to inspect before exporting use a wireframe:

OpenCascadeShapeSurfaceMeshToBoundaryMesh[union][
 "Wireframe"["MeshElementStyle" -> FaceForm[Orange]]]

enter image description here

Ah, yes, and export:

OpenCascadeShapeExport["~/test.stl", union]

Have a look at the aforementioned tutorial and also this Helical Bevelgear example to get an idea of the scope of OpenCascadeLink.

$\endgroup$
8
$\begingroup$

You could convert it to BoundaryMeshRegion and do operations:

regU = (RegionProduct[BoundaryDiscretizeGraphics@annuli[[#]], 
      Line[{{0}, {0.8}}]] & /@ Range[Length@annuli]);

cylinder = 
  BoundaryDiscretizeGraphics /@ {Cylinder[{{0, 0, 0.2}, {0, 
       0, -0.75}}, 5.8], 
    Cylinder[{{0, 0, -0.75}, {0, 0, -1.5}}, 6.0]};

RegionUnion[Flatten[{cylinder, regUU}]]
$\endgroup$
6
$\begingroup$

Although CSGRegion is hard to export to stl upto the 13.0.1 version.

annuliCylinder[{x_, y_}, {r1_, r2_}, {θ1_, θ2_}, {h1_, 
   h2_}] := 
 CSGRegion[
  "Difference", {CSGRegion[
    "Difference", {Cylinder[{{x, y, h1}, {x, y, h2}}, r2], 
     Cylinder[{{x, y, h1}, {x, y, h2}}, r1]}], 
   Parallelepiped[{x, y, 
     h1}, {{r2*Cos[θ1], r2*Sin[θ1], 
      h1}, {r2*Cos[θ2], r2*Sin[θ2], h1}, {x, y, 2 h2}}]}]
data = Append[#, {0, 1}] & /@ 
   List @@@ {Annulus[{0, 0}, {0.8`, 1}, {1.3681023133518435`, 
       6.255024218935966`}], 
     Annulus[{0, 0}, {1.8`, 2}, {2.9394676092071563`, 
       8.524521215589012`}], 
     Annulus[{0, 0}, {2.8`, 3}, {5.390068220020829`, 
       11.207832393335261`}], 
     Annulus[{0, 0}, {3.8`, 4}, {1.847790960182163`, 
       7.781910416962884`}], 
     Annulus[{0, 0}, {4.8`, 5}, {5.369176063296676`, 
       11.373108690157169`}]};
CSGRegion["Union", {annuliCylinder @@@ data, 
   Cylinder[{{0, 0, 0.2}, {0, 0, -0.75}}, 5.8], 
   Cylinder[{{0, 0, -0.75}, {0, 0, -1.5}}, 6.0]} // Flatten, 
 ImageSize -> Full]

enter image description here

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.