2012-04-02 22 views
32

Ho bisogno di calcolare l'angolo in gradi tra due punti per la mia propria classe di punti, il punto a è il punto centrale.Java: calcolo dell'angolo tra due punti in gradi

Metodo:

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

Test 1: // ritorna 45

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

Test 2: // ritorna -90, prevede: 270

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

Come posso convertire il risultato restituito in un numero compreso tra 0 e 359?

+7

appena notato che ATAN2 argomenti sono in ordine inverso: devono essere atan2 (y, x) – alexm

+0

Non so che cosa va male, ma il mio ordine funziona bene, l'ordine inverso no. – Aich

+2

È possibile misurare solo l'angolo tra tre punti. Potresti assumere '(0, 0)' o '(min (x1, x2), min (y1, y2))' è uno dei punti ma non puoi disegnare un angolo tra due punti. –

risposta

58

si potrebbe aggiungere il seguente:

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; 
} 

a proposito, perché vuoi di non utilizzare una doppia qui?

+0

Dato che l'angolo dovrebbe essere sempre inferiore a 0 per un istante, non vedo alcun motivo per utilizzare un ciclo while qui. – Makoto

+0

sì, immagino che non devi ... modificato. –

+0

Io chiamo questo metodo centinaia di volte in una cornice di gioco. Credo di avere un po 'più di prestazioni con meno precisione e inoltre non ho bisogno delle cifre aggiuntive. – Aich

1

Il javadoc per Math.atan(double) è abbastanza chiaro che il valore restituito può variare da -pi/2 a pi/2. Quindi è necessario compensare per quel valore di ritorno.

22

Ho iniziato con la soluzione johncarls, ma avevo bisogno di regolarlo per ottenere esattamente ciò di cui avevo bisogno. Principalmente, avevo bisogno che ruotasse in senso orario quando l'angolo aumentava. Avevo anche bisogno di 0 gradi per puntare NORD. La sua soluzione mi ha avvicinato, ma ho deciso di pubblicare la mia soluzione anche nel caso in cui aiutasse qualcun altro.

Ho aggiunto alcuni commenti aggiuntivi per aiutare a spiegare la mia comprensione della funzione nel caso in cui sia necessario apportare semplici modifiche.

/** 
* 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

Invece di aggiungere Pi/2 (un'approssimazione approssimativa) al valore radiante prima di convertirlo in gradi, avrebbe più senso aggiungere 90 dopo che è stato convertito in gradi. –

+0

Puoi farlo anche per i radianti? ** Modifica: ** Non importa: basta rimuovere la chiamata 'Math.toDegrees'. – starbeamrainbowlabs

1

Che dire qualcosa come:

angle = angle % 360; 
+1

Ma .. Non abbiamo l'angolo! – Joehot200

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

ora l'orientamento dei valori circolari per mantenere l'angolo compreso tra 0 e 359 può essere:

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

Sulla base di Saad Ahmed's answer, qui è un metodo che può essere utilizzato per qualsiasi due punti.

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

questo non è un metodo generico – FrankK

+0

@FrankK Ho rimosso "generico" come descrittore –

Problemi correlati