본문 바로가기

개발기/My Travel Map

2편: 시군구 250개 지도 데이터, 확대하면 틈이 벌어졌습니다

반응형

지도 SDK 대신 GeoJSON

지도 SDK를 붙이면 타일 이미지가 깔립니다. 하지만 제가 원한 건 도로도 건물도 없는, 지역 모양만 있는 지도였습니다. 지역이 색으로 채워지는 게 전부인 화면이라 타일은 오히려 방해였습니다.

그래서 공개 데이터를 썼습니다.

  • 출처: southkorea/southkorea-maps (통계청 2018 시군구 경계)
  • 시도 17개로 시작했다가 시군구 250개로 세분화했습니다. 시도 단위는 한 번 여행하면 금방 칠해져서 재미가 없습니다
  • 원본은 18MB라 저장소에는 넣지 않고 변환 결과만 커밋했습니다

경계 데이터는 그대로 쓰기엔 너무 무겁습니다. 점 개수를 줄이는 단순화(simplify)가 필요합니다.

그런데 확대하면 틈이 생겼습니다

부산 중구와 부산진구 사이에 흰 선 같은 틈이 보였습니다. 처음엔 안티에일리어싱 문제인 줄 알았는데, 확대할수록 틈이 더 벌어졌습니다.

원인은 단순화 방식이었습니다.

  • 지역마다 폴리곤을 독립적으로 단순화했습니다
  • A 지역과 B 지역이 공유하는 경계선이 양쪽에서 서로 다르게 깎였습니다
  • 두 선이 어긋난 만큼 빈 공간이 생기고, 확대하면 그게 그대로 커집니다

데이터 자체가 어긋나 있으니 그리는 쪽에서 아무리 손봐도 해결되지 않는 문제였습니다.

해결: 위상 보존 단순화

mapshaper를 쓰면 위상(topology)을 보존한 단순화가 됩니다. 폴리곤을 따로 보지 않고, 공유 경계를 하나의 arc로 인식해서 한 번만 단순화합니다. 양쪽이 같은 선을 쓰니 배율과 무관하게 틈이 생기지 않습니다.

 
bash
npx -y mapshaper@0.7.62 RAW \
  -simplify dp interval=20 keep-shapes \
  -filter-fields name,code \
  -o assets/geo/korea_sigungu.json format=geojson precision=0.00001
  • interval=20은 20m 간격으로 단순화한다는 뜻입니다
  • keep-shapes를 빼면 작은 섬들이 통째로 사라집니다

시도 경계는 따로 받지 않고 만들었습니다

굵은 시도 경계선도 필요했는데, 시도 데이터를 따로 받아 쓰면 또 같은 문제가 생깁니다. 출처가 다르면 선이 미묘하게 어긋납니다. 그래서 방금 만든 시군구 결과물을 시도 코드로 dissolve 해서 만들었습니다.

 
bash
npx -y mapshaper@0.7.62 korea_sigungu.json \
  -each 'sido=code.substr(0,2)' -dissolve sido \
  -o assets/geo/korea_sido.json format=geojson precision=0.00001

시군구 코드 5자리의 앞 2자리가 시도 코드라서 가능한 방법입니다. 이렇게 만들면 시도 경계가 시군구 경계와 정확히 겹칩니다.

결과물은 이렇습니다.

  • 시군구: 250 features / 122,588 points / 2.5MB
  • 시도: 17 features / 63,301 points / 1.3MB

삽질 기록 두 가지

zsh 단어 분리. 변환 과정을 tool/build_geo.sh로 만들었는데, 변수에 담은 옵션 문자열이 통째로 한 덩어리로 넘어가서 mapshaper가 계속 에러를 뱉었습니다. zsh는 bash와 달리 변수 확장 시 단어 분리를 하지 않습니다. 스크립트 맨 위에 setopt shwordsplit 한 줄을 넣어 해결했습니다.

교차 경고. intersections could not be repaired 경고가 나오는데, 원본 데이터 자체에 교차가 있어서 나는 것이라 정상입니다. 한참 들여다봤다가 원본을 열어 보고 포기했습니다.

다음 편에서는

이 데이터를 실제로 그리는 이야기입니다. CustomPainter로 250개 지역을 그리고, 최대 900배까지 확대할 수 있게 만드는 과정에서 좌표계와 행렬 때문에 꽤 고생했습니다.

 

반응형