In the gif above, the feature I'm talking about is a line string on the river in center of the image. As you can see, as I'm changing the perspective, the line string appears to be shifting from its place. I'm uploading a geojson for the said feature:

  "type": "FeatureCollection",
  "features": [
      "type": "Feature",
      "geometry": {
        "type": "LineString",
        "coordinates": [

I'm using a very basic geojson here. Currently, there is no 3rd coordinate (or z-coordinate) for the feature. But the same issue occurs even when I supply a z-coordinate.

I'm not getting why the feature is shifting. Also, the feature seems to move below the surface of map. I'm kind of new to this thing so not quite understanding why this is happening.


Yes, you are seeing the feature "below" the surface, which makes it appear to move as the perspective shifts. Currently Cesium's GeoJSON loader does not attempt to "clamp to terrain" any of the features it loads, although that may certainly get added at some future date.

The quickest solution is simply to turn terrain off, so the map is rendered on the WGS84 ellipsoid, and then your GeoJSON river will lie at the same zero-heights as the map, and won't appear to "move around" as the perspective changes.

But you may have reasons why terrain is required to be turned on. In this case, you will need to supply the z-coordinate, in meters. The correct z-coordinate for your sample river here is about 153.7 meters, and if you add this as the 3rd value in each of your lat/lon pairs above, you'll see the line comes pretty close (on the upriver side) to being exactly in-plane with the map with terrain turned on.

Cesium can sample the terrain heights for you (and indeed this is how I got the number 153.7). Load up the Sandcastle Terrain Demo and click the Sample Everest Terrain button, it will place markers at the correct heights on the terrain there. In the left column is the source for this, it makes use of the sampleTerrain function to sample a set of points. You can change the coordinates and sample a different area, like Chicago.

Any GeoJSON features that need to sit on terrain will need their lat/lon locations run through sampleTerrain or similar to get the correct heights. This can be an expensive and asynchronous operation, but it only needs to be done once if you're able to save the resulting heights back into the original GeoJSON file.

Here's a version of the sampleTerrain demo, refactored a bit and targeted near your river sample:

var gridWidth = 21;
var gridHeight = 21;
var centerLatitude = Cesium.Math.toRadians(41.64921533718473);
var centerLongitude = Cesium.Math.toRadians(-87.46780363235473);
var rectangleHalfSize = 0.002;
var e = new Cesium.Rectangle(centerLongitude - rectangleHalfSize,
                             centerLatitude - rectangleHalfSize,
                             centerLongitude + rectangleHalfSize,
                             centerLatitude + rectangleHalfSize);
var terrainSamplePositions = [];
for (var y = 0; y < gridHeight; ++y) {
    for (var x = 0; x < gridWidth; ++x) {
        var longitude = Cesium.Math.lerp(e.west, e.east, x / (gridWidth - 1));
        var latitude = Cesium.Math.lerp(e.south, e.north, y / (gridHeight - 1));
        var position = new Cesium.Cartographic(longitude, latitude);

Cesium.when(Cesium.sampleTerrain(viewer.terrainProvider, 9,
            terrainSamplePositions), function() {
    var ellipsoid = Cesium.Ellipsoid.WGS84;

    //By default, Cesium does not obsure geometry
    //behind terrain. Setting this flag enables that.
    viewer.scene.globe.depthTestAgainstTerrain = true;


    for (var i = 0; i < terrainSamplePositions.length; ++i) {
        var position = terrainSamplePositions[i];

            name : position.height.toFixed(1),
            position : ellipsoid.cartographicToCartesian(position),
            point : {
                pixelSize : 4,
                color : Cesium.Color.WHITE
            label : {
                text : position.height.toFixed(1),
                horizontalOrigin : Cesium.HorizontalOrigin.CENTER,
                scale : 0.5,
                pixelOffset : new Cesium.Cartesian2(0, -10),
                fillColor : Cesium.Color.WHITE
  • Thanks! It worked. Right now I'm using it without the terrain builder but will try Sand Castle terrain demo as well. :) – Ishan May 5 '15 at 5:55
  • My apologies.I meant terrain provider – Ishan May 5 '15 at 6:52
  • 1
    I'm glad it worked! But I'll point out that if you got it working by adding the 153.7 meter height values, then you've got some kind of terrain provider already in play, otherwise the height would be zero. Take a look at the construction options on Viewer, it could be named there or added later. Or go look at some mountains :) – emackey May 5 '15 at 13:00
  • No I'm not using those values. I simply disabled the terrain. 0 is working as ground level value and any value I'm giving for height is displayed properly. – Ishan May 6 '15 at 8:59
  • One more thing I wanted to ask. Is OL3 required to work on Cesium Sandcastle? Putting it other way, can I work on Cesium as a standalone library or with OL3 only? If it can work, can you direct me towards some tutorials where I can start learning. Sorry I'm very new in this field, so don't know much yet. – Ishan May 6 '15 at 9:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.