While trying to find the best way to obtain altitude at a given position, I found several ways to accomplish this. Unfortunately, each has it's own drawbacks.
The first example was found on the "Cesium Examples from Google Earth".
http://analyticalgraphicsinc.github.io/cesium-google-earth-examples/examples/groundAlt.html
The problem with this method is that it only works if the scene is in 3D. If the scene is 2D or Columbus View the altitude is not correct.
-----
The second way that I discovered is by using the getHeight function on the Globe object. This
works great if the terrain is loaded. The reference documentation eludes to an undefined being returned if no data is found. When using Cesium 1.6 I am never seeing an undefined but am receiving a negative number. This method would be ideal if it would return a Promise (similar to sampleTerrain). If the terrain needed to be loaded, the function would load the terrain and when the height value can be obtained would resolve the Promise and the altitude.
The problem with this function is that you don't know if terrain is loaded or not. I have seen some posts on the forum suggesting that you flyTo a location first. This doesn't exactly work if you have information which is sparsely spread out over the globe.
The good thing about this approach is that if the terrain is loaded you can obtain the height while being in 2D mode.
-------
The third way is to use sampleTerrain. This function returns a Promise and the Promise is resolved when the information is returned. This works great, in all modes (2d, 3d, Columbus View). The problem that I have found with this function is that a typical terrain server can only handle a hand full of requests at a time. This forces the user to issue a single request with locations for several future entities/ geometries and then has to remember what was needed for each entity/geometry.
I have also seen different results between the 3 different functions for the same location. ...
The url for the first way is attached above.
The code for the second and third ways are attached below:
If you want to see the error described with getHeight, load this into sandcastle and look at the console. This will show the negative values which I described above. If you uncomment line 139, and comment out lines 141 through 146 and hit the run button. then go to Mount Everest and then click on the Sample everest terrain button, in the console section you will see different altitudes for the same position.
If anybody has a good way to obtain height information without having to know if terrain is loaded or not, that works well regardless of the scene (2D, Columbus View and 3D) and won't require me to batch up positions to so I won't flood my terrain server I would greatly appreciate it. Otherwise I will start trying a way to figure how not flood my terrain server with requests.
I think the Cesium product and the forum are great!! Any words of wisdom would greatly be appreciated.
Jerry Stoy
var viewer = new Cesium.Viewer('cesiumContainer');
var scene = viewer.scene;
var globe = scene.globe;
globe.depthTestAgainstTerrain = true;
var cesiumTerrainProviderHeightmaps = new Cesium.CesiumTerrainProvider({
url : '//
cesiumjs.org/smallterrain',
credit : 'Terrain data courtesy Analytical Graphics, Inc.'
});
var cesiumTerrainProviderMeshes = new Cesium.CesiumTerrainProvider({
url : '//
cesiumjs.org/stk-terrain/tilesets/world/tiles'
});
var ellipsoidProvider = new Cesium.EllipsoidTerrainProvider();
var vrTheWorldProvider = new Cesium.VRTheWorldTerrainProvider({
url : '//
www.vr-theworld.com/vr-theworld/tiles1.0.0/73/',
credit : 'Terrain data courtesy VT MÄK'
});
viewer.terrainProvider = cesiumTerrainProviderMeshes;
Sandcastle.addToolbarMenu([{
text : 'CesiumTerrainProvider - STK World Terrain meshes',
onselect : function() {
viewer.terrainProvider = cesiumTerrainProviderMeshes;
}
}, {
text : 'CesiumTerrainProvider - Small Terrain heightmaps and water mask',
onselect : function() {
viewer.terrainProvider = cesiumTerrainProviderHeightmaps;
}
}, {
text : 'EllipsoidTerrainProvider',
onselect : function() {
viewer.terrainProvider = ellipsoidProvider;
}
}, {
text : 'VRTheWorldTerrainProvider',
onselect : function() {
viewer.terrainProvider = vrTheWorldProvider;
}
}], 'terrainMenu');
Sandcastle.addToolbarButton('Mount Everest', function() {
if (scene.mode === Cesium.SceneMode.SCENE3D || scene.mode === Cesium.SceneMode.COLUMBUS_VIEW) {
var target = new Cesium.Cartesian3(300770.50872389384, 5634912.131394585, 2978152.2865545116);
var offset = new Cesium.Cartesian3(6344.974098678562, -793.3419798081741, 2499.9508860763162);
viewer.camera.lookAt(target, offset);
viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
} else {
viewer.camera.viewRectangle(new Cesium.Rectangle(1.516102969, 0.48744464, 1.518102969, 0.48944464));
}
}, 'zoomButtons');
//Sandcastle.addToolbarButton('Half Dome', function() {
//if (scene.mode === Cesium.SceneMode.SCENE3D || scene.mode === Cesium.SceneMode.COLUMBUS_VIEW) {
//var target = new Cesium.Cartesian3(-2489625.0836225147, -4393941.44443024, 3882535.
9454173897);
//var offset = new Cesium.Cartesian3(-6857.40902037546, 412.3284835694358, 2147.5545426812023);
//viewer.camera.lookAt(target, offset);
//viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
//} else {
//viewer.camera.viewRectangle(new Cesium.Rectangle(-2.08724538, 0.6577939, -2.08524538, 0.6597939));
//}
//}, 'zoomButtons');
//Sandcastle.addToolbarButton('San Francisco Bay', function() {
//if (scene.mode === Cesium.SceneMode.SCENE3D || scene.mode === Cesium.SceneMode.COLUMBUS_VIEW) {
//var target = new Cesium.Cartesian3(-2708814.85583248, -4254159.450845907, 3891403.
9457429945);
//var offset = new Cesium.Cartesian3(70642.66030209465, -31661.517948317807, 35505.179997143336);
//viewer.camera.lookAt(target, offset);
//viewer.camera.lookAtTransform(Cesium.Matrix4.IDENTITY);
//} else {
//viewer.camera.viewRectangle(new Cesium.Rectangle(-2.147621889, 0.64829691, -2.125621889, 0.67029691));
//}
//}, 'zoomButtons');
var terrainSamplePositions;
function sampleTerrainSuccess() {
var ellipsoid = Cesium.Ellipsoid.WGS84;
var height = null;
viewer.entities.suspendEvents();
viewer.entities.removeAll();
for (var i = 0; i < terrainSamplePositions.length; ++i) {
var position = terrainSamplePositions[i];
//create a clone without the height being populated
var cartoPos = new Cesium.Cartographic(position.longitude, position.latitude);
console.warn('height = ' + position.height);
if(globe) {
height = globe.getHeight(cartoPos);
if(height) {
console.warn('globeHeight = ' + height);
}
}
viewer.entities.add({
name : position.height.toFixed(1),
position : ellipsoid.cartographicToCartesian(position),
billboard : {
verticalOrigin : Cesium.VerticalOrigin.BOTTOM,
scale : 0.7,
image : '../images/facility.gif'
},
label : {
text : position.height.toFixed(1),
horizontalOrigin : Cesium.HorizontalOrigin.CENTER,
scale : 0.3,
pixelOffset : new Cesium.Cartesian2(0, -14),
fillColor : Cesium.Color.RED,
outlineColor : Cesium.Color.WHITE
}
});
}
viewer.entities.resumeEvents();
}
Sandcastle.addToolbarButton('Sample Everest Terrain', function() {
var height;
var gridWidth = 41;
var gridHeight = 41;
var everestLatitude = Cesium.Math.toRadians(27.988257);
var everestLongitude = Cesium.Math.toRadians(86.925145);
var rectangleHalfSize = 0.005;
var e = new Cesium.Rectangle(everestLongitude - rectangleHalfSize, everestLatitude - rectangleHalfSize, everestLongitude + rectangleHalfSize, everestLatitude + rectangleHalfSize);
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);
//terrainSamplePositions.push(position);
if(globe) {
height = globe.getHeight(position);
if(height) {
console.warn('globeHeight = ' + height);
}
}
}
}
Cesium.when(Cesium.sampleTerrain(viewer.terrainProvider, 9, terrainSamplePositions), sampleTerrainSuccess);
}, 'sampleButtons');