[출처]카페 > 안동대학교 전자공학과 로봇동.. | 날로먹기   http://cafe.naver.com/at0/697

앞의 글에서 AR이라는 기술에 대해서 소개했었습니다.

이번에는 ARToolKit을 설치하는 방법을 알려 드릴려고 합니다.

 

ARToolKit은 AR기술을 좀더 쉽게 구현하기 위해 사용자에게 제공되는 라이브러리입니다.

 

 

준비물 : USB port 달린 컴퓨터, PC CAM(화상카메라) , Visual studio 6.0이상, DirectX 9.0b 이상

공식 사이트 : http://www.hitl.washington.edu/artoolkit/

 

 

자 그럼 시작해 보겠습니다.

 

(1) ARToolKit Download

ARToolKit 사이트에 가셔서 상단 메뉴중 Download로 이동합니다.

그러면 아래와 같은 화면이 나옵니다.

빨간색 박스 친부분을 눌러 최신 버전이 있는곳으로 이동합니다.

 

그럼 아래아 같은 화면이 나옵니다.

ARToolKit-2.72.1-bin-win32.zip를 다운 받습니다.

OpenVRML은 선택사항인데 아직은 필요 없으니깐 그냥 넘어갑니다.

 

다운을 완료 했으면 편하신 폴더에 압축을 풉니다.

 

 

(2) GLUT DLL Download

아래 사이트로 가서 glut-3.7.6-bin.zip를 다운 받습니다.

http://www.xmission.com/~nate/glut.html

 

압축을 풀고 각각의 파일을 해당 폴더에 복사해 주어야 합니다.

glut32.dll -> c:\windows\system32

다음의 파일은  비쥬얼 스튜디오가 설치된 폴더에 복사해야 합니다.

glut.h -> c:\Program Files\Microsoft Visual Studio\VC98\Include\GL

glut32.lib -> c:\Program Files\Microsoft Visual Studio\VC98\Lib

 

 

(3) Configure.win32.bat 실행

이제 ARToolkit을 압춘 해제한 폴더로 이동 합시다.

ARToolkit폴더로 이동하면 Configure.win32.bat 이라는 파일이 있습니다.

가볍게 더블클릭하여 실행해 줍니다.

그럼 도스화면 창이 뜨면서 실행되는게 보이는데 무슨무슨 파일이 복사되었다고 나옵니다.

확인하고 닫아줍니다.

 

 

(4) Batch Build

비쥬얼 스튜디오를 실행하여 ARToolkit 프로젝트를 엽니다.

File -> Open Workspace ->ARToolKit.dsw

그리고 상단의 메뉴에서 bulid -> Batch Build 를 클릭 합니다.

아래와 같은 화면이 나오는면 Win32Release, Win32 Debug만 클릭 되어 있는지 확인하고 build 클릭 합니다.

그럼 프로그램이 미친듯이 컴파일 할겁니다.

완료 되면 예제 소스 들을 돌려 봅시다.

 

(5) 예제 프로그램 실행하기

예제 프로그램은 ARToolKit폴더내에 examples폴더에 존재합니다.

많은 예제들이 존재하는것을 보실수 있을겁니다.

 

실행하기에 앞서 ARToolKit의 특징에 대해서 간단히 소개하고 넘어가겠습니다.

ARToolKit에서는 가상의 영상을 띄우기 위해 마커(marker)를 필요로 합니다.

이 마커라는것이 가상의 물체를 띄울 대상되는데 ARToolKit은 기본적으로 검은색 사각형을 마커로 잡습니다.

위의 사진과 같이 영상내에 검은색 사각형이 있고 그안에 hiro라는 글자가 보이시죠?

저게 ARToolkit의 마커가 되는 겁니다.

ARToolkit에서 사용하느 모든 마커는 검은색 사각형이 있어야 하고 사각형 안의 모양은 마은대로 변경 할 수 있습니다.

위의 사진에서는 hiro라는 글자가 새겨져 있는데 다른 영어를 적으셔도 되고

동그라미, 세모 등등 자신만의 모양을 만드셔도 됩니다.

단 마커를 사용하기 위해서는 프로그램에 기본적으로 저 마커가 등록이 되어 있어야 합니다.

그래야 화면내에서 저 마커를 찾아 가상 물체를 띄우겠죠?ㅎ

마커를 제작하는 방법은 다음시간에...ㅎ

 

ARToolKit에 대한 소개는 여기까지 하고 예제 프로그램을 실행해 보도록 하겠습니다.

일단 simple폴더에 있는 simpleTest.dsw를 실행해 보도록 하겠습니다.

컴파일 하고 ctrl + F5를 눌러 프로그램을 실행해 봅시다.

 

자 그럼~ 카메라 영상이 짠~~~하고 뜨나요~?

 

그럼 당신은 축복 받은 사람입니다.ㅎ

 

뭐든 그렇지만 처음 시작해서 한번에 되는일이 잘 없더군요.

꼭 삽질을 해야 아웃풋이 나오는거 같습니다.ㅎ

자! 여기서 실행하면 나타나는 대표적인 오류에 대해 해결 방안을 알려 드리겠습니다.

 

1) 실행시 msvcp71d.dll, msvcr71d.dll 등 dll파일을 찾을수 없다고 뜨는 경우

-> http://www.dll-files.com/ 사이트 가셔서 찾아서 다운 받아서 c:\windows\system32 에 복사해 두시면 됩니다.

msvcr71d.dll :  http://www.dll-files.com/dllindex/dll-files.shtml?msvcr71d

msvcp71d.dll : http://www.dll-files.com/dllindex/dll-files.shtml?msvcp71d

 

2) Camera parameter load error!! 문구가 뜨는 경우

-> 상단의 메뉴에서 Project -> Settings눌러 줍니다.

    여러 메뉴가 뜰텐데 Debug로 이동하셔서 Working directory란에 경로 지정을 좀 해줘야 합니다.

    ARToolkit 폴더의 bin폴더의 경로 적어 주면 됩니다. 아래 그림을 참고 하세요~

 

   

 

 

(6) Test

이제 모든 작업이 끝났습니다.

프로그램을 실행해 보고 마커위에 가상 물체가 잘 뜨는지 테스트 해 보시기 바랍니다.

simpleTest에서 사용되는 마커는 pattens폴더에 pattHiro.pdf를 사용하시면 됩니다.

프린터기로 출력하셔서 사용해 보세요~

 

아래는 실행 화면 입니다~육면체가 이쁘장하게 뜨네요.ㅎ

 

 

ARToolkit에 대해 더많이 알고 싶은 분은 공식 사이트(http://www.hitl.washington.edu/artoolkit/)로 가셔서 상단의 메뉴에 Documentation로 이동하면 ARToolkit사용 방법에 대해 친절히 설명해 놓았습니다.

차근차근 보고 따라해 보시기 바랍니다.^^

그럼 오늘도 수고~

 


Posted by 시그v

MFC를 사용하여 프로그램을 개발하고 있다면,

#ifdef _DEBUG
#define new
DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


위의 코드를 .cpp 화일에 넣어 프로그램이 종료 되었을때 아래와 같이 누수된 메모리를 할당하는 부분의 소스 코드와 라인 수를 출력 해준다.

Detected memory leaks!
Dumping objects ->
d:\sample\sample.cpp(35) : {48} client block at 0x003739D0, subtype 0, 4 bytes long.
 Data: <(   > 28 00 00 00
d:\sample\sample.cpp(34) : {47} client block at 0x00373990, subtype 0, 4 bytes long.
 Data: <    > 1E 00 00 00
Object dump complete.


위의 예에서는 두 블록의 메모리 누수가 검출 되었는데 각 라인의 의미는

 

 



d:\sample\sample.cp (35) : {48} client block at 0x003739D0, subtype 0, 4 bytes long.


sample.cpp 화일의 35번째 라인에서 할당된 메모리가 누수되었고 그것은 48번째로 할당된 메모리이며 메모리 주소는 0x003739d0, 4Byte가 누수되었다는 의미로 해석할 수 있다.

MFC를 사용하지 않은 프로그램의 경우 위의 DEFINE 문으로는 DEBUG_NEW를 찾을 수 없다는 컴파일 에러를 내뱉는데 그 경우엔 위의 DEFINE 문과 함께 아래와 같은 라인을 헤더에 삽입해서 해결할 수 있다.

#if !defined(_AFXDLL)
   #include <windows.h>
   #include <crtdbg.h>
   #if defined(DEBUG) | defined(_DEBUG)
      #if !defined(DEBUG_NEW)
         #define DEBUG_NEW new(_CLIENT_BLOCK, __FILE__, __LINE__)
      #endif
   #endif
#endif


DEBUG_NEW를 새로이 정의함으로써 DEBUG_NEW를 찾을 수 없는 문제를 해결한다.

간혹 malloc 을 이용한 메모리 할당은 위의 내용이 적용이 되질 않는데 이 경우엔 아래의 문장을 소스코드에 삽입한다.

- 헤더 화일에는 아래라인을 추가
#define DEBUG_MALLOC(size) _malloc_dbg(size, _NORMAL_BLOCK, __FILE__ , __LINE__)

- malloc을 재정의 하려는 소스 코드에 아래 라인을 추가.
#define malloc DEBUG_MALLOC


위의 방법들로 memory leak dump 에서 할당된 소스 코드와 라인수를  바로 찾을 수 있다.

 

 

[펌] 개발자의 끄적임 http://cromit.tistory.com/6

'Programming > Visual Studio' 카테고리의 다른 글

error LNK2005:  (0) 2010.01.13
error LNK2059  (0) 2010.01.13
error LNK1104  (1) 2010.01.13
error LNK2019 fatal, error LNK1120  (0) 2010.01.13
error LNK2005: 에러  (0) 2009.12.19
Posted by 시그v

[출처]착하게...삽시다! | 우기우기  http://blog.naver.com/ragcarib/12005303968


프로그램이 메모리에 올라가게 되면 Data Segment 와 Code Segment 로 나뉘게 된다.

 

Heap 과 Stack 은 Data Segment 를 이용하게 된다.

 

  • 힙(Heap)은 런 타임시에 크기가 결정되는 요소들이 저장되는 공간이다.

C의 malloc() 함수나 C++의 new 연산자로 메모리 할당이 될 때에는 이 Heap 공간에 메모리가 잡히게 된다.

 

  • 스택(Stack)은 컴파일시에 크기가 결정되어있는 요소들이 저장되는 공간이다.

함수가 받는 매개 변수나 함수내에서 사용되는 지역변수가 이 Stack 영역에 저장이 된다.

 

 

메모리를 가상으로 그림으로 그려보면 다음과 같이 나타낼 수 있다.

 

 

※데이터 영역

전역 변수와 static 변수 저장

----------------------------------

※힙 영역

동적 할당되는 데이터 저장

 (데이터가 위부터 순차적으로 저장)

 

 

 

※스택 영역

지역 변수와 매개변수가 저장

 (데이터가 아래부터 순차적으로 저장)

 

 

보통 전역 변수나 static 변수는 heap 의 윗 부분에 위치하고, Stack 은 Data Segment 의 처음부터 할당이 되고,

 

Heap 은 끝부분 부터 할당이 된다.

 

 

예제 코드를 작성하여 돌려보았다.

 

 

#include <stdio.h>

int A, B;

main()
{
 int a = 0;
 int b = 0;

 int *p1 = NULL;
 int *p2 = NULL;

 p1 = (int*)malloc(sizeof(A));
 p2 = (int*)malloc(sizeof(A));

 printf("전역 변수의 주소값 출력\n");
 printf("%d\n", &A);
 printf("%d\n", &B);
 printf("동적할당된 포인터의 주소값 출력\n");
 printf("%d\n", p1);
 printf("%d\n", p2);
 printf("지역 변수의 주소값 출력\n");
 printf("%d\n", &a);
 printf("%d\n", &b);

 free(p1);
 free(p2);
}

 

 

 

Visual Studio 2003에서 작성하였고, 알아보기 쉽게 10진수로 출력을 하였다.

 

메모리 할당이 된 간격은 틀리지만,

 

전역 변수와 동적 할당된 포인터의 메모리 할당 순서가 지역 변수의 메모리 할당 순서와 다른것을 확인할 수 있다.

 

 

Stack 영역에 올라가는 데이터는 프로그램이 실행되자마자 마로 메모리에 할당이 되고, 함수가 종료되거나, 프로그램이 종료될 때 자동으로 메모리 공간이 해제된다.

 

 

그에 반해, Heap 영역에 올라가는 데이터는 프로그램이 실행되는 중간에 메모리에 할당되고, 프로그램이 종료될 때

 

자동으로 메모리 공간이 해제되지 않는다. 메모리 공간을 해제하면 다시 그 영역을 사용할 수 있다.

 

 

따라서 동적으로 할당된 메모리 공간은 C의 free() 함수나 C++의 delete 연산자를 사용하여 메모리 공간을 다시 해제하여 주어야 한다.

 

그렇지 않을 경우 메모리 누수(leak) 가 발생하게 된다.

 

 

그렇다면 메모리 동적할당이 왜 필요한 것인가?

 

 

예를들어 다음과 같이 5개의 정수형 데이터를 입력하는 프로그램이 있다고 하자.

 

#include <stdio.h>

 

main()
{
 int arr[5];

 int i = 0;
 for(i = 0; i < 5; i++) {
  printf("정수 입력 : ");
  scanf("%d", &arr[i]);
 }
 for(i = 0; i < 5; i++) {
  printf("%d번째 입력 데이터 : %d\n", i+1, arr[i]);
 }
}

 

이 프로그램은 죽었다 깨어나도 5개의 정수형 데이터 밖에 입력을 하지 못한다. 이제 이 프로그램을 실행 시 마다 입력 되는 데이터의

 

수가 다르게 작성을 하고 싶어서 다음과 같이 프로그램을 작성하였다.

 

#include <stdio.h>

void func(int n);

main()
{
 int *p = NULL;
 int i = 0, n = 0;
 printf("입력할 데이터의 수를 입력 : ");
 scanf("%d", &n);
 func(n);
}

void func(int n)
{
 int arr[n];                     // Compile Error
 int i = 0;
 for(i = 0; i < n; i++){
  printf("정수 입력 : ");
  scanf("%d", &arr[i]);
 }
 for(i = 0; i < n; i++)
  printf("%d번째 입력 데이터 : %d\n", i+1, arr[i]);
}

 

-------------------------------------------------------------------------------------------------------------------

func() 함수 내의 arr 이라는 배열은 func 함수가 실행된 후 종료될 때 스택 메모리 영역에서 메모리가 해제 되므로

 

출력까지 func 함수 내에서 처리하였다. 주의깊게 보아야 할 부분은 배열 선언 시 인덱스 값으로 변수가 올 수 없다는 것이다.

 

(배열 선언시의 인덱스 값에는 상수만이 올 수 있다.)

-------------------------------------------------------------------------------------------------------------------

 

그럼 다음과 같은 문제를 포인터를 사용한 동적 메모리 할당으로 해결해보면 다음과 같은 방식으로 작성할 수 있다.

 

포인터와 배열의 차이점과 공통점을 어느정도 알고 있어야 한다.

 

#include <stdio.h>
#include <stdlib.h>


main()
{
 int *p = NULL;
 int i = 0, n = 0;
 printf("입력할 데이터의 수를 입력 : ");
 scanf("%d", &n);
 p = (int*)malloc(sizeof(int)*n);
 for(i = 0; i < n; i++){
  printf("정수 입력 : ");
  scanf("%d", (p)+i);
 }
 for(i = 0; i < n; i++)
  printf("%d번 입력 데이터 : %d\n", i+1, *((p)+i));

 free(p);                   // Important!!
}

 

 

-------------------------------------------------------------------------------------------------------------------

main() 함수 내에 포인터 변수 p가 선언되어 있고, 이를 입력받은 n의 갯수만큼 int 형으로 동적 메모리 할당을 하고 있다.

이후 포인터 변수 p를 이용하여 데이터를 입력받고 출력 한 후 할당받은 메모리 공간을 해제한다.

-------------------------------------------------------------------------------------------------------------------

 

 

동적 메모리 할당을 사용하면 위와 같은 이점을 활용할 수 있게된다.

 

 

C++에서의 new 와 delete 연산자를 이용한 메모리 할당/해제 방식은

 

 

int *p;

p = new int[데이터갯수];

delete[] p;

 

와 같은 방법으로 할당과 해제를 한다.

 

예를들어 '데이터 갯수' 부분에 5를 입력하게 되면

 

malloc(sizeof(int)*5) 와 같은 크기를 할당하게 된다. (new 연산자 사용시에는 데이터 타입을 알 수 있다.)

 


Posted by 시그v

기본 개념 작성일 : 1997 (In Skyteam)

작성일 : 2002년 11월 13 (In SkySoft)

1개정일 : 2005년 4월 13 (In Freechal)

작성자 : 채경석 kyuseo99@chol.com http://p8.co.kr


개요

본 가이드는 절대적이거나, 표준으로 규정된 내용들이 아니라 하나의 지침사항입니다.

프로그래밍에 조금의 지식이 있는 프로그래머라면 ‘(‘ 뒤에 공백이 있던지 말던지 ‘{‘ 어떻게 붙이던지 코드를 분석하는데 별다른 어려움이 없습니다. 하지만 본 가이드를 힘들게 작성하고 배우고 지켜야 하는 이유는, 좀 더 코드를 분석하는 시간을 줄이고 이해하기 쉽도록 하기 위해서 입니다. 이것이 적어도 동일한 프로젝트에서, 적어도 동일한 팀에서, 같은 스타일로 제작해야 하는 이유입니다.

아래 사항들은 표준도 아니고 절대적이지도 않기 때문에 일부분을 자신들의 팀이나, 프로젝트 스타일에 바꾸어 수정해서 사용하셔도 무방합니다.

 

 

 

1          이름

1.1          변수의 표기는 헝가리안 표기법을 사용한다.
(
헝가리안 표기법이 타이핑하기 불편하거나 귀찮을 수도 있으나 근본적으로 변수의 명확성을 강화한다.)
)     int nNumber, char szName, CString strInfo, CSurface surSportsCar, int *pnData, CWnd wndMain

1.2          각 변수 및 함수의 이름은 대문자로 시작한다.
(
소문자만을 이용하거나 ‘_’을 이용하거나 또는 소문자 + 첫 단어 대문자를 이용하는 많은 사용 예가 있기는 하지만 결국 여러 스타일을 동일 프로젝트에서 혼용하여 사용하는 것은 통일성과 가독성 등에 저해를 가져온다. 때문에 다양한 방법 중 한가지를 선택할 필요성을 느꼈고, 첫 문자를 대문자로 쓰는 것으로 통일하였다.)
)      int nTypeMax, char szFileInfomation, (O)
          int ntype_max, char szfile_infomation (X)
          int GetType();   BOOL SetMaxRange( int CX, int CY ), void SetFont( HFONT hFont )

1.3          헝가리안 표기법 중 포인터는 중첩하여 사용 가능하다.
(포인터 뿐만이
아니라 배열의 ‘a’ 나 다른 의미의 명확성을 위해서 몇몇 헝가리안 표기법도 중첩사용이 가능하다.)
)      int *pnCount, CSurface *psurBack, BYTE *pBuffer

1.4          헝가리안 표기법의 예외는 다음과 같다.
(
헝가리안 표기법이 만능도 아니고 절대적인 것도 아니다. 단순히 습관적이고 일반화된 선례 등은 예외가 될 수 있다.)

1.4.1          X, Y 와 같은 의미가 명확한 변수 ( 확장 : XDest, YDest )

1.4.2          For 문 등에서 사용하는 I, j 등의 이미 알려진 변수

1.4.3          구조체 멤버 변수

1.4.4          BYTE *pBuffer 와 같이 BYTE 라는 값이 큰 의미가 없는 경우

1.5          전역 변수는 ‘g_’ 을 사용한다.
(
지역변수 및 인자와 구분을 위해서 ‘g_’을 사용한다. 참고로 전역 변수는 가능한 사용을 자제한다.)
)     int g_nGameTimer, char g_szAppName

1.6          클래스의 멤버 변수는 ‘m_’ 을 사용한다.
(
지역변수 및 인자와 구분을 위해서 ‘m_’을 사용한다.)
)     m_surBack, m_szName, m_dwCode

1.7          포인터(*) 및 참조(&) 표기는 변수 앞에 붙여서 선언한다.
(
변수 앞에 붙여서 표기 하는 가장 중요한 이유는 char* szName, szType 과 같이 표기 할 경우 szType 이 포인터인지 아닌지 구분이 잘되지 않기 때문이다.)
올바른 예)
POINT *pPoint, char *szName;
POINT &pPoint, char &szName;

잘못된 예)
POINT* pPoint, char * szName;
POINT& pPoint, char & szName;

1.8          #define enum const 는 대문자와 단어 사이에 ‘_’ 붙인다.
)      #define WM_USER_PING_THREAD_END WM_USER+0x102
          #define PACKET_LOGIN_ANSWER_BAD_USER_OVER            8
          enum BUTTON_STATE{ BUTTON_NORMAL, BUTTON_OVER, BUTTON_DOWN, BUTTON_DISABLE };

1.9          #define 보다 const 형 또는 static const 형을 되도록 사용한다. (#define 과 같은 대문자 선언 시에 사용)
(
하지만 배열 등에 직접적으로 const 형은 컴파일 오류가 발생하기 때문에 현재 보류한다.)
) static const int MAX_CARD = 1000

1.10       클래스 내부에서 사용하는 상수 값은 클래스 내부에서 선언된 enum을 사용한다.
(#define
은 전역적으로 사용된다. 따라서 MAX_ITEM과 같은 일반적인 상수이름은 다른 곳에서 겹칠 우려가 있기 때문에 사용하기가 꺼려진다. 하지만 enum은 클래스 내부에서만 사용되기 때문에 MAX_ITEM와 같은 일반화된 상수를 사용할 수가 있다.)

1.11       구조체 이름은 대문자로 하고 각 단어 구분은 ‘_’ 로 한다.
(
구조체의 이름은 관습적으로 대문자만을 사용한다.)
)     struct TEST{ … }
          struct BANNER_UNIT{ … }, struct GAME_ITEM{ … },


1.12       구조체의 멤버 변수는 소문자를 이용하고 단어 별 구분 시에 ‘_’ 을 사용한다.
(
헝가리안 표기법이 사용되지 않는 이유는 오랜 기간 관습적으로 소문자 표기법이 이용되었기 때문이다.)
)
struct GAME_UNIT
{
          BYTE type;
          char id[13];
          WORD version;
          BYTE* buffer;
          CString ip_name,
};

1.13       일반적으로 지역 변수는 선언된 타입과 동일한 이름을 사용한다.
(
클래스나 구조체등의 이름을 이용하여 지역 변수를 선언하면 알아보기가 쉽고 변수명 작명을 위해 고민하지 않아도 된다.)
)     BANNER_UNIT BannerUnit, FAST_TABLE FastTable, CSkyPassword SkyPassword

1.14       템플릿 타입은 대문자 한 자로 표기한다.
(
관습에 의하여 템플릿은 한 자로 표기한다.)
)     template< class T>, template< class C, class D >

1.15       클래스를 이름은 첫 자를 C 시작한다.
(
클래스를 구분하는 헝가리안 표기법의 일종이다.)
)     CSurface, CPoint

1.16       클래스 함수의 경우 클래스 명에서 이미 명시된 부분은 제외한다.
(
이미 클래스 이름으로도 충분히 알 수 있는 내용을 중복하여 적는 것은 비효율적이며 올바르지 않는 방법이다. 이것은 마치 사각형의 사각형 가로크기는 얼마인가요?” 와 같은 표현이다.)
올바른 예)       Rect.GetWidth()
잘못된 예)      Rect.GetRectWidth()

1.17       BOOL형 변수는 사용하지 않는다.
(
빠른 이해와 잘못된 사용을 방지하기 위해서 BOOL은 항상 인 값을 사용한다. 이는 ‘!’ 와 같은 구문을 이용할 때 더욱더 편리하다.)
올바른 예)       BOOL bError 
잘못된 예)      BOOL bNoError

1.18       Enum의 경우 열거형으로 사용시 변수명의 앞에 표기한다. (단 클래스 내부에서 #define의 대용으로 사용시에는 예외이다.)
(enum
열거형으로 사용시 타입을 항상 표기함으로써 값들이 사용시 어떠한 열거형 인지 구분을 쉽게 해준다.)
)    
enum COLOR
{
          COLOR_RED,
         COLOR_GREEN,
         COLOR_BLUE,
};

1.19       함수명의 경우 동사가 앞에 오고 명사가 뒤에 오도록 한다.
(
영문법에 맞는 규칙으로 통일되게 사용한다.)
)      GetLine(), PlaySound(), MoveWindow()

1.20       BMP MP3, ID, XML등의 약어의 표현은 첫 대문자로 한다.
)     CBmpFile, m_Mp3, strUserId, CXml

 

2          일반

2.1          bool, true, false 는 사용하지 않고 BOOL, TRUE, FALSE 사용한다.
(BOOL
등은 4바이트 자료형이고 bool등은 1비트(실제로는 1바이트) 자료형이다. 32비트 운영체계의 경우 속도와 비교하는데 걸리는 성능 부분에도 유리하고 알아보기도 좋기 때문에 위와 같은 대문자로 된 자료형을 사용한다.)

2.2          한 라인이 너무 길지 않도록 주의한다.
(
정확히 컬럼의 크기가 정해진 것은 아니지만 일반적인 프로젝트 팀에서 사용하는 일반적인 해상도(1024~1280)에서 한눈에 보기 좋도록 작성한다.)

2.3          성능 향상 및 가독성 증가를 위해서 본 가이드라인은 위배 될 수 있다. (! 확고한 근거가 존재해야 한다)
(
가이드라인의 목표는 보기 좋고 통일된 코드작성이 가장 중요한 목표이다. 특수한 경우 가독성이나 성능 향상을 위해서 더 좋은 방법이 있다. 그러한 경우에는 본 가이드라인을 따르지 않는다.)

2.4          변수의 형 변환은 (자료형) 과 같은 변환을 사용한다.
(
일반적으로 여러 서적과 C++ 권고안에서 static_cast, const_cast등의 cast를 이용한 형 변환을 권고하고 있으나 타이핑의 불편, 가독성의 감소, 다양한 cast의 적절한 사용 등으로 인한 이유로 사용하는데 어려움이 있다.)
)
int nSize = ( int ) byLength; (O)
int nSize = const_cast<int> byLength; (X)

2.5          함수의 인자는 NULL 입력이 가능하다면 포인터(*)를 이용하고 그렇지 않다면 참조(&)을 사용한다.
(
포인터 방식의 최대 단점은 NULL을 원하지 않은 경우에도 NULL이 입력될 수 있다는 점이다. 따라서 이러한 것을 근본적으로 막기 위해서는 NULL이 입력되지 않기를 원하는 함수의 인자는 참조를 사용한다.)
)     int Draw( CSurface &rSurface );                              (NULL이 입력 불가한 경우)
          void GetValue(int *pId, int *pAge, int *pDate = NULL );          (NULL
이 입력 가능한 경우)

2.6          전역함수, API함수, 표준 C++ 라이블러리의 경우 일반적으로 ‘::’ 을 가능한 사용하지 않는다. (멤버 함수와 동일한 이름인 경우에만 ‘::’ 을 사용한다.)
(
이와는 별개로 전역 함수의 사용은 최소한 한다.)
올바른 예)       int nCount = ::GetWindowCount();               int nSize = strlen( szName );
잘못된 예)       int nCount = GetWindowCount();                 int nSize = ::strlen( szName );

2.7          STL 사용시 std:: 는 사용하지 않는다.
(
프로젝트에서 STL을 표준으로 사용하기를 결정했다면 ‘using std;’을 사용한다.)
올바른 예)        std::list List
잘못된 예)      list List


2.8          지역변수는 필요한 시점에서 선언한다.
(C++
에서는 변수를 미리 선언할 필요성이 없다. 단 기능이나 사용이 비슷한 변수들이 선언된다면 가독성 증가를 위해서 미리 선언 될 수 있다.)

2.9          매직 넘버(Magic Number)는 가능한 사용하지 않는다.
가능한 #define 이나 enum, static const 등을 이용하여 매직 넘버의 사용을 최소화한다.
(
개수, 최대값, 최소값, 범위 등의 매직 넘버는 사용을 최대한 자제하나 오히려 가독성과 사용용도가 떨어지는 이미지의 좌표값과 같은 일시적인 것은 특별히 사용을 회피 할 필요는 없다. 또한 0, 1, -1의 경우는 매직 넘버에서 예외가 될 수 있다.)

2.10       goto의 사용을 자제한다.
(goto
의 사용은 프로그램의 구조를 파악하기 어렵게 한다. 하지만 매우 특수한 경우에는 사용 될 수 있다.)

2.11       전역 변수나 멤버 변수보다는 지역변수를 사용한다.
(
전역 변수와 멤버 변수는 매우 오랜 기간 동안 생존해있고 중요한 변수이기 때문에 작성자를 포함한 프로그래머들은 그 변수들을 분석하고 기억하려고 한다. 따라서 사용을 최소화 한다면 그러한 수고가 줄어든다.)

2.12       포인터, 핸들은 NULL과 비교하고 숫자는 0과 비교한다.

2.13       복잡한 구문은 임시 변수를 사용한다.
(
부적절한 3항 연산자나 각종 비교구문의 중첩을 이용한 복잡한 코드는 가독성을 저해한다.)

올바른 예)
BOOL bCompare1 = ( nCount > 100 && nSize < 50 );
BOOL bCompare2 = ( nCount == 50 || nSize < 20 );
if( bCompare1 || bCompare2 )…      

잘못된 예)
if( ( nCount > 100 && nSize < 50 ) || ( nCount == 50 || nSize < 20 ) )…


3          클래스

3.1          클레스의 기본 구조는 다음과 같다.
(
생성자, 공개함수, 비공개함수, 멤버변수의 순서로 배열하고 각각은 public, protected 등으로 추가로 명기하여 구분한다. )

)
class CSound
{
public:                                 : public
함수를 최 상단에 배치한다.
    CSound();                     :
생성자를 최 상단에 배치한다.
    virtual ~CSound();               :
종결자는 일반적으로 virtual 이다.

    void Play();                          :
멤버 함수
    void Stop();
                                        : public, protected
등은 1라인 비운다.
protected:                                  : protected
함수를 배치한다.
    void PlayWav();                  
    void PlayOgg();
                                                 :
각각의 함수별 관련성 및 블록이 있다면 1라인 비운다.
    void StopWav();
    void StopOgg();

protected:                                 :
멤버 변수를 배치한다.  
    char m_szFileName[256];
    int m_nSize;
};

3.2          모든 멤버 변수는 public으로 선언하지 않는다.
(
정보은닉과 캡슐화를 위해서 멤버 변수들은 public으로 선언하지 않는다.)

3.3          inline 함수의 경우 헤더 선언에 inline 을 표기하지 않는다.
(
헤더 파일에 inline으로 명기하여 선언을 하는 것과 별개로 실제 구현에 inline으로 작성하면 함수는 inline으로 작동된다. 클래스 헤더를 잘 알아볼 수 없게 하는 inline은 굳이 사용 할 필요성이 없다.)
)
class CSound
{
올바른 예)       BOOL Play();
잘못된 예)       inline BOOL Play();         
};


3.4          inline 함수의 경우 선언구문 1라인 아래 줄에 입력한다.
(inline
함수는 헤더 파일의 하단에 선언하고 너무 많은 inline 함수가 존재한다면 *.ini 파일을 작성하여 헤더에서 include 한다.)
)
class CSound
{
public:
          BOOL CSound ::Play();
};

inline BOOL CSound ::Play()
{
    
}

또는

class CSound
{
public:
          BOOL CSound ::Play();
};

#include “Sound.inl

3.5          클래스 선언문에 어떠한 함수라도 구현을 하지 않는다.
(
클래스의 선언문은 매우 중요한 공간이다. 그 공간에 함수의 구현이 들어간다면 함수의 이름들을 한눈에 볼 수 없어 가독성이 매우 떨어지게 된다. 따라서 모든 구현은 cpp 파일 및 별개의 인라인 함수로 구현한다.)
잘못된 예)
class CTest
{
    BOOL Play()
    {
      
    }
};

3.6          클래스의 생성자종결자는 inline함수로 구현하지 않는다.
(
성능향상을 위한 몇몇 경우를 제외하면 생성자와 종결자는 호출되는 회수는 매우 적다. 따라서 inline으로 구현하지 않는다.)

3.7          종결자는 일반적으로 virtual로 선언한다.
(
종결자가 virtual이어야 상속될 경우 등에서 올바르게 종결자가 작동된다. 따라서 상속이 되지 않기를 바라는 경우와 클래스 크기를 줄이기 위한 경우 및 성능향상을 위한 경우를 제외하고 가상함수로 선언한다.)


4          파일 및 디렉토리

4.1          클래스명과 파일명은 ‘C’를 제외한 동일한 이름을 가진다.
)     클래스명 : CFileName
        
파일명    : FileName.h, FileName.cpp

4.2          1클래스 2파일(.h .cpp)을 가진다.

4.3          클래스의 복잡도에 따라서 여러 개의 cpp 파일을 가질 수 있다.
(
종종 멤버 함수가 많다면 함수의 검색 및 수정 등이 불편하여 관리가 어려워진다. 그러한 경우 비슷한 함수 별로 파일을 만든다면 쉽게 관리가 가능하다.)
)     클래스명 : CSurfaceGdi
        
파일명    : SurfaceGdi.h, SurfaceGdiPut.cpp SurfaceGdiInit.cpp, SurfaceGdiEffect.cpp

4.4          Inline 함수가 많이 존재할 경우 .ini 파일을 생성한다.
)     FileName.inl

4.5          매우 간단하면서 비슷한 여러 개의 클래스 및 구조체의 경우 1개의 파일에 포함될 수 있다.
(
작은 클래스, 구조체마다 각각의 파일을 가진다면 파일개수의 복잡성이 증가한다.)

4.6          문서(기획서, UML) 파일은 소스파일과 다른 특정 디렉토리를 사용한다. (:Document)
(
각종 문서들을 소스파일과 함께 관리한다면 더욱더 복잡한 파일목록들이 만들어질 것이다.)

4.7          일정 규모이상의 프로젝트의 시작은 폴더구조를 설계한 이후 시작한다.
(
프로젝트 시작 시 폴더의 구조와 각 폴더 별 연관성 등을 고려하여 폴더구조를 정의하고 상호 참조 관계 등을 정의하는 것으로 프로젝트를 시작해야 한다.)
)
- [App]
- [Common]
- [Core]
- [Sound]
- [Image]
- [Document]

4.8          #include 시 상대주소를 사용한다.   ) #include ‘../BugGame/BugMain.h
(
절대주소를 사용한다면 다른 프로그래머들은 컴파일이 안될 수도 있기 때문이다.)

4.9          #include 는 시스템 헤더 -> 라이브러리 -> 자체 코드 등의 순서로 작성한다.
(#include
또한 상위 -> 하위 관계를 지키도록 하면 가독성이 높아진다.)
)
#include ‘stdio.h
#include ‘afxinet.h
#include ‘MyImageEngine.h
#include ‘MyFile.h

4.10       백업은 다른 디스크드라이브에 받고 일정기간마다 CD 또는 별개의 매체에 저장한다.
(
백업의 중요성은 아무리 강조해도 지나치지 않다.)

4.11       프로그램 코드, 이미지, 사운드를 포함한 모든 소스는 소스세이프(SourceSafe) Subversion등의 소스관리툴을 사용한다.
(
다른 프로그래머가 소스 관리툴을 이용하더라도 컴파일과 실행을 할 수 있게 한다.)


5          레이아웃

5.1          변수 또는 함수 선언 시 TAB으로 정렬하지 않는다.
(TAB
문자를 이용한 정렬은 보기가 좋기는 하지만 결국 전체 스타일은 망가뜨린다. 또한 특정 변수의 추가 / 제거시 다른 변수들의 탭이 엉클어져 다시 정돈하는 과정이 필요하므로 불필요한 편집 작업을 늘린다.)
올바른 예)
int nCount;
int nSize;
BOOL bSuccess;
CString strName;

잘못된 예)
int                   nCount;
int                   nSize;
BOOL              bSuccess;
CString            strName;

5.2          가독성을 이유로 다음과 같은 정렬 방식은 가능하다.
int nSum =       a + b + c +
                       d + e;
if(       nCount > 100 && nSize > 50 &&
         nHit == 5 )

 

5.3          TAB의 크기는 4글자로 한다.

5.4          함수마다 1라인을 띄운다.

5.5          ‘+, -, *, %, /, <, >, =, ==, +=, -=‘ 와 같은 2개의 변수를 계산하거나 비교하는 경우에는 연산자의 전후는 1칸씩 띄어 쓴다.
(
변수 단독 붙여서 사용하는 ‘++, --, !, &(참조), *(포인터)’와 같은 연산자의 경우는 예외이다.)
올바른 예)
i = a + b – c;
nSum += nCount;
if( nSize < nMaxSize )
i++;

잘못된 예)
i=a+b–c;
nSum+=nCount;
if( nSize<nMaxSize )
i ++;

5.6          일반적으로 i++ 은 사용이 가능하지만 ++i 는 사용하지 않는다.
(
속도를 위해서 후자를 사용하는 사례들이 가끔 있지만 사실상 컴파일러의 최적화로 인하여 위 내용의 속도의 차이가 존재하지 않는다. 따라서 가독성과 통일성을 이유로 전자만 사용한다.)

5.7          소괄호의 사용은 다음과 같이 공백입력을 한다. (함수, if, while, for, switch, 형 변환 등 모두 동일함)
)
if( bSuccess ) …
int DoSomething( int nParam1, int nParam2 );
for( int I = 0; I < nCount; I++ )
int nIntSize = sizeof( int );
int nValue = ( int ) byValue;

5.8          중괄호의 사용은 다음과 같은 형식으로 한다. (함수, if, while, for, switch 모두 동일함)
올바른 예)
if( bSuccess )
{
          DoSomething();
         
}

int DoSomething()
{
         
}

잘못된 예)
if( bSuccess ){
          DoSomething();
         
}

if( bSuccess )
          {
          DoSomething();
         
          }

5.9          가독성을 위하여 다음과 같이 TAB으로 정렬이 가능하다.
(
본 가이드의 핵심은 가독성이 좋은 코드를 만드는 것을 도와주는 것이다. 따라서 그것을 위해서 몇몇 규범들은 위배 될 수 있다. 하지만 아래내용을 절대로 남용하지 않는다.)
) 
if(                    nCount == 0 )                   DoSomething();
else if(             nCount == nMaxCount )    DoSomething();
else                                                        DoSomething();

nValue =         ( nSize               * nCurrentSize )               / nDiv +
                       ( nCount             * nCurrentCount )            / nDiv +
                       ( nTime              * nCurrentTime )              / nDiv;

switch( nState )
{
          case STATE_NORMAL :   DoNormal(); break;
          case STATE_OVER :        DoOver(); break;
          case STATE_DOWN :      DoDown(); break;
}

5.10       Switch 구문은 다음과 같은 형식으로 한다. (‘:’ 의 띄어쓰기에 유의한다.)
)
switch( nState )
{
// case
관련 주석은 여기에
case STATE_NORMAL :
          //
아래 주석은 여기에
          DoSomething();
          break;

case STATE_OVER :
          DoSomething();
          break;

default :
          DoSomething();
          break;
}

5.11       한 줄 조건문반복문은 다음과 같이 모두 사용 할 수 있다. 하지만 동일 구문에 여러 스타일을 혼용하여 사용하면 안된다.
올바른 예)
if( bSuccess ) DoSomething();
else DoSomething();

if( bSuccess )
          DoSomething();
else
          DoSomething();

if( bSuccess )
{
          DoSomething();
}
else
{
          DoSomething();
}

잘못된 예)
if( bSuccess ) DoSomething();
else
{
          DoSomething();
}

if( bSuccess ) DoSomething();
else
          DoSomething();

if( bSuccess )
{
          DoSomething();
}
else   DoSomething();

5.12       ‘return’ 윗라인은 1줄 여백으로 한다.
올바른 예)
BOOL IsSuccess()
{
          BOOL bRtn = m_bRtn;

          return bRtn;
}

잘못된 예)
BOOL IsSuccess()
{
          BOOL bRtn = m_bRtn;
          return bRtn;
}

5.13       중괄호를 닫는 부분과 if, for등의 조건, 반복 구문에서는 1줄 여백을 가진다.
(
적절한 줄 여백은 코드를 읽기 쉽게 한다. 참고로 if-else구문은 else에만 적용한다.)
올바른 예)
if( bSuccess )
{
         
}
else
{
         
}

nSum += nCount;

잘못된 예)
if( bSuccess )
{
         
}
nSum += nCount;

 

6          If / switch / for / while / switch 구문

6.1          If / switch / for / while 구문 자체에서 복잡한 계산을 하지 않는다.
(
조건문 내의 복잡한 계산은 코드의 가독성을 저해한다.)
올바른 예)                                  // 잘못된 예)
nSum = 0;                                  //
for( int I = 0; I < 100; I++ )             // for( int I = 0, nSum = 0; I < 100; I++, nSum += I; )
{                                                // {
          nSum += I;                        //
          printf( “%d”, nSum );        //         printf( “%d”, nSum );
}                                                // }

hFile = open( szFileName, ‘w’ );// if( hFile = open( szFileName, ‘w’ ) )…
if( hFile )                                     // {
{                                                // }
}                                                //


6.2          Do – While 은 가능한 사용하지 않는다.
(While
만을 사용하는 것이 가독성이 증가된다.)

6.3          무한 루프 구문은 while( TRUE ) 또는 while( 1 )을 사용 한다.
올바른 예)
while( TRUE )
{
}

while( 1 )
{
}

잘못된 예)
for( ; ; )
{
}

do
{
} while( 1 )

6.4          BOOL HRESULT 등의 리턴 값을 TRUE, 0 과 비교하지 말고, ! 이나 비교 없이 단독으로 사용한다.
(
이것은 몇몇 버그가 있는 API 함수들을 위한 것이다. 즉 매뉴얼 상에는 리턴 값이 BOOL 이더라도 0 1 리턴 하지 않는 경우가 종종 있다. 따라서 일반적으로 0 인가 0 이 아닌 가로 구분하거나 본 구문과 같이 처리하는 것이 일반적이다. )
올바른 예)
if( IsMain() ) 
if( !IsMain() ) 

잘못된 예)
if( IsMain() == TRUE ) …


7          주석 (자세한 내용은 별첨 첨부)

7.1          주석은 모국어(한국어)로 작성한다.

7.2          주석은 Doxygen 표준을 사용한다.

7.3          복잡성에 따라서 세부적인 설명 및 예제를 포함할 수 있다.

7.4          일반적인 주석의 경우 /*, */ 보다는 가능한 // 으로 주석을 사용한다.
(Doxygen
의 경우를 예외로 한다.)

7.5          주석은 내용의 앞 라인과 같은 컬럼에 기록한다.
(
몇몇 특수한 상황에서 라인 뒤에 입력하는 경우도 있다.)
올바른 예)
//
성공했다면
if( bSuccess )
{
          //
어떤일을 한다.
          DoSomethinh();
}

잘못된 예)

//
성공했다면
if( bSuccess )
{
//
어떤일을 한다.
          DoSomethinh();
}

if( bSuccess ) //
성공했다면
{
          DoSomething(); //
어떤일을 한다. (X)
}


8           권장하는 함수명
일반적으로 생성, 초기화하는 부분은 BOOL 을 리턴 하고 파괴, 제거, 닫는 부분은 void 형 함수로 처리한다.
권장하는 함수명 뒤에 CreateImage, OpenFile과 같이 각종 명사를 붙여서 사용 할 수 있다.

8.1          Create / Destroy           생성 / 파괴

8.2          Open / Close                열다 / 닫다

8.3          Init / Final                      초기화 / 마지막

8.4          Play / Stop                   시작 / 정지

8.5          Get / Set                      얻음 / 넣음

8.6          Add / Remove              추가 / 삭제 (일반적으로 순서는 상관 없다)

8.7          Insert / Delete              (중간에) 삽입 / (중간에) 삭제

8.8          Start / Stop                   시작 / 정지

8.9          Suspend / Resume      일시 정지 / 재 시작

8.10       Begin / End                  시작 /

8.11       First / Last                    처음 /

8.12       Next / Previous             이전 / 다음

8.13       Increment / Decrement 증가 / 감소

8.14       Old / New                     이전 / 새로

8.15       Up / Down                    /

8.16       Min / Max                     최소 / 최대

8.17       Show / Hide                 보여줌 / 가림



참고 :
http://geosoft.no/development/cppstyle.html

http://blog.naver.com/iliyard/9298516

http://blogs.msdn.com/brada/articles/361363.aspx

Effective C++, Scott Meyers

More Effective C++, Scott Meyers

Code Complete, Steve McConnell

출처 - http://tong.nate.com/swallow/

'Programming > C/C++' 카테고리의 다른 글

[C/C++] 복합대입연산자  (1) 2010.01.14
[C/C++] 문자열 라이브러리 함수 구현  (0) 2010.01.13
[C/C++] sprintf  (0) 2010.01.13
[C/C++] 문자열 복사  (0) 2010.01.13
Posted by 시그v
1월달에는 나의 목표기도 했었던
MOS 자격증 따기 프로젝트를 
진행하고 있었어요
1월 말 즈음에 시험을 다 보고, 
성적을 확인하려고 했는데,

로그인이 안되는거 있죠..-_ㅜ


여기저기저기러기(엥?) 헤매다니다가
어느 블로거님도 저와 같은 상황이더라구요..

YBM측에서 MOS시험 ID를 'M+주민번호13자리'로 일괄적으로 만들라고 했었거든요..
이게 개인정보보호 차원에서 KISA(한국정보보호진흥원)에서 권고가 왔었다네요.

그래서 'M+주민번호 13자리'의 ID를 
새로 기존사용자들까지 바꾸게 되었다고 합니다..


공지사항 관련 글 주소-*

http://www.ybmit.com/mos/notice/notice_view.asp?n_seq=573

ID 찾는 방법
홈페이지로 접속해서
'시험 아이디 찾기'를 클릭해서
주민등록번호와 이름을 기입하면,
시험 ID를 알려주는데요.

ID..상당히 어렵습니다..
이걸 어떻게 외우나...

비밀번호는 기존 그대로 이니까,
ID를 찾아서 접속하시면 되시겠습니다




[+] 덧붙여서 MOS 시험 성적 확인 하는 방법은,

위의 주소로 접속한 다음에 
오른쪽 상단의 Login을 눌러서
자신의 ID와 Password를 넣어서 결과를 보면 됩니다^^

 

시험점수도 포함하여 자신이 본 시험의 결과가 나오게 됩니다!

저는 MOS Master가 되었습니다~(짜잔)

아무튼 참 답답했는데 우연치 않게 알게 되어
혹시나, 모르는 사람들이 있을까봐 블로그에 글을 쓰게 되었습니다~
도움이 되었으면 좋겠네요..


[출처]마법부리는곰  http://wizardbear.net/180
Posted by 시그v

error LNK2005: "public: __thiscall Cdefine::Cdefine(void)" (??0Cdefine@@QAE@XZ) already defined in Fluid_Simulation_menu.obj

error LNK2005: "public: __thiscall Cdefine::~Cdefine(void)" (??1Cdefine@@QAE@XZ) already defined in Fluid_Simulation_menu.obj

 

헤더 파일에 함수의 정의해서 그렇다.

에러를 보면 Cdefine(void)와 ~Cdefine(void) 함수가 헤더파일에 정의되어서 뜨는 에러이다.

'Programming > Visual Studio' 카테고리의 다른 글

error LNK2005:  (0) 2010.01.13
error LNK2059  (0) 2010.01.13
error LNK1104  (1) 2010.01.13
error LNK2019 fatal, error LNK1120  (0) 2010.01.13
VisualStudio 메모리 누수 체크 사용하기  (0) 2009.12.19
Posted by 시그v

1. 충돌처리
· 직선 교차점 알고리즘

1.        직선을 정의하는 두 점(선분의 시작점과 끝점)이 모두 평면의 한쪽 방향에 위치하고 있다면 직선은 
절대로 평면과 교차할 수 없기 때문에 이 두 점이 폴리곤의 양쪽 방향에  존재하는지를 알아본다.
2.        폴리곤을 정의하는 평면과 직선의 교차점을 계산한다.
3.        평면과 직선의 교차점이 폴리곤 영역 안에 포함되어 있는지를 검사해서 폴리곤 영역에 포함될 경우 
충돌을 나타내고 그렇지 않을 경우 충돌하지 않은 것을 나타낸다.

· 평면과 직선의 교차
직선을 정의하는 두 점이 폴리곤을 정의하는 평면의 양쪽에 존재하는지를 알아보는 첫번째 과정은 상당히 쉽다. 
수학에서 정의하는 3차원 평면에 대한 방정식으로 유도할 수 있다.

평면의 방정식
Ax + By + Cz + D = 0
위의 식에서 A, B, C는 평면의 노말 벡터의  x, y, z 요소를 각각 나타내고 D는 폴리곤 위에 존재하는 임의의 
한 점을 방정식에 대입해서 구할 수 있는 값이다.

평면의 방정식의 특징은 평면위에 존재하는 어떤 점을 x, y, z에 대입하더라도 항상 0 이 된다. 이러한 특성을 
이용하여 충돌처리를 할 수 있는데 평면의 방정식의 특성상 평면의 뒤쪽에 존재하는 점을 방정식의 x, y, z에 
대입한다면 음수 값을 가지고 앞쪽에 존재하는 점을 대입하면 양수 값을 갖게 된다. 따라서 직선을 정의하는 두 
점이 평면의 양쪽에 존재하는지를 알아보기 위해서는 단순히 두 점을 평면의 방정식에 대입해서 그 부호가 서로 
다른지를 알아보면 된다.
그럼 다음 함수를 보자
bool LineCrossPlane( Vector *line, Vector &normal, float &D )
{
        float        sign1, sign2;

        sign1 = (normal.i * line[0].x + normal.j * line[0].y + normal.k * line[0].z + D);
        sign2 = (normal.i * line[1].x + normal.j * line[1].y + normal.k * line[1].z + D);

        if( sign1 * sign2 >= 0.0 )
         return false;
        
return true;
}
위의 말을 더 쉽게 풀이해 보면
한 삼각형(평면)의 Face Normal을 Nx, Ny, Nz라고 정의하구 삼각형(평면)의 한점을 Px, Py Pz 라고 한다면, 
삼각형의 노말과 그 삼각형에 속하는 한점을 DotProduct를 하면 0 이 된다.이 말을 평면의 방정식에 대입하면 
이렇게 된다...
Nx * Px + Ny * Py + Nz * Pz + D = 0 ........ (1)
(평면의 방정식 A*x + B*y + C*z + D = 0 )

여기서
A = Nx
B = Ny
C = Nz
D = -( Nx * Px + Ny * Py + Nz * Pz )
Px, Py, Pz 는 평면에 속하는 한점이다.

· 교차점 계산
직선을 정의하는 두 점이 평면의 양쪽에 존재한다면 반드시 직선과 폴리곤이 교차하는 교차점이 존재한다고 
할 수 있다. 이러한 교차점을 구하기 위해서는 평면과 직선을 모두 방정식으로 표현해야 한다.

평면의 방정식
Ax + By + Cz + D = 0

직선을 방정식으로 표현하는 방법은 여러 가지가 있지만 그 중에서 직선 위에 존재하는 모든 점을 가장 간편하게 
나타내는 방정식은 직선의 시작점으로 부터의 거리를 이용하는 방법이다.

P(d) = Po + dD
위의 식에서 D는 직선의 방향을 나타내는 단위 벡터이고 P(0)는 시작점을 그리고 d는 P(0)으로부터 D 벡터가 정의
하는 방향으로 떨어져 있는 거리를 나타낸다. 따라서 P(d)는 P(0)으로부터 d만큼 D방향에 떨어져 있는 직선 위의 
한 점을 나타낸다. 위에서 정의한 일반식을 x, y, z 요소로 분할하면 다음과 같음을 알 수 있다.

Px = xo + dDx
Py = yo + dDy
Pz = zo + dDz
위에서 Px, Py, Pz는 직선의 시작점 xo, yo, zo로부터 Dx, Dy, Dz 방향으로 d만큼 떨어져 있는 직선 위의 한 점에 
대한 x-, y-, z- 요소를 나타낸다.

그럼 임의의 한 점에 대한 평면의 방정식을 써보면
Axo + AdDx + Byo + BdDy + Czo + CdDz + D = 0
위와 같이 된다.
만일 직선 위의 한 점 Px, Py, Pz가 평면위에 존재한다면(교차점이라면) 이 방정식의 왼쪽 항은 0값을 갖게 된다. 
따라서 위의 방정식으로부터 교차점을 찾기 위해서 먼저 상수 d에 대해 정리하면

d(Adx + BDy + CDz) + Axo + Byo + Czo + D = 0                 이것을 다시 정리하면
d = -(Axo + Byo + Czo + D) / (ADx + BDy + CDz)

Dx, Dy, Dz는 직선의 방향을 나타내는 단위 벡터이고 A, B, C, D는 평면을 나타내는 방정식의 계수다. 또 xo, 
yo, zo는 직선의 시작점을 나타내기 때문에 모두 상수임을 알 수 있다. 따라서 아무 문제없이 위의 방정식으로부터 d값을 구할 수 있다.

¨ NOTE
만일 평면과 직선이 서로 평행이라면 위의 방정식의 분모는 0 이 된다. 그 이유는 위 방정식의 분모를 보면 
평면에 수직인 법선벡터(A, B, C)와 직선의 방향을 나타내는 벡터(Dx, Dy, Dz)에 대한 내적임을 알 수 있다. 
만일 평면과 직선이 평행이라면 평면에 수직인 법선 벡터와 직선의 방향 벡터가 이루는 각은 90도이다. 따라서 
내적 정의에 의해 0이 된다.

함수는 다음과 같다.
bool  LineIntersectPlane( Vector &point, Vector *line, Vector &normal, float &D )
{
        Vector line2 = line[1] – line[0];
        float        d, first, second;
        
        line2.Normalize();        // 단위벡터로 만든다.

        first = -( normal.i*line[0].x + normal.j*line[0].y + normal.k*line[0].z + D );
        second = ( normal.i * line2.i + normal.j * line2.j + normal.k * line2.k );

        if( second == 0 )
          return false;
        
        d = first / second;

        if( d < 0 )
          return false;

        point = (line[0] + (Vector)(line2 * d));
        return true;
}

· 폴리곤 영역에서 충돌이 일어났는지 판별
폴리곤 영역에서 충돌이 일어났는지 판별하기 위해서는 교차점과 폴리곤의 Vertex가 이루는 각의 합을 계산해서 
360도와 같다면 영역에 포함된다고 할 수 있다.

내적 공식
A · B = |A| |B| cosq
위에서 q는 두 벡터가 이루는 각을 나타낸다. 따라서  이 방정식을 q에 대해 풀면 다음과 같다.

q = cos¯¹ (A · B / (|A| |B|))
위에서 cos¯¹은 코사인 함수의 역함수를 나타낸다. 폴리곤의 버텍스로부터 벡터 A와 B를 계산하기 위해서는 
단순히 각 버텍스에서 교차점을 빼면 된다.

내적 계산
A·B = x1x2 + y1y2 + z1z2

함수로 표현하면
bool  IsPointBounding( Vector &point, Vector  *Poly, long VertexCount )
{        
float Angle = 0.0f;

const MATCH_FACTOR = 0.99;
Vector A, B;

for( long n = 0; n {
        A = (Vector)(Poly[n] – point);
        B = (Vector)(Poly[(n+1) % VertexCount] – point);
        Angle += acos( A.Dot(B) / (A.Mag() * B.Mag()));
}

if( Angle >= (MATCH_FACTOR * (2.0 * PI)) )        // 360도는 2PI
  return true;
        
return true;
}


위의 세가지 과정을 통합한 것을 함수화 하면
bool LineIntersectsPolygon( Vector *line, Vector *poly, long VertexCount, Vertex &iPoint )
{
float D;
Vector          PolyNormal;

MakeNormal( poly, PolyNormal, D );

if( !LineCrossPlane( line, PolyNormal, D ) )
        return false;

LineIntersectPlane( iPoint, line, PolyNormal, D );

if( !IsPointBounding( iPoint, poly, VertexCount ) )
        return true;
}

· 직선 교차점 알고리즘을 이용한 폴리곤 충돌 검사
위에서 말한 직선 교차점 알고리즘은 직선과 폴리곤의 충돌을 알아보는 방법이었다. 그렇다면 지금부터 이 
알고리즘을 이용해 폴리곤간의 충돌검사 알고리즘을 만들어 보도록 한다. 직선 교차점 알고리즘을 이용해서 
폴리곤 충돌 검사를 하는 것은 매우 단순한 작업이다. 먼저 충돌 검사를 수행할 폴리곤을 A, B라 하고 폴리곤 
A의 각 경계선을 직선으로 정의한다. 그리고 이렇게 정의된 직선들과 폴리곤 B를 직선 교차점 알고리즘을 
이용해서 각각 충돌 검사를 한다. 충돌 검사에서 사용된 직선들은 폴리곤 A의 경계선을 나타내기 때문에 
이들 중 어느 하나라도 폴리곤 B와 교차한다면 두 개의 폴리곤은 서로 교차한다고 말 할 수 있다. 그러나 
어느 한 폴리곤만을 기준으로 처리할 경우 두 개의 폴리곤이 서로 교차함에도 불구하고 교차점을 알아낼 수 
없는 상황이 발생하게 된다. 따라서 A, B 폴리곤의 경계선을 모두 상호 비교해야 한다.

이것을 함수화 하면
bool  PolygonIntersect( Vector *A, long AVertexCount, Vector *B, long BvertexCount, Vector &iPoint )
{
long n;
Vector         Edge[2];

for( n = 0; n < AVertexCount; n++ )
{
  Edge[0] = A[n];
  Edge[1] = A[(n+1) % AVertexCount];
if( LineIntersectsPolygon( Edge, B, BvertexCount, iPoint ) )
        return true;
}

for( n = 0; n < BVertexCount; n++ )
{
  Edge[0] = B[n];
  Edge[1] = B[(n+1) % BVertexCount];
if( LineIntersectsPolygon( Edge, A, AvertexCount, iPoint ) )
        return true;
}

return false;
}

· 복잡한 충돌검사 처리
충돌 검사 알고리즘은 폴리곤에 평행하게 접근하는 직선과 충돌하기 바로 직전에는 평면의 앞쪽에 있다가 
충돌 후에는 폴리곤의 반대편으로 이동하는 경우 충돌을 정확하게 알아내지 못한다. 보통의 경우 이러한 
문제는 따로 처리할 필요가 없다. 왜냐하면, 가상세계의 객체는 복잡한 폴리곤으로 구성되기 때문에 객체를 
구성하는 폴리곤 중 하나라도 충돌이 포착되면 충돌처리를 해주면 되기 때문이다.

그러나 객체의 이동 속도가 굉장히 빠르다거나 혹은 사용자의 컴퓨터가 느릴 경우 객체의 어떤 폴리곤도 
충돌 객체에 걸리지 않고 빠져나가는 경우가 발생하게 된다. 이 문제를 해결하기 위한 가장 간편한 방법은 
첫번째 프레임에서의 객체의 위치와 다음 프레임에서의 객체의 위치를 연결하는 직선을 이용하는 것이다. 
이 직선 중에 하나가 다른 물체와 교차한다면 두 객체가 충돌한 것이기 때문에 물체를 이동시키지 말아야 한다.

· 충돌 검사를 위한 최적화
많은 폴리곤에 대하여 충돌검사를 수행한다면 수많은 수학적 연산에 의해 수행 속도를 떨어뜨릴 위험이 있기 
때문에 충돌검사 최적화를 해주어 충돌검사 회수를 감소시킬 수 있다.
첫번째 최적화 방법은 각 폴리곤과 객체에 대한 바운딩 스피어를 이용하는 방벙이다. 움직이는 객체의 바운딩 
스피어를 가상세계에 존재하는 다른 객체의 바운딩 스피어와 먼저 검사해서 서로 충돌이 발생했다면 각 객체가 
갖는 폴리곤의 바운딩 스피어와 다시 비교해서 충돌이 발생한 폴리곤을 찾는다. 마지막으로 이렇게 찾은 
폴리곤에 대해서 다시 라인 교차점 알고리즘을 이요해 정확한 교차점을 계산한다. 이방법은 바운딩 스피어를 
이용해 비교하는 범위를 줄여 가는 최적화 기법이라 할 수 있다. 따라서 이 방법을 사용할 경우 객체가 갖는 
모든 폴리곤에 대해 라인 교차점 알고리즘을 적용해야 하는 비효율을 줄일 수 있게 된다. 두개의 바운딩 
스피어가 교차하는지를 알아보기 위해서는 두 바운딩 스피어의 중심간의 거리를 계산하면 된다. 만일 이 
거리가 두 바운딩 스피어의 반지름의 합보다 작다면 두개의 구는 서로 교차하고 있다.

¨NOTE
폴리곤 또는 객체에 대한 바운딩 스피어를 계산하기 위해서는 먼저 바운딩 스피어의 중심점으로 사용되는 
객체의 중심점을 계산해야 한다. 모든 버텍스의 x, y, z값을 각각 더한 값을 버텍스의 개수로 나누면 객체의 
중심점을 구할 수 있으며, 이 중심으로부터 가장 먼 거리에 있는 버텍스와 거리가 바로 바운딩 스피어의 
반지름이 된다.

두 번째 최적화 방법은 가상세계를 작은 단위로 분할하는 방법이다. 이렇게 분할된 공간 안에 속하는 폴리곤을 
리스트로 관리하면서 충돌 검사를 할 때는 이 영역에 포함되는 폴리곤에 대해서만 충돌 검사를 수행하는 방법이다. 
이 방법을 사용하게 되면 특정 객체가 존재하는 가상세계의 일부 영역에 대해서만 충돌 검사를 할 수 있기 때문에 
충돌 검사를 해야하는 횟수를 크게 줄일 수 있는 장점이 있다. 하지만 복잡한 자료구조를 구성해야 한다는 단점이 있다.

· 바운딩 박스
바운딩 박스를 만들 때 우선 모든 면의 노말이 밖을 바라보게 바운딩 박스를 만들던지 아니면 모든면이 안으로 보는 
바운딩 박스를 만들어야 한다. 그럼 평면에 방정식을 이용해서 바운딩박스의 각각의 면에 한점이 면의 앞에 있는지
뒤에 있는지를 알수가 있을 것 이다. 만약 모든 바운딩박스의 면을 밖으로 바라보게 하였다면 한점이 바운딩박스의 
모든면에 대해서 평면의방정식 < 0 을 성립한다면 그 한점은
바운딩 박스에 안에 들어 있는 것임을 알수 있다.

· 바운딩 충돌
바운딩 박스는 8점으로 이루워져 있으므로 바운딩박스 & 바운딩박스의 충돌은 한쪽의 바운딩 박스에 다른쪽의 
바운딩박스의 8점을 검색해서 충돌여부를 판단하구 충돌이 없다면 이번에는 반대로 한번 더 검사해서 최종 결정을 
내리면 된다.

· 몇가지 주의점
바운딩박스가 만약 움직이는 물체에 붙어있다면 그 물체가 움직이고 회전하는 값을 그대루 바운딩 박스에 적용해야 
합니다. 바운딩 박스가 회전을 하든지 움직일때 마다 항상 새로 바운딩박스의 면의 노말을 구해서 평면의 방정식에 
사용해야 한다. 그래야 정확한 충돌을 찾을 수 있다.


[원본] http://expert3d.egloos.com/598593
Posted by 시그v

2009. 12. 19. 03:35 재테크

<저축실패습관 10>


<저축실패습관 10>

 

*오래 전 본 글인데, 지금 보니 새삼스레 느껴지는 게 있어 이렇게 올립니다.

 

대부분의 사람들은 하는 대로 “그냥” 저축을 한다. 저축의 필요성을 느끼고 저축을 하면서도 재테크라는 인식이 부족하다. 그냥 막연하게 통장을 만들고 얼마만큼의 돈을 넣으면 끝이라 생각한다. 그리고 빼먹지 않고 기한을 채우면 ‘열심히 저축을 하니까 알뜰히 사는 거야’ 라는 착각에 빠지는 경우도 있다.

 

하지만 분명히 말하자면 저축은 “그냥” 하는 것이 아니다. 저축은 가장 기본적인 재테크다. 이자계산법 하나 모르면서 재테크를 논한다는 건 참 웃긴 모양이 아닐 수 없다. ‘그냥 대충하면 되지 이자 몇 푼 차이난다고 그러느냐?’고 말하는 사람들도 있다. 하지만 단연코 말하건데 그런 사람은 부자가 되려는 기본이 안 되어 있는 사람이다.

 

 ‘그냥’ 하는대로 하면 결국 자기만 손해다. 그냥 대충대충 넘어가서 조금만 신경 쓰면 받을 수 있는 이자를 못 받는다면 본전이 아니라 손해다.

 

몰라서 손해 보는 것은 조금 덜 억울할 수 있어도 손해 보는 건 마찬가지다. 알면서 손해 보는 건 한마디로 바보들이 하는 행동이다. 알면서 손해 보는 행동을 하는 건 어디 가서도 하소연 못한다. 오히려 바보라는 소리만 더 들을 뿐이다.

그럼 사람들이 무엇을 몰라 손해를 보는 것일까?

 

사람들은 적립식펀드 등 일부 간접상품이 수익률이 높아 목돈을 훨씬 빨리 모을 수 있다고 생각한다. 하嗤?수수료와 위험성 등을 감안한다면 꾸준하게 은행에 저축하는 편이 목돈을 안정적으로 더 빨리 모을 수 있다. 즉 테크닉이 끈기를 이기지 못하는 것이다.

 

절약해서 무조건 저축을 많이 하면 된다고 생각하는 경우가 있는데 그건 잘못된 생각이다. 무계획적으로 저축하면 단시간에는 돈이 좀 모일지 모르지만 빨리 지칠 수 있고 예기치 못한 일들이 생기면 저축을 해지 해야 하는 경우도 생긴다. 그러므로 단기-중기-장기 생활설계를 하고 그에 맞는 저축 포트폴리오를 짜야한다.

 

무작정 통장의 갯수가 많으면 저축을 잘하고 있다고 생각하는 경우가 있다. 하지만 통장의 개수와 제대로 된 저축은 별 상관이 없다. 돈의 용도에 따라 몇 가지 유형의 통장을 만들어서 적정한 수의 통장을 가지고 체계적으로 관리해야 한다. 통장 관리도 재테크이기 때문이다. 예를 들어 급여통장과 생활비통장을 따로 분리하면 효율적으로 지출을 통제할 수 있다.

 

보험을 저축의 일종으로 이해하는 사람들이 의외로 많다. 보험은 저축이 아니다. 요즘 저축과 보험을 합친 저축성보험을 이용하는 경우가 많은데 생각보다 크게 도움이 되지 못한다. 목돈을 모으기 위한 것이라면 저축을 이용해야 하고 예기치 못한 사고에 대한 대비라면 보장성보험을 이용하는 것이 더 많은 혜택을 볼 수 있다.

 

비싼 대출이자를 내고 있으면서 적금을 들고 있다면 참으로 많은 손해를 보고 있는 것이다. 일반적으로 대출이자가 적금이자보다 훨씬 높기 때문에 빨리 대출을 갚는 것이 현명하다. 그리고 대출을 갚을 때는 상환계획을 짜서 체계적으로 상환해야 한다.

 

저축의 이자에도 15.4%의 세금을 떼는데 비과세(0%), 저율과세(1.4%), 세금우대(9.5%) 등의 절세형 저축상품을 충분히 활용하지 못해서 15.4% 세금 다 내는 것은 참으로 손해를 자초하는 멍청한 행동이다. 가능하면 가족들의 명의를 모두 이용해서 최대한 활용해야 한다. 하지만 무조건 절세형 상품이 유리한 것은 아닌 경우도 있으므로 절세형 상품의 금리상승 효과를 꼭 따져봐야 한다.

 

의외로 이자계산법을 제대로 모르는 사람들이 많다. 요즘은 각 금융기관 홈페이지에 금융계산기가 있어 편리하게 사용할 수 있지만 그래도 복리, 단리의 이자계산법 원리는 알고 있어야 한다. 원리를 알고 있어야 가입하려는 상품의 조건을 따져보고 작은 이자를 더 건질 수 있기 때문이다. 또한 예금이자를 더 받을 수는 있는 방법들을 잘 활용해야 한다. 예를 들어 24개월 보다 25개월 가입하는 것이 이자가 더 많은 경우가 있다.

 

표면적으로 단리이자가 복리이자보다 높다고 해서 무조건 표면금리가 높은 단리를 이용하는 것도 손해 보는 일이다. 단리는 만기 때 전체 액수에 대해서만 이자를 주지만 복리는 일정기간마다 이자에 다시 이자를 붙이기 때문에 시간이 지날수록 이자가 많아진다. 물론 짧은 기간이면 복리가 별 이득이 되지 않을 수도 있지만 장기상품일 때는 복리가 위력을 발휘한다.

 

저축을 하면서 세대주가 아니거나 되어 본 적이 없다면 큰 손해를 보고 있는 것이다. 세대주가 되면 장기주택마련저축에 가입해서 비과세와 소득공제를 받을 수 있고 청약저축에 가입해서 소득공제 혜택을 받을 수 있고 또한 투기과열지구에서는 75%까지 무주택우선청약의 기회를 가지기 때문이다.

 

요즘 은행들이 수수료를 높여서 이익을 많이 챙기고 있다. 따라서 금융거래를 할 때마다 생각보다 비싼 수수료를 내는 것도 적지 않은 손해이다. 수수료를 아끼는 가장 좋은 방법은 무엇보다도 폰뱅킹, 인터넷뱅킹 등의 전자금융을 활용하는 것이다.

알면서 손해보고 바보라는 소리 듣기 싫으면 손해 보지 않는 방법들을 찾아내 그 방법으로 저축하면 자연스럽게 이자를 더 받을 수 있을 것이다.

 

출처-다음 카페 '저축나라',  저서-저축기술 

'재테크' 카테고리의 다른 글

[일반] 월급관리 유의사항 10  (0) 2010.01.14
[펀드] 펀드의 기초 상식  (0) 2010.01.14
20대에 부자가 되는 14가지 노하우  (0) 2009.12.19
Posted by 시그v

1. 천생연분 직장을 찾아라


진정 자기가 좋아하고 잘할 수 있는
일이 무엇인지 깊이 생각해 보고 직업 선택을 해야 한다.
미래는 고소득 직종이라는 말이 사라지고
어느 분야에서든 전문성과 차별성을 가진 사람이
살아남는 시대가 올 것이다.


2. 맞춤형 전략을 갖자


인생이라는 그라운드를 뛰고 있는 우리에겐
자신의 일에서 성공을 쟁취하기 위한 꼼꼼한 전략이 필요하다.
주의해야 할 점은 남이 하는대로 무조건 따라하는 것이 아니라
자신을 먼저 파악하고 그에 맞는 전략을 세워야 한다는 것.


3. 같은 꿈을 꾸는 사람들과 자주 만나라


20대는 많은 부류의 사람들과 어울릴 수 있는 시기다.
이때 자신과 같은 꿈을 갖고 있는 사람들과 만나는 게 중요하다.
정보를 함께 공유하고 꿈을 이루기 위한
여러 가지 방안도 함께 생각해 볼 수 있다.

4. 외국어 공부하는 비법을 터득하라


글로벌 시대, 영어 공부의 중요성은 더 이상 설명할 필요가 없다.
영어공부는 치열한 생존수단이다.
영어 잘하는 것 하나만으로 더 좋은 조건의 직장을 찾을 수가 있고
몸값을 두 배로 받는 세상이다.
영어 실력은 부를 끌어 오는 적극적인 수단이다.


5. 역할 모델을 따라해라


목표를 갖게 되었으면 목표를 이룬 사람을
모델로 해 매진하는 것도 좋은 방법이다.
초보자는 아는 것도 적고 목표에 가깝게 가는 방법을
판단하기 어렵기 때문이다.


6. 시간을 관리하자.

속도의 시대. 돈을 관리하는 것보다

시간을 관리하는 것이 중요한 세상이다.
시간을 관리할 수 있는 가장 중요한 방법은
자신에게 가장 효율적인 시간이 어느 때인지를 파악해
그 시간을 적극적으로 활용하는 것이다.


7. 신문 경제면에 매일 눈도장을 찍어라

경제교육을 위한 가장 좋은 방법은

신문의 경제면을 매일 꾸준히 보는 것이다.
어려운 용어와 그래프가 부담스럽더라도 기죽지 말고
모르는 것을 하나씩 체크해 가며 알아두면
어느새 경제적 감각이 생길 것이다.


8. 책! 너는 내 운명, 손에서 놓지 말자


부자가 되겠다고 결심한 사람에게 책은 필수다.
재테크와 주식에 관련된 책을 읽기로 마음먹었다면

한꺼번에 두 세권을 산다.
한권만 읽어도 되지 않을까 하는 생각이 들지만
두 권을 읽으면 두 배의 효과 그 이상을 얻게 된다.
같은 주제라도 저자에 따라 자신의 생각을 전달하는 방법이 다르며
같은 주제의 책을 두 권 읽으면 복습의 효과도 볼 수 있다.


9. 말 딸리는 사람이 되지 말자

휴먼 네트워크 시대에서는 말 잘하는 것도 능력이다.
말을 잘해야 상대방을 잘 설득시킬 수 있기 때문이다.
말 한마디가 큰 경제력을 행사한다.


10. 경험의 경력을 높이자

이력서에 쓰지 못하는 것일지라도 자신의 경험경력을 높여보자
아르바이트, 여행, 가릴 것 없이 많은 경험을 해보자.
20대에는 누구보다 많은 아르바이트 경험을 해 보는 것이 중요하다.
아르바이트는 용돈도 안겨주고

더할 나위 없는 인생 경험을 쌓게 해준다.


11. 메모하는 습관을 갖자

정보가 쏟아지는 시대. 인간의 두뇌가 모든 것을 기억할 수는 없다.
그래서 메모의 중요성이 강조된다.
순간적으로 떠오른 아이디어는

시간이 지나면 기억할 수 없기 때문에
항상 메모할 것을 휴대하고 다녀야 한다.


12. 열애에 빠지자


지금 당장 돈벌이가 되지 않는다 해도

미치도록 좋아하는 일을 찾고 해보자.
차별성과 전문성이 무기가 되는 시대라는 점을 기억해라.
옛날에는 단순한 놀이라도 생각했던 것이
사업이 되기도 하고 직업이 되기도 한다.
아무 생각 없이 좋아서 몰두할 수 있는

일을 평생의 동반자로 만들며 열애에 빠지자.


13. 남은 생애를 위해 체력을 관리하자


정신적인 스트레스를 이기려면 건강은 기본이다.
건강과 체력은 다른 사람에게 신뢰를 주고

열정적인 삶을 사는 바탕이 된다.
체력은 모든 일의 전제조건이다.


14. 긍정적인 마인드를 갖자


누구나 겪는 실패지만 그 실패를 잘 딛고 일어서는

사람이 있는가 하면
영영 헤어나오지 못하는 사람들도 있다.
어떻게 성공하는가도 중요하지만

어떻게 실패를 극복하느냐가 더 중요하다.
실패를 벗어날 수 있는 가장 좋은 방법은

늘 긍정적으로 생각하는 것이다.
실패해도 '곧 다음 기회가 오겠지'라는 생각으로
매 순간을 밝고 소중하게 꾸려 나가야 한다.
삶의 희망을 주는노래와 책, 그리고
밝은 성격의 사람들과 어울리며 활기찬 날들을 만들어 보자. 

'재테크' 카테고리의 다른 글

[일반] 월급관리 유의사항 10  (0) 2010.01.14
[펀드] 펀드의 기초 상식  (0) 2010.01.14
<저축실패습관 10>  (0) 2009.12.19
Posted by 시그v

[ OpenGL 기본 설정 ]

 ----------------------------------------------------------------------
>> GL-1156-shimchan2.zip ... 18kb
GL.H
GLU.H
GLAUX.H

① 위 화일들을 각 디렉토리에 복사한다.
    →c:\Program Files\Microsoft Visual Studio\vc98\Include\
    →c:\Program Files\Microsoft Visual Studio\vc98\Include\GL\

Visual Studio 6.0 설치시 기본으로 들어있는 파일이지만
없는 경우도 있답니다.(standard version 설치시.ㅋ)

-----------------------------------------------------------------------
>> test1-1414-shimchan2.zip ... 146kb

GLUT.H
GLUT.lib
GLUT32.lib
GLUT.dll
GLUT32.dll
test1.cpp

① 위 화일들을 지정 디렉토리에 복사한다.
▶ GLUT.H →c:\Program Files\Microsoft Visual Studio\vc98\Include\
                →c:\Program Files\Microsoft Visual Studio\vc98\Include\GL\

▶ GLUT.lib GLUT32.lib →c:\Program Files\Microsoft Visual Studio\vc98\Lib
  
▶ GLUT.dll GLUT32.dll →glu.dll(glu32.dll) 화일이 있는 디렉토리에 복사
                         (예로 win98은 c:\windows\system 에 복사)
                         (windows 2000은 c:\winnt\system32에 복사)
                         (windows xp는 c:\windows\system32에 복사)

② VC++ 실행한후
▶ project -> settings -> link 탭 -> Object/library modules: 메뉴에 다음을 첨가.
opengl32.lib glu32.lib glut32.lib

③ console모드로 프로젝트를 만들고 프로젝트에 test1.cpp 추가하여 컴파일한다.

참고) GLUT 3.7버전은 따로 2번의 과정을 할 필요 없이 GLUT.H만 include하면 알아서 링크해줍니다.
      (포함되어 있는 glut의 버전은 3.7입니다.)

 

Posted by 시그v

블로그 이미지
Computer graphics & Programming
시그v

공지사항

Yesterday
Today
Total

달력

 « |  » 2025.5
1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31

최근에 올라온 글

최근에 받은 트랙백

최근에 달린 댓글

믹시