Skip to content

Instantly share code, notes, and snippets.

@kylebarron
Created February 14, 2019 00:37
Show Gist options
  • Save kylebarron/0e206d4500b5f939ade98764d9e1ef66 to your computer and use it in GitHub Desktop.
Save kylebarron/0e206d4500b5f939ade98764d9e1ef66 to your computer and use it in GitHub Desktop.
Combine Halfmile GPX segments into one or a few big GPX files
#! /usr/bin/env python3
"""
Program: Combine Halfmile GPX tracks into a single GPX track
Author: Kyle Barron
"""
import io
import requests
import gpxpy
import gpxpy.gpx
from zipfile import ZipFile
def main():
for state in ['ca1', 'ca2', 'or', 'wa']:
gpxs = download_gpx_tracks(state[:2])
tracks, waypoints = split_into_tracks_and_waypoints(gpxs)
split = int(state[2]) if state.startswith('ca') else None
tracks = combine(sort_gpxs(tracks), split)
waypoints = combine(sort_gpxs(waypoints), split)
with open(f'{state}_pct_tracks.gpx', 'w') as f:
f.write(tracks.to_xml())
with open(f'{state}_pct_waypoints.gpx', 'w') as f:
f.write(waypoints.to_xml())
def download_gpx_tracks(state):
headers = {'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.102 Safari/537.36'}
unzipped_content = {}
url = 'https://www.pctmap.net/wp-content/uploads/pct'
url += f'/{state}_state_gps.zip'
r = requests.get(url, headers=headers)
content = io.BytesIO(r.content)
with ZipFile(content) as zf:
for name in zf.namelist():
if not name.startswith(state):
continue
if not name.endswith('.gpx'):
continue
unzipped_content[name] = zf.read(name).decode('utf-8')
return unzipped_content
def split_into_tracks_and_waypoints(gpxs):
tracks = {}
waypoints = {}
for name, data in gpxs.items():
if name.endswith('tracks.gpx'):
tracks[name] = data
elif name.endswith('waypoints.gpx'):
waypoints[name] = data
else:
raise Exception()
return tracks, waypoints
def sort_gpxs(gpx):
return dict(sorted(gpx.items()))
def combine(gpx, split=None):
new_gpx = gpxpy.gpx.GPX()
if split is not None:
if split == 1:
gpx = dict(list(gpx.items())[:len(gpx) // 2])
elif split == 2:
gpx = dict(list(gpx.items())[len(gpx) // 2:])
else:
raise Exception('split must be 1, 2, or None')
for name, g in gpx.items():
g = gpxpy.parse(g)
for track in g.tracks:
new_gpx.tracks.append(track)
for waypoint in g.waypoints:
new_gpx.waypoints.append(waypoint)
for route in g.routes:
new_gpx.routes.append(route)
return new_gpx
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment