Update, March 2016: Cesium 1.19 has been released with a new function, Camera.computeViewRectangle, that does as good a job as can be done computing the view rectangle, given the caveats below. I now recommend using it instead of sniffing the imagery tiles as shown here. I'm keeping the original answer below because it explains the problems of computing a simple view rectangle on a 3D view of the globe.
Original answer: There's no easy mapping from a 3D globe to a 2D zoom level. On a round globe, different tiles are at different distances from the 3D camera: Some tiles are draped over the horizon, or viewed at steep angles. The camera may be down low near a point on the ground, but looking out towards the horizon, so it can see high-level tiles in the foreground and low-level ones in the background.
You can see this in action, graphically, using the Cesium Inspector.
- Click the tiny
+
sign next to + Terrain
at the bottom of Cesium Inspector.
- Next, put a checkmark on
Show tile coordinates
.
- Zoom the camera around and watch the tiles change.
For an even deeper understanding, do the above an then continue:
- Zoom the camera close to a city or spot on the ground.
- Use middle-drag (or ctrl-left-drag) to tilt the view towards the horizon.
- Put a checkmark on
Suspend LOD Update
.
- Straighten out the camera and back up a little bit, to see tiles floating in space. Note the ones that were near the camera (when Level-of-Detail was suspended) are small and high-level, but the ones that were visible in the distance are large and low-level.
Now that you've seen that several different tile levels contribute to a single camera view, I'll share some highly un-official code. The Cesium Inspector is making use of some private API points to snoop on the tiles being loaded, and since this is open-source, you can snoop on those tiles too. Using private APIs is not supported and can break in any future release of Cesium. Ready? Open up a copy of Cesium Sandcastle and paste in the following code:
// This code reports the min/max values of ANY tiles being considered for rendering.
// The values will change asynchronously as the server sends higher-level tiles.
var viewer = new Cesium.Viewer('cesiumContainer');
var west, south, east, north;
var toolbar = document.getElementById('toolbar');
viewer.clock.onTick.addEventListener(function () {
west = south = 999;
east = north = -999;
// CAUTION: Accessing _private variables is not officially supported and
// the API can break at any time without warning.
var tilesToRender = viewer.scene.globe._surface.tileProvider._tilesToRenderByTextureCount;
if (Cesium.defined(tilesToRender)) {
var numArrays = tilesToRender.length;
for (var j = 0; j < numArrays; ++j) {
var quadtrees = tilesToRender[j];
if (Cesium.defined(quadtrees)) {
var numTrees = quadtrees.length;
for (var i = 0; i < numTrees; ++i) {
var rectangle = quadtrees[i].rectangle;
west = Math.min(west, rectangle.west);
south = Math.min(south, rectangle.south);
east = Math.max(east, rectangle.east);
north = Math.max(north, rectangle.north);
}
}
}
}
if (west > 900) {
toolbar.innerHTML = 'Location not known.';
} else {
toolbar.innerHTML =
'West: ' + Cesium.Math.toDegrees(west).toFixed(4) + '<br/>' +
'South: ' + Cesium.Math.toDegrees(south).toFixed(4) + '<br/>' +
'East: ' + Cesium.Math.toDegrees(east).toFixed(4) + '<br/>' +
'North: ' + Cesium.Math.toDegrees(north).toFixed(4);
}
});
If you move the camera around in this demo, you can spot the problems with this method. When the camera is far enough from the Earth, the reported coordinates are the entire planet, but as you get close to a particular location, the reported coordinates narrow down to just some tiles around that location. However, if you tilt the camera towards the horizon, then the reported coordinates include tiles stretching out beyond that horizon, and the camera ends up near one of the sides or corners of those coordinates, not the center. Still, there may be applications where it is handy to have a rough idea of what tiles are visible at all in the 3D scene.