Why do I sometimes get errors when exporting 3D graphics which have been translated or scaled?
If, as I suspect, exporting to "OBJ"
does not support geometric transformations, one fix is to convert your graphics to "normal" graphics. (I wish Normal
would do this, perhaps via an option.)
Here is a quick example of how to do this. To code it up in full generality means handling all of the graphics primitives and all the transformations (and transforming the VertexNormals
, too, I suppose). I'll restrict my focus to the OP's specific example. (Update notice: I simplified the code a bit. See edit history.)
ClearAll[normify, xfcoords, ixfcoords];
normify[Translate[g_, v : {__?NumericQ}]] := normify[Translate[g, {v}]];
normify[Translate[g_, v_?MatrixQ]] := xfcoords[g, TranslationTransform[#]] & /@ v;
normify[g_] := g;
SetAttributes[xfcoords, Listable];
xfcoords[g_, xf_] := ixfcoords[g, xf];
ixfcoords[(obj : GraphicsComplex | Polygon | Line | Point)[coords_, rest___], xf_] :=
obj[xf[coords], rest];
ixfcoords[g_, xf_] := g;
Example:
normalexp = normify //@ exp
FreeQ[normalexp, Translate]
(* True *)
It exports without error and creates a file, but I don't know how to check the output.
Export["/tmp/rhomdod2.obj", normalexp]
(* "/tmp/rhomdod2.obj" *)
Here is an alternate approach to eliminating Translate
from Graphics3D
objects.
It seems that Normal
has not been taught how to handle Translate
objects with multiple translation vectors. So, you can work around this problem by threading the last argument of Translate
before using Normal
. Here is a function to do this:
normalize[g_Graphics3D] := Normal[
g /. t:Translate[_, {__List}] :> Thread[t, List, -1]
]
Using the simple example from the comment to @Michael's answer:
test = Graphics3D[Translate[Cuboid[], {{1,1,1}, {3,3,3}}]];
normalize[test] //InputForm
Graphics3D[{Cuboid[{1, 1, 1}, {2, 2, 2}], Cuboid[{3, 3, 3}, {4, 4, 4}]}]
Using the more complicated OP example:
GraphicsRow[{exp, normalize[exp]}]
The output looks the same, and the normalized version is free of Translate
:
FreeQ[normalize[exp], Translate]
True
If you don't mucking about with the internals of Mathematica, you can instead teach Normal
how to handle these types of Translate
objects:
Unprotect[Internal`GeometricTransformation3D];
With[{gt = Internal`GeometricTransformation3D},
gt[t:Translate[_, {__List}], r__] := gt[Thread[t, List, -1], r]
]
Protect[Internal`GeometricTransformation3D];
Then:
Normal[
Graphics3D[Translate[Cuboid[{0,0,0}], {{1,1,1}, {3,3,3}}]]
]//InputForm
Graphics3D[{Cuboid[{1, 1, 1}, {2, 2, 2}], Cuboid[{3, 3, 3}, {4, 4, 4}]}]