SceneView lock camera on SetView

859
1
01-17-2019 09:29 AM
BjørnarSundsbø1
Occasional Contributor II

Hello,

When performing SceneView.SetViewpoint with a viewpoint without camera details, the scene snaps to 2D view where the camera looks straight down. What I'm looking at, is the ability for the user to toggle a lock of the camera orientation when performing SetView operations.

Scenario 1:

When synchronizing the scene with a MapView, and I navigate the MapView, I imagine it might be interesting to keep the camera at the same angle and heading as before the operation.

Scenario 2:

Having found "the perfect camera angle", and I i.e. zoom to a vehicle in some list outside of the map itself, I would like to keep the current camera orientation.

I'm not sure if this is some crackpot developer idea that doesn't go well with real life usage, or if the idea has some merit. Before I dig too deep, I would love to get some feedback if it makes sense at all

Known issues:

- Avoid ending up with for example a 45 degree angle horizon

- Ending up inside of mountains or buildings (might be able to recover by getting camera point elevation, and Elevate until I'm at a safe distance?)

- Avoid synchronize camera adjustments after SetViewpoint back to the MapView (scenario 1)

- Probably can't do this when zooming to an envelope

- Inconsistensies in behavior (see previous issue)

0 Kudos
1 Reply
BjørnarSundsbø1
Occasional Contributor II

Currently we believe it makes sense to keep the camera angle locked when the user choose to.

Using the concept from GeoView viewpoint synchronization—ArcGIS Runtime SDK for .NET Samples | ArcGIS for Developers , I have changed the code like this.

     private void OnNavigationComplete(object sender, EventArgs eventArgs)
        {
            // Get a reference to the MapView or SceneView that raised the event
            GeoView sendingView = (GeoView)sender;

            // Get a reference to the other view
            if (sendingView is MapView)
            {
                // Intentionally not doing anything here
            }
            else
            {
                MyMapView.SetViewpoint(sendingView.GetCurrentViewpoint(ViewpointType.CenterAndScale));
            }           
        }

        private void OnViewpointChanged(object sender, EventArgs e)
        {
            // Get the MapView or SceneView that sent the event
            GeoView sendingView = sender as GeoView;

            // Only take action if this geoview is the one that the user is navigating.
            // Viewpoint changed events are fired when SetViewpoint is called; This check prevents a feedback loop
            if (sendingView.IsNavigating)
            {
                // If the MapView sent the event, update the SceneView's viewpoint
                if (sender is MapView)
                {
                    // Get the viewpoint
                    Viewpoint updateViewpoint = MyMapView.GetCurrentViewpoint(ViewpointType.CenterAndScale);
                    UpdateSceneWithCameraLock(updateViewpoint);
                }
                else // Else, update the MapView's viewpoint
                {
                    // Get the viewpoint
                    Viewpoint updateViewpoint = MySceneView.GetCurrentViewpoint(ViewpointType.CenterAndScale);

                    // Set the viewpoint
                    MyMapView.SetViewpoint(updateViewpoint);
                }
            }
        }

        private void UpdateSceneWithCameraLock(Viewpoint updateViewpoint)
        {
            MapPoint lookAtPoint = updateViewpoint.TargetGeometry as MapPoint ?? updateViewpoint.TargetGeometry.Extent.GetCenter();
            var lookAtPointTransformed = (MapPoint)GeometryEngine.Project(lookAtPoint, MySceneView.SpatialReference);
            // Keep current camera settings
            var previousCamera = MySceneView.Camera;

            // Set new viewpoint
            MySceneView.SetViewpoint(updateViewpoint);
            var newCamera = MySceneView.Camera;
            // Tilt camera, looking at new center point
            var targetCamera = new Camera(lookAtPointTransformed, newCamera.Location.Z, previousCamera.Heading, previousCamera.Pitch, 0);
            MySceneView.SetViewpointCamera(targetCamera);
        }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

I tilt the camera to a 70 degree pitch. I then pan around the MapView. On every change of MapView.ViewpointChanged, the camera pitch for the scene is reduced every the event is raised for MapView, resulting in a pitch of 0 towards the end. The heading is also adjusted towards 0. This effect is extremely visible around the equator, but less so in the north. Why is this, and how can I avoid?

I haven't found a better way than this to keep the camera altitude than first calling SetViewpoint, and then moving the camera. Suggestions are welcome for doing both in the same operation. I feel like I'm missing a method on the Camera to set a new lookAtPoint while maintaining the rest of the parameters. While this example is based on synchronized MapView with SceneView, I would like to do the same for zooming to an extent or points, while keeping the same camera orientation.

0 Kudos