Cecium DIS-style dead reckoning

1. A concise explanation of the problem you're experiencing.

I like to visualize several entities that move around. Rather than constantly updating the position of each entity (by sending the position data from a simulator through e.g. a websocket connection), I like to off-load the updating to Cesium using dead reckoning models. I looked at SampledPositionProperty, we may be able to support this, but I have really no clue how to get that working.

Does Cesium support DIS-style dead reckoning? I.e. first order derivative of position change / velocity.

If so, how can this be done? Is there a simple example you can point me to?

2. A minimal code example. If you've found a bug, this helps us reproduce and repair it.

Currently, the position updates are static and transmitted every so many seconds causing overhead.

Code snippet to create entity:

               var billboard = {
                    image: sym.asCanvas(), //Get the canvas for the billboard
                    pixelOffset: new Cesium.Cartesian2(-sym.markerAnchor.x, -sym.markerAnchor.y), // Symbol offset
                    eyeOffset: new Cesium.Cartesian3(0.0, 0.0, 0.0), // default
                    horizontalOrigin: Cesium.HorizontalOrigin.LEFT, // default
                    verticalOrigin: Cesium.VerticalOrigin.TOP};

                var entity = {
                    id: milsym.id,
                    billboard: billboard,
                };

                var position = new Cesium.Cartesian3(milsym.geocentricPosition.x, milsym.geocentricPosition.y, milsym.geocentricPosition.z);

                entity.position = new Cesium.ConstantPositionProperty(position);

                viewer.entities.add(entity);

3. Context. Why do you need to do this? We might know a better way to accomplish your goal.

N/A

4. The Cesium version you're using, your operating system and browser.

Version 1.53. FF en GC on Windows 10.

This is a very good question, and I believe the answer is yes. This is something I’ve been working on recently to try and provide an example for how to use it. This example shows you how to set up the different interpolation options:

This PR adds a Sandcastle example that uses these sample properties to move the vehicle’s position, in addition to the wheels and orientation:

The example is in this file:

https://github.com/AnalyticalGraphicsInc/cesium/blob/15c98a49a3e10e91b248687eb21906d5100a7244/Apps/Sandcastle/gallery/Time%20Dynamic%20Wheels.html

Here the samples are all added ahead of time, but you should be able to add samples at run time, and the Sampled properties can extrapolate forwards. I hope you find this helpful until we can set up a tutorial on this common use case.

If you get it working it’d be very helpful to the community to post your example here/or as a Sandcastle link!

I have got an example going, but use Cesium.ConstantPositionProperty. The entity position is updated with either the received position on the websocket, or every so many seconds using a timer. In the latter case the position is dead-reckoned. Maybe not the best approach, but it does work.

A better way is - I assume - using Cesium.CallbackProperty. When the callback is triggered, the position for the requested time should be returned. This position should be dead reckoned from the last received websocket update. I have done this yet. When and how often is the callback called? Do I have control over the call rate?

Once I have this in place I also like to visualize the path that the entity traversed. Although this is another questions, I like to know how to do this as well.

I am happy to post code once I get callback option going, hopefully with track display included. Any help appreciated.

When and how often is the callback called? Do I have control over the call rate?

The callback is called every time the property is required. It’s best to think of it not as an update function that advances the simulation, but more as a function that evaluates the property for any given time.

So in a given frame, if the Cesium render code gets the Entity’s position to figure out whether it’s in view of the camera, and your own code uses the Entity’s position to compute something, then that function will l be called twice per frame. This way, Cesium can support things like being able to play any simulation in reverse, as well as easily pause and step through.

So you can see how the callback property in this example computes the position based on the passed in time:

https://cesiumjs.org/Cesium/Build/Apps/Sandcastle/?src=Callback%20Property.html

So in your case, I think if you keep track of all the positions you get from the websocket, and then in the callback, given a time, do your computation there and return the position. Does that work for you?

The simulation (whose spatial data is sent over the websocket to the browser), only moves forward in time. The simulation can run non-real time (not necessarily scaled real time), but in my current setup I only use wall clock time (1x real time). Spatial data includes 2nd order derivatives, and is only sent when the difference with the local dead-reckoned model is more than 1 meter. So, if the difference with the local model remains small, no spatial data is sent to the browser at the other end for a long time. The browser is assumed to follow the same dead-reckoning model using the last received spatial data to work from. The dead-reckoning only works forward in time.

From the cesium spec it is unclear if the callback only moves time forward, i.e. if every callback is for a time greater than the previous invocation. If so I can do the dead-reckon calculation in the callback function.

Currently I use a ConstantPositionProperty for each entity, which I update at a rate of 10Hz to get relatively smooth movement on the display. When I use the Cesium callback the update rate is determined by Cesium, 2 x fps, right? How does this work out performance-wise for say 1000-1500 entities?

I think in that case the way you have it might be best. The CallbackProperties are not evaluated a specific number of times per frame, it’s evaluated only when needed (like a getter function).

From the cesium spec it is unclear if the callback only moves time forward, i.e. if every callback is for a time greater than the previous invocation.

I wouldn’t say the callback moves time in any direction. Its role is to return a value at a particular given time. This makes it great for properties that can be computed independently for any point in time (for example, I think this is how the sun’s position is computed, given any particular time it can compute its position). However, for properties that require knowledge of past frames/states it might not be a great option (which is why, in the vehicle Sandcastle PR I linked above, to rotate the wheels I did not use a CallbackProperty, because in order to know the rotation of the wheel at any given time, I’d need to sample the velocity of the vehicle at all the moments in time from some start position leading up to this moment, which would be a performance hit doing it every frame for a long period of time).

Hope that makes it a little clearer.

Thanks so far. I will explore the links and examples you provided for my application.

Any updates? I’m just about to implement the same thing for our application.

Scott, if your question is if it’s possible to supply a list of positions and time and have CesiumJS compute the velocity/interpolate etc, the answer is yes. This code example shows some of that, specifically with the velocity piece: https://sandcastle.cesium.com/index.html?src=Time%20Dynamic%20Wheels.html.

That’s just not how it works unfortunately. We’ll be getting frequent property updates, and we never know when a new update will be coming. We will be getting a speed and an orientation(heading for ground units) and I need to interpolate frame by frame on the heading at the current speed. Currently, everything works fairly well for ships which don’t move very fast. Consider a F35 which is traveling at over 500 miles and hour. That unit jumps from position to position. I was thinking about changing the position property dynamically to the CallbackProperty when the unit has a speed > 0, and then switching the position to a constant value when speed = 0. We might have upwards of a 1000 units, so I was a little worried about performance. Any other suggestions are welcome. I might just store the position as ‘bergtwvd’ is suggesting.

This should still work since CesiumJS supports forward extrapolation. If I understand your use case correctly, you want the entity to continue moving with the velocity computed from the given positions, and when given a new position in time to re-compute the velocity and continue this interpolation, right?

I wouldn’t expect it to jump from position to position no matter how fast it’s going, if the positions are given in a SampledPositionedProperty, with a JulianDate for each position.

I don’t think there are any code examples with forward extrapolation, but if you can put together a small sample in Sandcastle showing how you’re implementing this and the issues you’re running into, I’d be happy to show you what I mean, and perhaps that can become a new code example in Sandcastle.

Yes that sounds correct. Forward extrapolation, based upon the current position, speed, and orientation. As soon as a new speed and/or orientation is received then a new beginning position should be set.

Part of the issue(jumping) is with our current implementation, that’s what I’m trying to fix. I’ve been looking through the documentation and trying to find what Cesium classes if any would be helpful. I think the best way to set up a demo would be to just set up an array of speeds, with headings and try to iterate over those every 5 seconds.

https://www.sciencedirect.com/topics/computer-science/dead-reckoning#:~:text=Dead%20reckoning%20(deduced%20reckoning)%20is,over%20elapsed%20time%20and%20course.

Our first example is just dealing with ships which will all be sea level. Later we’ll need to handle ground and air. I suspect for sea and ground we’ll just use the heading, but for air we’ll have to use the full orientation.

Scott

This last sandcastle app looks pretty good. I’ll have to put this code into our app and see how it works. I’m a little concerned that selection box and the heading label are drifting off. It appears that the FOV and possibly the order of the rendering is causing the issue?? Only guessing, though. If the Cesium team has any input that would be great to hear. The billboard jumps from one location to another so you have to zoom out and relocate the icon when it disappears. I noticed that I had issues in the eastern and western hemispheres.

Update: Visually the movement looks pretty good, but movement on an arbitrary XY plane seems off. I’ve added the current Lat/Long to the display to aid in the understanding of the movement of the entity.

@Scott_Haynes, a couple things about your Sandcastle:

  • The drift you see is because the billboard has a height reference heightReference: Cesium.HeightReference.CLAMP_TO_GROUND that’s different from the label. Make sure both have the same height reference if you want them to match
  • Your callback property is updating the position on each frame, instead of using a SampledPositionProperty. This means you won’t be able to use interpolation/extrapolation, you won’t be able to pause/play, or use the timeline to see the past positions.

Instead of using a CallbackProperty, you should create a SampledPositionProperty. And then create an onTick event (or whenever you get new data from the server) to add new positions when you get them and a timestamp:

position.addSample(time, location);

SampledPositionProperty is not a possibility. We do not use the timeline, nor could we. We’ll have a LVC simuation running and our app is the central visualization tool for the entire system. One of the sims might be a F35 virtual sim. At any one time we have a position, orientation, and a speed. I might receive another update in 2-30 seconds. The frequency of the updates is unknown. My sample position would have to be the next position, which is basically what I’m doing. Basically, I have what I want, but I cant get the correct velocity vector given the information I have. What I have is close, but not perfect.