对于智能手机的增强现实网络应用程序,我正在尝试计算用户手持设备时的指南针方向,屏幕处于垂直平面,屏幕顶部朝上。
我从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中。
有人在我的方法中看到错误或者知道更可靠的方法来计算罗盘标题吗?
答案 0 :(得分:12)
根据规范 *中提供的工作示例确定罗盘标题所需的步骤如下:
alpha
,beta
和gamma
值从度数转换为弧度为alphaRad
,betaRad
,gammaRad
。rA
,rB
和alphaRad
按照规范中的工作示例计算rotationA(betaRad
)和rotationB(gammaRad
)组件(如图所示)在下面的示例代码中。)compassHeading = Math.atan(rA / rB)
。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日),目前可用于:
其他浏览器尚未符合DeviceOrientation事件规范中描述的DeviceOrientation校准和/或未提供absolute
DeviceOrientation数据值,因此无法使用非完整数据确定compassHeading
。< / p>
* 确定向量的水平分量的罗盘方向,该向量与设备的屏幕正交并指向屏幕的背面。
答案 1 :(得分:0)
我也玩了一些DeviceOrientationEvent(可能会采用你的公式...),并不时看到类似的问题。您可能想要尝试校准,如video。您可以在youtube上搜索更多示例。
答案 2 :(得分:0)
似乎不建议从设备定向事件中获取指南针的方向,这可能是出于隐私原因。您应该查看Geolocation API,它需要权限。这些事件有Coordinates.heading。