从DeviceOrientation Event API计算罗盘标题 [英] Calculate compass heading from DeviceOrientation Event API

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

问题描述

对于智能手机的增强现实网络应用程序,我试图计算指南针的标题,当用户手中拿着设备时,屏幕在垂直平面上,屏幕顶端朝上。



我已经从 http://dev.w3.org/geo/api/spec-source-orientation (见工作示例),并实现了以下功能:

<$ p $函数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; $。

$ b $ / code $ / pre

而.toDeg()是一个Number对象的扩展礼貌 http://www.movable-type.co.uk/scripts/latlong.html


$ b $

  / **将弧度转换为数字(带符号)度* / 
if(typeof Number。 prototype.toDeg =='undefined'){
Number.prototype.toDeg = function(){
return this * 180 / Math.PI;
};

$ / code>

然而,问题是计算出来的罗盘航向值从-75到80即使设备(谷歌Galaxy Nexus)被安装来保持一个静态的位置。这似乎发生在谷歌浏览器BETA和FF BETA 23中。



有人在我的方法中看到错误,或知道计算罗盘标题的更可靠的方法吗? / p>

解决方案 *根据规范中提供的工作示例确定指南针标题所需的步骤如下:


  • 转换返回的DeviceOrientation alpha alphaRad 从度数到弧度的beta gamma betaRad gammaRad

  • 计算rotationA( rA alphaRad 和rotationB( rB ) > betaRad gammaRad (如下面的示例代码所示)。
  • 计算 compassHeading = Math.atan(rA / rB)

  • 将返回的半个单位圆标题转换为整个单元c
  • compassHeading 从弧度转换回角度(可选)。
  • >


以下是在JavaScript中实现了规范中的示例

  function compassHeading(alpha ,beta,gamma){

//将度数转换为弧度
var alphaRad = alpha *(Math.PI / 180);
var betaRad = beta *(Math.PI / 180);
var gammaRad = gamma *(Math.PI / 180);

//计算方程组件
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);

//计算A,B,C旋转分量
var rA = - cA * sG - sA * sB * cG;
var rB = - sA * sG + cA * sB * cG;
var rC = - cB * cG;

//计算指南针标题
var compassHeading = Math.atan(rA / rB);

//从半个单位圆转换为整个单位圆
if(rB <0){
compassHeading + = Math.PI;
} else if(rA <0){
compassHeading + = 2 * Math.PI;
}

//将弧度转换为度
compassHeading * = 180 / Math.PI;

return compassHeading;


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

var heading = null;

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

//用标题...做一些事情...

},false);

您也可以



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


  • Google Chrome for Android

  • 适用于Android的Opera Mobile

  • 适用于Android的Firefox Beta


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

    * 确定正交矢量的水平分量的罗盘方向到设备的屏幕并指出屏幕的背面。


    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.

    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;
        }
    }
    

    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;
        };
    }  
    

    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:

    • 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).

    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);
    

    You can also view a demo of the code provided above.

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

    • Google Chrome for Android
    • Opera Mobile for Android
    • Firefox Beta for Android

    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.

    * Determining the compass heading of the horizontal component of a vector which is orthogonal to the device's screen and pointing out of the back of the screen.

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

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