Geojson floating and shifting on the terrain

1. My GML was extracted from the database tables to GeoJSON, when loading it to Cesium, they appear to be floating in the air.
turned out they had terrain information embedded in them, so I had to activate the terrainProvider. which made them drop to the ground, but they are not fixed.
When I move the around, the data seem to be shifting around.

Here is my code

var viewer = new Cesium.Viewer('cesiumContainer');
  var terrainSamplePositions = ;
  var terrainProvider = new Cesium.CesiumTerrainProvider({
  url : '//assets.agi.com/stk-terrain/world'
});
viewer.terrainProvider = terrainProvider;
// Cesium.GeoJsonDataSource.clampToGround = true;
  var promise = Cesium.GeoJsonDataSource.load('Lyon_PY.geojson');
  promise.then(function(dataSource) {
    viewer.dataSources.add(dataSource);
    viewer.zoomTo(promise);
  
   var entities1 = dataSource.entities.values;
   for (var i = 0; i < entities1.length; i++) {
    var entity = entities1[i];
        var name = entity.name;
     var positions = entity.polygon.positions.getValue();
        for (var p = 0; p < positions.length; ++p) {
            terrainSamplePositions.push(Cesium.Cartographic.fromCartesian(positions[p]));
        }
}
  Cesium.when(Cesium.sampleTerrain(viewer.terrainProvider, 9, terrainSamplePositions), function() {
        // Fudge the height values to keep off the ground.
        for (var k = 0; k < terrainSamplePositions.length; ++k) {
            terrainSamplePositions[k].height = 1.0; // one meter off the ground
        }
        // Update all lines to sit on top of the terrain.
        var cartesians = viewer.scene.globe.ellipsoid.cartographicArrayToCartesianArray(
            terrainSamplePositions);
        var index = 0;
        for (var j = 0; j < entities1.length; j++) {
            var entity = entities1[j];
            var numPositions = entity.polygon.positions.getValue().length;
            var positions = ;
            for (var p = 0; p < numPositions; ++p) {
                positions.push(cartesians[index]);
                ++index;
            }
            entity.polygon.positions.setValue(positions);
        }
    });
});

Using Cesium 1.36, Chrome and firefox testing browsers.

Is there a way to NOT depend on the terrain and simply drape the data to the ground?
that would be the better solution for me, since I have other data that will float when I add the terrain.

Hi,

I can’t load your data so I’m not sure what the exact problem is, but our Cesium Workshop Tutorial section on Loading and Styling Entities has some good sample code on loading in a GeoJson file and configuring.

Thanks,

Gabby

It looks like there’s a bug in GeoJsonDataSource.js:306 where the logical operator should be ‘or’ rather than ‘and’ to effect what the comment indicates.

// Clamp to ground if there isn’t a height specified

if (coordinates.length === 2 || options.clampToGround) {

billboard.heightReference = HeightReference.CLAMP_TO_GROUND;

}

``

Here’s my Sandcastle example which works as expected after making the above change.

var stkWorldTerrain = new Cesium.CesiumTerrainProvider({

url: ‘//assets.agi.com/stk-terrain/world

});

var viewer = new Cesium.Viewer(‘cesiumContainer’, {

terrainProvider: stkWorldTerrain,

baseLayerPicker: false

});

var geojsonObject = {

‘type’: ‘FeatureCollection’,

‘features’: [{

‘type’: ‘Feature’,

‘geometry’: {

‘type’: ‘Point’,

‘coordinates’: [-75.5966, 40.0386, 5075.9392]

}

}]

};

// Cesium.GeoJsonDataSource.clampToGround = true;

var promise = Cesium.GeoJsonDataSource.load(geojsonObject, {

clampToGround: true,

markerColor: Cesium.Color.AQUA

});

promise.then(function(dataSource) {

viewer.dataSources.add(dataSource);

viewer.zoomTo(dataSource.entities);

});

``

Scott

Hey,

Thanks @Gabby ... I went through the link you shared.

Thanks @Scott for the reply, I did try to fix the bug you mentioned, but still my data shifts just the same.

If you could take a look at my code and sampled data example here, I'd really appreciate it : https://github.com/Ayah93/Testing

Thanks.

Scott-
Re: if (coordinates.length === 2 || options.clampToGround)

is stating two requirements, first, the "length" of two means there is an X and Y, two coordinates. If there is a Z, or three coordinates, clampToGround is not supported. You cannot even include a Z of 0.0, there simply cannot be a third dimension coordinate, it must be a 2 coordinate x-y pair, i.e. length === 2.
AND second, options.clampToGround has been set.
I struggled with this long ago, you must have control of your datasource and be able to completely strip off any 3rd dimension.
Thanks
Jon

Hi Jon,

Are you saying I have to go back to the original data and disable the Z coordinates?
because whether I did what Scott suggested or not.
with the ClampToGround active or not, I still have the same problem.
If I disable the terrain effect, then my data are floating in the air!

Is this solvable? what are my options?

Thanks

I looked at your github and wasted an hour before I realized what was going on.
I edited a copy of your index.html on my development machine, and tried a simple test case, using only the first 3 polygons from your geojson with the Z coordinate removed.
No matter what I did, I could not see them. But they were there, 3 tiny little polygons, and they clamped to ground.
I finally loaded your sampled.geojson and realized that your data is 3-D building faces converted into geojson format.
No, Cesium does not support that type of geojson.
Obviously, you cannot remove the Z from that data and still have 4 vertical walls and sloped rooftops. Removing the Z values would flatten your buildings into pancakes.
Cesium requires other approaches to loading 3D building models -not as a geoJsonDatasource - which I cannot help you with.
I wish Cesium could easily consume ESRI CityEngine 3D buildings, but I don't think there's a user-friendly approach yet.
I was stopped dead in my tracks a couple years ago, trying to get 3D data out of ArcGIS into Cesium. Even the nearly-finished native support for shapefiles in Cesium was abandoned, unfortunately.
The use case for draping polygon data over terrain in Cesium is much simpler than what you were attempting - it must be flat, 2-D polygon data.
Best of luck-
-Jon

<!DOCTYPE html>
<html lang="en">
<head>
  <!-- Use correct character set. -->
  <meta charset="utf-8">
  <!-- Tell IE to use the latest, best version. -->
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <!-- Make the application on mobile take up the full browser screen and disable user scaling. -->
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=false">
  <title>Hello World!</title>
  <script src="../Cesium/Build/Cesium/Cesium.js"></script>

  <style>
      @import url(../Cesium/Build/Cesium/Widgets/widgets.css);
     html, body, #cesiumContainer {
    top: 0px;
    left: 0px;
    position: absolute;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    overflow: hidden;
    z-index: -1;
  }

  </style>
</head>
<body>
  <div id="cesiumContainer"></div>
  
  <script>
  var terrainProvider = new Cesium.CesiumTerrainProvider({
  url : '//assets.agi.com/stk-terrain/world'
});
  var viewer = new Cesium.Viewer('cesiumContainer', {
    terrainProvider: terrainProvider,
    baseLayerPicker: false
});
geojsonOption = {
  clampToGround : true
};
viewer.terrainProvider = terrainProvider;
//Cesium.GeoJsonDataSource.clampToGround = true;
   pinksGeoJsonDataSource = new Cesium.GeoJsonDataSource("PinksSurfPolygons");
  //var promise = Cesium.GeoJsonDataSource.load('pink_first_three_polygons_without_Z_sampled.geojson', geojsonOption, {
  //var promise = pinksGeoJsonDataSource.load('pink_first_three_polygons_without_Z_sampled.geojson', geojsonOption);
  var promise = pinksGeoJsonDataSource.load('sampled.geojson', geojsonOption);
  promise.then(function(dataSource) {
  var entities = pinksGeoJsonDataSource.entities.values;
  for (var i = 0; i < entities.length; i++) {
      var entity = entities[i];
    if(Cesium.defined(entity.polygon)){
      //Set the polygon material color;
      entity.polygon.material = Cesium.Color.RED;
    }
}
    viewer.dataSources.add(pinksGeoJsonDataSource);
    //viewer.zoomTo(promise);
    viewer.zoomTo(pinksGeoJsonDataSource);
  
});
  
  </script>

</body>
</html>

Thank you so much and I appreciate you giving time to help me out with this.
I've wasted days unfortunately trying to figure this out!

To be clear, I do have other data, also geojson facades, not floating, not flattened.. but 3D geojson. So I didn't think this would have that mush of a problem.
The only difference is that the original GML data did not have the terrain effect therefor the data had zero and non-Zero Z's. and it worked perfectly.

Again thank you.
Regards.

That's cool. To be clear, i should have said, Cesium does not support clampToGround for that type of geojson.

Hi,

I can't load your data so I'm not sure what the exact problem is, but our Cesium Workshop Tutorial section on Loading and Styling Entities has some good sample code on loading in a GeoJson file and configuring.

Thanks,
Gabby

Hey Gabby,

Here is a working example, with my problem.
anyway to fix this? Plunker - Changing CZML colors after DS processing

Thanks

Gabby, take a look, but i dont tbink there is a sutuon on the Cesium side. Its a data issue.
Pink,
Id like to know what is your source of the geojson, and what you mean by "original GML data did not have the terrain effect therefor the data had zero and non-Zero Z's. and it worked perfectly.".
What software has a "terrain effect" that solves this issue, so 3D geojson building faces load "perfectly" in cesium?

pink-
I lost track of another thread i meant to reply to. I think you posted on another thread about performance issues loading a large geojsondatasource, which I assume is your "perfect" 3-D geojson building faces, exported with some software with the "terrain effect" enabled.

I went back to work on some old Google Maps overlay code, trying to prove a concept would work. A third-party developer of a Google Map-based mobile Windows expected performance problems would prevent Google Maps from overlaying address labels on our city's 73000 buildings from geojson.

My first attempt using Google Maps data.loadGeoJson(url), to load a 20mb geojson file containing 73000 address point features with a label property, caused Google Maps to hang up for a few minutes. Unacceptable performance.

The solution found on Google developers forum was NOT to use GMaps data.loadGeoJson(url).
Instead, use jQuery.getJSON(url,data) to load the json into an array of features, a feature collection.
An eventlistener on the map 'idle' event, after every pan or zoom, checks if the map is zoomed-in to a high level, 18-20, then for-loops through the array of features to compare each coordinate pair to the current Google Map view extent, adding a marker and label to the map only for a feature within the view, and deleting any marker and label for feature IDs added previously that are outside the view.
This solved the performance issue when using data.loadGeoJson in Google Maps, and made the address labels loaded from geojson redraw quickly, when panning or zooming, when within the scale-dependency.
I intend to try this same approach in Cesium, for a large geosjson file, using Cesium.CustomDataSource to add entities from a feature collection, instead of using Cesium.GeoJsonDataSource. This also has the advantage of more control over styling and classification of individual entities, based on feature property values, than bulk loading with a GeoJsonDataSource.
When doing some heavy lifting with the browser and webGL, loading many geojson features, looking in the cesiumjs library for solutions to browser and webgl performance problems is looking for help in the wrong place. Using scale-dependency, and selectively add only the features within current extents.
I hope you achieve satisfactory results; even floating and shifting, what you have already looks promising.
-Jon

Hey Jon,

I start my project with City GML data, that I import into the citygml importer/exporter, which imports them into my database, then I run some python scripts on them to obtain my results, I then use another python script to export them as geojsons.

I cannot share my data, it's why I share samples.
but here is an example of a 3D facades Geojson https://plnkr.co/edit/3SPBWe5a4yE9hRbZFLoV?p=preview

If you notice the sample.goejson:
some surfaces have all 0 for the Z Value; because they are on the ground
The sides have both zeros and height values,
whist the top surface's z values are all of the constant height.

meanwhile the floating data are not based to zero! they have the height of the terrain plus the constant building height. which causes them to float if the terrain is deactivated. ( here is the difference in the original gml data; because in my extraction of data, I do not mess with the coordinates, I only rewrite them into geojson format)

regarding my question about slow performance, that was due to the floating data as well, it has about 12K buildings and it was taking very long to load, specially that I had it in facades as well, meaning over 53K objects in the geojson file!.
but other regions that only go up to 5K or so, are working just fine.

I hope this answers your question.

Hi,

It seems the problem is basically that the buildings were under the terrain, and by exaggerating the terrain - via trial and error - to a certain number, the shifting phenomena will be corrected.

This is awesome news! I have great hopes of using Cesium for 3D building visualization someday, but ESRI retains a stranglehold on their data formats, and getting CityEngine data out of ArcGIS and into Cesium seemed like an impossible dream. It looks like there may be a path forward for ESRI ArcGIS users, following in your footsteps, converting 3D buildings into CityGML. Thanks for sharing what you can, and good luck to you getting CityGML working well in Cesium!

Hi Gully, I have a 3D data that was originally resulted from ArcScene, edited in Cinema4D and visualized and Cesium.here
(click options => Site Visits => Karakol or Tuekta , then switch 3D/2D button on)

I’m not familiar with CityEngine but if it exports (.vrml) files then it should be -in a way - doable.

Cheers,

Mussab