【问题标题】:Calculate compass heading from DeviceOrientation Event API从 DeviceOrientation 事件 API 计算罗盘航向
【发布时间】:2013-08-07 20:00:57
【问题描述】:

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

我从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 中。

是否有人发现我的方法有错误或知道计算指南针航向的更可靠方法?

【问题讨论】:

    标签: html google-chrome firefox math


    【解决方案1】:

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

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

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

    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 版谷歌浏览器
    • Opera Mobile for Android
    • 适用于 Android 的 Firefox 测试版

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

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

    【讨论】:

    • 感谢代码,指南针航向在我的 Galaxy Nexus 和 Chrome FF 上非常准确
    • stackoverflow.com/questions/16048514/… 上查看我更强大的跨平台答案。
    • 在 Samsung Galaxy 8(FF、Chrome)上尝试了您的代码 2018,似乎不起作用(evt.absolute 始终为假)
    • Chrome 最近引入了deviceorientationabsolute 事件,应该使用它来获取基于世界的坐标。信息和状态在这里:developer.mozilla.org/en-US/docs/Web/API/Window/…
    • 我推荐使用Math.atan2,因为Math.atan 仅提供+-pi/2 之间的角度。
    【解决方案2】:

    我也玩过一些DeviceOrientationEvent(可能会采用你的公式......)并且不时看到类似的问题。您可能想像video 那样尝试校准。您可以在 youtube 上搜索更多示例。

    【讨论】:

      【解决方案3】:

      似乎不推荐从设备方向事件中获取指南针方向,这可能是出于隐私原因。您应该查看需要权限的Geolocation API。事件有Coordinates.heading

      【讨论】:

      • 这里的问题是设备需要移动才能从 Coordinates.heading 获取读数。从您提供的链接中:“如果 Coordinates.speed 为 0,则标题为 NaN。”
      猜你喜欢
      • 2011-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多