산가브리엘 산맥에서 가장 접근하기 어려운 지점 찾기
이 글은 OpenStreetMap 데이터와 보로노이 다이어그램(Voronoi diagram) 알고리즘을 활용하여, 산가브리엘 산맥에서 도로나 등산로로부터 가장 멀리 떨어진 '접근 불가능의 극점(Pole of Inaccessibility)'을 계산하는 과정을 설명합니다. 복잡한 3D 지형 데이터 대신 적절한 수학적 근사(평면 투영 및 오차 무시)를 적용하여 연산을 단순화하고 효율적으로 결과를 도출한 기술적 접근이 흥미롭습니다. 개발자와 데이터 분석가에게 지리 공간 데이터를 처리하고 최적화하는 실용적인 사례를 제공합니다.
원문 제목: 산가브리엘 산맥의 접근 불가능의 극점(Poles of Inaccessibility)
소스: hackernews
업데이트: 저는 가장 먼 극점(Pole)을 방문해서 그곳에 기록부(register)를 설치해 두었습니다: https://eispiraten.com/viewtopic.php?t=7040 . 꼭 방문해서 서명해 보세요! 또한 미국 본토(48개 주)에 대해서도 유사한 분석을 실행해 보았습니다.
어느 날 친구와 함께 등산을 하던 중, '산가브리엘 산맥에서 가장 접근하기 어려운 지점은 어디일까?'라는 질문이 나왔습니다. 여기서 '접근 가능하다'는 것의 기준은 근처에 도로나 등산로가 있다는 것을 의미합니다. 저는 이 질문에 답해보기로 결심했습니다. 결과물로 나온 코드는 새 리포지토리에 있습니다: https://github.com/dkogan/inaccessibility.
이러한 지점은 '접근 불가능의 극점(Pole of Inaccessibility)'이라고 불리며, 주어진 객체들(여기서는 도로 등)으로부터 최대한 멀리 떨어진 지점을 의미합니다. 이러한 극점의 위치는 지구상에서 가장 내륙 깊숙한 곳이나 육지로부터 가장 머디 바다 한가운데 같은 형태로 잘 알려져 있습니다. 여기서는 범위를 산가브리엘 산맥으로 한정하고, 도로와 등산로에서 최대한 벗어나는 곳을 찾고자 합니다.
접근 방식
입력 데이터 처리 OpenStreetMap에는 모든 도로와 등산로를 매핑할 수 있는 오픈 데이터가 있습니다. 이것이 우리의 입력 데이터셋입니다. 2D 기하학에서 '접근 불가능의 극점'을 계산하는 가장 좋은 방법은, 우리가 피하고자 하는 기하학적 객체들에 대한 보로노이 다이어그램(Voronoi diagram)을 구성한 뒤, 가장 멀리 떨어진 지점에 해당하는 보로노이 정점(vertex)을 찾는 것입니다.
하지만 우리가 사는 세상은 2D가 아니며, 타원체 위에 다양한 고도가 존재합니다. 이 분석의 궁극적인 목적은 '야외 탐험가들이 방문할 수 있는 장소를 찾아내고 다른 사람들에게 증명하는 것'이므로 극단적인 정확도는 필요하지 않습니다. 따라서 세상을 '국소적으로 평면'이라고 가정하고, 보로노이 다이어그램 기반의 방법을 사용하는 것으로 충분하다고 판단했습니다.
그래서 조회 영역의 중심점에서 지구 표면에 접하는 평면(tangent plane)을 하나 만들고, 모든 입력 지점을 이 평면에 투영했습니다. 예를 들어 대양처럼 넓은 지역의 극점을 찾을 때는 이 방식이 통하지 않겠지만, 이 산맥에서는 잘 작동합니다. 이 접면을 계산할 때는 지구가 완벽한 구형이라고 가정했습니다. 접점에서 멀어지면서 평면을 따라 이동할수록 고도 오차는 다음과 같이 커집니다: E = sqrt(R_earth^2 + d^2) - R_earth. 산가브리엘 산맥은 폭이 약 80km이고, 접면이 그 중앙에 위치하므로 최악의 경우 d = 40km이며 이때 오차는 약 125m 정도입니다. 이 정도면 충분히 훌륭한 결과입니다.
(플롯 출처 생략)
지형(고도 차이)은 거리 측정 기준에 포함시키면 보로노이 다이어그램보다 훨씬 복잡한 알고리즘이 필요하므로 무시했으며, 이렇게 하면 '접근 불가능성'의 개념을 더 명확하게 유지할 수 있습니다.
접근 불가능의 극점 계산 저는 가장 기본적인 보로노이 알고리즘을 사용하고 싶었기 때문에, 입력 데이터를 선분이 아닌 '점들의 집합'으로만 표현했습니다. 합리적인 정확도를 얻기 위해 모든 도로를 최소 100m마다 한 번씩 점으로 샘플링했습니다.
이제 2D 평면에 충분히 빽빽한 점 집합이 생겼으니, 여기에 보로노이 다이어그램을 구성합니다. 아무런 제약이 없으면 가장 먼 지점은 한쪽으로 무한히 멀어지는 곳에 위치할 것이므로, 일반적으로 해를 '입력 점들의 볼록 껍질(convex hull) 내부'로 제한합니다. 즉, 접근 불가능의 극점은 보로노이 정점 위에 있거나, 보로노이 모서리와 볼록 껍질의 교차점에 있게 됩니다.
제 경우 조회 영역의 가장자리(평지 쪽)가 내부(산악 지역)보다 도로가 더 많으므로, 극점이 볼록 껍질 위에 놓여 있지 않을 것이라고 단순 가정했습니다. 조회 지역 밖의 모든 보로노이 정점을 무시하면 되기 때문에 구현이 훨씬 단순해집니다. 그러므로 저는 모든 보로노이 정점을 살펴보고, 인접한 입력 점 사이의 거리를 확인한 다음, 해당 거리가 가장 큰 정점을 찾아 반환하면 됩니다.
구현 처리 과정의 각 단계는 각자의 독립적인 프로그램으로 작성되었습니다. 이렇게 하면 구현이 단순해지고 각 부분을 개별적으로 다루기 쉽습니다.
데이터 가져오기 먼저 OSM(OpenStreetMap)을 쿼리합니다. 이 작업은 query.sh 스크립트로 수행됩니다. 이 스크립트는 쿼리(조회) 영역의 구석 좌표들을 입력으로 받아... (이하 생략)