Zoom to new location and keep camera distance

I’m developing an app where the user can freely move the 3D world around. From a list of locations, the user can choose to zoom there. At the moment, I’m using a fixed distance 5000.0, like this:

// zooming works by assinging the zoom entity a new position, making it
// visible (but transparent), fly there and hiding it again
this.zoomEntity.position = Cesium.Cartesian3.fromDegrees(longitude, latitude, altitude);

this.zoomEntity.point.heightReference =
    altitude === 0.0 ? Cesium.HeightReference.CLAMP_TO_GROUND : Cesium.HeightReference.NONE;

this.zoomEntity.show = true;

console.log("MapView: zooming to: start flying");

this.viewer.flyTo(
    this.zoomEntity,
    {
        offset: new Cesium.HeadingPitchRange(
            this.viewer.camera.heading,
            this.viewer.camera.pitch,
            5000.0)
    }).then(function () {
        this.zoomEntity.show = false;
        console.log("MapView: zooming to: flying finished");
    });

First, is there an easier way than using an transparent entity to fly/zoom to a location? And second, I’d like to get rid of the 5000.0 value. If the user is zoomed further into the map, e.g. to read OpenStreetMap labels, I’d like the final distance to the terrain to be the same. How to implement that? Maybe by picking terrain height in the center of the screen window?

Thanks for your insights and also for making CesiumJS!

Cheers,
Michael

Look here, maybe it helps

Thanks, that helps with the first problem I have, and I can get rid of the zoom entity with that. My second problem still remains.

You can get the camera height with camera.positionCartographic.height, see: https://cesium.com/docs/cesiumjs-ref-doc/Camera.html?classFilter=camera#positionCartographic

You can get that value, and then put that in your flyTo options. Instead of using an invisible entity, you can just pass in a lat/lon (use viewer.camera.flyTo). This is what I did to get the “fly to a location but keep the camera height” in my app here: 🌍 Waking up and Sleeping 🌎 - Live Twitter Map.

If your user is going to be really close to the ground, you may need to sample terrain height at the lat/lon you’re flying to, since a height of 500 meters relative to the ellipsoid in one place on Earth may be underground in another place.

Thanks Omar! I guess I have to sample terrain at the destination (and also at the current camera location). Usually the user will zoom in to read the OSM labels and see hiking paths.

1 Like

I now tried to implement zooming by replacing my invisible zoom-to entity with viewer.camera.flyTo(), and the problem I discovered that viewer.camera.flyTo() has no way to specify an offset using HeadingPitchRange. flyToBoundingSphere() has that options parameter, but not flyTo(). I’d like to keep the camera’s heading and pitch and don’t know how to specify it otherwise. Would it be easys to add the offset parameter? Also I have the feeling that viewer.camera.flyTo(options) flies in a straight line, not like viewer.flyTo(entity, options), which flies in an arc.

It seems there’s already an issue for that :slight_smile: flyTo using heading/pitch/range · Issue #2501 · CesiumGS/cesium · GitHub

I got it to work! At least the “getting the current viewing distance from the camera” part. Here’s my code:

The getCurrentViewingDistance() function returns the exact value that I have to put into the range parameter of a Cesium.HeadingPitchRange object in order to keep the distance to the terrain (in the center of the view). Unfortunately the flyTo() function has no offset parameter (yet), so I have to stick with my zoomEntity.

1 Like