diff --git a/.gitignore b/.gitignore index 64cadab..a7ba0e6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .DS_Store .vscode __pycache__ +build diff --git a/README.md b/README.md index 21d7071..b3eaff2 100644 --- a/README.md +++ b/README.md @@ -49,44 +49,52 @@ For more options: `gpxinfo -h` ``` $ gpxclean -h -usage: gpxclean [-h] [-e] [-t] [-x] [-r] [-tr] [-a] [-w] [-o F] +usage: gpxclean [-h] [-e] [-m] [-x] [-r] [-t] [-a] [-w] [-o OUTPUT] [-f FOLDER] [-p PREFIX] Clean GPX tracks optional arguments: - -h, --help show this help message and exit - -e, --extensions Remove extensions - -t, --time Remove time - -x, --elevations Remove extensions - -r, --routes Remove routes - -tr, --tracks Remove tracks - -a, --author Remove author data - -w, --waypoints Waypoints - -o F, --output F Output GPX file + -h, --help show this he + -e, --extensions Remove exten + -m, --time Remove time + -x, --elevations Remove exten + -r, --routes Remove route + -t, --tracks Remove track + -a, --author Remove autho + -w, --waypoints Remove waypo + -o OUTPUT, --output OUTPUT + Output GPX file + -f FOLDER, --folder FOLDER + Folder containing files + -p PREFIX, --prefix PREFIX + Prefix of output files ``` ## gpxmerge ``` $ gpxmerge -h -usage: gpxmerge [-h] [-o F] [-t] [gpx [gpx ...]] +usage: gpxmerge [-h] [-o OUTPUT] [-m] [-f FOLDER] [gpx ...] Merge GPX files positional arguments: - gpx GPX file + gpx GPX file optional arguments: - -h, --help show this help message and exit - -o F, --output F Output GPX file - -t, --time Sort by time + -h, --help show this help message and exit + -o OUTPUT, --output OUTPUT + Output GPX file + -m, --time Sort by time + -f FOLDER, --folder FOLDER + Folder containing files ``` ## gpxsimplify ``` $ gpxsimplify -h -usage: gpxsimplify [-h] [-d DISTANCE] gpx +usage: gpxsimplify [-h] [-d DISTANCE] [-o OUTPUT] [-f FOLDER] [-p PREFIX] gpx Simplify tracks using the Ramer-Douglas-Peucker algorithm @@ -97,6 +105,12 @@ optional arguments: -h, --help show this help message and exit -d DISTANCE, --distance DISTANCE Max distance + -o OUTPUT, --output OUTPUT + Output GPX file + -f FOLDER, --folder FOLDER + Folder containing files + -p PREFIX, --prefix PREFIX + Prefix of output files ``` ## gpxsplitter diff --git a/gpxtools/gpxclean.py b/gpxtools/gpxclean.py index 73e0554..0cc7f24 100644 --- a/gpxtools/gpxclean.py +++ b/gpxtools/gpxclean.py @@ -1,7 +1,7 @@ import argparse import gpxpy.gpx as gpxpy import gpxpy as gpx_parser - +import glob from . import common from typing import * @@ -9,13 +9,16 @@ def main() -> None: parser = argparse.ArgumentParser(description='Clean GPX tracks') parser.add_argument('-e', '--extensions', action='store_true', help='Remove extensions') - parser.add_argument('-t', '--time', action='store_true', help='Remove time') + parser.add_argument('-m', '--time', action='store_true', help='Remove time') parser.add_argument('-x', '--elevations', action='store_true', help='Remove extensions') parser.add_argument('-r', '--routes', action='store_true', help='Remove routes') - parser.add_argument('-tr', '--tracks', action='store_true', help='Remove tracks') + parser.add_argument('-t', '--tracks', action='store_true', help='Remove tracks') parser.add_argument('-a', '--author', action='store_true', help='Remove author data') - parser.add_argument('-w', '--waypoints', action='store_true', help='Waypoints') - parser.add_argument('-o', '--output', metavar='F', type=str, default='clean.gpx', help='Output GPX file') + parser.add_argument('-w', '--waypoints', action='store_true', help='Remove waypoints') + parser.add_argument('-o', '--output', type=str, help='Output GPX file') + parser.add_argument('-f', '--folder', type=str, help='Folder containing files') + parser.add_argument('-p', '--prefix', type=str, default = 'cleaned_', help='Prefix of output files') + args, gpx_files = parser.parse_known_args() extensions: bool = args.extensions @@ -26,9 +29,15 @@ def main() -> None: author: bool = args.author waypoints: bool = args.waypoints output = args.output + folder = args.folder + prefix = args.prefix + + if folder: + filelist = glob.glob(folder + '*.gpx') + gpx_files.extend(filelist) for gpx_file in gpx_files: - with open(gpx_file) as f: + with open(gpx_file, encoding='utf-8') as f: g = gpx_parser.parse(f) if extensions: common.clean_extensions(g) @@ -50,9 +59,10 @@ def main() -> None: if waypoints: g.waypoints = [] - if not output: - output = common.prefix_filename(gpx_file, "clean_") + if len(gpx_files) > 1 or (not output): + out_gpx = common.prefix_filename(gpx_file, prefix) - with open(output, "w") as f: - f.write(g.to_xml()) + with open(out_gpx, "w", encoding='utf-8') as f: + print(f'Cleaned {gpx_file} => {out_gpx}') + f.write(g.to_xml()) diff --git a/gpxtools/gpxinfo.py b/gpxtools/gpxinfo.py index 07dc73b..ea3bdfe 100644 --- a/gpxtools/gpxinfo.py +++ b/gpxtools/gpxinfo.py @@ -7,8 +7,9 @@ import math as mod_math import argparse as mod_argparse -import gpxpy as mod_gpxpy -import gpxpy.gpx as mod_gpx +import gpxpy.gpx as gpxpy +import gpxpy as gpx_parser +import glob from typing import * @@ -50,7 +51,7 @@ def format_speed(speed: float, miles: bool) -> str: return '{:.2f}m/s = {:.2f}km/h'.format(speed, speed * 3600. / 1000.) -def print_gpx_part_info(gpx_part: Union[mod_gpx.GPX, mod_gpx.GPXTrack, mod_gpx.GPXTrackSegment], indentation: str=' ', miles: bool = False, seconds: bool = False) -> None: +def print_gpx_part_info(gpx_part: Union[gpxpy.GPX, gpxpy.GPXTrack, gpxpy.GPXTrackSegment], indentation: str=' ', miles: bool = False, seconds: bool = False) -> None: """ gpx_part may be a track or segment. """ @@ -91,7 +92,7 @@ def print_gpx_part_info(gpx_part: Union[mod_gpx.GPX, mod_gpx.GPXTrack, mod_gpx.G print('') -def print_gpx_info(gpx: mod_gpx.GPX, gpx_file: str, miles: bool, seconds: bool, only_track: bool) -> None: +def print_gpx_info(gpx: gpxpy.GPX, gpx_file: str, miles: bool, seconds: bool, only_track: bool) -> None: print('File: %s' % gpx_file) if gpx.name: @@ -123,7 +124,7 @@ def run(gpx_files: List[str], miles: bool, seconds: bool, only_track: bool) -> N for gpx_file in gpx_files: try: - gpx = mod_gpxpy.parse(open(gpx_file)) + gpx = gpx_parser.parse(open(gpx_file, encoding='utf-8')) print_gpx_info(gpx, gpx_file, miles, seconds, only_track) except Exception as e: mod_logging.exception(e) @@ -138,12 +139,20 @@ def main() -> None: parser.add_argument('-s', '--seconds', action='store_true', help='print times as N seconds, rather than HH:MM:SS') parser.add_argument('-m', '--miles', action='store_true', help='print distances and speeds using miles and feet') parser.add_argument('-d', '--debug', action='store_true', help='show detailed logging') + parser.add_argument('-f', '--folder', type=str, help='Folder containing files') + args, gpx_files = parser.parse_known_args() seconds = args.seconds miles = args.miles debug = args.debug only_track = args.track + folder: bool = args.folder + + if folder: + filelist = glob.glob(folder + '*.gpx') + gpx_files.extend(filelist) if debug: mod_logging.basicConfig(level=mod_logging.DEBUG, format='%(asctime)s %(name)-12s %(levelname)-8s %(message)s') + run(gpx_files=gpx_files, miles=miles, seconds=seconds, only_track=only_track) \ No newline at end of file diff --git a/gpxtools/gpxmerge.py b/gpxtools/gpxmerge.py index 5cc9136..13ca561 100644 --- a/gpxtools/gpxmerge.py +++ b/gpxtools/gpxmerge.py @@ -1,6 +1,8 @@ import argparse -import gpxpy.gpx as gpx -import gpxpy +import gpxpy.gpx as gpxpy +import gpxpy as gpx_parser +import glob + import datetime import os.path as path import datetime @@ -9,7 +11,7 @@ from typing import * -def get_time(g: gpx.GPX) -> Optional[datetime.datetime]: +def get_time(g: gpxpy.GPX) -> Optional[datetime.datetime]: for t in g.tracks: for s in t.segments: for pt in s.points: @@ -19,14 +21,20 @@ def get_time(g: gpx.GPX) -> Optional[datetime.datetime]: def main() -> None: parser = argparse.ArgumentParser(description='Merge GPX files') - parser.add_argument('gpx_files', metavar='gpx', type=str, default='', nargs='*', help='GPX file') - parser.add_argument('-o', '--output', metavar='F', type=str, default='merged.gpx', help='Output GPX file') - parser.add_argument('-t', '--time', action='store_true', help='Sort by time') - args = parser.parse_args() + # parser.add_argument('gpx_files', metavar='gpx', type=str, default='', nargs='*', help='GPX file') + parser.add_argument('-o', '--output', type=str, default='merged.gpx', help='Output GPX file') + parser.add_argument('-m', '--time', action='store_true', help='Sort by time') + parser.add_argument('-f', '--folder', type=str, help='Folder containing files') + + args, gpx_files = parser.parse_known_args() - gpx_files = args.gpx_files out_file = args.output sort_by_time = args.time + folder = args.folder + + if folder: + filelist = glob.glob(folder + '*.gpx') + gpx_files.extend(filelist) keep_extensions = True @@ -38,13 +46,13 @@ def main() -> None: for gpx_file in gpx_files: print(f"Reading {gpx_file}") - gpxs.append(gpxpy.parse(open(gpx_file))) + gpxs.append(gpx_parser.parse(open(gpx_file, encoding='utf-8'))) if sort_by_time: print("Sorting by time") gpxs = sorted(gpxs, key=get_time) - base_gpx: Optional[gpx.GPX] = None + base_gpx: Optional[gpxpy.GPX] = None for g in gpxs: if base_gpx: if len(g.nsmap) != len(base_gpx.nsmap): @@ -69,5 +77,5 @@ def main() -> None: print("Removing extensions") common.clean_extensions(base_gpx) - with open(out_file, "w") as f: + with open(out_file, "w", encoding='utf-8') as f: f.write(base_gpx.to_xml()) \ No newline at end of file diff --git a/gpxtools/gpxsimplify.py b/gpxtools/gpxsimplify.py index c711a04..ab707a2 100644 --- a/gpxtools/gpxsimplify.py +++ b/gpxtools/gpxsimplify.py @@ -7,25 +7,42 @@ import math as mod_math import argparse as mod_argparse from . import common - -import gpxpy as mod_gpxpy -import gpxpy.gpx as mod_gpx +# import gpxpy.gpx as gpxpy +import gpxpy as gpx_parser +import glob from typing import * def main() -> None: parser = mod_argparse.ArgumentParser(description='Simplify tracks using the Ramer-Douglas-Peucker algorithm') parser.add_argument('-d', '--distance', type=float, default=10, help='Max distance') - parser.add_argument('gpx_files', metavar='gpx', type=str, default='', nargs=1, help='GPX file') + # parser.add_argument('gpx_files', metavar='gpx', type=str, default='', nargs=1, help='GPX file') + parser.add_argument('-o', '--output', type=str, help='Output GPX file') + parser.add_argument('-f', '--folder', type=str, help='Folder containing files') + parser.add_argument('-p', '--prefix', type=str, default = 'simplified_', help='Prefix of output files') - args = parser.parse_args() - gpx_file = args.gpx_files[0] + args, gpx_files = parser.parse_known_args() distance = args.distance + folder = args.folder + output = args.output + prefix = args.prefix - with open(gpx_file) as f: - g = mod_gpxpy.parse(f) + if folder: + filelist = glob.glob(folder + '*.gpx') + gpx_files.extend(filelist) - g.simplify(max_distance=distance) + for gpx_file in gpx_files: + + with open(gpx_file, encoding='utf-8') as f: + g = gpx_parser.parse(f) + + g.simplify(max_distance=distance) + + if len(gpx_files) > 1 or (not output): + out_gpx = common.prefix_filename(gpx_file, prefix) + + with open(out_gpx, "w", encoding='utf-8') as f: + f.write(g.to_xml()) + + print(f'Simplified {gpx_file} => {out_gpx}') - with open(common.prefix_filename(gpx_file, "_simplified"), "w") as f: - f.write(g.to_xml()) \ No newline at end of file diff --git a/gpxtools/gpxsplitter.py b/gpxtools/gpxsplitter.py index fd60783..4ef6de4 100644 --- a/gpxtools/gpxsplitter.py +++ b/gpxtools/gpxsplitter.py @@ -23,7 +23,7 @@ def save_gpx(gpg: gpxpy.GPX) -> None: def process(gpx_file: str, split_by_days: bool, time_interval: str) -> None: print(f"Opening {gpx_file}") - with open(gpx_file) as f: + with open(gpx_file, encoding='utf-8') as f: gpx = gpx_parser.parse(f) split_func: Callable[[datetime.datetime, datetime.datetime, int], bool] @@ -76,14 +76,14 @@ def fltr(pt: gpxpy.GPXTrackPoint) -> bool: gpx_interval.remove_empty() fn = common.prefix_filename(gpx_file, time_from.strftime(TIME_FORMAT)) - with open(fn, "w") as f: + with open(fn, "w", encoding='utf-8') as f: f.write(gpx_interval.to_xml()) print(f"Saved {fn}") def main() -> None: parser = argparse.ArgumentParser(description='Split GPX file') parser.add_argument('-d', '--days', action='store_true', default=False, help='Split multi-day track into single day tracks') - parser.add_argument('-t', '--time', type=str, default="", help='Split by time intervals (for exampe 1m, 2s, 3h)') + parser.add_argument('-m', '--time', type=str, default="", help='Split by time intervals (for exampe 1m, 2s, 3h)') parser.add_argument('gpx_files', metavar='gpx', type=str, default='', nargs='*', help='GPX file') args = parser.parse_args()