使用四元数实现设备定向

Device orientation using Quaternion(使用四元数实现设备定向)
本文介绍了使用四元数实现设备定向的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了一个监听移动设备旋转的JS SDK,提供3个输入:

α:角度范围为0到360度
β:-180度至180度之间的角度
γ:-90度到90度之间的角度

Documentation for device rotation

我曾尝试使用欧拉角来确定设备方向,但遇到了gimbal lock effect,当设备指向上方时,导致计算爆炸。这导致我使用Quaternion,这不会受到万向节锁定效果的影响。

我找到了将α,β和γ转换为四元数的this js library,因此对于以下值:

α:81.7324
β:74.8036
γ:-84.3221

我得到ZXY订单的这个四元数:

w:0.7120695154301472
x:0.6893688637611577
y:-0.10864439143062626
z:0.07696733776346154

编码:

var rad = Math.PI / 180;
window.addEventListener("deviceorientation", function(ev) {

  // Update the rotation object
  var q = Quaternion.fromEuler(ev.alpha * rad, ev.beta * rad, ev.gamma * rad, 'ZXY');

  // Set the CSS style to the element you want to rotate
  elm.style.transform = "matrix3d(" + q.conjugate().toMatrix4() + ")";

}, true);

使用从四元数派生的4D CS矩阵可视化设备方向反映了正确的设备方向(DEMO, use mobile):


错误使用Euler Angels和开发工具可视化(DEMO, use mobile):


我想编写一个方法,用于在设备处于以下方向之一时获取α,β和γ并输出:

  • 肖像
  • 人像颠倒
  • 左侧横向
  • 横向向右
  • 向上显示
  • 向下显示
将每个方向定义为围绕相关轴的+-45°范围。

我应该采取什么方法?

推荐答案

假设您已经成功地将欧拉角转换为单位四元数,下面是确定设备方向的简单方法:

  1. 将世界空间向量直接指向(即沿+z轴),并使用四元数(或其共轭)将其旋转到设备坐标。(请注意,您也可以直接使用欧拉角,或使用旋转矩阵,或使用可用于变换矢量的设备旋转的任何其他表示法。)

  2. 取变换后的向量,找出绝对值最大的分量。这将告诉您设备的哪个轴指向最接近垂直,而组件值的符号告诉您它指向的是向上还是向下。

特别是:

  • 如果设备x轴最垂直,则设备处于横向;
  • 如果设备y轴最垂直,则设备处于纵向;
  • 如果设备z轴最垂直,则设备的屏幕指向向上或向下。

这里有一个简单的JS演示,它至少应该在Chrome上工作--或者它会工作,除了设备定向API似乎根本不能在Stack代码片断中工作。:(有关现场演示,请尝试this CodePen instead。

数据-lang="js"数据-隐藏="假"数据-控制台="真"数据-巴贝尔="假">
const orientations = [
  ['landscape left', 'landscape right'],  // device x axis points up/down
  ['portrait', 'portrait upside down'],   // device y axis points up/down
  ['display up', 'display down'],         // device z axis points up/down
];

const rad = Math.PI / 180;

function onOrientationChange (ev) {
  const q = Quaternion.fromEuler(ev.alpha * rad, ev.beta * rad, ev.gamma * rad, 'ZXY');

  // transform an upward-pointing vector to device coordinates
  const vec = q.conjugate().rotateVector([0, 0, 1]);

  // find the axis with the largest absolute value
  const [value, axis] = vec.reduce((acc, cur, idx) => (Math.abs(cur) < Math.abs(acc[0]) ? acc : [cur, idx]), [0, 0]);

  const orientation = orientations[axis][1 * (value < 0)];

  document.querySelector('#angles').textContent = `alpha = ${ev.alpha.toFixed(1)}°, beta = ${ev.beta.toFixed(1)}°, gamma = ${ev.gamma.toFixed(1)}°`;
  document.querySelector('#vec').textContent = `vec = ${vec.map(a => a.toFixed(3))}, dominant axis = ${axis}, value = ${value.toFixed(3)}`;
  document.querySelector('#orientation').textContent = `orientation = ${orientation}`;
}

onOrientationChange({ alpha: 0, beta: 0, gamma: 0 });
window.addEventListener("deviceorientation", onOrientationChange, true);
<script src="https://cdn.jsdelivr.net/npm/quaternion@1.1.0/quaternion.min.js"></script>
<div id="angles"></div>
<div id="vec"></div>
<div id="orientation"></div>

请注意,在设备定向API提供的欧拉角的符号和范围中,浏览器之间apparently存在一些不一致,这可能会导致在其他浏览器上计算错误的符号。您可能需要执行一些浏览器嗅探来修复此问题,或者使用类似gyronorm.js的包装库。

这篇关于使用四元数实现设备定向的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

Why local notification is not firing for UNCalendarNotificationTrigger(为什么没有为UNCalendarNotificationTrigger触发本地通知)
iOS VoiceOver functionality changes with Bundle Identifier(IOS画外音功能随捆绑包标识符而变化)
tabbar middle tab out of tabbar corner(选项卡栏中间的选项卡角外)
Pushing UIViewController above UITabBar(将UIView控制器推送到UITabBar上方)
Dropbox Files.download does not start when number of files in folder is gt; 1000(当文件夹中的文件数为1000时,Dropbox Files.Download不会启动)
How to target newer versions in .gitlab-ci.yml using auto devops (java 11 instead of 8 and Android 31 instead of 29)(如何在.gitlab-ci.yml中使用自动开发工具(Java 11而不是8,Android 31而不是29)瞄准较新的版本)