class_docstr: The fly camera provides a way to explore 3D data using an
  interaction style that resembles a flight simulator.
  
  For this camera, the ``scale_factor`` indicates the speed of the
  camera in units per second, and the ``center`` indicates the
  position of the camera.
  
  Parameters
  ----------
  fov : float
      Field of view. Default 60.0.
  rotation : float | None
      Rotation to use.
  **kwargs : dict
      Keyword arguments to pass to `BaseCamera`.
  
  Notes
  -----
  Interacting with this camera might need a bit of practice.
  The reaction to key presses can be customized by modifying the
  keymap property.
  
  Moving:
  
    * arrow keys, or WASD to move forward, backward, left and right
    * F and C keys move up and down
    * Space bar to brake
  
  Viewing:
  
    * Use the mouse while holding down LMB to control the pitch and yaw.
    * Alternatively, the pitch and yaw can be changed using the keys
      IKJL
    * The camera auto-rotates to make the bottom point down, manual
      rolling can be performed using Q and E.
code: def __init__(self, fov=60, rotation=None, **kwargs):
      # Motion speed vector
      self._speed = np.zeros((6,), "float64")
      self._distance = None
  
      # Acceleration and braking vectors, set from keyboard
      self._brake = np.zeros((6,), "uint8")  # bool-ish
      self._acc = np.zeros((6,), "float64")
  
      # Init rotations
      self._auto_roll = True  # Whether to roll to make Z up
      self._rotation1 = Quaternion()  # The base rotation
      self._rotation2 = Quaternion()  # The delta yaw and pitch rotation
  
      PerspectiveCamera.__init__(self, fov=fov, **kwargs)
  
      # Set camera attributes
      self.rotation1 = (
          rotation.normalize()
          if (rotation is not None)
          else Quaternion()
      )
  
      # To store data at start of interaction
      self._event_value = None
  
      # Whether the mouse-system wants a transform update
      self._update_from_mouse = False
  
      # Mapping that defines keys to thrusters
      self._keymap = {
          keys.UP: (+1, 1),
          keys.DOWN: (-1, 1),
          keys.RIGHT: (+1, 2),
          keys.LEFT: (-1, 2),
          #
          "W": (+1, 1),
          "S": (-1, 1),
          "D": (+1, 2),
          "A": (-1, 2),
          "F": (+1, 3),
          "C": (-1, 3),
          #
          "I": (+1, 4),
          "K": (-1, 4),
          "L": (+1, 5),
          "J": (-1, 5),
          "Q": (+1, 6),
          "E": (-1, 6),
          #
          keys.SPACE: (
              0,
              1,
              2,
              3,
          ),  # 0 means brake, apply to translation
          # keys.ALT: (+5, 1),  # Turbo
      }
  
      # Timer. Each tick we calculate new speed and new position
      self._timer = Timer(0.01, start=False, connect=self.on_timer)
  
imports: from __future__ import division
  import math
  import numpy
  from ...app import Timer
  from ...util.quaternion import Quaternion
  from ...util import keys
  from .perspective import PerspectiveCamera
label_desc: Use image node_id 1 to create a new FlyCamera object from inherited base classes: PerspectiveCamera with example: obj = FlyCamera(fov, rotation)