Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best and most performant implementation of dynamic shapes in cesium

Tags:

cesium

I am currently working an application that is using a Cesium Viewer. I need to be able to display a collection of shapes that will be updated dynamically. I am having trouble understanding the best way to do this.

I currently am using Entities and using CallbackProperties to allow for the updating of shapes.

You can through this into a sandcastle to get an idea of how I am doing this. There is a polygon object that is being used as the basis for the cesiumCallback, and it is getting edited by another piece of code. (simulated with the setTimeout)

var viewer = new Cesium.Viewer('cesiumContainer', {});

var polygon = {};
polygon.coordinates = [
    {longitude: 0, latitude: 0, altitude: 0},
    {longitude: 10, latitude: 10, altitude: 0},
    {longitude: 10, latitude: 0, altitude: 0}
];


// converts generic style options to cesium one (aka color -> material)
var polOpts = {};

 // function for getting location
polOpts.hierarchy = new Cesium.CallbackProperty(function() {
  var hierarchy = [];
  for (var i = 0; i < polygon.coordinates.length; i++) {
       var coordinate = polygon.coordinates[i];
       hierarchy.push(Cesium.Cartesian3.fromDegrees(coordinate.longitude, coordinate.latitude, coordinate.altitude));
  }
  return hierarchy;
}, false);

viewer.entities.add({polygon: polOpts});

setInterval(function(polygon){
       polygon.coordinates[0].longitude--;
}.bind(this, polygon), 1000);

The polygon being passed in is a class that generically describes a polygon, so it has an array of coordinates and style options, as well as a render method that calls this method renderPolygon passing in itself. This method of rendering shapes works for everything I need it to, but it is not very performant. There are two cases for shapes updating, one type of shape will be updated over a long period of time, as a slow rate like once every few seconds. The other is shapes that will will get updated many times, like thousands, in a few seconds, then not change again for a long time, if ever.

I had two ideas for how to fix this.

Idea 1: Have two methods, a renderDynamicPolygon and a renderStaticPolygon. The renderDynamicPolygon method would do the above functionality, using the cesiumCallbackProperties. This would be used for shapes that are getting updated many times during the short time they are being updated. The renderStaticPolygon method would replace the entities properties that are using callbackProperties with constant values, once the updating is done.

This creates a lot of other work to make sure shapes are in the right state, and doesn't help the shapes that are being updated slowly over a long period of time.

Idea 2: Similarly to how the primitives work, I tried removing the old entity and adding it again with its updated properties each time its need to be updated, but this resulted in flickering, and unlike primitives, i could not find a async property for entities.

I also tried using primitives. It worked great for polylines, I would simply remove the old one and add a new one with the updated properties. I was also using the async = false to ensure there was no flickering. This issue I ran into here was not all shapes can be created using primitives. (Is this true?)

The other thing I tried was using the geometry instance using the geometry and appearance. After going through the tutorial on the cesium website I was able to render a few shapes, and could update the appearance, but found it close to impossible to figure out how to update the shapes correctly, and also have a very hard time getting them to look correct. Shapes need to have the right shape, a fill color and opacity and a stroke color, opacity and weight. I tried to use the polygonOutlineGeometry, but had not luck.

What would be the best way to implement this? Are one of these options headed the right way or is there some other method of doing this I have not uncovered yet?


[Edit] I added an answer of where I have gotten, but still not complete and looking for answers.

like image 862
Zac Avatar asked Sep 30 '15 15:09

Zac


1 Answers

I have came up with a pretty good solution to this, but it still has one small issue.

I made too ways of showing entities. I am calling one render and one paint. Render uses the the Cesium.CallbackProperty with the isConstant property true, and paint with the isConstantProperty false.

Then I created a function to change the an entity from render to paint and vice vera. It goes through the entities callback properties an uses the setCallback property to overwrite the property with a the correct function and isConstant value.

Example: I create a ellipse based on a circle object I have defined.

// isConst is True if it is being "painted" and false if it is being "rendered"
ellipse: lenz.util.extend(this._getStyleOptions(circle), {
  semiMinorAxis: new Cesium.CallbackProperty(
    this._getRadius.bind(this, circle),
    isConst
  ),
  semiMajorAxis: new Cesium.CallbackProperty(
    this._getRadius.bind(this, circle),
    isConst
  ),
})

So when the shape is being updated (while the user is drawing a shape) the shape is rendered with the isConstant being false. Then when the drawing is complete it is converted to the painted version using some code like this:

existingEntity.ellipse.semiMinorAxis.setCallback(
  this._getRadius.bind(this, circle),
  isConst
);
                            existingEntity.ellipse.semiMajorAxis.setCallback(
  this._getRadius.bind(this, circle, 1),
  isConst
);

This works great performance wise. I am able to draw hundreds of shapes without the frame dropping much at all. I have attached a screen shot of the cesium map with 612 entities before and after my changes, the frame rate is in the upper right using the chrome render tool.

Before: Locked up at fps 0.9 Note: I redacted the rest of the ui, witch makes the globe look cut off, sorry enter image description here

And after the changes: The fps remains at 59.9, almost perfect!

enter image description here

Whenever the entity is 'converted' from using constant to not constant callback properties, it and all other entities of the same type flash off then on again. I cannot find a better way to do this conversion. I feel as thought there must still be some thing I am missing.

like image 84
Zac Avatar answered Sep 27 '22 19:09

Zac