Rotating animations in MMA

*To*: mathgroup at smc.vnet.net*Subject*: [mg2608] Rotating animations in MMA*From*: rustybel at foothill.net (Russell Towle)*Date*: Mon, 27 Nov 1995 21:35:45 -0500

Here is an example of the code I use to produce animations. Needs["Graphics`Shapes`"] (*I read in this file to use the embedded functions RotateShape and TranslateShape*) (*Here is code to produce a right prism; the prism is regular, i.e., has square lateral faces, when height is set to 1. It is centered on the origin*) Prism[n_Integer,height_] := Block[{d=((2*Sin[Pi/n])*height)/2}, Graphics3D[{N[Table[ Polygon[{{Cos[2Pi i/n], Sin[2Pi i/n], -d}, {Cos[2Pi (i+1)/n], Sin[2Pi (i+1)/n], -d}, {Cos[2Pi (i+1)/n], Sin[2Pi (i+1)/n], d}, {Cos[2Pi i/n], Sin[2Pi i/n], d}}], {i, n}]], Polygon[Table[N[{Cos[2Pi i/n],Sin[2Pi i/n],-d}],{i, n}]], Polygon[Table[N[{Cos[2Pi i/n],Sin[2Pi i/n],d}],{i, n, 1, -1}]]}]]/; n > 2 Prism[n_:12, height_:1] := Prism[n, height] (*preview the object to be animated, assigning it a name; I usually use a single letter, like g, but that's immaterial. Display the object with Axes->True so that you can get an idea of what the PlotRange must be to show all of it.*) object=Show[Prism[12,6], Boxed->True, Axes->True, ViewPoint->{1.199, -1.242, 1.010}] (*Here is the Do loop which produces the animation frames. The iterator specification is last; it is the variable i. My first step is to preview the object, by setting the beginning and end of the loop to zero. Only one frame is generated. If my PlotRange has been set properly, the entire object is visible. I set PlotRange by choosing the largest dimension of the object, dividing by 2, adding a little bit, and giving this value a name, say, r. The prism above extends 3 units above and below the xy plane, its largest dimension is 6, and I set r=6.25. Unless I specify otherwise, the object has inherited the ViewPoint used for the initial preview. I usually choose a ViewPoint fairly close to the object, perhaps {0,0,2}. The distance from the object greatly affects its colors; close ViewPoints result in richly saturated colors, which I like. I then crop the preview image; on my Macintosh this means selecting it and dragging its handles with the command key down. I crop it because, especially when the ViewPoint is close to the object, the perspective transformation in MMA leaves a rather large margin of empty space around the object. Since it is the object I want to see, I crop as close as seems esthetically proper. Then I resize the image, by selecting it and dragging the handles: I make it larger. Within the constraints of memory, I wish to have the object be as large as possible. In practice, this often means merely restoring it to roughly its original size, say, 284 by 284 pixels. But I have sometimes created larger frames, say, 400 by 480 pixels. But memory use is a real bugbear. As the frames are created, one sees the front end memory use meter filling. I very often find myself selecting large blocks of frames in the middle of the process and then choosing "Convert to Bitmap PICT," which destroys the Postscipt code but reduces memory use significantly. The process above, of cropping and resizing, takes some practice and forethought. For instance, in the case of a prism which stretches, say, 10 units along the z axis but has a basal radius of only 1 unit, if one previews at ViewPoint->{0,0,2} and then crops as detailed above, and then rotates the prism about the x-axis, parts of it will swing out of view. In an animation such as this the ViewPoint is fixed, and the object rotates. This prism is symmetrical by a rotation of 60 degrees around the z axis, so an animation will show continuous smooth motion by creating frames in, say, 3- or 4- or 5-degree steps. In this case I have set the iterator i to take steps of 3 degrees. I often find it easier to work in degrees, rather than radians, when setting up animations. OK. Now, the RotateShape function accepts three variables, in this form: RotateShape[object, {zrotation, xrotation, zrotation}]. Don't ask me why the last one isn't rotation about the y axis. At any rate, for the simple animation below, only rotation around the z axis is done. I am using degrees but the rotation matrix wants radians, so I write Degree i. The iterator is incrementing in steps of 3, therefore the rotation hapens in steps of 3 degrees. I know that the object will be carried into itself in 60 degrees, since it is a hexagonal prism. Since the iterator starts counting at 0, I must stop counting at 57. Then, when I double-click any frame to initiate animation, and the MMA animation default is in place, the frames will show smooth, continuous rotation, since the first frame (when i=0) will be displayed immediately after the 20th frame (when i=57). All this is only to say that, in this case, the iterator specification will look like {i,0,57,3}. 20 frames of a size such as 280 by 280 pixels will usually be produced without memory problems on a typical platform. Of course, for animation, the more RAM the better. Where too little RAM may easily become a problem is when more complex or less symmetrical objects are involved, or when more complex rotations are involved. So far we have only rotated the hexagonal prism about its axis of symmetry, and have only had to step through an interval of 60 degrees. However, we might wish to rotate the axis of symmetry itself, while rotating the prism about this axis. It requires a rotation of 180 degrees to carry the prism into itself, in this case. We may suddenly realize that a step of 3 is too small; we switch to 4, 5, even 6, to reduce the number of frames. However, for now, stick with 3. Now, instead of 20 frames, we need 60 frames. We write RotateShape[object, Degree i, Degree i, 0]. The iterator now must be {i, 0, 177, 3}. I am using a Mac with 64 MB available to MMA, and usually create frames around 320 pixels square. If the forms I animate are not too complex, I can sometimes allocate much more memory to the front end and let the kernel struggle along with just as little as possible. Of course, one can also proceed in stages: First set the iterator like this: {i, 0, 57, 3}; then save the frames to a separate file, delete, and set the iterator like this: {i, 60, 117, 3}; save frames, delete, then {i, 120, 177, 3}. When all the frames have been generated, I usually use the Convert to QuickTime, with compression algorithm set to Animation, bit depth to Thousands, quality to Best, and frames per second to 12. By combining the RotateShape function with the TranslateShape function (which were read in from Graphics Shapes), one can create animations of solar systems of polyhedra, pyramids spinning while orbiting prisms which in turn spin while orbiting a pentagonal dodecahedron. TranlsateShape can also be used to close-pack polyhedra which close-pack (like cubes, or rhombic dodecahedra, or Platonic tetrahedra mixed with octahedra), and then in an animation one can cause the close-packing to explode, by using an iterator inside the TranslateShape (just as we used an iterator in RotateShape, above). I hope this is helpful. I find animation to be one of the most desirable and wonderful features of MMA, and would like to see it used to its best advantage. If perchance I have made some dreadful error or omission in this, I would be very pleased to hear about it. Or the same, if anyone makes good use of these techniques.*) r=6.25; Do[ Show[ RotateShape[object,Degree i,0,0], ViewPoint->{.5,.5,.75}, PlotRange->{{-r,r},{-r,r},{-r,r}}, Boxed->False, Axes->False, Background->GrayLevel[0]], {i, 0, 0, 3}] Russell Towle Box 141 Dutch Flat, CA 95714 USA