IDL/New Graphics

3차원 공간상에서 지도와 타 그래픽 요소의 중첩 표출 [1]

이상우_idl 2023. 3. 8. 14:40
728x90
반응형

오늘은 글 제목을 3차원 공간상에서 지도와 타 그래픽 요소의 중첩 표출이라고 적었는데, 구체적으로 얘기해보면 XYZ 축으로 구성되는 3차원 그래픽 공간에서 지도를 바닥에 깔고 그 위에 다른 평면적인 그래픽 요소들(이미지, 벡터 등)을 중첩하여 표출하는 방법에 관한 것입니다. 약간 비슷한 느낌의 표출 예제를 제가 예전에 관련 게시물을 통하여 한번 소개했던 적이 있으므로 이 게시물에 수록된 그림들을 한번 참조해보시면 좋을 것 같습니다. 일단 오늘은 첫 순서로서 3차원 그래픽 공간에서 지도를 바닥에 깔고 그 위에 벡터장을 중첩 표출하는 예제를 소개해보고자 합니다.

 

그러면 본격적인 시작을 위하여 먼저 예제 데이터부터 생성해보겠습니다. 여기서는 한반도 및 주변 영역에 대한 2차원적인 벡터장이 여러 고도층에 걸쳐서 분포하는 상황을 가정해보았습니다. 이러한 가상 데이터를 정의하고 생성하는 과정은 다음과 같습니다.

 

x = [100:150:5.0]
y = [10:60:5.0]
z = [100:1000:100.0]
nx = N_ELEMENTS(x)
ny = N_ELEMENTS(y)
nz = N_ELEMENTS(z)
u = RANDOMU(seed, nx, ny, nz)*60-30
v = RANDOMU(seed, nx, ny, nz)*60-30
HELP, u, v, x, y, z
PRINT, MIN(u), MAX(u)
PRINT, MIN(v), MAX(v)

 

약간 복잡해 보일 수도 있지만 여기서 정의된 주요 항목들에 대한 설명을 붙이면 다음과 같습니다.

 

x : 경도 방향의 격자점 위치 좌표값들로 구성된 1차원 배열이며 값의 범위는 100~150 (5도 간격)

y : 위도 방향의 격자점 위치 좌표값들로 구성된 1차원 배열이며 값의 범위는 10~60 (5도 간격)

z : 고도 방향의 층별 고도값들로 구성된 1차원 배열이며 값의 범위는 100~1000 (100m 간격)

u : 벡터의 U 성분값들로 구성된 11x11x10 구조의 3차원 배열이며 값의 범위는 대략 -30~+30

v : 벡터의 V 성분값들로 구성된 11x11x10 구조의 3차원 배열이며 값의 범위는 대략 -30~+30

 

일단 이렇게 가상의 데이터 배열들을 생성해둔 다음에는 XYZ 축으로 구성된 3차원 공간을 생성하고 맨 밑바닥에 있는 XY 평면 상에 바탕 지도를 깔려고 합니다. 이를 위해서는 먼저 3차원 공간을 생성해야 하는데, 여기서는 PLOT3D 함수를 사용해보겠습니다. 그 과정은 다음과 같습니다.

 

xx = INDGEN(10)
yy = INDGEN(10)
zz = INDGEN(10)
win = WINDOW(DIMENSIONS=[600, 600], /NO_TOOLBAR)
p = PLOT3D(xx, yy, zz, /NODATA, $
  XRANGE=[100, 150], YRANGE=[10, 60], ZRANGE=[0, 1000], $
  XMINOR=0, YMINOR=0, XTICKLEN=0, YTICKLEN=0, $
  XSHOWTEXT=0, YSHOWTEXT=0, /CURRENT)

 

여기서 xx, yy, zz는 그냥 PLOT3D 함수를 사용하기 위한 최소한의 요건 때문에 임시로 생성한 데이터일 뿐이기 때문에, PLOT3D 함수에서는 /NODATA 키워드를 사용함으로써 실제로는 보이지 않도록 처리하였습니다. 그리고 어차피 나중에 바탕 지도를 XY 평면에 표시할 것이기 때문에 X, Y 축에 대해서는 눈금 및 문자들이 보이지 않도록 처리하였습니다. 여기까지 진행된 결과는 다음 그림과 같습니다.

 

 

이제 이렇게 생성된 3차원 공간의 XY 평면상에 바탕 지도를 깔아서 표출해봅시다. 이를 위한 과정은 다음과 같습니다.

 

mg = MAPGRID(LONGITUDE_MIN=100, LONGITUDE_MAX=150, $
  LATITUDE_MIN=10, LATITUDE_MAX=60, COLOR='black', $
  LABEL_POSITION=0, LINESTYLE=1)
m = MAP('Geographic', LIMIT=[10, 100, 60, 150], /OVERPLOT)
mc = MAPCONTINENTS(FILL_COLOR='gold', /HIRES)

 

그런데 이 내용을 잘 보면 NG 체계에서 통상적으로 지도 표출을 할 때의 방식과 약간 다릅니다. 즉 통상적으로는 MAP 함수를 먼저 사용하고 그 뒤에 MAPCONTINENTS 함수에 의한 대륙경계선 표시 및 기타 격자선 관련 설정들이 이어지는 경우가 많는데요. 여기서는 MAPGRID 함수를 먼저 사용하고 그 뒤에 MAP, MAPCONTINENTS 함수들이 뒤따르는 방식으로 처리하였습니다. 왜냐하면 제가 테스트해본 바에 의하면 MAP 함수를 먼저 사용할 경우에는 무슨 이유인지 몰라도 기존의 XYZ 축이 다 사라지는 문제가 있어서, 나름대로 해결책을 찾아본 것이 이 방법이기 때문입니다. 어쨌든 이렇게 처리를 하면 결과는 다음 그림과 같습니다.

 

 

이와 같이 XYZ 공간의 XY 평면 상에 바탕 지도를 표출하는 것까지는 구현을 했습니다. 이제 그 다음에는 벡터장을 그 위에 중첩하여 표출해보려고 합니다. 이를 위해서는 VECTOR 함수를 사용하여 층(Layer) 하나씩 표출하는 방식으로 가야합니다. 즉 앞서 예제 데이터를 생성할 때 u, v를 3차원 배열로 생성을 하긴 했지만 이 상태 그대로는 VECTOR 함수에 바로 투입할 수 없습니다. 왜냐하면 VECTOR 함수 자체는 2차원적인 표출만 가능하며 2차원적인 데이터만 받을 수 있다는 특성 때문입니다. 그래서 하나의 층(Layer)을 선택하여 그 층에 대한 2차원적인 데이터를 추출하고 이 데이터를 VECTOR 함수에 투입하여 표출하는 방식으로 가야합니다. 지금 우리가 사용중인 예제 데이터의 경우는 총 10개의 층들이 있으므로 그 중 하나의 층을 선택하여 처리해봅시다. 그 과정은 다음과 같습니다.

 

indz = 7

u_ext = u[*, *, indz]
v_ext = v[*, *, indz]
vec = VECTOR(u_ext, v_ext, x, y, ARROW_THICK=3, $
  HEAD_SIZE=1.2, /HEAD_PROPORTIONAL, LENGTH_SCALE=1.5, $
  COLOR='green', CLIP=0, /OVERPLOT, ZVALUE=z[indz])

 

여기서는 8번째 층을 선택하기 위하여 Z 방향의 인덱스인 indz를 7로 설정하고 u, v로부터 u_ext, v_ext를 추출한 다음, 이들을 VECTOR 함수에 투입하였습니다. 즉 u의 경우 원래는 11x11x10의 3차원 배열이었지만 u_ext는 8번째 층에 대하여 추출된 11x11의 2차원 배열이 되고 v의 경우도 동일한 방식으로 추출하여 v_ext를 얻은 것입니다. 그리고 VECTOR 함수에서는 /OVERPLOT 키워드를 사용해야할 뿐 아니라 ZVALUE 키워드에 대하여 고도값을 투입해야 한다는 것을 유의해야 합니다. 그래야 XYZ 공간 내에서 Z축의 값이 그 고도와 맞는 위치에 벡터장이 2차원적인 평면의 형태로 표출됩니다. 실제 표출 결과는 다음 그림과 같습니다.

 

 

일단 이와 같은 방식을 사용하면 특정한 하나의 층에 대한 벡터장을 골라서 표출하는 것은 가능합니다. 그런데 만약 하나의 층으로 국한하지않고 모든 층들의 벡터장을 한꺼번에 표출하고 싶다면 위와 같은 작업을 반복형으로 처리해야 합니다. 즉 바로 이전에 indz의 값을 하나로 설정하여 처리했던 과정을 다음과 같이 반복형 구문으로 감싸는 방식으로 변경하면 됩니다.

 

FOR indz = 0, nz-1 DO BEGIN
  u_ext = u[*, *, indz]
  v_ext = v[*, *, indz]
  HELP, u_ext, v_ext
  vec = VECTOR(u_ext, v_ext, x, y, ARROW_THICK=3, $
    HEAD_SIZE=1.2, /HEAD_PROPORTIONAL, LENGTH_SCALE=1.5, $
    COLOR='green', CLIP=0, /OVERPLOT, ZVALUE=z[indz])
ENDFOR

 

표출 결과는 다음과 같습니다.

 

 

다만 이 그림을 보면 모든 층의 벡터장들이 한꺼번에 표시되다보니 가독성은 그리 좋지는 않은 것 같습니다. 따라서 그냥 한번에 하나의 층만 표출하는 것이 가독성 측면에서는 더 나을 것 같다는 생각이 듭니다. 그리고 이 상태에서 XYZ 공간의 시선 방향을 다음과 같이 처리하면 마치 바로 위에서 내려다본 것과 같은 모습으로 표출할 수도 있습니다.

 

p.Rotate, /RESET

 

 

이렇게 하면 모든 층들에 대한 벡터들의 모습이 겹쳐보이긴 하는데 어쨌든 이러한 표출도 가능하다는 점을 참조하시면 좋을 것 같습니다. XYZ 축으로 구성되는 3차원적인 그래픽 개체의 시선 방향을 조정하는 방법에 관해서는 관련 게시물의 내용을 참조하시면 됩니다.

 

다음 회차에서는 3차원 좌표계 내에서 지도를 바닥에 깔고 그 위에 이미지(Image), 등위선(Contour) 등과 같은 2차원적인 그림을 중첩 표출하는 예제를 소개해보도록 하겠습니다.

반응형