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 |