html - 从 DeviceOrientation Event API 计算罗盘航向

标签 html google-chrome firefox math

对于智能手机的增强现实网络应用程序,当用户将设备拿在手中时,我会尝试计算罗盘航向,屏幕处于垂直平面且屏幕顶部朝上。

我从 http://dev.w3.org/geo/api/spec-source-orientation 中获取了建议的公式(参见工作示例)并实现了以下功能:

function compassHeading(alpha, beta, gamma) {
    var a1, a2, b1, b2;
    if ( beta !== 0 || gamma !== 0 ) {
        a1 = -Math.cos(alpha) * Math.sin(gamma);
        a2 = Math.sin(alpha) * Math.sin(beta) * Math.cos(gamma);
        b1 = -Math.sin(alpha) * Math.sin(gamma);
        b2 = Math.cos(alpha) * Math.sin(beta) * Math.cos(gamma);
        return Math.atan((a1 - a2) / (b1 + b2)).toDeg();
    }
    else {
        return 0;
    }
}

虽然 .toDeg() 是一个数字对象扩展礼貌 http://www.movable-type.co.uk/scripts/latlong.html

/** Converts radians to numeric (signed) degrees */
if (typeof Number.prototype.toDeg == 'undefined') {
    Number.prototype.toDeg = function() {
        return this * 180 / Math.PI;
    };
}  

但是,问题是计算出的罗盘航向值会从大约 -75 跳到 80,即使设备 (Google Galaxy Nexus) 安装为保持静止位置也是如此。这似乎发生在 Google Chrome BETA 和 FF BETA 23 中。

有人发现我的方法有误或知道计算罗盘航向的更可靠方法吗?

最佳答案

根据规范中提供的工作示例确定罗盘航向所需的步骤*如下:

  • 将返回的 DeviceOrientation alphabetagamma 值从度数转换为弧度,如 alphaRad betaRad, gammaRad.
  • 使用 alphaRadbetaRad
  • 根据规范中的工作示例计算 rotationA (rA) 和 rotationB (rB) 组件gammaRad(如以下示例代码所示)。
  • 计算 compassHeading = Math.atan(rA/rB)
  • 将返回的半单位圆航向转换为 [0-360) 度范围内的整个单位圆航向。
  • compassHeading 从弧度转换回度数(可选)。

这是 worked example from the specification用 JavaScript 实现:

function compassHeading(alpha, beta, gamma) {

  // Convert degrees to radians
  var alphaRad = alpha * (Math.PI / 180);
  var betaRad = beta * (Math.PI / 180);
  var gammaRad = gamma * (Math.PI / 180);

  // Calculate equation components
  var cA = Math.cos(alphaRad);
  var sA = Math.sin(alphaRad);
  var cB = Math.cos(betaRad);
  var sB = Math.sin(betaRad);
  var cG = Math.cos(gammaRad);
  var sG = Math.sin(gammaRad);

  // Calculate A, B, C rotation components
  var rA = - cA * sG - sA * sB * cG;
  var rB = - sA * sG + cA * sB * cG;
  var rC = - cB * cG;

  // Calculate compass heading
  var compassHeading = Math.atan(rA / rB);

  // Convert from half unit circle to whole unit circle
  if(rB < 0) {
    compassHeading += Math.PI;
  }else if(rA < 0) {
    compassHeading += 2 * Math.PI;
  }

  // Convert radians to degrees
  compassHeading *= 180 / Math.PI;

  return compassHeading;

}

window.addEventListener('deviceorientation', function(evt) {

  var heading = null;

  if(evt.absolute === true && evt.alpha !== null) {
    heading = compassHeading(evt.alpha, evt.beta, evt.gamma);
  }

  // Do something with 'heading'...

}, false);

您也可以 view a demo of the code provided above .

截至撰写本文时(2014 年 2 月 17 日),它目前适用于:

  • Android 版谷歌浏览器
  • Android 版 Opera Mobile
  • Android 版 Firefox 测试版

其他浏览器还不符合 DeviceOrientation 事件规范中描述的 DeviceOrientation 校准和/或不提供 absolute DeviceOrientation 数据值,因此无法确定 compassHeading数据不全。

* 确定垂直于设备屏幕并指向屏幕背面的矢量水平分量的罗盘航向。

关于html - 从 DeviceOrientation Event API 计算罗盘航向,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18112729/

相关文章:

Python Flask 从表单获取数据属性

css - 预加载关键帧中指定的 css 背景图像

Java 小程序在 Firefox 中无法运行

java - 使用 Selenium WebDriver 启动 Firefox 时出现 NotConnectedException

jquery - 将鼠标悬停在选择下拉菜单上时,包含 div 会失去焦点

javascript - 为 IE10 制作特定的 css 代码

javascript - 滚动时导航栏样式闪烁

javascript - document.fileSize 浏览器支持

javascript - 根据下拉选择和文本框值更改 url

google-chrome - 识别 Chrome 网页