protected void onHorizontalTranslateRel(
      Angle forwardChange, Angle sideChange, ViewInputAttributes.ActionAttributes actionAttribs) {
    View view = this.getView();
    if (view == null) // include this test to ensure any derived implementation performs it
    {
      return;
    }

    if (forwardChange.equals(Angle.ZERO) && sideChange.equals(Angle.ZERO)) {
      return;
    }

    if (view instanceof BasicFlyView) {

      Vec4 forward = view.getForwardVector();
      Vec4 up = view.getUpVector();
      Vec4 side = forward.transformBy3(Matrix.fromAxisAngle(Angle.fromDegrees(90), up));

      forward = forward.multiply3(forwardChange.getDegrees());
      side = side.multiply3(sideChange.getDegrees());
      Vec4 eyePoint = view.getEyePoint();
      eyePoint = eyePoint.add3(forward.add3(side));
      Position newPosition = view.getGlobe().computePositionFromPoint(eyePoint);

      this.setEyePosition(this.uiAnimControl, view, newPosition, actionAttribs);
      view.firePropertyChange(AVKey.VIEW, null, view);
    }
  }
  protected void onHorizontalTranslateRel(
      double forwardInput,
      double sideInput,
      double totalForwardInput,
      double totalSideInput,
      ViewInputAttributes.DeviceAttributes deviceAttributes,
      ViewInputAttributes.ActionAttributes actionAttributes) {
    Angle forwardChange;
    Angle sideChange;

    this.stopGoToAnimators();
    if (actionAttributes.getMouseActions() != null) {
      forwardChange =
          Angle.fromDegrees(
              -totalForwardInput * getScaleValueElevation(deviceAttributes, actionAttributes));
      sideChange =
          Angle.fromDegrees(
              totalSideInput * getScaleValueElevation(deviceAttributes, actionAttributes));
    } else {
      forwardChange =
          Angle.fromDegrees(
              forwardInput * speed * getScaleValueElevation(deviceAttributes, actionAttributes));
      sideChange =
          Angle.fromDegrees(
              sideInput * speed * getScaleValueElevation(deviceAttributes, actionAttributes));
    }
    onHorizontalTranslateRel(forwardChange, sideChange, actionAttributes);
  }
  protected void onRotateView(
      double headingInput,
      double pitchInput,
      double totalHeadingInput,
      double totalPitchInput,
      ViewInputAttributes.DeviceAttributes deviceAttributes,
      ViewInputAttributes.ActionAttributes actionAttributes) {

    Angle headingChange;
    Angle pitchChange;
    this.stopGoToAnimators();
    headingChange =
        Angle.fromDegrees(
            totalHeadingInput * getScaleValueElevation(deviceAttributes, actionAttributes));
    pitchChange =
        Angle.fromDegrees(
            totalPitchInput * getScaleValueElevation(deviceAttributes, actionAttributes));
    onRotateView(headingChange, pitchChange, actionAttributes);
  }
  /**
   * Called when the roll changes due to user input.
   *
   * @param rollInput Change in roll.
   * @param deviceAttributes Attributes of the input device.
   * @param actionAttributes Action that caused the change.
   */
  protected void onRoll(
      double rollInput,
      ViewInputAttributes.DeviceAttributes deviceAttributes,
      ViewInputAttributes.ActionAttributes actionAttributes) {
    Angle rollChange;
    this.stopGoToAnimators();

    rollChange =
        Angle.fromDegrees(rollInput * getScaleValueElevation(deviceAttributes, actionAttributes));

    this.onRoll(rollChange, actionAttributes);
  }