Atan2 () ile 0-360 derece eşleme nasıl yapılır


108

atan2(y, x) 180 ° 'de saat yönünde -180 ° ..0 °' ye geçiş yaptığı süreksizliğe sahiptir.

Değer aralığını 0 ° ..360 ° ile nasıl eşlerim?

İşte kodum:

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

Bana verilen bir darbe dokunmatik olayın yönünü hesap yapıyorum startPointve endPoint, XY hem nokta yapılar. Kod iPhone içindir, ancak destekleyen herhangi bir dil işe yarar atan2f().


Not: Gönderilen güncelleme yöntemi sıfır derece döndürmez, ancak 0 ile 360.0'ın hemen üzerindeki değerler verir.
chux

2
> [2 konumdan nasıl açı alınır] [1] [1]: stackoverflow.com/questions/9457988/…
MAnoj Sarnaik

Bu işlev harika çalışıyor, ancak "BearingDegrees" hesaplamasının açısı ters çevrildi. örneğin, 45 derece tipik olarak 1. çeyrekte olur, ancak bu 4. kadranda olur. 135 derece tipik olarak 2. kadranda olacaktır, ancak bu fonksiyon onu 3. kadranda döndürür. x fonksiyonunun dönüş değerini basitçe alabilir ve bunu 360'tan doğru açı değerini elde etmek için reddedebilirim, ancak bunun neden ilk etapta olduğunu merak ediyorum.
goelv

Yanıtlar:


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

6
Muhtemelen x = 0 durumu için x> = 0 da istenir.
bpw1621

13
Bu gösterimden memnun olmayanlar ve yerleşik derecelere dönüştürülmeyenler için: if (x> 0) {radyan = x;} else {radyan = 2 * PI + x;} bu nedenle sonuca sadece 2PI ekliyoruz eğer 0'dan az
David Doria

1
Veya (x >= 0 ? x : (2*PI + x)) * 180/PIolduğu gibi(x < 0 ? 2*PI + x : x) * 180/PI
user3342816

97

Modulo kullanarak çözüm

Tüm vakaları yakalayan basit bir çözüm.

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

Açıklama

Pozitif: 1 ila 180

1 ile 180'e 360 ​​arasında herhangi bir pozitif sayıyı değiştirirseniz, girdiğiniz sayının aynısını alırsınız. Buradaki Mod, bu pozitif sayıların aynı değer olarak döndürülmesini sağlar.

Negatif: -180 ila -1

Burada modu kullanmak, 180 ve 359 derece aralığında değerler döndürür.

Özel durumlar: 0 ve 360

Mod kullanılması, 0'ın döndürüldüğü anlamına gelir, bu da bunu 0-359 derece güvenli bir çözüm haline getirir.


3
müthiş çözümler :)
Qadir Hussain

5
360 eklemenin gerekli olduğuna inanmıyorum. -1% 360, hala 359 :)
pleasemorebacon

11
Bunun tüm dillerde doğru olduğunu düşünmüyorum. Javascript'te-1 % 360 = -1
Startec

Java'da da geçerli bir yaklaşım değil
Hulk

1
@pleasemorebacon Yanlış. Bazı dillerde -1% 360 -1'dir.
Pharap

40

Atan2'den gelen cevap 0 ° 'den küçükse 360 ​​° eklemeniz yeterli.


6
O günlerden birini yaşıyorsanız "sadece 2 * PI ekleyin" ile aynıdır .
Chris O

33

Veya dallanmayı sevmiyorsanız, sadece iki parametreyi olumsuzlayın ve yanıta 180 ° ekleyin.

(Dönüş değerine 180 ° eklemek, onu 0-360 aralığına güzel bir şekilde yerleştirir, ancak açıyı çevirir. Her iki giriş parametresinin de reddedilmesi onu geri döndürür.)


2
Teşekkürler, tam da aradığım buydu.
Jeremy Herrman

2
Kodumu normal olmayan açıları (<0,> = 360) kullanacak şekilde değiştirmeyi tercih ederim, ancak her zaman bu sahte "optimize edilmiş" hissi hedefleyen biri var gibi görünüyor; bu yüzden bunu eklemek istedim. (Yoksa kullandığım bazı geçici hata ayıklama kodlarının daha hızlı yolu bu olduğu için miydi? Hmm)
aib

1
2+ yıldan sonra aynı fikirde olabileceğim için kesinlikle kolay değil. Yani: Dönüş değerine 180 ° eklemek onu 0-360 aralığına güzel bir şekilde sokar, ancak açıyı çevirir. Her iki giriş parametresinin de reddedilmesi onu geri döndürür.
aib

$ X = 0 $ ve $ y> 0 $ iirc
Trinidad

22

@erikkallen yakın ama tam olarak doğru değil.

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

Bu, C ++ 'da çalışmalıdır: (fmod'un nasıl uygulandığına bağlı olarak, koşullu ifadeden daha hızlı veya daha yavaş olabilir)

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

Alternatif olarak şunu yapabilirsiniz:

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

(x, y) ve (-x, -y) açıları 180 derece farklı olduğundan.


sizi Fortran'da doğru anladıysam, atan2 (-y, -x) * 180 / PI + 180'dir. Doğru mu?
gansub

üzgünüm FORTRAN'ı bilmiyorum. Ama matematiğiniz doğru görünüyor.
Jason S

11

Pozitif ve negatif x ve y'nin tüm kombinasyonları için işe yarayan 2 çözümüm var.

1) Suistimal atan2 ()

Belgelere göre atan2, y ve x parametrelerini bu sırayla alır. Ancak bunları tersine çevirirseniz aşağıdakileri yapabilirsiniz:

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

2) atan2 () 'yi doğru kullanın ve daha sonra dönüştürün

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

Siz bayım, hayat kurtarıcısınız. Sadece bu yaklaşımı Unity'de kullandım ve bir cazibe gibi çalışıyor.
porfiriopartida

7

@Jason S: "fmod" varyantınız standartlara uygun bir uygulama üzerinde çalışmayacaktır. C standardı açık ve nettir (7.12.10.1, "fmod fonksiyonları"):

y sıfır değilse, sonuç x ile aynı işarete sahip olur

Böylece,

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

aslında aşağıdakilerin ayrıntılı bir şekilde yeniden yazılmasıdır:

atan2(y,x)/M_PI*180

Ancak üçüncü öneriniz yerinde.


5

Normalde yaptığım şey bu:

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;

Açıyı 0 ila 360'a yönlendirmek için bir formül yaptım

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

2

Alternatif bir çözüm, şu şekilde tanımlanan mod () işlevini kullanmaktır :

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

Daha sonra aşağıdaki fonksiyonla ini (x, y) ve bitiş (x, y) noktaları arasındaki açı elde edilir. Açı, [0, 360] dereceye normalleştirilmiş derece cinsinden ifade edilir. ve Kuzey, 360 dereceye referans veriyor.

    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

R paketleri jeosfer, bir başlangıç ​​noktası ve doğuya / kuzeye doğru verilen sabit bir yatak çizgisi olan BearingRhumb'ı hesaplayacaktır. Doğulaşma ve kuzeye gitme bir matris veya vektör içinde olmalıdır. Bir rüzgar gülünün başlangıç ​​noktası 0,0'dır. Aşağıdaki kod, sorunu kolayca çözüyor gibi görünüyor:

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


Nedir Math.PI? İle aynı M_PImı?
Pang

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

Bu 0 ° -360 ° saat yönünün tersine derece döndürür, 0 ° saat 3 konumunda.


1

0 ila 360 derece değer aralığına sahip bir formül.

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

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

Bunun soruyla nasıl bir ilgisi olduğunu açıklayabilir misiniz?
Klaus Gütter

1

İşte bazı javascript. Sadece x ve y değerlerini girin.

var angle = (Math.atan2(x,y) * (180/Math.PI) + 360) % 360;
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.