대학 1학년때,
동아리에서 각자 자신이 갈 분야를 택해서 멘토 멘티를 정하고 공부를 하는 시간을 가졌다.
나는 뭘 골랐는지 기억이 안나는데, 게임을 택했던 친구는 있었다.
게임 멘토는 친구에게 윈도우 api로 탱크를 회전시키라는 과제를 주셨었다.
나도 같이 지켜봤는데 삼각함수를 이용한 문제였고
결국 그 친구는 포기했고, 나 또한 수포자였다.
그래서 이번에 시도해봤다.
1. 삼각함수
삼각함수가 뭐에 쓰는건지 나는 몰랐다.
관심은 있었으나, 배우기에는 산이 너무 높아보였고, 하기 싫었다.
그러던 중 올해 초에 유튜브에서 이런 영상을 봤다.
https://www.youtube.com/watch?v=C_UsgRpyrUM&t=121s
이 영상을 본 기억을 종합해 sin과 cos을 조합하면 원을 그릴 수 있다는 것을 생각했다.
그래서 일단 콤파스마냥 중심점에서 가장자리까지 선을 그어 원을 그려봤다.
2. 회전하는 선 그려보기
switch (wParam) {
case VK_LEFT:
ang--;
break;
case VK_RIGHT:
ang++;
break;
}
y = sin(DEG2RAD*ang);
x = cos(DEG2RAD*ang);
MoveToEx(hdc, 500, 250, NULL);
LineTo(hdc, 500 + (250 * sin(DEG2RAD*ang)), 250 + (250 * cos(DEG2RAD * ang)));
이딴식으로 하면 그려진다.
DEG2RAD 는 Pi/180 즉 라디안으로 전처리기로 정의해놓은 값이다.
y와 x는 좌표같지만 sin과 cos이 있으므로 삼각함수 결과 값이다.
그래서 500,250의 좌표에서 250의 길이로 시계바늘 돌아가듯이 선이 그어진다.
3. 이제 사각형을 회전시켜보자.
static float ang = 0;
HDC hdc;
static float r = 0;
static int pA[] = { 300,150,0 }, pB[] = { 700,150,0 }, pC[] = { 300, 350,0 }, pD[] = { 700, 350,0 }, mP[] = { 500,250 };
switch (message)
{
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// 메뉴 선택을 구문 분석합니다.
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
hdc = BeginPaint(hWnd, &ps);
pA[2] = atan2f(mP[1] - pA[1], mP[0] - pA[0]) * 180 / PI;
pB[2] = atan2f(mP[1] - pB[1], mP[0] - pB[0]) * 180 / PI;
pC[2] = atan2f(mP[1] - pC[1], mP[0] - pC[0]) * 180 / PI;
pD[2] = atan2f(mP[1] - pD[1], mP[0] - pD[0]) * 180 / PI;
r = sqrt(pow((pC[1] - pA[1]), 2) + pow((pD[0] - pC[0]), 2))/2;
MoveToEx(hdc, mP[0] + r*cos(DEG2RAD*(pA[2] + ang)), mP[1] + r*sin(DEG2RAD*(pA[2] + ang)), NULL);
LineTo(hdc, mP[0] + r*cos(DEG2RAD*(pB[2] + ang)), mP[1] + r*sin(DEG2RAD*(pB[2] + ang)));
LineTo(hdc, mP[0] + r*cos(DEG2RAD*(pD[2] + ang)), mP[1] + r*sin(DEG2RAD*(pD[2] + ang)));
LineTo(hdc, mP[0] + r*cos(DEG2RAD*(pC[2] + ang)), mP[1] + r*sin(DEG2RAD*(pC[2] + ang)));
LineTo(hdc, mP[0] + r*cos(DEG2RAD*(pA[2] + ang)), mP[1] + r*sin(DEG2RAD*(pA[2] + ang)));
EndPaint(hWnd, &ps);
}
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_KEYDOWN:
switch (wParam) {
case VK_LEFT:
ang--;
break;
case VK_RIGHT:
ang++;
break;
}
InvalidateRect(hWnd, NULL, TRUE);
break;
막상 어떻게 해야할지 몰라 일단 4개 점의 x,y좌푯값을 저장하는 배열들을 만들었다.(pA, pB, pC, pD)
그리고 그 배열에는 x,y 좌표 뿐만 아니라 좌표와 중심점(mP) 사이의 처음 각도 또한 저장한다.
그리고 사각형의 대각선은 지름이다. 피타고라스의 공식을 이용해 반지름을 구한다.
이제 중심점 x,y에서
(반지름 * cos(라디안 * (점과 중심점 사이의 각도 + 변화된 각도) ) ) 와
(반지름 * sin(라디안 * (점과 중심점 사이의 각도 + 변화된 각도) ) ) 를 더해주면
점의 좌표가 나온다.
각 꼭짓점의 좌표를 모두 구해 선으로 이어주면
그것이 사각형이 된다.
그리고 왼쪽, 오른쪽 방향키를 누르면 ang값을 올리거나 내려서 위에서 말한 변화된 각도를 줄 수가 있다.
뭔가 코드를 더 줄일 수 있을것 같지만,
이대로 올리는 편이
미래의 나에게도 현재의 나에게도 혹시라도 읽게될 누군가에게도
더 쉽게 받아들일 수 있을지도 모르겠다.
QUICK SORT ALGORITHM with others (1) | 2021.01.09 |
---|---|
Windows API 바라보는 방향으로 움직이기 (2) | 2021.01.04 |
HEAP TREE with HEAP SORT ALGORITHM (0) | 2020.12.10 |
STACK ALGORITHM with LINEAR LIST (2) | 2020.12.07 |
0.1 + 0.2 != 0.3 (작성중) (0) | 2020.08.19 |
댓글 영역