관리 메뉴

ㄴrㅎnㅂrㄹrㄱi

[강좌 21] 그래프나 수치를 나타내는 기호 본문

API 관련/API 강좌모음

[강좌 21] 그래프나 수치를 나타내는 기호

님투 2007. 10. 26. 03:43
반응형

[API]그래프나 수치를 나타내는 기초




다음은 이공계학생이나 관련있는 분들이 실험에서 사용할 수 있도록 하는 그래프나 수치를 나타내는 기초를 설명합니다.책을 서술하듯이 적어 나갑니다. 굳이 높임말을 사용하지 않았습니다. 유용하게 사용하시길 바랍니다.

시작하기전에...
나름대로의 경험과 시행착오로 느낀 공부방법에 대하여 간단히 적어본다. 프로그래밍언어를
공부한다는 것은 어떤 언어를 사용하며 어떤 종류의 프로그램에 관심이 있으며 무엇을 해 볼것인
가와 관련이 있으므로 다음 내용을 참조하라. 어떤 언어를 공부하면서 기본 문법을 익히고 기초
적인 작업을 하면서 최초로 와 닿는 것이 이런 것을 어떻게 구현할까 하는 문제에 봉착한는데 이
문제가 알고리즘이라는 것이다. 중급이상으로 가기 위해 알고리즘을 공부하려면 반드시 디버거의
사용법을 해당 매뉴얼을 가지고 시간을 조금이라도 투자하여야 한다. 디버거는 결코 어렵지 않은
데 디버거를 무시하고 공부한다면 시간적으로도 결국 손해가 된다는 것이다. 복잡하다고 느끼는
것은 쪼개어 부분을 이해하라. devide and conquer이라는 말이 명언이다. 재귀호출과 같은 알고리
즘은 종이에 표시를 해보면 쉽게 흐름을 잡을 수 있다. 결국 하고자 하는 마음이 하고자 하는 것
을 이루어 준다고 볼 수 있다. 윈도우즈 프로그래밍의 마스터는 두가지 부류의 공부가 되어야 한
다. 하나는 API에 대한 이해인데 API가 제공해주는 함수를 이용한다면 하고자하는 어떤 작업에
대한 것도 제공해 준다는 것이다. 여기서는 API를 이용한 수치모델링에 중점을 둘것이므로 많
은 API는 필요하지는 않다. 다른 하나는 윈도우의 구조를 이해하는 것인데 이책의 내용과는 연관
성이 별로 없다.
API를 이용하는 Microsoft의 MFC(C++), Visual Basic(BASIC), Borland의 OWL(C++),
Delphi(Object Pascal)등이 유명하고 계속하여 프로그래밍 툴들이 쏟아지다시피 나오고 있다. 여기서는 Windows에서 컴파일 할 수 있는 C언어 컴파일러이면 사용가능하도록 코딩한다. 즉 Visual
C++, Borland C++ 등을 사용하여 컴파일 할 수 있다. 오래 되지 않은 옛날 MS-DOS에서 C프로
그램을 할 때 Assembly언어가 필요한 경우가 많았다. 프로그래밍 환경이 변하여 Windows에서는
C언어가 Assembly언어의 역할을 거의 해낸다. C언어는 C++언어와 호환을 유지하며 전환도 아주
쉽고 다른 기계로의 이식이 용이하다. 무엇보다도 Windows에서 C언어는 API의 사용에 자유를
준다. API 자체가 C언어로 구성되었다고 생각해 본다면 쉽게 납득이 될 것이다. 툴을 이용한
Windows 프로그래밍의 단점은 처음에는 쉬운 것 같고 발전하는 것 같지만 결국 벽에 막혀 고생
하게 된다. 결국 Windows 프로그래밍은 C와 API를 이용하는 것이 최상이라는 것이다. C와 API
를 이용하는 Windows 프로그램은 지적만족, 학습효과, 발전방향 등에 충분한 이득을 줄 것이다.
윈도우즈에서 수치모델을 구성하는 것은 어떤 MS-DOS용 언어를 사용하는 것에 대해 다음과 같
은 이점이 있다. 무엇보다 작업을 interactive하게 꾸밀 수 있다. 메뉴, 다이얼로그 박스, 다양한
폰트의 이용, 한글을 마음껏 사용 할 수 있다. 스크롤을 이용한 대형 도표나 그래픽도 가능하다.
이외의 엄청난 이익은 직접 체험해 보라. 그리고 이런 이익은 하루아침에 소유되어 지지 않는
다는 것을 충분히 알 수 있으리라.
여기서는 C언어에 대한 설명과 윈도우즈 프로그래밍의 기본에 대해서는 전혀 설명하지를 않고 있
다. 왜냐하면 홍수처럼 쏟아져 나오는 많은 책들이 그러한 것들을 중복하고 있기 때문이고 다시
여기서 중복해야할 이유가 없기 때문이다.

오차
오차는 유한자리 산술연산(finite-digit arithmetic)으로 인하여 기인되는 현상이다. 대다수의 수치
해석관련 서적은 이 문제에 대하여 다루고 있다.

그래픽의 이해와 응용

2차원 그래프를 그려보자.
2차원 그래프를 그릴 때 필요한 여러 가지 필요한 내용을 생각해보고 예제를 통하여 개선시켜나
간다. y = x 의 그래프를 그리기 위해서는 먼저 x와 y축이 필요 할 것이다. 그리고 x값이 1증가
할 때 y값도 역시 1증가 하므로 x 값을 y에 대입한후 시작점에서 (x, y)로 선을 긋는다. 또 x값
을 1증가 시키고 y에 대입한후 다시 선을 연결 시킨다. 다음에 예가 있다.

#include <windows.h>

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static char szAppName[] = "Simple Graphic" ;
HWND hwnd ;
MSG msg ;
WNDCLASSEX wndclass ;

wndclass.cbSize = sizeof (wndclass) ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ;

RegisterClassEx (&wndclass) ;

hwnd = CreateWindow (szAppName,
      "간단한 그래픽 그리기",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInstance,
      NULL) ;        

ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;

while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM
lParam)
{
HDC hdc ;
PAINTSTRUCT ps ;
int x, y;
switch (iMsg)
{
case WM_PAINT :
  hdc = BeginPaint (hwnd, &ps) ;

// 아래는 그래픽 그리기 루틴이다.
// MM_TEXT 맵핑모드 그리기이다.
  MoveToEx(hdc,100,50,NULL);
  LineTo(hdc,100,350);
  MoveToEx(hdc,100,200,NULL);
  LineTo(hdc,500,200);
  MoveToEx(hdc,100,200,NULL);

  for (x=0;x<200;x++) {
      y=x;
  LineTo(hdc,x+100, -y+200);
          }
// 이제는 MM_LOMETRIC 맵핑모드이다.
// MM_TEXT 맵핑모드보다 고해상도이므로 나타는 크기가 작게 보인다.
SetMapMode(hdc, MM_LOMETRIC);
      SetViewportOrgEx(hdc, 100, 200, NULL);

  MoveToEx(hdc,100,50,NULL);
  LineTo(hdc,100,350);
  MoveToEx(hdc,100,200,NULL);
  LineTo(hdc,500,200);
  MoveToEx(hdc,100,200,NULL);

  for (x=0;x<200;x++) {
      y=x;
  LineTo(hdc,x+100, y+200);
          }
// 위는 그래픽 그리기 루틴이다.

          EndPaint(hwnd,&ps);
          return 0;

case WM_DESTROY :
PostQuitMessage (0) ;
return 0 ;
}

return DefWindowProc (hwnd, iMsg, wParam, lParam) ;
}


다음은 프로그램에 대한 설명이다.
MoveToEx(hdc,100,50,NULL); // 픽셀단위로 100, 50으로 좌표를 옮긴다.
LineTo(hdc,100,350); // 픽셀단위로 100, 350으로 선을 긋는다.
MoveToEx(hdc,100,200,NULL);
LineTo(hdc,500,200);
MoveToEx(hdc,100,200,NULL);

for (x=0;x<200;x++)
{
y=x;
LineTo(hdc,x+100, -y+200); // 기본 좌표는 MM_TEXT 맵핑모드이고 x값은 오른쪽으로
} // 증가하고 y값은 아래로 증가한다.
그러면 다음을 생각해보자.

SetMapMode(hdc, MM_LOMETRIC); // MM_LOMETRIC 맵핑모드는 x값은 오른쪽으로 증가
// 하고 y값은 위로 가면서 증가한다.
SetViewportOrg(hdc, 100, 200); // 좌표의 중점을 0.1mm단위로 100, 200에 설정한다.
// 아래는 그래픽 그리기 루틴이다.
MoveToEx(hdc,100,50,NULL); // 좌표 100, 200에서 오른쪽방향으로 100,
          //     위쪽으로 50만큼 이동한다.
LineTo(hdc,100,350); // 좌표(100, 350)으로 줄을 긋는다.
MoveToEx(hdc,100,200,NULL);
LineTo(hdc,500,200);
MoveToEx(hdc,100,200,NULL);

for (x=0;x<200;x++)
{
y=x;
LineTo(hdc,x+100, y+200); // y의 부호가 양임을 알 수 있다.
}
// 위는 그래픽 그리기 루틴이다.

위에서 두가지 좌표 시스템을 보았다. 나머지 맵핑모드는 이 두가지 좌표를 비교해 본다면 쉽게
이해할 수 있다.
위의 두가지 좌표 시스템에서 중요한 점은 맵핑 방향보다 해상도의 차이가 중요함을 상기하기 바
란다.
이제 기본적인 그래프를 하나 그려 보기로 한다. 좌표는 디폴트 매핑모드인 MM_TEXT로 하고
식은 y = x/2-10을 그려본다. y = x 부분을 y = x/2-10 으로 바꾸면 된다. 그리고 축에 알맞는 좌표를 긋고 좌표에 눈금자를 표시할 수 있도록한다.

#include <windows.h>
#include <math.h>

LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static char szAppName[] = "Graph2D" ;
HWND hwnd ;
MSG msg ;
WNDCLASSEX wndclass ;

wndclass.cbSize = sizeof (wndclass) ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
wndclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION) ;

RegisterClassEx (&wndclass) ;

hwnd = CreateWindow (szAppName, "간단한 방정식 그리기.",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;

ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;

while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}

LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM
lParam)
{
static int cxClient, cyClient ;
HDC hdc ;
int x, y ;
PAINTSTRUCT ps ;
BOOL bLine = FALSE;
switch (iMsg)
{
case WM_SIZE:
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
return 0 ;

case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;

// 아래는 그래픽 그리기 루틴이다.
MoveToEx (hdc, 0, cyClient / 2, NULL) ;
LineTo (hdc, cxClient, cyClient / 2) ;
          MoveToEx (hdc, cxClient/2, 0, NULL);
          LineTo (hdc, cxClient/2, cyClient);

          //논리적 점 (0, 0)을 클라이언트 영역의 중앙에 설정한다.
SetViewportOrgEx(hdc, cxClient/2, cyClient/2, NULL);

          for(x=-200; x<200; x++){
              y = x/2-10;
              if(bLine == FALSE){
                  MoveToEx(hdc, x, -y, NULL);
//                 if(bLine == FALSE)
                  bLine = TRUE;
              }
              else
                  LineTo(hdc, x, -y);
          }
          for(x=-200; x<200; x+=5){
              MoveToEx(hdc, x, 0, NULL);
              LineTo(hdc, x, -5);
          }
return 0 ;
// 위는 그래픽 그리기 루틴이다.
case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;
}

return DefWindowProc (hwnd, iMsg, wParam, lParam) ;
}

프로그램을 실행해보면 미관이 별로 아름답지는 못하다는 것을 느낄 것이다. 이해를 쉽게 하고자
화면의 일부분만을 그린 것을 쉽게 눈치 챌 수 있을 것이다. 다음은 이프로그램에 대한 설명이다.
WM_PAINT 부분을 눈여겨 볼 필요가 있다.
MoveToEx (hdc, 0, cyClient / 2, NULL) ;
LineTo (hdc, cxClient, cyClient / 2) ;
// 화면의 중앙에 수평선을 긋는다. WM_SIZE 메시지에서 cxClient, cyClient값을 얻었다.
// 그리고 아래의 두라인은 화면의 중앙에 수직선을 긋는다.
MoveToEx (hdc, cxClient/2, 0, NULL);
  LineTo (hdc, cxClient/2, cyClient);
//논리적 점 (0, 0)을 클라이언트 영역의 중앙에 설정한다.
SetViewportOrgEx(hdc, cxClient/2,cyClient/2, NULL);
//화면 좌표의 증감방향에 유의하라.

// 다음은 그래픽을 그린다. bLine == FALSE를 비교하는 이유는 x가 -200일 때 해당하는 y값으
// 로 그릴 펜을 이동하기 위함이다. 그리고 난후 200까지는 선을 잇는다.
          for(x=-200; x<200; x++){
              y = x/2-10;
              if(bLine == FALSE){
                  MoveToEx(hdc, x, -y, NULL);
                  bLine = TRUE;
              }
              else
                  LineTo(hdc, x, -y);
          }
// 다음은 자(Ruler)를 그리는 루틴이다. 5픽셀 간격으로 줄을 긋는다.
// 자를 얼마든지 보기 좋게 그을 수 있을 것이다. 예를 들면 매 5픽셀 간격은 4픽셀 길이로 줄을
// 긋고 100픽셀 간격은 8픽셀 간격으로 긋는다면 보기가 조금 더 나을 것이다.
// LineTo앞에 if문을 이용하면 될것이고 아니면 다른 방법이 얼마든지 있을 수 있다.
// x축에만 자를 그렸는데 y축에도 자를 그려야 할 것이다. 다음의 예제에서 완성시켜보자.
          for(x=-200; x<200; x+=5){
              MoveToEx(hdc, x, 0, NULL);
              LineTo(hdc, x, -5);
          }
그런데 이번 예제는 분위기가 조금 다른 방법으로 그린다.

다이얼로그 기반 프로그래밍으로 구현해 보았다. 다이얼로그는 윈도우이므로 다이얼로그를 이용한 프로그램도 윈도우 프로그램의 흔한 방법이다. 예를들면
많이쓰는 툴중 visual Basic같은 툴이 다이얼로그 프로그램을 많이 이용한다고 한다. 다음에 소스
와 설명이 이어진다.

#include <windows.h>
#include "resource.h"

BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
              PSTR szCmdLine, int iCmdShow)
{
  DialogBox(hInstance, MAKEINTRESOURCE(IDD_GRAPH), NULL, DlgProc);
  return 0;
}

BOOL CALLBACK DlgProc(HWND hDlg, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
HDC hdc ;
int x, y ;
PAINTSTRUCT ps ;
  RECT rect;
BOOL bLine = FALSE;

  switch(iMsg)
  {
  case WM_INITDIALOG:
      return FALSE;

case WM_PAINT:
hdc = BeginPaint (hDlg, &ps) ;
      GetClientRect(hDlg, &rect);

FillRect(hdc, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));

MoveToEx (hdc, rect.top, rect.bottom / 2, NULL) ;
LineTo (hdc, rect.right, rect.bottom / 2) ;

MoveToEx (hdc, rect.right/2, rect.top, NULL) ;
LineTo (hdc, rect.right/2, rect.bottom) ;


  //논리적 점 (0, 0)을 다이얼로그 박스의 중앙에 설정한다.
SetViewportOrgEx(hdc, rect.right/2, rect.bottom/2, NULL);
      for(x=-100; x<100; x++){
      y = x/2-10;
          if(bLine == FALSE){
              MoveToEx(hdc, x, -y, NULL);
              bLine = TRUE;
          }
          else
              LineTo(hdc, x, -y);
      }
          for(x=-100; x<100; x+=5){
              MoveToEx(hdc, x, 0, NULL);
              LineTo(hdc, x, -5);
          }
for(y=-200; y<200; y+=5){
              MoveToEx(hdc, 0, y, NULL);
              (y%20==0) ? LineTo(hdc, 10, y) : LineTo(hdc, 5, y);
          }
     
return 0 ;

case WM_DESTROY:
PostQuitMessage (0) ;
return 0 ;

case WM_COMMAND :
switch (LOWORD (wParam))
{
      case IDOK :
                  case IDCANCEL:
                      EndDialog (hDlg, 0) ;
                      return TRUE ;
}
break ;
}
return FALSE ;
  }


//{{NO_DEPENDENCIES}}
// Microsoft Developer Studio generated include file.
// Used by DLGG2.RC
//
#define IDD_GRAPH 101

// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 102
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1000
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif


//Microsoft Developer Studio generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"

/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////////
// Korean resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_KOR)
#ifdef _WIN32
LANGUAGE LANG_KOREAN, SUBLANG_DEFAULT
#pragma code_page(949)
#endif //_WIN32

/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

IDD_GRAPH DIALOG DISCARDABLE 0, 0, 259, 218
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "다이얼로그 박스에 그래프를 그린다."
FONT 10, "System"
BEGIN
DEFPUSHBUTTON "OK",IDOK,202,7,50,14
PUSHBUTTON "Cancel",IDCANCEL,202,24,50,14
END


/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO DISCARDABLE
BEGIN
IDD_GRAPH, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 252
TOPMARGIN, 7
BOTTOMMARGIN, 211
END
END
#endif // APSTUDIO_INVOKED


#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//

1 TEXTINCLUDE DISCARDABLE
BEGIN
"resource.h\0"
END

2 TEXTINCLUDE DISCARDABLE
BEGIN
"#include ""afxres.h""\r\n"
"\0"
END

3 TEXTINCLUDE DISCARDABLE
BEGIN
"\r\n"
"\0"
END

#endif // APSTUDIO_INVOKED

#endif // Korean resources
/////////////////////////////////////////////////////////////////////////////



#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//


/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

화면에 나타내는 그래프를 이용한 기초 수치모델 방법 끝

반응형

'API 관련 > API 강좌모음' 카테고리의 다른 글

[강좌 20] 메모리  (0) 2007.10.26
[강좌 19] 초기화 파일  (0) 2007.10.26
[강좌 18] 파일과 디렉토리  (0) 2007.10.26
[강좌 17] 폰트  (0) 2007.10.26
[강좌 16] 멀티미디어4  (0) 2007.10.26
Comments