http://wibler.egloos.com/3407369
제목 그대로 그림에서처럼 두 벡터 사이의 각도를 구해보죠.
이건 원운동을 하기
위해 필요한 작업이에요.
사실 이건 고등학교 수학책에도 나올만한 문제이지요. 백터의 내적을 이용하면 되거든요.
a점의
x1, y1이고 b점이 x2, y2면 아시다시피 두 백터의 내적은 다음과 같아요.
a*b = |a||b|*cos(c) -- 앞의 *
는 내적을 표해요. 표현하기가 마땅치 않군요.
이걸 풀어쓰고 정리하면(루트는 sqrt()로 쓸게요)
cos(c) = {
x1 * y1 + x2 * y2 } / { sqrt( x1^2 + y1^2 ) * sqrt( x2^2 + y2^2 ) }
이제
cos의 역함수인 acos()함수를 쓰면 c를 구할 수 있어요. 보통은.
그런데 여기서 math.h 에 들어있는 acos의 한계가
나와요. 이놈은 리턴을 0~180까지의 범위만으로 하거든요.
다시 설명하자면 다음과 같이 점이 있을때.
나는 a에서 b까지 시계방향으로 측정한 각도를 구하고 싶은데 위 방법대로
하면
반시계방향의 각도가 나와 버린다는 소리죠.
그래서 내적을 이용해 구하기전에 약간의 사전작업을 해야 해요. 다시
그림을 보자면.
일단 a를 90도 회전시킨 a' 을 구해요. 이건 매우 쉬워요.
주의해야할껀
좌표계의 방향이에요. 보통 윈도우를 만들면 아래쪽으로 갈수록
y값이 커지는건 알고 있죠. 그걸 기준으로 설명할게요.
a
가 x1, y1 이고 a' 이 x1', y1' 일때 시계방향으로 회전시키고 싶으면
x1' = -y1, y1' = x1이
되요.
반시계방향이라면. x1' = y1, y1' = -x1이 되죠. 조금만 생각해보면 답나와요.
이제 a'점과
b점사이의 각도를 위의 방식으로 내적을 이용해서 구해요.
이제 거의 다 됬어요. 방금구한 각도를 c' 라고
할때.
방금구한 각도가 90 보다 크면 a에서 b까지의 각도는
180도 보다 크다는 이야기에요.
그렇다면 간단하죠.
c'이 90보다 작을때에는 a와 b사이의 각도는
내적을 이용해서 바로 구할 수 있고.
c'이 90보다 클 때에는 360에서 내적을 이용해 구한 a와 b사이의 각도를 빼면
되지요.
아까 설명했다시피 c'이 90보다 클때는 a와 b사이의 각도가 반시계방향의 각도로 나오잖아요.
0~180의
범위로.
이런식으로 시계방향 혹은 반시계방향으로 0~360범위의 각도를 구할 수 있답니다.
아래 코드는 그걸
짜본거에요.
세번째 인자인 isClockWise는 true로 하면 시계방향, false로 하면 반시계방향의 각도를
구합니다.
fPOINT 는 전에 말했다시피 float x, y로 구성된
구조체입니다.
----------------------------------------------------------------------------------------
float
CPath::CalAngleBetweenTwoPoint(fPOINT ptPoint1, fPOINT ptPoint2, BOOL
isClockWise)
{
//acos()나 asin()함수로 구하는 각도를 degree로 나타냈을때
//그 범위는
0~180이다.
//각도를 0~360으로 나타내기 위한 사전작업으로
//기준점(ptPoint1)을 90도 회전시킨 점을
구한다.
fPOINT ptRotated90Point1 = {0,0};
if(isClockWise)
{
ptRotated90Point1.x=
-ptPoint1.y;
ptRotated90Point1.y =
ptPoint1.x;
}
else
{
ptRotated90Point1.x =
ptPoint1.y;
ptRotated90Point1.y = -ptPoint1.x;
}
//앞서 계산한 점과 두번째 인자로 받은 점간의 각도를 구함.
//이 각도가 90도보다 크다면 첫번째인자로 받은 기준점과 두번째
점간의 각도가
//180도보다 크다는 것을 의미한다.
float fAng = acos( (ptRotated90Point1.x * ptPoint2.x + ptRotated90Point1.y *
ptPoint2.y) /
(sqrt(
ptRotated90Point1.x * ptRotated90Point1.x + ptRotated90Point1.y *
ptRotated90Point1.y ) *
sqrt(ptPoint2.x * ptPoint2.x +
ptPoint2.y * ptPoint2.y) ) )
* 360 / TWOPI;
//fAng의 크기에 따라 두점사이의 각도를 다른 방식으로 구함.
if(fAng > 90)
return 360 -
acos( (ptPoint1.x * ptPoint2.x + ptPoint1.y * ptPoint2.y) /
(sqrt( ptPoint1.x * ptPoint1.x +
ptPoint1.y * ptPoint1.y ) *
sqrt(ptPoint2.x * ptPoint2.x +
ptPoint2.y * ptPoint2.y) ) )
* 360 / TWOPI;
else
return acos( (ptPoint1.x * ptPoint2.x + ptPoint1.y * ptPoint2.y)
/
(sqrt( ptPoint1.x * ptPoint1.x
+ ptPoint1.y * ptPoint1.y ) *
sqrt(ptPoint2.x * ptPoint2.x +
ptPoint2.y * ptPoint2.y) ) )
* 360 / TWOPI;
}
'수학 (Mathematics) > 3D수학' 카테고리의 다른 글
언프로젝션과 픽킹 (0) | 2012.11.02 |
---|---|
D3DXVec3TransformNormal & D3DXVec3TransformCoord (0) | 2012.11.02 |
D3DXVec3TransformCoord & D3DXVec3Transform 둘의 차이는 w 로 나누었는가의 차이 (0) | 2012.11.02 |
D3DXVec3TransformNormal 과 D3DXVec3TransformCoord 의 차이 (0) | 2012.10.31 |
convex polygon 이든 concave polygon 이든 모든 다각형의 내부에서 점의 존재여부 판단 (0) | 2012.10.27 |