Moving Points along GPS Track on QGIS

Mar. 01, 2019 | tags: GPS

After implementing timestamp as M-value on SpatiaLite + QGIS as described in the previous article,I tried making moving point animation with QGIS and TimeManager plugin following Anita Graser's another article.

However, point doesn't move in real-time. When I move TimeManager's slider, I have to wait a few seconds to see a point.

So, I implemented more effective algorithm.

Here's the real-time movie of both 2 algorithms. The first (red point) is Anita's and the second (blue point) is mine. The whole trajectories shown are tracks of 10 day travel.


(1) Geometry generator code

Here are the codes behind the moving points. The source data is "timestamp as M-value" track lines.

One layer of geometry generator is set as right.

Below is the text version of the expression to copy & paste.

WHEN ( m(end_point($geometry)) > second(age(animation_datetime(), to_datetime('1970-01-01 00:00')))
AND m(start_point($geometry)) <= second(age(animation_datetime(), to_datetime('1970-01-01 00:00'))))
line_lookup_m( $geometry, second(age(animation_datetime(), to_datetime('1970-01-01 00:00'))))

(2) Custom function definition

In this expression, custom function line_lookup_m() is called. This function is defind as right.

Below is the text version of the line_lookup_m().

Explanation of the algorithm

Time can never be reversed. So, we can reasonably assume each GPS track is ordered by timestamp, which is m-value (it seems even enforceable in PostGIS using ST_IsValidTrajectory() function.)

So for any given time target_m, we check every track's start time and end time and see whether target_m is in-between.

If it is, we pick timestamp of the middle point and see whether it is larger than target_m or not. If it is larger, we can say that point to plot is in the latter half of the track, and see whether the middle point of that half is larger than target_m or not. We repeat this halving process until we find a point to plot.

This is just a standard binary search algorithm.

For animation purpose, I modified the algorithm when reaching down to one point without finding exact match to target_m to interpolate neighboring points based on timestamp.

Notes on QGIS custom expression

QGIS expression doesn't support neither loop functionality or recursive function call, which is necessary to implement binary search. So, we have to write a custom function.

Unfortunately, QGIS custom function is not so well documented. The following points will be helpful, if you are interested in writing your own.

  • Logs can be output with QgsMessageLog.logMessage() to log message panel. This enables good old printf debugging.
  • Editings on function builder is always automatically saved but not evaluated until you click "save and load functions" button.
  • Returning points have to be converted to QgsGeometry.

Source codes of TimeManager plugin and QGIS (expression related parts) will be also helpful.