IDL/Mapping

ESRI Shapefile의 활용 및 해독에 관하여 (Part 3)

이상우_IDL 2018. 4. 1. 21:15
728x90

(지난 회 내용에서 바로 이어집니다)


앞서 지난 회에서는 예제 Shape 파일 내부에 담긴 각종 정보들을 IDLffShape 클래스의 객체를 이용하여 추출하여 활용해보기 시작했습니다. 특히 남한 영역의 윤곽선에 해당되는 좌표 데이터를 추출하여 경위도 좌표값 배열로 재구성하고 지도상에 표출하는 과정까지 살펴보았습니다. 그런데 남한 영역을 구성하는 부분영역들에 대한 구분이 제대로 되지 않은 상태이기 때문에, 표출된 윤곽선의 모습에 있어서 문제가 있음을 확인하였습니다. 오늘은 부분영역(Parts)을 구분하는 과정을 먼저 보기로 하겠습니다. 내용은 지난 회에서 이어지기때문에 예제코드의 내용도 바로 이어집니다.


먼저 부분영역의 갯수를 확인하기 위해서는 다음과 같이 entity 내의 N_Parts라는 속성의 값을 확인하면 됩니다.


ent = obj->GetEntity(j)

PRINT, ent.N_Parts


실제로 출력된 값은 7입니다. 즉 7개의 부분영역들이 존재한다는 의미입니다. 앞선 게시물에서 전체 윤곽선의 좌표값들이 총 502개가 있는 것을 확인하였는데, 이 502개가 세부적으로 7개의 부분들로 나눠진다는 의미입니다. 그러면 502개의 좌표값들이 어떻게 7개로 나눠지는가에 대한 정보가 필요합니다. 이러한 정보는 Vertices의 경우처럼 포인터(Pointer)의 형태로 존재하기 때문에 다음과 같은 문법을 사용하여 추출하면 됩니다.


parts = *(ent.Parts)

HELP, parts

PRINT, parts


여기서는 추출된 정보를 parts라는 배열에 담고, HELP와 PRINT를 사용하여 그 정보 및 원소값들을 출력하였습니다. 출력된 내용은 다음과 같습니다.


PARTS           LONG      = Array[7]

       0         361         401         426         447         473         491


출력된 7개의 정수값들은 502개의 점들이 각 부분(Part)이 나눠지는 위치 인덱스에 해당됩니다. 따라서 각 부분영역별 인덱스 범위는 다음과 같다는 얘기가 됩니다.


0~360

361~400

401~425

426~446

447~472

473~490

491~501


따라서 윤곽선을 그림으로 표출할 때에 이 정보를 토대로 각 부분별로 따로 작업을 해주면, 이전의 경우처럼 마디의 경계 부분에서 급격하게 건너뛰며 이어지는 문제를 피할 수 있게 됩니다. 이러한 방식으로 표출 작업을 다시 진행해봅시다. 먼저 지도의 바탕을 먼저 표출하는 과정은 지난번과 같습니다.


win = WINDOW(DIMENSIONS=[800, 500], /NO_TOOLBAR)

m = MAP('Geographic', LIMIT=limit, FILL_COLOR='light blue', $

  MARGIN=0.1, CLIP=0, /CURRENT)

mc = MAPCONTINENTS(file, FILL_COLOR='gold')

m.MapGrid.LABEL_POSITION = 0

m.MapGrid.LINESTYLE = 1

lons = REFORM(vts[0, *])

lats = REFORM(vts[1, *])


이제 POLYLINE 함수를 이용하여 윤곽선을 표출하는 과정이 필요한데, 각 부분(Part)별로 나눠서 순차적으로 작업을 해야 하므로 다음과 같이 반복형 구문으로 구현하였습니다. 다만 작업의 편의성을 위하여 앞서 얻었던 parts 배열에 포인트 갯수값을 추가로 넣었다는 점유의하시기 바랍니다.


parts = [parts, ent.N_Vertices]

FOR j = 0, N_ELEMENTS(parts)-2 DO BEGIN

  PRINT, parts[j], parts[j+1]-1

  lons_parts = lons[parts[j]:parts[j+1]-1]

  lats_parts = lats[parts[j]:parts[j+1]-1]

  plg = POLYLINE(lons_parts, lats_parts, COLOR='red', THICK=3, /DATA)

ENDFOR


이 반복문에서는 각 부분별 인덱스 범위에 맞는 경위도 좌표들을 각각 lons_parts, lats_parts로 구성하여 활용하였습니다. 이와 같이 각 부분영역별로 윤곽선을 따로 표출하는 방식으로 작업을 하면, 다음 그림과 같은 결과를 얻게 됩니다.



이제는 각 부분영역이 서로 혼란스럽게 엉키지 않고 정상적으로 표시되는 것을 확인할 수 있습니다. 이 반복문에서는 매 회차마다 각 부분영역별 인덱스 범위를 출력하도록 하였습니다. 실제로 출력된 값들은 다음과 같습니다. 앞서 위에 적어놓았던 값들과 동일합니다.


           0         360

         361         400

         401         425

         426         446

         447         472

         473         490

         491         501


위의 반복문은 각 회차마다 해당 부분영역 윤곽선을 그리는 작업을 수행합니다. 만약 반복인자인 j의 값을 특정하게 되면, 그 인덱스에 해당되는 부분영역의 윤곽선만 그리고 나머지 부분영역들은 그냥 넘기도록 할 수도 있습니다. 위의 내용에서 반복문만 다음과 같이 수정해봅시다.


FOR j = 0, N_ELEMENTS(parts)-2 DO BEGIN

  IF j NE 0 THEN CONTINUE

  PRINT, parts[j], parts[j+1]-1

  lons_parts = lons[parts[j]:parts[j+1]-1]

  lats_parts = lats[parts[j]:parts[j+1]-1]

  plg = POLYLINE(lons_parts, lats_parts, COLOR='red', THICK=3, /DATA)

ENDFOR


여기서는 각 회차마다 먼저 IF문에서 j가 특정 인덱스 값이 아니면 그냥 다음 회차로 바로 넘어가도록 하였습니다. 즉 j가 특정한 인덱스 값일 경우에만 실행되는 효과를 얻을 수 있습니다. 위의 경우라면 j가 0일 경우에만 윤곽선이 그려집니다. 그 모습은 다음 그림과 같습니다. 가장 큰 부분영역에 해당되는 윤곽선만 그려진 것이 보입니다.



만약 IF문에서 0이란 값을 1로 대체할 경우에는 그 다음 부분영역의 윤곽선만 그려지게 됩니다. 그 모습은 다음 그림과 같은데, 제주도에 해당되는 영역임을 알 수 있습니다.



만약 IF문에서 1이란 값을 2로 대체할 경우에는 그 다음 부분영역의 윤곽선만 그려지게 됩니다. 그 모습은 다음 그림과 같은데, 거제도에 해당되는 영역임을 알 수 있습니다.



그래픽 표출에 있어서 POLYLINE 대신 POLYGON을 사용할 수도 있습니다. POLYLINE 함수가 점들을 선으로 이어주는 역할을 하는 반면, POLYGON 함수는 점들로 구성된 다각형(Polygon)을 그리는 역할을 합니다. 반복문의 내용을 다음과 같이 바꿔봅시다.


FOR j = 0, N_ELEMENTS(parts)-2 DO BEGIN

  PRINT, parts[j], parts[j+1]-1

  lons_parts = lons[parts[j]:parts[j+1]-1]

  lats_parts = lats[parts[j]:parts[j+1]-1]

  plg = POLYGON(lons_parts, lats_parts, FILL_COLOR='green', /DATA)

ENDFOR


여기서는 반복문 내에서 POLYLINE 대신 POLYGON을 사용하였습니다. 그리고 각 다각형마다 그 내부를 초록색으로 채우도록 하였습니다. 그 결과는 다음 그림과 같습니다.



이와 같이 여러 개의 부분영역들로 구성된 경우에는 부분(Parts)에 대한 정보까지 추가적으로 추출하여 활용을 해야, 각 부분영역별로 윤곽선을 제대로 표출할 수 있게 됩니다. 상당수의 국가들이 아마 이런 경우에 해당될 것입니다. 일본과 중국의 경우 부분영역의 갯수가 각각 29, 22개가 나옵니다. 일본과 중국에 대해서 경위도 범위를 조금 확대하여 그려본 모습은 다음 두 그림과 같습니다.



이 그림들을 그리는데 있어서는, 일본과 중국의 인덱스가 각각 185와 184이고, 지도의 경위도 범위인 limit의 값들을 다음과 같이 설정하였음을 참조하시면 됩니다.


limit = [30, 120, 60, 150]; Japan

limit = [10, 70, 60, 150]; China


지금까지 3회에 걸쳐 ESRI Shape 파일의 정보를 추출하여 활용하는 방법 전반을 관련 예제와 함께 살펴보았습니다. 물론 여기서 더 이어질만한 추가적인 내용들이 아마도 또 있을 것 같습니다. 다른 종류의 Shape 파일을 사용하는 예제를 생각해 볼 수도 있고, 마스킹(Masking) 기법에 응용하는 예제 역시 다뤄볼만한 주제가 될 수 있으리라 생각을 합니다. 정확히 언제가 될지는 모르지만 이러한 내용도 준비가 된다면 그 때 올려보도록 하겠습니다.

LIST