Coordinates of bounding box of visible map area.

3,006 views
Skip to first unread message

gaurs...@gmail.com

unread,
Mar 13, 2015, 4:11:15 PM3/13/15
to cesiu...@googlegroups.com
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).
horizon_covered.png
horizon_visible.png

Hyper Sonic

unread,
Mar 14, 2015, 5:13:18 PM3/14/15
to cesiu...@googlegroups.com
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.)

kirkpatr...@gmail.com

unread,
Apr 21, 2015, 10:41:47 AM4/21/15
to cesiu...@googlegroups.com
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?

Hyper Sonic

unread,
Apr 22, 2015, 9:15:10 PM4/22/15
to cesiu...@googlegroups.com, kirkpatr...@gmail.com
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=scale*vector.x;temp.y=scale*vector.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;
}

kirkpatr...@gmail.com

unread,
Apr 23, 2015, 9:47:13 AM4/23/15
to cesiu...@googlegroups.com, kirkpatr...@gmail.com
Awesome. I never would have figured that out on my own. Thanks, Hyper Sonic.

Hyper Sonic

unread,
Apr 23, 2015, 11:38:15 AM4/23/15
to cesiu...@googlegroups.com, kirkpatr...@gmail.com
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.

raghu....@gmail.com

unread,
Oct 9, 2015, 1:35:47 PM10/9/15
to cesium-dev, kirkpatr...@gmail.com
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.

Ákos Maróy

unread,
Apr 24, 2016, 3:07:40 PM4/24/16
to cesium-dev, kirkpatr...@gmail.com
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

Gerry Creighton

unread,
Feb 2, 2017, 11:10:50 AM2/2/17
to cesium-dev, kirkpatr...@gmail.com
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.

Gerry Creighton

unread,
Feb 2, 2017, 1:35:02 PM2/2/17
to cesium-dev, kirkpatr...@gmail.com
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
Reply all
Reply to author
Forward
0 new messages