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;
}
``