5

I have some GPX track files, each containing tracks with thousands of trackpoints.

I need to split those files into multiple ones, each with 500 (or more, accordingly) points each.

Unfortunately I cannot simplify those tracks, I really need to split them.

As long as I could find, gpsbabel isn't able to do so. I am open to use any tool either on Linux (preferably) or Windows as well.

3 Answers 3

4

Surprisingly it seems gpsbabel indeed can't do it. But at least it can help by first converting to csv. Then I split the result with Unix' split and convert back to gpx with gpsbabel. A similar strategy might work with PowerShell, but I don't know if it has a split equivalent. Here is the bash function I used:

splitTrack() {
    # $1 shall be the gpx file to split
    pfx="${1%.*}-"
    gpsbabel -i gpx -f "$1" -t -o csv -F - \
    | split -d -l 500 --additional-suffix=.csv - "$pfx"

    for f in "$pfx"*.csv; do
        fout=${f%.*}.gpx
        gpsbabel -i csv -f "$f" -x transform,trk=wpt -x nuketypes,waypoints \
                            -o gpx -F "$fout"
        rm "$f"
    done
}

EDIT: Added hint from comments about getting track points out instead of way points.

2
  • Uhm, that generates files with plenty of waypoints though, rather than trackpoints. I tried the transform options described here: gpsbabel.org/htmldoc-1.5.1/filter_transform.html but I was unsuccessful. Would you please have any tip about how to convert the CSV temporary file into a proper track rather than a collection of waypoints? Thanks again
    – Dakatine
    Oct 16, 2018 at 14:49
  • 1
    found it! gpsbabel -i csv -f "$f" -x transform,trk=wpt -x nuketypes,waypoints -o gpx -F "$fout"
    – Dakatine
    Oct 16, 2018 at 15:01
2

Thanks for the script! It's useful to me as well because my Garmin bike navigator starts to throw trackpoints away after a certain number of trackpoints is reached.

I added a separation of waypoints and tracks and a little bit of "compression" to Harald's script (which works in zsh as well).

    splitTrack() {
      # $1 shall be the gpx file to split
      pfx="${1%.*}-"
      # Split tracks off and simplify track (reduce number of trackpoints but keep 
      # sufficient accuracy for bike navigation)
      gpsbabel -i gpx -f "$1" -x nuketypes,waypoints,routes \
      -x simplify,crosstrack,error=0.003k -o gpx -F "${pfx}tracks.gpx"
      # Split waypoints off (import as extra POI gpx to device)
      gpsbabel -i gpx -f "$1" -x nuketypes,tracks,routes -o gpx \
      -F "${pfx}waypoints.gpx"
      # 500 pack from tracks in CSV, start suffix with 01 instead of 00
      gpsbabel -i gpx -f "${pfx}tracks.gpx" -t -o csv -F - \
      | split -d --numeric=1 -l 500 --additional-suffix=.csv - "$pfx"
      rm "${pfx}tracks.gpx"
      # CSV back to gpx
      for f in "$pfx"*.csv; do
        fout=${f%.*}.gpx
        gpsbabel -i csv -f "$f" -x transform,trk=wpt -x nuketypes,waypoints \
             -o gpx -F "$fout"
        rm "$f"
      done
    }

If you want to keep elevation data as well, you may want to use the UNICSV format. Please adjust the re-import command to the field set exported from the GPX to (Uni)CSV. For more information see https://www.gpsbabel.org/htmldoc-development/fmt_unicsv.html. The following snippet requires the usual GNU toolset (sed/tail/split) installed.

splitTrack() {
    # ===
    # abort if no file is passed as argument 1

    if ! [[ -f "$1" ]] 
        then
            echo File missing!
            return
    fi
    # ===

    # ===
    # Set prefix for files according to source file name

    pfx="${1%.*}-"
    # ===

    # ===
    # save waypoints in another file

    gpsbabel \
        -i gpx \
        -f "$1" \
        -x nuketypes,tracks,routes \
        -o gpx \
        -F "${pfx}waypoints.gpx"
    # ===

    # ===
    # filter only track
    # simplify track
    # transform simplified track into waypoints
    # print waypoints in UNICSV format
    # pipe
    # ignore UNICSV header
    # pipe
    # take 500 lines and duplicate each 500th line (overlap 1 line)
    # in order to avoid gap in transition from one to next track part
    # credit goes to https://stackoverflow.com/questions/21756040/extract-a-range-of-rows-with-overlap-using-sed/21757062#21757062
    # pipe
    # split/save each block of 500 lines into separated UNICSV files with prefix according to source file

    gpsbabel \
        -i gpx \
        -f "$1" \
        -x nuketypes,waypoints,routes \
        -x simplify,crosstrack,error=0.003k \
        -x transform,wpt=trk \
        -o unicsv \
        -F - \
    | tail \
        -n +2 \
    | sed \
        -nr ':a;$!{N;s/[^\n]+/&/500;Ta};p;$q;s/.*((\n[^\n]*){1})$/\1/;D' \
    | split \
        -d \
        -a 3 \
        --numeric=1 \
        -l 500 \
        --additional-suffix=.csv \
        - \
        "$pfx"
    # ===

    # ===
    # convert separated UNICSV files back to GPX track files 
    # by transforming UNICSV waypoints back to trackpoints
    # also filter out superfluous name tag

    for f in "$pfx"*.csv; do
        gpsbabel \
            -i unicsv,fields=no+lat+lon+name+ele \
            -f "$f" \
            -x transform,trk=wpt \
            -x nuketypes,waypoints \
            -o gpx \
            -F - \
        | grep \
            -v '<name>.*</name>\|<cmt>.*</cmt>\|<desc>.*</desc>' \
            > "${f%.*}.gpx"
        rm "$f"
    done
    # ===

    return
}

This should work for example with the GPX tracks generated by https://brouter.de/brouter-web

0

If you dont need the time information, you can add a fake time, and then splitt according to the added time. The example takes an unknown track, reduces it to 2000 points, adds a timestamp beginning at the 1.1.2000 and then makes four tracks with 500 waypoints each. So by getting the first 500 waypoints, get the range up to including 8min 19sec.

Pitfall in this example: If there is more than one track in the source, simpify seems to work on each track individually, so there might be more than 2000 waypoints in the output. In this case, there will be waypoints missing at the end.

gpsbabel -t -i gpx -f MultiDayTrackToGo.gpx -x simplify,count=2000 -x track,faketime=f20000101000000+1 -x track,start=20000101000000,stop=20000101000819 -o gpx -F part1.gpx
gpsbabel -t -i gpx -f MultiDayTrackToGo.gpx -x simplify,count=2000 -x track,faketime=f20000101000000+1 -x track,start=20000101000820,stop=20000101001639 -o gpx -F part2.gpx
gpsbabel -t -i gpx -f MultiDayTrackToGo.gpx -x simplify,count=2000 -x track,faketime=f20000101000000+1 -x track,start=20000101001640,stop=20000101002459 -o gpx -F part3.gpx
gpsbabel -t -i gpx -f MultiDayTrackToGo.gpx -x simplify,count=2000 -x track,faketime=f20000101000000+1 -x track,start=20000101002500,stop=20000101003319 -o gpx -F part4.gpx

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.