14

Imagine I have drawn a circle with center coordinates (cx,cy) on the screen and a random point (A) is selected on the circle.

trigonometric circle

By having the the coordinates of point A, I need to find the angle of (a).

Update:

I have tried using the following formula:

Math.toDegrees(Math.asin(((x - cx) / radius).toDouble()))

which is actually the reverse of (the circle is created by feeding angles to this one):

x = radius * Math.sin(Math.toRadians(angle.toDouble())) + cx
y = radius * Math.cos(Math.toRadians(angle.toDouble())) + cy

But since the y coordinate is not present in the formula the answer could be wrong.

Bandreid
  • 2,727
  • 28
  • 47
2hamed
  • 8,719
  • 13
  • 69
  • 112

4 Answers4

17

If you know the cartesian coordinates of the point A(x,y), then you can find the angle theta by converting it into polar coordinates as below:

double theta = Math.toDegrees(Math.atan2(y - cy, x - cx));

This formula works if your X axis is in 0 degrees, otherwise you need to consider the offset.

Nabin Bhandari
  • 15,949
  • 6
  • 45
  • 59
  • 1
    Thanks, but the problem here is that this formula can not differentiate between quadrants correctly. This formula always return an angle from 0 to 180. – 2hamed Sep 24 '17 at 08:14
  • You can figure out the angle using CAST rule, eg. if both x and y are positive the angle is same, and if both x and y are negative the angle is theta+180 – Nabin Bhandari Sep 24 '17 at 08:23
  • 2
    @HamedMomeni so did you check the `Math` package documentation? *"This method computes the phase theta by computing an arc tangent of y/x in the range of -pi to pi"* – pskink Sep 24 '17 at 08:23
  • 1
    @pskink you are correct. `System.out.println(Math.toDegrees(Math.atan2(2,2)));` prints 45 whereas `System.out.println(Math.toDegrees(Math.atan2(-2,-2)));` prints -135. – Nabin Bhandari Sep 24 '17 at 08:27
4

I think the method you are looking for i Math.atan2 which computes the angle to an x and y cordinate. I have now modified the code to adjust for putting 0 degrees downwards. I have also flipped the y-axis to put 0, 0 cordinate in the upper left corner (screen coordinates), and adjusted degrees above 180 to be reported as negative degrees:

public double theta(int cx, int cy, int x, int y)
{
    double angle = Math.toDegrees(Math.atan2(cy - y, x - cx)) + 90;
    return angle <= 180? angle: angle - 360;
}

A small test to verify some angles...

@Test
public void test()
{
    assertThat(theta(50, 50, 60, 50), is(90.0));
    assertThat(theta(50, 50, 50, 60), is(0.0));
    assertThat(theta(50, 50, 40, 50), is(-90.0));
    assertThat(theta(50, 50, 50, 40), is(180.0));
}
Per Huss
  • 4,755
  • 12
  • 29
  • 2
    right answer but... the direction is reversed and the starting point is offset by pi / 2 - so i dont think the OP accepts it as he wants the fish, not the fishing rod – pskink Sep 24 '17 at 08:29
3

You can find the tangent angles and add to 90 or substruct from 270 that angle and find the result, I believe. I design the code like your drawing. You can make it more generic, I guess. You have 4 area:

  1. 0 degree to 90 degree
  2. 90 degree to 180 degree
  3. 90 degree to -90(270) degree
  4. -90(270) degree to 0(360) degree

Code:

public static double findAngle(double x,  double y,
                               double cx, double cy, double radius){
    double beta, alfa;

    double distanceX = Math.abs(Math.abs(x) - Math.abs(cx));
    double distanceY = Math.abs(Math.abs(y) - Math.abs(cy));

    // check the point is on the circle or not
    // with euchlid
    if (radius != Math.sqrt(x * x + y * y)) {
        return -1;
    }

    if (x >= cx && y <= cy) {
        // find tangent
        beta = Math.atan(distanceY / distanceX);
        alfa = 90 - beta;
        return alfa;
    }
    // 90-180 -> second area
    else if (x >= cx && y >= cy) {
        beta = Math.atan(distanceY / distanceX);
        alfa = 90 + beta;
        return alfa;
    }
    // 180 - -90 -> third area
    else if (x <= cx && y >= cy) {
        beta = Math.atan(distanceY / distanceX);
        alfa = 270 - beta;
        return alfa;
    }
    // -90 - 0 -> forth area
    else if (x <= cx && y <= cy) {
        beta = Math.atan(distanceY / distanceX);
        alfa = 270 + beta;
        if (alfa == 360) {
            alfa = 0;
        }
        return alfa;    
    } 
    else {
        return -1;
    }
}
Yunnosch
  • 26,130
  • 9
  • 42
  • 54
Oguz
  • 1,867
  • 1
  • 17
  • 24
2

The main catch with Atan2 is the center point. If your center is offset (Cx, Cy) and not at the origin and you want to find the arc angle between (X1, Y1) and (X2, Y2) then I would suggest this approach:

double startAngle = Math.Atan2(Y1-Cy, X1-Cx);
double endAngle = Math.Atan2(Y2-Cy, X2-Cx);
double ArcAngle = endangle - startAngle;
Lore
  • 1,286
  • 1
  • 22
  • 57