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

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: fixed comment Created 7 years, 1 month 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
« no previous file with comments | « no previous file | content/public/android/javatests/src/org/chromium/content/browser/DeviceMotionAndOrientationTest.java » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 <br>
231 * R = Rz(alpha) * Rx(beta) * Ry(gamma), <br>
232 * where Rz, Rx and Ry are rotation matrices around Z, X and Y axes in the w orld coordinate
233 * reference frame respectively. The reference frame consists of three ortho gonal axes X, Y, Z
234 * where X points East, Y points north and Z points upwards perpendicular to the ground plane.
235 * The computed angles alpha, beta and gamma are in radians and clockwise-po sitive when viewed
236 * along the positive direction of the corresponding axis. Except for the sp ecial case when the
237 * beta angle is +-pi/2 these angles uniquely define the orientation of a mo bile device in 3D
238 * space. The alpha-beta-gamma representation resembles the yaw-pitch-roll c onvention used in
239 * vehicle dynamics, however it does not exactly match it. One of the differ ences is that the
240 * 'pitch' angle beta is allowed to be within [-pi, pi). A mobile device wit h pitch angle
241 * greater than pi/2 could correspond to a user lying down and looking upwar d at the screen.
242 *
243 * <p>
244 * Upon return the array values is filled with the result,
245 * <ul>
246 * <li>values[0]: rotation around the Z axis, alpha in [0, 2*pi)</li>
247 * <li>values[1]: rotation around the X axis, beta in [-pi, pi)</li>
248 * <li>values[2]: rotation around the Y axis, gamma in [-pi/2, pi/2)</li>
249 * </ul>
250 * <p>
251 *
252 * @param R
253 * a 3x3 rotation matrix {@see SensorManager.getRotationMatrix}.
254 *
255 * @param values
256 * an array of 3 doubles to hold the result.
257 *
258 * @return the array values passed as argument.
259 */
260 @VisibleForTesting
261 public static double[] computeDeviceOrientationFromRotationMatrix(float[] R, double[] values) {
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 values;
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)
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; // gamma = -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; // gamma = -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 return values;
304 }
305
224 private void getOrientationUsingGetRotationMatrix() { 306 private void getOrientationUsingGetRotationMatrix() {
225 if (mAccelerationIncludingGravityVector == null || mMagneticFieldVector == null) { 307 if (mAccelerationIncludingGravityVector == null || mMagneticFieldVector == null) {
226 return; 308 return;
227 } 309 }
228 310
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]; 311 float[] deviceRotationMatrix = new float[9];
233 if (!SensorManager.getRotationMatrix(deviceRotationMatrix, null, 312 if (!SensorManager.getRotationMatrix(deviceRotationMatrix, null,
234 mAccelerationIncludingGravityVector, mMagneticFieldVector)) { 313 mAccelerationIncludingGravityVector, mMagneticFieldVector)) {
235 return; 314 return;
236 } 315 }
237 316
238 // Convert rotation matrix to rotation angles. 317 double[] rotationAngles = new double[3];
239 // Assuming that the rotations are appied in the order listed at 318 computeDeviceOrientationFromRotationMatrix(deviceRotationMatrix, rotatio nAngles);
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 319
244 float[] rotationAngles = new float[3]; 320 gotOrientation(Math.toDegrees(rotationAngles[0]),
245 SensorManager.getOrientation(deviceRotationMatrix, rotationAngles); 321 Math.toDegrees(rotationAngles[1]),
246 322 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 } 323 }
264 324
265 private SensorManagerProxy getSensorManagerProxy() { 325 private SensorManagerProxy getSensorManagerProxy() {
266 if (mSensorManagerProxy != null) { 326 if (mSensorManagerProxy != null) {
267 return mSensorManagerProxy; 327 return mSensorManagerProxy;
268 } 328 }
269 SensorManager sensorManager = (SensorManager)WeakContext.getSystemServic e( 329 SensorManager sensorManager = (SensorManager)WeakContext.getSystemServic e(
270 Context.SENSOR_SERVICE); 330 Context.SENSOR_SERVICE);
271 if (sensorManager != null) { 331 if (sensorManager != null) {
272 mSensorManagerProxy = new SensorManagerProxyImpl(sensorManager); 332 mSensorManagerProxy = new SensorManagerProxyImpl(sensorManager);
(...skipping 181 matching lines...) Expand 10 before | Expand all | Expand 10 after
454 @Override 514 @Override
455 public void unregisterListener(SensorEventListener listener, int sensorT ype) { 515 public void unregisterListener(SensorEventListener listener, int sensorT ype) {
456 List<Sensor> sensors = mSensorManager.getSensorList(sensorType); 516 List<Sensor> sensors = mSensorManager.getSensorList(sensorType);
457 if (!sensors.isEmpty()) { 517 if (!sensors.isEmpty()) {
458 mSensorManager.unregisterListener(listener, sensors.get(0)); 518 mSensorManager.unregisterListener(listener, sensors.get(0));
459 } 519 }
460 } 520 }
461 } 521 }
462 522
463 } 523 }
OLDNEW
« no previous file with comments | « no previous file | content/public/android/javatests/src/org/chromium/content/browser/DeviceMotionAndOrientationTest.java » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698