@egjs/view360
Version:
360 integrated viewing solution from inside-out view to outside-in view. It provides user-friendly service by rotating 360 degrees through various user interaction such as motion sensor and touch.
1,800 lines (1,494 loc) • 208 kB
JavaScript
import PosePredictor from 'webvr-polyfill/src/sensor-fusion/pose-predictor';
import Util from 'webvr-polyfill/src/util';
import MathUtil from 'webvr-polyfill/src/math-util';
import ComplementaryFilter from 'webvr-polyfill/src/sensor-fusion/complementary-filter';
import _ESPromise from 'es6-promise';
import Agent from '@egjs/agent';
import Axes, { PanInput, PinchInput, MoveKeyInput, WheelInput } from '@egjs/axes';
import Component from '@egjs/component';
function _extends() {
_extends = Object.assign || function (target) {
for (var i = 1; i < arguments.length; i++) {
var source = arguments[i];
for (var key in source) {
if (Object.prototype.hasOwnProperty.call(source, key)) {
target[key] = source[key];
}
}
}
return target;
};
return _extends.apply(this, arguments);
}
function _inheritsLoose(subClass, superClass) {
subClass.prototype = Object.create(superClass.prototype);
subClass.prototype.constructor = subClass;
subClass.__proto__ = superClass;
}
function _assertThisInitialized(self) {
if (self === void 0) {
throw new ReferenceError("this hasn't been initialised - super() hasn't been called");
}
return self;
}
/**
* Copyright (c) 2015 NAVER Corp.
* egjs projects are licensed under the MIT license
*/
/* eslint-disable no-new-func, no-nested-ternary */
var win = typeof window !== "undefined" && window.Math === Math ? window : typeof self !== "undefined" && self.Math === Math ? self : Function("return this")();
/* eslint-enable no-new-func, no-nested-ternary */
var doc = win.document;
var userAgent = win.navigator.userAgent;
var IS_SAFARI_ON_DESKTOP = userAgent.indexOf("Safari") !== -1 && userAgent.indexOf("Chrome") === -1 && userAgent.indexOf("Mac OS X") !== -1;
/**
* Copyright (c) 2015 NAVER Corp.
* egjs projects are licensed under the MIT license
*/
win.Float32Array = typeof win.Float32Array !== "undefined" ? win.Float32Array : win.Array;
var Float32Array$1 = win.Float32Array;
var getComputedStyle = win.getComputedStyle;
var userAgent$1 = win.navigator.userAgent;
var SUPPORT_TOUCH = "ontouchstart" in win;
var SUPPORT_DEVICEMOTION = "ondevicemotion" in win;
var DeviceMotionEvent = win.DeviceMotionEvent;
var devicePixelRatio = win.devicePixelRatio;
var TRANSFORM = function () {
var docStyle = doc.documentElement.style;
var target = ["transform", "webkitTransform", "msTransform", "mozTransform"];
for (var i = 0, len = target.length; i < len; i++) {
if (target[i] in docStyle) {
return target[i];
}
}
return "";
}(); // check for will-change support
var SUPPORT_WILLCHANGE = win.CSS && win.CSS.supports && win.CSS.supports("will-change", "transform");
function toAxis(source, offset) {
return offset.reduce(function (acc, v, i) {
if (source[i]) {
acc[source[i]] = v;
}
return acc;
}, {});
}
/**
* Original Code
* https://github.com/toji/gl-matrix/blob/v2.3.2/src/gl-matrix/common.js
* Common utilities
* modified by egjs
*/
var glMatrix = {};
glMatrix.ARRAY_TYPE = typeof Float32Array !== 'undefined' ? Float32Array : Array;
var degree = Math.PI / 180;
glMatrix.toRadian = function (a) {
return a * degree;
};
glMatrix.toDegree = function (a) {
return a / degree;
}; // glMatrix.EPSILON = 0.000001;
glMatrix.EPSILON = 0.0001;
/**
* Original Code
* https://github.com/toji/gl-matrix/blob/v2.3.2/src/gl-matrix/vec3.js
* 3 Dimensional Vector Util
* modified by egjs
*/
/**
* @class 3 Dimensional Vector
* @name vec3
*/
var vec3 = {};
/**
* Creates a new, empty vec3
*
* @returns {vec3} a new 3D vector
*/
vec3.create = function () {
var out = new glMatrix.ARRAY_TYPE(3);
out[0] = 0;
out[1] = 0;
out[2] = 0;
return out;
};
/**
* Creates a new vec3 initialized with the given values
*
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @returns {vec3} a new 3D vector
*/
vec3.fromValues = function (x, y, z) {
var out = new glMatrix.ARRAY_TYPE(3);
out[0] = x;
out[1] = y;
out[2] = z;
return out;
};
vec3.set = function (out, x, y, z) {
out[0] = x;
out[1] = y;
out[2] = z;
return out;
};
vec3.copy = function (out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
return out;
};
/**
* Scales a vec3 by a scalar number
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to scale
* @param {Number} b amount to scale the vector by
* @returns {vec3} out
*/
vec3.scale = function (out, a, b) {
out[0] = a[0] * b;
out[1] = a[1] * b;
out[2] = a[2] * b;
return out;
};
/**
* Subtracts vector b from vector a
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
vec3.subtract = function (out, a, b) {
out[0] = a[0] - b[0];
out[1] = a[1] - b[1];
out[2] = a[2] - b[2];
return out;
};
/**
* Calculates the length of a vec3
*
* @param {vec3} a vector to calculate length of
* @returns {Number} length of a
*/
vec3.length = function (a) {
var x = a[0],
y = a[1],
z = a[2];
return Math.sqrt(x * x + y * y + z * z);
};
/**
* Normalize a vec3
*
* @param {vec3} out the receiving vector
* @param {vec3} a vector to normalize
* @returns {vec3} out
*/
vec3.normalize = function (out, a) {
var x = a[0],
y = a[1],
z = a[2];
var len = x * x + y * y + z * z;
if (len > 0) {
//TODO: evaluate use of glm_invsqrt here?
len = 1 / Math.sqrt(len);
out[0] = a[0] * len;
out[1] = a[1] * len;
out[2] = a[2] * len;
}
return out;
};
/**
* Calculates the dot product of two vec3's
*
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {Number} dot product of a and b
*/
vec3.dot = function (a, b) {
return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
};
/**
* Computes the cross product of two vec3's
*
* @param {vec3} out the receiving vector
* @param {vec3} a the first operand
* @param {vec3} b the second operand
* @returns {vec3} out
*/
vec3.cross = function (out, a, b) {
var ax = a[0],
ay = a[1],
az = a[2],
bx = b[0],
by = b[1],
bz = b[2];
out[0] = ay * bz - az * by;
out[1] = az * bx - ax * bz;
out[2] = ax * by - ay * bx;
return out;
};
/**
* Transforms the vec3 with a quat
*
* @param {vec3} out the receiving vector
* @param {vec3} a the vector to transform
* @param {quat} q quaternion to transform with
* @returns {vec3} out
*/
vec3.transformQuat = function (out, a, q) {
// benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
var x = a[0],
y = a[1],
z = a[2],
qx = q[0],
qy = q[1],
qz = q[2],
qw = q[3],
// calculate quat * vec
ix = qw * x + qy * z - qz * y,
iy = qw * y + qz * x - qx * z,
iz = qw * z + qx * y - qy * x,
iw = -qx * x - qy * y - qz * z; // calculate result * inverse quat
out[0] = ix * qw + iw * -qx + iy * -qz - iz * -qy;
out[1] = iy * qw + iw * -qy + iz * -qx - ix * -qz;
out[2] = iz * qw + iw * -qz + ix * -qy - iy * -qx;
return out;
};
/**
* Rotate a 3D vector around the z-axis
* @param {vec3} out The receiving vec3
* @param {vec3} a The vec3 point to rotate
* @param {vec3} b The origin of the rotation
* @param {Number} c The angle of rotation
* @returns {vec3} out
*/
vec3.rotateZ = function (out, a, b, c) {
var p = [],
r = []; //Translate point to the origin
p[0] = a[0] - b[0];
p[1] = a[1] - b[1];
p[2] = a[2] - b[2]; //perform rotation
r[0] = p[0] * Math.cos(c) - p[1] * Math.sin(c);
r[1] = p[0] * Math.sin(c) + p[1] * Math.cos(c);
r[2] = p[2]; //translate to correct position
out[0] = r[0] + b[0];
out[1] = r[1] + b[1];
out[2] = r[2] + b[2];
return out;
};
/**
* Original Code
* https://github.com/toji/gl-matrix/blob/v2.3.2/src/gl-matrix/vec2.js
* 2 Dimensional Vector Util
* modified by egjs
*/
/**
* @class 2 Dimensional Vector
* @name vec2
*/
var vec2 = {};
vec2.copy = function (out, a) {
out[0] = a[0];
out[1] = a[1];
return out;
};
/**
* Original Code
* https://github.com/toji/gl-matrix/blob/v2.3.2/src/gl-matrix/quat.js
* Quaternion util
* modified by egjs
*/
/**
* @class Quaternion
* @name quat
*/
var quat = {};
/**
* Creates a new identity quat
*
* @returns {quat} a new quaternion
*/
quat.create = function () {
var out = new glMatrix.ARRAY_TYPE(4);
out[0] = 0;
out[1] = 0;
out[2] = 0;
out[3] = 1;
return out;
};
/**
* Creates a new quat initialized with values from an existing quaternion
*
* @param {quat} a quaternion to clone
* @returns {quat} a new quaternion
* @function
*/
quat.clone = function (a) {
var out = new glMatrix.ARRAY_TYPE(4);
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
return out;
};
/**
* Creates a new quat initialized with the given values
*
* @param {Number} x X component
* @param {Number} y Y component
* @param {Number} z Z component
* @param {Number} w W component
* @returns {quat} a new quaternion
* @function
*/
quat.fromValues = function (x, y, z, w) {
var out = new glMatrix.ARRAY_TYPE(4);
out[0] = x;
out[1] = y;
out[2] = z;
out[3] = w;
return out;
};
/**
* Copy the values from one quat to another
*
* @param {quat} out the receiving quaternion
* @param {quat} a the source quaternion
* @returns {quat} out
* @function
*/
quat.copy = function (out, a) {
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
return out;
};
/**
* Sets a quat from the given angle and rotation axis,
* then returns it.
*
* @param {quat} out the receiving quaternion
* @param {vec3} axis the axis around which to rotate
* @param {Number} rad the angle in radians
* @returns {quat} out
**/
quat.setAxisAngle = function (out, axis, rad) {
rad = rad * 0.5;
var s = Math.sin(rad);
out[0] = s * axis[0];
out[1] = s * axis[1];
out[2] = s * axis[2];
out[3] = Math.cos(rad);
return out;
};
/**
* Multiplies two quat's
*
* @param {quat} out the receiving quaternion
* @param {quat} a the first operand
* @param {quat} b the second operand
* @returns {quat} out
*/
quat.multiply = function (out, a, b) {
var ax = a[0],
ay = a[1],
az = a[2],
aw = a[3],
bx = b[0],
by = b[1],
bz = b[2],
bw = b[3];
out[0] = ax * bw + aw * bx + ay * bz - az * by;
out[1] = ay * bw + aw * by + az * bx - ax * bz;
out[2] = az * bw + aw * bz + ax * by - ay * bx;
out[3] = aw * bw - ax * bx - ay * by - az * bz;
return out;
};
/**
* Rotates a quaternion by the given angle about the X axis
*
* @param {quat} out quat receiving operation result
* @param {quat} a quat to rotate
* @param {number} rad angle (in radians) to rotate
* @returns {quat} out
*/
quat.rotateX = function (out, a, rad) {
rad *= 0.5;
var ax = a[0],
ay = a[1],
az = a[2],
aw = a[3],
bx = Math.sin(rad),
bw = Math.cos(rad);
out[0] = ax * bw + aw * bx;
out[1] = ay * bw + az * bx;
out[2] = az * bw - ay * bx;
out[3] = aw * bw - ax * bx;
return out;
};
/**
* Rotates a quaternion by the given angle about the Y axis
*
* @param {quat} out quat receiving operation result
* @param {quat} a quat to rotate
* @param {number} rad angle (in radians) to rotate
* @returns {quat} out
*/
quat.rotateY = function (out, a, rad) {
rad *= 0.5;
var ax = a[0],
ay = a[1],
az = a[2],
aw = a[3],
by = Math.sin(rad),
bw = Math.cos(rad);
out[0] = ax * bw - az * by;
out[1] = ay * bw + aw * by;
out[2] = az * bw + ax * by;
out[3] = aw * bw - ay * by;
return out;
};
/**
* Calculates the conjugate of a quat
* If the quaternion is normalized, this function is faster than quat.inverse and produces the same result.
*
* @param {quat} out the receiving quaternion
* @param {quat} a quat to calculate conjugate of
* @returns {quat} out
*/
quat.conjugate = function (out, a) {
out[0] = -a[0];
out[1] = -a[1];
out[2] = -a[2];
out[3] = a[3];
return out;
};
/**
* Normalize a quat
*
* @param {quat} out the receiving quaternion
* @param {quat} a quaternion to normalize
* @returns {quat} out
* @function
*/
quat.normalize = function (out, a) {
var x = a[0],
y = a[1],
z = a[2],
w = a[3];
var len = x * x + y * y + z * z + w * w;
if (len > 0) {
len = 1 / Math.sqrt(len);
out[0] = x * len;
out[1] = y * len;
out[2] = z * len;
out[3] = w * len;
}
return out;
};
/**
* Returns whether or not the quaternions have approximately the same elements in the same position (when compared with ===)
*
* @param {quat} a The first quaternion.
* @param {quat} b The second quaternion.
* @returns {Boolean} True if the vectors are equal, false otherwise.
*/
quat.equals = function (a, b) {
var a0 = a[0],
a1 = a[1],
a2 = a[2],
a3 = a[3];
var b0 = b[0],
b1 = b[1],
b2 = b[2],
b3 = b[3];
return Math.abs(a0 - b0) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a0), Math.abs(b0)) && Math.abs(a1 - b1) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a1), Math.abs(b1)) && Math.abs(a2 - b2) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a2), Math.abs(b2)) && Math.abs(a3 - b3) <= glMatrix.EPSILON * Math.max(1.0, Math.abs(a3), Math.abs(b3));
};
/**
* Returns whether or not the quaternions have exactly the same elements in the same position (when compared with ===)
*
* @param {quat} a The first quaternion.
* @param {quat} b The second quaternion.
* @returns {Boolean} True if the vectors are equal, false otherwise.
*/
quat.exactEquals = function (a, b) {
return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3];
};
/**
* Original Code
* https://github.com/toji/gl-matrix/blob/v2.3.2/src/gl-matrix/mat4.js
* 4x4 Matrix util
* modified by egjs
*/
/**
* @class 4x4 Matrix
* @name mat4
*/
var mat4 = {};
/**
* Creates a new identity mat4
*
* @returns {mat4} a new 4x4 matrix
*/
mat4.create = function () {
var out = new glMatrix.ARRAY_TYPE(16);
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = 1;
out[6] = 0;
out[7] = 0;
out[8] = 0;
out[9] = 0;
out[10] = 1;
out[11] = 0;
out[12] = 0;
out[13] = 0;
out[14] = 0;
out[15] = 1;
return out;
};
/**
* Set a mat4 to the identity matrix
*
* @param {mat4} out the receiving matrix
* @returns {mat4} out
*/
mat4.identity = function (out) {
out[0] = 1;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = 1;
out[6] = 0;
out[7] = 0;
out[8] = 0;
out[9] = 0;
out[10] = 1;
out[11] = 0;
out[12] = 0;
out[13] = 0;
out[14] = 0;
out[15] = 1;
return out;
};
/**
* Rotates a matrix by the given angle around the X axis not using SIMD
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat4} out
*/
mat4.rotateX = function (out, a, rad) {
var s = Math.sin(rad),
c = Math.cos(rad),
a10 = a[4],
a11 = a[5],
a12 = a[6],
a13 = a[7],
a20 = a[8],
a21 = a[9],
a22 = a[10],
a23 = a[11];
if (a !== out) {
// If the source and destination differ, copy the unchanged rows
out[0] = a[0];
out[1] = a[1];
out[2] = a[2];
out[3] = a[3];
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
} // Perform axis-specific matrix multiplication
out[4] = a10 * c + a20 * s;
out[5] = a11 * c + a21 * s;
out[6] = a12 * c + a22 * s;
out[7] = a13 * c + a23 * s;
out[8] = a20 * c - a10 * s;
out[9] = a21 * c - a11 * s;
out[10] = a22 * c - a12 * s;
out[11] = a23 * c - a13 * s;
return out;
};
/**
* Rotates a matrix by the given angle around the Y axis not using SIMD
*
* @param {mat4} out the receiving matrix
* @param {mat4} a the matrix to rotate
* @param {Number} rad the angle to rotate the matrix by
* @returns {mat4} out
*/
mat4.rotateY = function (out, a, rad) {
var s = Math.sin(rad),
c = Math.cos(rad),
a00 = a[0],
a01 = a[1],
a02 = a[2],
a03 = a[3],
a20 = a[8],
a21 = a[9],
a22 = a[10],
a23 = a[11];
if (a !== out) {
// If the source and destination differ, copy the unchanged rows
out[4] = a[4];
out[5] = a[5];
out[6] = a[6];
out[7] = a[7];
out[12] = a[12];
out[13] = a[13];
out[14] = a[14];
out[15] = a[15];
} // Perform axis-specific matrix multiplication
out[0] = a00 * c - a20 * s;
out[1] = a01 * c - a21 * s;
out[2] = a02 * c - a22 * s;
out[3] = a03 * c - a23 * s;
out[8] = a00 * s + a20 * c;
out[9] = a01 * s + a21 * c;
out[10] = a02 * s + a22 * c;
out[11] = a03 * s + a23 * c;
return out;
};
/**
* Calculates a 4x4 matrix from the given quaternion
*
* @param {mat4} out mat4 receiving operation result
* @param {quat} q Quaternion to create matrix from
*
* @returns {mat4} out
*/
mat4.fromQuat = function (out, q) {
var x = q[0],
y = q[1],
z = q[2],
w = q[3],
x2 = x + x,
y2 = y + y,
z2 = z + z,
xx = x * x2,
yx = y * x2,
yy = y * y2,
zx = z * x2,
zy = z * y2,
zz = z * z2,
wx = w * x2,
wy = w * y2,
wz = w * z2;
out[0] = 1 - yy - zz;
out[1] = yx + wz;
out[2] = zx - wy;
out[3] = 0;
out[4] = yx - wz;
out[5] = 1 - xx - zz;
out[6] = zy + wx;
out[7] = 0;
out[8] = zx + wy;
out[9] = zy - wx;
out[10] = 1 - xx - yy;
out[11] = 0;
out[12] = 0;
out[13] = 0;
out[14] = 0;
out[15] = 1;
return out;
};
/**
* Generates a perspective projection matrix with the given bounds
*
* @param {mat4} out mat4 frustum matrix will be written into
* @param {number} fovy Vertical field of view in radians
* @param {number} aspect Aspect ratio. typically viewport width/height
* @param {number} near Near bound of the frustum
* @param {number} far Far bound of the frustum
* @returns {mat4} out
*/
mat4.perspective = function (out, fovy, aspect, near, far) {
var f = 1.0 / Math.tan(fovy / 2),
nf = 1 / (near - far);
out[0] = f / aspect;
out[1] = 0;
out[2] = 0;
out[3] = 0;
out[4] = 0;
out[5] = f;
out[6] = 0;
out[7] = 0;
out[8] = 0;
out[9] = 0;
out[10] = (far + near) * nf;
out[11] = -1;
out[12] = 0;
out[13] = 0;
out[14] = 2 * far * near * nf;
out[15] = 0;
return out;
};
/**
* Original Code
* https://github.com/toji/gl-matrix/blob/v2.3.2/src/gl-matrix.js
* Math Util
* modified by egjs
*/
function quatToVec3(quaternion) {
var baseV = vec3.fromValues(0, 0, 1);
vec3.transformQuat(baseV, baseV, quaternion);
return baseV;
}
var util = {};
util.isPowerOfTwo = function (n) {
return n && (n & n - 1) === 0;
};
util.extractPitchFromQuat = function (quaternion) {
var baseV = quatToVec3(quaternion);
return -1 * Math.atan2(baseV[1], Math.sqrt(Math.pow(baseV[0], 2) + Math.pow(baseV[2], 2)));
}; // implement reference
// the general equation of a plane : http://www.gisdeveloper.co.kr/entry/평면의-공식
// calculating angle between two vectors : http://darkpgmr.tistory.com/121
var ROTATE_CONSTANT = {
PITCH_DELTA: 1,
YAW_DELTA_BY_ROLL: 2,
YAW_DELTA_BY_YAW: 3
};
ROTATE_CONSTANT[ROTATE_CONSTANT.PITCH_DELTA] = {
targetAxis: [0, 1, 0],
meshPoint: [0, 0, 1]
};
ROTATE_CONSTANT[ROTATE_CONSTANT.YAW_DELTA_BY_ROLL] = {
targetAxis: [0, 1, 0],
meshPoint: [1, 0, 0]
};
ROTATE_CONSTANT[ROTATE_CONSTANT.YAW_DELTA_BY_YAW] = {
targetAxis: [1, 0, 0],
meshPoint: [0, 0, 1]
};
function getRotationDelta(prevQ, curQ, rotateKind) {
var targetAxis = vec3.fromValues(ROTATE_CONSTANT[rotateKind].targetAxis[0], ROTATE_CONSTANT[rotateKind].targetAxis[1], ROTATE_CONSTANT[rotateKind].targetAxis[2]);
var meshPoint = ROTATE_CONSTANT[rotateKind].meshPoint;
var prevQuaternion = quat.clone(prevQ);
var curQuaternion = quat.clone(curQ);
quat.normalize(prevQuaternion, prevQuaternion);
quat.normalize(curQuaternion, curQuaternion);
var prevPoint = vec3.fromValues(0, 0, 1);
var curPoint = vec3.fromValues(0, 0, 1);
vec3.transformQuat(prevPoint, prevPoint, prevQuaternion);
vec3.transformQuat(curPoint, curPoint, curQuaternion);
vec3.transformQuat(targetAxis, targetAxis, curQuaternion);
var rotateDistance = vec3.dot(targetAxis, vec3.cross(vec3.create(), prevPoint, curPoint));
var rotateDirection = rotateDistance > 0 ? 1 : -1; // when counter clock wise, use vec3.fromValues(0,1,0)
// when clock wise, use vec3.fromValues(0,-1,0)
// const meshPoint1 = vec3.fromValues(0, 0, 0);
var meshPoint2 = vec3.fromValues(meshPoint[0], meshPoint[1], meshPoint[2]);
var meshPoint3;
if (rotateKind !== ROTATE_CONSTANT.YAW_DELTA_BY_YAW) {
meshPoint3 = vec3.fromValues(0, rotateDirection, 0);
} else {
meshPoint3 = vec3.fromValues(rotateDirection, 0, 0);
}
vec3.transformQuat(meshPoint2, meshPoint2, curQuaternion);
vec3.transformQuat(meshPoint3, meshPoint3, curQuaternion);
var vecU = meshPoint2;
var vecV = meshPoint3;
var vecN = vec3.create();
vec3.cross(vecN, vecU, vecV);
vec3.normalize(vecN, vecN);
var coefficientA = vecN[0];
var coefficientB = vecN[1];
var coefficientC = vecN[2]; // const coefficientD = -1 * vec3.dot(vecN, meshPoint1);
// a point on the plane
curPoint = vec3.fromValues(meshPoint[0], meshPoint[1], meshPoint[2]);
vec3.transformQuat(curPoint, curPoint, curQuaternion); // a point should project on the plane
prevPoint = vec3.fromValues(meshPoint[0], meshPoint[1], meshPoint[2]);
vec3.transformQuat(prevPoint, prevPoint, prevQuaternion); // distance between prevPoint and the plane
var distance = Math.abs(prevPoint[0] * coefficientA + prevPoint[1] * coefficientB + prevPoint[2] * coefficientC);
var projectedPrevPoint = vec3.create();
vec3.subtract(projectedPrevPoint, prevPoint, vec3.scale(vec3.create(), vecN, distance));
var trigonometricRatio = (projectedPrevPoint[0] * curPoint[0] + projectedPrevPoint[1] * curPoint[1] + projectedPrevPoint[2] * curPoint[2]) / (vec3.length(projectedPrevPoint) * vec3.length(curPoint)); // defensive block
trigonometricRatio > 1 && (trigonometricRatio = 1);
var theta = Math.acos(trigonometricRatio);
var crossVec = vec3.cross(vec3.create(), curPoint, projectedPrevPoint);
distance = coefficientA * crossVec[0] + coefficientB * crossVec[1] + coefficientC * crossVec[2];
var thetaDirection;
if (rotateKind !== ROTATE_CONSTANT.YAW_DELTA_BY_YAW) {
thetaDirection = distance > 0 ? 1 : -1;
} else {
thetaDirection = distance < 0 ? 1 : -1;
}
var deltaRadian = theta * thetaDirection * rotateDirection;
return glMatrix.toDegree(deltaRadian);
}
util.getRotationDelta = getRotationDelta;
/**
* Returns a number value indiciating the version of Chrome being used,
* or otherwise `null` if not on Chrome.
*
* Ref: https://github.com/immersive-web/cardboard-vr-display/pull/19
*/
/**
* In Chrome m65, `devicemotion` events are broken but subsequently fixed
* in 65.0.3325.148. Since many browsers use Chromium, ensure that
* we scope this detection by branch and build numbers to provide
* a proper fallback.
* https://github.com/immersive-web/webvr-polyfill/issues/307
*/
var version = -1; // It should not be null because it will be compared with number
var branch = null;
var build = null;
var match = /Chrome\/([0-9]+)\.(?:[0-9]*)\.([0-9]*)\.([0-9]*)/i.exec(userAgent$1);
if (match) {
version = parseInt(match[1], 10);
branch = match[2];
build = match[3];
}
var CHROME_VERSION = version;
var IS_CHROME_WITHOUT_DEVICE_MOTION = version === 65 && branch === "3325" && parseInt(build, 10) < 148;
var IS_ANDROID = /Android/i.test(userAgent$1);
var CONTROL_MODE_VR = 1;
var CONTROL_MODE_YAWPITCH = 2;
var TOUCH_DIRECTION_NONE = 1;
var TOUCH_DIRECTION_YAW = 2;
var TOUCH_DIRECTION_PITCH = 4;
var TOUCH_DIRECTION_ALL = TOUCH_DIRECTION_YAW | TOUCH_DIRECTION_PITCH;
/* Const for MovableCoord */
var MC_DECELERATION = 0.0014;
var MC_MAXIMUM_DURATION = 1000;
var MC_BIND_SCALE = [0.20, 0.20];
var MAX_FIELD_OF_VIEW = 110;
var PAN_SCALE = 320; // const DELTA_THRESHOLD = 0.015;
var YAW_RANGE_HALF = 180;
var PITCH_RANGE_HALF = 90;
var CIRCULAR_PITCH_RANGE_HALF = 180;
var GYRO_MODE = {
NONE: "none",
YAWPITCH: "yawPitch",
VR: "VR"
};
var STILLNESS_THRESHOLD = 200; // millisecond
var DeviceMotion =
/*#__PURE__*/
function (_Component) {
_inheritsLoose(DeviceMotion, _Component);
function DeviceMotion() {
var _this;
_this = _Component.call(this) || this;
_this._onDeviceMotion = _this._onDeviceMotion.bind(_assertThisInitialized(_assertThisInitialized(_this)));
_this._onDeviceOrientation = _this._onDeviceOrientation.bind(_assertThisInitialized(_assertThisInitialized(_this)));
_this._onChromeWithoutDeviceMotion = _this._onChromeWithoutDeviceMotion.bind(_assertThisInitialized(_assertThisInitialized(_this)));
_this.isWithoutDeviceMotion = IS_CHROME_WITHOUT_DEVICE_MOTION;
_this.isAndroid = IS_ANDROID;
_this.stillGyroVec = vec3.create();
_this.rawGyroVec = vec3.create();
_this.adjustedGyroVec = vec3.create();
_this._timer = null;
_this.lastDevicemotionTimestamp = 0;
_this._isEnabled = false;
_this.enable();
return _this;
}
var _proto = DeviceMotion.prototype;
_proto._onChromeWithoutDeviceMotion = function _onChromeWithoutDeviceMotion(e) {
var alpha = e.alpha,
beta = e.beta,
gamma = e.gamma; // There is deviceorientation event trigged with empty values
// on Headless Chrome.
if (alpha === null) {
return;
} // convert to radian
alpha = (alpha || 0) * Math.PI / 180;
beta = (beta || 0) * Math.PI / 180;
gamma = (gamma || 0) * Math.PI / 180;
this.trigger("devicemotion", {
inputEvent: {
deviceorientation: {
alpha: alpha,
beta: beta,
gamma: -gamma
}
}
});
};
_proto._onDeviceOrientation = function _onDeviceOrientation() {
var _this2 = this;
this._timer && clearTimeout(this._timer);
this._timer = setTimeout(function () {
if (new Date().getTime() - _this2.lastDevicemotionTimestamp < STILLNESS_THRESHOLD) {
vec3.copy(_this2.stillGyroVec, _this2.rawGyroVec);
}
}, STILLNESS_THRESHOLD);
};
_proto._onDeviceMotion = function _onDeviceMotion(e) {
// desktop chrome triggers devicemotion event with empthy sensor values.
// Those events should ignored.
var isGyroSensorAvailable = !(e.rotationRate.alpha == null);
var isGravitySensorAvailable = !(e.accelerationIncludingGravity.x == null);
if (e.interval === 0 || !(isGyroSensorAvailable && isGravitySensorAvailable)) {
return;
}
var devicemotionEvent = _extends({}, e);
devicemotionEvent.interval = e.interval;
devicemotionEvent.timeStamp = e.timeStamp;
devicemotionEvent.type = e.type;
devicemotionEvent.rotationRate = {
alpha: e.rotationRate.alpha,
beta: e.rotationRate.beta,
gamma: e.rotationRate.gamma
};
devicemotionEvent.accelerationIncludingGravity = {
x: e.accelerationIncludingGravity.x,
y: e.accelerationIncludingGravity.y,
z: e.accelerationIncludingGravity.z
};
devicemotionEvent.acceleration = {
x: e.acceleration.x,
y: e.acceleration.y,
z: e.acceleration.z
};
if (this.isAndroid) {
vec3.set(this.rawGyroVec, e.rotationRate.alpha || 0, e.rotationRate.beta || 0, e.rotationRate.gamma || 0);
vec3.subtract(this.adjustedGyroVec, this.rawGyroVec, this.stillGyroVec);
this.lastDevicemotionTimestamp = new Date().getTime();
devicemotionEvent.adjustedRotationRate = {
alpha: this.adjustedGyroVec[0],
beta: this.adjustedGyroVec[1],
gamma: this.adjustedGyroVec[2]
};
}
this.trigger("devicemotion", {
inputEvent: devicemotionEvent
});
};
_proto.enable = function enable() {
if (this.isAndroid) {
win.addEventListener("deviceorientation", this._onDeviceOrientation);
}
if (this.isWithoutDeviceMotion) {
win.addEventListener("deviceorientation", this._onChromeWithoutDeviceMotion);
} else {
win.addEventListener("devicemotion", this._onDeviceMotion);
}
this._isEnabled = true;
};
_proto.disable = function disable() {
win.removeEventListener("deviceorientation", this._onDeviceOrientation);
win.removeEventListener("deviceorientation", this._onChromeWithoutDeviceMotion);
win.removeEventListener("devicemotion", this._onDeviceMotion);
this._isEnabled = false;
};
return DeviceMotion;
}(Component);
ComplementaryFilter.prototype.run_ = function () {
if (!this.isOrientationInitialized) {
this.accelQ = this.accelToQuaternion_(this.currentAccelMeasurement.sample);
this.previousFilterQ.copy(this.accelQ);
this.isOrientationInitialized = true;
return;
}
var deltaT = this.currentGyroMeasurement.timestampS - this.previousGyroMeasurement.timestampS; // Convert gyro rotation vector to a quaternion delta.
var gyroDeltaQ = this.gyroToQuaternionDelta_(this.currentGyroMeasurement.sample, deltaT);
this.gyroIntegralQ.multiply(gyroDeltaQ); // filter_1 = K * (filter_0 + gyro * dT) + (1 - K) * accel.
this.filterQ.copy(this.previousFilterQ);
this.filterQ.multiply(gyroDeltaQ); // Calculate the delta between the current estimated gravity and the real
// gravity vector from accelerometer.
var invFilterQ = new MathUtil.Quaternion();
invFilterQ.copy(this.filterQ);
invFilterQ.inverse();
this.estimatedGravity.set(0, 0, -1);
this.estimatedGravity.applyQuaternion(invFilterQ);
this.estimatedGravity.normalize();
this.measuredGravity.copy(this.currentAccelMeasurement.sample);
this.measuredGravity.normalize(); // Compare estimated gravity with measured gravity, get the delta quaternion
// between the two.
var deltaQ = new MathUtil.Quaternion();
deltaQ.setFromUnitVectors(this.estimatedGravity, this.measuredGravity);
deltaQ.inverse(); // Calculate the SLERP target: current orientation plus the measured-estimated
// quaternion delta.
var targetQ = new MathUtil.Quaternion();
targetQ.copy(this.filterQ);
targetQ.multiply(deltaQ); // SLERP factor: 0 is pure gyro, 1 is pure accel.
this.filterQ.slerp(targetQ, 1 - this.kFilter);
this.previousFilterQ.copy(this.filterQ);
if (!this.isFilterQuaternionInitialized) {
this.isFilterQuaternionInitialized = true;
}
};
ComplementaryFilter.prototype.getOrientation = function () {
if (this.isFilterQuaternionInitialized) {
return this.filterQ;
} else {
return null;
}
};
var K_FILTER = 0.98;
var PREDICTION_TIME_S = 0.040;
var FusionPoseSensor =
/*#__PURE__*/
function (_Component) {
_inheritsLoose(FusionPoseSensor, _Component);
function FusionPoseSensor() {
var _this;
_this = _Component.call(this) || this;
_this.deviceMotion = new DeviceMotion();
_this.accelerometer = new MathUtil.Vector3();
_this.gyroscope = new MathUtil.Vector3();
_this._onDeviceMotionChange = _this._onDeviceMotionChange.bind(_assertThisInitialized(_assertThisInitialized(_this)));
_this._onScreenOrientationChange = _this._onScreenOrientationChange.bind(_assertThisInitialized(_assertThisInitialized(_this)));
_this.filter = new ComplementaryFilter(K_FILTER);
_this.posePredictor = new PosePredictor(PREDICTION_TIME_S);
_this.filterToWorldQ = new MathUtil.Quaternion();
_this.isFirefoxAndroid = Util.isFirefoxAndroid();
_this.isIOS = Util.isIOS(); // Ref https://github.com/immersive-web/cardboard-vr-display/issues/18
_this.isChromeUsingDegrees = CHROME_VERSION >= 66;
_this._isEnabled = false; // Set the filter to world transform, depending on OS.
if (_this.isIOS) {
_this.filterToWorldQ.setFromAxisAngle(new MathUtil.Vector3(1, 0, 0), Math.PI / 2);
} else {
_this.filterToWorldQ.setFromAxisAngle(new MathUtil.Vector3(1, 0, 0), -Math.PI / 2);
}
_this.inverseWorldToScreenQ = new MathUtil.Quaternion();
_this.worldToScreenQ = new MathUtil.Quaternion();
_this.originalPoseAdjustQ = new MathUtil.Quaternion();
_this.originalPoseAdjustQ.setFromAxisAngle(new MathUtil.Vector3(0, 0, 1), -win.orientation * Math.PI / 180);
_this._setScreenTransform(); // Adjust this filter for being in landscape mode.
if (Util.isLandscapeMode()) {
_this.filterToWorldQ.multiply(_this.inverseWorldToScreenQ);
} // Keep track of a reset transform for resetSensor.
_this.resetQ = new MathUtil.Quaternion();
_this.deviceMotion.on("devicemotion", _this._onDeviceMotionChange);
_this.enable();
return _this;
}
var _proto = FusionPoseSensor.prototype;
_proto.enable = function enable() {
if (this.isEnabled()) {
return;
}
this.deviceMotion.enable();
this._isEnabled = true;
win.addEventListener("orientationchange", this._onScreenOrientationChange);
};
_proto.disable = function disable() {
if (!this.isEnabled()) {
return;
}
this.deviceMotion.disable();
this._isEnabled = false;
win.removeEventListener("orientationchange", this._onScreenOrientationChange);
};
_proto.isEnabled = function isEnabled() {
return this._isEnabled;
};
_proto.destroy = function destroy() {
this.disable();
this.deviceMotion = null;
};
_proto._triggerChange = function _triggerChange() {
var orientation = this.getOrientation(); // if orientation is not prepared. don't trigger change event
if (!orientation) {
return;
}
if (!this._prevOrientation) {
this._prevOrientation = orientation;
return;
}
if (quat.equals(this._prevOrientation, orientation)) {
return;
}
this.trigger("change", {
quaternion: orientation
});
};
_proto.getOrientation = function getOrientation() {
var orientation; // Hack around using deviceorientation instead of devicemotion
if (this.deviceMotion.isWithoutDeviceMotion && this._deviceOrientationQ) {
this.deviceOrientationFixQ = this.deviceOrientationFixQ || function () {
var y = new MathUtil.Quaternion().setFromAxisAngle(new MathUtil.Vector3(0, 1, 0), -this._alpha);
return y;
}.bind(this)();
orientation = this._deviceOrientationQ;
var out = new MathUtil.Quaternion();
out.copy(orientation);
out.multiply(this.filterToWorldQ);
out.multiply(this.resetQ);
out.multiply(this.worldToScreenQ);
out.multiplyQuaternions(this.deviceOrientationFixQ, out); // return quaternion as glmatrix quaternion object
var out_ = quat.fromValues(out.x, out.y, out.z, out.w);
return quat.normalize(out_, out_);
} else {
// Convert from filter space to the the same system used by the
// deviceorientation event.
orientation = this.filter.getOrientation();
if (!orientation) {
return null;
}
var _out = this._convertFusionToPredicted(orientation); // return quaternion as glmatrix quaternion object
var _out_ = quat.fromValues(_out.x, _out.y, _out.z, _out.w);
return quat.normalize(_out_, _out_);
}
};
_proto._convertFusionToPredicted = function _convertFusionToPredicted(orientation) {
// Predict orientation.
this.predictedQ = this.posePredictor.getPrediction(orientation, this.gyroscope, this.previousTimestampS); // Convert to THREE coordinate system: -Z forward, Y up, X right.
var out = new MathUtil.Quaternion();
out.copy(this.filterToWorldQ);
out.multiply(this.resetQ);
out.multiply(this.predictedQ);
out.multiply(this.worldToScreenQ);
return out;
};
_proto._onDeviceMotionChange = function _onDeviceMotionChange(_ref) {
var inputEvent = _ref.inputEvent;
var deviceorientation = inputEvent.deviceorientation;
var deviceMotion = inputEvent;
var accGravity = deviceMotion.accelerationIncludingGravity;
var rotRate = deviceMotion.adjustedRotationRate || deviceMotion.rotationRate;
var timestampS = deviceMotion.timeStamp / 1000;
if (deviceorientation) {
if (!this._alpha) {
this._alpha = deviceorientation.alpha;
}
this._deviceOrientationQ = this._deviceOrientationQ || new MathUtil.Quaternion();
this._deviceOrientationQ.setFromEulerYXZ(deviceorientation.beta, deviceorientation.alpha, deviceorientation.gamma);
this._triggerChange();
} else {
// Firefox Android timeStamp returns one thousandth of a millisecond.
if (this.isFirefoxAndroid) {
timestampS /= 1000;
}
this.accelerometer.set(-accGravity.x, -accGravity.y, -accGravity.z);
this.gyroscope.set(rotRate.alpha, rotRate.beta, rotRate.gamma); // Browsers on iOS, Firefox/Android, and Chrome m66/Android `rotationRate`
// is reported in degrees, so we first convert to radians.
if (this.isIOS || this.isFirefoxAndroid || this.isChromeUsingDegrees) {
this.gyroscope.multiplyScalar(Math.PI / 180);
}
this.filter.addAccelMeasurement(this.accelerometer, timestampS);
this.filter.addGyroMeasurement(this.gyroscope, timestampS);
this._triggerChange();
this.previousTimestampS = timestampS;
}
};
_proto._onScreenOrientationChange = function _onScreenOrientationChange(screenOrientation) {
this._setScreenTransform(win.orientation);
};
_proto._setScreenTransform = function _setScreenTransform() {
this.worldToScreenQ.set(0, 0, 0, 1);
switch (win.orientation) {
case 0:
break;
case 90:
this.worldToScreenQ.setFromAxisAngle(new MathUtil.Vector3(0, 0, 1), 90 / -180 * Math.PI);
break;
case -90:
this.worldToScreenQ.setFromAxisAngle(new MathUtil.Vector3(0, 0, 1), -90 / -180 * Math.PI);
break;
case 180:
this.worldToScreenQ.setFromAxisAngle(new MathUtil.Vector3(0, 0, 1), 180 / -180 * Math.PI);
break;
default:
break;
}
this.inverseWorldToScreenQ.copy(this.worldToScreenQ);
this.inverseWorldToScreenQ.inverse();
};
return FusionPoseSensor;
}(Component);
function getDeltaYaw(prvQ, curQ) {
var yawDeltaByYaw = util.getRotationDelta(prvQ, curQ, ROTATE_CONSTANT.YAW_DELTA_BY_YAW);
var yawDeltaByRoll = util.getRotationDelta(prvQ, curQ, ROTATE_CONSTANT.YAW_DELTA_BY_ROLL) * Math.sin(util.extractPitchFromQuat(curQ));
return yawDeltaByRoll + yawDeltaByYaw;
}
function getDeltaPitch(prvQ, curQ) {
var pitchDelta = util.getRotationDelta(prvQ, curQ, ROTATE_CONSTANT.PITCH_DELTA);
return pitchDelta;
}
var TiltMotionInput =
/*#__PURE__*/
function (_Component) {
_inheritsLoose(TiltMotionInput, _Component);
function TiltMotionInput(el, options) {
var _this;
_this = _Component.call(this) || this;
_this.element = el;
_this._prevQuaternion = null;
_this._quaternion = null;
_this.fusionPoseSensor = null;
_this.options = _extends({
scale: 1,
threshold: 0
}, options);
_this._onPoseChange = _this._onPoseChange.bind(_assertThisInitialized(_assertThisInitialized(_this)));
return _this;
}
var _proto = TiltMotionInput.prototype;
_proto.mapAxes = function mapAxes(axes) {
this.axes = axes;
};
_proto.connect = function connect(observer) {
if (this.observer) {
return this;
}
this.observer = observer;
this.fusionPoseSensor = new FusionPoseSensor();
this.fusionPoseSensor.enable();
this._attachEvent();
return this;
};
_proto.disconnect = function disconnect() {
if (!this.observer) {
return this;
}
this._dettachEvent();
this.fusionPoseSensor.disable();
this.fusionPoseSensor.destroy();
this.fusionPoseSensor = null;
this.observer = null;
return this;
};
_proto.destroy = function destroy() {
this.disconnect();
this.element = null;
this.options = null;
this.axes = null;
this._prevQuaternion = null;
this._quaternion = null;
};
_proto._onPoseChange = function _onPoseChange(event) {
if (!this._prevQuaternion) {
this._prevQuaternion = quat.clone(event.quaternion);
this._quaternion = quat.clone(event.quaternion);
return;
}
quat.copy(this._prevQuaternion, this._quaternion);
quat.copy(this._quaternion, event.quaternion);
this.observer.change(this, event, toAxis(this.axes, [getDeltaYaw(this._prevQuaternion, this._quaternion), getDeltaPitch(this._prevQuaternion, this._quaternion)]));
};
_proto._attachEvent = function _attachEvent() {
this.fusionPoseSensor.on("change", this._onPoseChange);
};
_proto._dettachEvent = function _dettachEvent() {
this.fusionPoseSensor.off("change", this._onPoseChange);
};
return TiltMotionInput;
}(Component);
var screenRotationAngleInst = null;
var refCount = 0;
var ScreenRotationAngle =
/*#__PURE__*/
function () {
function ScreenRotationAngle() {
refCount++;
if (screenRotationAngleInst) {
return screenRotationAngleInst;
}
/* eslint-disable */
screenRotationAngleInst = this;
/* eslint-enable */
this._onDeviceOrientation = this._onDeviceOrientation.bind(this);
this._onOrientationChange = this._onOrientationChange.bind(this);
this._spinR = 0;
this._screenOrientationAngle = 0;
win.addEventListener("deviceorientation", this._onDeviceOrientation);
win.addEventListener("orientationchange", this._onOrientationChange);
}
var _proto = ScreenRotationAngle.prototype;
_proto._onDeviceOrientation = function _onDeviceOrientation(e) {
if (e.beta === null || e.gamma === null) {
// (Chrome) deviceorientation is fired with invalid information {alpha=null, beta=null, ...} despite of not dispatching it. We skip it.
return;
} // Radian
var betaR = glMatrix.toRadian(e.beta);
var gammaR = glMatrix.toRadian(e.gamma);
/* spinR range = [-180, 180], left side: 0 ~ -180(deg), right side: 0 ~ 180(deg) */
this._spinR = Math.atan2(Math.cos(betaR) * Math.sin(gammaR), Math.sin(betaR));
};
_proto._onOrientationChange = function _onOrientationChange(e) {
if (win.screen && win.screen.orientation && win.screen.orientation.angle !== undefined) {
this._screenOrientationAngle = screen.orientation.angle;
} else if (win.orientation !== undefined) {
/* iOS */
this._screenOrientationAngle = win.orientation >= 0 ? win.orientation : 360 + win.orientation;
}
};
_proto.getRadian = function getRadian() {
// Join with screen orientation
// this._testVal = this._spinR + ", " + this._screenOrientationAngle + ", " + window.orientation;
return this._spinR + glMatrix.toRadian(this._screenOrientationAngle);
};
_proto.unref = function unref() {
if (--refCount > 0) {
return;
}
win.removeEventListener("deviceorientation", this._onDeviceOrientation);
win.removeEventListener("orientationchange", this._onOrientationChange);
this._spinR = 0;
this._screenOrientationAngle = 0;
/* eslint-disable */
screenRotationAngleInst = null;
/* eslint-enable */
refCount = 0;
};
return ScreenRotationAngle;
}();
/**
* RotationPanInput is extension of PanInput to compensate coordinates by screen rotation angle.
*
* The reason for using this function is that in VR mode,
* the roll angle is adjusted in the direction opposite to the screen rotation angle.
*
* Therefore, the angle that the user touches and moves does not match the angle at which the actual object should move.
* @extends PanInput
*/
var RotationPanInput =
/*#__PURE__*/
function (_PanInput) {
_inheritsLoose(RotationPanInput, _PanInput);
/**
* Constructor
*
* @private
* @param {HTMLElement} el target element
* @param {Object} [options] The option object
* @param {Boolean} [options.useRotation] Whether to use rotation(or VR)
*/
function RotationPanInput(el, options) {
var _this;
_this = _PanInput.call(this, el, options) || this;
_this._useRotation = false;
_this._screenRotationAngle = null;
_this.setUseRotation(!!(options && options.useRotation));
_this._userDirection = Axes.DIRECTION_ALL;
return _this;
}
var _proto = RotationPanInput.prototype;
_proto.setUseRotation = function setUseRotation(useRotation) {
this._useRotation = useRotation;
if (this._screenRotationAngle) {
this._screenRotationAngle.unref();
this._screenRotationAngle = null;
}
if (this._useRotation) {
this._screenRotationAngle = new ScreenRotationAngle();
}
};
_proto.connect = function connect(observer) {
// User intetened direction
this._userDirection = this._direction; // In VR Mode, Use ALL direction if direction is not none
// Because horizontal and vertical is changed dynamically by screen rotation.
// this._direction is used to initialize hammerjs
if (this._useRotation && this._direction & Axes.DIRECTION_ALL) {
this._direction = Axes.DIRECTION_ALL;
}
_PanInput.prototype.connect.call(this, observer);
};
_proto.getOffset = function getOffset(properties, useDirection) {
if (this._useRotation === false) {
return _PanInput.prototype.getOffset.call(this, properties, useDirection);
}
var offset = _PanInput.prototype.getOffset.call(this, properties, [true, true]);
var newOffset = [0, 0];
var theta = this._screenRotationAngle.getRadian();
var cosTheta = Math.cos(theta);
var sinTheta = Math.sin(theta);
newOffset[0] = offset[0] * cosTheta - offset[1] * sinTheta;
newOffset[1] = offset[1] * cosTheta + offset[0] * sinTheta; // Use only user allowed direction.
if (!(this._userDirection & Axes.DIRECTION_HORIZONTAL)) {
newOffset[0] = 0;
} else if (!(this._userDirection & Axes.DIRECTION_VERTICAL)) {
newOffset[1] = 0;
}
return newOffset;
};
_proto.destroy = function destroy() {
if (this._useRotation) {
this._screenRotationAngle && this._screenRotationAngle.unref();
}
_PanInput.prototype.destroy.call(this);
};
return RotationPanInput;
}(PanInput);
var ORIGIN_VECTOR = vec3.fromValues(0, 0, 0);
var X_AXIS_VECTOR = vec3.fromValues(1, 0, 0);
var Y_AXIS_VECTOR = vec3.fromValues(0, 1, 0);
var DeviceQuaternion =
/*#__PURE__*/
function (_Component) {
_inheritsLoose(DeviceQuaternion, _Component);
function DeviceQuaternion() {
var _this;
_this = _Component.call(this) || this;
_this._screenRotationAngle = new ScreenRotationAngle();
_this._fusionPoseSensor = new FusionPoseSensor();
_this._quaternion = quat.create();
_this._fusionPoseSensor.enable();
_this._fusionPoseSensor.on("change", function (e) {
_this._quaternion = e.quaternion;
_this.trigger("change", {
isTrusted: true
});
});
return _this;
}
var _proto = DeviceQuaternion.prototype;
_proto.getCombinedQuaternion = function getCombinedQuaternion(yaw, pitch) {
var deviceR = this._screenRotationAngle.getRadian(); // rotate x-axis around z-axis about screen rotation angle.
var pitchAxis = vec3.rotateZ(vec3.create(), X_AXIS_VECTOR, ORIGIN_VECTOR, deviceR);
var yawQ = quat.setAxisAngle(quat.create(), Y_AXIS_VECTOR, glMatrix.toRadian(-yaw)); // rotate quaternion around new x-axis about pitch angle.
var pitchQ = quat.setAxisAngle(quat.create(), pitchAxis, glMatrix.toRadian(-pitch));
var conj = quat.conjugate(quat.create(), this._quaternion); // Multiply pitch quaternion -> device quaternion -> yaw quaternion
var outQ = quat.multiply(quat.create(), pitchQ, conj);
quat.multiply(outQ, outQ, yawQ);
return outQ;
};
_proto.destroy = function destroy() {
// detach all event handler
this.off();
if (this._fusionPoseSensor) {
this._fusionPoseSensor.off();
this._fusionPoseSensor.destroy();
this._fusionPoseSensor = null;
}
if (this._screenRotationAngle) {
this._screenRotationAngle.unref();
this._screenRotationAngle = null;
}
};
return DeviceQuaternion;
}(Component);
var VERSION = "3.2.2-rc";
var DEFAULT_YAW_RANGE = [-YAW_RANGE_HALF, YAW_RANGE_HALF];
var DEFAULT_PITCH_RANGE = [-PITCH_RANGE_HALF, PITCH_RANGE_HALF];
var CIRCULAR_PITCH_RANGE = [-CIRCULAR_PITCH_RANGE_HALF, CIRCULAR_PITCH_RANGE_HALF];
/**
* A module used to provide coordinate based on yaw/pitch orientation. This module receives user touch action, keyboard, mouse and device orientation(if it exists) as input, then combines them and converts it to yaw/pitch coordinates.
*
* @alias eg.YawPitchControl
* @extends eg.Component
*
* @support {"ie": "10+", "ch" : "latest", "ff" : "latest", "sf" : "latest", "edge" : "latest", "ios" : "7+", "an" : "2.3+ (except 3.x)"}
*/
var YawPitchControl =
/*#__PURE__*/
function () {
var YawPitchControl =
/*#__PURE__*/
function (_Component) {
_inheritsLoose(YawPitchControl, _Component);
// Expose DeviceOrientationControls sub module for test purpose
/**
* @param {Object} options The option object of the eg.YawPitch module
* @param {Element}[options.element=null] element A base element for the eg.YawPitch module
* @param {Number} [options.yaw=0] initial yaw (degree)
* @param {Number} [options.pitch=0] initial pitch (degree)
* @param {Number} [options.fov=65] initial field of view (degree)
* @param {Boolean} [optiosn.showPolePoint=true] Indicates whether pole is shown
* @param {Boolean} [options.useZoom=true] Indicates whether zoom is available
* @param {Boolean} [options.useKeyboard=true] Indicates whether keyboard is enabled
* @param {String} [config.gyroMode=yawPitch] Enables control through device motion.
* @param {Number} [options.touchDirection=TOUCH_DIRECTION_ALL] Direction of the touch movement (TOUCH_DIRECTION_ALL: all, TOUCH_DIRECTION_YAW: horizontal, TOUCH_DIRECTION_PITCH: vertical, TOUCH_DIRECTION_NONE: no mo