DoSpinShift

The Syntax is:

DoSpinShift;

If you haven't already read it, you might like to look at the discussion of the DoShift Command before continuing.  When several actors must be moved simultaneously, intercalating their motions in a script using the SpinShift, ShiftSpin, Spin, and Shift commands is a simple method to use.  But when many individual calls are needed for a very smooth motion, it can be a bit slow.  An alternative for continuous motion called DoSpinShift is available that will in general be faster. 

            Suppose, for example, that you wanted to SpinShift some actors simultaneously along their trajectories given by differential equations, or by curves, or even stochastically.  You could create the trajectories as an anonymous (and invisible) actor.  If you wanted the orientation to change, as well as the position, for example, in rotating and orbiting a planet, you would create an invisible actor with the sequence of pairs of orientations and positions, in that order, and use either DoSpinShift or DoShiftSpin.

For SpinShifts, we need a type of invisible anonymous actor which is a sequence of pairs:   Quaternion(), Vertex()  (or (Vertex4(),  Vertex3())) in that order.  The Quaternion() or Vertex4() will always be interpreted as spin, and the Vertex() (or Vertex3() ) will always be interpreted as shifts.  This is the order we use:  Vertex4(),  Vertex3(), Vertex4(),  Vertex3(), ..., Vertex4(),  Vertex3(), that is:  Spin, Shift, Spin, Shift, Spin, Shift, ... Spin, Shift  when defining the invisible actor whether we use DoSpinShift or DoShiftSpin.

            The queue works this way.  Suppose it contains the ordered list of actors:  {a1, a2, .., an}.  Then when DoSpinShift is called, tha actor a1 is spun by the first Quaternion, then shifted by the following vertex3,  a2 is spun by the next Quaternion, then shifted by the following vertex3, a3 is spun by the next Quaternion, then shifted by the following vertex3, ..., an spun by the nth Quaternion, then shifted by the following vertex3,  then a1 spun by the (n+1) Quaternion, then shifted by the following vertex3, and so on cyclically, until there are no more quaternion/vertex pairs.

Suppose you wanted to orbit a "Space Shuttle" along the circular path (t from 0 to 2*pi):

c(t) := [5*cos(radian(t)), 0, 5*sin(radian(t))]

  For simplicity, suppose that the V vertices placed the center of mass of the shuttle at the origin initially, and that it was oriented, bottom to top, along the y-axis. To make the motion natural, we want a sequence of "Spinshifts"  first orienting the rocket in a direction tangent to the curve, then shifting it out to the appropriate location.  See Moving Actors for pictures.

            Clearly, a sequence of shifts would not do.  The shuttle would "translate" around the orbit in an unnatural manner.   The following script will cause the shuttle to orbit in a natural way:

refresh;                                        'clear anonymous actors'

c(t) := [5*cos(radian(t)), 0, 5*sin(radian(t))];

'Define the orbit curve.  Since we pass arguments in degrees, use Radian() to translate for Sin and Cos'

gldraw {                                                 'this creates the anonymous invisible actor'

make u quat(90, [1,0,0]);

do

  angle := 0

  until angle > 360 {

  v := quat(-angle, [0,1,0]);

  w := v*u;                                               'compose two spins'

  quaternion(w);                           'spin component'

  vertex( c(angle) );                      'shift component'

  angle := angle+5;                       'increment the angle which is measured in degrees'

}

}

push "shuttle";

dospinshift;

            There are several things to note.  We generally work with degree measure of angles, since OpenGL and Quat() expect degrees.  So we use the Radian() function where necessary to translate degrees to radians.  The trigonometric functions always expect radians.

            The curve c(t) defines an orbit of radius 5 centered at the origin in the x-z plane.  It begins and ends at [5,0,0].  But notice that it is traversed in such a way that initially it comes "out" of the screen towards the viewer.  This is the opposite of what would be dictated by the right-hand rule with the y-axis as center.

            To "point" the rocket correctly, we need two spins:  first, rotate it 90 degrees about the positive x-axis  (right-hand rule), and then rotate it through the opposite of the current angle about the positive y-axis (right-hand rule).  This orients it correctly at the origin.  Next, shift it to the location on the orbit with that orientation.

            To compose the two spins, we simply multiply the appropriate quaternions.

u := quat(90, [1,0,0]);

v := quat(-angle, [0,1,0]);

and form v*u = w.  This means u first, then v as noted earlier.  Then we execute the two commands for each angle: 

quaternion(w);                          'spin component'

vertex( c(angle) );                     'shift component'

            The Vertex() and Quaternion()  functions are useful for this sort of script because they accept vectors (as Mathscript objects) as arguments, and these may be computed in a flexible, symbolic way.  Otherwise, we'd have to "peel off" the components for Vertex3() or Vertex4().

            It is always Quaternion() = Spin first, then Vertex() = Shift second, whether we use a SpinShift or a ShiftSpin.  And, of course, the pairs: Quaternion(), Vertex() are now used for each actor in the Queue.  This means that the script must anticipate in the Gldraw{...} statement just how many actors will be in the queue in order to intercalate the motions correctly.  Usually, this is easy to do, even at run time. 

            Now the last two statements in the script are:

Push "shuttle";

DoSpinShift;

            This actually sets up the queue (in this case, "shuttle"), and puts the shuttle in orbit.   Just as in the case with DoShift, MathScript will interpret a DoSpinShift or DoShiftSpin to mean:  Use the invisible actor to guide the actors through a sequence of motions. 

See Also

                        Moving Actors

                        DoShiftSpin

                        DoShift

                        Push