How to circle around a model/entity / viewer.flyTo() path

In our current Google Earth application we have an animation sequence that circles around a model.
In GE this is fairly easy: we do a LookAt() sequence (at an appropriate range and tilt) where the heading increases e.g. 10 degrees each step (i.e. at the ‘frameend’ event) until we have completed the circle. The LookAt has a certain speed/duration, and its path is direct.

I tried to achieve the same in Cesium by using the viewer.flyTo(), where the heading increases 10 degrees each step (using the Promise).

The problem is that flyTo() does not have a direct path, but ‘animates’ to the new position, which is not good in this case.

Is there a way to change the path taken by flyTo(), or should I take a different approach?

The camera.lookAt() misses the possibility to set the duration, and does not have a Promise or OnComplete. The camera.flyTo() could be used but requires quite some calculation to position and aim the camera.

Thanks, Willem

Consider calling camera.lookAt each frame

Can do this by putting lookAt into a
viewer.clock.onTick.addEventListener(function(clock){});

``

function.

As I recall lookAt changes the camera’s transform matrix and doesn’t put it back, which might be desired or not matter. You can set the camera’s transform back to the identity matrix (world coordinates) with camera._setTransform(Cesium.Matrix4.IDENTITY);

I finally found time to try out your suggestions.
The circle animation works fine now with a camera.lookAt() at each clock tick.

So thanks to Alexander and Hyper Sonic!

Willem

Glad you got it working!

Hello

I think my question is most likely related to this one, but a bit different:

  • I use lookAt() to set my camera with HeadingPitchRange() on a defined target.

  • Right now I can continuously rotateLeft and rotateRight with a given speed around my target when I press a defined key on the keyboard (as described in the tutorial), it stops when I release the key, this works great.

  • However, I should be able to:
    a) RotateLeft and RotateRight around the target with intervals (e.g. always 36°) when I click the key (Position 1: heading 0; Position 2: heading 36, Position 3: heading: 72 and so on).
    b) It should only do one step (press the key -> rotate 36° -> release key -> press key again -> rotate 36° etc.).
    c) This rotation should be animated (i.e. has a given duration when it goes from P1 to P2; the camera should be centered on the target).

I tried several approaches with lookAt() (here I miss the animation when I try to rotate, it just sets the camera to the new position) and flyTo() (here I miss the range parameter that is available in lookAt() [sure, if I had all positions then it would be possible, but this is definitely to complicated] but can’t find a way that works how it should. Any help is appreciated!

Regards
Martin

For keyboard trigger events you can do viewer.canvas.addEventListener(“keydown”, function(e){console.log(e.keyCode);}, false);

(change the function to something that starts a timer, I believe canvas needs focus to accept keystrokes which by default I don’t think it does)

Say frametime is 16ms and you want to animate for 1000ms, that would be 1000/16 = 62.5 moves per frame. 36deg / 62.5 = 0.584 degrees per frame.

So each frame you’d do something like

var deltaAngle = 0.584/180Math.PI;// /180Math.PI is deg to rad
viewer.clock.onTick.addEventListener(function(clock)
{
if(timerNotDone)
{
viewer.scene.camera.rotate(Cesium.Cartesian3.UNIT_Z, deltaAngle);

    }

});

``

Just fill in the timer logic and the keyDown logic. If you want to be more accurate you can also calculate for changing framerate, and also on the last move frame just move directly to the target rotation value.

Awesome, thanks!

yep, that with the canvas “focusing” is true.

The “animation” works perfectly. With the timer I’m struggling (I do not have much experience in this topic, so I’m happy to learn an easy solution, maybe I tried it the hard way…): I experimented with two approaches: With a new Cesium.clock() as well as Date.now().

  • I can define a Cesium clock as written in the tutorial and it seems to work, but as soon as I use the (new) clock in a onTick.listener it shows me “real” time (what I suppose should provide clock 1, the normal one, but not my artificially one).
  • The next step was to construct the new clock within the onTick.listener, but of course then it gets me every tick a new clock.
  • With Date.now() I’m facing another problem: I tried to get the Date.now() as the current Time and add 1 second to this variable; then I created an onTick.listener that checks when Date.now()+1sec passed and should then stop the animation. Even the function seems to work, it just don’t stop, maybe it does not “catch” the exact timing and of course, after that it continues.
    So my minimum solution at the moment (but at least it works) is a setTimeout() that starts the animation and stops it after 1 sec. I’m aware of the fact that it does not get me the exact desired angle due to possible framerate issues, but this could be fixed with a direct shift after 1 sec to the new position.

You could probably use Cesium.clock as well, but JavaScript’s currentTime=new Date().getTime(); works fine (milliseconds.) Just record the value to compare to next time to get frametime. Although the onTick listener function is passed the clock parameter you don’t have to use it, depends if you want your events based on simulation time or ‘wall’ time.

Say 400ms have passed, so there’s 600ms left. Say frametime is 16ms, 600/16 = 37.5 more moves to make. Say you have 10 degrees remaining, so 10/37.5 = 0.2666 degrees to rotate this frame.