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. 4 5 #include "content/browser/device_orientation/accelerometer_mac.h" 6 7 #include <math.h> 8 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" 12 13 namespace content { 14 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; 19 } 20 21 AccelerometerMac::~AccelerometerMac() { 22 } 23 24 AccelerometerMac::AccelerometerMac() { 25 } 26 27 const DeviceData* AccelerometerMac::GetDeviceData(DeviceData::Type type) { 28 if (type != DeviceData::kTypeOrientation) 29 return NULL; 30 return GetOrientation(); 31 } 32 33 // Retrieve per-axis orientation values. 34 // 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 37 // 38 // Note: only beta and gamma angles are provided. Alpha is set to zero. 39 // 40 // Returns false in case of error. 41 // 42 const Orientation* AccelerometerMac::GetOrientation() { 43 DCHECK(sudden_motion_sensor_.get()); 44 45 // Retrieve per-axis calibrated values. 46 float axis_value[3]; 47 if (!sudden_motion_sensor_->ReadSensorValues(axis_value)) 48 return NULL; 49 50 // Transform the accelerometer values to W3C draft angles. 51 // 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. 54 // 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: 59 // 60 // x_acc = sin(gamma) 61 // y_acc = - cos(gamma) * sin(beta) 62 // z_acc = cos(beta) * cos(gamma) 63 // 64 // After that the rest is just a bit of trigonometry. 65 // 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 68 // the equations. 69 // 70 const double kRad2deg = 180.0 / M_PI; 71 72 scoped_refptr<Orientation> orientation(new Orientation()); 73 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. 78 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) 84 } 85 if (orientation->gamma() == 90.0) { 86 static double just_less_than_90 = nextafter(90, 0); 87 orientation->set_gamma(just_less_than_90); 88 } 89 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); 95 96 orientation->AddRef(); 97 return orientation.get(); 98 } 99 100 bool AccelerometerMac::Init() { 101 sudden_motion_sensor_.reset(SuddenMotionSensor::Create()); 102 return sudden_motion_sensor_.get() != NULL; 103 } 104 105 } // namespace content 106