├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── build
└── lib
│ └── mapmatcher
│ ├── __init__.py
│ └── mapmatcher.py
├── dist
└── mapmatcher-1.0.win32.exe
├── example.PNG
├── install.txt
├── mapMatch.PNG
├── mapMatch.mapMatch.pyt.xml
├── mapMatch.pyt
├── mapMatch.pyt.xml
├── mapmatcher
├── __init__.py
├── __init__.pyc
├── mapmatcher.py
└── mapmatcher.pyc
├── setup.py
├── testSegments.cpg
├── testSegments.dbf
├── testSegments.prj
├── testSegments.sbn
├── testSegments.sbx
├── testSegments.shp
├── testSegments.shp.xml
├── testSegments.shx
├── testTrack.cpg
├── testTrack.dbf
├── testTrack.prj
├── testTrack.sbn
├── testTrack.sbx
├── testTrack.shp
├── testTrack.shx
├── testTrack_pth.cpg
├── testTrack_pth.dbf
├── testTrack_pth.prj
├── testTrack_pth.sbn
├── testTrack_pth.sbx
├── testTrack_pth.shp
├── testTrack_pth.shp.xml
└── testTrack_pth.shx
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
4 | # Custom for Visual Studio
5 | *.cs diff=csharp
6 |
7 | # Standard to msysgit
8 | *.doc diff=astextplain
9 | *.DOC diff=astextplain
10 | *.docx diff=astextplain
11 | *.DOCX diff=astextplain
12 | *.dot diff=astextplain
13 | *.DOT diff=astextplain
14 | *.pdf diff=astextplain
15 | *.PDF diff=astextplain
16 | *.rtf diff=astextplain
17 | *.RTF diff=astextplain
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Windows image file caches
2 | Thumbs.db
3 | ehthumbs.db
4 |
5 | # Folder config file
6 | Desktop.ini
7 |
8 | # Recycle Bin used on file shares
9 | $RECYCLE.BIN/
10 |
11 | # Windows Installer files
12 | *.cab
13 | *.msi
14 | *.msm
15 | *.msp
16 |
17 | # Windows shortcuts
18 | *.lnk
19 |
20 | # =========================
21 | # Operating System Files
22 | # =========================
23 |
24 | # OSX
25 | # =========================
26 |
27 | .DS_Store
28 | .AppleDouble
29 | .LSOverride
30 |
31 | # Thumbnails
32 | ._*
33 |
34 | # Files that might appear in the root of a volume
35 | .DocumentRevisions-V100
36 | .fseventsd
37 | .Spotlight-V100
38 | .TemporaryItems
39 | .Trashes
40 | .VolumeIcon.icns
41 |
42 | # Directories potentially created on remote AFP share
43 | .AppleDB
44 | .AppleDesktop
45 | Network Trash Folder
46 | Temporary Items
47 | .apdisk
48 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 simonscheider
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Map Matcher
2 |
3 | This python script allows map matching (matching of tracking points to a network)
4 | in arcpy using a Hidden Markov model with
5 | probabilities parameterized based on spatial + network distances.
6 | Follows the ideas in Newson, Krumm (2009):
7 | "Hidden markov Map Matching through noise and sparseness"
8 |
9 | Author: Simon Scheider
10 |
11 | Created: 16/03/2017
12 |
13 |
14 | ## Installation
15 |
16 | To install as a toolbox in ArcGIS, see [mapMaptch.pyt](#mapmatchpyt-arcgis-python-toolbox)
17 |
18 | The code is written in Python 2.7 and depends on:
19 |
20 | * arcpy (ships with ArcGIS and its own Python 2.7)
21 | * [networkx](https://networkx.github.io)
22 |
23 | `python pip install networkx`
24 |
25 | * note: requires installing GDAL first, which can be obtained as a windows wheel from [here](http://www.lfd.uci.edu/~gohlke/pythonlibs/)
26 | and then installed with pip locally:
27 |
28 | `python pip install GDAL-2.1.3-cp27-cp27m-win32.whl`
29 |
30 | To install the mapmatcher Python module, simply download and execute this windows executable:
31 | - [mapmatching/dist/mapmatcher-1.0.win32.exe](https://github.com/simonscheider/mapmatching/blob/master/dist/mapmatcher-1.0.win32.exe).
32 |
33 | ## Usage
34 |
35 | Example:
36 |
37 | `from mapmatcher import mapmatcher`
38 |
39 | `arcpy.env.workspace = 'C:/Users/simon/Documents/GitHub/mapmatching'`
40 |
41 | `opt = mapmatcher.mapMatch('testTrack.shp', 'testSegments.shp')`
42 |
43 | `#outputs testTrack_pth.shp`
44 |
45 | `mapmatcher.exportPath(opt, 'testTrack.shp')`
46 |
47 | The last method saves a new shape file named _testTrack_pth.shp_ in the current arcpy workspace, containing a sequence of segments to which the track was mapped.
48 |
49 | Results are shown here:
50 |
51 |
52 |
53 |
54 | The main method is _mapMatch_. Based on the Viterbi algorithm for Hidden Markov models,
55 | see https://en.wikipedia.org/wiki/Viterbi_algorithm, it gets trackpoints and segments, and returns the most probable segment path (a list of segments) for the list of points.
56 |
57 | ### Method _mapMatch_:
58 | * @param **track** = a shape file (filename) with point geometries representing a track, can be unprojected (WGS84). The order of points in this file should reflect the temporal order.
59 |
60 | * @param **segments** = a shape file of network segments, should be _projected_ (in meter) to compute Euclidean distances properly (e.g. GCS Amersfoord). _Note_: To compute network distances, the script turns this network into a graph using [networkx](https://networkx.github.io), based on coincidence of segment end points. It is therefore important that logically connected segments are also geometrically connected (no geometrical errors). Other than this, the script does have other requirements for the network.
61 |
62 | * @param _decayconstantNet_ (optional) = the network distance (in meter) after which the match probability falls under 0.34 ([exponential decay](https://en.wikipedia.org/wiki/Exponential_decay)). Default is 30 meters. This distance parameter depends on the intervals between successing points in the track.
63 |
64 | * @param _decayConstantEu_ (optional) = the Euclidean distance (in meter) after which the match probability falls under 0.34 (exponential decay). Default is 10 meters. This distance parameter depends on the measurement accuracy of tracking points.
65 |
66 | * @param _maxDist_ (optional) = the Euclidean distance threshold (in meter) for taking into account segments candidates. Default is 50 meters. Depends also on measurement accuracy of track points.
67 |
68 | * result = delivers back a path (a list of segment ids).
69 |
70 | #### Note:
71 | Depending on the type of movement, optional parameters need to be fine tuned to get optimal results. For example, when tracking frequency is very slow, then track points are far apart, and then _decayconstantNet_ needs to be increased accordingly.
72 |
73 | ### Method _exportPath_ :
74 | Exports the path into a shape file named _segments_pth.shp_ inside the current ArcGIS workspace.
75 |
76 |
77 | # mapMatch.pyt (ArcGIS Python toolbox)
78 |
79 | To use the Python method as an ArcGIS toolbox, you need to do the following:
80 |
81 | 1. In your ArcGIS Python version (e.g. Folder `C:\Python27\ArcGIS10.3\Lib\site-packages`), install required modules for GDAL and networkx in a cmd window:
82 |
83 | - if you have not installed it yet, install pip (http://pip.readthedocs.io/en/latest/installing/).
84 | - Download a suitable GDAL wheel from [here](http://www.lfd.uci.edu/~gohlke/pythonlibs/). Then execute:
85 | - `python pip install GDAL-2.1.3-cp27-cp27m-win32.whl`
86 | - `python pip install networkx`
87 |
88 | 2. Install mapmatcher Python module by downloading and executing the windows executable [mapmatching/dist/mapmatcher-1.0.win32.exe](https://github.com/simonscheider/mapmatching/blob/master/dist/mapmatcher-1.0.win32.exe). Make sure you select exactly the Python installation that ships with your ArcGIS as a target folder.
89 |
90 | 3. Download the ArcGIS Python toolbox [mapMatch.pyt](https://github.com/simonscheider/mapmatching/blob/master/mapMatch.pyt), together with meta data files [mapMatch.mapMatch.pyt.xml](https://github.com/simonscheider/mapmatching/blob/master/mapMatch.mapMatch.pyt.xml) and [mapMatch.pyt.xml](https://github.com/simonscheider/mapmatching/blob/master/mapMatch.pyt.xml) and drop it anywhere on your computer.
91 |
92 | 4. Now you can open the toolbox by clicking on it inside an ArcGIS Catalog Window:
93 |
94 |
95 | The tool saves a new shape file named _NameofInputTrack_pth.shp_ inside the current ArcGIS workspace that contains the path of segments to which the track was mapped. When executing, make sure the network is as small as possible to speed up.
96 |
--------------------------------------------------------------------------------
/build/lib/mapmatcher/__init__.py:
--------------------------------------------------------------------------------
1 | import mapmatcher
2 |
--------------------------------------------------------------------------------
/build/lib/mapmatcher/mapmatcher.py:
--------------------------------------------------------------------------------
1 | """
2 | -------------------------------------------------------------------------------
3 | # Name: mapMatcher
4 | # Purpose: This python script allows map matching (matching of track points to a network)
5 | # in arcpy using a Hidden Markov model with
6 | # probabilities parameterized based on spatial + network distances.
7 | # Follows the ideas in Newson, Krumm (2009):
8 | # "Hidden markov Map Matching through noise and sparseness"
9 | #
10 | # Example usage under '__main__'
11 | #
12 | # Author: Simon Scheider
13 | #
14 | # Created: 01/03/2017
15 | # Copyright: (c) simon 2017
16 | # Licence:
17 |
18 | The code is written in Python 2.7 and depends on:
19 |
20 | * arcpy (ships with ArcGIS and its own Python 2.7)
21 | * networkx (# python pip install networkx (https://networkx.github.io))
22 | (note: requires installing GDAL first, which can be obtained as a wheel from
23 | http://www.lfd.uci.edu/~gohlke/pythonlibs/ and then installed with pip locally:
24 | python pip install GDAL-2.1.3-cp27-cp27m-win32.whl
25 | )
26 |
27 | #-------------------------------------------------------------------------------
28 | """
29 |
30 | __author__ = "Simon Scheider"
31 | __copyright__ = ""
32 |
33 |
34 | import sys
35 |
36 | try:
37 | from math import exp, sqrt
38 | import os
39 | import arcpy
40 | arcpy.env.overwriteOutput = True
41 | import networkx as nx
42 | import time
43 |
44 | except ImportError:
45 | print "Error: missing one of the libraries (arcpy, networkx)"
46 | sys.exit()
47 |
48 |
49 |
50 | def mapMatch(track, segments, decayconstantNet = 30, decayConstantEu = 10, maxDist = 50, addfullpath = True):
51 | """
52 | The main method. Based on the Viterbi algorithm for Hidden Markov models,
53 | see https://en.wikipedia.org/wiki/Viterbi_algorithm.
54 | It gets trackpoints and segments, and returns the most probable segment path (a list of segments) for the list of points.
55 | Inputs:
56 | @param track = a shape file (filename) representing a track, can also be unprojected (WGS84)
57 | @param segments = a shape file of network segments, should be projected (in meter) to compute Euclidean distances properly (e.g. GCS Amersfoord)
58 | @param decayconstantNet (optional) = the network distance (in meter) after which the match probability falls under 0.34 (exponential decay). (note this is the inverse of lambda).
59 | This depends on the point frequency of the track (how far are track points separated?)
60 | @param decayConstantEu (optional) = the Euclidean distance (in meter) after which the match probability falls under 0.34 (exponential decay). (note this is the inverse of lambda).
61 | This depends on the positional error of the track points (how far can points deviate from their true position?)
62 | @param maxDist (optional) = the Euclidean distance threshold (in meter) for taking into account segments candidates.
63 | @param addfullpath (optional, True or False) = whether a contiguous full segment path should be outputted. If not, a 1-to-1 list of segments matching each track point is outputted.
64 |
65 | note: depending on the type of movement, optional parameters need to be fine tuned to get optimal results.
66 | """
67 | #Make sure passed in parameters are floats
68 | decayconstantNet = float(decayconstantNet)
69 | decayConstantEu = float(decayConstantEu)
70 | maxDist= float(maxDist)
71 |
72 | #gest start time
73 | start_time = time.time()
74 |
75 | #this array stores, for each point in a track, probability distributions over segments, together with the (most probable) predecessor segment taking into account a network distance
76 | V = [{}]
77 |
78 | #get track points, build network graph (graph, endpoints, lengths) and get segment info from arcpy
79 | points = getTrackPoints(track, segments)
80 | r = getSegmentInfo(segments)
81 | endpoints = r[0]
82 | lengths = r[1]
83 | graph = getNetworkGraph(segments,lengths)
84 | pathnodes = [] #set of pathnodes to prevent loops
85 |
86 | #init first point
87 | sc = getSegmentCandidates(points[0], segments, decayConstantEu, maxDist)
88 | for s in sc:
89 | V[0][s] = {"prob": sc[s], "prev": None, "path": [], "pathnodes":[]}
90 | # Run Viterbi when t > 0
91 | for t in range(1, len(points)):
92 | V.append({})
93 | #Store previous segment candidates
94 | lastsc = sc
95 | #Get segment candidates and their a-priori probabilities (based on Euclidean distance for current point t)
96 | sc = getSegmentCandidates(points[t], segments, decayConstantEu, maxDist)
97 | for s in sc:
98 | max_tr_prob = 0
99 | prev_ss = None
100 | path = []
101 | for prev_s in lastsc:
102 | #determine the highest network transition probability from previous candidates to s and get the corresponding network path
103 | pathnodes = V[t-1][prev_s]["pathnodes"][-10:]
104 | n = getNetworkTransP(prev_s, s, graph, endpoints, lengths, pathnodes, decayconstantNet)
105 | np = n[0] #This is the network transition probability
106 | tr_prob = V[t-1][prev_s]["prob"]*np
107 | #this selects the most probable predecessor candidate and the path to it
108 | if tr_prob > max_tr_prob:
109 | max_tr_prob = tr_prob
110 | prev_ss = prev_s
111 | path = n[1]
112 | if n[2] != None:
113 | pathnodes.append(n[2])
114 | #The final probability of a candidate is the product of a-priori and network transitional probability
115 | max_prob = sc[s] * max_tr_prob
116 | V[t][s] = {"prob": max_prob, "prev": prev_ss, "path": path, "pathnodes":pathnodes}
117 |
118 | #Now max standardize all p-values to prevent running out of digits
119 | maxv = max(value["prob"] for value in V[t].values())
120 | maxv = (1 if maxv == 0 else maxv)
121 | for s in V[t].keys():
122 | V[t][s]["prob"]=V[t][s]["prob"]/maxv
123 |
124 |
125 | intertime1 = time.time()
126 | print("--- Viterbi forward: %s seconds ---" % (intertime1 - start_time))
127 | #print V
128 |
129 | #opt is the result: a list of (matched) segments [s1, s2, s3,...] in the exact order of the point track: [p1, p2, p3,...]
130 | opt = []
131 |
132 | # get the highest probability at the end of the track
133 | max_prob = max(value["prob"] for value in V[-1].values())
134 | previous = None
135 | if max_prob == 0:
136 | print " probabilities fall to zero (network distances in data are too large, try increasing network decay parameter)"
137 |
138 | # Get most probable ending state and its backtrack
139 | for st, data in V[-1].items():
140 | if data["prob"] == max_prob:
141 | opt.append(st)
142 | previous = st
143 | break
144 | ## print " previous: "+str(previous)
145 | ## print " max_prob: "+str(max_prob)
146 | ## print " V -1: "+str(V[-1].items())
147 |
148 | # Follow the backtrack till the first observation to fish out most probable states and corresponding paths
149 | for t in range(len(V) - 2, -1, -1):
150 | #Get the subpath between last and most probable previous segment and add it to the resulting path
151 | path = V[t + 1][previous]["path"]
152 | opt[0:0] =(path if path !=None else [])
153 | #Insert the previous segment
154 | opt.insert(0, V[t + 1][previous]["prev"])
155 | previous = V[t + 1][previous]["prev"]
156 | intertime2 = time.time()
157 | print("--- Viterbi backtracking: %s seconds ---" % (intertime2 - intertime1))
158 |
159 | #Clean the path (remove double segments and crossings) (only in full path option)
160 | print "path length before cleaning :" +str(len(opt))
161 | opt = cleanPath(opt, endpoints)
162 | intertime3 = time.time()
163 | print("--- Path cleaning: %s seconds ---" % (intertime3 - intertime2))
164 | print "final length: "+str(len(opt))
165 | pointstr= [str(g.firstPoint.X)+' '+str(g.firstPoint.Y) for g in points]
166 | optstr= [str(i) for i in opt]
167 | print 'The path for points ['+' '.join(pointstr)+'] is: '
168 | print '[' + ' '.join(optstr) + '] with highest probability of %s' % max_prob
169 |
170 | #If only a single segment candidate should be returned for each point:
171 | if addfullpath == False:
172 | opt = getpointMatches(points,opt)
173 | optstr= [str(i) for i in opt]
174 | print "Individual point matches: "+'[' + ' '.join(optstr) + ']'
175 | intertime4 = time.time()
176 | print("--- Picking point matches: %s seconds ---" % (intertime4 - intertime3))
177 |
178 | return opt
179 |
180 | #Fishes out a 1-to-1 list of path segments nearest to the list of points in the track (not contiguous, may contain repeated segments)
181 | def getpointMatches(points, path):
182 | qr = '"OBJECTID" IN ' +str(tuple(path))
183 | arcpy.SelectLayerByAttribute_management('segments_lyr',"NEW_SELECTION", qr)
184 | opta = []
185 | for point in points:
186 | sdist = 100000
187 | candidate = ''
188 | cursor = arcpy.da.SearchCursor('segments_lyr', ["OBJECTID", "SHAPE@"])
189 | for row in cursor:
190 | #compute the spatial distance
191 | dist = point.distanceTo(row[1])
192 | if dist
2 | 20170221130747001.0TRUE201703161906311500000005000ItemDescriptionc:\program files (x86)\arcgis\desktop10.3\Help\gpmapMatchA map matching tool based on a Hidden Markov ModelThis tool allows map matching (matching of track points to a network) in arcpy using a Hidden Markov model with probabilities parameterized based on spatial + network distances.
3 | It outputs a file "NameofInputTrack_pth.shp" inside the current workspace, which contains a path of network segments to which the track was mapped.Follows the ideas in Newson, Krumm (2009): "Hidden markov Map Matching through noise and sparseness"
4 | ArcToolbox Toolbox
5 |
--------------------------------------------------------------------------------
/mapmatcher/__init__.py:
--------------------------------------------------------------------------------
1 | import mapmatcher
2 |
--------------------------------------------------------------------------------
/mapmatcher/__init__.pyc:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonscheider/mapmatching/4ff01eadea5f0618a972cc5693866a870ab62d4d/mapmatcher/__init__.pyc
--------------------------------------------------------------------------------
/mapmatcher/mapmatcher.py:
--------------------------------------------------------------------------------
1 | """
2 | -------------------------------------------------------------------------------
3 | # Name: mapMatcher
4 | # Purpose: This python script allows map matching (matching of track points to a network)
5 | # in arcpy using a Hidden Markov model with
6 | # probabilities parameterized based on spatial + network distances.
7 | # Follows the ideas in Newson, Krumm (2009):
8 | # "Hidden markov Map Matching through noise and sparseness"
9 | #
10 | # Example usage under '__main__'
11 | #
12 | # Author: Simon Scheider
13 | #
14 | # Created: 01/03/2017
15 | # Copyright: (c) simon 2017
16 | # Licence:
17 |
18 | The code is written in Python 2.7 and depends on:
19 |
20 | * arcpy (ships with ArcGIS and its own Python 2.7)
21 | * networkx (# python pip install networkx (https://networkx.github.io))
22 | (note: requires installing GDAL first, which can be obtained as a wheel from
23 | http://www.lfd.uci.edu/~gohlke/pythonlibs/ and then installed with pip locally:
24 | python pip install GDAL-2.1.3-cp27-cp27m-win32.whl
25 | )
26 |
27 | #-------------------------------------------------------------------------------
28 | """
29 |
30 | __author__ = "Simon Scheider"
31 | __copyright__ = ""
32 |
33 |
34 | import sys
35 |
36 | try:
37 | from math import exp, sqrt
38 | import os
39 | import arcpy
40 | arcpy.env.overwriteOutput = True
41 | import networkx as nx
42 | import time
43 |
44 | except ImportError:
45 | print "Error: missing one of the libraries (arcpy, networkx)"
46 | sys.exit()
47 |
48 |
49 |
50 | def mapMatch(track, segments, decayconstantNet = 30, decayConstantEu = 10, maxDist = 50, addfullpath = True):
51 | """
52 | The main method. Based on the Viterbi algorithm for Hidden Markov models,
53 | see https://en.wikipedia.org/wiki/Viterbi_algorithm.
54 | It gets trackpoints and segments, and returns the most probable segment path (a list of segments) for the list of points.
55 | Inputs:
56 | @param track = a shape file (filename) representing a track, can also be unprojected (WGS84)
57 | @param segments = a shape file of network segments, should be projected (in meter) to compute Euclidean distances properly (e.g. GCS Amersfoord)
58 | @param decayconstantNet (optional) = the network distance (in meter) after which the match probability falls under 0.34 (exponential decay). (note this is the inverse of lambda).
59 | This depends on the point frequency of the track (how far are track points separated?)
60 | @param decayConstantEu (optional) = the Euclidean distance (in meter) after which the match probability falls under 0.34 (exponential decay). (note this is the inverse of lambda).
61 | This depends on the positional error of the track points (how far can points deviate from their true position?)
62 | @param maxDist (optional) = the Euclidean distance threshold (in meter) for taking into account segments candidates.
63 | @param addfullpath (optional, True or False) = whether a contiguous full segment path should be outputted. If not, a 1-to-1 list of segments matching each track point is outputted.
64 |
65 | note: depending on the type of movement, optional parameters need to be fine tuned to get optimal results.
66 | """
67 | #Make sure passed in parameters are floats
68 | decayconstantNet = float(decayconstantNet)
69 | decayConstantEu = float(decayConstantEu)
70 | maxDist= float(maxDist)
71 |
72 | #gest start time
73 | start_time = time.time()
74 |
75 | #this array stores, for each point in a track, probability distributions over segments, together with the (most probable) predecessor segment taking into account a network distance
76 | V = [{}]
77 |
78 | #get track points, build network graph (graph, endpoints, lengths) and get segment info from arcpy
79 | points = getTrackPoints(track, segments)
80 | r = getSegmentInfo(segments)
81 | endpoints = r[0]
82 | lengths = r[1]
83 | graph = getNetworkGraph(segments,lengths)
84 | pathnodes = [] #set of pathnodes to prevent loops
85 |
86 | #init first point
87 | sc = getSegmentCandidates(points[0], segments, decayConstantEu, maxDist)
88 | for s in sc:
89 | V[0][s] = {"prob": sc[s], "prev": None, "path": [], "pathnodes":[]}
90 | # Run Viterbi when t > 0
91 | for t in range(1, len(points)):
92 | V.append({})
93 | #Store previous segment candidates
94 | lastsc = sc
95 | #Get segment candidates and their a-priori probabilities (based on Euclidean distance for current point t)
96 | sc = getSegmentCandidates(points[t], segments, decayConstantEu, maxDist)
97 | for s in sc:
98 | max_tr_prob = 0
99 | prev_ss = None
100 | path = []
101 | for prev_s in lastsc:
102 | #determine the highest network transition probability from previous candidates to s and get the corresponding network path
103 | pathnodes = V[t-1][prev_s]["pathnodes"][-10:]
104 | n = getNetworkTransP(prev_s, s, graph, endpoints, lengths, pathnodes, decayconstantNet)
105 | np = n[0] #This is the network transition probability
106 | tr_prob = V[t-1][prev_s]["prob"]*np
107 | #this selects the most probable predecessor candidate and the path to it
108 | if tr_prob > max_tr_prob:
109 | max_tr_prob = tr_prob
110 | prev_ss = prev_s
111 | path = n[1]
112 | if n[2] != None:
113 | pathnodes.append(n[2])
114 | #The final probability of a candidate is the product of a-priori and network transitional probability
115 | max_prob = sc[s] * max_tr_prob
116 | V[t][s] = {"prob": max_prob, "prev": prev_ss, "path": path, "pathnodes":pathnodes}
117 |
118 | #Now max standardize all p-values to prevent running out of digits
119 | maxv = max(value["prob"] for value in V[t].values())
120 | maxv = (1 if maxv == 0 else maxv)
121 | for s in V[t].keys():
122 | V[t][s]["prob"]=V[t][s]["prob"]/maxv
123 |
124 |
125 | intertime1 = time.time()
126 | print("--- Viterbi forward: %s seconds ---" % (intertime1 - start_time))
127 | #print V
128 |
129 | #opt is the result: a list of (matched) segments [s1, s2, s3,...] in the exact order of the point track: [p1, p2, p3,...]
130 | opt = []
131 |
132 | # get the highest probability at the end of the track
133 | max_prob = max(value["prob"] for value in V[-1].values())
134 | previous = None
135 | if max_prob == 0:
136 | print " probabilities fall to zero (network distances in data are too large, try increasing network decay parameter)"
137 |
138 | # Get most probable ending state and its backtrack
139 | for st, data in V[-1].items():
140 | if data["prob"] == max_prob:
141 | opt.append(st)
142 | previous = st
143 | break
144 | ## print " previous: "+str(previous)
145 | ## print " max_prob: "+str(max_prob)
146 | ## print " V -1: "+str(V[-1].items())
147 |
148 | # Follow the backtrack till the first observation to fish out most probable states and corresponding paths
149 | for t in range(len(V) - 2, -1, -1):
150 | #Get the subpath between last and most probable previous segment and add it to the resulting path
151 | path = V[t + 1][previous]["path"]
152 | opt[0:0] =(path if path !=None else [])
153 | #Insert the previous segment
154 | opt.insert(0, V[t + 1][previous]["prev"])
155 | previous = V[t + 1][previous]["prev"]
156 | intertime2 = time.time()
157 | print("--- Viterbi backtracking: %s seconds ---" % (intertime2 - intertime1))
158 |
159 | #Clean the path (remove double segments and crossings) (only in full path option)
160 | print "path length before cleaning :" +str(len(opt))
161 | opt = cleanPath(opt, endpoints)
162 | intertime3 = time.time()
163 | print("--- Path cleaning: %s seconds ---" % (intertime3 - intertime2))
164 | print "final length: "+str(len(opt))
165 | pointstr= [str(g.firstPoint.X)+' '+str(g.firstPoint.Y) for g in points]
166 | optstr= [str(i) for i in opt]
167 | print 'The path for points ['+' '.join(pointstr)+'] is: '
168 | print '[' + ' '.join(optstr) + '] with highest probability of %s' % max_prob
169 |
170 | #If only a single segment candidate should be returned for each point:
171 | if addfullpath == False:
172 | opt = getpointMatches(points,opt)
173 | optstr= [str(i) for i in opt]
174 | print "Individual point matches: "+'[' + ' '.join(optstr) + ']'
175 | intertime4 = time.time()
176 | print("--- Picking point matches: %s seconds ---" % (intertime4 - intertime3))
177 |
178 | return opt
179 |
180 | #Fishes out a 1-to-1 list of path segments nearest to the list of points in the track (not contiguous, may contain repeated segments)
181 | def getpointMatches(points, path):
182 | qr = '"OBJECTID" IN ' +str(tuple(path))
183 | arcpy.SelectLayerByAttribute_management('segments_lyr',"NEW_SELECTION", qr)
184 | opta = []
185 | for point in points:
186 | sdist = 100000
187 | candidate = ''
188 | cursor = arcpy.da.SearchCursor('segments_lyr', ["OBJECTID", "SHAPE@"])
189 | for row in cursor:
190 | #compute the spatial distance
191 | dist = point.distanceTo(row[1])
192 | if dist
2 | 20170207134751001.0FALSENLstreets002file://\\ad.geo.uu.nl\dfs\Plaza\mze\STreets2013.gdbLocal Area Network1561.077893290167.870354292906.746645612814.1809231ProjectedGCS_AmersfoortLinear Unit: Meter (1.000000)<ProjectedCoordinateSystem xsi:type='typens:ProjectedCoordinateSystem' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xs='http://www.w3.org/2001/XMLSchema' xmlns:typens='http://www.esri.com/schemas/ArcGIS/10.3'><WKT>PROJCS["RD_New",GEOGCS["GCS_Amersfoort",DATUM["D_Amersfoort",SPHEROID["Bessel_1841",6377397.155,299.1528128]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Double_Stereographic"],PARAMETER["False_Easting",155000.0],PARAMETER["False_Northing",463000.0],PARAMETER["Central_Meridian",5.38763888888889],PARAMETER["Scale_Factor",0.9999079],PARAMETER["Latitude_Of_Origin",52.15616055555555],UNIT["Meter",1.0],AUTHORITY["EPSG",28992]]</WKT><XOrigin>-30515500</XOrigin><YOrigin>-30279500</YOrigin><XYScale>146716411.36275291</XYScale><ZOrigin>-100000</ZOrigin><ZScale>10000</ZScale><MOrigin>-100000</MOrigin><MScale>10000</MScale><XYTolerance>0.001</XYTolerance><ZTolerance>0.001</ZTolerance><MTolerance>0.001</MTolerance><HighPrecision>true</HighPrecision><WKID>28992</WKID><LatestWKID>28992</LatestWKID></ProjectedCoordinateSystem>RD_New201507060906340020150706090847001500000005000ItemDescriptionMicrosoft Windows 7 Version 6.1 (Build 7601) Service Pack 1; Esri ArcGIS 10.3.0.4322NLstreets13.0759777.42421553.50262250.606694Netherlands and surroundings with limited attribute table: Subset ESRI streetmap 2013 (Tde Jong)streets NetherlandsFile Geodatabase Feature ClassdatasetEPSG8.2.62072326SimpleFALSE2072326TRUEFALSENLstreetsFeature Class2072326OBJECTIDOBJECTIDOID400Internal feature number.EsriSequential unique whole numbers that are automatically generated.ShapeShapeGeometry000Feature geometry.EsriCoordinates defining the features.FOWFOWInteger400FREEWAYFREEWAYInteger400BACKRDBACKRDInteger400RDCONDRDCONDInteger400PRIVATERDPRIVATERDInteger400ONEWAYONEWAYString200KPHKPHInteger400COUNTRYCOUNTRYString4000ROAD_CLROAD_CLInteger400FULLNAMEFULLNAMEString10000RESTR_01RESTR_01String100RESTR_02RESTR_02String100RESTR_04RESTR_04String100RESTR_05RESTR_05String100RESTR_06RESTR_06String100RESTR_07RESTR_07String100RESTR_09RESTR_09String100RESTR_10RESTR_10String100NET_LEVELNET_LEVELInteger400Shape_LengthShape_LengthDouble800Length of feature in internal units.EsriPositive real numbers that are automatically generated.20150706/9j/4AAQSkZJRgABAQEAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0a
3 | HBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIy
4 | MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCACFAMgDASIA
5 | AhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA
6 | AAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3
7 | ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm
8 | p6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA
9 | AwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx
10 | BhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK
11 | U1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3
12 | uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3+iii
13 | gAooooAKKKKACiiigAooooAKKKqajqdlpNt9ovrhIY8hQTklj6ADkn2FNJt2QFuiuUkk17xHdo+m
14 | 30miWEHyzJNaq88zMqtjBP7vAIx3yTx0pfFN14cs7WC38V6gHilbfHAyn5nXuojG7jOOp6962VB8
15 | yje7fRav+vmK50ouYDP5AmjM2CfL3jdgdTjr3qsusWL6y+kpK7XscYldFichFOcEtjaM4PBOa+f9
16 | Z+Jtvp7yxeDrJrXTXkeRjJ83mkn5nCHgDPZ92cjhQMF+n/Eu+j0C7uDq0dv4hViqxJbKkJiwCGIH
17 | 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
95 | AooooAKKKKACiiigAooooA//2Q==
96 |
--------------------------------------------------------------------------------
/testSegments.shx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonscheider/mapmatching/4ff01eadea5f0618a972cc5693866a870ab62d4d/testSegments.shx
--------------------------------------------------------------------------------
/testTrack.cpg:
--------------------------------------------------------------------------------
1 | UTF-8
--------------------------------------------------------------------------------
/testTrack.dbf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonscheider/mapmatching/4ff01eadea5f0618a972cc5693866a870ab62d4d/testTrack.dbf
--------------------------------------------------------------------------------
/testTrack.prj:
--------------------------------------------------------------------------------
1 | PROJCS["RD_New",GEOGCS["GCS_Amersfoort",DATUM["D_Amersfoort",SPHEROID["Bessel_1841",6377397.155,299.1528128]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Double_Stereographic"],PARAMETER["False_Easting",155000.0],PARAMETER["False_Northing",463000.0],PARAMETER["Central_Meridian",5.38763888888889],PARAMETER["Scale_Factor",0.9999079],PARAMETER["Latitude_Of_Origin",52.15616055555555],UNIT["Meter",1.0]]
--------------------------------------------------------------------------------
/testTrack.sbn:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonscheider/mapmatching/4ff01eadea5f0618a972cc5693866a870ab62d4d/testTrack.sbn
--------------------------------------------------------------------------------
/testTrack.sbx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonscheider/mapmatching/4ff01eadea5f0618a972cc5693866a870ab62d4d/testTrack.sbx
--------------------------------------------------------------------------------
/testTrack.shp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonscheider/mapmatching/4ff01eadea5f0618a972cc5693866a870ab62d4d/testTrack.shp
--------------------------------------------------------------------------------
/testTrack.shx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonscheider/mapmatching/4ff01eadea5f0618a972cc5693866a870ab62d4d/testTrack.shx
--------------------------------------------------------------------------------
/testTrack_pth.cpg:
--------------------------------------------------------------------------------
1 | UTF-8
--------------------------------------------------------------------------------
/testTrack_pth.dbf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonscheider/mapmatching/4ff01eadea5f0618a972cc5693866a870ab62d4d/testTrack_pth.dbf
--------------------------------------------------------------------------------
/testTrack_pth.prj:
--------------------------------------------------------------------------------
1 | PROJCS["RD_New",GEOGCS["GCS_Amersfoort",DATUM["D_Amersfoort",SPHEROID["Bessel_1841",6377397.155,299.1528128]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Double_Stereographic"],PARAMETER["False_Easting",155000.0],PARAMETER["False_Northing",463000.0],PARAMETER["Central_Meridian",5.38763888888889],PARAMETER["Scale_Factor",0.9999079],PARAMETER["Latitude_Of_Origin",52.15616055555555],UNIT["Meter",1.0]]
--------------------------------------------------------------------------------
/testTrack_pth.sbn:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonscheider/mapmatching/4ff01eadea5f0618a972cc5693866a870ab62d4d/testTrack_pth.sbn
--------------------------------------------------------------------------------
/testTrack_pth.sbx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonscheider/mapmatching/4ff01eadea5f0618a972cc5693866a870ab62d4d/testTrack_pth.sbx
--------------------------------------------------------------------------------
/testTrack_pth.shp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonscheider/mapmatching/4ff01eadea5f0618a972cc5693866a870ab62d4d/testTrack_pth.shp
--------------------------------------------------------------------------------
/testTrack_pth.shp.xml:
--------------------------------------------------------------------------------
1 |
2 | 20170207134751001.0FALSEtestTrack_pth002file://\\UU062133\C$\Users\schei008\Documents\Github\mapmatching\testTrack_pth.shpLocal Area Network1561.077893290167.870354292906.746645612814.18092310.000ProjectedGCS_AmersfoortLinear Unit: Meter (1.000000)<ProjectedCoordinateSystem xsi:type='typens:ProjectedCoordinateSystem' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xs='http://www.w3.org/2001/XMLSchema' xmlns:typens='http://www.esri.com/schemas/ArcGIS/10.3'><WKT>PROJCS["RD_New",GEOGCS["GCS_Amersfoort",DATUM["D_Amersfoort",SPHEROID["Bessel_1841",6377397.155,299.1528128]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Double_Stereographic"],PARAMETER["False_Easting",155000.0],PARAMETER["False_Northing",463000.0],PARAMETER["Central_Meridian",5.38763888888889],PARAMETER["Scale_Factor",0.9999079],PARAMETER["Latitude_Of_Origin",52.15616055555555],UNIT["Meter",1.0],AUTHORITY["EPSG",28992]]</WKT><XOrigin>-30515500</XOrigin><YOrigin>-30279500</YOrigin><XYScale>146716411.36275291</XYScale><ZOrigin>-100000</ZOrigin><ZScale>10000</ZScale><MOrigin>-100000</MOrigin><MScale>10000</MScale><XYTolerance>0.001</XYTolerance><ZTolerance>0.001</ZTolerance><MTolerance>0.001</MTolerance><HighPrecision>true</HighPrecision><WKID>28992</WKID><LatestWKID>28992</LatestWKID></ProjectedCoordinateSystem>RD_NewFeatureClassToFeatureClass segments_lyr C:\Users\schei008\Documents\Github\mapmatching testTrack_pth # "OBJECTID "OBJECTID" true true false 10 Long 0 10 ,First,#,segments_lyr,OBJECTID,-1,-1;FOW "FOW" true true false 10 Long 0 10 ,First,#,segments_lyr,FOW,-1,-1;FREEWAY "FREEWAY" true true false 10 Long 0 10 ,First,#,segments_lyr,FREEWAY,-1,-1;BACKRD "BACKRD" true true false 10 Long 0 10 ,First,#,segments_lyr,BACKRD,-1,-1;RDCOND "RDCOND" true true false 10 Long 0 10 ,First,#,segments_lyr,RDCOND,-1,-1;PRIVATERD "PRIVATERD" true true false 10 Long 0 10 ,First,#,segments_lyr,PRIVATERD,-1,-1;ONEWAY "ONEWAY" true true false 2 Text 0 0 ,First,#,segments_lyr,ONEWAY,-1,-1;KPH "KPH" true true false 10 Long 0 10 ,First,#,segments_lyr,KPH,-1,-1;COUNTRY "COUNTRY" true true false 40 Text 0 0 ,First,#,segments_lyr,COUNTRY,-1,-1;ROAD_CL "ROAD_CL" true true false 10 Long 0 10 ,First,#,segments_lyr,ROAD_CL,-1,-1;FULLNAME "FULLNAME" true true false 100 Text 0 0 ,First,#,segments_lyr,FULLNAME,-1,-1;RESTR_01 "RESTR_01" true true false 1 Text 0 0 ,First,#,segments_lyr,RESTR_01,-1,-1;RESTR_02 "RESTR_02" true true false 1 Text 0 0 ,First,#,segments_lyr,RESTR_02,-1,-1;RESTR_04 "RESTR_04" true true false 1 Text 0 0 ,First,#,segments_lyr,RESTR_04,-1,-1;RESTR_05 "RESTR_05" true true false 1 Text 0 0 ,First,#,segments_lyr,RESTR_05,-1,-1;RESTR_06 "RESTR_06" true true false 1 Text 0 0 ,First,#,segments_lyr,RESTR_06,-1,-1;RESTR_07 "RESTR_07" true true false 1 Text 0 0 ,First,#,segments_lyr,RESTR_07,-1,-1;RESTR_09 "RESTR_09" true true false 1 Text 0 0 ,First,#,segments_lyr,RESTR_09,-1,-1;RESTR_10 "RESTR_10" true true false 1 Text 0 0 ,First,#,segments_lyr,RESTR_10,-1,-1;NET_LEVEL "NET_LEVEL" true true false 10 Long 0 10 ,First,#,segments_lyr,NET_LEVEL,-1,-1;Shape_Leng "Shape_Leng" true true false 19 Double 0 0 ,First,#,segments_lyr,Shape_Leng,-1,-1" #201802201508410020180220150841001500000005000ItemDescriptionMicrosoft Windows 7 Version 6.1 (Build 7601) Service Pack 1; Esri ArcGIS 10.3.1.4959testTrack_pth13.0759777.42421553.50262250.606694Netherlands and surroundings with limited attribute table: Subset ESRI streetmap 2013 (Tde Jong)streets NetherlandsShapefile0.000datasetEPSG8.6.20SimpleFALSE0FALSEFALSEtestTrack_pthFeature Class0FIDFIDOID400Internal feature number.EsriSequential unique whole numbers that are automatically generated.OBJECTIDOBJECTIDInteger10100Internal feature number.EsriSequential unique whole numbers that are automatically generated.ShapeShapeGeometry000Feature geometry.EsriCoordinates defining the features.FOWFOWInteger10100FREEWAYFREEWAYInteger10100BACKRDBACKRDInteger10100RDCONDRDCONDInteger10100PRIVATERDPRIVATERDInteger10100ONEWAYONEWAYString200KPHKPHInteger10100COUNTRYCOUNTRYString4000ROAD_CLROAD_CLInteger10100FULLNAMEFULLNAMEString10000RESTR_01RESTR_01String100RESTR_02RESTR_02String100RESTR_04RESTR_04String100RESTR_05RESTR_05String100RESTR_06RESTR_06String100RESTR_07RESTR_07String100RESTR_09RESTR_09String100RESTR_10RESTR_10String100NET_LEVELNET_LEVELInteger10100Shape_LengShape_LengDouble190020180220/9j/4AAQSkZJRgABAQEAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRofHh0a
3 | HBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/2wBDAQkJCQwLDBgNDRgyIRwhMjIyMjIy
4 | MjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjL/wAARCACFAMgDASIA
5 | AhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA
6 | AAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3
7 | ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm
8 | p6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA
9 | AwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx
10 | BhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK
11 | U1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3
12 | uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD3+iii
13 | gAooooAKKKKACiiigAooooAKKKqajqdlpNt9ovrhIY8hQTklj6ADkn2FNJt2QFuiuUkk17xHdo+m
14 | 30miWEHyzJNaq88zMqtjBP7vAIx3yTx0pfFN14cs7WC38V6gHilbfHAyn5nXuojG7jOOp6962VB8
15 | yje7fRav+vmK50ouYDP5AmjM2CfL3jdgdTjr3qsusWL6y+kpK7XscYldFichFOcEtjaM4PBOa+f9
16 | Z+Jtvp7yxeDrJrXTXkeRjJ83mkn5nCHgDPZ92cjhQMF+n/Eu+j0C7uDq0dv4hViqxJbKkJiwCGIH
17 | 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
95 | AooooAKKKKACiiigAooooA//2Q==
96 |
--------------------------------------------------------------------------------
/testTrack_pth.shx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/simonscheider/mapmatching/4ff01eadea5f0618a972cc5693866a870ab62d4d/testTrack_pth.shx
--------------------------------------------------------------------------------