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.

## Codes

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.