Come mappare atan2 () ai gradi 0-360


108

atan2(y, x) ha quella discontinuità a 180 ° dove passa a -180 ° ..0 ° andando in senso orario.

Come faccio a mappare l'intervallo di valori a 0 ° ..360 °?

ecco il mio codice:

CGSize deltaPoint = CGSizeMake(endPoint.x - startPoint.x, endPoint.y - startPoint.y);
float swipeBearing = atan2f(deltaPoint.height, deltaPoint.width);

Sto calcolando la direzione di un evento di tocco di scorrimento dato startPointe endPoint, entrambe le strutture del punto XY. Il codice è per l'iPhone, ma qualsiasi lingua che supporti atan2f()lo farà.


Nota: il metodo di aggiornamento pubblicato non restituirà zero gradi, ma valori da appena sopra 0 a 360.0.
chux - Ripristina Monica il

2
> [Come ottenere l'angolo da 2 posizioni] [1] [1]: stackoverflow.com/questions/9457988/...
Manoj Sarnaik

Questa funzione funziona alla grande, tuttavia l'angolo del calcolo "BearingDegrees" viene invertito. ad esempio, 45 gradi sarebbero tipicamente dal 1 ° quadrante, tuttavia questo nel 4 ° quadrante. 135 gradi sarebbero tipicamente nel 2 ° quadrante, ma questa funzione restituisce che si trova nel 3 ° quadrante. posso semplicemente prendere il valore di ritorno della funzione x e negarlo da 360 per ottenere il valore dell'angolo corretto, tuttavia sono curioso di sapere perché questo sta accadendo in primo luogo?
goelv

Risposte:


66
(x > 0 ? x : (2*PI + x)) * 360 / (2*PI)

6
Probabilmente vuoi anche x> = 0 per il caso x = 0.
bpw1621

13
Per coloro che non sono a proprio agio con questa notazione e senza la conversione in gradi incorporata: if (x> 0) {radians = x;} else {radians = 2 * PI + x;} quindi stiamo solo aggiungendo 2PI al risultato se è inferiore a 0.
David Doria

1
O (x >= 0 ? x : (2*PI + x)) * 180/PIcome in(x < 0 ? 2*PI + x : x) * 180/PI
user3342816

97

Soluzione che utilizza Modulo

Una soluzione semplice che cattura tutti i casi.

degrees = (degrees + 360) % 360;  // +360 for implementations where mod returns negative numbers

Spiegazione

Positivo: da 1 a 180

Se modifichi un numero positivo compreso tra 1 e 180 per 360, otterrai lo stesso numero che hai inserito. Mod qui garantisce che questi numeri positivi vengano restituiti con lo stesso valore.

Negativo: da -180 a -1

L'uso di mod qui restituirà valori nell'intervallo di 180 e 359 gradi.

Casi speciali: 0 e 360

L'uso di mod significa che viene restituito 0, rendendolo una soluzione sicura da 0 a 359 gradi.


3
soluzioni fantastiche :)
Qadir Hussain

5
Non credo sia necessario aggiungere 360. -1% 360 è ancora 359 :)
pleaseemorebacon

11
Non penso che sia corretto in tutte le lingue. In Javascript-1 % 360 = -1
Startec

Inoltre non è un approccio praticabile in Java
Hulk

1
@pleasemorebacon Errato. In alcune lingue -1% 360 è -1.
Pharap

40

Basta aggiungere 360 ​​° se la risposta da atan2 è inferiore a 0 °.


6
Che equivale a "aggiungi solo 2 * PI" se hai uno di quei giorni.
Chris O

33

Oppure, se non ti piace la ramificazione, nega semplicemente i due parametri e aggiungi 180 ° alla risposta.

(L'aggiunta di 180 ° al valore di ritorno lo colloca piacevolmente nell'intervallo 0-360, ma ribalta l'angolo. La negazione di entrambi i parametri di input lo ribalta indietro.)


2
Grazie, è proprio quello che stavo cercando.
Jeremy Herrman

2
Preferirei modificare il mio codice per utilizzare angoli denormalizzati (<0,> = 360) ma sembra che ci sia sempre qualcuno che mira a quella falsa sensazione "ottimizzata"; ecco perché ho voluto aggiungere questo. (O era perché questo era il modo più veloce per aggirare il codice di debug temporaneo che ho usato?
Hmm

1
Sicuramente non è semplice da brontolare, dato che posso essere d'accordo dopo 2+ anni. Quindi: l'aggiunta di 180 ° al valore di ritorno lo colloca piacevolmente nell'intervallo 0-360, ma inverte l'angolo. La negazione di entrambi i parametri di input lo fa tornare indietro.
aprile

Questo può avere alcuni problemi quando $ x = 0 $ e $ y> 0 $ iirc
Trinidad

22

@erikkallen è vicino ma non del tutto corretto.

theta_rad = atan2(y,x);
theta_deg = (theta_rad/M_PI*180) + (theta_rad > 0 ? 0 : 360);

Questo dovrebbe funzionare in C ++: (a seconda di come fmod è implementato, potrebbe essere più veloce o più lento dell'espressione condizionale)

theta_deg = fmod(atan2(y,x)/M_PI*180,360);

In alternativa potresti fare questo:

theta_deg = atan2(-y,-x)/M_PI*180 + 180;

poiché (x, y) e (-x, -y) differiscono in angoli di 180 gradi.


se ti ho capito correttamente in Fortran è atan2 (-y, -x) * 180 / PI + 180. È corretto?
gansub

scusa non conosco FORTRAN. Ma la tua matematica sembra giusta.
Jason S

11

Ho 2 soluzioni che sembrano funzionare per tutte le combinazioni di x e y positive e negative.

1) Abuso atan2 ()

Secondo la documentazione, atan2 accetta i parametri y e x in quest'ordine. Tuttavia, se li inverti puoi fare quanto segue:

double radians = std::atan2(x, y);
double degrees = radians * 180 / M_PI;
if (radians < 0)
{
    degrees += 360; 
}

2) Usa atan2 () correttamente e poi converti

double degrees = std::atan2(y, x) * 180 / M_PI;
if (degrees > 90)
{
    degrees = 450 - degrees;
}
else
{
    degrees = 90 - degrees;
}

Signore, sei un salvatore di vita. Ho appena usato questo approccio in Unity e funziona come un fascino.
porfiriopartida

7

@ Jason S: la tua variante "fmod" non funzionerà su un'implementazione conforme agli standard. Lo standard C è esplicito e chiaro (7.12.10.1, "le funzioni fmod"):

se y è diverso da zero, il risultato ha lo stesso segno di x

in tal modo,

fmod(atan2(y,x)/M_PI*180,360)

in realtà è solo una verbosa riscrittura di:

atan2(y,x)/M_PI*180

Il tuo terzo suggerimento, tuttavia, è perfetto.


5

Questo è quello che faccio normalmente:

float rads = atan2(y, x);
if (y < 0) rads = M_PI*2.f + rads;
float degrees = rads*180.f/M_PI;

2
angle = Math.atan2(x,y)*180/Math.PI;

Ho creato una formula per l'orientamento dell'angolo da 0 a 360

angle + Math.ceil( -angle / 360 ) * 360;

2

Una soluzione alternativa è utilizzare la funzione mod () definita come:

function mod(a, b) {return a - Math.floor (a / b) * b;}

Quindi, con la seguente funzione, si ottiene l'angolo tra i punti ini (x, y) e end (x, y) . L'angolo è espresso in gradi normalizzati a [0, 360] gradi. e Nord con riferimento a 360 gradi.

    function angleInDegrees(ini, end) {
        var radian = Math.atan2((end.y - ini.y), (end.x - ini.x));//radian [-PI,PI]
        return mod(radian * 180 / Math.PI + 90, 360);
    }

1

La geosfera dei pacchetti R calcolerà il cuscinetto Rhumb, che è una linea di rilevamento costante dato un punto di origine e direzione est / nord. L'est e il nord devono essere in una matrice o vettore. Il punto di origine di una rosa dei venti è 0,0. Il codice seguente sembra risolvere prontamente il problema:

windE<-wind$uasE
windN<-wind$vasN
wind_matrix<-cbind(windE, windN)
wind$wind_dir<-bearingRhumb(c(0,0), wind_matrix)
wind$wind_dir<-round(wind$wind_dir, 0)

1
theta_rad = Math.Atan2(y,x);
if(theta_rad < 0)
  theta_rad = theta_rad + 2 * Math.PI;    //if neg., add 2 PI to it
theta_deg = (theta_rad/M_PI*180) ;        //convert from radian to degree

//or
theta_rad = Math.Atan2(y,x);
theta_rad = (theta_rad < 0) ? theta_rad + 2 * Math.PI : theta_rad;
theta_deg = (theta_rad/M_PI*180) ;

-1 gradi diventa (-1 + 360) = 359 gradi
-179 gradi diventa (-179 + 360) = 181 gradi


Cosa Math.PI? È lo stesso di M_PI?
Pang

1
double degree = fmodf((atan2(x, y) * (180.0 / M_PI)) + 360, 360);

Questo restituirà il grado da 0 ° -360 ° in senso antiorario, 0 ° è a ore 3.


1

Una formula per avere un intervallo di valori compreso tra 0 e 360 ​​gradi.

f (x, y) = 180-90 * (1 + segno (x)) * (1 segno (y ^ 2)) - 45 * (2 + segno (x)) * segno (y)

     -(180/pi())*sign(x*y)*atan((abs(x)-abs(y))/(abs(x)+abs(y)))

Puoi spiegare come questo si collega alla domanda?
Klaus Gütter

1

Ecco alcuni javascript. Basta inserire i valori x e y.

var angle = (Math.atan2(x,y) * (180/Math.PI) + 360) % 360;
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.