UNPKG

tofu.js

Version:

a helper three.js library for building UC-AR

117 lines (93 loc) 3.1 kB
import { EventDispatcher, Quaternion, Vector3, Euler } from 'three'; import Utils from './Utils'; const zee = new Vector3(0, 0, 1); const euler = new Euler(); const q0 = new Quaternion(); const q1 = new Quaternion(-Math.sqrt(0.5), 0, 0, Math.sqrt(0.5)); // - PI/2 around the x-axis const ROTATE_ORDER = 'YXZ'; class Orienter extends EventDispatcher { constructor(options) { super(); options = options || {}; this._orient = this._orient.bind(this); this._change = this._change.bind(this); this.needFix = Utils.isBoolean(options.needFix) ? options.needFix : true; this.fix = 0; this.timing = 8; this.alpha = 0; this.beta = 0; this.gamma = 0; this.lon = 0; this.lat = 0; this.direction = 0; this.quaternion = new Quaternion(); this.eared = false; this.nodce = true; this.connect(); } connect() { this._change(); if (this.eared) return; this.eared = true; window.addEventListener('deviceorientation', this._orient, false); window.addEventListener('orientationchange', this._change, false); } disconnect() { this.eared = false; window.removeEventListener('deviceorientation', this._orient, false); window.removeEventListener('orientationchange', this._change, false); } _orient(event) { if (!Utils.isNumber(event.alpha) || !Utils.isNumber(event.beta) || !Utils.isNumber(event.gamma)) { this.nodce = true; return; } if (this.needFix) { if (this.timing === 0) { this.needFix = false; this.fix = event.alpha; } this.timing--; } else { this.alpha = Utils.euclideanModulo(event.alpha - this.fix, 360); } this.nodce = false; this.beta = event.beta; this.gamma = event.gamma; this.update(); this.emit('deviceorientation', { alpha: this.alpha, beta: this.beta, gamma: this.gamma, lon: this.lon, lat: this.lat, quaternion: this.quaternion, }); } update() { if (!this.eared || this.nodce) return; const alpha = Utils.DTR(this.alpha); const beta = Utils.DTR(this.beta); const gamma = Utils.DTR(this.gamma); euler.set(beta, alpha, -gamma, ROTATE_ORDER); // 'ZXY' for the device, but 'YXZ' for us this.quaternion.setFromEuler(euler); // orient the device this.quaternion.multiply(q1); // camera looks out the back of the device, not the top this.quaternion.multiply(q0.setFromAxisAngle(zee, -this.direction)); // adjust for screen orientation this.calculation(); } calculation() { this.lon = Utils.euclideanModulo(this.alpha + this.gamma, 360); const face = new Vector3(0, 0, -1); face.applyQuaternion(this.quaternion); const xzFace = new Vector3(face.x, 0, face.z); const cos = Utils.clamp(xzFace.dot(face), -1, 1); const nor = face.y >= 0 ? 1 : -1; const degree = Utils.RTD(Math.acos(cos)); this.lat = this.beta < 0 ? nor * (180 - degree) : nor * degree; } _change() { this.direction = window.orientation || 0; this.update(); } } export default Orienter;