atan2() -> I don't really get what this is doing / difference from atan()

edited March 2015 in Programming Questions

From the docs :

atan2()

Calculates the angle (in radians) from a specified point to the coordinate origin as measured from the positive x-axis. Values are returned as a float in the range from PI to -PI. The atan2() function is most often used for orienting geometry to the position of the cursor. Note: The y-coordinate of the point is the first parameter, and the x-coordinate is the second parameter, due the the structure of calculating the tangent

atan()

The inverse of tan(), returns the arc tangent of a value. This function expects the values in the range of -Infinity to Infinity (exclusive) and values are returned in the range -PI/2 to PI/2


I'm not too sure what the real difference is here though. I get that atan2() is generally used instead of atan() for movement, and I've seen it work better, but I don't really understand why this is.

Can anyone explain further please?

thanks

Answers

  • edited March 2015 Answer ✓

    Let's start off by mentioning what tan() does, just to make sure we're on the same page.

    ATAN

    The tangent method computes the ratio between the triangle's base length, and its height (3/3), given an angle. The problem with this method is that if you take the triangle's opposite (the one with a width and height of -3), you will get the same result as for the first.

    Now to the inverse of tan(). atan() takes that ratio, and converts it back to an angle. But it doesn't know whether the ratio came from a division of two negatives, or two positives, so it just assumes the latter.

    This is why atan() can cover only half a circle (-PI/2 to PI/2). The atan2() method was created to fix this issue. The reason I stated above is the very reason that it takes two arguments, and not one.

    Because atan2() can take two values, it can determine whether the angle is at 45 degrees, or at the completely opposite side of the circle.

    Here's an example code of the two methods in action:

    void setup() {
      size(300, 300);
    }
    
    void draw() {
      background(160);
    
      PVector atn = new PVector(-1, 0);
      atn.rotate(atan(height/2 - mouseX == 0 & height/2 - mouseY == 0 ? 0 : (float) (height/2 - mouseY)/(width/2 - mouseX))); //The atan() method.
      atn.mult(100);
      atn.add(width/2, height/2, 0);
    
      line(width/2, height/2, atn.x, atn.y);
    
      PVector atn2 = new PVector(-1, 0);
      atn2.rotate(atan2(height/2 - mouseY, width/2 - mouseX)); //The atan2() method.
      atn2.mult(100);
      atn2.add(width/2, height/2, 0);
    
      line(width/2, height/2, atn2.x, atn2.y);
    }
    

    Moving your mouse around the window, you will see that one line will warp 180 degrees at one point, while the other keeps following your mouse, no matter what. The first is atan(), and the second is atan2().

    The atan2() method was designed just to cover the limits that atan() can't reach. Nothing more.

  • thanks for that Mente!

    I'm not sure what I'm getting confused with at the moment, I have this code that makes a sin wave. I'm trying to get the sin wave to move slowly, undulate, just be a wave thats not static really.

    I can see that the x position is governed by the for loop, which displaces the ellipses evenly across the screen.

    The y positions are dictated by the sin() function, which is mapped from 0 to height, so the wave fills the screen. In order to position the ellipses at different heights the sin function takes a variable angle as input, which is gradually increased. The more slight the increase of this angle, the more gradual the curve (0.0000001 increase is basically a flat line)

    What I don't see is how to make this wave undulate slowly. The movement is controlled by the frameRate, but obviously changing this (as I have) makes for a poor quality animation.

    I need to add another parameter, but I'm not sure what this could be?

    thanks :)

    here's the code :

    float startAngle = 0;
    float angleVel = 0.2;
    
    void setup(){
        size(600,400);
        frameRate(2);
    }
    
    float angle;
    void draw(){
    
        background(200);
    
        //float angle = startAngle;
        stroke(0);
        strokeWeight(2);
        noFill();
    
        for (int x = 0; x < width; x += 5) {
            float y = map(sin(angle),-1,1,0,height);
            stroke(0);
            fill(0,50);
            ellipse(x,y,48,48);
            angle += angleVel;
        };
    
        //angle += 0.0001;
    
    
    }
    
  • Just thought that I'd edit this!

    Its working, but I'm struggling to explain it to myself. The key is having the startAngle.

    Here's the new code :

    float startAngle = 0;
    float angleVel = 0.4;
    
    void setup(){
        size(600,400);
    }
    
    void draw(){
    
        background(0);
    
        float angle = startAngle;
    
        stroke(0);
        strokeWeight(2);
        noFill();
    
        float num = (width/30);
        float size = num * 1.7; 
        for (int x = 0; x < width; x += num) {
            float y = map(sin(angle),-1,1,0,height);
            noStroke();
            fill(200,150);
            ellipse(x,y,size,size);
            angle += angleVel;
        };
        startAngle += 0.02;
    
        //angle += 0.0001;
    
    
    }
    

    Actually this isn't the key, I've removed this and it still works.

    I'm not sure if there's anything obvious that I'm getting confused with here or not!

    cheers

    float startAngle = 0;
    float angleVel = 0.4;
    
    void setup(){
        size(600,400);
    }
    
    float angle = 0;
    
    void draw(){
    
        background(0);
    
        //float angle = startAngle;
    
        stroke(0);
        strokeWeight(2);
        noFill();
    
        float num = (width/30);
        float size = num * 1.7; 
        for (int x = 0; x < width; x += num) {
            float y = map(sin(angle),-1,1,0,height);
            noStroke();
            fill(200,150);
            ellipse(x,y,size,size);
            angle += angleVel;
        };
        //startAngle += 0.02;
        angle += 0.02;
    
    
    
    }
    
Sign In or Register to comment.