2
$\begingroup$

I tried to export the following model for 3D printing but failed:

model = 
 Graphics3D[
    Table[
      {Rotate[
        Ellipsoid[{0, 0, 0}, {4, 2, 3}],     
        i*Pi/(30/2) + Pi/180, {0, 0, 1}  
      ]}, 
      {i, 30} 
    ]
 ];

Export["test.obj", model]

Export::type: Graphics3D cannot be exported to the OBJ format.

Export::type: RuleDelayed cannot be exported to the OBJ format.

enter image description here

Is there any problem with my code? I found that if I use Cylinder or Cuboid instead of Ellipsoid, the model will be exported without any warning, why?

$\endgroup$
  • $\begingroup$ Isn't this precisely the same problem you outlined in your previous question a few hours ago? $\endgroup$ – MarcoB Apr 2 at 13:53
  • $\begingroup$ @MarcoB These two question have some similarities, but they are not the same problem. I just want to find a easy way to solve these two questions. Thank you! $\endgroup$ – qg X Apr 2 at 13:59
  • $\begingroup$ The best way to do it might depend on what you want to do with the exported model. $\endgroup$ – Henrik Schumacher Apr 2 at 14:21
  • $\begingroup$ @HenrikSchumacher I want to do 3D printing, but there's no format that I can export successfully. I want to find a useful way by code. $\endgroup$ – qg X Apr 2 at 14:40
  • 1
    $\begingroup$ This isn't the first example in which GeometricTransformation causes trouble when exporting. (Another example I can find at the moment: mathematica.stackexchange.com/q/63173/1871 ) It should be easier to find a workaround in this case, given rotated ellipsoid is not hard to generate without Rotate. $\endgroup$ – xzczd Apr 2 at 15:09
2
$\begingroup$

The best workaround I can think out at the moment is to turn to RegionPlot3D.

To plot ellipsoid with RegionPlot3D, we need formula for general ellipsoid, which has been mentioned in the Details of document of Ellipsoid:

$$(x-p).{\Sigma^{-1 }}.(x-p)\leq 1$$

where $\Sigma$ is weight matrix, which can be generated with the help of TransformedRegion:

mat = TransformedRegion[Ellipsoid[{0, 0, 0}, {4, 2, 3}], 
                        RotationTransform[k Pi/(30/2) + Pi/180, {0, 0, 1}]][[2]]

$$\left( \begin{array}{ccc} 16 \cos ^2\left(\frac{\pi k}{15}+\frac{\pi }{180}\right)+4 \sin ^2\left(\frac{\pi k}{15}+\frac{\pi }{180}\right) & 12 \cos \left(\frac{\pi k}{15}+\frac{\pi }{180}\right) \sin \left(\frac{\pi k}{15}+\frac{\pi }{180}\right) & 0 \\ 12 \cos \left(\frac{\pi k}{15}+\frac{\pi }{180}\right) \sin \left(\frac{\pi k}{15}+\frac{\pi }{180}\right) & 4 \cos ^2\left(\frac{\pi k}{15}+\frac{\pi }{180}\right)+16 \sin ^2\left(\frac{\pi k}{15}+\frac{\pi }{180}\right) & 0 \\ 0 & 0 & 9 \\ \end{array} \right)$$

So the inequality representing the region is

expr = Or @@ Table[{x, y, z}.Inverse@mat.{x, y, z} <= 1 // Evaluate, {k, 30}];

expr is so large a symbolic expression, thus we compile it to speed up plotting:

cf = Compile[{x, y, z}, Evaluate@expr, 
             RuntimeOptions -> {"EvaluateSymbolically" -> False}];

(gra = RegionPlot3D[cf[x, y, z], {x, -5, 5}, {y, -5, 5}, {z, -5, 5}, Mesh -> None, 
                    PlotPoints -> 100]) // AbsoluteTiming

enter image description here

Finally discretize gra and export (directly exporting gra is OK, but it takes 89.2224 seconds to finish):

disgra = gra // DiscretizeGraphics; // AbsoluteTiming
(* {3.33076, Null} *)

Export["test.obj", disgra] // AbsoluteTiming
(* {1.02844, "test.obj"} *)

The biggest advantage of this approach is, the quality of the generated mesh seems to be good:

Show[disgra, PlotRange -> {-5, 0}]

enter image description here

FindMeshDefects@disgra

enter image description here

So the generated .obj file should be suitable for 3D printing.


Indeed, it's suitable for 3D printing:

enter image description here

$\endgroup$
  • 1
    $\begingroup$ Here is another way to compute mat: mat = With[{θ = i*Pi/(30/2) + Pi/180}, RotationMatrix[θ, {0, 0, 1}].DiagonalMatrix[{4, 2, 3}^2].RotationMatrix[-θ, {0, 0, 1}]] Recognizing that this is effectively an eigendecomposition, the inverse is then easy to assemble: With[{θ = i*Pi/(30/2) + Pi/180}, RotationMatrix[θ, {0, 0, 1}].DiagonalMatrix[1/{4, 2, 3}^2].RotationMatrix[-θ, {0, 0, 1}]] $\endgroup$ – J. M. is away Apr 3 at 12:50
  • $\begingroup$ Thank you very much! I need to learn more to understand these codes. Thank you for your help to me all the time. I won't be able to solve any problems without your help, so thanks again! $\endgroup$ – qg X Apr 3 at 13:23
1
$\begingroup$

Not a solution of the underlying problem but a way to circumvent it.

k = 30;
α = Pi/(k/2);
m = 360/(2 Pi/α);
n = 180;

f = {ϕ, θ} \[Function] {4 Cos[ϕ] Cos[θ], 2 Sin[ϕ] Cos[θ], 3 Sin[θ]};
pts0 = f @@@ Tuples[{
      Subdivide[-.5 Pi, .5 Pi, n],
      Subdivide[-1. α, 1. α, m]
      }][[All, {2, 1}]];
A = RotationMatrix[-N@α, {0, 0, 1}];
pts = (Join @@ NestList[#.A &, pts0, k - 1]);
polys = Mod[
   MeshCells[ArrayMesh[ConstantArray[1, {m, (k + 1) n}]], 2, "Multicells" -> True][[1, 1]],
   Length[pts], 1];

plot = Graphics3D[{
    EdgeForm[],
    GraphicsComplex[pts, Polygon[polys]]
    },
   PlotRange -> All
   ];
R = DiscretizeGraphics@plot

Export["test.obj", R]

enter image description here

There are several problems with your approach. They are not problems by themself but they make it hard for Mathematica to do what you want.

  1. You utilize GeometricTransformations and as xzczd pointed out the Export does not like it.

  2. Contrary to Line or Triangle, Ellipsoid is a primitive that is not natively supported by the OBJ format. Mathematica has to discretize the Ellipsoids first (i.e. approximate by triangle meshes).

  3. Although we see only the pumpkin-shaped surface, most part of the overall geometry is hidden in the interior. With Show[model,PlotRange -> {{-5, 5}, {-5, 5}, {0, 4}}] you can see that it is quite a mess. Upon Export, all this mess has also to be discretized. Maybe the many self intersections of the geometry cause a problem. And you 3D printer software also won't like it. Moreover DiscretizeGraphics cannot handle Ellipsoid primitives; DiscretizeGraphics[model] just returns EmptyRegion[3].

This first of these problems could be avoided as follows:

center = {0, 0, 0};
quadric = DiagonalMatrix[{4, 2, 3}^2];
model = Graphics3D[
  Table[
   translation = {0., 0., 0.};
   rotation = RotationMatrix[i*Pi/(30/2) + Pi/180, {0, 0, 1}];
   Ellipsoid[center + translation, rotation.quadric.Inverse[rotation]],
   {i, 30}]
  ]

But still, Export cannot handle it correctly because of the other two problems.

$\endgroup$
  • $\begingroup$ Thank you for suggesting a feasible way to circumvent it! I get another problem: model = Graphics3D[Table[{Rotate[Translate[Ellipsoid[{0, 0, 0}, {4, 2, 3}], {10, 0, 0}], i*Pi/(30/2) + Pi/180, {0, 0, 1}]}, {i, 30}]] If I want to translate each ellipsoid like this, how can I do it in your code? I‘m not very good at writing code, so I hope you can reply to me when you are not busy. Sincere thanks! $\endgroup$ – qg X Apr 3 at 1:52
  • $\begingroup$ I found another example may help solving this problem: link, they "normify" Translate, and that really did work. So can I "normify" Rotate like that? I hope you can take a look. Thanks! $\endgroup$ – qg X Apr 3 at 2:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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