Tuesday, August 19, 2014

Cesium in action

Cesium is a WebGL virtual globe and map engine.
You can use it to build time-aware GIS applications. What do I mean by "time-aware"?
Suppose you want to let the user playback scenarios on the map. For instance, meteor hits over the years or satellite/airplane tracking.
Most map engines don't "understand" time. The way to implement this kind of functionality using ArcGIS for JS for example, is using different layers for each discrete moment. This is very heavy, not easy to implement and shows only discrete moments.
Cesium, on the other hand, supports continuous playback (and even comes with a clock and timeline built-in!). Cesium offers a data format, called CZML, which is basically a regular JSON array. In this array, you can specify elements. These elements could be points, polylines, polygons, text labels, images or even 3D models. For each element you can specify properties that will determine the element's life span, position, size, color, texture and a bunch of other things.
For example, you could say that a blue point with a black border will appear for 5 seconds at 2014-05-05 18:00:00 at longitude 34, latitude 35, height 0. This is represented as the following CZML:


Seems simple, right? it is. CZML provides a way to paint a scenario for Cesium to play, and you can do amazing things with it, just look at the Cesium Samples Page.
The rest of this post is some issues and best practices with Cesium.
I used Cesium for the past few months to build a small analysis tool for some clients. They can load Excel files that specify times and coordinates of events. The application will allow playback of those events and some advanced processing of those events.
Our application needed to create CZMLs on the fly, so we wrapped CZML creation in a nice small JS API. It is bad to just create CZMLs with actual JSON. This could cause code duplication and performance issues.
Beware of interpolation! Cesium supports interpolation of some properties, which means that if the color of the point is yellow at 5PM and green at 6PM, when playing back you will see the color changes gradually from yellow to green, instead of changing momentarily at 6PM. That is awesome, sometimes. For us it was mostly annoying, because we didn't need it usually, so we had to do an annoying work-around of keeping the same color 5 seconds before the changing time. That way the interpolation would happen only during those 5 seconds, which is short enough to be unnoticeable.
Interpolation sometimes causes acute performance issues. We ran into such a problem in the evening, while loading the application with real data, which was large enough to make the playback hideously slow and then the engine would collapse and Cesium would throw a weird error and just stop working. We spent 5 hours fixing this problem... It turned out to be interpolation again. Luckily, we found out that the show property wasn't interpolatable and we used it to show a point in specific times, instead of changing the alpha of the color to make it disappear.
Also, we noticed that using the show property sometimes causes performance issues, if you put more than one interval in the show array. The workaround is to tell it when not to appear (negative infinity to start time 1, end time 1 to start time 2, end time 2 to positive infinity). Weird but works :)
Loading a Cesium data source is possibly a heavy action, because it reads and processes your CZML. If you have several data sources that gets updated, use multiple data sources for a viewer (yes, Cesium supports that: viewer.dataSources) and load only the relevant ones. We used to load all data sources, even when just one data source gets updated. Looking for performance bottlenecks in our application, we noticed this inefficiency. So we made this process modular, loading only dirty data sources.

Hope this helps someone!

5 comments:

  1. Hi, This looks like a really nice tool.

    About the performance issues,
    Does Cesium keep it's own data structure once you input the data points to it?
    Because many time's the actual Access to the objects to change properties (Like Alpha or Show/Hide) takes the majority of time.
    I don't know the exact way of implementation of the tool or your solution,
    But a lot of times while working with GIS tools (Not in JS but still..) i would use a HashMap of some kind to store the "Indicates" of the entities, and then access them faster when needed.

    If you want i can look at the code and try to help :)

    Thanks a lot for the interesting article!

    ReplyDelete
    Replies
    1. After Cesium reads the CZML the data is stored in the primitives array, which you can access and manipulate too. This is performance-friendly but not very comfortable.

      Delete
    2. So actually what you're saying is the any access to the entities is of O(n)?
      Isn't the idea of making another mapping of a HashMap to the entities better?

      Delete
    3. Cesium strives for the best possible performance, It says so, on their git-hub page: "We strive for the best possible performance".

      Actually on their last update (1.0) they made some major API changes that although are highly less user friendly, are said to greatly improve performance in render time.

      Delete
    4. In JS Arrays are objects, and objects are(Kinda) hashMaps.
      As I can do something like so:

      myAwesomeArray = [];
      myAwesomeArray[0] = 15;
      myAwesomeArray.myAwesomeValue = 85;

      console.log(myAwesomeArray["myAwesomeValue"]) // Prints 85

      Delete