1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <cmath>
6 
7 #include "base/memory/ref_counted.h"
8 #include "base/numerics/math_constants.h"
9 #include "base/test/task_environment.h"
10 #include "services/device/generic_sensor/fake_platform_sensor_fusion.h"
11 #include "services/device/generic_sensor/relative_orientation_euler_angles_fusion_algorithm_using_accelerometer.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 
14 namespace device {
15 
16 namespace {
17 
18 class RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest
19     : public testing::Test {
20  public:
RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest()21   RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest() {
22     auto fusion_algorithm = std::make_unique<
23         RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometer>();
24     fusion_algorithm_ = fusion_algorithm.get();
25     fake_fusion_sensor_ = base::MakeRefCounted<FakePlatformSensorFusion>(
26         std::move(fusion_algorithm));
27     fusion_algorithm_->set_fusion_sensor(fake_fusion_sensor_.get());
28     EXPECT_EQ(1UL, fusion_algorithm_->source_types().size());
29   }
30 
VerifyRelativeOrientationEulerAngles(double acceleration_x,double acceleration_y,double acceleration_z,double expected_beta_in_degrees,double expected_gamma_in_degrees)31   void VerifyRelativeOrientationEulerAngles(double acceleration_x,
32                                             double acceleration_y,
33                                             double acceleration_z,
34                                             double expected_beta_in_degrees,
35                                             double expected_gamma_in_degrees) {
36     SensorReading reading;
37     reading.accel.x = acceleration_x;
38     reading.accel.y = acceleration_y;
39     reading.accel.z = acceleration_z;
40 
41     fake_fusion_sensor_->SetSensorReading(mojom::SensorType::ACCELEROMETER,
42                                           reading,
43                                           true /* sensor_reading_success */);
44 
45     SensorReading fused_reading;
46     EXPECT_TRUE(fusion_algorithm_->GetFusedData(
47         mojom::SensorType::ACCELEROMETER, &fused_reading));
48 
49     EXPECT_TRUE(
50         std::isnan(fused_reading.orientation_euler.z.value() /* alpha */));
51     EXPECT_DOUBLE_EQ(expected_beta_in_degrees,
52                      fused_reading.orientation_euler.x /* beta */);
53     EXPECT_DOUBLE_EQ(expected_gamma_in_degrees,
54                      fused_reading.orientation_euler.y /* gamma */);
55   }
56 
57  protected:
58   base::test::TaskEnvironment task_environment_;
59   scoped_refptr<FakePlatformSensorFusion> fake_fusion_sensor_;
60   RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometer*
61       fusion_algorithm_;
62 };
63 
64 }  // namespace
65 
TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,NoAccelerometerReading)66 TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,
67        NoAccelerometerReading) {
68   SensorReading reading;
69   fake_fusion_sensor_->SetSensorReading(mojom::SensorType::ACCELEROMETER,
70                                         reading,
71                                         false /* sensor_reading_success */);
72   SensorReading fused_reading;
73   EXPECT_FALSE(fusion_algorithm_->GetFusedData(mojom::SensorType::ACCELEROMETER,
74                                                &fused_reading));
75 }
76 
77 // Tests a device resting flat.
TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,NeutralOrientation)78 TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,
79        NeutralOrientation) {
80   double acceleration_x = 0.0;
81   double acceleration_y = 0.0;
82   double acceleration_z = base::kMeanGravityDouble;
83 
84   double expected_beta_in_degrees = 0.0;
85   double expected_gamma_in_degrees = 0.0;
86 
87   VerifyRelativeOrientationEulerAngles(acceleration_x, acceleration_y,
88                                        acceleration_z, expected_beta_in_degrees,
89                                        expected_gamma_in_degrees);
90 }
91 
92 // Tests an upside-down device, such that the W3C boundary [-180, 180) causes
93 // the beta value to become negative.
TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,UpsideDown)94 TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,
95        UpsideDown) {
96   double acceleration_x = 0.0;
97   double acceleration_y = 0.0;
98   double acceleration_z = -base::kMeanGravityDouble;
99 
100   double expected_beta_in_degrees = -180.0;
101   double expected_gamma_in_degrees = 0.0;
102 
103   VerifyRelativeOrientationEulerAngles(acceleration_x, acceleration_y,
104                                        acceleration_z, expected_beta_in_degrees,
105                                        expected_gamma_in_degrees);
106 }
107 
108 // Tests for positive beta value before the device is completely upside-down.
TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,BeforeUpsideDownBoundary)109 TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,
110        BeforeUpsideDownBoundary) {
111   double acceleration_x = 0.0;
112   double acceleration_y = -base::kMeanGravityDouble / 2.0;
113   double acceleration_z = -base::kMeanGravityDouble / 2.0;
114 
115   double expected_beta_in_degrees = 135.0;
116   double expected_gamma_in_degrees = 0.0;
117 
118   VerifyRelativeOrientationEulerAngles(acceleration_x, acceleration_y,
119                                        acceleration_z, expected_beta_in_degrees,
120                                        expected_gamma_in_degrees);
121 }
122 
123 // Tests a device lying on its top-edge.
TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,TopEdge)124 TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,
125        TopEdge) {
126   double acceleration_x = 0.0;
127   double acceleration_y = base::kMeanGravityDouble;
128   double acceleration_z = 0.0;
129 
130   double expected_beta_in_degrees = -90.0;
131   double expected_gamma_in_degrees = 0.0;
132 
133   VerifyRelativeOrientationEulerAngles(acceleration_x, acceleration_y,
134                                        acceleration_z, expected_beta_in_degrees,
135                                        expected_gamma_in_degrees);
136 }
137 
138 // Tests before a device is completely on its top-edge.
TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,BeforeTopEdgeBoundary)139 TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,
140        BeforeTopEdgeBoundary) {
141   double acceleration_x = 0.0;
142   double acceleration_y = base::kMeanGravityDouble / 2.0;
143   double acceleration_z = base::kMeanGravityDouble / 2.0;
144 
145   double expected_beta_in_degrees = -45.0;
146   double expected_gamma_in_degrees = 0.0;
147 
148   VerifyRelativeOrientationEulerAngles(acceleration_x, acceleration_y,
149                                        acceleration_z, expected_beta_in_degrees,
150                                        expected_gamma_in_degrees);
151 }
152 
153 // Tests a device lying on its bottom-edge.
TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,BottomEdge)154 TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,
155        BottomEdge) {
156   double acceleration_x = 0.0;
157   double acceleration_y = -base::kMeanGravityDouble;
158   double acceleration_z = 0.0;
159 
160   double expected_beta_in_degrees = 90.0;
161   double expected_gamma_in_degrees = 0.0;
162 
163   VerifyRelativeOrientationEulerAngles(acceleration_x, acceleration_y,
164                                        acceleration_z, expected_beta_in_degrees,
165                                        expected_gamma_in_degrees);
166 }
167 
168 // Tests before a device is completely on its bottom-edge.
TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,BeforeBottomEdgeBoundary)169 TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,
170        BeforeBottomEdgeBoundary) {
171   double acceleration_x = 0.0;
172   double acceleration_y = -base::kMeanGravityDouble / 2.0;
173   double acceleration_z = base::kMeanGravityDouble / 2.0;
174 
175   double expected_beta_in_degrees = 45.0;
176   double expected_gamma_in_degrees = 0.0;
177 
178   VerifyRelativeOrientationEulerAngles(acceleration_x, acceleration_y,
179                                        acceleration_z, expected_beta_in_degrees,
180                                        expected_gamma_in_degrees);
181 }
182 
183 // Tests a device lying on its left-edge.
TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,LeftEdge)184 TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,
185        LeftEdge) {
186   double acceleration_x = -base::kMeanGravityDouble;
187   double acceleration_y = 0.0;
188   double acceleration_z = 0.0;
189 
190   double expected_beta_in_degrees = 0.0;
191   double expected_gamma_in_degrees = -90.0;
192 
193   VerifyRelativeOrientationEulerAngles(acceleration_x, acceleration_y,
194                                        acceleration_z, expected_beta_in_degrees,
195                                        expected_gamma_in_degrees);
196 }
197 
198 // Tests for negative gamma value before the device is completely on its left
199 // side.
TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,BeforeLeftEdgeBoundary)200 TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,
201        BeforeLeftEdgeBoundary) {
202   double acceleration_x = -base::kMeanGravityDouble / std::sqrt(2.0);
203   double acceleration_y = 0.0;
204   double acceleration_z = base::kMeanGravityDouble / std::sqrt(2.0);
205 
206   double expected_beta_in_degrees = 0.0;
207   double expected_gamma_in_degrees = -45.0;
208 
209   VerifyRelativeOrientationEulerAngles(acceleration_x, acceleration_y,
210                                        acceleration_z, expected_beta_in_degrees,
211                                        expected_gamma_in_degrees);
212 }
213 
214 // Tests a device lying on its right-edge, such that the W3C boundary [-90, 90)
215 // causes the gamma value to become negative.
TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,RightEdge)216 TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,
217        RightEdge) {
218   double acceleration_x = base::kMeanGravityDouble;
219   double acceleration_y = 0.0;
220   double acceleration_z = 0.0;
221 
222   double expected_beta_in_degrees = 0.0;
223   double expected_gamma_in_degrees = -90.0;
224 
225   VerifyRelativeOrientationEulerAngles(acceleration_x, acceleration_y,
226                                        acceleration_z, expected_beta_in_degrees,
227                                        expected_gamma_in_degrees);
228 }
229 
230 // Tests for positive gamma value before the device is completely on its right
231 // side.
TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,BeforeRightEdgeBoundary)232 TEST_F(RelativeOrientationEulerAnglesFusionAlgorithmUsingAccelerometerTest,
233        BeforeRightEdgeBoundary) {
234   double acceleration_x = base::kMeanGravityDouble / std::sqrt(2.0);
235   double acceleration_y = 0.0;
236   double acceleration_z = base::kMeanGravityDouble / std::sqrt(2.0);
237 
238   double expected_beta_in_degrees = 0.0;
239   double expected_gamma_in_degrees = 45.0;
240 
241   VerifyRelativeOrientationEulerAngles(acceleration_x, acceleration_y,
242                                        acceleration_z, expected_beta_in_degrees,
243                                        expected_gamma_in_degrees);
244 }
245 
246 }  // namespace device
247