2012-04-02 21 views
32

Muszę obliczyć kąt w stopniach między dwoma punktami dla mojej własnej klasy punktowej, punkt a będzie punktem centralnym.Java: Obliczanie kąta między dwoma punktami w stopniach

Metoda:

public float getAngle(Point target) { 
    return (float) Math.toDegrees(Math.atan2(target.x - x, target.y - y)); 
} 

Test 1: // zwraca 45

Point a = new Point(0, 0); 
    System.out.println(a.getAngle(new Point(1, 1))); 

Test 2: // Zwraca -90 oczekuje: 270

Point a = new Point(0, 0); 
    System.out.println(a.getAngle(new Point(-1, 0))); 

jaki sposób można przekonwertować Zwrócony wynik na liczbę od 0 do 359?

+7

Właśnie zauważyłem, że ATAN2 argumenty są w odwrotnej kolejności: należy atan2 (y, x) – alexm

+0

Nie wiem co jest nie tak, ale moje zamówienie działa dobrze, w odwrotnej kolejności nie. – Aich

+2

Możesz zmierzyć kąt między trzema punktami. Możesz założyć, że '(0, 0)' lub '(min (x1, x2), min (y1, y2)) jest jednym z punktów, ale nie możesz narysować kąta między dwoma punktami. –

Odpowiedz

58

można dodać następujące:

public float getAngle(Point target) { 
    float angle = (float) Math.toDegrees(Math.atan2(target.y - y, target.x - x)); 

    if(angle < 0){ 
     angle += 360; 
    } 

    return angle; 
} 

przy okazji, dlaczego chcesz, aby nie używać podwójnego tutaj?

+0

Ponieważ kąt na chwilę spadnie tylko poniżej 0, nie widzę powodu, aby używać tu pętli while. – Makoto

+0

tak, myślę, że nie musisz ... edytować. –

+0

Metodę tę nazywam setkami razy w ramce gry. Myślę, że mam trochę więcej wydajności z mniejszą precyzją i nie potrzebuję też dodatkowych cyfr. – Aich

1

Javadoc dla Math.atan(double) jest całkiem jasne, że powracająca wartość może wynosić od -pi/2 do pi/2. Musisz więc zrekompensować tę wartość zwracaną.

22

Zacząłem od rozwiązania z johncarls, ale potrzebowałem go dostosować, aby uzyskać dokładnie to, czego potrzebowałem. Głównie, potrzebowałem go, aby obracać się zgodnie z ruchem wskazówek zegara, gdy kąt wzrósł. Potrzebowałem również 0 stopni, by wskazać NORTH. Jego rozwiązanie zbliżyło mnie do siebie, ale zdecydowałem się również opublikować moje rozwiązanie, na wypadek gdyby pomogło to komukolwiek innemu.

Dodałem kilka dodatkowych komentarzy, które pomagają wyjaśnić moją wiedzę na temat funkcji na wypadek konieczności wprowadzenia prostych modyfikacji.

/** 
* Calculates the angle from centerPt to targetPt in degrees. 
* The return should range from [0,360), rotating CLOCKWISE, 
* 0 and 360 degrees represents NORTH, 
* 90 degrees represents EAST, etc... 
* 
* Assumes all points are in the same coordinate space. If they are not, 
* you will need to call SwingUtilities.convertPointToScreen or equivalent 
* on all arguments before passing them to this function. 
* 
* @param centerPt Point we are rotating around. 
* @param targetPt Point we want to calcuate the angle to. 
* @return angle in degrees. This is the angle from centerPt to targetPt. 
*/ 
public static double calcRotationAngleInDegrees(Point centerPt, Point targetPt) 
{ 
    // calculate the angle theta from the deltaY and deltaX values 
    // (atan2 returns radians values from [-PI,PI]) 
    // 0 currently points EAST. 
    // NOTE: By preserving Y and X param order to atan2, we are expecting 
    // a CLOCKWISE angle direction. 
    double theta = Math.atan2(targetPt.y - centerPt.y, targetPt.x - centerPt.x); 

    // rotate the theta angle clockwise by 90 degrees 
    // (this makes 0 point NORTH) 
    // NOTE: adding to an angle rotates it clockwise. 
    // subtracting would rotate it counter-clockwise 
    theta += Math.PI/2.0; 

    // convert from radians to degrees 
    // this will give you an angle from [0->270],[-180,0] 
    double angle = Math.toDegrees(theta); 

    // convert to positive range [0-360) 
    // since we want to prevent negative angles, adjust them now. 
    // we can assume that atan2 will not return a negative value 
    // greater than one partial rotation 
    if (angle < 0) { 
     angle += 360; 
    } 

    return angle; 
} 
+1

Zamiast dodawać Pi/2 (niedokładne przybliżenie) do wartości radianowej przed zamianą na stopnie, bardziej sensownym byłoby dodanie 90 po konwersji na stopnie. –

+0

Czy możesz to zrobić również dla radianów? ** Edycja: ** Nieważne - po prostu usuwasz wywołanie'Math.toDegrees'. – starbeamrainbowlabs

1

Co o czymś takim:

angle = angle % 360; 
+1

Ale .. Nie mamy kąta! – Joehot200

1
angle = Math.toDegrees(Math.atan2(target.x - x, target.y - y)); 

teraz orientacji wartości okrągłych zachować kąt pomiędzy 0 a 359 może być:

angle = angle + Math.ceil(-angle/360) * 360 
1

podstawie Saad Ahmed's answer tutaj to metoda, która może być użyta dla dowolnych dwóch punktów.

public static double calculateAngle(double x1, double y1, double x2, double y2) 
{ 
    double angle = Math.toDegrees(Math.atan2(x2 - x1, y2 - y1)); 
    // Keep angle between 0 and 360 
    angle = angle + Math.ceil(-angle/360) * 360; 

    return angle; 
} 
+0

to nie jest standardowa metoda. – FrankK

+0

@FrankK Usunąłem "rodzajowy" jako deskryptor –