summaryrefslogtreecommitdiffhomepage
path: root/scripts/match-road.sh
blob: 18461029de7937e69fa2edcb0aa74ebe703038fb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#!/usr/bin/env bash
#
# Author: Pham
#
# This script accepts a single GPX file as parameter and
# output the processed GPX body to STDOUT, using Mapbox Map Matching API v4.
# read doc at: https://docs.mapbox.com/api/legacy/map-matching-v4/
#
# Example:
#
# match-road.sh raw.gpx > new.gpx
#
# Hint:
#
# Remember to put Mapbox Access Token at the top!

#set -x
set -e

# put yout Mapbox token here
ACCESS_TOKEN=$(cat ~/settings/tokens/mapbox)
# number of coordinates for each Mapbox Map Matching API request, Maximum value is 100
LIMIT=10

ORIGIN_DATA=/tmp/$(basename $1).origin
RESPONSE=/tmp/$(basename $1).response

# extract data from the given gpx file, dump coordindate and time with the following format:
# [121.0179739,14.5515336] 1984-01-01T08:00:46.234
function get_data() {
    sed -nr '/<trkpt /, /<\/trkpt>/ {H; /<\/trkpt>/ {x; s/\n/ /g; p; s/.*//; x}}' $1 |\
    sed -nr 'h; s/.*lon="([^"]+).*/\1/; H; g
                s/.*lat="([^"]+).*/\1/; H; g
                # If trkpt has no time, leave it blank
                /time/ {
                    s/.*<time>([^.]+).*<\/time>.*/\1/
                    H; g
                }
                s/^[^\n]+\n//; s/\n/ /g; p' |\
    sed -r 's/^([^ ]+) ([^ ]+)/[\1,\2]/' |\
    awk '!_[$2]++'
}

# Read date Make GeoJSON object for Map Matching API
function make_geojson() {
    #jq -nR '{type: "Feature", properties: {coordTimes: .[1]}, geometry: {type: "LineString", coordinates: .[0]}}'
    awk '{printf("[%s,\"%s\"]\n", $1, $2)}' |\
        jq '[inputs] | {type: "Feature", properties: {coordTimes: (map(.[1]))}, geometry: {type: "LineString", coordinates: map(.[0])}}'
}

get_data $1 > $ORIGIN_DATA

# Consume raw data with serveral request
while [ -s $ORIGIN_DATA ]; do
    head -$LIMIT $ORIGIN_DATA |\
    make_geojson
    exit 0
    # Mapbox Map Matching API, store response into tmp file
    curl -X POST -s  --data @- --header "Content-Type:application/json" https://api.mapbox.com/matching/v4/mapbox.driving.json?access_token=$ACCESS_TOKEN > $RESPONSE

    # Put existing timestamps to matched points, and interpolate new timestamps into new points
    join -a1 \
        <(jq -c  '.features[0].geometry.coordinates[]' $RESPONSE) \
        <(jq -cr '.features[0].properties | [.matchedPoints, (.indices | map(.+1))] | transpose[] | "\(.[0]) \(.[1])"' $RESPONSE) |\
    sed '/ / !s/$/ -1/' |\
    while read coor index; do
        if [ $index -gt -1 ]; then
            echo $coor $(sed -n "$index p" $ORIGIN_DATA | cut -d' ' -f1 | date -f - +%s)
        else
            echo $coor $index
        fi
    done |\
    awk '{COOR[NR][0]=$1; N++; COOR[NR][1]=$2} END{for (i=1; i<=N; i++) {printf COOR[i][0]; if (COOR[i][1] != -1) {print " "COOR[i][1]; LAST=i} else {while(COOR[i+n][1] == -1) n++; print " "COOR[LAST][1]+(COOR[i+n][1]-COOR[LAST][1])*(i-LAST)/(i+n-LAST)}}}' |\
    while read coor unix_time; do
        # Transform unix timestamp into human readable time format, like following:
        # Transform [121.018088,14.5516] 18.50
        # Into      [121.018088,14.5516] 1970-01-01T08:00:18.50Z
        echo $coor $(date -d @$unix_time +'%Y-%m-%dT%H:%M:%S.%2NZ')
    done | tee /dev/tty

    # Remove processed raw data
    sed -i "1,$LIMIT d" $ORIGIN_DATA
done #|\
# Make GPX format for output
sed -E 's/\[([^,]+),([^,]+)\] (.*)/      <trkpt lon="\1" lat="\2"><time>\3<\/time><\/trkpt>/' |\
sed "1i \
<gpx version=\"1.1\" creator=\"Garmin Connect\"\n\
  xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd http://www.garmin.com/xmlschemas/GpxExtensions/v3 http://www.garmin.com/xmlschemas/GpxExtensionsv3.xsd http://www.garmin.com/xmlschemas/TrackPointExtension/v1 http://www.garmin.com/xmlschemas/TrackPointExtensionv1.xsd\"\n\
  xmlns=\"http://www.topografix.com/GPX/1/1\"\n\
  xmlns:gpxtpx=\"http://www.garmin.com/xmlschemas/TrackPointExtension/v1\"\n\
  xmlns:gpxx=\"http://www.garmin.com/xmlschemas/GpxExtensions/v3\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\">\n\
  <trk>\n\
    <name>$(sed -nE 's/.*<name>(.*)<\/name>.*/\1/p; /<name>/q' $1)<\/name>\n\
    <trkseg>
\$a \
\ \ \ \ <\/trkseg>\n\
  <\/trk>\n\
<\/gpx>\n\
    "