Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 } |
| OLD | NEW |