2016-04-15 66 views
5

我试图获取沿左右轴和上下轴的两个事件之间的方向变化,这些轴通常定义为手机xy轴瞬间t1t2其中那些电话线从(x1, y1)移动到(x2, y2)之间(https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Orientation_and_motion_data_explainedhtml5 - 在相对坐标系下获取设备方向旋转

即,它想获得(angle(x2-x1), angle(y1-y2))

当设备处于纵向模式(与横向模式相反)时,这些轴似乎对应于betagamma。然而,当手机处于垂直(底面向地面)时,gamma值变得非常不稳定,和90至-90度跳跃(在相同的场合,α180度跳跃)可以很容易地看到here on your phone

我想避免这种情况,并获得360范围内的值。以下是我迄今为止:

// assuming portrait mode 
var beta0, gamma0; 
window.addEventListener('deviceorientation', function(orientation) { 
    if (typeof beta0 === 'undefined') { 
    beta0 = beta; 
    gamma0 = gamma; 
    } 

    console.log('user has moved to the left by', gamma - gamma0, ' and to the top by', beta - beta0); 
}); 

当设备大多是水平的,而不是在所有当它是垂直

回答

3

好的工作正常。首先,设备定向输入一个简单的解释:

绝对坐标系,(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')与绕ZZ' = 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, gammas, 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度的顶底部旋转)
+0

我尝试推行这种方法 - 请https://stackoverflow.com/questions/46975452/adjusting-mobile-accelerometer-data-to-account-for-phone-rotation - 我我得到不同的acc。我打开手机时的结果。你能评论一下,看看我是否错过了一些东西?谢谢 – user1361529