วิธีแมป atan2 () ถึงองศา 0-360


108

atan2(y, x) มีความไม่ต่อเนื่องที่ 180 °ซึ่งจะเปลี่ยนเป็น -180 ° ..0 °ไปตามเข็มนาฬิกา

ฉันจะจับคู่ช่วงของค่าเป็น 0 ° ..360 °ได้อย่างไร

นี่คือรหัสของฉัน:

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

ฉันกำลังคำนวณทิศทางของเหตุการณ์การสัมผัสที่ปัดตามstartPointและendPointโครงสร้างจุด XY ทั้งสอง รหัสนี้ใช้สำหรับ iPhone แต่ภาษาใดก็ได้ที่รองรับatan2f()จะทำ


หมายเหตุ: วิธีการอัปเดตที่โพสต์จะไม่คืนค่าศูนย์องศา แต่มีค่าตั้งแต่ 0 ถึง 360.0
chux - คืนสถานะ Monica

2
> [วิธีรับมุมจาก 2 ตำแหน่ง] [1] [1]: stackoverflow.com/questions/9457988/…
MAnoj Sarnaik

ฟังก์ชันนี้ใช้งานได้ดี แต่มุมของการคำนวณ "bearingDegrees" จะพลิก ตัวอย่างเช่นโดยทั่วไปแล้ว 45 องศาจะอยู่ข้างจตุภาคที่ 1 อย่างไรก็ตามสิ่งนี้ในจตุภาคที่ 4 โดยทั่วไปแล้ว 135 องศาจะอยู่ในควอดแรนท์ที่ 2 แต่ฟังก์ชันนี้จะคืนค่าให้อยู่ในควอดแรนต์ที่ 3 ฉันสามารถใช้ค่าส่งคืนฟังก์ชัน x และลบจาก 360 เพื่อให้ได้ค่ามุมที่ถูกต้อง แต่ฉันอยากรู้ว่าทำไมสิ่งนี้ถึงเกิดขึ้นตั้งแต่แรก?
goelv

คำตอบ:


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

6
อาจต้องการ x> = 0 สำหรับกรณี x = 0
bpw1621

13
สำหรับผู้ที่ไม่คุ้นเคยกับสัญกรณ์นี้และไม่มีการแปลงเป็นองศาในตัว: if (x> 0) {เรเดียน = x;} else {เรเดียน = 2 * PI + x;} ดังนั้นเราจะเพิ่ม 2PI ให้กับผลลัพธ์ถ้า มันน้อยกว่า 0
David Doria

1
หรือ(x >= 0 ? x : (2*PI + x)) * 180/PIใน(x < 0 ? 2*PI + x : x) * 180/PI
user3342816

97

วิธีแก้ปัญหาโดยใช้ Modulo

วิธีง่ายๆที่ตอบสนองทุกกรณี

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

คำอธิบาย

บวก: 1 ถึง 180

หากคุณแก้ไขจำนวนบวกใด ๆ ระหว่าง 1 ถึง 180 x 360 คุณจะได้ตัวเลขเดียวกันกับที่คุณใส่ไว้ Mod ที่นี่เพื่อให้แน่ใจว่าตัวเลขบวกเหล่านี้จะถูกส่งกลับเป็นค่าเดียวกัน

ค่าลบ: -180 ถึง -1

การใช้ mod ที่นี่จะส่งคืนค่าในช่วง 180 และ 359 องศา

กรณีพิเศษ: 0 และ 360

การใช้ mod หมายความว่าจะส่งคืน 0 ทำให้เป็นโซลูชัน 0-359 องศาที่ปลอดภัย


3
โซลูชั่นที่ยอดเยี่ยม :)
Qadir Hussain

5
ฉันไม่เชื่อว่าจำเป็นต้องเพิ่ม 360 -1% 360 ยังคงเป็น 359 :)
pleasemorebacon

11
ฉันไม่คิดว่านี่จะถูกต้องในทุกภาษา ใน Javascript-1 % 360 = -1
Startec

ยังไม่ใช่แนวทางที่ใช้ได้ผลใน Java
Hulk

1
@pleasemorebacon ไม่ถูกต้อง ในบางภาษา -1% 360 คือ -1
Pharap

40

เพิ่ม 360 °ถ้าคำตอบจาก atan2 น้อยกว่า 0 °


6
ซึ่งเป็นเช่นเดียวกับ "เพียงแค่เพิ่ม 2 * PI" ถ้าคุณมีหนึ่งในบรรดาวัน
Chris O

33

หรือถ้าคุณไม่ชอบการแตกแขนงให้ลบพารามิเตอร์สองตัวและเพิ่ม 180 °ในคำตอบ

(การเพิ่ม 180 °ไปยังค่าที่ส่งคืนจะทำให้อยู่ในช่วง 0-360 ได้ดี แต่จะพลิกมุมการลบพารามิเตอร์อินพุตทั้งสองจะพลิกกลับ)


2
ขอบคุณนี่คือสิ่งที่ฉันกำลังมองหา
Jeremy Herrman

2
ฉันอยากจะแก้ไขโค้ดของฉันให้ใช้มุมที่ผิดปกติ (<0,> = 360) แต่ดูเหมือนว่าจะมีใครบางคนมุ่งเป้าไปที่ความรู้สึก "ปรับให้เหมาะสม" ของปลอม นั่นคือเหตุผลที่ฉันต้องการเพิ่มสิ่งนี้ (หรือเป็นเพราะนี่เป็นวิธีที่เร็วกว่าในการแก้ปัญหาโค้ดชั่วคราวที่ฉันใช้หืม)
aib

1
ไม่ตรงไปตรงมาอย่างแน่นอนเพราะฉันสามารถเห็นด้วยหลังจาก 2 ปีขึ้นไป ดังนั้น: การเพิ่ม 180 °ไปยังค่าส่งคืนจะทำให้อยู่ในช่วง 0-360 ได้ดี แต่จะพลิกมุม การลบพารามิเตอร์อินพุตทั้งสองจะพลิกกลับ
aib

ปัญหานี้อาจมีปัญหาเมื่อ $ x = 0 $ และ $ y> 0 $ iirc
Trinidad

22

@erikkallen อยู่ใกล้ แต่ไม่ค่อยถูกต้อง

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

สิ่งนี้ควรใช้งานได้ใน C ++: (ขึ้นอยู่กับวิธีการนำ fmod มาใช้อาจเร็วหรือช้ากว่านิพจน์เงื่อนไข)

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

หรือคุณสามารถทำได้:

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

เนื่องจาก (x, y) และ (-x, -y) ต่างกันในมุม 180 องศา


ถ้าฉันเข้าใจคุณถูกต้องใน Fortran มันคือ atan2 (-y, -x) * 180 / PI + 180 ถูกต้องหรือไม่?
gansub

ขอโทษฉันไม่รู้จัก FORTRAN แต่คณิตศาสตร์ของคุณดูถูกต้อง
Jason S

12

ฉันมีวิธีแก้ปัญหา 2 วิธีที่ดูเหมือนจะใช้ได้กับการผสม x และ y ทั้งหมด

1) การละเมิด atan2 ()

ตามเอกสาร atan2 ใช้พารามิเตอร์ y และ x ตามลำดับนั้น อย่างไรก็ตามหากคุณย้อนกลับคุณสามารถทำสิ่งต่อไปนี้:

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

2) ใช้ atan2 () อย่างถูกต้องและแปลงในภายหลัง

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

คุณชายเป็นผู้ช่วยชีวิต เพิ่งใช้แนวทางนี้ใน Unity และทำงานได้อย่างมีเสน่ห์
porfiriopartida

7

@ Jason S: ตัวแปร "fmod" ของคุณจะไม่ทำงานกับการใช้งานที่เป็นไปตามมาตรฐาน มาตรฐาน C นั้นชัดเจนและชัดเจน (7.12.10.1, "the fmod functions"):

ถ้า y ไม่ใช่ศูนย์ผลลัพธ์จะมีเครื่องหมายเดียวกับ x

ดังนั้น

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

เป็นเพียงการเขียนซ้ำอย่างละเอียดของ:

atan2(y,x)/M_PI*180

อย่างไรก็ตามคำแนะนำที่สามของคุณเป็นจุดที่ชัดเจน


5

นี่คือสิ่งที่ฉันทำตามปกติ:

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


2

ทางเลือกอื่นคือการใช้ฟังก์ชันmod () ที่กำหนดเป็น:

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

จากนั้นด้วยฟังก์ชั่นดังต่อไปนี้มุมระหว่างINI (x, y)และจบ (x, y)จุดที่จะได้รับ มุมจะแสดงเป็นองศาปกติถึง [0, 360] องศา และทิศเหนืออ้างอิง 360 องศา

    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 package geosphere จะคำนวณ bearingRhumb ซึ่งเป็นเส้นแบริ่งคงที่โดยกำหนดจุดกำเนิดและทิศตะวันออก / ทิศเหนือ ทิศตะวันออกและทิศตะวันออกเฉียงเหนือต้องอยู่ในเมทริกซ์หรือเวกเตอร์ จุดกำเนิดของกุหลาบลมคือ 0,0 ดูเหมือนว่ารหัสต่อไปนี้จะช่วยแก้ปัญหาได้ทันที:

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 องศากลายเป็น (-1 + 360) = 359 องศา
-179 องศากลายเป็น (-179 + 360) = 181 องศา


คืออะไรMath.PI? มันเหมือนกับM_PI?
ปัง

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

นี่จะกลับองศาจาก 0 ° -360 °ทวนเข็มนาฬิกา, 0 °คือที่ 3 นาฬิกา


1

สูตรที่มีช่วงของค่าตั้งแต่ 0 ถึง 360 องศา

f (x, y) = 180-90 * (1 + เครื่องหมาย (x)) * (1-sign (y ^ 2)) - 45 * (2 + sign (x)) * sign (y)

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

คุณช่วยอธิบายได้ไหมว่าสิ่งนี้เกี่ยวข้องกับคำถามนี้อย่างไร
Klaus Gütter

1

นี่คือจาวาสคริปต์ เพียงแค่ใส่ค่า x และ y

var angle = (Math.atan2(x,y) * (180/Math.PI) + 360) % 360;
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.