Va bene. In primo luogo, una semplice spiegazione dell'ingresso orientamento del dispositivo:
Il sistema di coordinate assoluto, (X, Y, Z)
è tale che X
è East, Y
è Nord e Z
è in alto. Il sistema di coordinate relative del dispositivo, (x, y, z)
è tale che x
è corretto, è in alto e z
è attivo. Poi gli angoli di orientamento, (alpha, beta, gamma)
sono gli angoli che descrivono la successione di tre semplici rotazioni che cambiano (X, Y, Z)
a (x, y, z)
come così:
- ruotano intorno
Z
da alpha
gradi, che trasforma (X, Y, Z)
a (X', Y', Z')
con Z'
= Z
- ruota intorno a
X'
di beta
gradi, che trasforma (X', Y', Z')
a (X'', Y'', Z'')
con X''
= X'
- ruotare intorno
Y''
da gamma
gradi, che trasforma (X'', Y'', Z'')
a (x, y, z)
con y
= Y''
(vengono chiamati intrinseche angoli Tait-Bryan di tipo Z-X'-Y''
)
Ora possiamo ottenere la matrice di rotazione corrispondente componendo semplice matrice di rotazione che corrisponde ciascuna a una delle tre rotazioni.
[ 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 ]
dove A, B, C
sono brevi per alpha, beta, gamma
e s, c
per sin, cos
.
Ora, ci interessa angoli di destra-sinistra (y
asse) e top-down (x
asse) rotazioni delta tra due posizioni (x, y, z)
e (x', y', z')
che corrispondono agli orientamenti (A, B, C)
e (A', B', C')
L' coordinate di (x', y', z')
in termini di (x, y, z)
sono date da R(A', B', C') * R(A, B, C)^-1 = R(A', B', C') * R(A, B, C)^T
poiché l'inversa è la trasposizione per matrice ortogonale (rotazione). Infine, se z' = p*x + q*y + r*z
, l'angolo di quelle rotazioni è p
attorno all'asse destra-sinistra e q
attorno a quello in alto (questo è vero per piccoli angoli, che presuppongono l'aggiornamento frequente dell'orientamento, altrimenti asin(p)
e asin(r)
sono più vicini alla verità)
ecco alcuni javascript per ottenere la matrice di rotazione:
/*
* 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
};
e ora otteniamo i delta angolari:
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;
}
Infine, per tenere conto di orientamento dello schermo, dobbiamo sostituire
_z = alpha;
_x = beta;
_y = gamma;
da
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;
}
noti che gli angoli di destra-sinistra e dall'alto verso il basso cumulative dipenderà del percorso scelto dall'utente, e non può essere dedotto direttamente dall'orientamento del dispositivo, ma deve essere tracciato attraverso il movimento. Si può arrivare alla stessa posizione con diversi movimenti:
Metodo 1:
- tenere il telefono in orizzontale e ruotare di 90 gradi in senso orario. (questa non è né una rotazione sinistra-destra né una rotazione dall'alto in basso)
- mantieni il telefono in modalità orizzontale e ruotalo di 90 verso di te. (questa non è una rotazione sinistra-destra di 90 gradi)
- mantieni il telefono di fronte a te e ruota di 90 in modo che sia attivo. (Questo non è né a 90 gradi di rotazione sinistra-destra)
Metodo 2:
- ruotare il telefono di 90 gradi in modo che esso si affronta e verticale (questo è a 90 gradi top- rotazione in basso)
ho provato attuazione di questo approccio - vedere https://stackoverflow.com/questions/46975452/adjusting-mobile-accelerometer-data-to-account-for-phone-rotation - I sto diventando diverso risultati mentre accendo il telefono. Puoi commentare per vedere se mi manca qualcosa? grazie – user1361529