Cách ánh xạ atan2 () sang độ 0-360


108

atan2(y, x) có sự gián đoạn đó ở 180 ° trong đó nó chuyển sang -180 ° ..0 ° theo chiều kim đồng hồ.

Làm cách nào để ánh xạ phạm vi giá trị đến 0 ° ..360 °?

đây là mã của tôi:

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

Tôi đang tính toán hướng của một sự kiện chạm khi vuốt dựa trên startPointendPointcả hai cấu trúc điểm XY. Mã dành cho iPhone nhưng bất kỳ ngôn ngữ nào hỗ trợ atan2f()sẽ làm được.


Lưu ý: Phương thức cập nhật đã đăng sẽ không trả về 0 độ mà là các giá trị từ trên 0 đến 360.0.
Chux - Khôi phục Monica

2
> [Cách lấy góc từ 2 vị trí] [1] [1]: stackoverflow.com/questions/9457988/…
MAnoj Sarnaik

Chức năng này hoạt động tốt, tuy nhiên góc của phép tính "MangDegrees" bị lật. ví dụ: 45 độ thường sẽ theo góc phần tư thứ nhất, tuy nhiên điều này ở góc phần tư thứ 4. 135 độ thường sẽ ở góc phần tư thứ 2 nhưng hàm này trả về nó ở góc phần tư thứ 3. tôi có thể chỉ cần lấy giá trị trả về của hàm x và phủ định giá trị đó từ 360 để có được giá trị góc chính xác tuy nhiên tôi rất tò mò muốn biết tại sao điều này lại xảy ra ngay từ đầu?
goelv

Câu trả lời:


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

6
Có lẽ cũng muốn x> = 0 cho trường hợp x = 0.
bpw1621,

13
Đối với những người không thoải mái với ký hiệu này và không có chuyển đổi sang độ được tích hợp sẵn: if (x> 0) {radians = x;} else {radians = 2 * PI + x;}, vì vậy chúng tôi chỉ thêm 2PI vào kết quả nếu nó nhỏ hơn 0.
David Doria

1
Hoặc (x >= 0 ? x : (2*PI + x)) * 180/PInhư trong(x < 0 ? 2*PI + x : x) * 180/PI
user3342816

97

Giải pháp sử dụng Modulo

Một giải pháp đơn giản mà bắt tất cả các trường hợp.

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

Giải trình

Tích cực: 1 đến 180

Nếu bạn sửa đổi bất kỳ số dương nào từ 1 đến 180 x 360, bạn sẽ nhận được chính xác số mà bạn đã nhập. Việc sửa đổi ở đây chỉ đảm bảo các số dương này được trả về cùng một giá trị.

Tiêu cực: -180 đến -1

Sử dụng mod ở đây sẽ trả về giá trị trong khoảng 180 và 359 độ.

Các trường hợp đặc biệt: 0 và 360

Sử dụng mod có nghĩa là 0 được trả về, làm cho đây là giải pháp 0-359 độ an toàn.


3
giải pháp tuyệt vời :)
Qadir Hussain

5
Tôi không tin rằng cần phải thêm 360. -1% 360 vẫn là 359 :)
pleasemorebacon

11
Tôi không nghĩ rằng điều này là đúng trong tất cả các ngôn ngữ. Trong Javascript-1 % 360 = -1
Startec

Cũng không phải là một cách tiếp cận khả thi trong Java
Hulk

1
@pleasemorebacon Không chính xác. Trong một số ngôn ngữ -1% 360 là -1.
Pharap

40

Chỉ cần thêm 360 ° nếu câu trả lời từ atan2 nhỏ hơn 0 °.


6
Tương tự như "chỉ thêm 2 * PI" nếu bạn đang gặp một trong những ngày đó.
Chris O

33

Hoặc nếu bạn không thích phân nhánh, chỉ cần phủ định hai tham số và thêm 180 ° vào câu trả lời.

(Việc thêm 180 ° vào giá trị trả về sẽ đặt giá trị đó dễ dàng trong phạm vi 0-360, nhưng làm lệch góc. Việc điều chỉnh cả hai thông số đầu vào sẽ lật ngược lại.)


2
Cảm ơn, đây chỉ là những gì tôi đang tìm kiếm.
Jeremy Herrman

2
Tôi muốn sửa đổi mã của mình để sử dụng các góc không chuẩn hóa (<0,> = 360) nhưng dường như luôn có ai đó nhắm đến cảm giác "tối ưu hóa" giả mạo đó; đó là lý do tại sao tôi muốn thêm điều này. (Hay là vì đây là cách nhanh hơn để giải quyết một số mã gỡ lỗi tạm thời mà tôi đã sử dụng? Hmm)
aib

1
Chắc chắn không dễ để tìm hiểu, vì tôi có thể đồng tình sau hơn 2 năm. Vì vậy: Việc thêm 180 ° vào giá trị trả về sẽ đặt nó độc đáo trong phạm vi 0-360, nhưng làm lệch góc. Việc điều chỉnh cả hai thông số đầu vào sẽ lật ngược lại.
aib

Điều này có thể có một số vấn đề khi $ x = 0 $ và $ y> 0 $ iirc
Trinidad

22

@erikkallen gần gũi nhưng không hoàn toàn đúng.

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

Điều này sẽ hoạt động trong C ++: (tùy thuộc vào cách fmod được triển khai, nó có thể nhanh hơn hoặc chậm hơn so với biểu thức điều kiện)

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

Ngoài ra, bạn có thể làm điều này:

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

vì (x, y) và (-x, -y) khác nhau về góc 180 độ.


nếu tôi hiểu bạn đúng ở Fortran thì nó là atan2 (-y, -x) * 180 / PI + 180. Có đúng không?
gansub 19/07/2016

xin lỗi tôi không biết FORTRAN. Nhưng toán học của bạn có vẻ đúng.
Jason S

11

Tôi có 2 giải pháp dường như hoạt động cho tất cả các kết hợp của x và y tích cực và tiêu cực.

1) Lạm dụng atan2 ()

Theo tài liệu atan2 lấy tham số y và x theo thứ tự đó. Tuy nhiên, nếu bạn đảo ngược chúng, bạn có thể làm như sau:

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

2) Sử dụng atan2 () một cách chính xác và chuyển đổi sau đó

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

Ngài là một vị cứu tinh. Chỉ cần sử dụng cách tiếp cận này trong Unity và hoạt động như một sự quyến rũ.
porfiriopartida

7

@Jason S: biến thể "fmod" của bạn sẽ không hoạt động khi triển khai tuân thủ tiêu chuẩn. Tiêu chuẩn C rõ ràng và rõ ràng (7.12.10.1, "các hàm fmod"):

nếu y khác không, kết quả có cùng dấu với x

do đó,

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

thực ra chỉ là một bản viết lại dài dòng của:

atan2(y,x)/M_PI*180

Tuy nhiên, gợi ý thứ ba của bạn là đúng.


5

Đây là những gì tôi thường làm:

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;

Tôi đã thực hiện một Công thức cho góc định hướng thành 0 đến 360

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

2

Một giải pháp thay thế là sử dụng hàm mod () được định nghĩa là:

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

Khi đó, với hàm số sau, ta nhận được góc giữa điểm ini (x, y)điểm cuối (x, y) . Góc được biểu thị bằng độ được chuẩn hóa thành [0, 360] độ. và Bắc tham chiếu 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

Geosphere của gói R sẽ tính toán mangRhumb, là một đường mang không đổi cho một điểm gốc và nới lỏng / hướng đông bắc. Việc nới lỏng và hướng đông bắc phải nằm trong ma trận hoặc vectơ. Điểm gốc của một bông hồng là 0,0. Đoạn mã sau dường như dễ dàng giải quyết sự cố:

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 độ trở thành (-1 + 360) = 359 độ
-179 độ trở thành (-179 + 360) = 181 độ


Là gì Math.PI? Nó có giống với M_PIkhông?
Pang

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

Điều này sẽ trả về độ từ 0 ° -360 ° ngược chiều kim đồng hồ, 0 ° ở vị trí 3 giờ.


1

Một công thức để có phạm vi giá trị từ 0 đến 360 độ.

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

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

Bạn có thể vui lòng giải thích làm thế nào điều này liên quan đến câu hỏi?
Klaus Gütter

1

Đây là một số javascript. Chỉ cần nhập các giá trị x và y.

var angle = (Math.atan2(x,y) * (180/Math.PI) + 360) % 360;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.