Skip to content

Releases: addy90/map-matching-2

v1.2.1

Choose a tag to compare

@addy90 addy90 released this 28 Sep 11:00

This is mainly a dependency update release with a few bug- and compatibility fixes, and I can present to you my PhD thesis that covers more details, benchmarks, and information on my method and implementation:

Wöltche, Adrian (2026): Map matching methods for assigning vehicle positions to road networks, Bamberg: University of Bamberg Press, doi: 10.20378/irb-116612. (The PDF is free to download and read.)

The following changes have been made:

  • The README has been updated with references to my PhD thesis (as linked above), which includes way more details and information than the older article about the methods, implementation, and comparison benchmarks. In this manner, obsolete and redundant information, that is also present in my PhD thesis, has been reduced, to improve the readability of the README.
  • A new custom CMake dependency management (Managed_FetchContent) has been introduced, which facilitates updating dependencies without manually removing already existing cmake-build-* directories.
  • Additionally, CMake dependency has been updated to 4.3 minimum.
  • The dependencies have been updated: Boost to 1.91.0, csv-parser to v5.4.0, date to 3.0.5, expat to 2.8.5, protozero to 1.8.2, rpmalloc to 2.0.1. Boost could not yet be updated to 1.92.0 due to an upstream bug, which will be fixed in Boost 1.93.0: boostorg/geometry#1492
  • The build chain now uses Ubuntu 22.04 instead of 20.04 due to the dependencies no longer building on the older Ubuntu version. As such, the minimum requirement now is Ubuntu 22.04 LTS and Debian 12 due to glibc dependency.
  • Some build compatibility fixes have been incorporated from PR #11. Thanks to @controversial for the discussion and the ideas. However, we currently cannot support building on macOS due to lack of a development station. Furthermore, there were issues with rpmalloc. Maybe these are fixed now with the dependency update of rpmalloc, but we cannot verify this and thus cannot officially support macOS, except concerning the published Docker image.
  • We fixed an issue with the "is_result" column from the candidates-columns setting not being present or being present twice in combination with the candidates-export-all setting.
  • We made some smaller fixes in the README for manual Windows building and enabled CMake ctest.

Full Changelog: v1.2.0...v1.2.1

v1.2.0

Choose a tag to compare

@addy90 addy90 released this 02 Apr 11:03

This is a new feature release with the following new options and build updates:

  • We updated the libraries Boost to 1.90.0, csv-parser to 2.5.2, expat to 2.7.5, libosmium to 2.23.1, and zlib to 1.3.2
  • We updated the CMake build system to 4.2 due to changes in the zlib upstream package
  • We went back from the completely static build to a build that depends on glibc again, because of crashes. We know it was never recommended to do so. However, since we still build on Ubuntu 20.04 LTS and glibc is upwards-compatible, it should work on any recent system. If not, please let us know.
  • We reworked the error calculation when a skip is considered within a match, to prevent it further as to a last resort when nothing else works. The error is now higher and no longer dependent of the position of the track point in the track. It should reduce introduced gaps compared to before.
  • We made the importing of numbers more robust and more platform independent. The newson-krumm data set did not import correctly on Windows before, which is now fixed thanks to this change.
  • We reworked the export-edges mode. Previously, the export-edges setting overwrote the match column in the output with a re-extracted match based on the complete road network edges. This still is possible, but now, the edges column can be added to the output columns instead, to export both results simultaneously.
  • We reworked the candidates export setting. Previously, all candidates were exported, which polluted the file. Now only the candidates that are part of the resulting match are exported. The new candidates-export-all setting allows for the old behavior but has to be opted in now when all candidates are of interest. Also, the from and to columns are now off by default, but can still be enabled, as well as the is_result column that is only automatically enabled when candidates-export-all is on.
  • We have a new time-interpolation for the match times that interpolates the timings based on the prepared track (the track that is actually matched after trajectory-simplification has been applied). By default, the times are interpolated based on geometric distances, but the interpolation can also be set to points for interpolating based on the number of points, or none for no interpolation. The interpolated times are only outputted when the new match_times column is specified and for every point in the match WKT line, a corresponding time is given in the list. This works similar to the track_times and prepared_times. The trajectory-simplification can also be disabled so that the original track times are used for interpolating the match times, which improves time accuracy but reduces matching accuracy at the same time.
  • We have a new concatenate-skips setting that concatenates partial matches (i.e., MultiLineString WKT lines) and makes them into LineString WKT lines again, when it is possible, i.e., when there exist routes between the partial matches. This setting also sets a new export-routing-max-distance-factor-override to disabled so that eventually, the partial matches can be connected, even when they have a very large distance. By default, the concatenate-skips setting is disabled and the export-routing-max-distance-factor-override is set to the same value as routing-max-distance-factor, which is used during optimization to limit routing distance. Be warned that this almost always makes the match less accurate, because there is generally a reason why a gap exists in the match. But if you need a complete line without gaps, this setting is for you. However, it also depends on the next point:
  • We have a new remove-oneway-dead-end setting on preparing road network graphs for removing parts of the road network that can only be routed into but not out of it, for example, oneways that lead somewhere but no returning edges exist. This can happen as part of map errors or when osm tags are filtered in such a way that such oneways remain whereas the returning roads are filtered out. This is best used in combination with remove-unconnected and concatenate-skips to make sure that all MultiLineStrings can be connected into one single LineString.

Full Changelog: v1.1.7...v1.2.0

v1.1.7

Choose a tag to compare

@addy90 addy90 released this 10 Sep 14:43

This release adds a new feature and corrects an immediate bug that we encountered with the v1.1.6 release earlier today.

  • The new sorting of points with timestamps was not working correctly with containers such as ordered sets, which is used in the comparison algorithm. We corrected this by introducing a sorting operator specifically meant for the sorting on import.
  • We introduce a new feature "warp detection" that can remove large outliers that can occur when there is a jump from one point to another within a blink of time, for example, traveling a distance of 200 meters but the timestamp is the same for both points. We use a very high default speed detection of 1500 km/h as we don't know of any vehicle on ground that can go faster and because our candidate adoption feature takes care of outliers itself already. But the less outliers, the better the results, especially when the outliers are plain obvious. This feature is primarily meant to remove points with duplicate timestamps, especially when they are not in the same geopositions. But it can also remove points that have a different timestamp but a respective too high travel speed between the points. This feature is on by default but only is applied when a valid time information is provided with the track.
  • The new time point sorting and the new warp detection feature showed some errors in our floating-car-data ground truth data. Therefore, we corrected the errors that we found and upload the corrected data in this repository now. It should be used instead of the old data from the linked zip file. However, the OSM data from that zip file is still necessary.

Full Changelog: v1.1.6...v1.1.7

v1.1.6

Choose a tag to compare

@addy90 addy90 released this 10 Sep 08:03

This release fixes a bug in sorting points after timestamp during import of tracks from CSV or GPX files. The fix should in practice improve the matching accuracy of tracks that contain points with different geocoordinates with the same timestamp.

  • When two points have the same timestamp, which can unfortunately occur in practice, for example when two GPS points are measured within the same second but the timestamp resolution is only seconds, then sorting these points by timestamp can lead to a change of order. Usually, points with the same timestamp are already in the right order in the import file, because they were written in that order, so the order should not be changed even when the timestamp is the same. Not all sorting algorithms fulfil this criteria, but there is std::stable_sort that we already used, which guarantees the order of elements with the same value. The regular std::sort does not keep the order of elements with the same value. However, we mistakenly did not only order by timestamp previously but also by geoposition in case the timestamp is the same. This is not really useful and lead to std::stable_sort not being able to keep the order, because our sorting criteria was wrong. This is now fixed.

Full Changelog: v1.1.5...v1.1.6

v1.1.5

Choose a tag to compare

@addy90 addy90 released this 21 Aug 09:21

This is a small bugfix and library update.

  • We fixed a bug that made disabling --routing-max-distance-factor by setting it to a negative value not working as expected.
  • The A* algorithm now uses the exact distance in the heuristics function.
  • We added a new --a-star-euclidean mode for enabling the old behavior that uses Euclidean distance based on spherical trigonometry.
  • We updated Boost to 1.89.0
  • We made some cleanups in the CMake and Docker build environments, we also tried using a newer base os for compiling, but ran into glibc and pthread crash issues with static linking. Although not linking statically works per se, it reduces the compatibility with other systems that we have not tested. Static linking is a mixed bag. Therefore, we kept the old base os for now. We also added some new options for the CMake build system and we also added a new test suit to check if the binary runs on recent Ubuntu and Debian systems.
  • We build against GCC 15.2.0 now on Linux.

Full Changelog: v1.1.4...v1.1.5

v1.1.4

Choose a tag to compare

@addy90 addy90 released this 13 Aug 09:01

This is another small bugfix release that catches a crash when using the remove-duplicate-edges functionality.

  • The remove-duplicate-edges functionality could crash when duplicate edges were removed from the graph. This has been fixed.

Full Changelog: v1.1.3...v1.1.4

v1.1.3

Choose a tag to compare

@addy90 addy90 released this 12 Aug 10:16

This is a bugfix release addressing a specific issue in the comparison algorithm.

  • In very rare occurrences, there were errors in the point-snapping part of the comparison algorithm. This lead to correct matching parts being missed to be detected as such. The error has been fixed.
  • We also profiled the algorithm after applying the fix and found a way to double the speed of the comparison algorithm by caching computed bounding-boxes. So the comparison algorithm is now faster than ever.

Full Changelog: v1.1.2...v1.1.3

v1.1.2

Choose a tag to compare

@addy90 addy90 released this 06 Aug 11:25

This is a small release with two fixes for very specific issues:

  • The Q-learning algorithm is still a proof-of-concept in this application, because Value Iteration (which is the default algorithm) is faster and gives optimal results. Still, Q-learning suffered from an old piece of code that tried helping to "guide" the algorithm into quicker more optimal action selection. In ongoing tests, this part of code made Q-learning exceptionally slow in comparison, so we removed it. Planning algorithms in combination with Q-learning should be a better alternative. However, we have not yet dived deep into this yet, since Value Iteration works so well in our use-case. So Q-learning should be faster now, although it is still a proof-of-concept rather than the recommended algorithm to choose here.
  • When exporting third-party network data as artificial OSM data file, we did not export any tags with the ways. Although tags can be later added artificially with osmosis, it is easier to just modify the tags with osmosis, osmconvert, or osmium. However, modification only works when there are tags, so we use the temporary highway=road tag (that is explicitely reserved for this purpose) now. This should make later working with artificial exported OSM files easier.
  • We updated the date library to 3.0.4 and protozero to 1.8.1
  • Some build system adaptions were made for working with address sanitizers and perf in Docker environment

Full Changelog: v1.1.1...v1.1.2

v1.1.1

Choose a tag to compare

@addy90 addy90 released this 16 May 13:27

This is a bugfix release following the new 1.1 version.

  • The track split-time functionality had an error that was corrected. In the previous version, the point at which a track was split into two parts was contained in both parts. This was wrong behavior and lead to the segment with the time-difference exceeding the definition being contained in the second track part. This means, the first two points in the next track part had a time-difference that was larger than the defined value. Now the track is correctly split in that the previous track part ends at the split point and the next track part starts at the next point that has the respective time-difference. With the correct behavior now, each track part only contains points with time-differences that are below the defined split-time value.
  • We fixed another rare crash in the network import.
  • We fixed an issue with the GPX track import when no timestamp information was available.

Full Changelog: v1.1.0...v1.1.1

v1.1.0

Choose a tag to compare

@addy90 addy90 released this 15 May 08:48

This is a big update with a lot of quality-of-life updates especially for map matching large floating car data sets.

  • We updated several third-party libraries; libosmium to v2.22.0, Expat to version 2.7.1, and Boost to version 1.88.0; we also now removed protobuf from the repository as it was no longer referenced.
  • The update to Boost 1.88.0 fixed an issue that prevented to use newer Clang compilers, so we can build against Clang 20 now, see boostorg/thread#402, however, the AppImage release contains a GCC build.
  • We also updated GCC to 15.1.0 and CMake to 3.31.6, and on Windows, we used the newest Visual Studio version 17.14.0.
  • We now build the software completely statically linked on Linux, in the hope that this solves issues with the AppImage now working on other systems than the target system it was compiled for, due to glibc incompatibilities.
  • We also use a more recent appimage-tool now that uses a new runtime which should also improve compatibility of the AppImage and also may render libfuse2 obsolete, see AppImage/AppImageKit#877 (comment).
  • We changed the official Dockerfile to incorporate the fix discussed in #9, thanks to @mschrader15. The entrypoint has changed, the application is now directly called instead of a sub-shell. The official Docker image at addy90/map-matching-2 was updated accordingly.
  • We refactored the track importer functionality to accommodate for further changes.
  • With this refactoring, we added two new filter methods that can filter tracks during import:
    • A new split-time method that can split tracks into multiple tracks when the difference between two point timestamps exceeds a defined value. This is an important setting for large floating car data where multiple individual tracks are aggregated under the same id. This method is able to split the individual tracks based on a difference between two points, for example, when you define 600 seconds, a track is split into two tracks when there are two points that have a time difference of at least 10 minutes. Only works for tracks that are imported with a time information, of course.
    • A new filter-polygon method that only keeps tracks that are either within (i.e., in practice covered-by, which means the border counts, too) or intersect (i.e., within or partially overlapping) a given bounding-box or complex polygon. A bounding box can be defined as WKT BOX (10 20, 40 50) with the lowest x, y and highest x, y coordinates, and a complex polygon (which needs to be closed and counter-clockwise defined) can be defined as WKT POLYGON ((30 10, 40 40, 20 40, 10 20, 30 10)) with a list of x and y coordinates. The filter-method can be selected so that only tracks that completely lie within the given polygon or bounding box are kept, or all tracks that lie within or intersect the border, i.e., intersect contains within, so only tracks that completely lie outside the polygon or bounding box are filtered out. This setting is especially useful for when from a large floating car data set, only a specific region is of interest. It works in combination with split-time so that first the tracks are split and then, in case a split part is kept by the filter, that part is kept, while the rest is not. So first the splitting, then the polygon-filtering. Keep in mind that the filtering is done in the import-thread, not in the parallel matching threads, so you may not want to use very complex and large polygons, as these increase the time it takes to filter a track immensely; in these cases, we recommend to compute and use the convex hull of the polygon, or use a bounding box of the polygon, to not bottleneck the import thread.
  • We now output the start and stop time of the track in the results, however, due to technical design decisions, the original time-zone is not kept and needs to be defined with the new export-time-zone setting, if the default system setting is not wanted. Alternatively, unix timestamps can be exported with the new export-timestamps setting. It is also possible to export all timestamps of all points of the track in a new column, check the columns setting in the help.txt. Of course this setting is only useful for tracks which have times, but it is still possible to match tracks without time-information, this has not changed. The output of the track times, however, can be useful for further analyses.
  • We now sort points by timestamp with stable-sort so that points that have the same timestamp are not reordered anymore. This may slightly improve matching quality in such cases. Btw., the candidates export functionality also exports the time information now, see candidates-columns.
  • We use eager-initialization of track metadata, such as segment lengths and azimuths, and we moved that initialization to a later step in the pipeline so that it is carried out only for the tracks that were not filtered out before, to address unnecessary computations.
  • We also finally added general switches to disable all steps of trajectory-simplification and candidate-adoption with one setting.

Full Changelog: v1.0.11...v1.1.0