GPS Route Site

GPX 파일 안에는 무엇이 들어 있나

GPX는 GPS 경로를 주고받는 표준 형식입니다. 열어 보면 그냥 XML이고, 구조는 30분이면 다 이해할 수 있을 만큼 단순합니다.

그런데 같은 코스를 담은 GPX 두 개가 기기에서 전혀 다르게 동작하는 일이 흔합니다. 하나는 "코스"로 들어가는데 다른 하나는 지도에 점만 찍히거나, 17 km짜리 코스가 40 km로 나오거나 합니다. 원인은 대부분 이 글에서 다루는 세 가지입니다.

점이 세 종류입니다

GPX에는 좌표를 담는 태그가 셋 있고, 셋 다 구조는 같은데 뜻이 다릅니다. GPX 1.1 스펙의 정의를 그대로 옮기면 이렇습니다.

태그 스펙의 정의 실제 의미
<wpt>지도 위의 웨이포인트, 관심 지점, 이름 붙은 지형지물독립된 점. 화장실, 정상, 주차장
<rtept> (<rte> 안)목적지로 이어지는 분기점의 순서 있는 목록계획된 경로. "여기서 좌회전"
<trkpt> (<trk> 안)경로를 서술하는 점의 순서 있는 목록기록된 자취. 빵부스러기

핵심은 rte는 계획이고 trk는 기록이라는 것입니다. 대부분의 기기와 앱이 이 둘을 다르게 취급합니다 — 한쪽은 따라갈 경로로, 다른 한쪽은 지나간 활동으로요. 받은 파일이 기대와 다르게 들어갔다면 가장 먼저 확인할 것이 이것입니다. 파일을 텍스트 편집기로 열어 <trk가 있는지 <rte가 있는지 보면 됩니다.

셋 다 없거나 좌표가 하나도 없으면 그 파일은 빈 파일입니다.

<trkseg>이 여러 개인 것은 정상입니다

<trk> 안에는 <trkseg>(트랙 세그먼트)가 하나 이상 들어갑니다. 스펙은 이렇게 정의합니다 — "논리적으로 순서대로 연결된 트랙 포인트의 목록", 그리고 세그먼트가 나뉘는 이유는 GPS 수신이 끊겼거나 기기가 꺼졌을 때입니다.

즉 <trkseg>이 셋이라고 경로가 셋인 게 아닙니다. 하나의 경로가 신호 끊김으로 세 토막이 된 것이고, 이어 붙이는 게 맞습니다.

<trk>가 여러 개인 것은 전혀 다른 이야기입니다

한 파일에 <trk>가 여럿이면 그건 서로 다른 경로입니다. 그리고 여기서 실제로 사고가 납니다.

이 사이트가 두루누비 코스를 들여올 때 겪은 일입니다.

두루누비는 한 코스의 본선과 만조 우회로를 하나의 파일에 두 개의 <trk>로 넣습니다. 문서 안의 <trkpt>를 전부 읽으면 둘이 끝과 끝으로 이어 붙습니다. 서해랑길 34코스는 실제 17.0 km인데 40.2 km로 나왔고, 한 경로가 끝나고 다른 경로가 시작하는 중간에 5 km짜리 점프가 직선으로 그어졌습니다.

그래서 이 사이트의 파서는 첫 번째 <trk>만 읽습니다. 세그먼트가 아니라 트랙 요소를 기준으로 범위를 잡기 때문에, 위의 <trkseg> 여럿은 그대로 이어지고 <trk> 여럿은 나뉩니다.

남의 GPX 거리가 이상하게 크다면 <trk> 개수를 세어 보세요. grep -c "<trk>" 파일.gpx 한 줄이면 됩니다.

<ele>는 선택 요소입니다 — 그리고 구멍이 문제입니다

고도는 각 점 안의 <ele>에 미터 단위로 들어가는데, 스펙상 선택 요소입니다. 없어도 유효한 GPX입니다.

까다로운 건 일부 점에만 있는 경우입니다. 천 개 점 중 몇 개가 <ele> 없이 오는 공개 파일이 실제로 있습니다. 구멍이 뚫린 프로파일로 누적 상승을 합하면 그 값은 틀립니다. 그래서 이 사이트는 고도를 전부-아니면-전무로 다룹니다 — 모든 점에 유효한 <ele>가 있을 때만 그 파일의 고도를 쓰고, 하나라도 비면 고도 서비스에 다시 물어봅니다.

고도가 채워져 있어도 값이 가짜인 경우는 더 까다로운데, 그건 누적 상승 안내에서 따로 다룹니다.

<time>은 방향을 정합니다

<time>도 선택 요소이고, 스펙은 UTC 기준 ISO 8601을 요구합니다.

기록된 활동에는 보통 있고 계획한 경로에는 보통 없습니다. 그런데 여기에 함정이 하나 있습니다 — GPX에는 "정방향"이라는 개념이 없습니다. 점은 문서에 적힌 순서대로 읽히고, 첫 점이 출발지가 됩니다.

그래서 역방향으로 내보낸 파일은 출발점과 도착점이 뒤바뀐 채로 들어갑니다. 이 사이트는 모든 점에 시각이 있고 그 시각이 거꾸로 흐르면(마지막 시각이 첫 시각보다 이르면) 시간순으로 뒤집습니다. <time>이 없는 파일은 그렇게 판단할 근거가 없어서 화면에서 직접 뒤집으셔야 합니다.

이 사이트가 내보내는 파일

지도에서 그린 경로를 GPX로 받으면 정확히 이 구조가 나옵니다.

<?xml version="1.0" encoding="UTF-8"?>
<gpx version="1.1" creator="gps-file-generator"
     xmlns="http://www.topografix.com/GPX/1/1">
  <metadata>
    <name>경로 이름</name>
  </metadata>
  <wpt lat="37.5554" lon="126.9726">
    <name>서울역</name>
  </wpt>
  <trk>
    <name>경로 이름</name>
    <trkseg>
      <trkpt lat="37.5554" lon="126.9726"></trkpt>
      <trkpt lat="37.5561" lon="126.9738"></trkpt>
    </trkseg>
  </trk>
</gpx>

읽을 점 세 가지입니다.

  • <trk> 하나에 <trkseg> 하나. 위에서 본 두 함정을 애초에 만들지 않습니다.
  • 경유지는 <wpt>로 따로. 트랙 안에 섞지 않으므로 경로를 지우지 않고도 마커만 다룰 수 있습니다.
  • <ele>도 <time>도 없습니다. 그린 경로는 기록된 활동이 아니라 계획이고, 지어낸 고도나 시각을 넣는 것보다 없는 편이 정직합니다. 고도는 화면의 그래프에서 보시면 됩니다.

GeoJSON과 KML은 언제 쓰나

같은 경로를 세 형식으로 받을 수 있는데, 쓰임이 다릅니다.

형식 쓰는 곳 형태
GPXGPS 기기, 운동 앱XML. <trk> 하나에 트랙 포인트
GeoJSON웹 지도, GIS 도구, 코드JSON. FeatureCollection 안의 LineString
KML구글 어스, 구글 지도XML. Placemark 안의 LineString

무엇을 쓸지 모르겠으면 GPX입니다. 좌표 순서 하나만 조심하시면 됩니다 — GeoJSON과 KML은 경도,위도 순이고 GPX는 lat/lon을 이름으로 구분합니다. 직접 변환 코드를 짜다 지구 반대편이 나오는 사고가 대개 여기서 납니다.

파일이 기기에서 안 열릴 때

텍스트 편집기로 열어 위에서부터 확인하세요.

1. 좌표가 있나 — <trkpt, <rtept, <wpt 중 하나라도 있어야 합니다. 없으면 빈 파일입니다.

2. <trk>인가 <rte>인가 — 기대한 것과 다르게 들어갔다면 여기입니다.

3. <trk>가 몇 개인가 — 둘 이상이면 거리가 부풀고 중간에 직선 점프가 생깁니다.

4. 네임스페이스가 맞나 — xmlns="http://www.topografix.com/GPX/1/1". 엄격한 기기는 이게 없으면 거부합니다.

5. 점이 너무 많지 않나 — 기기마다 코스당 점 개수 상한이 있습니다. 수만 점짜리 파일은 줄여야 합니다.

받은 파일을 실제로 기기에 넣는 절차는 GPX 파일 사용법에 있습니다.