Another spinning ziggurat

In the program on the previous page, the rotation rates of the ziggurat’s blocks are not synchronized. On this page, we’ll synchronize their behaviors by setting their rotation rates to the terms of an arithmetic progression.

An arithmetic progression is a sequence of numbers in which the difference between successive terms is constant. For example, in the sequence 2, 5, 8, 11, 14, 17, …, successive terms differ by 3. Where we let a stand for the initial term and b stand for the common difference, an arithmetic sequence has the form a, a+b, a+2b, a+3b, …. Where s0 denotes the initial term, the i‘th term is given by si = a + bi. In the previous example, a=2 and b=3.

To rotate a ziggurat’s blocks, we set the rotation rate of the bottom block to a rotations per second (rps), and the rotation rate of every other block to b greater than the block just beneath it. In other words, the rotation rates follow an arithmetic progression in which the i’th block spins at rate a + bi rps.

Another spinning ziggurat

Recall from the previous page that we used this code to attach a random rotation behavior to every block:

zig = ziggurat(nbrLevels, nbrSides, height, scale);
moveChildren(zig, makeRandomYRotator(0.25, true));

The specific behavior was assigned by the call to makeRandomYRotator, so for the current program we’ll call a different function. To assign rotation rates that follow the arithmetic progression a + bi, we’ll call makeArithYRotator(a, b). For example, we would use the following code to assign the bottom block a rotation rate of 0.01 rps, and each successive block a rate of 0.02 rps greater than that of its predecessor:

moveChildren(zig, makeArithYRotator(0.01, 0.02));

Based on the framework of the previous program, all we need to do is define this function:

function makeArithYRotator(rpsA, rpsB) {
    let spinY = makeSpin(1);
    function f(child, i) {
        child.rps = rpsA + rpsB * i;
        return spinY;
    }
    return f;
}

Our rotating ziggurat returns to the same configuration at regular time intervals. If the bottom block is stationary (that is, a = 0), repeat configurations recur at the same position; otherwise the configuration as a whole rotates around the vertical axis. The time it takes for a configuration to repeat is a function of b and the number of sides n. One way to infer this function is to experiment with the program: set a to zero and b and n to small values, and then time how long it takes for a memorable configuration to repeat.

To understand this function, note that a regular n-sided block appears in the same position after turning every 1/n full rotations, or 2\pi/n radians. Since two successive blocks — one immediately on top of the other — differ in speed by b rotations per second, their difference in rotation angle is equal to 2\pi b. The two blocks realign whenever 2\pi b is a multiple of 2\pi /n. This occurs every t seconds such that bnt is an integer, that is, every t=\frac{1}{bn} seconds. This same relation holds for all pairs of successive blocks from bottom to top, so it applies to realignment of the zigurrat as a whole.

As an example, when b = 0.01, the ziggurat realigns every 1/(4*0.01) = 25 seconds when n = 4, and every 1/(6*0.01) = 16.666 seconds when n = 6.