对于智能手机的增强现实网络应用程序,当用户将设备拿在手中时,我会尝试计算罗盘航向,屏幕处于垂直平面且屏幕顶部朝上。
我从 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() 是一个数字对象扩展礼貌 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 中。
有人发现我的方法有误或知道计算罗盘航向的更可靠方法吗?
最佳答案
根据规范中提供的工作示例确定罗盘航向所需的步骤*如下:
- 将返回的 DeviceOrientation
alpha
、beta
和gamma
值从度数转换为弧度,如alphaRad
、betaRad
,gammaRad
. - 使用
alphaRad
、betaRad
和- 根据规范中的工作示例计算 rotationA (
rA
) 和 rotationB (rB
) 组件gammaRad
(如以下示例代码所示)。 - 根据规范中的工作示例计算 rotationA (
- 计算
compassHeading = Math.atan(rA/rB)
。 - 将返回的半单位圆航向转换为 [0-360) 度范围内的整个单位圆航向。
- 将
compassHeading
从弧度转换回度数(可选)。
这是 worked example from the specification用 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);
您也可以 view a demo of the code provided above .
截至撰写本文时(2014 年 2 月 17 日),它目前适用于:
- Android 版谷歌浏览器
- Android 版 Opera Mobile
- Android 版 Firefox 测试版
其他浏览器还不符合 DeviceOrientation 事件规范中描述的 DeviceOrientation 校准和/或不提供 absolute
DeviceOrientation 数据值,因此无法确定 compassHeading
数据不全。
* 确定垂直于设备屏幕并指向屏幕背面的矢量水平分量的罗盘航向。
关于html - 从 DeviceOrientation Event API 计算罗盘航向,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18112729/