/**
   * Calculates a rotation vector from the gyroscope angular speed values.
   *
   * @param gyroValues
   * @param deltaRotationVector
   * @param timeFactor
   * @see http://developer.android .com/reference/android/hardware/SensorEvent.html#values
   */
  private void getRotationVectorFromGyro(float timeFactor) {
    // Calculate the angular speed of the sample
    float magnitude =
        (float)
            Math.sqrt(
                Math.pow(gyroscope[0], 2) + Math.pow(gyroscope[1], 2) + Math.pow(gyroscope[2], 2));

    // Normalize the rotation vector if it's big enough to get the axis
    if (magnitude > EPSILON) {
      gyroscope[0] /= magnitude;
      gyroscope[1] /= magnitude;
      gyroscope[2] /= magnitude;
    }

    // Integrate around this axis with the angular speed by the timestep
    // in order to get a delta rotation from this sample over the timestep
    // We will convert this axis-angle representation of the delta rotation
    // into a quaternion before turning it into the rotation matrix.
    float thetaOverTwo = magnitude * timeFactor / 2.0f;
    float sinThetaOverTwo = (float) Math.sin(thetaOverTwo);
    float cosThetaOverTwo = (float) Math.cos(thetaOverTwo);

    deltaVectorGyro[0] = sinThetaOverTwo * gyroscope[0];
    deltaVectorGyro[1] = sinThetaOverTwo * gyroscope[1];
    deltaVectorGyro[2] = sinThetaOverTwo * gyroscope[2];
    deltaVectorGyro[3] = cosThetaOverTwo;

    // Create a new quaternion object base on the latest rotation
    // measurements...
    quatGyroDelta = new Quaternion(deltaVectorGyro[3], Arrays.copyOfRange(deltaVectorGyro, 0, 3));

    // Since it is a unit quaternion, we can just multiply the old rotation
    // by the new rotation delta to integrate the rotation.
    quatGyro = quatGyro.multiply(quatGyroDelta);
  }
  /** Calculates orientation angles from accelerometer and magnetometer output. */
  private void calculateOrientation() {
    // To get the orientation vector from the acceleration and magnetic
    // sensors, we let Android do the heavy lifting. This call will
    // automatically compensate for the tilt of the compass and fail if the
    // magnitude of the acceleration is not close to 9.82m/sec^2. You could
    // perform these steps yourself, but in my opinion, this is the best way
    // to do it.
    if (SensorManager.getRotationMatrix(rotationMatrix, null, acceleration, magnetic)) {
      SensorManager.getOrientation(rotationMatrix, baseOrientation);

      getRotationVectorFromAccelMag(baseOrientation);

      if (!hasOrientation) {
        quatGyro = new Quaternion(quatAccelMag.getScalarPart(), quatAccelMag.getVectorPart());
      }

      hasOrientation = true;
    }
  }
  /** Calculate the fused orientation. */
  private void calculateFusedOrientation() {
    float oneMinusCoeff = (1.0f - filterCoefficient);

    // Apply the complementary filter. // We multiply each rotation by their
    // coefficients (scalar matrices)...

    // Scale our quaternion for the gyroscope
    quatGyro = quatGyro.multiply(filterCoefficient);

    // Scale our quaternion for the accel/mag
    quatAccelMag = quatAccelMag.multiply(oneMinusCoeff);

    // ...and then add the two quaternions together.
    // output[0] = alpha * output[0] + (1 - alpha) * input[0];
    quatGyro = quatGyro.add(quatAccelMag);

    // Now we get a structure we can pass to get a rotation matrix, and then
    // an orientation vector from Android.
    fusedVector[0] = (float) quatGyro.getVectorPart()[0];
    fusedVector[1] = (float) quatGyro.getVectorPart()[1];
    fusedVector[2] = (float) quatGyro.getVectorPart()[2];
    fusedVector[3] = (float) quatGyro.getScalarPart();

    // We need a rotation matrix so we can get the orientation vector...
    // Getting Euler
    // angles from a quaternion is not trivial, so this is the easiest way,
    // but perhaps
    // not the fastest way of doing this.
    SensorManager.getRotationMatrixFromVector(fusedMatrix, fusedVector);

    // Get the fused orienatation
    SensorManager.getOrientation(fusedMatrix, fusedOrientation);
  }