blob: 5bb3c1e3943d8b203ad4db4b85d0be702d79f681 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "services/device/generic_sensor/orientation_euler_angles_fusion_algorithm_using_quaternion.h"
#include <cmath>
#include "base/logging.h"
#include "services/device/generic_sensor/orientation_util.h"
#include "services/device/generic_sensor/platform_sensor_fusion.h"
namespace device {
namespace {
// Helper function to convert a quaternion to a rotation matrix. x, y, z, w
// are values of a quaternion representing the orientation of the device in
// 3D space. Returns a 9 element rotation matrix:
// r[ 0] r[ 1] r[ 2]
// r[ 3] r[ 4] r[ 5]
// r[ 6] r[ 7] r[ 8]
std::vector<double> ComputeRotationMatrixFromQuaternion(double x,
double y,
double z,
double w) {
std::vector<double> r(9);
double sq_x = 2 * x * x;
double sq_y = 2 * y * y;
double sq_z = 2 * z * z;
double x_y = 2 * x * y;
double z_w = 2 * z * w;
double x_z = 2 * x * z;
double y_w = 2 * y * w;
double y_z = 2 * y * z;
double x_w = 2 * x * w;
r[0] = 1 - sq_y - sq_z;
r[1] = x_y - z_w;
r[2] = x_z + y_w;
r[3] = x_y + z_w;
r[4] = 1 - sq_x - sq_z;
r[5] = y_z - x_w;
r[6] = x_z - y_w;
r[7] = y_z + x_w;
r[8] = 1 - sq_x - sq_y;
return r;
}
void ComputeEulerAnglesFromQuaternion(double x,
double y,
double z,
double w,
double* alpha_in_degrees,
double* beta_in_degrees,
double* gamma_in_degrees) {
std::vector<double> rotation_matrix =
ComputeRotationMatrixFromQuaternion(x, y, z, w);
device::ComputeOrientationEulerAnglesFromRotationMatrix(
rotation_matrix, alpha_in_degrees, beta_in_degrees, gamma_in_degrees);
}
constexpr mojom::SensorType GetEulerAngleFusedType(bool absolute) {
return absolute ? mojom::SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES
: mojom::SensorType::RELATIVE_ORIENTATION_EULER_ANGLES;
}
constexpr mojom::SensorType GetQuaternionSourceType(bool absolute) {
return absolute ? mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION
: mojom::SensorType::RELATIVE_ORIENTATION_QUATERNION;
}
} // namespace
OrientationEulerAnglesFusionAlgorithmUsingQuaternion::
OrientationEulerAnglesFusionAlgorithmUsingQuaternion(bool absolute)
: PlatformSensorFusionAlgorithm(GetEulerAngleFusedType(absolute),
{GetQuaternionSourceType(absolute)}) {}
OrientationEulerAnglesFusionAlgorithmUsingQuaternion::
~OrientationEulerAnglesFusionAlgorithmUsingQuaternion() = default;
bool OrientationEulerAnglesFusionAlgorithmUsingQuaternion::GetFusedDataInternal(
mojom::SensorType which_sensor_changed,
SensorReading* fused_reading) {
// Transform the *_ORIENTATION_QUATERNION values to
// *_ORIENTATION_EULER_ANGLES.
DCHECK(fusion_sensor_);
SensorReading reading;
if (!fusion_sensor_->GetSourceReading(which_sensor_changed, &reading))
return false;
ComputeEulerAnglesFromQuaternion(
reading.orientation_quat.x, reading.orientation_quat.y,
reading.orientation_quat.z, reading.orientation_quat.w,
&fused_reading->orientation_euler.z.value() /* alpha_in_degrees */,
&fused_reading->orientation_euler.x.value() /* beta_in_degrees */,
&fused_reading->orientation_euler.y.value() /* gamma_in_degrees */);
return true;
}
} // namespace device