Examples

download zipped archive of all examples

Related

  • Trigonometry, What is it good for? (follow along to 7 parts)
  • Trigonometry

    Trigonometry is the study of the relationships between the sides and angles of triangles.

     

    Cartesian vs. Polar Coordinates

    In our applets, we’ve modeled motion and different behaviors using cartesian coordinates, i.e. each object exists as a point with an X and Y coordinate (relative to the point 0,0). However, we can also describe any given point by an angle of rotation around the origin and a radius from the origin. Basic trigonometry gives us a method for converting between the two.

    Knowing how sine, cosine and tangent work (as well as the Pythagorean Theorem), we can develop formulas to convert back and forth between the two.

    float r = 50.0f;
    float theta = radians(30);
    // Convert from polar to cartesian
    float x = r * cos(theta);
    float y = r * sin(theta);
    println(x + " " + y);
    // Convert from cartesian to polar
    r = sqrt(x*x + y*y);
    theta = atan2(y,x);
    println(r + " " + degrees(theta));
    

    In Processing, we are only allowed to specify the location of a pixel via its “cartesian” coordinate, however, the above formulas for conversion will allow us to describe angular (or radial) velocity, acceleration, etc.

    Oscillations

    An oscillation is a periodic movement between two points, such as a pendulum. To simulate an oscillation with an applet, we can use simple harmonic motion. Simple harmonic motion (the periodic sinusoidal oscillation of an object) can be expressed as an x location as a function of time, with the following 3 elements:

  • amplitude: the distance from the center of motion to either extreme.
  • period: the amount of time it takes for one complete cycle of motion.
  • frequency: the number of of cycles per time unit (1 / period).
  •  
    The position x as a function of time t can be expressed as:

    x (t) = amplitude * cosine ( 2 * PI * t / period )

    In writing code for a simulation of an oscillating movement, we can think of a unit of time as one frame of animation. The code below demonstrates an oscillation with amplitude of 75 (assuming a global variable — framecounter — that counts the number of cycles through the loop.

    float period = 600.0f;
    float amplitude = 75.0f;
    float x = amplitude * cos(TWO_PI * framecounter / period);
    framecounter++;
    

    However, we can also easily describe the same situation with the concepts of angular velocity (and accleration). In other words, consider the following (assumes global variables “theta” and “theta_vel”):

    float amplitude = 75.0f;
    float x = amplitude * sin(theta);
    theta += theta_vel;
    

    Here, the period / frequency are tied directly to the angular velocity. An object oscillating with an angular velocity of 10 will have twice the period (half the frequency) as one with a velocity of 20. This is a simpler way to program oscillations and is analogous to the types of motion we looked at in weeks 1 and 2.

    Pendulum

    A typical example of an oscillating motion is a pendulum. In this case, we have a gravity force (a Vector pointing down) but the pendulum can only move in the direction allowed by its arm. We therefore consider the pendulum’s angle and evaluate the situation based on an angular acceleration and velocity.

    Given a pendulum with an angle theta (0 being the pendulum at rest) and a radius r, we can use sine to calculate the angular component of the gravitational force.

    Fg = M * G;
    Fpendulum = Fg * sine (theta)
    Angular Acceleration = Fpendulum / M = G * sine(theta);

    Note this is an ideal world scenario with no tension in the pendulum arm, a more realistic formula might be:
    Angular Acceleration = (G / R) * sine(theta)

    A more substantial explanation: http://www.myphysicslab.com/pendulum1.html

    Using this forumla, we can create a Pendulum class with all the necessary data

    class Pendulum {
    
      PVector loc;      //location of pendulum ball
      PVector origin;   //location of arm origin
      float r;           //length of arm
      float theta;       //pendulum arm angle
      float theta_vel;   //angle velocity
      float theta_acc;   //angle acceleration
    
      float ballr;       //ball radius
      float damping;     //arbitary damping amount
    
    etc. . .
    

    We can then write an update method which calculates the angular acceleration based on the force of gravity and the current pendulum angle and calculates the new position (via polar to cartesian conversion).

    void update() {
      float G = 0.2;                         //arbitrary universal gravitational constant
      theta_acc = (-1 * G / r) * sin(theta); //calculate acceleration (see: http://www.myphysicslab.com/pendulum1.html)
      theta_vel += theta_acc;                //increment velocity
      theta_vel *= damping;                  //arbitrary damping
      theta += theta_vel;                    //increment theta
      loc.set(r*sin(theta),r*cos(theta),0);  //polar to cartesian conversion
      loc.add(origin);                       //make sure the location is relative to the pendulum's origin
    }
    

    Waves

    To start, we will look at creating a wave pattern by simply graphing the sine function. To do this, we will need to consider the following elements:

  • amplitude: height of the wave (y-axis)
  • x spacing: # of pixels between each point along the x-axis
  • width: # of pixels for the entire wave (in our examples, will be the screen width)
  • period: # of pixels for one cycle of the wave
  •  
    Our technique will be to fill an array with height values, i.e. for every x value (along the x-axis), we will calculate a y-value via sine or cosine and store it in an array. Since 360 degrees (or two pi) is one cycle of a sine wave, we calculate how x will increment according to the period via this formula:

    dx * ( period / xspacing) = 2*PI
    dx = (2*PI*xspacing) / period

    int xspacing  = 8;                            //note the use of integer here
    int w         = width;                        //as these two values will be used to specify the size of the array
    
    float period    = 100.0f;
    float amplitude = 50.0f;                      //arbitrary amplitude
    float   dx = (TWO_PI / period) * xspacing;    //One period = 360 degrees = TWO_PI
    float[] yvalues = new float[w/xspacing];      //an array for the number of height values we need
    
    //we use a for statement to run through every element of the array
    //incrementing x as we go for the sine calculation
    float   x = 0.0f;                             //our values start at angle value 0
    for (int i = 0; i < yvalues.length; i++) {
      yvalues[i] = sin(x)*amplitude;
      x+=dx;
    }
    

    One we have the height values stored in an array, we can choose to graph them via any type of drawing technique. Here’s one boring solution, simply rendering ellipses at each location. Note that it is not entirely necessary to use an array in this case as we could have rendered the ellipses as we calculated the sine wave. Nevertheless, having the array allows for more flexibility and keeps our code well organized, with the various parts kept modular.

    for (int x = 0; x < yvalues.length; x++) {
      noStroke();
      fill(0,0,255,50);
      ellipseMode(CENTER);
      ellipse(x*xspacing,yvalues[x],16,16);
    }
    

    The above code will draw a static representation of a wave, to put one in motion, we simply start x off at a different “angle” each time (see the examples for an implementation of the above with a wave in motion).

    Making more complex waves:

  • Using Noise: We can implement a noise function (instead of sine or cosine) to calculate the height values and create a randomish-looking wave.
  • /***also try adding a second dimension for noise here to change the wave over time!!***/
    for (int i = 0; i < yvalues.length; i++) {
      float n = 2*noise(x)-1.0f;       //scale noise to be between 1 and -1 yvalues[i] = n*amplitude;
      yvalues[i] = n*amplitude;
      x+=dx;
    }
    
  • Additive Waves: By adding two or more waves together of different amplitudes and frequencies, we can create more complex wave patterns. See examples above for full implementation (code snippet below).
  • // Set all height values to zero
    for (int i = 0; i < yvalues.length; i++) {
      yvalues[i] = 0.0f;
    }
    
    // Accumulate wave height values
    for (int j = 0; j < maxwaves; j++) {
      float x = theta;
      for (int i = 0; i < yvalues.length; i++) {
        // Every other wave is cosine instead of sine
        if (j % 2 == 0)  yvalues[i] += sin(x)*amplitude[j];
        else yvalues[i] += cos(x)*amplitude[j];
        x+=dx[j];
      }
    }
    

    Graphing in Two Dimensions

    As we saw with perlin noise, by visiting every pixel in the window and calculating a value based on the x,y coordinate, one can create interesting patterns and textures. Similar interesting effects can be developed by applying the same technique to trigonometric functions.

    size(100,100);
    loadPixels();
    for (int i = 0; i < width; i++) {
      for (int j = 0; j < height; j++) {
        float x = i;
        float y = j;
        pixels[i+j*width] = color(x+y);
      }
    }
    updatePixels();
    

    For every x & y coordinate we create a grayscale color based on the x, y value, the result is a simple gradient effect. Graphing trig functions based on polar coordinates can produce much more interesting results. However, we have to map the screen width and height to values that are more useful. In other words instead of the top left being(0,0) and the bottom right being (100,100), we would want (0,0) to be in the center with (-4,-4) top left and (4,4) bottom right.

    float w = 8.0f;         //2D space width
    float h = 8.0f;         //2D space height
    float dx = w / width;   //increment x this amount per pixel
    float dy = h / height;  //increment y this amount per pixel
    float x = -w/2;         //start x at -1 * width / 2
    loadPixels();
    for (int i = 0; i < width; i++) {
      float y = -h/2;       //start y at -1 * height / 2
      for (int j = 0; j < height; j++) {
        float r = sqrt((x*x) + (y*y));    //convert cartesian to polar
        float theta = atan2(y,x);         //convert cartesian to polar
        float val = cos(r);               //calculate a value between -1 and 1
        pixels[i+j*width] = color((val + 1.0f) * (255.0/2));   //scale that value to 0 and 255
        y += dy;                          //increment y
      }
      x += dx;                            //increment x
    }
    updatePixels();

    A more interesting one to try:

    float val = sin(6 * cos(r) + 5 * theta);           //calculate a value between -1 and 1
    

    One Response to “Oscillation”  

    1. 1 steve cooley

      Hey, Daniel! I really appreciate you sharing your code! Check out the additive wave derivation I was learning some Processing with on my site:

      http://somejunkwelike.com/fineart/additivewave6/

      I grabbed your feed, so I’ll be readin’ you later. :)
      -Steve

    Leave a Reply