Home | History | Annotate | Download | only in device_orientation
      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