// Copyright (c) 2012 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 "content/browser/device_orientation/accelerometer_mac.h" #include #include "base/logging.h" #include "content/browser/device_orientation/orientation.h" #include "third_party/sudden_motion_sensor/sudden_motion_sensor_mac.h" namespace content { // Create a AccelerometerMac object and return NULL if no valid sensor found. DataFetcher* AccelerometerMac::Create() { scoped_ptr accelerometer(new AccelerometerMac); return accelerometer->Init() ? accelerometer.release() : NULL; } AccelerometerMac::~AccelerometerMac() { } AccelerometerMac::AccelerometerMac() { } const DeviceData* AccelerometerMac::GetDeviceData(DeviceData::Type type) { if (type != DeviceData::kTypeOrientation) return NULL; return GetOrientation(); } // Retrieve per-axis orientation values. // // Axes and angles are defined according to the W3C DeviceOrientation Draft. // See here: http://dev.w3.org/geo/api/spec-source-orientation.html // // Note: only beta and gamma angles are provided. Alpha is set to zero. // // Returns false in case of error. // const Orientation* AccelerometerMac::GetOrientation() { DCHECK(sudden_motion_sensor_.get()); // Retrieve per-axis calibrated values. float axis_value[3]; if (!sudden_motion_sensor_->ReadSensorValues(axis_value)) return NULL; // Transform the accelerometer values to W3C draft angles. // // Accelerometer values are just dot products of the sensor axes // by the gravity vector 'g' with the result for the z axis inverted. // // To understand this transformation calculate the 3rd row of the z-x-y // Euler angles rotation matrix (because of the 'g' vector, only 3rd row // affects to the result). Note that z-x-y matrix means R = Ry * Rx * Rz. // Then, assume alpha = 0 and you get this: // // x_acc = sin(gamma) // y_acc = - cos(gamma) * sin(beta) // z_acc = cos(beta) * cos(gamma) // // After that the rest is just a bit of trigonometry. // // Also note that alpha can't be provided but it's assumed to be always zero. // This is necessary in order to provide enough information to solve // the equations. // const double kRad2deg = 180.0 / M_PI; scoped_refptr orientation(new Orientation()); orientation->set_beta(kRad2deg * atan2(-axis_value[1], axis_value[2])); orientation->set_gamma(kRad2deg * asin(axis_value[0])); // TODO(aousterh): should absolute_ be set to false here? // See crbug.com/136010. // Make sure that the interval boundaries comply with the specification. At // this point, beta is [-180, 180] and gamma is [-90, 90], but the spec has // the upper bound open on both. if (orientation->beta() == 180.0) { orientation->set_beta(-180.0); // -180 == 180 (upside-down) } if (orientation->gamma() == 90.0) { static double just_less_than_90 = nextafter(90, 0); orientation->set_gamma(just_less_than_90); } // At this point, DCHECKing is paranoia. Never hurts. DCHECK_GE(orientation->beta(), -180.0); DCHECK_LT(orientation->beta(), 180.0); DCHECK_GE(orientation->gamma(), -90.0); DCHECK_LT(orientation->gamma(), 90.0); orientation->AddRef(); return orientation.get(); } bool AccelerometerMac::Init() { sudden_motion_sensor_.reset(SuddenMotionSensor::Create()); return sudden_motion_sensor_.get() != NULL; } } // namespace content