Accumulated Angle

보통 회전(rotation)하는 양을 나타낼 때 [0,360) 범위의 숫자를 사용한다. 이러한 경우에 361º는 (360+1)º와 동일한 방향(orientation)을 나타내므로 1º로 표기한다. 그런데, 가끔 이러한 범위 제약 없이 연속적으로 누적하여 회전량을 표기해야 할 필요성이 있을 때가 있다. 예를 들어보자. 1 프레임(frame) 마다 1도씩 시계 방향으로 회전하는 애니메이션(animation)을 만든다고 생각해보자. 이러한 애니메이션(animation)의 데이터 순서는 다음과 같다.

0, 1, 2, …, 359, 0, 1, 2, …, 359, 0, 1, 2, …, 359, 0, 1, 2, …

하지만, 우리가 원하는 것은 다음과 같은 데이터이다.

0, 1, 2, …, 359, 360, 361, 362, …, 719, 720, 721, 722, …, 1079, 1080, 1081, 1082, …

첫 번째 시퀀스(sequence)가 주어져 있을 때, 두 번째 시퀀스(sequence)를 만들어 내려면 어떻게 해야 할까?

우선 다음의 두 가지 알아야 할 사실들을 정리해보자.

[알아야할 사실 1]
수직선(數直線, number line) 상에서 오른쪽에 있는 수가 왼쪽에 있는 수 보다 더 크다. 마찬가지로 왼쪽에 있는 수는 오른쪽에 있는 수 보다 더 작다. 그리고, 두 수 사이의 거리는 “(큰 수) – (작은 수)”로 구할 수 있다. 수직선 상의 어떤 수에 다른 양수를 더해주면 오른쪽으로 이동하고, 다른 양수를 빼주면 왼쪽으로 이동한다.

[알아야할 사실 2]
회전 각도에 360의 배수를 더하거나 빼주어도 동일한 방향을 나타낸다. 즉, xº = ( x ± 360 × n )º (n=0, 1, 2, …)

일단 이전 프레임에서의 회전 각도를 저장해서 가지고 있어야 한다.

double theta_previous;
double theta_current;

그리고, 매 프레임 마다 회전 각도를 입력 데이터(input data)로 부터 받아들인다.

theta_previous = theta_current;
theta_current = input_angles[iFrame];

문제가 발생하여 수정해주어야 하는 프레임의 검출(detection)은 다음과 같은 조건으로 할 수 있다.

if( abs( theta_current – theta_previous ) > 180 )

왜 180인가? 180º는 반바퀴 회전한 것을 의미한다. 여기서는 한 프레임 사이에 발생하는 최대 회전 각도의 차이가 180º 보다 작다는 가정을 한다. 만약 한 프레임 사이에 180º 보다 더 큰 각도 변화가 생겼다고 한다면 시계 방향으로 돌아간 것인지, 반시계 방향으로 돌아간 것인지 판단하기 애매한 상황이기 때문에 이러한 극단적인 경우는 발생하지 않는다고 가정하자. 이웃한 두 프레임 사이의 시간 간격은 1/24초 정도로 매우 짧기 때문에 한 프레임 만에 180º 이상 돌아가는 상황은 정상적으로 볼 수 없기 때문이다.

그 다음 처리는 두 가지 경우로 나눌 수 있다.

case #1) theta_current > theta_previous
즉, 수직선 상에서 theta_previous는 상대적으로 왼쪽에 theta_current는 상대적으로 오른쪽에 위치하는 경우이다. 그리고, 이 때 이 둘 사이의 거리가 너무 크기 때문에 줄여주어야 한다. theta_previous는 이전 값으로 고정되어 있어 건드릴 수 없기 때문에 theta_current를 수정하여 둘 사이의 차이를 줄여주어야 한다. 따라서, theta_current -= 360을 해준다. 그리고, 다시 둘 사이의 거리를 비교한다. 만약 여전히 그 차이가 180 보다 크다면 다시 theta_current -= 360을 해준다. 둘 사이의 거리가 180 보다 작아질 때 까지 이러한 과정을 반복해 준다.

case #2) theta_current < theta_previous
즉, 수직선 상에서 theta_previous는 상대적으로 오른쪽에 theta_current는 상대적으로 왼쪽에 위치하는 경우이다. 그리고, 이 때 이 둘 사이의 거리가 너무 크기 때문에 줄여주어야 한다. theta_previous는이전 값으로 고정되어 있어 건드릴 수 없기 때문에 theta_current를 수정하여 둘 사이의 차이를 줄여주어야 한다. 따라서, theta_current += 360을 해준다. 그리고, 다시 둘 사이의 거리를 비교한다. 만약 여전히 그 차이가 180 보다 크다면 다시 theta_current += 360을 해준다. 둘 사이의 거리가 180 보다 작아질 때 까지 이러한 과정을 반복해 준다.

이러한 알고리즘이 제대로 작동하는지 확인보기 위해 위의 예제에서 한 군데만 살펴보자. 360 프레임에서 theta_previous = 359, theta_current = 0; abs( theta_current – theta_previous ) > 180 이다. theta_previous > theta_current 이므로 둘 사이의 거리를 좁히기 위해서 theta_current에 360을 더해준다. 그러면, theta_current = 360이 된다.

다시 둘 사이의 거리를 구해보면 abs( theta_current – theta_previous ) = 1이 된다. 즉, 둘의 차이가 180 보다 작아졌기 때문에 문제가 해결되었다. theta_previous = theta_current를 해주고 다음 프레임으로 넘어가서 동일한 방식으로 계속 처리해주면 된다.

Add a Comment