1 // Copyright (c) 2012 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.
5 #include "content/browser/device_orientation/accelerometer_mac.h"
9 #include "base/logging.h"
10 #include "content/browser/device_orientation/orientation.h"
11 #include "third_party/sudden_motion_sensor/sudden_motion_sensor_mac.h"
15 // Create a AccelerometerMac object and return NULL if no valid sensor found.
16 DataFetcher
* AccelerometerMac::Create() {
17 scoped_ptr
<AccelerometerMac
> accelerometer(new AccelerometerMac
);
18 return accelerometer
->Init() ? accelerometer
.release() : NULL
;
21 AccelerometerMac::~AccelerometerMac() {
24 AccelerometerMac::AccelerometerMac() {
27 const DeviceData
* AccelerometerMac::GetDeviceData(DeviceData::Type type
) {
28 if (type
!= DeviceData::kTypeOrientation
)
30 return GetOrientation();
33 // Retrieve per-axis orientation values.
35 // Axes and angles are defined according to the W3C DeviceOrientation Draft.
36 // See here: http://dev.w3.org/geo/api/spec-source-orientation.html
38 // Note: only beta and gamma angles are provided. Alpha is set to zero.
40 // Returns false in case of error.
42 const Orientation
* AccelerometerMac::GetOrientation() {
43 DCHECK(sudden_motion_sensor_
.get());
45 // Retrieve per-axis calibrated values.
47 if (!sudden_motion_sensor_
->ReadSensorValues(axis_value
))
50 // Transform the accelerometer values to W3C draft angles.
52 // Accelerometer values are just dot products of the sensor axes
53 // by the gravity vector 'g' with the result for the z axis inverted.
55 // To understand this transformation calculate the 3rd row of the z-x-y
56 // Euler angles rotation matrix (because of the 'g' vector, only 3rd row
57 // affects to the result). Note that z-x-y matrix means R = Ry * Rx * Rz.
58 // Then, assume alpha = 0 and you get this:
61 // y_acc = - cos(gamma) * sin(beta)
62 // z_acc = cos(beta) * cos(gamma)
64 // After that the rest is just a bit of trigonometry.
66 // Also note that alpha can't be provided but it's assumed to be always zero.
67 // This is necessary in order to provide enough information to solve
70 const double kRad2deg
= 180.0 / M_PI
;
72 scoped_refptr
<Orientation
> orientation(new Orientation());
74 orientation
->set_beta(kRad2deg
* atan2(-axis_value
[1], axis_value
[2]));
75 orientation
->set_gamma(kRad2deg
* asin(axis_value
[0]));
76 // TODO(aousterh): should absolute_ be set to false here?
77 // See crbug.com/136010.
79 // Make sure that the interval boundaries comply with the specification. At
80 // this point, beta is [-180, 180] and gamma is [-90, 90], but the spec has
81 // the upper bound open on both.
82 if (orientation
->beta() == 180.0) {
83 orientation
->set_beta(-180.0); // -180 == 180 (upside-down)
85 if (orientation
->gamma() == 90.0) {
86 static double just_less_than_90
= nextafter(90, 0);
87 orientation
->set_gamma(just_less_than_90
);
90 // At this point, DCHECKing is paranoia. Never hurts.
91 DCHECK_GE(orientation
->beta(), -180.0);
92 DCHECK_LT(orientation
->beta(), 180.0);
93 DCHECK_GE(orientation
->gamma(), -90.0);
94 DCHECK_LT(orientation
->gamma(), 90.0);
96 orientation
->AddRef();
97 return orientation
.get();
100 bool AccelerometerMac::Init() {
101 sudden_motion_sensor_
.reset(SuddenMotionSensor::Create());
102 return sudden_motion_sensor_
.get() != NULL
;
105 } // namespace content