DoShift
The Syntax is:
Doshift;
When several actors must be translated 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 DoShift is available that will in general be faster.
Suppose, for example, that you wanted to translate 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 the trajectories were to be sequences of positions (without changing orientation) you would use the glDraw{...} protocol with the desired sequences of positions as Vertex() or Vertex3() calls computed within it. You should not use Begin() ... end() within the glDraw{..} or any other OpenGL functions. Then you would use the DoShift command to move the actors in the queue through the sequence of steps in the invisible actor.
The queue works this way. Suppose it contains the ordered list of actors: {a1, a2, .., an}. Then when DoShift is called, tha actor a1 is moved to the first position, a2 is moved to the second position, a3 is moved to the third position, ..., an is moved to the nth position, then a1 is moved to the (n+1) position, and so on cyclically, until there are no more positions.
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.
Here we discuss the Shift case, where orientation does not change. Suppose, for example, you wanted to revolve a sphere about a circular orbit. Suppose the V vertices place the sphere initially at the origin [0,0,0]. Then the following script would move it in a circular orbit in the x-z plane.
refresh; 'clear all anonymous actors'
c(t) := [5*cos(radian(t)), 0, 5*sin(radian(t))]; 'define the curve trajectory'
gldraw { 'now create the invisible actor'
do
angle := 0
until angle > 3600 {
vertex( c(angle) );
angle := angle + 1;
}
}
push "sphere"; 'place the sphere in the queue'
DoShift; 'move it'
The first line, refresh; removes all anonymous actors so that we may start a new one. In general, anonymous actors are concatenated in memory to the limit of storage, roughly 13,000 OpenGL statements.
The second command creates a curve whose points will be the translation (Shift) vectors that we want to apply in sequence. This is a convenience, and we needn't use a curve. We could instead generate the points from a differential equation, stochastic process, or any other means.
The third command is a glDraw {...} protocol. This creates the anonymous actor. It is the only way to create an anonymous actor. In this case, it is a sequence of 3600 points, that will cause the sphere to revolve 10 times. The "points" must be created with the "vertex()" or the "vertex3()" command within the draw. Vertex is convenient here, because we can simply write: vertex( c(angle)) and Mathscript knows what we mean.
Now in general, you may create an invisible actor of this type (sequence of vertices) with up to 13,000 vertices. So long sequences of motion are possible.
Note: To stop drawing, simply press the Esc key.
The actor created by glDraw{...} is "invisible" because we have not used a begin() - end() block. So the Vertex() calls do not actually trigger OpenGL to draw anything. But this sequence is nevertheless "compiled" into a display list. The invisible actor (the orbit) remains around until you make another call to refresh; or until you select: Scene, Refresh. Remember, however, only to use the Vertex() or Vertex3() OpenGL commands.
The next statement adds "sphere" to the queue of actors to move along this invisible actor. For each actor that you plan to move, you should make a separate Push call with its name. If a name is repeated, it is ignored the second time an attempt is made to push it. The actors are moved in the order in which they are pushed after the invisible actor is created.
Note: Each time an invisible actor is created (or any call to glDraw{..} is made), the queue is erased. So you should call glDraw{...} first to create the invisible actor, then create the queue of actors to move using push.
The last statement, which may appear strange, actually puts the sphere in motion. It is:
DoShift;
Each vertex() statement in the invisible actor is interpreted as a "shift" in the usual sense. There should be only vertex (or vertex3() ) statements in the invisible actor. If MathScript encounters any other type of OpenGL statement, it stops the animation at that point.
When MathScript sees a DoShift; call, it always behaves this way. If there is no invisible actor defined, then it simply returns. When this entire script is run, there is a small delay while MathScript builds the invisible actor, and then the sphere is set in motion. You should, of course, create the invisible actor only once. Each time DoShift is called henceforth, this sequence of motions will be repeated.
DoShift;
will immediately set the queue in motion using the invisible actor already created. And of course, if you want to change the track of motion, then call Refresh; first, and build a new invisible actor.
That is how DoShift works for continuous motion. It is generally a bit faster than a series of Shift calls, because it computes the whole motion at once. The discrete form (Shift) should be used if you want to have decision points along the trajectory. Motion is terminated with the Esc key.
See Also