http://astronote.org 지돌스타 별자리 프로그램을 만들고 싶어하시는 분들을 위해 이번에 제가 야근을 하면서 이 글을 썼습니다. ㅋㅋ 무엇보다 별자리 프로그램을 만드는데 가장 기본적인 것은 3차원정보를 어떻게 컴퓨터 화면(2차원)에 표시할 수 있을까입니다. 이러한 기술에 대한 구현은 프로그램 세계에서 이미 DirectX나 OpenGL 이라는 특수 그래픽 라이브러리를 통해 제공되고 있습니다. 사실 이것들을 이용하면 쉽게 3차원 정보를 2차원으로 표현할 수 있습니다. 하지만 별자리 프로그램을 하고자 하는 사람이 이런 기본적인 방법 및 기술에 대한 지식이 없다면 진정으로 안다고 할 수 없겠지요. 이 글은 별자리 프로그램을 시도하는데 가장 기초적인 내용을 담고 있습니다. 여기에 있는 내용만 잘 습득하신다면 공간의 2차원 표현에 대한 기본적인 기술을 익히게 되는 것입니다.
미리보기 : http://blog.jidolstar.com/web_example/173/ ![]() [실행화면] 자바스크립트를 이용한 3D 표현 미리 알아두어야 할 사항 여러분은 여기 내용을 습득하시기 위해 아래와 같은 기본 지식이 필요합니다. 고등학교를 다니거나 졸업하신 분이라면 한번 씩 꼭 접해봤던 것 일겁니다. 즉, 여기서 쓰는 내용은 고등학생 수준에서 이해할 수 있도록 쓴 것임을 일러둡니다. 1. 벡터와 행렬 벡터와 행렬에 대해 기본적으로 아셔야 합니다. 고등학교 때 공부하는 것이 괜히 공부하는게 아니겠죠? 천문프로그램을 하실려면 고등학교 시절 과목에 대해 기피해서는 안됩니다. 가장 기본이 되니깐요. 여기서는 정방행렬×정방행렬, 정방행렬×백터, 회전행렬에 대한 기본적인 이해가 필요합니다. 벡터와 행렬을 왜 배우는가? 지금까지 잘 모르셨다면 여기서 확실히 알아가시길 바랍니다. 2. 삼각함수 사인, 코사인, 탄젠트 에 대한 기본적인 지식이 있어야 합니다. 고등학교때(요즘은 중학교때부터 하지 않나요?) 2차원 2×2 행렬의 회전행렬을 공부하셨을 겁니다. 그때는 직접 계산해서 증명도 했지만 시험을 위해 외우기까지 했었던 기억이 나네요. 삼각함수는 회전행렬을 구하기 위해 반드시 필요합니다. 3. 다룰 수 있는 프로그램 프로그램을 할 건데 기본적인 프로그램 지식은 있어야 겠지요. C언어나 Basic등 어느 언어라도 익숙하신 분이라면 정말 다행이지만, 프로그래밍에 대해 잘 모르시는 분이라면 일단 이론쪽만 보시고 프로그램쪽 설명은 나중에 보세요. 여기서는 Javascript를 이용할 겁니다. Java가 아니라 Javascript입니다. Javascript를 이용하면 특별한 프로그램 툴이 필요 없이 메모장과 인터넷 브라우져만 있으면 됩니다. 게다가 간단하게 브라우저 위에 그림도 그릴 수 있으므로 더욱 좋습니다. MFC, API등과 같은 다른 GUI프로그래밍이 가능한 프로그램을 다룰 수 있으시다면 제가 만들어 놓은 것을 바탕으로 응용하실 수 있을 겁니다. 3차원 좌표계를 알아보자. 우리가 사용할 3차원 좌표계를 봅시다. 직교좌표계 위의 그림을 보고 바로 이해했다면 다음으로 넘어가길 바랍니다. 모르신다면 다음을 읽어보시죠. 위의 그림은 축이 3개가 있는 3차원 직교좌표계를 표현한 그림입니다. 그 좌표계 위에 있는 한 점의 좌표값이 (Ax, Ay, Az) 일때 원점에서부터 그 점까지 벡터로 표시한 겁니다. 벡터는 아시다시피 방향과 크기를 가지고 있는 수학적 표현 방법입니다. 벡터를 가지고 위치를 표현하기 위해서는 출발점의 좌표가 있어야 하는데 위의 직각좌표계의 원점인 (0,0,0)이 됩니다. 또 각 축방향을 가지고 크기가 1인 벡터를 단위벡터라고 하며 여기서는 i, j, k 로 표기했습니다. 그러므로 최종적으로 좌표값 (Ax, Ay, Az)를 가리키는 벡터값은 A = Axi+Ayj+Azk 이 됩니다. 주의해서 보실 것은 벡터는 방향과 크기를 동시에 가지므로 표기법도 다릅니다. 여기서는 굵은 글자로 표기했는데, 수기로 표시하려면 위에 →를 표시해야겠죠?이 벡터를 행렬로 표기할 때는 우리는 A = [AxAy Az]T 식으로 표현할 겁니다. 너무 쉽다고요? ㅋㅋㅋ 죄송합니다. 그럼 다음을 보시죠. 구면좌표계 위의 그림은 직교좌표계 값을 구면좌표계 형태로 표현한겁니다. 별자리 프로그래밍을 하다보면 적경, 적위, 방위각, 고도, 은경, 은위, 황경, 황위 등의 용어를 듣게 되는데 이러한 말들이 다 구면좌표계값이 됩니다. 별은 지구에서 보는 것이므로 모두 거리가 1이라고 가정하면 직교좌표계 값보다는 구면좌표계 값으로 표현하는 것이 좋기 때문이지요. 하지만 각종 좌표변환을 하려면 구면좌표계보다는 직교좌표계가 훨씬 편합니다. 그래서 천문 프로그램을 하면 구면좌표계와 직교좌표계의 변환이 많이 필요하답니다. 아래 직교좌표계와 구면좌표계의 관계식을 보시죠. [식1] 직교좌표계 → 구면좌표계 변환 longitude를 계산할 때 주의사항으로는 tan-1() 함수는 기본적으로 공역이 -π/2 ~ π/2 이므로 1사분면과 4사분면밖에 값을 얻을 수 없습니다. 이때는 Ax값이 음수인 경우 tan-1() 의 결과값에 π를 더해주면 전 사분면의 값을 얻을 수 있습니다. javascript나 c에서는 atan()함수대신 atan2() 함수를 사용하면 이와 같은 결과를 얻을 수 있습니다. [식 2] 구면좌표계 → 직교좌표계 변환 3차원 좌표의 2차원 좌표 표현 먼저 생각할 것이 있습니다. 도대체 어떻게 3차원을 2차원으로 본다는 것일까요? 그 아이디어는 의외로 간단합니다. 2개의 좌표만 추출해서 화면에 뿌려주면 되는겁니다. 그럼 뭐할려고 이런 글을 쓰는거져? 라고 물으신다면... 전 그냥 자겠습니다, ㅋ 농담이고요. 어떠한 물체는 어떻게 보느냐에 따라 그 형태가 다르게 보이죠. 물체를 돌려봐도 되구요. 제가 물체 주위를 돌아봐도 됩니다. 어쨌든 물체의 형태는 상대적인 움직임에 따라 다른 형태로 보이게 되어 있습니다. 그럼 여기서는 어떻게 해본다는 걸까요?먼저 아래 그림을 보시죠. [3차원 좌표를 2차원으로 보는 방법]
그림 실력이 없어서 죄송합니다. ㅋ 위 그림에서 보는 부분을 보세요. 두 그림 다 Y축에서 원점 방향으로 물체를 보고 있습니다. 또 좌표축의 위치는 바뀌었지만 원점은 그대로입니다. 이때 X축과 Z축은 화면의 좌표축으로 놓고 Y축은 무시해버리면 되는 겁니다. 즉 위 직육면체의 각 꼭지점 좌표 (Ax, Ay, Az)중 Ay는 무시하고 Ax와 Az만 화면에 출력하면 되는 것이지요. 이것이 3차원을 2차원으로 표현하는 가장 기본이 되는 겁니다. 한가지 더 생각할 것은 물체는 항상 정위치라는 겁니다. 위 그림에서 첫 번째 그림 좌표계에서 정육면체의 꼭지점의 좌표는 변하지 않았습니다. 즉 원점은 그대로이고 좌표축만 회전된 겁니다. 이때 벡터 A와 벡터 A'는 같은 벡터입니다. 즉 위의 벡터는 다음과 같은 관계에 있습니다. [식 3] 벡터 A와 벡터 A' 의 관계 위 수식에서 벡터 A와 벡터 A' 의 각 요소들은 다르다는 것을 아셔야 합니다. 자 그럼 이해하셨나요? 좌표계를 회전해서 한 좌표값만 무시하면 되는 겁니다. 그럼 좌표계를 회전하는 방법만 알면 되는거져? 지금부터 설명하는 것이 어떻게 보면 핵심이 되는 부분이기도 합니다. 그럼 잘 따라오시길 바래요~. 참고로 말씀드린다면 실세계에서 보는 것은 이런 투영방식으로는 한계가 있습니다. 화면의 가장자리에 대한 처리가 미흡하기 때문이지요. 이에 대한 내용은 이 글 맨 아래를 참고하세요. 문제의 핵심! 3차원 좌표계의 회전 여기까지 오시느라 고생 많으셨습니다. 마지막 코스입니다. 코사인, 사인.. 정신 없을겁니다. 그러나 어려운 미분적분을 다루는게 아니므로 걱정마시고 잘 따라오시길 바랍니다. ![]() 오~ 처음에 나온 그림입니다. 친숙하군요. ㅋ 저는 이 좌표계를 회전할 겁니다. 자 다음 그림을 보시죠. ![]() 그림이 좀 복잡한가요? 잘 보시면 아까 정육면체 가져다 놓고 그린거랑 별반 다를 것 없습니다. 단지 빨간색 회전된 좌표계가 추가된 것뿐입니다. 원점을 기준으로 가리키는 한점은 항상 똑같은 위치입니다. 이 말은 벡터 A와 벡터 A'가 같다는 말입니다. 그림에 나와 있는 식은 좀 전에 봤던 식이죠? 이것 이해 못하셨으면 앞으로 다시 가서 이해하시고 오시길 바랍니다. 자 다음 식을 보시죠. [식 4] Ax'값은 회전된 좌표계의 X‘축 값입니다. 이 값은 벡터값과 회전된 좌표계 X‘축의 단위벡터와의 스칼라 곱의 값과 같습니다.(모르시겠다면... 수학책을 보세요.) 근데 벡터 A와 벡터 A'가 같다고 했으니 위의 식처럼 되는 겁니다. 이해하시죠? 그럼 다른 축값도 마찬가지겠죠? 다음 식을 보시죠. ![]() [식 5] 자 이제 위 식을 행렬형태로 전개하겠습니다. ![]() [식 6] 회전행렬을 이용한 변환식 위의 식이 바로 회전행렬의 일반식입니다. 벡터 A의 각 요소 값을 벡터 A'의 요소값으로 구하는데 위의 식을 사용하면 되는 겁니다. 잘 아시겠지만 행렬안에 단위벡터들의 스칼라곱은 모두 cos()함수입니다. 그럼 각도는 어떻게 구할까요? 임의로 돌아가는 좌표계에 대해 어떻게 각도를 구하라는 것일까요? 이에 대한 해답은 축의 회전에 있습니다. 좌표계가 임의로 돌아가도 3개의 축을 최소 3번만 돌리면 그 임의로 돌아간 좌표계와 일치 시킬 수 있습니다. 예를 들어 X축을 회전시키고 Y축을 회전한 다음 Z축을 회전하면 원점이 일치하는 어느 임의의 좌표계라도 일치 시킬 수 있다는 겁니다. 잘 이해가 안 가신다면 직접 볼펜 6자루 가지고 직접 시험을 해보세요. 그리 어렵지 않은 개념입니다. 그럼 좌표축을 회전하는 식을 유도해볼까요? 여기서 우리는 한 가지 약속하고자 합니다. 각 축이 커지는 방향으로 엄지손가락의 끝방향과 일치시키고 축을 감싸지을 때 나머지 손가락의 끝 방향이 정회전 방향으로 정의합니다. 이러한 정의는 필수적으로 정해두어야 나중에 헷갈리지 않습니다. [X축 회전] [식 7] X축 회전시 회전행렬의 각 요소값 계산 [식 8] X축 회전시 회전행렬의 각 요소값 2. Y축 회전행렬과 Z축 회전행렬 X축 회전행렬을 구하는 방식과 동일한 방법으로 구하면 됩니다. 결론적으로 다음식과 같습니다. [식 9] Y축 회전시 회전행렬의 각 요소값 [식 10] Z축 회전시 회전행렬의 각 요소값 [식 8], [식 9], [식 10] 을 이용하면 우리는 벡터값의 회전값을 구할 수 있는 것입니다. [식 9]와 [식 10]은 반드시 한번정도는 유도해 보길 바랍니다. 한가지 주의해야할 사항은 행렬의 곱은 교환법칙이 성립되지 않습니다.(결합법칙, 분배법칙은 성립) 가령 x축 회전행렬을 Mx라 하고 y축 회전행렬을 My라고 할때 Mx My와 My Mx는 같지 않습니다. 즉, 같은 각도로 x축 회전후 y축 회전한 것과 y축 회전후 x축 회전한 것은 같지 않다는 겁니다. 왜 그런지는 곱해보면 압니다. ^^ 프로그램을 짜보자 앞서 프로그램은 Javascript로 구현한다고 했습니다. Javascript로도 얼마든지 천문프로그램을 할 수 있으며 그래픽 처리도 가능합니다. 특별한 툴 없이 이런 프로그래밍을 하는 시대가 와서 얼마나 기쁜지... ㅡㅜ;; 전 컴퓨터 하나 가지고 싶어서 마음 고생할 때가 엊그제 같은데 말이죠. ㅎㅎ 여기서는 Javascript를 처음 해보시는 분들을 위해 간단히 학습할 수 있도록 도움을 주고 난 뒤 본격적인 응용에 들어가겠습니다. 1. 수학함수 정의를 해보자 Javascript에서는 기본적으로 삼각함수를 제공하고 있습니다. Math라는 객체를 이용하면 되는데요... 뭐.. 객체 어쩌구 저쩌구 하면 알기 힘드니 직접 그 방법을 가르쳐 드리지요. 메모장을 펴고 다음과 같은 코딩을 하고 html 확장자로 저장하신다음 실행해보세요. 오오~~ 신기신기.... Math 옆에 .PI를 하고 변수 a에 저장하면 a에는 3.14159값이 들어갑니다. 그 값을 alert()함수를 통해 위의 그림과 같은 경고창에 띄워주는거져. ㅎㅎ 그럼 다른 함수들을 사용해봅시다. ![]() 오오오~~ 삼각함수도 됩니다. 신기하군요. 그런데 sin(π)가 0이 아니고 1.224606e-16 이라고 나오는군요. 왜 그럴까요? 그건 컴퓨터는 sin함수를 Tayor 급수형태로 전개한 결과를 출력했기 때문입니다. 당연히 sin(π)는 0이지만 sin()함수의 Taylor 급수형태는 무한급수이므로 무한적으로 컴퓨터는 무한적으로 계산할 수 없습니다. 뒤에 e-16는 ×10-16을 뜻하므로 0하고 가깝다고 생각할 수 있겠죠? 한가지 더! tan-1() 함수가 2개가 있습니다. Math.atan()와 Math.atan2()가 있는데요. Math.atan()는 결과는 -π/2 ~ π/2입니다. 그러므로 1사분면과 4사분면까지 밖에 계산할 수 없습니다. 모든 사분면을 알고 싶다면 -π ~ π 까지 계산되는 Math.atan2()를 사용해야 할겁니다. 2. 벡터를 만들어 보자 Javascript로 벡터를 어떻게 만들까요? 일단 다음 프로그램을 보시죠. function은 함수를 뜻합니다. Vector는 그 함수의 이름이고요. 3개의 인자를 받습니다. 즉, x, y, z값입니다. 이 값은 this.x, this.y, this.z를 통해 이 함수의 맴버 변수가 됩니다. 이렇게 하면 외부에서 이 변수들을 접근할 수 있습니다. 예를들어 var v1 = new Vector(1,2,3)으로 벡터를 생성하고 나서 그 값은 v1.x, v1.y, v1.z 와 같은 형식으로 접근이 가능합니다. this는 바로 이런 역할을 해주는 겁니다. 이 벡터에는 여러 가지 기능을 제공할 수 있습니다. 즉, 벡터의 크기나 구면좌표값등을 얻거나 설정할 수 있겠지요. 다음 프로그램을 보시죠. ![]() 아까 프로그램과 다르게 function GetLength()라는 함수가 Vector()함수 내에 정의되었습니다. 또 this.GetLength = GetLength를 통해 이 함수를 외부에서 접근할 수 있도록 했습니다. 즉, 이 함수는 벡터의 크기를 반환합니다. 여기서 Math.sqrt()함수는 제곱근을 구해주는 함수입니다. 어떻게 사용할까요? var length = v1.GetLength(); 이런 식으로 하면 length에 v1 벡터의 크기가 입력되겠죠? 행렬도 Vector와 동일하게 만들어집니다. 단지 요소가 3개가 아닌 9개 되겠죠? 3. Javascript로 그림을 그려보자 Javascript로 그림을 그리는건 쉽지 않은 일입니다. 일일이 계산해야하고 참 어려운 일이죠. 하지만 세상에는 정말 똑똑한 사람들이 많지요. 그들중에는 Javascript로 그림을 그릴 수 있게 프로그램 소스를 제공하는 착한 분들이 있습니다. ㅎ 일단 http://www.walterzorn.com/jsgraphics/jsgraphics_e.htm 로 놀러가 보세요. 영문 페이지로 되어 있지만 Javascript로도 아주 쉽게 그림을 그릴 수 있도록 소스를 만들어 놯고 사용법도 무지 간단하답니다. 간단한 예를 보여드리지요. 먼저 그곳에서 제공하는 wz_jsgraphics.js라는 프로그램 소스를 다운로드 받고 아래와 같이 코딩합니다. ![]() 결과는 다음과 같습니다. DIV Tag에 ID를 입력하고 그 ID를 최초 생성시 인자로 넘겨주면 해당 DIV에 그림을 그립니다. 사용방법이 너무 간단하므로 더 이상의 설명은 필요 없을 것 같네요. 4. 응용 프로그램을 만들자 위에서 Javascript를 가지고 함수도 사용해보고 함수도 만들어 봤습니다. 또한 그림까지 그려봤죠? 프로그래밍 초보자에게는 어려운 내용일 수 있습니다만 조금만 공부하시면 아주 어려운 내용만은 아닙니다. 소스 코드를 공개하겠습니다. 다운 받아가세요~~ 별도의 설치가 필요없답니다. 로컬에서 하면 ActiveX 설치하라고 나오는데, 그건 IE만 그런겁니다. Javascript에 나쁜 코드가 들어가 있을까봐서 IE에서 막아놓은 건데요. 무시하시고 실행하시면 되욤~ 제공한 프로그램은 좌표 회전후 새로운 좌표계의 X축과 Y축에 해당되는 값을 가지고 출력한 겁니다. 프로그램 내용을 보면 알 수 있을 겁니다. 참고로 한가지 말씀드린다면 여기서 설명드린 것은 단순히 회전에 관해서만 입니다. 이동, 투영, 확대에 대해 조금더 공부하실려면 다음 사이트를 참고하세요 http://en.wikipedia.org/wiki/Perspective_transform http://en.wikipedia.org/wiki/3D_projection http://en.wikipedia.org/wiki/Translation_%28geometry%29 http://en.wikipedia.org/wiki/perspectiv ··· stortion
나름대로 열심히 썼지만 아무래도 부족한 점이 있어보이네요. 별자리 프로그램과 같은 천문 프로그램을 만들어 보고 싶다는 생각을 가지신 분을 위해 도움을 드린겁니다. 내용이 어렵다고 생각되시면 선형대수학을 공부하시면 큰 도움이 될겁니다. 천문 프로그램은 만들고 싶은데 여기 내용을 전혀 모르시겠다면 고등학교 수학을 먼저 공부하세요. 그리고 프로그램에 대한 전반적인 지식을 습득하시는 것이 좋습니다. C언어가 가장 무난한 프로그램 언어 같네요. 아무쪼록 나만의 천문프로그램을 만드는데 큰 도움이 되었으면 하네요. 앞으로도 이러한 내용을 가끔씩 쓸 예정입니다. 기대 하셔도 좋을 듯... ^^ 추가내용어떤 분이 내 글을 보고 Delphi를 이용해 OCX를 만들었다. ![]() 글쓴이/저작권 : 지돌스타 (http://blog.jidolstar.com/173 , http://astronote.org ) Trackback Address :: http://blog.jidolstar.com/trackback/173
|
||||||||



























3차원을 2차원으로 표현.zip