blob: 04c5d71b65c213c01b5400122be7bc8dd921e17d [file] [log] [blame]
// 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 <math.h>
#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<AccelerometerMac> 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> 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