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);

startPointendPoint두 XY 포인트 구조체가 주어지면 스 와이프 터치 이벤트의 방향을 계산하고 있습니다. 코드는 iPhone 용이지만 지원하는 모든 언어가 가능합니다 atan2f().


참고 : 게시 된 업데이트 메서드는 0도를 반환하지 않지만 0에서 360.0 바로 위의 값을 반환합니다.
chux - 분석 재개 모니카

2
> [1] [2 개 위치에서 각도를 얻는 방법] [1] : stackoverflow.com/questions/9457988/...
마노 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 2011

13
이 표기법에 익숙하지 않고 내장 된 각도로의 변환이없는 사람들을 위해 : if (x> 0) {radians = x;} else {radians = 2 * PI + x;} 그래서 우리는 결과에 2PI를 더합니다. 덜 0보다
데이비드 도리아

1
또는에서 (x >= 0 ? x : (2*PI + x)) * 180/PI와 같이(x < 0 ? 2*PI + x : x) * 180/PI
user3342816 2014

97

모듈로를 사용한 솔루션

모든 경우를 포착하는 간단한 솔루션입니다.

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

설명

양수 : 1 ~ 180

1과 180 사이의 양수를 360으로 변형하면 입력 한 것과 똑같은 숫자를 얻게됩니다. 여기서 Mod는이 양수가 동일한 값으로 반환되도록합니다.

음수 : -180 ~ -1

여기서 mod를 사용하면 180도에서 359도 범위의 값이 반환됩니다.

특수한 경우 : 0 및 360

mod를 사용하면 0이 반환되어 안전한 0-359도 솔루션이됩니다.


3
멋진 솔루션 :)
Qadir Hussain

5
360을 추가 할 필요가 없다고 생각합니다. -1 % 360은 여전히 ​​359입니다. :)
pleasemorebacon

11
나는 이것이 모든 언어에서 정확하다고 생각하지 않습니다. 자바 스크립트-1 % 360 = -1
Startec

자바도하지 실용적인 접근 방식
헐크

1
@pleasemorebacon 틀 렸습니다. 일부 언어에서 -1 % 360은 -1입니다.
Pharap

40

atan2의 답이 0 °보다 작 으면 360 ° 만 추가하면됩니다.


6
날 중 하나가 있는 경우 "2 * PI 추가"와 동일 합니다.
Chris O

33

또는 분기가 마음에 들지 않으면 두 매개 변수를 부정하고 답에 180 °를 더하세요.

(반환 값에 180 °를 더하면 0-360 범위에 멋지게 배치되지만 각도가 반전됩니다. 두 입력 매개 변수를 모두 부정하면 다시 반전됩니다.)


2
고마워요, 제가 찾던 바로 그것입니다.
Jeremy Herrman

2
비정규 화 된 각도 (<0,> = 360)를 사용하도록 내 코드를 수정하고 싶지만 항상 가짜 "최적화 된"느낌을 목표로하는 사람이있는 것 같습니다. 그래서 이것을 추가하고 싶었습니다. (?이 흠 내가 사용하는 몇 가지 임시 코드를 디버깅하는 주위에 빠른 방법이기 때문에 또는 그 것이었다)
AIB

1
2 년 이상이 지난 후에 동의 할 수 있기 때문에 grok에게 확실히 간단하지 않습니다. 따라서 반환 값에 180 °를 더하면 0-360 범위에 멋지게 배치되지만 각도가 뒤집 힙니다. 두 입력 매개 변수를 모두 부정하면 다시 반전됩니다.
aib

이것은 $ IIRC 몇 가지 문제 $ X = 0 $ 및 $ Y> 0을 가질 수 있습니다
트리니다드

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

11

양수와 음수 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, "fmod 함수") :

y가 0이 아니면 결과는 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
angle = Math.atan2(x,y)*180/Math.PI;

각도를 0에서 360으로 맞추는 공식을 만들었습니다.

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

2

다른 해결책은 다음과 같이 정의 된 mod () 함수 를 사용하는 것입니다.

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

그런 다음 다음 함수를 사용하여 ini (x, y)end (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 패키지 geosphere는 원점과 동쪽 / 북쪽이 주어진 일정한 방위선 인 bearingRhumb을 계산합니다. Easting과 Northing은 행렬 또는 벡터에 있어야합니다. 바람 장미의 원점은 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합니까?
Pang

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- 기호 (y ^ 2))-45 * (2+ 기호 (x)) * 기호 (y)

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

이것이 질문과 어떤 관련이 있는지 설명해 주시겠습니까?
Klaus Gütter 2018

1

여기에 자바 스크립트가 있습니다. x와 y 값만 입력하면됩니다.

var angle = (Math.atan2(x,y) * (180/Math.PI) + 360) % 360;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.