从 DeviceOrientation Event API 计算罗盘航向 [英] Calculate compass heading from 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
alpha
、beta
和gamma
值从度数转换为弧度为alphaRad
、betaRad
,gammaRad
. - 使用
alphaRad
、betaRad<,根据规范中的工作示例计算rotationA (
rA
) 和rotationB (rB
) 组件/code> 和gammaRad
(如下面的示例代码所示). - 计算
compassHeading = Math.atan(rA/rB)
. - 将返回的半单位圆航向转换为 [0-360) 度范围内的整个单位圆航向.
- 将
compassHeading
从弧度转换回角度(可选).
- Convert returned DeviceOrientation
alpha
,beta
andgamma
values from degrees to radians asalphaRad
,betaRad
,gammaRad
. - Compute rotationA (
rA
) and rotationB (rB
) components per the worked example in the specification usingalphaRad
,betaRad
andgammaRad
(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屋!