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 <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 wihtin [-pi, pi). A mobile device wit h pitch angle | |
Michael van Ouwerkerk
2013/10/30 14:21:02
nit: s/wihtin/within/
timvolodine
2013/10/30 14:40:01
Done.
| |
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 Loading... | |
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 } |
OLD | NEW |