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

Side by Side 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 unified diff | Download patch
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 package org.chromium.content.browser; 5 package org.chromium.content.browser;
6 6
7 import android.content.Context; 7 import android.content.Context;
8 import android.hardware.Sensor; 8 import android.hardware.Sensor;
9 import android.hardware.SensorEvent; 9 import android.hardware.SensorEvent;
10 import android.hardware.SensorEventListener; 10 import android.hardware.SensorEventListener;
(...skipping 191 matching lines...) Expand 10 before | Expand all | Expand 10 after
202 break; 202 break;
203 case Sensor.TYPE_GYROSCOPE: 203 case Sensor.TYPE_GYROSCOPE:
204 if (mDeviceMotionIsActive) { 204 if (mDeviceMotionIsActive) {
205 gotRotationRate(values[0], values[1], values[2]); 205 gotRotationRate(values[0], values[1], values[2]);
206 } 206 }
207 break; 207 break;
208 case Sensor.TYPE_MAGNETIC_FIELD: 208 case Sensor.TYPE_MAGNETIC_FIELD:
209 if (mMagneticFieldVector == null) { 209 if (mMagneticFieldVector == null) {
210 mMagneticFieldVector = new float[3]; 210 mMagneticFieldVector = new float[3];
211 } 211 }
212 System.arraycopy(values, 0, mMagneticFieldVector, 0, 212 System.arraycopy(values, 0, mMagneticFieldVector, 0, mMagneticFi eldVector.length);
213 mMagneticFieldVector.length);
214 if (mDeviceOrientationIsActive) { 213 if (mDeviceOrientationIsActive) {
215 getOrientationUsingGetRotationMatrix(); 214 getOrientationUsingGetRotationMatrix();
216 } 215 }
217 break; 216 break;
218 default: 217 default:
219 // Unexpected 218 // Unexpected
220 return; 219 return;
221 } 220 }
222 } 221 }
223 222
223 /**
224 * Returns orientation angles from a rotation matrix, such that the angles a re according
225 * to spec {@link http://dev.w3.org/geo/api/spec-source-orientation.html}.
226 * <p>
227 * It is assumed the rotation matrix transforms a 3D column vector from devi ce coordinate system
228 * to the world's coordinate system, as e.g. computed by {@see SensorManager .getRotationMatrix}.
229 * <p>
230 * In particular we compute the decomposition of a given rotation matrix R s uch that
231 * <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.
232 * where <b>Rz</b>, <b>Rx</b> and <b>Ry</b> are rotation matrices around Z, X and Y axes in the
233 * world coordinate reference frame respectively. The reference frame consis ts of three
234 * orthogonal axes X, Y, Z where X points East, Y points north and Z points
235 * upwards perpendicular to the ground plane. The computed angles alpha, bet a and gamma are in
236 * <i>radians</i> and clockwise-positive when viewed along the positive dire ction of the
237 * corresponding axis. Except for the special case when the beta angle is +- <i>pi</i>/2 these
238 * angles uniquely define the orientation of a mobile device in 3D space. Th e alpha-beta-gamma
239 * representation resembles the yaw-pitch-roll convention used in vehicle dy namics, however it
240 * does not exactly match it. One of the differences is that the 'pitch' ang le beta is allowed
241 * to be wihtin [-<i>pi</i>, <i>pi</i>). A mobile device with pitch angle gr eater than
242 * <i>pi</i>/2 could correspond to a user lying down and looking upward at t he screen.
243 *
244 * <p>
245 * Upon return the array values is filled with the result,
246 * <ul>
247 * <li>values[0]: rotation around the Z axis, alpha in [0,2*<i>pi</i>)</li>
248 * <li>values[1]: rotation around the X axis, beta in [-<i>pi</i>,<i>pi</i>) </li>
249 * <li>values[2]: rotation around the Y axis, gamma in [-<i>pi<i>/2,<i>pi<i> /2)</li>
250 * </ul>
251 * <p>
252 *
253 * @param R
254 * rotation matrix {@see SensorManager.getRotationMatrix}.
255 *
256 * @param values
257 * an array of 3 doubles to hold the result.
258 *
259 * @return the array values passed as argument.
260 */
261 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
262 /*
263 * 3x3 (length=9) case:
264 * / R[ 0] R[ 1] R[ 2] \
265 * | R[ 3] R[ 4] R[ 5] |
266 * \ R[ 6] R[ 7] R[ 8] /
267 *
268 */
269 if (R.length != 9)
270 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
271
272 if (R[8] > 0) { // cos(beta) > 0
273 values[0] = Math.atan2(-R[1], R[4]);
274 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
275 values[2] = Math.atan2(-R[6], R[8]); // gamma (-pi/2, pi/2)
276 } else if (R[8] < 0) { // cos(beta) < 0
277 values[0] = Math.atan2(R[1], -R[4]);
278 values[1] = -Math.asin(R[7]);
279 values[1] += (values[1] >= 0) ? -Math.PI : Math.PI; // beta [-pi,-pi /2) U (pi/2,pi)
280 values[2] = Math.atan2(R[6], -R[8]); // gamma (-pi/2, pi/2)
281 } else { // R[8] == 0
282 if (R[6] > 0) { // cos(gamma)==0, cos(beta) > 0
283 values[0] = Math.atan2(-R[1], R[4]);
284 values[1] = Math.asin(R[7]); // beta [-pi/2, pi/2]
285 values[2] = -Math.PI/2;
286 } else if (R[6] < 0) { // cos(gamma)==0, cos(beta) < 0
287 values[0] = Math.atan2(R[1], -R[4]);
288 values[1] = -Math.asin(R[7]);
289 values[1] += (values[1] >= 0) ? -Math.PI : Math.PI; // beta [-pi ,-pi/2) U (pi/2,pi)
290 values[2] = -Math.PI/2;
291 } else { // R[6] == 0, cos(beta) == 0
292 // gimbal lock discontinuity
293 values[0] = Math.atan2(R[3], R[0]);
294 values[1] = (R[7] > 0) ? Math.PI/2 : -Math.PI/2; // beta = +-pi /2
295 values[2] = 0; // gamma = 0
296 }
297 }
298
299 // alpha is in [-pi, pi], make sure it is in [0,2*pi].
300 if (values[0] < 0)
301 values[0] += 2*Math.PI; // alpha [0,2*pi)
302 }
303
224 private void getOrientationUsingGetRotationMatrix() { 304 private void getOrientationUsingGetRotationMatrix() {
225 if (mAccelerationIncludingGravityVector == null || mMagneticFieldVector == null) { 305 if (mAccelerationIncludingGravityVector == null || mMagneticFieldVector == null) {
226 return; 306 return;
227 } 307 }
228 308
229 // Get the rotation matrix.
230 // The rotation matrix that transforms from the body frame to the earth
231 // frame.
232 float[] deviceRotationMatrix = new float[9]; 309 float[] deviceRotationMatrix = new float[9];
233 if (!SensorManager.getRotationMatrix(deviceRotationMatrix, null, 310 if (!SensorManager.getRotationMatrix(deviceRotationMatrix, null,
234 mAccelerationIncludingGravityVector, mMagneticFieldVector)) { 311 mAccelerationIncludingGravityVector, mMagneticFieldVector)) {
235 return; 312 return;
236 } 313 }
237 314
238 // Convert rotation matrix to rotation angles. 315 double[] rotationAngles = new double[3];
239 // Assuming that the rotations are appied in the order listed at 316 getOrientationMobileDevice(deviceRotationMatrix, rotationAngles);
240 // http://developer.android.com/reference/android/hardware/SensorEvent.h tml#values
241 // the rotations are applied about the same axes and in the same order a s required by the
242 // API. The only conversions are sign changes as follows. The angles ar e in radians
243 317
244 float[] rotationAngles = new float[3]; 318 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
245 SensorManager.getOrientation(deviceRotationMatrix, rotationAngles); 319 Math.toDegrees(rotationAngles[1]),
246 320 Math.toDegrees(rotationAngles[2]));
247 double alpha = Math.toDegrees(-rotationAngles[0]);
248 while (alpha < 0.0) {
249 alpha += 360.0; // [0, 360)
250 }
251
252 double beta = Math.toDegrees(-rotationAngles[1]);
253 while (beta < -180.0) {
254 beta += 360.0; // [-180, 180)
255 }
256
257 double gamma = Math.toDegrees(rotationAngles[2]);
258 while (gamma < -90.0) {
259 gamma += 360.0; // [-90, 90)
260 }
261
262 gotOrientation(alpha, beta, gamma);
263 } 321 }
264 322
265 private SensorManagerProxy getSensorManagerProxy() { 323 private SensorManagerProxy getSensorManagerProxy() {
266 if (mSensorManagerProxy != null) { 324 if (mSensorManagerProxy != null) {
267 return mSensorManagerProxy; 325 return mSensorManagerProxy;
268 } 326 }
269 SensorManager sensorManager = (SensorManager)WeakContext.getSystemServic e( 327 SensorManager sensorManager = (SensorManager)WeakContext.getSystemServic e(
270 Context.SENSOR_SERVICE); 328 Context.SENSOR_SERVICE);
271 if (sensorManager != null) { 329 if (sensorManager != null) {
272 mSensorManagerProxy = new SensorManagerProxyImpl(sensorManager); 330 mSensorManagerProxy = new SensorManagerProxyImpl(sensorManager);
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
454 @Override 512 @Override
455 public void unregisterListener(SensorEventListener listener, int sensorT ype) { 513 public void unregisterListener(SensorEventListener listener, int sensorT ype) {
456 List<Sensor> sensors = mSensorManager.getSensorList(sensorType); 514 List<Sensor> sensors = mSensorManager.getSensorList(sensorType);
457 if (!sensors.isEmpty()) { 515 if (!sensors.isEmpty()) {
458 mSensorManager.unregisterListener(listener, sensors.get(0)); 516 mSensorManager.unregisterListener(listener, sensors.get(0));
459 } 517 }
460 } 518 }
461 } 519 }
462 520
463 } 521 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698