У меня проблема с преобразованием значений ускорения устройства в систему координат Земли в веб-приложении с использованием чистого JavaScript (большинство вопросов, связанных с решениями, относятся к Android или iOS).
Я использую библиотеку gl-matrix для выполнения расчетов и пока основываю свое решение в основном на ответах, которые я нашел для нативных приложений Android. Что у меня пока есть для обработчиков событий для ориентации и движения:
readonly deg2rad = Math.PI / 180; // Degree-to-Radian conversion
rotMatrix: mat3;
relRotMatrix: mat3;
earthAcc: mat3;
resetOrientationPending: boolean = false;
handleOrientation(event) {
var absolute = event.absolute;
var alpha = event.alpha;
var beta = event.beta;
var gamma = event.gamma;
if (this.rotMatrix) {
let curRotMat = this.getRotationMatrix(alpha * this.deg2rad, beta * this.deg2rad, gamma * this.deg2rad);
this.relRotMatrix = mat3.multiply(mat3.create(), this.rotMatrix, curRotMat);
}
else if (this.resetOrientationPending) {
this.resetOrientationPending = false;
this.rotMatrix = mat3.transpose(mat3.create(), this.getRotationMatrix(alpha * this.deg2rad, beta * this.deg2rad, gamma * this.deg2rad));
}
}
handleMotion(event) {
let x = event.acceleration.x;
let y = event.acceleration.y;
let z = event.acceleration.z;
let accMatrix = mat3.fromTranslation(mat3.create(), [x, y, z]);
this.earthAcc = mat3.multiply(mat3.create(), this.relRotMatrix, accMatrix);
let ex = this.earthAcc[6];
let ey = this.earthAcc[7];
let ez = this.earthAcc[8];
}
getRotationMatrix(alpha: number, beta: number, gamma: number): mat3 {
let _x, _y, _z;
let cX, cY, cZ, sX, sY, sZ;
_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);
let res = mat3.create();
res[0] = cZ * cY + sZ * sX * sY; // row 1, col 1
res[1] = cX * sZ; // row 2, col 1
res[2] = -cZ * sY + sZ * sX * cY; // row 3, col 1
res[3] = -cY * sZ + cZ * sX * sY; // row 1, col 2
res[4] = cZ * cX; // row 2, col 2
res[5] = sZ * sY + cZ * cY * sX; // row 3, col 2
res[6] = cX * sY; // row 1, col 3
res[7] = -sX; // row 2, col 3
res[8] = cX * cY; // row 3, col 3
return res;
}
Если мой телефон лежит на столе (в портретном режиме), верхняя часть которого направлена от меня, и выполняю «resetOrientation», это работает для перемещения влево / вправо и вперед / назад. То есть, если я поверну телефон на 180 градусов вокруг оси z (имеется в виду, что он все еще лежит на столе), и верх будет направлен на меня, ускорение (матрица earthAcc в коде) для движения L / R и F / B будет все еще правильно. Но вверх / вниз не правильно, и как только я начинаю поворачивать телефон вокруг другой оси, я получаю противоречивые результаты.
Возможно, отсутствует только одна строка или что-то в этом роде, надеюсь, кто-то, кто является гуру матричной алгебры, обнаружит проблему:)
ОБНОВЛЕНИЕ: изменив способ создания accMatrix в handleMotion следующим образом:
let accMatrix = mat3.create();
accMatrix.set([0, 0, 0, 0, 0, 0, x, y, z]);
... У меня также работает UP / DOWN, но если я поворачиваю телефон по любой другой оси, кроме Z, он больше не дает правильных значений.
ОБНОВЛЕНИЕ 2: я тестирую это на iOS Safari (Iphone), поэтому не знаю, может ли это быть проблемой, связанной с типом устройства, но я использую библиотеку Gyronorm, которая должна возвращать нормализованные значения.