구글 차트 API에서는 지도 API를 마련해 세계지도와 미국 주단위 지도를 차트로 쓸 수 있게 하고 있다. 한반도의 도와 시군구 단위의 차트를 만들려면
웹으로 한반도 지도 차트를 제공하기 위해서 필요한 절차는
행정구역 정보 확보이때 행정구역을 구하기 위해 NGIS.go.kr 등을 돌아보았으나 원본 형태로 확보할만한 곳은 없었다. 구글맵에 사용자들이 참여한 정보의 원본을 받을 수 있으나, 자체 지도가 없는 저개발국을 위한 프로젝트이기 때문에 아프리카와 동남아 국가들뿐이고 대한민국은 없다.구글 어스에 행정구역 경계선이 나오므로 추출하여 이용할 수 있나 찾아보았더니 직접 추출할 수는 없다고 하면서 구글 어스 커뮤니티 링크가 있었고 거기에서 세계 행정구역 경계 목록을 찾았고 대한민국 도 단위와 시군구 단위의 .kmz 파일을 구했다. (만든지 오래되지 않았음에도 서울이 서울직할시로 표기되고 울산이 없는 것으로 보아 참조한 자료가 상당히 오래됐으리라 짐작할 수 있지만, 대신 지도 커뮤니티 자료실에서 .shp, .dbf 등이 있다는 것을 알게 되어 행정구역 파일을 확인했다. (ArcViewer 프로그램이 공식 어플인 것 같은데 설치 중에도 1935 에러가 떴고 필요한 패키지를 준비한 다음 설치를 하고 나서도 .shp를 어떻게 여는지 모르겠어서 포기) EDSViewer로 XML과 CSV로 변환을 했는데 깔끔하긴 한데 내부 구조를 잘 모르겠다. 특히 좌표 방식을 모르겠다. 법정동 행정구역이 있는데 도 구분번호는 전화 지역번호인 건 알겠지만 거기 덧붙은 시 번호는 뭔지 모르겠다. 일단 법정동코드가 같이 붙어 있으므로 구분에 무리는 없을 것이다. GIS 정보 추출KML은 일련의 Polygon을 포함한 XML이므로 적당한 도구를 통해 XML에 포함된 정보를 추출하면 될 것이다.이때 필요한 스키마는
데이터베이스는 구글 앱엔진을 가정하고, 적당한 앱엔진용 loader를 구현하면 된다. grep -n POINTS *dong.xml | sed 's/: <\//, /' | tr ':' '-' | awk '{print $1}' | xargs echo | tr ',' '\n' | bc | sort -gr근데 지금 보니 .csv에 있는 건 1동 2동이 따로 있는 걸 보니 행정동이네... 행정동도 코드가 있기는 한데... 그냥 법정동코드 있는 구 단위까지만 할까?-_- 구 단위는 법정동 코드에서 5자리까지만 쓰고 나머지는 0이라 코드도 간단해질 텐데. 좌표는 53개부터 2857개까지 있다. 이렇게 한 지역의 둘레 벡터를 구성하는 점의 좌표들이 적지 않아서 애초 생각했던 식으로 폴리곤 하나당 DB row 하나 구성은 불가능하겠다. 그렇다면 필드 구성을 법정동코드,폴리곤상점의순서,X좌표,Y좌표,폴리곤번호(섬은독립폴리곤)...시군구 통합 파일의 폴리곤을 처리해보니 82만여 줄이 나온다. 근데 시군구 .csv에 저장된 법정동코드로 짐작되는 일련번호가 중복되는 게 있다. 전체 247줄이던 게 중복 제거하면 233줄 뿐이다. 가령 청주시상당구와 청주시흥덕구가 4311000000으로 같은데 이건 그냥 청주시 번호고 실제로는 4311100000과 4311300000이 각각 구 단위 번호다. 이렇게 되면 중복되는 것뿐 아니라 고유번호 자체가 잘못 매겨졌을 수도 있다는 건데 코드 말고 그냥 이름 필드로 비교해서 저장할까? 벡터 폴리곤 그리기KML 자체를 렌더링하는 것은 없는 것 같고, 어차피 한반도라는 제한된 구간 안이므로 Polygon을 가져와 경도·위도를 좌표상의 가로·세로에 그대로 대입해 이미지를 생성할 수 있을 것으로 생각된다. 이때 GET 방식의 URL에 지정된 일련의 코드를 그대로 수용해 하나의 이미지 공간 안에 그려넣고 그대로 출력해주면 될 것이다. 가령 도와 시, 구가 섞여서 호출됐을 경우 (법정동코드를 쓴다면) 큰 단위부터 차례로 그려서 작은 단위가 덮어쓰도록 처리하면 (어차피 같은 영역을 공유하는 폴리곤이므로) 사용자의 의도가 무엇이든 간에 한 번에 출력할 수 있을 것으로 보인다. 일단 .csv 첫째 줄인 강릉시를 따로 빼다가 ImageMagick -draw 명령으로 그려보았다. POINTS의 좌표들은 단위가 상당히 큰데 그게 다 들어갈만한 크기로 하면 임시 파일 크기도 엄청나게 커지고 처리가 끝나지 않는다. 10만x10만 크기로 했을 때는 반나절 정도를 놔뒀다가 결국 포기했고, 1만x1만은 분 단위의 시간이 걸린 다음에 완료가 됐다. 1000x1000 정도가 순간적인 반응 속도를 보여줄 수 있는 수준인 것 같다. 구글 차트 API가 가로x세로 해서 출력 크기 30만 픽셀까지를 한계로 두고 있는데 에러 표시에는 메모리 사용량을 거론하지만 크기 때문도 있을 것 같다. 어차피 대단히 정밀한 그림이 필요한 것이 아니므로 차트의 좌표는 적당히 자릿수를 줄여서 처리해야 하겠다. 다음은 벡터를 그려낸 결과와 강릉시청 제공 행정구역 지도의 비교. 벡터는 그리고 보니 상하가 뒤집어져 있어서 돌려야 했다. 좌표 시작점이 다른 모양이다. 해안가에 선이 튀어나와 있는 건 무슨 이유인지 모르겠다. 원본의 좌표가 틀렸거나 추출 때 순서 등이 꼬인 것 같은데. 구글 앱엔진 적용Datastore 저장GeoPtProperty 필드를 지원하고, ListProperty로 여러 값을 하나에 넣을 수 있게 되어 있다. 만 단위까지 올라가는 값들을 다 넣을 수 있을지는 모르겠지만 일단 된다고 가정하면, 행정구역마다 한 row를 차지하고 그 중의 한 필드로 폴리곤 좌표를 넣을 수 있게 된다. 이때 곤란한 점은 한 영역에 속하는 폴리곤이 계속 이어지는 것이 아니라 중간중간 끝나고 다시 시작한다는 부분이다. XML로 추출한 내용에서 PART > START[INDEX="n"]이 왜 있는 건지 몰랐는데 좌표들이 새로 시작하는 부분을 안내하는 것으로 생각된다. (위의 강릉시 그림에서 해안선에 부자연스럽게 겹쳐진 길쭉한 부분이 제대로 끊어지지 않았기 때문에 생겼다) 따라서 Datastore에도 하나의 ListProperty 안에 전체 폴리곤을 넣지 않거나, 혹은 별개 필드로 PART 정보도 같이 저장해 그릴 때 참조하는 방법이 있겠다. 그런데 GeoPtProperty에 맞추기 위해 경위도로 변환을 했더니 tm128 = Proj(proj='tmerc', lat_0='38N', lon_0='128E', ellps='bessel', x_0=400000, y_0=600000, k=0.9999, towgs84='-146.43,507.89,681.46')utm = Proj(proj='tmerc', lat_0='38N', lon_0='127E', ellps='GRS80', x_0=200000, y_0=500000, k=0.9999, towgs84='-146.43,507.89,681.46')long, lat = transform(utm,latlong,x,y)처음에는 tm128->latlong을 했던 거였고, 이번엔 utm->latlong이 맞는 거였다. (저 식을 쓸 수 있게 공개해두신 분들께 감사를!) -- 하지만 자세히 보면 서쪽으로 300미터 정도 밀려 있다. 뭐, 이 정도야. 이미지 처리현재 앱엔진은 제한적인 이미지 처리 API만을 제공하는데 벡터 처리는 전혀 포함되어 있지 않다. 최종 출력물의 품질이나 중간 가공 과정에서의 다양성을 생각해보면 가급적 벡터 기반으로 처리할 수 있어야 한다. 이미지 자체를 DB에 BLOB으로 저장하고 가져올 수 있다는 점, 그리고 API 중에 이미지 중첩이 있다는 점은 고려할만한 부분이다. 하지만 가령 고정적인 형태로 지역의 부분부분을 저장해둔다고 해도 차트로 표현하기 위해서는 선이 그려진 부분을 적당한 크기로 잘라내야 하고 그러기 위해서는 실시간으로 테두리를 검출하거나 사전에 이미지 바이너리와 함께 영역 정보도 기록해둬야 한다는 점을 고려해야 한다. (이 과정에서 이미지 크기에 따라 품질의 차이가 상당할 것이다) 그런데 외부 모듈로도 벡터를 구현할만한 게 도무지 안 보인다. aggdraw 모듈이 있기는 한데 소스 빌드를 해서 쓰는 거라 패키지에 같이 포함시켜서 올릴 수가 없을 것 같다. PNGCanvas라는 게 있긴 한데 polyline까지만 라인을 여러 개 그리는 식으로 처리해주고 polygon 내부를 색칠하거나 하는 동작은 지원하지 않는다. 정 없으면 wrapper 식으로 만들려고 했던 수준이라서 급한대로 쓸 수는 있겠지만 만족스러운 구현 수준은 아니다. |

처리 순서
0) .shp에서 정보를 뽑아내는 것은 pyshp를 통해서 쉽게 처리할 수 있겠다. XML을 따로 뽑아내는 절차를 거칠 필요가 없음
1) 각 지역의 지도 이미지는 미리 SVG 정도의 완성체로 준비해두거나, 아니면 그때그때 준비할 수 있는 수준으로 저장해두고 만든 결과를 캐시하는 수준.
2) 어떤 지역들을 그려달라는 요청이 오면 그 지역과 인접 지역의 벡터 정보를 불러오고
3) 경계선을 검출하고 캔버스에 올리고
3-1) 인접 지역일수록, 넓은 범위일수록 먼저 캔버스에 올려서, 나중에 올라온 것이 겹치도록 함
3-2) 직접 요청된 지역 외의 인접지역은 폴리곤을 단순화하고 흐릿하게 표시할 필요 있음
4) 이미지로 렌더링
4-1) 혹은 HTML5 canvas에 직접 폴리곤 그대로를 노출하는 방법도 있음