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.
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.
CASE 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')))) THEN line_lookup_m( $geometry, second(age(animation_datetime(), to_datetime('1970-01-01 00:00')))) END
In this expression, custom function
line_lookup_m() is called. This function is defind as right.
Below is the text version of the
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
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
- 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
Source codes of TimeManager plugin and QGIS (expression related parts) will be also helpful.