Notes on anim, a simple animation utility

As we’re going to now focus on simulating things that move, it’s handy to be able to see animations of what they look like. You can do this with a little program anim that I wrote. This program reads in lines of text (using scanf), interprets them as instructions to draw on the screen, and then does so.

You’ll first need to get anim on your computer. You can do this as follows:

  1. Download the source code to anim. It lives at https://walterfreeman.github.io/phys307/anim.tar. Download this and unpack it using tar xvf anim.tar.
  2. In your terminal, go to the directory where you saved the file. This is an ordinary C file, so you can look at it if you want (or make changes!)
  3. You’ll need to install some packages first.
    • On a Linux system, you’ll need to do sudo apt install freeglut3-dev libglew-dev libpng-dev imagemagick libpng-dev.
    • On a Mac, in the past you just needed xquartz. I’m not sure now; we’ll figure this out in class, no doubt~
    • On Ubuntu-on-Windows, try sudo apt install freeglut3-dev libglew-dev libpng-dev imagemagick libpng-dev. Sol is expert at installing this on Windows and he can help us.
  4. Compile it:
    • Linux/Windows: make anim
    • Mac: make anim-mac
  5. Copy it to your system directory: sudo make install

You can try it by running anim and then typing things in. Here are some simple commands; note that monospace Roman letters like this are meant to be typed literally, while Italic letters like this are to be replaced with numerical values.

Try it: for instance, run anim, then type the following:

c 0 0 1
C 1 0 0
l -1 -1 0.5 0.8
F

Note that the anim window is blank until the first F command, which actually transfers the graphics commands you’ve given it to the screen.

These commands, in order, draw a circle with radius 1 at the origin; switch the color to red; draw a line from -1,-1 to 0.5,0.8; and finally send the frame to the display.

So, how do you use this with your code?

The trick lies in the Linux “pipe” operator. You are already familiar with the output redirection operator $\tt \rangle$, which sends the output of one program to a text file. For instance, you might have run

./trapezoid_rule > trap_err.txt

for last week’s homework.

However, what you want to do here is send the output of one program (yours) to another program (anim). This is done with the | operator, for instance

./simulate_pendulum | anim

If you then print out anim drawing commands using your program, they will be redirected to anim and you’ll see the animation on screen.

Try running the following program. (If you’d like to paste it into your editor and gedit isn’t letting you cut and paste on the Windows boxes, try using the editors nano or vim instead of gedit.)

#include <stdio.h>
#include <math.h>

int main(void)
{
  double theta,x,y;
  for (theta=0;1;theta+=0.01)
  {
    x=cos(theta);
    y=sin(theta);
    printf("l 0.0 0.0 %e %e\n,x,y);  // draw a line
    printf("c %e %e 0.05\n",x,y); // draw a circle
    printf("F\n"); // flush frame
  }
}

Run this program first by piping its output through less to see its output one screen at a time, i.e. ./animtest | less. Note what it is doing, and predict what the animation will look like.

Then, run it using anim: ./animtest | anim. What does it do? Is this what you expected? This is very similar to what you will do to animate your pendulum, except in this case your angle will be the result of solving a differential equation.

Note that even though your program can calculate very fast, anim can only draw 60 frames per second (on most monitors). This means that you may not want to draw every frame to the screen. You can avoid this by only printing one out of every $N$ frames to the screen, as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
#include <math.h>

int main(void)
{
    double theta,x,y;
    int frame_skip = 100,frame=0;
    for (theta=0;1;theta+=0.0001)
      {
        
        x=cos(theta);
        y=sin(theta);
        if (frame % frame_skip == 0) // if the current frame number is divisible by frame_skip, draw a frame
        {
          printf("l 0.0 0.0 %e %e\n,x,y);  // draw a line
          printf("c %e %e 0.05\n",x,y); // draw a circle
          printf("F\n"); // flush frame
        }

        frame++;
      }
}

In the preceding code, try changing the frame_skip value and seeing the effect. Altering the skip value in your future simulations will allow you to visualize results at a useful speed, while allowing the computer to use more than one Euler or RK2 timestep per frame for greater precision.

Anim also can be controlled from within the window. Here are some commands that can be used from within anim, while it is running.

There are many more anim commands, including many which draw in three dimensions (more on those when we start doing things in 3D!) Here are some of the others that will be useful to you:


t x y
(displayed text)

So, in short, you first print “t” followed by the x,y coordinates of where you want the text to appear, and then on the next line, print the text you’d like to display. For instance, to print “The cake is a lie” at coordinates (0.6, 0.8), you would print

t 0.6 0.8
The cake is a lie

What’s the difference between “t” and “T”? Using “t” prints text at particular simulation coordinates, so scrolling around will move your text around the screen. This is particularly useful for labeling points on figures. Using “T” (capital) fixes your text to a particular place in the window (whose coordinates are (-1,-1) to (1,1); this is useful for annotating a simulation with the current time, energy, etc.)

Output bypass (read this!)

Anim, used as detailed above, hijacks your program’s output. When you run ./myprogram | anim, you are directing all of the printf statements (sending text to “standard output”) to anim instead of the console. This makes certain things inconvenient:

How do you get around this? The answer is with the ! command in anim. This is important: if anim sees any line beginning with a !, it will chop the ! off and print it without change to the screen.

Try out this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>
#include <math.h>

int main(void)
{
  double theta,x,y;
  int frame_skip = 100,frame=0,circles=0;
  for (circles=0; circles < 20; circles++)
  {
    for (theta=0;theta<2*M_PI;theta+=0.0001)
    {

      x=cos(theta);
      y=sin(theta);
      if (frame % frame_skip == 0) // if the current frame number is divisible by frame_skip, draw a frame
      {
	printf("l 0.0 0.0 %e %e\n,x,y);  // draw a line
	  printf("c %e %e 0.05\n",x*1.05,y*1.05); // draw a circle
	printf("t %e %e\ntheta = %e\n",x*1.5,y*1.5,theta); // notice that this prints two lines
	printf("F\n"); // flush frame
      }

      frame++;
    }
    printf("!Completed %d cycles\n",circles);
  }
}