Overcoming Out of Memory Errors When Adding Billboards/Points

I am working on a project where I add utility data to the 3D world created by Cesium. I am initially focusing on one city, which has about 500,000 utilities in it, and will eventually want to expand this project to all across the country. However, I am already running out of memory issues with just this one city’s data. My data is coming from a geoJSON file containing the lat/long of each utility as well as some identifying information.

I want to allow users to click on the object and see a description with some more data in it, so I started out with the standard billboard. However, after reading the documentation, I learned that billboards take up more memory than Points. So I switched to Points, but then learned that Points to not have the description info box and the Points also called the memory error.

What is the best way to solve the memory issue while retaining the info box functionality? Is there a way to only display the meters that are within the current view?

Thanks so much for any help, I am new to Cesium and am excited about its potential!

Welcome to the Cesium community! This sounds like a very interesting project. Is the data for this publicly available?

This is exactly the ideal solution here. This is why we created 3D Tiles as a standard format. This is how the Cesium OSM Buildings dataset works, which is contains over 350 million buildings with metadata contained in each building. So you can have both a large dataset and a lot of data at the same time.

The tricky thing for your use case is at the moment we have no pipeline for tiling vector data like GeoJSON into 3D Tiles. So your options are:

  1. Convert your data into something that Cesium ion can tile into 3D Tiles (see full list here: https://cesium.com/docs/tutorials/uploading/). Your best bet would probably be KML/COLLADA as described here: https://cesium.com/blog/2020/04/09/kml-collada-metadata/. Where the KML specifies the location and metadata, and the COLLADA model can be any representation of the structure.
  2. Implement some of the principles behind 3D Tiles yourself in your application.

Option 2 is not trivial but may be a good solution. It would require you to pre-generate some spatial data structure for all your points (like a quadtree), so you can efficiently get the points in any given area, only show these points, and then re-cycle points instead of creating/destroying a lot of them whenever the camera moves.

@omar thanks so much for the quick reply. No the data is not publicly available, this is a company project. I created a python script to convert my original csv data (before I converted it into geoJSON) into kml. However, after trying to add it to Ion, I got an error message saying “Only KML/KMZ files with models are supported”. I do not think I want to add a 3D representation of every utility, but would rather do something similar to the Cesium billboards. Is this possible? I created a kml label style with an icon, which I assumed would serve as the “model”, but this obviously did not work as I intended. I read the KML documentation for creating points, and it seemed like there was not an argument for the 3D model? Thanks so much for your help.

Here is a sample of my KML file if that helps

<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2" xmlns:gx="http://www.google.com/kml/ext/2.2">
    <Document id="1">
        <Style id="2">
            <IconStyle id="4">
                <colorMode>normal</colorMode>
                <scale>1</scale>
                <heading>0</heading>
                <Icon id="5">
                    <href>http://maps.google.com/mapfiles/kml/paddle/blu-blank.png</href>
                </Icon>
            </IconStyle>
            <LabelStyle id="3">
                <color>ff0000ff</color>
                <colorMode>normal</colorMode>
                <scale>2</scale>
            </LabelStyle>
        </Style>
        <Placemark id="7">
            <name>Meter1234</name>
            <description>This is meter 1234</description>
            <styleUrl>#2</styleUrl>
            <Point id="6">
                <coordinates>0.0,0.0,5</coordinates>
            </Point>
        </Placemark>

@omar I wanted to provide an update- Again, sorry for the confusion, this is my first time using Cesium.
I have since attempted to add the kml file without using Cesium Ion, and instead using Cesium.KmlDataSource.load('./Source/SampleData/meters.kml', kmlOptions); within the code. I assume this is the better way to do it?

Looking at the length of the dataSource in the promise.then function, it seems that it loaded in the correct amount of entities. However, none of the entities are shown on the map. Is this because there is not a model provided? I was thinking that since I added them to the map as billboards, then that would mean I would not need any models. My code is copied from the sample app that loads kml data of NYC neighborhoods, so I am not sure what is different. Do you have any tips on why the billboards aren’t showing?

var metersPromise = Cesium.KmlDataSource.load('./Source/SampleData/meters.kml', kmlOptions);

// Add geocache billboard entities to scene and style them
metersPromise.then(function(dataSource) {
    // Add the new data as entities to the viewer
    viewer.dataSources.add(dataSource);

    // Get the array of entities
    var metersEntities = dataSource.entities.values;
    for (var i = 0; i < metersEntities.length; i++) {
        var entity = metersEntities[i];
        if (Cesium.defined(entity.billboard)) {
            // Adjust the vertical origin so pins sit on terrain
            entity.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
            // Disable the labels to reduce clutter
            entity.label = undefined;
            // Add distance display condition
            entity.billboard.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(0.0, 200000.0);
            // Compute latitude and longitude in degrees
            var cartographicPosition = Cesium.Cartographic.fromCartesian(entity.position.getValue(Cesium.JulianDate.now()));
            var latitude = Cesium.Math.toDegrees(cartographicPosition.latitude);
            var longitude = Cesium.Math.toDegrees(cartographicPosition.longitude);
            // Modify description
            var description = '<table class="cesium-infoBox-defaultTable cesium-infoBox-defaultTable-lighter"><tbody>' +
                '<tr><th>' + "Longitude" + '</th><td>' + longitude.toFixed(5) + '</td></tr>' +
                '<tr><th>' + "Latitude" + '</th><td>' + latitude.toFixed(5) + '</td></tr>' +
                '</tbody></table>';
            entity.description = description;
        }
    }
});

Converting your vector data to 3D Tiles through the KML/COLLADA pipeline would require you to create a very specific structure for your KML (as shown here: https://cesium.com/blog/2020/04/09/kml-collada-metadata/).

I would expect adding the KML directly to work (this would be exactly the same as loading them as GeoJSON though, it would add all the data to the map at the same time). You can upload the KML file to Cesium ion and send me a link here to take a look at why it isn’t working (select “Host without tiling” when you upload) or you can send a private message on the forum if you’re unable to share a link publicly.