Jak odwzorować atan2 () na stopnie 0-360


108

atan2(y, x) ma tę nieciągłość przy 180 °, gdzie przechodzi do -180 °. 0 ° zgodnie z ruchem wskazówek zegara.

Jak odwzorować zakres wartości na 0 ° .,360 °?

oto mój kod:

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

Jestem obliczania kierunek zdarzenia dotyku swiping zważywszy na startPointi endPoint, kodowanym punktowe zarówno XY. Kod jest przeznaczony dla iPhone'a, ale każdy obsługiwany język atan2f()będzie odpowiedni.


Uwaga: metoda opublikowanej aktualizacji nie zwróci zero stopni, ale wartości od nieco powyżej 0 do 360,0.
chux - Przywróć Monikę

2
> [Jak uzyskać kąt z 2 pozycji] [1] [1]: stackoverflow.com/questions/9457988/…
MAnoj Sarnaik

Ta funkcja działa świetnie, jednak kąt obliczania „BearingDegrees” jest odwrócony. na przykład 45 stopni będzie zwykle oznaczane w 1. kwadrancie, jednak w 4. kwadrancie. Zwykle w drugiej ćwiartce znajduje się 135 stopni, ale ta funkcja zwraca wartość w trzeciej ćwiartce. mogę po prostu wziąć wartość zwracaną przez funkcję x i zanegować ją z 360, aby uzyskać prawidłową wartość kąta, ale jestem ciekawy, dlaczego tak się dzieje w pierwszej kolejności?
goelv

Odpowiedzi:


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

6
Prawdopodobnie również chcesz x> = 0 dla przypadku x = 0.
bpw1621

13
Dla tych, którzy nie czują się komfortowo z tą notacją i bez wbudowanej konwersji na stopnie: if (x> 0) {radianów = x;} else {radianów = 2 * PI + x;} więc po prostu dodajemy 2PI do wyniku, jeśli jest mniej niż 0.
David Doria,

1
Albo (x >= 0 ? x : (2*PI + x)) * 180/PIjak w(x < 0 ? 2*PI + x : x) * 180/PI
user3342816

97

Rozwiązanie wykorzystujące Modulo

Proste rozwiązanie, które obejmuje wszystkie przypadki.

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

Wyjaśnienie

Pozytywny: od 1 do 180

Jeśli zmodyfikujesz dowolną liczbę dodatnią z zakresu od 1 do 180 na 360, otrzymasz dokładnie tę samą liczbę, którą wstawiłeś. Mod tutaj tylko zapewnia, że ​​te liczby dodatnie są zwracane jako ta sama wartość.

Ujemna: od -180 do -1

Użycie mod tutaj zwróci wartości z zakresu od 180 do 359 stopni.

Przypadki specjalne: 0 i 360

Użycie mod oznacza, że ​​zwracane jest 0, dzięki czemu jest to bezpieczne rozwiązanie w zakresie 0-359 stopni.


3
super rozwiązania :)
Qadir Hussain

5
Nie wydaje mi się, aby trzeba było dodawać 360. -1% 360 to nadal 359 :)
pleasemorebacon

11
Myślę, że nie jest to poprawne we wszystkich językach. W Javascript-1 % 360 = -1
Startec

Nie jest to również opłacalne podejście w Javie
Hulk,

1
@pleasemorebacon Incorrect. W niektórych językach -1% 360 to -1.
Pharap

40

Po prostu dodaj 360 °, jeśli odpowiedź z atan2 jest mniejsza niż 0 °.


6
Co oznacza „po prostu dodaj 2 * PI”, jeśli masz jeden z tych dni.
Chris O

33

A jeśli nie lubisz rozgałęziania, po prostu zaneguj dwa parametry i dodaj 180 ° do odpowiedzi.

(Dodanie 180 ° do wartości zwracanej ładnie umieszcza ją w zakresie 0-360, ale odwraca kąt. Negowanie obu parametrów wejściowych odwraca ją.)


2
Dzięki, właśnie tego szukałem.
Jeremy Herrman

2
Wolałbym zmodyfikować mój kod, aby używał zdenormalizowanych kątów (<0,> = 360), ale zawsze wydaje się, że ktoś dąży do tego fałszywego „zoptymalizowanego” odczucia; dlatego chciałem to dodać. (A może dlatego, że był to szybszy sposób na obejście tymczasowego kodu debugowania, którego użyłem? Hmm)
aib

1
Zdecydowanie nie jest to łatwe do zrozumienia, co mogę przyznać po ponad 2 latach. Tak więc: dodanie 180 ° do wartości zwracanej ładnie umieszcza ją w zakresie 0-360, ale odwraca kąt. Negacja obu parametrów wejściowych odwraca to.
aib

Może to mieć pewne problemy, gdy $ x = 0 $ i $ y> 0 $ iirc
Trinidad

22

@erikkallen jest blisko, ale nie do końca.

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

To powinno działać w C ++: (w zależności od tego, jak zaimplementowano fmod, może być szybsze lub wolniejsze niż wyrażenie warunkowe)

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

Alternatywnie możesz to zrobić:

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

ponieważ (x, y) i (-x, -y) różnią się kątami o 180 stopni.


jeśli dobrze cię zrozumiałem w Fortranie jest to atan2 (-y, -x) * 180 / PI + 180. Czy to prawda?
gansub

przepraszam, nie znam FORTRANU. Ale twoja matematyka wygląda dobrze.
Jason S

11

Mam 2 rozwiązania, które wydają się działać dla wszystkich kombinacji dodatnich i ujemnych x i y.

1) Nadużycie atan2 ()

Zgodnie z dokumentacją atan2 przyjmuje parametry y i x w tej kolejności. Jeśli jednak je odwrócisz, możesz wykonać następujące czynności:

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

2) Użyj atan2 () poprawnie, a następnie przekonwertuj

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

Panie, jesteś zbawcą życia. Po prostu zastosowałem to podejście w Unity i działa jak urok.
porfiriopartida

7

@Jason S: Twój wariant „fmod” nie będzie działał z implementacją zgodną ze standardami. Standard C jest jasny i przejrzysty (7.12.10.1, „funkcje fmod”):

jeśli y jest niezerowe, wynik ma taki sam znak jak x

a zatem,

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

jest właściwie tylko szczegółowym przepisaniem:

atan2(y,x)/M_PI*180

Twoja trzecia sugestia jest jednak trafna.


5

To jest to, co zwykle robię:

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;

Zrobiłem wzór na ustawienie kąta w zakresie od 0 do 360

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

2

Alternatywnym rozwiązaniem jest użycie funkcji mod () zdefiniowanej jako:

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

Następnie za pomocą następującej funkcji uzyskuje się kąt między punktami ini (x, y) i końcowymi (x, y) . Kąt jest wyrażony w stopniach znormalizowanych do [0, 360] stopni. i północ w odniesieniu do 360 stopni.

    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

Geosfera pakietów R obliczy BearingRhumb, który jest stałą linią namiaru z podanym punktem początkowym i współrzędną wschodnią / północną. Kierunek wschodni i północ muszą znajdować się w macierzy lub wektorze. Punkt początkowy róży wiatrów to 0,0. Poniższy kod wydaje się łatwo rozwiązać problem:

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
st staje się (-1 + 360) = 359 st -179 st staje się (-179 + 360) = 181 st


Co Math.PI? Czy to jest to samo co M_PI?
Pang

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

Spowoduje to zwrócenie stopnia od 0 ° -360 ° w kierunku przeciwnym do ruchu wskazówek zegara, 0 ° oznacza godzinę 3.


1

Formuła mająca zakres wartości od 0 do 360 stopni.

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

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

Czy możesz wyjaśnić, jak to się ma do pytania?
Klaus Gütter

1

Oto trochę javascript. Wystarczy wprowadzić wartości x i y.

var angle = (Math.atan2(x,y) * (180/Math.PI) + 360) % 360;
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.