好的工作正常。首先,設備定向輸入一個簡單的解釋:
絕對座標系,(X, Y, Z)
是這樣的:X
是東,Y
是北美和Z
到了。設備相對座標系(x, y, z)
就是這樣的,x
是正確的,y
是最高的,z
是最高的。然後,定向角,(alpha, beta, gamma)
是描述的該改變(X, Y, Z)
到(x, y, z)
作爲這樣三個簡單的旋轉繼承角度:
- 由
alpha
度,其將(X, Y, Z)
到(X', Y', Z')
與繞Z
Z'
= Z
- 圍繞
X'
轉過beta
度,將(X', Y', Z')
轉換爲(X'', Y'', Z'')
,其中X''
= X'
- 繞
Y''
由gamma
度,其將(X'', Y'', Z'')
到(x, y, z)
與y
= Y''
(Z-X'-Y''
類型的它們被稱爲本徵大吉-布賴恩角度)
現在,我們可以通過合成獲得相應的旋轉矩陣簡單的旋轉矩陣,每個旋轉矩陣對應三個旋轉中的一個。
[ cC 0 sC ] [ 1 0 0 ] [ cA -sA 0 ]
R(A, B, C) = Ry(C)*Rx(B)*Rz(A) = | 0 1 0 |*| 0 cB -sB |*[ sA cA 0 ]
[ -sC 0 cC ] [ 0 sB cB ] [ 0 0 1 ]
其中A, B, C
是短於alpha, beta, gamma
s, c
和用於sin, cos
。
現在,我們感興趣的是左右(y
軸)和自上而下(x
軸)的兩個位置(x, y, z)
和(x', y', z')
之間旋轉增量的對應於所述取向角度(A, B, C)
和(A', B', C')
的根據(x, y, z)
,(x', y', z')
的座標由R(A', B', C') * R(A, B, C)^-1 = R(A', B', C') * R(A, B, C)^T
給出,因爲逆是正交(旋轉)矩陣的轉置。最後,如果是z' = p*x + q*y + r*z
,那些旋轉的角度在左右軸周圍是p
而在自上而下的軸周圍是q
(這對於假定頻繁定向更新的小角度是如此,否則asin(p)
和asin(r)
距離事實更近)
所以這裏是一些JavaScript得到旋轉矩陣:
/*
* gl-matrix is a nice library that handles rotation stuff efficiently
* The 3x3 matrix is a 9 element array
* such that indexes 0-2 correspond to the first column, 3-5 to the second column and 6-8 to the third
*/
import {mat3} from 'gl-matrix';
let _x, _y, _z;
let cX, cY, cZ, sX, sY, sZ;
/*
* return the rotation matrix corresponding to the orientation angles
*/
const fromOrientation = function(out, alpha, beta, gamma) {
_z = alpha;
_x = beta;
_y = gamma;
cX = Math.cos(_x);
cY = Math.cos(_y);
cZ = Math.cos(_z);
sX = Math.sin(_x);
sY = Math.sin(_y);
sZ = Math.sin(_z);
out[0] = cZ * cY + sZ * sX * sY, // row 1, col 1
out[1] = cX * sZ, // row 2, col 1
out[2] = - cZ * sY + sZ * sX * cY , // row 3, col 1
out[3] = - cY * sZ + cZ * sX * sY, // row 1, col 2
out[4] = cZ * cX, // row 2, col 2
out[5] = sZ * sY + cZ * cY * sX, // row 3, col 2
out[6] = cX * sY, // row 1, col 3
out[7] = - sX, // row 2, col 3
out[8] = cX * cY // row 3, col 3
};
,現在我們得到的角增量:
const deg2rad = Math.PI/180; // Degree-to-Radian conversion
let currentRotMat, previousRotMat, inverseMat, relativeRotationDelta,
totalRightAngularMovement=0, totalTopAngularMovement=0;
window.addEventListener('deviceorientation', ({alpha, beta, gamma}) => {
// init values if necessary
if (!previousRotMat) {
previousRotMat = mat3.create();
currentRotMat = mat3.create();
relativeRotationDelta = mat3.create();
fromOrientation(currentRotMat, alpha * deg2rad, beta * deg2rad, gamma * deg2rad);
}
// save last orientation
mat3.copy(previousRotMat, currentRotMat);
// get rotation in the previous orientation coordinate
fromOrientation(currentRotMat, alpha * deg2rad, beta * deg2rad, gamma * deg2rad);
mat3.transpose(inverseMat, previousRotMat); // for rotation matrix, inverse is transpose
mat3.multiply(relativeRotationDelta, currentRotMat, inverseMat);
// add the angular deltas to the cummulative rotation
totalRightAngularMovement += Math.asin(relativeRotationDelta[6])/deg2rad;
totalTopAngularMovement += Math.asin(relativeRotationDelta[7])/deg2rad;
}
最後,考慮到屏幕方向,我們不得不更換
_z = alpha;
_x = beta;
_y = gamma;
通過
const getScreenOrientation =() => {
switch (window.screen.orientation || window.screen.mozOrientation) {
case 'landscape-primary':
return 90;
case 'landscape-secondary':
return -90;
case 'portrait-secondary':
return 180;
case 'portrait-primary':
return 0;
}
if (window.orientation !== undefined)
return window.orientation;
};
const screenOrientation = getScreenOrientation();
_z = alpha;
if (screenOrientation === 90) {
_x = - gamma;
_y = beta;
}
else if (screenOrientation === -90) {
_x = gamma;
_y = - beta;
}
else if (screenOrientation === 180) {
_x = - beta;
_y = - gamma;
}
else if (screenOrientation === 0) {
_x = beta;
_y = gamma;
}
注意,累積左右和上下角度將取決於用戶所選擇的路徑,並且不能從設備方向直接推斷,而必須通過運動進行跟蹤。您可以到達同一位置不同的走勢:
方法1:
- 保持手機水平和順時針旋轉90度。 (這既不是左右旋轉也不是上下旋轉)
- 讓您的手機處於橫向模式並向您旋轉90°。 (這不是90度的左右旋轉)
- 讓你的手機朝向你,並旋轉90°,這樣它就起來了。 (這既不是左右一旋轉90度)
方法2:
- 90度旋轉手機以使其朝向你和垂直(這是一個90度的頂底部旋轉)
我嘗試推行這種方法 - 請https://stackoverflow.com/questions/46975452/adjusting-mobile-accelerometer-data-to-account-for-phone-rotation - 我我得到不同的acc。我打開手機時的結果。你能評論一下,看看我是否錯過了一些東西?謝謝 – user1361529