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.

VIDEO
Codes
(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.

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
(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.

comments