html5 - Calculate compass heading from DeviceOrientation Event API -
for augmented reality web app smartphones i'm trying calculate compass heading when user holding device in hand, screen in vertical plane , top of screen pointing upwards.
i have taken suggested formula http://dev.w3.org/geo/api/spec-source-orientation (see worked example) , implemented 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() number object extension courtesy http://www.movable-type.co.uk/scripts/latlong.html
/** converts radians numeric (signed) degrees */ if (typeof number.prototype.todeg == 'undefined') { number.prototype.todeg = function() { return * 180 / math.pi; }; }
however, problem calculated compass heading value jumps -75 80 if device (google galaxy nexus) mounted hold static position. seems happen in both google chrome beta , ff beta 23.
does see error in approach or know more reliable way calculate compass heading?
the steps need determine compass heading according worked example provided in specification* follows:
- convert returned deviceorientation
alpha
,beta
,gamma
values degrees radiansalpharad
,betarad
,gammarad
. - compute rotationa (
ra
) , rotationb (rb
) components per worked example in specification usingalpharad
,betarad
,gammarad
(as shown in example code below). - compute
compassheading = math.atan(ra / rb)
. - convert returned half unit circle headings whole unit circle headings in range [0-360) degrees.
- convert
compassheading
radians degrees (optional).
here worked example specification implemented in javascript:
function compassheading(alpha, beta, gamma) { // convert degrees 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 half unit circle whole unit circle if(rb < 0) { compassheading += math.pi; }else if(ra < 0) { compassheading += 2 * math.pi; } // convert radians 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); } // 'heading'... }, false);
you can view demo of code provided above.
as of time of writing (17th feb 2014) works in:
- google chrome android
- opera mobile android
- firefox beta android
other browsers not yet conform deviceorientation calibration described in deviceorientation event specification and/or not provide absolute
deviceorientation data values making impossible determine compassheading
non-complete data.
* determining compass heading of horizontal component of vector orthogonal device's screen , pointing out of of screen.
Comments
Post a Comment