Search code examples
javaprocessingdrawtrigonometry

Drawing Spiral Using Java in Processing


I have a Java program written in Processing I made that draws a spiral in processing but I am not sure how some of the lines of code work. I wrote them based on a tutorial. I added comments in capital letters to the lines I do not understand. The comments in lowercase are lines that I do understand. If you understand how those lines work, please explain in very simple terms! Thank you so much.

void setup()
  {
    size(500,500);
    frameRate(15);
  }

  void draw()
  { 
    background(0); //fills background with black
    noStroke(); //gets rid of stroke

    int circlenumber = 999;// determines how many circles will be drawn 
    float radius = 5; //radius of each small circle
    float area = (radius) * (radius) * PI; //area of each small circle
    float total = 0; //total areas of circles already drawn
    float offset = frameCount * 0.01; //HOW DOES IT WORK & WHAT DOES IT DO

    for (int i = 1; i <= circlenumber; ++i) { // loops through all of the circles making up the pattern

      float angle = i*19 + offset; //HOW DOES IT WORK & WHAT DOES IT DO
      total += area; // adds up the areas of all the small circles that have already been drawn
      float amplitude = sqrt( total / PI ); //amplitude of trigonometric spiral
      float x = width/2 + cos(angle) * amplitude;//HOW DOES IT WORK & WHAT DOES IT DO

      float hue = i;//determines circle color based on circle number
      fill(hue, 44, 255);//fills circle with that color

      ellipse(x, 1*i, radius*2, radius*2); //draws circle
    }
  }

Solution

  • Essentially what this is doing is doing a vertical cosine curve with a changing amplitude. Here is a link to a similar thing to what the program is doing. https://www.desmos.com/calculator/p9lwmvknkh

    Here is an explanation of this different parts in order. I'm gonna reference some of the variables from the link I provided:

    float offset = frameCount * 0.01
    

    What this is doing is determining how quickly the cosine curve is animating. It is the "a" value from desmos. To have the program run, each ellipse must change its angle in the cosine function just a little bit each frame so that it moves. frameCount is a variable that stores the current amount of frames that the animation/sketch has run for, and it goes up every frame, similar to the a-value being animated.

    for (int i = 1; i <= circlenumber; ++i) {
          float angle = i*19 + offset;
    

    This here is responsible for determining how far from the top the current ellipse should be, modified by a stretching factor. It's increasing each time so that each ellipse is slightly further along in the cosine curve. This is equivalent to the 5(y+a) from desmos. The y-value is the i as it is the dependent variable. That is the case because for each ellipse we need to determine how far it is from the top and then how far it is from the centre. The offset is the a-value because of the reasons discussed above.

    float x = width/2 + cos(angle) * amplitude
    

    This calculates how far the ellipse is from the centre of the screen (x-centre, y value is determined for each ellipse by which ellipse it is). The width/2 is simply moving all of the ellipses around the centre line. If you notice on Desmos, the center line is y-axis. Since in Processing, if something goes off screen (either below 0 or above width), we don't actually see it, the tutorial said to offset it so the whole thing shows. The cos(angle)*amplitude is essentially the whole function on Desmos. cos(angle) is the cosine part, while amplitude is the stuff before that. What this can be treated as is essentially just a scaled version of the dependent variable. On desmos, what I'm doing is sqrt(-y+4) while the tutorial essentially did sqrt(25*i). Every frame, the total (area) is reset to 0. Every time we draw a circle, we increase it by the pi * r^2 (area of circle). That is where the dependent variable (i) comes in. If you notice, they write float amplitude = sqrt( total / PI ); so the pi from the area is cancelled out.

    One thing to keep in mind is that the circles aren't actually moving down, it's all an illusion. To demonstrate this, here is some modified code that will draw lines. If you track a circle along the line, you'll notice that it doesn't actually move down.

    void setup()
      {
        size(500,500);
        frameRate(15);
      }
    
      void draw()
      { 
        background(0); //fills background with black
        noStroke(); //gets rid of stroke
    
        int circlenumber = 999;// determines how many circles will be drawn 
        float radius = 5; //radius of each small circle
        float area = (radius) * (radius) * PI; //area of each small circle
        float total = 0; //total areas of circles already drawn
        float offset = frameCount * 0.01; //HOW DOES IT WORK & WHAT DOES IT DO
    
        for (int i = 1; i <= circlenumber; ++i) { // loops through all of the circles making up the pattern
    
          float angle = i*19 + offset; //HOW DOES IT WORK & WHAT DOES IT DO
          total += area; // adds up the areas of all the small circles that have already been drawn
          float amplitude = sqrt( total / PI ); //amplitude of trigonometric spiral
          float x = width/2 + cos(angle) * amplitude;//HOW DOES IT WORK & WHAT DOES IT DO
    
          float hue = i;//determines circle color based on circle number
          fill(hue, 44, 255);//fills circle with that color
    
          stroke(hue,44,255);
          if(i%30 == 0)
              line(0,i,width,i);
    
          ellipse(x, i, radius*2, radius*2); //draws circle
        }
      }
    

    Hopefully this helps clarify some of the issues with understanding.