Coordinates of bounding box of visible map area.

Hi,
How do I get the coordinates of the extremes of the visible area of map (the bounding box).
Cesium loads images depending upon the current visible area, so I wanted to ask is there a built in method defined to get the values.

PS. I have attached two images of what I mean by the bounding box(marked with red color).

If all four corners show a portion of the Earth you can get a ray for each corner using Camera.prototype.getPickRay then obtain coordinates from the ray to Earth intersects using Globe.prototype.pick (change from Cartesian to Cartographic if you need.)

I'm in the same boat. For the first instance, you can create a bounding box from upper left to lower right by utilizing the canvas's dimensions:

var posUL = viewer.camera.pickEllipsoid(new Cesium.Cartesian2(0, 0), Cesium.Ellipsoid.WGS84);
var posLR = viewer.camera.pickEllipsoid(new Cesium.Cartesian2(viewer.canvas.width, viewer.canvas.height), Cesium.Ellipsoid.WGS84);

You can convert each position to degrees if necessary. This works well, unless any part of the globe's horizon is shown within the viewport, such as your second example. I've yet to figure out how to create a bounding box for that case.

Essentially, I need to know the northern most, southern most, eastern most, and western most points on the globe that are currently visible. I haven't seen any properties/methods in the camera or scene that would help me determine this. Does anyone have any ideas?

Here’s a SandCastle that can determine the horizon bounding box. I’ve borrowed the labeling code from the picking SandCastle demo. Rotate logic from Google Earth API math3d.js . The frustum can bind it even further, but this might help for cases where the horizon binds before the frustum does. If you had one of these total surround displays https://www.youtube.com/watch?v=a2e9noEg1zg frustums wouldn’t even exist! Frustums are for the Solid Angle deficient http://en.wikipedia.org/wiki/Solid_angle .
var viewer = new Cesium.Viewer(‘cesiumContainer’);

var CC3=Cesium.Cartesian3;

var camera = viewer.scene.camera;

var ellipsoid = viewer.scene.globe.ellipsoid;

var rad = 6371000; //Earth average radius

var entityN = viewer.entities.add({

label : {

show : false

}

});

var entityW = viewer.entities.add({

label : {

show : false

}

});

var entityS = viewer.entities.add({

label : {

show : false

}

});

var entityE = viewer.entities.add({

label : {

show : false

}

});

Sandcastle.addToolbarButton(‘horizon points’, function() {

//horizon basics

var dist=CC3.magnitude(camera.position);

var angle=Math.asin(rad/dist);

var toSurf=Math.sqrt(Math.pow(dist,2)-Math.pow(rad,2));

//‘horizon arm’

var rotatee = camera.position.clone();

rotatee = CC3.negate(rotatee,new CC3());

CC3.normalize(rotatee,rotatee);

var rotater = new CC3(0,0,1);

CC3.cross(rotatee,rotater,rotater);

var rotated = new CC3();var cartesian = new CC3();

rotated = rotate(rotatee,rotater,angle);

cartesian = scaleVector(toSurf,rotated);

CC3.add(cartesian,camera.position,cartesian);

//north

dropOne(entityN,cartesian);

//east

cartesian = rotate(cartesian,rotatee,Math.PI/2); //rotatee now rotater

dropOne(entityE,cartesian);

//south

cartesian = rotate(cartesian,rotatee,Math.PI/2); //rotatee now rotater

dropOne(entityS,cartesian);

//west

cartesian = rotate(cartesian,rotatee,Math.PI/2); //rotatee now rotater

dropOne(entityW,cartesian);

});

function dropOne(entity,cartesian)

{

if (cartesian) {

var cartographic = ellipsoid.cartesianToCartographic(cartesian);

var longitudeString = Cesium.Math.toDegrees(cartographic.longitude).toFixed(2);

var latitudeString = Cesium.Math.toDegrees(cartographic.latitude).toFixed(2);

entity.position = cartesian;

entity.label.show = true;

entity.label.text = ‘(’ + longitudeString + ', ’ + latitudeString + ‘)’;

} else {

entity.label.show = false;

}

}

function rotate(rotatee,rotater,angle)

{

//rotater: unit vector, angle:radians

//CCW looking from vector tip to vector base

var CC3=Cesium.Cartesian3;var rotated=new CC3();

var c = Math.cos(angle);var s = Math.sin(angle);

var dotScale = CC3.dot(rotatee,rotater,new CC3());

var rotaterScaled = scaleVector(dotScale,rotater);

var vPerpAxis = CC3.subtract(rotatee,rotaterScaled,new CC3()); //using Pythagoras theorem

var comp1 = scaleVector(c,vPerpAxis);

var vPerpPerpAxis = CC3.cross(rotater,vPerpAxis,new CC3()); //perp to both of these

var comp2 = scaleVector(s,vPerpPerpAxis);

return addVectors([rotaterScaled,comp1,comp2]);

}

function scaleVector(scale,vector)

{

var temp = new Cesium.Cartesian3();

temp.x=scalevector.x;temp.y=scalevector.y;temp.z=scale*vector.z;

return temp;

}

function addVectors(vectors)

{

var resultant=new Cesium.Cartesian3(0,0,0);

var i=0;while(i<vectors.length)

{

resultant.x+=vectors[i].x;

resultant.y+=vectors[i].y;

resultant.z+=vectors[i].z;

i+=1;

}

return resultant;

}

``

Awesome. I never would have figured that out on my own. Thanks, Hyper Sonic.

You’re welcome. You can modify it to get any number of horizon points. Currently it’s every 90 degrees, but it could be modified to say every 10 degrees or whatever. It is an approximation as it assumes a perfect sphere, but it isn’t that far off. It doesn’t work correctly if the poles are visible since it seeks the north,west,south,east points of the horizon, but it can be modified for any view point.

Hi HiperSonic,
As per my requirement i have to show the placemarks with in the bounding box. The solution for the first pic like earth is covering all 4 corners is working fine.. but when i tilting or rotating the map in same area where i can see all placemarks i could not get the correct bounding box values as i could see only few placemarks there. Does it need to do something with rotate/tilt angle..?

Could you please help me to get bounding box value after tilting/rotating map.

Regards,
Raghu.

Hi,

I wonder if there is a ‘combined’ result for the above. that would give an estimated area for what the camera is seeing. e.g. see the attached image:

for this, the camera.pickEllipsoid() approach doesn’t work, but the horizon calculation approach gives way too large an area, as it will calculate the horizon in all directions, not just the camera viewing direction.

Akos

I’m in the same boat at @kirkparick. I only need a rectangle of what is in view. I used the code example in my project and it draws a much larger rectangle that follows the curvature of the globe.

I actually figured out my issue. Using the code samples in this thread I cobbled together the following for getting a rectangle of the current view.
//view rectangle
var posUL = cam.pickEllipsoid(new Cesium.Cartesian2(0, 0), Cesium.Ellipsoid.WGS84);
var posLR = cam.pickEllipsoid(new Cesium.Cartesian2(viewer.canvas.width, viewer.canvas.height), Cesium.Ellipsoid.WGS84);
var posLL = cam.pickEllipsoid(new Cesium.Cartesian2(0, viewer.canvas.height), Cesium.Ellipsoid.WGS84);
var posUR = cam.pickEllipsoid(new Cesium.Cartesian2(viewer.canvas.width, 0), Cesium.Ellipsoid.WGS84);

//north
cartographic = ellipsoid.cartesianToCartographic(posUL);
maxLat = Cesium.Math.toDegrees(cartographic.latitude).toFixed(2);

//east
cartesian = rotate(cartesian,rotatee,Math.PI/2); //rotatee now rotater
cartographic = ellipsoid.cartesianToCartographic(posUR);
maxLon = Cesium.Math.toDegrees(cartographic.longitude).toFixed(2);

//south
cartesian = rotate(cartesian,rotatee,Math.PI/2); //rotatee now rotater
cartographic = ellipsoid.cartesianToCartographic(posLR);
minLat = Cesium.Math.toDegrees(cartographic.latitude).toFixed(2);

//west
cartesian = rotate(cartesian,rotatee,Math.PI/2); //rotatee now rotater
cartographic = ellipsoid.cartesianToCartographic(posLL);
minLon = Cesium.Math.toDegrees(cartographic.longitude).toFixed(2);

I use minLon, minLat, maxLon and maxLat for other variables in my code but this did the trick.
-Gerry

@Hyper_Sonic

Hi Hyper_Sonic,

could you give me some details for the calculation of the horizon points.

I used the calculations, but I got too big regions - to understand the calculations:

I cannot associate the calculated angle to a right triangle and the calculation of the toSurf according pythagoras rule.

should it be the acos instead of asin ?

Does anyone has a tip.

Rüdiger

Camera now implements a computeViewRectangle() function that returns an approximate rectangle of the current view.