blob: 4c66319e5736cea43e5abb0e7a5686921e08d5ab [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_quaternion_fusion_algorithm_using_euler_angles.h"
#include <cmath>
#include "base/logging.h"
#include "services/device/generic_sensor/generic_sensor_consts.h"
#include "services/device/generic_sensor/platform_sensor_fusion.h"
#include "ui/gfx/geometry/angle_conversions.h"
namespace device {
namespace {
void ComputeQuaternionFromEulerAngles(double alpha_in_degrees,
double beta_in_degrees,
double gamma_in_degrees,
double* x,
double* y,
double* z,
double* w) {
if (std::isnan(alpha_in_degrees)) {
// The RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometer
// algorithm cannot measure rotation around the z-axis because it only
// measures the direction of Earth's gravitational field through the
// accelerometer. It sets |alpha| to NaN to reflect that. There is no
// analogue in the world of quaternions so we set |alpha| to 0 to choose
// an arbitrary fixed orientation around the z-axis.
alpha_in_degrees = 0.0;
}
double alpha_in_radians = gfx::DegToRad(alpha_in_degrees);
double beta_in_radians = gfx::DegToRad(beta_in_degrees);
double gamma_in_radians = gfx::DegToRad(gamma_in_degrees);
double cx = std::cos(beta_in_radians / 2);
double cy = std::cos(gamma_in_radians / 2);
double cz = std::cos(alpha_in_radians / 2);
double sx = std::sin(beta_in_radians / 2);
double sy = std::sin(gamma_in_radians / 2);
double sz = std::sin(alpha_in_radians / 2);
*x = sx * cy * cz - cx * sy * sz;
*y = cx * sy * cz + sx * cy * sz;
*z = cx * cy * sz + sx * sy * cz;
*w = cx * cy * cz - sx * sy * sz;
}
constexpr mojom::SensorType GetQuaternionFusedType(bool absolute) {
return absolute ? mojom::SensorType::ABSOLUTE_ORIENTATION_QUATERNION
: mojom::SensorType::RELATIVE_ORIENTATION_QUATERNION;
}
constexpr mojom::SensorType GetEulerAngleSourceType(bool absolute) {
return absolute ? mojom::SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES
: mojom::SensorType::RELATIVE_ORIENTATION_EULER_ANGLES;
}
} // namespace
OrientationQuaternionFusionAlgorithmUsingEulerAngles::
OrientationQuaternionFusionAlgorithmUsingEulerAngles(bool absolute)
: PlatformSensorFusionAlgorithm(GetQuaternionFusedType(absolute),
{GetEulerAngleSourceType(absolute)}) {}
OrientationQuaternionFusionAlgorithmUsingEulerAngles::
~OrientationQuaternionFusionAlgorithmUsingEulerAngles() = default;
bool OrientationQuaternionFusionAlgorithmUsingEulerAngles::GetFusedDataInternal(
mojom::SensorType which_sensor_changed,
SensorReading* fused_reading) {
// Transform the *_ORIENTATION_EULER_ANGLES values to
// *_ORIENTATION_QUATERNION.
DCHECK(fusion_sensor_);
SensorReading reading;
if (!fusion_sensor_->GetSourceReading(which_sensor_changed, &reading))
return false;
ComputeQuaternionFromEulerAngles(
reading.orientation_euler.z /* alpha_in_degrees */,
reading.orientation_euler.x /* beta_in_degrees */,
reading.orientation_euler.y /* gamma_in_degrees */,
&fused_reading->orientation_quat.x.value(),
&fused_reading->orientation_quat.y.value(),
&fused_reading->orientation_quat.z.value(),
&fused_reading->orientation_quat.w.value());
return true;
}
} // namespace device