微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

html5 – 从DeviceOrientation事件API计算罗盘方向

对于智能手机的增强现实网络应用程序,我正在尝试计算当用户手持设备时的罗盘方向,屏幕在垂直平面中,屏幕顶部朝上.

我从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()是一个Number对象扩展,由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;
    };
}

然而,问题在于,即使安装了设备(Google galaxy Nexus)以保持静态位置,计算出的罗盘航向值也会从大约-75跳到80.这似乎发生在Google Chrome BETA和FF BETA 23中.

有人在我的方法中看到错误或者知道更可靠的方法来计算罗盘方向吗?

解决方法

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

>将返回的DeviceOrientation alpha,beta和gamma值从度数转换为弧度为alpharad,betarad,gammarad.
>使用alpharad,betarad和gammarad计算规范中每个工作示例的rotationA(rA)和rotationB(rB)组件(如下面的示例代码所示).
>计算compassheading = Math.atan(rA / rB).
>将返回的半单位圆标题转换为[0-360]度范围内的整个单位圆标题.
>将compassheading从弧度转换回度(可选).

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

function compassheading(alpha,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日),目前适用于:

> Google Chrome for Android
>适用于Android的Opera Mobile
>适用于Android的Firefox Beta

其他浏览器尚未符合DeviceOrientation事件规范中描述的DeviceOrientation校准和/或不提供绝对的DeviceOrientation数据值,因此无法确定带有非完整数据的compassheading.

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

原文地址:https://www.jb51.cc/html5/168820.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。