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

Unified Diff: content/public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java

Issue 40393002: Android: fix the computation of device orientation angles in accordance with spec. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 2 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/public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java
diff --git a/content/public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java b/content/public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java
index eb9cf0ec596f90bf1b888bc7ea6ba3be984ec85b..96ffe494a8e7bca57c126820b17d6777977a05cb 100644
--- a/content/public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java
+++ b/content/public/android/java/src/org/chromium/content/browser/DeviceMotionAndOrientation.java
@@ -209,8 +209,7 @@ class DeviceMotionAndOrientation implements SensorEventListener {
if (mMagneticFieldVector == null) {
mMagneticFieldVector = new float[3];
}
- System.arraycopy(values, 0, mMagneticFieldVector, 0,
- mMagneticFieldVector.length);
+ System.arraycopy(values, 0, mMagneticFieldVector, 0, mMagneticFieldVector.length);
if (mDeviceOrientationIsActive) {
getOrientationUsingGetRotationMatrix();
}
@@ -221,45 +220,104 @@ class DeviceMotionAndOrientation implements SensorEventListener {
}
}
+ /**
+ * Returns orientation angles from a rotation matrix, such that the angles are according
+ * to spec {@link http://dev.w3.org/geo/api/spec-source-orientation.html}.
+ * <p>
+ * It is assumed the rotation matrix transforms a 3D column vector from device coordinate system
+ * to the world's coordinate system, as e.g. computed by {@see SensorManager.getRotationMatrix}.
+ * <p>
+ * In particular we compute the decomposition of a given rotation matrix R such that
+ * <b>R</b> = <b>Rz</b>(alpha)*<b>Rx</b>(beta)*<b>Ry</b>(gamma),
Michael van Ouwerkerk 2013/10/29 16:18:06 Perhaps all of this documentation would be easier
timvolodine 2013/10/30 14:14:47 Done.
+ * where <b>Rz</b>, <b>Rx</b> and <b>Ry</b> 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
+ * <i>radians</i> and clockwise-positive when viewed along the positive direction of the
+ * corresponding axis. Except for the special case when the beta angle is +-<i>pi</i>/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 wihtin [-<i>pi</i>, <i>pi</i>). A mobile device with pitch angle greater than
+ * <i>pi</i>/2 could correspond to a user lying down and looking upward at the screen.
+ *
+ * <p>
+ * Upon return the array values is filled with the result,
+ * <ul>
+ * <li>values[0]: rotation around the Z axis, alpha in [0,2*<i>pi</i>)</li>
+ * <li>values[1]: rotation around the X axis, beta in [-<i>pi</i>,<i>pi</i>)</li>
+ * <li>values[2]: rotation around the Y axis, gamma in [-<i>pi<i>/2,<i>pi<i>/2)</li>
+ * </ul>
+ * <p>
+ *
+ * @param R
+ * rotation matrix {@see SensorManager.getRotationMatrix}.
+ *
+ * @param values
+ * an array of 3 doubles to hold the result.
+ *
+ * @return the array values passed as argument.
+ */
+ public static void getOrientationMobileDevice(float[] R, double[] values) {
Michael van Ouwerkerk 2013/10/29 16:18:06 Why not create the array in this method and then r
Michael van Ouwerkerk 2013/10/29 16:18:06 @VisibleForTesting
Michael van Ouwerkerk 2013/10/29 16:18:06 How about naming this according to what it does e.
timvolodine 2013/10/30 14:14:47 ok, I've added a return double[]. However we still
timvolodine 2013/10/30 14:14:47 Done.
timvolodine 2013/10/30 14:14:47 renamed to computeDeviceOrientationFromRotationMat
+ /*
+ * 3x3 (length=9) case:
+ * / R[ 0] R[ 1] R[ 2] \
+ * | R[ 3] R[ 4] R[ 5] |
+ * \ R[ 6] R[ 7] R[ 8] /
+ *
+ */
+ if (R.length != 9)
+ return;
Michael van Ouwerkerk 2013/10/29 16:18:06 Worth calling out in the Javadoc the possibility f
timvolodine 2013/10/30 14:14:47 this should not happen, or it would be incorrect u
+
+ if (R[8] > 0) { // cos(beta) > 0
+ values[0] = Math.atan2(-R[1], R[4]);
+ values[1] = Math.asin(R[7]); // beta (-pi/2, pi/2)
bulach 2013/10/24 17:08:44 both in comments and in some real places like 294,
timvolodine 2013/10/30 14:14:47 Done. (however left some comments as is for readab
+ values[2] = Math.atan2(-R[6], R[8]); // gamma (-pi/2, pi/2)
+ } else if (R[8] < 0) { // cos(beta) < 0
+ values[0] = Math.atan2(R[1], -R[4]);
+ values[1] = -Math.asin(R[7]);
+ values[1] += (values[1] >= 0) ? -Math.PI : Math.PI; // beta [-pi,-pi/2) U (pi/2,pi)
+ values[2] = Math.atan2(R[6], -R[8]); // gamma (-pi/2, pi/2)
+ } else { // R[8] == 0
+ if (R[6] > 0) { // cos(gamma)==0, cos(beta) > 0
+ values[0] = Math.atan2(-R[1], R[4]);
+ values[1] = Math.asin(R[7]); // beta [-pi/2, pi/2]
+ values[2] = -Math.PI/2;
+ } else if (R[6] < 0) { // cos(gamma)==0, cos(beta) < 0
+ values[0] = Math.atan2(R[1], -R[4]);
+ values[1] = -Math.asin(R[7]);
+ values[1] += (values[1] >= 0) ? -Math.PI : Math.PI; // beta [-pi,-pi/2) U (pi/2,pi)
+ values[2] = -Math.PI/2;
+ } else { // R[6] == 0, cos(beta) == 0
+ // gimbal lock discontinuity
+ values[0] = Math.atan2(R[3], R[0]);
+ values[1] = (R[7] > 0) ? Math.PI/2 : -Math.PI/2; // beta = +-pi/2
+ values[2] = 0; // gamma = 0
+ }
+ }
+
+ // alpha is in [-pi, pi], make sure it is in [0,2*pi].
+ if (values[0] < 0)
+ values[0] += 2*Math.PI; // alpha [0,2*pi)
+ }
+
private void getOrientationUsingGetRotationMatrix() {
if (mAccelerationIncludingGravityVector == null || mMagneticFieldVector == null) {
return;
}
- // Get the rotation matrix.
- // The rotation matrix that transforms from the body frame to the earth
- // frame.
float[] deviceRotationMatrix = new float[9];
if (!SensorManager.getRotationMatrix(deviceRotationMatrix, null,
mAccelerationIncludingGravityVector, mMagneticFieldVector)) {
return;
}
- // Convert rotation matrix to rotation angles.
- // Assuming that the rotations are appied in the order listed at
- // http://developer.android.com/reference/android/hardware/SensorEvent.html#values
- // the rotations are applied about the same axes and in the same order as required by the
- // API. The only conversions are sign changes as follows. The angles are in radians
-
- float[] rotationAngles = new float[3];
- SensorManager.getOrientation(deviceRotationMatrix, rotationAngles);
-
- double alpha = Math.toDegrees(-rotationAngles[0]);
- while (alpha < 0.0) {
- alpha += 360.0; // [0, 360)
- }
-
- double beta = Math.toDegrees(-rotationAngles[1]);
- while (beta < -180.0) {
- beta += 360.0; // [-180, 180)
- }
-
- double gamma = Math.toDegrees(rotationAngles[2]);
- while (gamma < -90.0) {
- gamma += 360.0; // [-90, 90)
- }
+ double[] rotationAngles = new double[3];
+ getOrientationMobileDevice(deviceRotationMatrix, rotationAngles);
- gotOrientation(alpha, beta, gamma);
+ gotOrientation(Math.toDegrees(rotationAngles[0]),
Michael van Ouwerkerk 2013/10/29 16:18:06 If degrees are needed, why not return those from t
timvolodine 2013/10/30 14:14:47 yeah, but to make it more generic it would be bett
+ Math.toDegrees(rotationAngles[1]),
+ Math.toDegrees(rotationAngles[2]));
}
private SensorManagerProxy getSensorManagerProxy() {

Powered by Google App Engine
This is Rietveld 408576698