So ordnen Sie atan2 () den Graden 0-360 zu


108

atan2(y, x) hat diese Diskontinuität bei 180 °, wo sie im Uhrzeigersinn auf -180 ° ..0 ° umschaltet.

Wie ordne ich den Wertebereich 0 ° ..360 ° zu?

Hier ist mein Code:

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

Ich Berechnung der Richtung eines streichBerührungsEreignis angesichts der startPointund endPointbeide XY Punkt structs. Der Code ist für das iPhone, aber jede Sprache, die atan2f()dies unterstützt , reicht aus.


Hinweis: Die veröffentlichte Aktualisierungsmethode gibt keine Nullgrade zurück, sondern Werte von knapp über 0 bis 360,0.
chux

2
> [Wie man Winkel von 2 Positionen erhält
MAnoj Sarnaik

Diese Funktion funktioniert hervorragend, jedoch wird der Winkel der Berechnung der "Lagergrade" umgedreht. Zum Beispiel würden 45 Grad typischerweise durch den 1. Quadranten, jedoch dies im 4. Quadranten. 135 Grad befinden sich normalerweise im 2. Quadranten, aber diese Funktion gibt zurück, dass sie sich im 3. Quadranten befinden. Ich kann einfach den Funktionsrückgabewert x nehmen und diesen von 360 negieren, um den richtigen Winkelwert zu erhalten. Ich bin jedoch gespannt, warum dies überhaupt geschieht.
Goelv

Antworten:


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

6
Möchte wahrscheinlich auch x> = 0 für den Fall x = 0.
bpw1621

13
Für diejenigen, die mit dieser Notation nicht vertraut sind und keine Umrechnung in eingebaute Grade vornehmen: if (x> 0) {radians = x;} else {radians = 2 * PI + x;}, also addieren wir nur 2PI zum Ergebnis if es ist weniger als 0.
David Doria

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

97

Lösung mit Modulo

Eine einfache Lösung, die alle Fälle erfasst.

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

Erläuterung

Positiv: 1 bis 180

Wenn Sie eine positive Zahl zwischen 1 und 180 mal 360 modifizieren, erhalten Sie genau die gleiche Zahl, die Sie eingegeben haben. Mod hier stellt nur sicher, dass diese positiven Zahlen als der gleiche Wert zurückgegeben werden.

Negativ: -180 bis -1

Wenn Sie hier mod verwenden, werden Werte im Bereich von 180 bis 359 Grad zurückgegeben.

Sonderfälle: 0 und 360

Die Verwendung von mod bedeutet, dass 0 zurückgegeben wird, was dies zu einer sicheren Lösung von 0-359 Grad macht.


3
tolle Lösungen :)
Qadir Hussain

5
Ich glaube nicht, dass es notwendig ist, 360 hinzuzufügen. -1% 360 ist immer noch 359 :)
Pleasemorebacon

11
Ich denke nicht, dass dies in allen Sprachen richtig ist. In Javascript-1 % 360 = -1
Startec

Auch kein praktikabler Ansatz in Java
Hulk

1
@pleasemorebacon Falsch. In einigen Sprachen ist -1% 360 -1.
Pharap

40

Fügen Sie einfach 360 ° hinzu, wenn die Antwort von atan2 weniger als 0 ° beträgt.


6
Das ist das gleiche wie "nur 2 * PI hinzufügen", wenn Sie einen dieser Tage haben.
Chris O

33

Oder wenn Sie keine Verzweigung mögen, negieren Sie einfach die beiden Parameter und fügen Sie der Antwort 180 ° hinzu.

(Wenn Sie dem Rückgabewert 180 ° hinzufügen, liegt er gut im Bereich von 0 bis 360, dreht aber den Winkel um. Wenn Sie beide Eingabeparameter negieren, wird er zurückgedreht.)


2
Danke, das ist genau das, wonach ich gesucht habe.
Jeremy Herrman

2
Ich würde meinen Code lieber ändern, um denormalisierte Winkel (<0,> = 360) zu verwenden, aber es scheint immer jemanden zu geben, der auf dieses falsche "optimierte" Gefühl abzielt. deshalb wollte ich das hinzufügen. (Oder lag es daran, dass dies der schnellere Weg war, um einen von mir verwendeten temporären Debug-Code zu umgehen? Hmm)
aib

1
Auf jeden Fall nicht einfach zu groken, da ich nach 2+ Jahren zustimmen kann. Also: Wenn Sie dem Rückgabewert 180 ° hinzufügen, liegt er gut im Bereich von 0 bis 360, dreht aber den Winkel um. Wenn Sie beide Eingabeparameter negieren, wird es zurückgeschaltet.
Aib

Dies kann einige Probleme haben, wenn $ x = 0 $ und $ y> 0 $ iirc
Trinidad

22

@erikkallen ist nah aber nicht ganz richtig.

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

Dies sollte in C ++ funktionieren: (Je nachdem, wie fmod implementiert ist, kann es schneller oder langsamer sein als der bedingte Ausdruck)

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

Alternativ können Sie dies tun:

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

da (x, y) und (-x, -y) sich in den Winkeln um 180 Grad unterscheiden.


Wenn ich Sie in Fortran richtig verstanden habe, ist es atan2 (-y, -x) * 180 / PI + 180. Ist das richtig?
Gansub

Entschuldigung, ich kenne FORTRAN nicht. Aber deine Mathematik sieht richtig aus.
Jason S

11

Ich habe 2 Lösungen, die für alle Kombinationen von positivem und negativem x und y zu funktionieren scheinen.

1) Missbrauch atan2 ()

Gemäß den Dokumenten nimmt atan2 die Parameter y und x in dieser Reihenfolge. Wenn Sie sie jedoch umkehren, können Sie Folgendes tun:

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

2) Verwenden Sie atan2 () korrekt und konvertieren Sie anschließend

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

Sie, mein Herr, sind ein Lebensretter. Habe gerade diesen Ansatz in Unity verwendet und funktioniert wie ein Zauber.
Porfiriopartida

7

@Jason S: Ihre "fmod" -Variante funktioniert bei einer standardkonformen Implementierung nicht. Der C-Standard ist explizit und klar (7.12.10.1, "die fmod-Funktionen"):

Wenn y ungleich Null ist, hat das Ergebnis das gleiche Vorzeichen wie x

so,

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

ist eigentlich nur eine ausführliche Umschreibung von:

atan2(y,x)/M_PI*180

Ihr dritter Vorschlag ist jedoch genau richtig.


5

Das mache ich normalerweise:

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;

Ich habe eine Formel zum Ausrichten des Winkels in 0 bis 360 erstellt

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

2

Eine alternative Lösung besteht darin, die Funktion mod () zu verwenden, die wie folgt definiert ist:

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

Dann wird mit der folgenden Funktion der Winkel zwischen den Punkten ini (x, y) und end (x, y) erhalten. Der Winkel wird in Grad ausgedrückt, die auf [0, 360] Grad normiert sind. und Nord mit 360 Grad.

    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

Die Geosphäre des R-Pakets berechnet die PeilungRumb, eine konstante Peilungslinie bei gegebenem Ursprungspunkt und Ost / Nord. Die Ost- und Nordrichtung muss in einer Matrix oder einem Vektor liegen. Der Ursprungspunkt für eine Windrose ist 0,0. Der folgende Code scheint das Problem leicht zu beheben:

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 ° wird (-1 + 360) = 359 °
-179 ° wird (-179 + 360) = 181 °


Was ist Math.PI? Ist es das gleiche wie M_PI?
Pang

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

Dies gibt den Grad von 0 ° -360 ° gegen den Uhrzeigersinn zurück, 0 ° ist um 3 Uhr.


1

Eine Formel für den Wertebereich von 0 bis 360 Grad.

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

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

Können Sie bitte erklären, wie dies mit der Frage zusammenhängt?
Klaus Gütter

1

Hier ist etwas Javascript. Geben Sie einfach x- und y-Werte ein.

var angle = (Math.atan2(x,y) * (180/Math.PI) + 360) % 360;
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.