Fly with camera so the Earth is on the side of the screen

Hi everybody,

I’m struggling with the task how to fly from position A to position B as shown in the pictures. I can get to desired position by using functions such as:
camera.moveRight, camera.moveLeft, …

camera.zoomOut,

camera.twistRight
, which I binded to keyboard buttons.

Camera Position A (green line is going straight up to the sky)

Camera Position B:

If I understand correctly, for camera.flyTo I need to know coordinates, where to fly and orientation or direction of the camera. The thing is I’d need this generic, so if I click on any point on Earth, camera will fly to position B as shown in the picture. So the Earth is on left side of screen and the clicked point is at the rightmost edge of the Earth.

Does anybody have some hints how to calculate parameters for camera.flyTo in order to achieve this?

Thanks a lot for any kind of help

Apparently you want the surface point to be on the horizon. The horizon can be reasonably calculated like I’ve done here: https://groups.google.com/d/msg/cesium-dev/qZ8oLz3hFYU/ESMYti8dxesJ

vect1 from camera.position to (0,0,0)

vect2 from camera position to surface point

So you’d set the angle between vect1 and vect2 to be that of the horizon angle. Do you have a preference of horizon angle? That would narrow it down to a circle of locations. You could place the Earth on the left side of the screen from any of those locations. Does it matter where on that circle the camera is located?

Thanks a lot for a reply.

As for my preferences, I’d stick with the easiest to implement, since my knowledge with 3D computer graphics is very limited. It doesn’t have to look exactly like in the picture, but basically yes. The Earth would take around 1/6 or 1/7 of the screen. The point should be at rightmost point on the globe. The point should be vertically in the middle (same distance to top and bottom of the screen)

I’m really not sure what your specification is for moving the camera’s location and where it’s “target” lookAt is. From your image it appears that the camera itself does not need to be moved, it just needs to be re-oriented for a new look up target at an appropriate altitude as the ground point.

You might be absolutely correct. I’m complete novice with Cesiumjs and 3D graphics at all, so I don’t have many clues what are ways to achieve desired result.
Once again the specification:
After clicking on any given entity on the globe, camera should move/re-orient so that:

  • Earth appears of left side of the screen. Takes area of around 1/7 of the screen.
  • Clicked entity appears at the rightmost point of the globe
  • Clicked entity appears vertically in the middle. Same number of pixels to the top and bottom of screen. (doesn’t have to be pixel perfect of course)

If this doesn’t have to move camera, just re-orientate, could you please give some hints how to calculate new orientation?

Thanks a ton

To achieve approximately the same view in your screenshot I’ve determined about a 12 Mega Meter height which is about a 20 deg horizon angle from Nadir, and camera pitch is about -55deg. In the screenshot the camera is looking North Easterly. Does the heading matter?

Okay here’s what I found out:

// Lets say this is point position
var pointPosition = Cesium.Cartesian3.fromDegrees(20, 20, 0)

// Lets say this is position at the end of a green line

var lineEndPosition = Cesium.Cartesian3.fromDegrees(20, 20, 5000000)

// Now, when I firstly fly to line end

camera.flyTo({

destination : position,

complete : function() { // Then I rotate and zoom out

camera.lookRight(Cesium.Math.toRadians(90)); // Rotate camera 90 degrees right camera.zoomOut(10000000);

}

});

And now is the camera at good enough position. Works for any point at map. The thing is only “flyTo” method comes with nice continuous movement to position. “lookRight” and “zoomOut” performs instantly. If only I could use sort of “dry run” of “lookRight” and “zoomOut”, just to get final camera position/direction and then actually use “flyTo”. Any ideas how to achieve this?

Here’s some math you could use to do the dry run you were referring to. I haven’t tested it, but it should work.

//determine destination for flyTo
var camera = viewer.scene.camera;
var CC3=Cesium.Cartesian3;
var temp = camera.direction.clone();
temp = rotate(temp,camera.up,Cesium.Math.toRadians(90));
temp = CC3.negate(temp);
temp = scaleVector(10000000,temp);
temp = addVectors(temp,camera.position);//temp is now destination for flyTo
function rotate(rotatee,rotater,angle)//from math3d.js GE API
{
//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;
}

``

Thanks. This calculation didn’t works well. It just ended up in a wrong position, but luckily I figured out right calculation:

function calculateCameraPosition(currentCamera) {

var moveScratch = new CC3();

var resultPosition = new CC3();

var resultDirection = new CC3();

var resultUp = new CC3();

var lookScratchQuaternion = new Cesium.Quaternion();

var lookScratchMatrix = new Cesium.Matrix3();

// Rotate

var turnAngle = Cesium.Math.toRadians(90);

var quaternion = Cesium.Quaternion.fromAxisAngle(currentCamera.up, -turnAngle, lookScratchQuaternion);

var rotation = Cesium.Matrix3.fromQuaternion(quaternion, lookScratchMatrix);

var direction = currentCamera.direction;

var up = currentCamera.up;

Cesium.Matrix3.multiplyByVector(rotation, direction, resultDirection);

Cesium.Matrix3.multiplyByVector(rotation, up, resultUp);

// Zoom out

var cameraPosition = currentCamera.position;

CC3.multiplyByScalar(resultDirection, -10000000, moveScratch);

CC3.add(cameraPosition, moveScratch, resultPosition);

return {

destination : resultPosition,

orientation : {

direction : resultDirection,

up : resultUp

}

}

}

``

Ya it should have been -90, as looking from tip to base of the up vector CCW is turn left. Plus it only moved around camera direction vector, I see you wanted to move the entire orientation looking at your code, which requires 2 vectors. I’m glad you got it working!