从 DeviceOrientation Event API 计算罗盘航向 [英] Calculate compass heading from DeviceOrientation Event API

查看:23
本文介绍了从 DeviceOrientation Event API 计算罗盘航向的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于智能手机的增强现实网络应用,我试图计算当用户将设备拿在手中时的指南针航向,屏幕处于垂直平面且屏幕顶部朝上.

For an augmented reality web app for smartphones I'm trying to calculate the compass heading when the user is holding the device in their hand, with the screen in a vertical plane and the top of the screen pointing upwards.

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

I have taken the suggested formula from http://dev.w3.org/geo/api/spec-source-orientation (see Worked Example) and implemented the following function:

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() 是一个 Number 对象扩展礼貌 http://www.movable-type.co.uk/scripts/latlong.html

while .toDeg() is a Number object extension courtesy 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 中.

However, the problem is that the calculated compass heading value jumps from about -75 to 80 even if the device (Google Galaxy Nexus) is mounted to hold a static position. This seems to happen in both Google Chrome BETA and FF BETA 23.

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

Does somebody see an error in my approach or know a more reliable way to calculate the compass heading?

推荐答案

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

The steps you need to determine the compass heading according to the worked example provided in the specification* are as follows:

  • 将返回的 DeviceOrientation alphabetagamma 值从度数转换为弧度为 alphaRadbetaRad, gammaRad.
  • 使用alphaRadbetaRad<,根据规范中的工作示例计算rotationA (rA) 和rotationB (rB) 组件/code> 和 gammaRad(如下面的示例代码所示).
  • 计算 compassHeading = Math.atan(rA/rB).
  • 将返回的半单位圆航向转换为 [0-360) 度范围内的整个单位圆航向.
  • compassHeading 从弧度转换回角度(可选).
  • Convert returned DeviceOrientation alpha, beta and gamma values from degrees to radians as alphaRad, betaRad, gammaRad.
  • Compute rotationA (rA) and rotationB (rB) components per the worked example in the specification using alphaRad, betaRad and gammaRad (as shown in the example code below).
  • Compute compassHeading = Math.atan(rA / rB).
  • Convert returned half unit circle headings to whole unit circle headings in the range [0-360) degrees.
  • Convert compassHeading from radians back to degrees (optional).

这是规范中的工作示例 在 JavaScript 中实现:

Here is the worked example from the specification implemented in 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);

您还可以查看所提供代码的演示上面.

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

As of the time of writing (17th Feb 2014) this currently works in:

  • Android 版谷歌浏览器
  • Android 版 Opera 手机
  • Android 版 Firefox Beta

其他浏览器尚不符合 DeviceOrientation 事件规范中描述的 DeviceOrientation 校准和/或不提供 absolute DeviceOrientation 数据值,从而无法确定 compassHeading数据不完整.

Other browsers do not yet conform to the DeviceOrientation calibration described in the DeviceOrientation Event specification and/or do not provide absolute DeviceOrientation data values making it impossible to determine compassHeading with non-complete data.

* 确定与设备屏幕正交并指向屏幕背面的矢量水平分量的罗盘航向.

这篇关于从 DeviceOrientation Event API 计算罗盘航向的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆