gpt4 book ai didi

html5 - 获取相对坐标中的设备方向旋转

转载 作者:太空狗 更新时间:2023-10-29 14:55:00 24 4
gpt4 key购买 nike

我正在尝试沿左右轴和上下轴在两个 deviceorientation 事件之间改变方向,这些轴通常定义为手机 xy 轴 ( https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Orientation_and_motion_data_explained )

即在 t1t2 之间,电话轴从 (x1, y1) 移动到 (x2, y2) ,它想要得到(angle(x2-x1), angle(y1-y2))

当设备处于纵向模式(与横向模式相反)时,这些轴似乎对应于 betagamma。但是当手机垂直(底部朝向地面)时,gamma 值变得极不稳定,从 90 度跳到 -90 度(同时,alpha 跳了 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);
});

当设备大部分是水平的时候它工作正常,而当它是垂直的时候根本不工作

最佳答案

好的。先简单解释下设备方向输入:

绝对坐标系,(X, Y, Z) 是这样的,X 是东,Y 是北, Z 已启动。设备相对坐标系 (x, y, z)x 在右,y 在上,z 已启动。然后方向角 (alpha, beta, gamma) 是描述三个简单旋转的连续角度,这些旋转将 (X, Y, Z) 更改为 (x, y, z) 这样:

  • 围绕 Z 旋转 alpha 度,将 (X, Y, Z) 转换为 (X', Y' , 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'' 类型的固有 Tait-Bryan 角)

现在我们可以通过组合简单的旋转矩阵来得到相应的旋转矩阵,每个旋转矩阵对应三个旋转中的一个。

                                 [   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、Calpha、beta、gamma 的缩写,s、csin、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,则这些旋转的角度是围绕左右轴的 pq 围绕自上而下的一个(这对于小角度是正确的,假设频繁的方向更新,否则 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 screen = window.screen;
const getScreenOrientation = () => {
const oriented = screen && (screen.orientation || screen.mozOrientation);
if (oriented) switch (oriented.type || oriented) {
case 'landscape-primary':
return 90;
case 'landscape-secondary':
return -90;
case 'portrait-secondary':
return 180;
case 'portrait-primary':
return 0;
}
return window.orientation|0; // defaults to zero if orientation is unsupported
};

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;
}

请注意,累积的左右角度和上下角度将取决于用户选择的路径,不能直接从设备方向推断,但必须通过运动进行跟踪。您可以通过不同的 Action 到达相同的位置:

  • 方法一:

    • 保持手机水平并顺时针旋转 90 度。 (这既不是左右旋转也不是上下旋转)
    • 将您的手机保持横向模式并朝您旋转 90 度。 (这既不是90度左右旋转)
    • 让您的手机面向您并旋转 90 度,使其朝上。 (这既不是90度左右旋转)
  • 方法二:

    • 将手机旋转 90 度,使其面向您并垂直(这是上下旋转 90 度)

关于html5 - 获取相对坐标中的设备方向旋转,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36639182/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com