/**
   * Setup the view to a first person mode (zoom = 0)
   *
   * @param view the orbit view to set into a first person view.
   */
  protected void setupFirstPersonView(OrbitView view) {
    if (view.getZoom() == 0) // already in first person mode
    return;

    Vec4 eyePoint = view.getEyePoint();
    // Center pos at eye pos
    Position centerPosition = wwd.getModel().getGlobe().computePositionFromPoint(eyePoint);
    // Compute pitch and heading relative to center position
    Vec4 normal =
        wwd.getModel()
            .getGlobe()
            .computeSurfaceNormalAtLocation(
                centerPosition.getLatitude(), centerPosition.getLongitude());
    Vec4 north =
        wwd.getModel()
            .getGlobe()
            .computeNorthPointingTangentAtLocation(
                centerPosition.getLatitude(), centerPosition.getLongitude());
    // Pitch
    view.setPitch(Angle.POS180.subtract(view.getForwardVector().angleBetween3(normal)));
    // Heading
    Vec4 perpendicular = view.getForwardVector().perpendicularTo3(normal);
    Angle heading = perpendicular.angleBetween3(north);
    double direction = Math.signum(-normal.cross3(north).dot3(perpendicular));
    view.setHeading(heading.multiply(direction));
    // Zoom
    view.setZoom(0);
    // Center pos
    view.setCenterPosition(centerPosition);
  }
  /**
   * Reset the view to an orbit view state if in first person mode (zoom = 0)
   *
   * @param view the orbit view to reset
   */
  protected void resetOrbitView(OrbitView view) {
    if (view.getZoom() > 0) // already in orbit view mode
    return;

    // Find out where on the terrain the eye is looking at in the viewport center
    // TODO: if no terrain is found in the viewport center, iterate toward viewport bottom until it
    // is found
    Vec4 centerPoint = computeSurfacePoint(view, view.getHeading(), view.getPitch());
    // Reset the orbit view center point heading, pitch and zoom
    if (centerPoint != null) {
      Vec4 eyePoint = view.getEyePoint();
      // Center pos on terrain surface
      Position centerPosition = wwd.getModel().getGlobe().computePositionFromPoint(centerPoint);
      // Compute pitch and heading relative to center position
      Vec4 normal =
          wwd.getModel()
              .getGlobe()
              .computeSurfaceNormalAtLocation(
                  centerPosition.getLatitude(), centerPosition.getLongitude());
      Vec4 north =
          wwd.getModel()
              .getGlobe()
              .computeNorthPointingTangentAtLocation(
                  centerPosition.getLatitude(), centerPosition.getLongitude());
      // Pitch
      view.setPitch(Angle.POS180.subtract(view.getForwardVector().angleBetween3(normal)));
      // Heading
      Vec4 perpendicular = view.getForwardVector().perpendicularTo3(normal);
      Angle heading = perpendicular.angleBetween3(north);
      double direction = Math.signum(-normal.cross3(north).dot3(perpendicular));
      view.setHeading(heading.multiply(direction));
      // Zoom
      view.setZoom(eyePoint.distanceTo3(centerPoint));
      // Center pos
      view.setCenterPosition(centerPosition);
    }
  }
  protected void updateView(ScreenAnnotation control, String controlType) {
    if (this.wwd == null) return;
    if (!(this.wwd.getView() instanceof OrbitView)) return;

    OrbitView view = (OrbitView) this.wwd.getView();
    view.stopAnimations();
    view.stopMovement();

    if (controlType.equals(AVKey.VIEW_PAN)) {
      resetOrbitView(view);
      // Go some distance in the control mouse direction
      Angle heading = computePanHeading(view, control);
      Angle distance = computePanAmount(this.wwd.getModel().getGlobe(), view, control, panStep);
      LatLon newViewCenter =
          LatLon.greatCircleEndPosition(view.getCenterPosition(), heading, distance);
      // Turn around if passing by a pole - TODO: better handling of the pole crossing situation
      if (this.isPathCrossingAPole(newViewCenter, view.getCenterPosition()))
        view.setHeading(Angle.POS180.subtract(view.getHeading()));
      // Set new center pos
      view.setCenterPosition(new Position(newViewCenter, view.getCenterPosition().getElevation()));
    } else if (controlType.equals(AVKey.VIEW_LOOK)) {
      setupFirstPersonView(view);
      Angle heading = computeLookHeading(view, control, headingStep);
      Angle pitch = computeLookPitch(view, control, pitchStep);
      // Check whether the view will still point at terrain
      Vec4 surfacePoint = computeSurfacePoint(view, heading, pitch);
      if (surfacePoint != null) {
        // Change view state
        final Position eyePos = view.getEyePosition(); // Save current eye position
        view.setHeading(heading);
        view.setPitch(pitch);
        view.setZoom(0);
        view.setCenterPosition(eyePos); // Set center at the eye position
      }
    } else if (controlType.equals(AVKey.VIEW_ZOOM_IN)) {
      resetOrbitView(view);
      view.setZoom(computeNewZoom(view, -zoomStep));
    } else if (controlType.equals(AVKey.VIEW_ZOOM_OUT)) {
      resetOrbitView(view);
      view.setZoom(computeNewZoom(view, zoomStep));
    } else if (controlType.equals(AVKey.VIEW_HEADING_LEFT)) {
      resetOrbitView(view);
      view.setHeading(view.getHeading().addDegrees(headingStep));
    } else if (controlType.equals(AVKey.VIEW_HEADING_RIGHT)) {
      resetOrbitView(view);
      view.setHeading(view.getHeading().addDegrees(-headingStep));
    } else if (controlType.equals(AVKey.VIEW_PITCH_UP)) {
      resetOrbitView(view);
      if (view.getPitch().degrees >= pitchStep)
        view.setPitch(view.getPitch().addDegrees(-pitchStep));
    } else if (controlType.equals(AVKey.VIEW_PITCH_DOWN)) {
      resetOrbitView(view);
      if (view.getPitch().degrees <= 90 - pitchStep)
        view.setPitch(view.getPitch().addDegrees(pitchStep));
    } else if (controlType.equals(AVKey.VIEW_FOV_NARROW)) {
      if (view.getFieldOfView().degrees / fovStep >= 4)
        view.setFieldOfView(view.getFieldOfView().divide(fovStep));
    } else if (controlType.equals(AVKey.VIEW_FOV_WIDE)) {
      if (view.getFieldOfView().degrees * fovStep < 120)
        view.setFieldOfView(view.getFieldOfView().multiply(fovStep));
    } else if (controlType.equals(AVKey.VERTICAL_EXAGGERATION_UP)) {
      SceneController sc = this.wwd.getSceneController();
      sc.setVerticalExaggeration(sc.getVerticalExaggeration() + this.veStep);
    } else if (controlType.equals(AVKey.VERTICAL_EXAGGERATION_DOWN)) {
      SceneController sc = this.wwd.getSceneController();
      sc.setVerticalExaggeration(Math.max(1d, sc.getVerticalExaggeration() - this.veStep));
    }

    view.firePropertyChange(AVKey.VIEW, null, view);
  }