| // 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 |