8
$\begingroup$

Update notice: The expression returned by "Faces" changed in V11, so an alternative for V11 has been included.

When I try and export 3D graphics, I get an error if some of the graphics complexes are translated. For example:

r1 = PolyhedronData["RhombicDodecahedron", "Faces"];           (* works in V10 *)
r1 = PolyhedronData["RhombicDodecahedron", "GraphicsComplex"]; (* fix for V11 *)

trans = 2 Table[
    Mean[PolyhedronData["RhombicDodecahedron", "VertexCoordinates"][[
      n]]], {n, PolyhedronData["RhombicDodecahedron", "FaceIndices"]}];

r2 = Table[
   Translate[r1, n], {n, 
    Table[Accumulate[RandomChoice[trans, m]], {m, 6}]}];

exp = Graphics3D[r2, Boxed -> False, SphericalRegion -> True];

Export["rhomdod2.obj", exp]

gives the errors

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

I never get these errors when I just export a single object or an untranslated object.

$\endgroup$
  • 1
    $\begingroup$ It has seemed to me that transformations are not implemented for all export formats. I don't know for sure whether that is the case, but, if so, it is probably version-dependent, too. $\endgroup$ – Michael E2 Dec 5 '15 at 22:41
  • 1
    $\begingroup$ Note to site users: The OP's code produced valid graphics before V11. Now it's broken. Use "GraphicsComplex" in place of "Faces" for V11. $\endgroup$ – Michael E2 Jun 1 '18 at 18:20
8
$\begingroup$

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

Mathematica graphics

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"  *)
$\endgroup$
  • $\begingroup$ I tested your code and don't seems to work? My example:pts = {{1, 1, 1}, {3, 3, 3}}; test = Graphics3D[Translate[Cuboid[], pts]] on MMA 11.3 $\endgroup$ – Mariusz Iwaniuk Jun 1 '18 at 17:58
  • $\begingroup$ @MariuszIwaniuk I don't have V11.3 yet. It works for me in V11.2 if I add Cuboid to the alternatives of geometric objects that ixfcoords recognizes. One would have to do this for Sphere and whatever other objects you have. -- Also PolyhedronData["RhombicDodecahedron", "Faces"] has changed from V10 to V11. Now it no longer returns a GraphicsComplex. It's very discouraging working with M sometimes. Sometimes I'll get getting prepared for class just to find that at some point in the last year, they've broken a demonstration that I wrote three years before and worked just fine. $\endgroup$ – Michael E2 Jun 1 '18 at 18:10
  • 1
    $\begingroup$ Instead Cuboid[] I used PolyhedronData["Cube", "GraphicsComplex"] and works fine now on MMA 11.3. Thanks a lot :) $\endgroup$ – Mariusz Iwaniuk Jun 1 '18 at 19:12
5
$\begingroup$

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

enter image description here

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

$\endgroup$

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.