Cara memetakan atan2 () ke derajat 0-360

108

atan2(y, x) memiliki diskontinuitas pada 180 ° di mana ia beralih ke -180 ° ..0 ° searah jarum jam.

Bagaimana cara memetakan rentang nilai ke 0 ° ..360 °?

ini kode saya:

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

Saya sedang menghitung arah acara sentuh menggesek yang diberikan startPointdan endPoint, kedua struktur titik XY. Kode untuk iPhone tetapi bahasa apa pun yang mendukung atan2f()akan dilakukan.

willc2
sumber
Catatan: Metode pembaruan yang diposting tidak akan mengembalikan nol derajat, tetapi nilai dari tepat di atas 0 hingga 360.0.
chux - Kembalikan Monica
2
> [Cara Mendapatkan sudut dari 2 posisi] [1] [1]: stackoverflow.com/questions/9457988/…
MAnoj Sarnaik
Fungsi ini bekerja dengan baik, namun sudut perhitungan "bearingDegrees" dibalik. misalnya, 45 derajat biasanya berada di kuadran pertama, namun ini di kuadran ke-4. 135 derajat biasanya berada di kuadran ke-2 tetapi fungsi ini mengembalikannya ke kuadran ke-3. saya hanya dapat mengambil nilai pengembalian fungsi x dan meniadakannya dari 360 untuk mendapatkan nilai sudut yang benar namun saya penasaran untuk mengetahui mengapa ini terjadi di tempat pertama?
goelv

Jawaban:

66
(x > 0 ? x : (2*PI + x)) * 360 / (2*PI)
erikkallen
sumber
6
Mungkin juga ingin x> = 0 untuk kasus x = 0.
bpw1621
13
Bagi mereka yang tidak nyaman dengan notasi ini, dan tanpa konversi ke derajat bawaan: if (x> 0) {radians = x;} else {radians = 2 * PI + x;} jadi kami hanya menambahkan 2PI ke hasil jika kurang dari 0.
David Doria
1
Atau (x >= 0 ? x : (2*PI + x)) * 180/PIseperti di(x < 0 ? 2*PI + x : x) * 180/PI
user3342816
97

Solusi menggunakan Modulo

Solusi sederhana yang menangkap semua kasus.

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

Penjelasan

Positif: 1 hingga 180

Jika Anda memodifikasi bilangan positif antara 1 dan 180 x 360, Anda akan mendapatkan angka yang sama persis dengan yang Anda masukkan. Mod di sini hanya memastikan bilangan positif ini dikembalikan sebagai nilai yang sama.

Negatif: -180 hingga -1

Menggunakan mod di sini akan mengembalikan nilai dalam kisaran 180 dan 359 derajat.

Kasus khusus: 0 dan 360

Menggunakan mod berarti 0 dikembalikan, menjadikannya solusi 0-359 derajat yang aman.

Liam George Betsworth
sumber
3
solusi yang luar biasa :)
Qadir Hussain
5
Saya tidak percaya perlu menambahkan 360. -1% 360 masih 359 :)
pleasemorebacon
11
Saya rasa ini tidak benar dalam semua bahasa. Dalam Javascript-1 % 360 = -1
Startec
Juga bukan pendekatan yang layak di Jawa
Hulk
1
@pleasemorebacon Salah. Dalam beberapa bahasa -1% 360 adalah -1.
Pharap
40

Tambahkan saja 360 ° jika jawaban dari atan2 kurang dari 0 °.

dave4420
sumber
6
Yang sama dengan "tambahkan saja 2 * PI" jika Anda mengalami salah satu dari hari - hari itu.
Chris O
33

Atau jika Anda tidak suka bercabang, cukup negasikan kedua parameter tersebut dan tambahkan 180 ° ke jawabannya.

(Menambahkan 180 ° ke nilai kembali akan menempatkannya dengan baik dalam kisaran 0-360, tetapi membalik sudutnya. Meniadakan kedua parameter masukan akan membalikkannya kembali.)

aib
sumber
2
Terima kasih, inilah yang saya cari.
Jeremy Herrman
2
Saya lebih suka memodifikasi kode saya untuk menggunakan sudut yang dinormalisasi (<0,> = 360) tetapi sepertinya selalu ada seseorang yang membidik kesan palsu "dioptimalkan"; itulah mengapa saya ingin menambahkan ini. (Atau apakah karena ini adalah cara
tercepat
1
Jelas tidak mudah untuk pergi, karena saya bisa setuju setelah 2+ tahun. Jadi: Menambahkan 180 ° ke nilai yang dikembalikan menempatkannya dengan baik dalam kisaran 0-360, tetapi membalik sudutnya. Meniadakan kedua parameter input akan membalikkannya kembali.
aib
Ini dapat mengalami beberapa masalah ketika $ x = 0 $ dan $ y> 0 $ iirc
Trinidad
22

@erikkallen sudah dekat tetapi kurang tepat.

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

Ini seharusnya berfungsi di C ++: (bergantung pada bagaimana fmod diimplementasikan, ini mungkin lebih cepat atau lebih lambat daripada ekspresi kondisional)

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

Alternatifnya, Anda bisa melakukan ini:

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

karena (x, y) dan (-x, -y) berbeda sudut sebesar 180 derajat.

Jason S
sumber
jika saya memahami Anda dengan benar di Fortran, itu adalah atan2 (-y, -x) * 180 / PI + 180. Apakah itu benar?
gansub
maaf saya tidak tahu FORTRAN. Tapi matematikamu sepertinya benar.
Jason S
11

Saya memiliki 2 solusi yang tampaknya berfungsi untuk semua kombinasi x dan y positif dan negatif.

1) Penyalahgunaan atan2 ()

Menurut dokumen atan2 mengambil parameter y dan x dalam urutan itu. Namun jika Anda membalikkannya, Anda dapat melakukan hal berikut:

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

2) Gunakan atan2 () dengan benar dan konversikan sesudahnya

double degrees = std::atan2(y, x) * 180 / M_PI;
if (degrees > 90)
{
    degrees = 450 - degrees;
}
else
{
    degrees = 90 - degrees;
}
Fibbles
sumber
Anda tuan, adalah penyelamat hidup. Baru saja menggunakan pendekatan ini di Unity dan berfungsi seperti pesona.
porfiriopartida
7

@Jason S: varian "fmod" Anda tidak akan berfungsi pada penerapan yang sesuai standar. Standar C eksplisit dan jelas (7.12.10.1, "fungsi fmod"):

jika y bukan nol, hasilnya memiliki tanda yang sama dengan x

jadi,

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

sebenarnya hanyalah penulisan ulang yang panjang dari:

atan2(y,x)/M_PI*180

Saran ketiga Anda, bagaimanapun, tepat.

Stephen Canon
sumber
5

Inilah yang biasanya saya lakukan:

float rads = atan2(y, x);
if (y < 0) rads = M_PI*2.f + rads;
float degrees = rads*180.f/M_PI;
andrés
sumber
2
angle = Math.atan2(x,y)*180/Math.PI;

Saya telah membuat Formula untuk mengarahkan sudut menjadi 0 hingga 360

angle + Math.ceil( -angle / 360 ) * 360;
Saad Ahmed
sumber
2

Solusi alternatifnya adalah dengan menggunakan fungsi mod () yang didefinisikan sebagai:

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

Kemudian, dengan fungsi berikut, diperoleh sudut antara titik ini (x, y) dan ujung (x, y) . Sudut tersebut dinyatakan dalam derajat yang dinormalisasi menjadi [0, 360] derajat. dan referensi Utara 360 derajat.

    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);
    }
A. Torrez Garay
sumber
1

Geosfer paket R akan menghitung bearingRhumb, yang merupakan garis bantalan konstan yang diberi titik asal dan arah timur / utara. The easting dan northing harus berupa matriks atau vektor. Titik asal mawar angin adalah 0,0. Kode berikut tampaknya siap menyelesaikan masalah:

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)
Ariane
sumber
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 derajat menjadi (-1 + 360) = 359 derajat
-179 derajat menjadi (-179 + 360) = 181 derajat

PhilC
sumber
Apa Math.PI? Apakah itu sama dengan M_PI?
Pang
1
double degree = fmodf((atan2(x, y) * (180.0 / M_PI)) + 360, 360);

Ini akan mengembalikan derajat dari 0 ° -360 ° berlawanan arah jarum jam, 0 ° pada pukul 3.

Finallz
sumber
1

Rumus yang memiliki rentang nilai dari 0 hingga 360 derajat.

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

     -(180/pi())*sign(x*y)*atan((abs(x)-abs(y))/(abs(x)+abs(y)))
theodore panagos
sumber
Bisakah Anda menjelaskan bagaimana ini berhubungan dengan pertanyaan?
Klaus Gütter
1

Berikut beberapa javascript. Masukkan saja nilai x dan y.

var angle = (Math.atan2(x,y) * (180/Math.PI) + 360) % 360;
squarcle
sumber