Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(230)

Unified Diff: content/renderer/device_sensors/device_orientation_util.cc

Issue 2885203004: Refactor content/renderer/device_sensors to use device/generic_sensor instead of device/sensors (Closed)
Patch Set: updated content/renderer/BUILD.gn Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: content/renderer/device_sensors/device_orientation_util.cc
diff --git a/content/renderer/device_sensors/device_orientation_util.cc b/content/renderer/device_sensors/device_orientation_util.cc
new file mode 100644
index 0000000000000000000000000000000000000000..15f27bfa8e9ed88a11fa6ac29fe58d91544b4e19
--- /dev/null
+++ b/content/renderer/device_sensors/device_orientation_util.cc
@@ -0,0 +1,254 @@
+// Copyright 2017 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.
+
+#define _USE_MATH_DEFINES // For VC++ to get M_PI. This has to be first.
+
+#include "content/renderer/device_sensors/device_orientation_util.h"
+
+#include <cmath>
+#include <vector>
+
+#include "base/logging.h"
+#include "third_party/WebKit/public/platform/modules/device_orientation/WebDeviceOrientationData.h"
+
+namespace {
+
+bool IsAngleDifferent(bool has_angle1,
+ double angle1,
+ bool has_angle2,
+ double angle2) {
+ if (has_angle1 != has_angle2)
+ return true;
+ return (has_angle1 &&
+ std::fabs(angle1 - angle2) >= content::kOrientationThreshold);
+}
+
+// Helper function to convert a quaternion to a rotation matrix. x, y, z, w
+// are values of a quaternion representing the orientation of the device in
+// 3D space. Returns a 9 element rotation matrix:
+// r[ 0] r[ 1] r[ 2]
+// r[ 3] r[ 4] r[ 5]
+// r[ 6] r[ 7] r[ 8]
+std::vector<double> ComputeRotationMatrixFromQuaternion(double x,
+ double y,
+ double z,
+ double w) {
+ std::vector<double> r(9);
+
+ double sq_x = 2 * x * x;
+ double sq_y = 2 * y * y;
+ double sq_z = 2 * z * z;
+ double x_y = 2 * x * y;
+ double z_w = 2 * z * w;
+ double x_z = 2 * x * z;
+ double y_w = 2 * y * w;
+ double y_z = 2 * y * z;
+ double x_w = 2 * x * w;
+
+ r[0] = 1 - sq_y - sq_z;
+ r[1] = x_y - z_w;
+ r[2] = x_z + y_w;
+ r[3] = x_y + z_w;
+ r[4] = 1 - sq_x - sq_z;
+ r[5] = y_z - x_w;
+ r[6] = x_z - y_w;
+ r[7] = y_z + x_w;
+ r[8] = 1 - sq_x - sq_y;
+
+ return r;
+}
+
+// Helper function to compute the rotation matrix using gravity and geomagnetic
+// data. Returns a 9 element rotation matrix:
+// r[ 0] r[ 1] r[ 2]
+// r[ 3] r[ 4] r[ 5]
+// r[ 6] r[ 7] r[ 8]
+// r is meaningful only when the device is not free-falling and it is not close
+// to the magnetic north. If the device is accelerating, or placed into a
+// strong magnetic field, the returned matricx may be inaccurate.
+//
+// Free fall is defined as condition when the magnitude of the gravity is less
+// than 1/10 of the nominal value.
+bool ComputeRotationMatrixFromGravityAndGeomagnetic(double gravity_x,
+ double gravity_y,
+ double gravity_z,
+ double geomagnetic_x,
+ double geomagnetic_y,
+ double geomagnetic_z,
+ std::vector<double>* r) {
+ double gravity_squared =
+ (gravity_x * gravity_x + gravity_y * gravity_y + gravity_z * gravity_z);
+ double g = 9.81;
+ double free_fall_gravity_squared = 0.01 * g * g;
+ if (gravity_squared < free_fall_gravity_squared) {
+ // gravity less than 10% of normal value
+ return false;
+ }
+
+ double hx = geomagnetic_y * gravity_z - geomagnetic_z * gravity_y;
+ double hy = geomagnetic_z * gravity_x - geomagnetic_x * gravity_z;
+ double hz = geomagnetic_x * gravity_y - geomagnetic_y * gravity_x;
+ double norm_h = std::sqrt(hx * hx + hy * hy + hz * hz);
+ if (norm_h < 0.1) {
+ // device is close to free fall, or close to magnetic north pole.
+ // Typical values are > 100.
+ return false;
+ }
+
+ double inv_h = 1.0 / norm_h;
+ hx *= inv_h;
+ hy *= inv_h;
+ hz *= inv_h;
+ double inv_gravity = 1.0 / std::sqrt(gravity_squared);
+ gravity_x *= inv_gravity;
+ gravity_y *= inv_gravity;
+ gravity_z *= inv_gravity;
+ double mx = gravity_y * hz - gravity_z * hy;
+ double my = gravity_z * hx - gravity_x * hz;
+ double mz = gravity_x * hy - gravity_y * hx;
+
+ r->resize(9);
+
+ (*r)[0] = hx;
+ (*r)[1] = hy;
+ (*r)[2] = hz;
+ (*r)[3] = mx;
+ (*r)[4] = my;
+ (*r)[5] = mz;
+ (*r)[6] = gravity_x;
+ (*r)[7] = gravity_y;
+ (*r)[8] = gravity_z;
+
+ return true;
+}
+
+// Returns orientation angles from a rotation matrix, such that the angles are
+// according to spec http://dev.w3.org/geo/api/spec-source-orientation.html}.
+//
+// It is assumed the rotation matrix transforms a 3D column vector from device
+// coordinate system to the world's coordinate system.
+//
+// In particular we compute the decomposition of a given rotation matrix r such
+// that
+// r = rz(alpha) * rx(beta) * ry(gamma)
+// where rz, rx and ry are rotation matrices around z, x and y axes in the world
+// coordinate reference frame respectively. The reference frame consists of
+// three orthogonal axes x, y, z where x points East, y points north and z
+// points upwards perpendicular to the ground plane. The computed angles alpha,
+// beta and gamma are in degrees and clockwise-positive when viewed along the
+// positive direction of the corresponding axis. Except for the special case
+// when the beta angle is +-pi/2 these angles uniquely define the orientation of
+// a mobile device in 3D space. The alpha-beta-gamma representation resembles
+// the yaw-pitch-roll convention used in vehicle dynamics, however it does not
+// exactly match it. One of the differences is that the 'pitch' angle beta is
+// allowed to be within [-pi, pi). A mobile device with pitch angle greater than
+// pi/2 could correspond to a user lying down and looking upward at the screen.
+//
+// r is a 9 element rotation matrix:
+// r[ 0] r[ 1] r[ 2]
+// r[ 3] r[ 4] r[ 5]
+// r[ 6] r[ 7] r[ 8]
+//
+// alpha: rotation around the z axis, in [0, 2*pi)
+// beta: rotation around the x axis, in [-pi, pi)
+// gamma: rotation around the y axis, in [-pi/2, pi/2)
+void ComputeDeviceOrientationFromRotationMatrix(const std::vector<double>& r,
+ double* alpha,
+ double* beta,
+ double* gamma) {
+ DCHECK_EQ(9u, r.size());
+
+ if (r[8] > 0) { // cos(beta) > 0
+ *alpha = std::atan2(-r[1], r[4]);
+ *beta = std::asin(r[7]); // beta (-pi/2, pi/2)
+ *gamma = std::atan2(-r[6], r[8]); // gamma (-pi/2, pi/2)
+ } else if (r[8] < 0) { // cos(beta) < 0
+ *alpha = std::atan2(r[1], -r[4]);
+ *beta = -std::asin(r[7]);
+ *beta += (*beta >= 0) ? -M_PI : M_PI; // beta [-pi,-pi/2) U (pi/2,pi)
+ *gamma = std::atan2(r[6], -r[8]); // gamma (-pi/2, pi/2)
+ } else { // r[8] == 0
+ if (r[6] > 0) { // cos(gamma) == 0, cos(beta) > 0
+ *alpha = std::atan2(-r[1], r[4]);
+ *beta = std::asin(r[7]); // beta [-pi/2, pi/2]
+ *gamma = -M_PI / 2; // gamma = -pi/2
+ } else if (r[6] < 0) { // cos(gamma) == 0, cos(beta) < 0
+ *alpha = std::atan2(r[1], -r[4]);
+ *beta = -std::asin(r[7]);
+ *beta += (*beta >= 0) ? -M_PI : M_PI; // beta [-pi,-pi/2) U (pi/2,pi)
+ *gamma = -M_PI / 2; // gamma = -pi/2
+ } else { // r[6] == 0, cos(beta) == 0
+ // gimbal lock discontinuity
+ *alpha = std::atan2(r[3], r[0]);
+ *beta = (r[7] > 0) ? M_PI / 2 : -M_PI / 2; // beta = +-pi/2
+ *gamma = 0; // gamma = 0
+ }
+ }
+
+ // alpha is in [-pi, pi], make sure it is in [0, 2*pi).
+ if (*alpha < 0)
+ *alpha += 2 * M_PI; // alpha [0, 2*pi)
+}
+
+double RadiansToDegrees(double radians) {
+ return (180.0 * radians) / M_PI;
+}
+
+} // namespace
+
+namespace content {
+
+bool IsSignificantlyDifferent(const blink::WebDeviceOrientationData& data1,
+ const blink::WebDeviceOrientationData& data2) {
+ return IsAngleDifferent(data1.has_alpha, data1.alpha, data2.has_alpha,
+ data2.alpha) ||
+ IsAngleDifferent(data1.has_beta, data1.beta, data2.has_beta,
+ data2.beta) ||
+ IsAngleDifferent(data1.has_gamma, data1.gamma, data2.has_gamma,
+ data2.gamma);
+}
+
+void ComputeDeviceOrientationFromQuaternion(double x,
+ double y,
+ double z,
+ double w,
+ double* alpha,
+ double* beta,
+ double* gamma) {
+ std::vector<double> rotation_matrix =
+ ComputeRotationMatrixFromQuaternion(x, y, z, w);
+ double alpha_radians, beta_radians, gamma_radians;
+ ComputeDeviceOrientationFromRotationMatrix(rotation_matrix, &alpha_radians,
+ &beta_radians, &gamma_radians);
+ *alpha = RadiansToDegrees(alpha_radians);
+ *beta = RadiansToDegrees(beta_radians);
+ *gamma = RadiansToDegrees(gamma_radians);
+}
+
+bool ComputeDeviceOrientationFromGravityAndGeomagnetic(double gravity_x,
+ double gravity_y,
+ double gravity_z,
+ double geomagnetic_x,
+ double geomagnetic_y,
+ double geomagnetic_z,
+ double* alpha,
+ double* beta,
+ double* gamma) {
+ std::vector<double> rotation_matrix;
+ if (!ComputeRotationMatrixFromGravityAndGeomagnetic(
+ gravity_x, gravity_y, gravity_z, geomagnetic_x, geomagnetic_y,
+ geomagnetic_z, &rotation_matrix)) {
+ return false;
+ }
+
+ double alpha_radians, beta_radians, gamma_radians;
+ ComputeDeviceOrientationFromRotationMatrix(rotation_matrix, &alpha_radians,
+ &beta_radians, &gamma_radians);
+ *alpha = RadiansToDegrees(alpha_radians);
+ *beta = RadiansToDegrees(beta_radians);
+ *gamma = RadiansToDegrees(gamma_radians);
+ return true;
+}
+
+} // namespace content

Powered by Google App Engine
This is Rietveld 408576698