| /* Copyright (c) 2015, Brandon Jones, Colin MacKenzie IV. |
| |
| Permission is hereby granted, free of charge, to any person obtaining a copy |
| of this software and associated documentation files (the "Software"), to deal |
| in the Software without restriction, including without limitation the rights |
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
| copies of the Software, and to permit persons to whom the Software is |
| furnished to do so, subject to the following conditions: |
| |
| The above copyright notice and this permission notice shall be included in |
| all copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
| THE SOFTWARE. */ |
| |
| var glMatrix = require("./common.js"); |
| var mat3 = require("./mat3.js"); |
| var vec3 = require("./vec3.js"); |
| var vec4 = require("./vec4.js"); |
| |
| /** |
| * @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; |
| }; |
| |
| /** |
| * Sets a quaternion to represent the shortest rotation from one |
| * vector to another. |
| * |
| * Both vectors are assumed to be unit length. |
| * |
| * @param {quat} out the receiving quaternion. |
| * @param {vec3} a the initial vector |
| * @param {vec3} b the destination vector |
| * @returns {quat} out |
| */ |
| quat.rotationTo = (function() { |
| var tmpvec3 = vec3.create(); |
| var xUnitVec3 = vec3.fromValues(1,0,0); |
| var yUnitVec3 = vec3.fromValues(0,1,0); |
| |
| return function(out, a, b) { |
| var dot = vec3.dot(a, b); |
| if (dot < -0.999999) { |
| vec3.cross(tmpvec3, xUnitVec3, a); |
| if (vec3.length(tmpvec3) < 0.000001) |
| vec3.cross(tmpvec3, yUnitVec3, a); |
| vec3.normalize(tmpvec3, tmpvec3); |
| quat.setAxisAngle(out, tmpvec3, Math.PI); |
| return out; |
| } else if (dot > 0.999999) { |
| out[0] = 0; |
| out[1] = 0; |
| out[2] = 0; |
| out[3] = 1; |
| return out; |
| } else { |
| vec3.cross(tmpvec3, a, b); |
| out[0] = tmpvec3[0]; |
| out[1] = tmpvec3[1]; |
| out[2] = tmpvec3[2]; |
| out[3] = 1 + dot; |
| return quat.normalize(out, out); |
| } |
| }; |
| })(); |
| |
| /** |
| * Sets the specified quaternion with values corresponding to the given |
| * axes. Each axis is a vec3 and is expected to be unit length and |
| * perpendicular to all other specified axes. |
| * |
| * @param {vec3} view the vector representing the viewing direction |
| * @param {vec3} right the vector representing the local "right" direction |
| * @param {vec3} up the vector representing the local "up" direction |
| * @returns {quat} out |
| */ |
| quat.setAxes = (function() { |
| var matr = mat3.create(); |
| |
| return function(out, view, right, up) { |
| matr[0] = right[0]; |
| matr[3] = right[1]; |
| matr[6] = right[2]; |
| |
| matr[1] = up[0]; |
| matr[4] = up[1]; |
| matr[7] = up[2]; |
| |
| matr[2] = -view[0]; |
| matr[5] = -view[1]; |
| matr[8] = -view[2]; |
| |
| return quat.normalize(out, quat.fromMat3(out, matr)); |
| }; |
| })(); |
| |
| /** |
| * 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 = vec4.clone; |
| |
| /** |
| * 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 = vec4.fromValues; |
| |
| /** |
| * 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 = vec4.copy; |
| |
| /** |
| * Set the components of a quat to the given values |
| * |
| * @param {quat} out the receiving quaternion |
| * @param {Number} x X component |
| * @param {Number} y Y component |
| * @param {Number} z Z component |
| * @param {Number} w W component |
| * @returns {quat} out |
| * @function |
| */ |
| quat.set = vec4.set; |
| |
| /** |
| * Set a quat to the identity quaternion |
| * |
| * @param {quat} out the receiving quaternion |
| * @returns {quat} out |
| */ |
| quat.identity = function(out) { |
| out[0] = 0; |
| out[1] = 0; |
| out[2] = 0; |
| out[3] = 1; |
| 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; |
| }; |
| |
| /** |
| * Adds two quat's |
| * |
| * @param {quat} out the receiving quaternion |
| * @param {quat} a the first operand |
| * @param {quat} b the second operand |
| * @returns {quat} out |
| * @function |
| */ |
| quat.add = vec4.add; |
| |
| /** |
| * 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; |
| }; |
| |
| /** |
| * Alias for {@link quat.multiply} |
| * @function |
| */ |
| quat.mul = quat.multiply; |
| |
| /** |
| * Scales a quat by a scalar number |
| * |
| * @param {quat} out the receiving vector |
| * @param {quat} a the vector to scale |
| * @param {Number} b amount to scale the vector by |
| * @returns {quat} out |
| * @function |
| */ |
| quat.scale = vec4.scale; |
| |
| /** |
| * 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; |
| }; |
| |
| /** |
| * Rotates a quaternion by the given angle about the Z 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.rotateZ = function (out, a, rad) { |
| rad *= 0.5; |
| |
| var ax = a[0], ay = a[1], az = a[2], aw = a[3], |
| bz = Math.sin(rad), bw = Math.cos(rad); |
| |
| out[0] = ax * bw + ay * bz; |
| out[1] = ay * bw - ax * bz; |
| out[2] = az * bw + aw * bz; |
| out[3] = aw * bw - az * bz; |
| return out; |
| }; |
| |
| /** |
| * Calculates the W component of a quat from the X, Y, and Z components. |
| * Assumes that quaternion is 1 unit in length. |
| * Any existing W component will be ignored. |
| * |
| * @param {quat} out the receiving quaternion |
| * @param {quat} a quat to calculate W component of |
| * @returns {quat} out |
| */ |
| quat.calculateW = function (out, a) { |
| var x = a[0], y = a[1], z = a[2]; |
| |
| out[0] = x; |
| out[1] = y; |
| out[2] = z; |
| out[3] = Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); |
| return out; |
| }; |
| |
| /** |
| * Calculates the dot product of two quat's |
| * |
| * @param {quat} a the first operand |
| * @param {quat} b the second operand |
| * @returns {Number} dot product of a and b |
| * @function |
| */ |
| quat.dot = vec4.dot; |
| |
| /** |
| * Performs a linear interpolation between two quat's |
| * |
| * @param {quat} out the receiving quaternion |
| * @param {quat} a the first operand |
| * @param {quat} b the second operand |
| * @param {Number} t interpolation amount between the two inputs |
| * @returns {quat} out |
| * @function |
| */ |
| quat.lerp = vec4.lerp; |
| |
| /** |
| * Performs a spherical linear interpolation between two quat |
| * |
| * @param {quat} out the receiving quaternion |
| * @param {quat} a the first operand |
| * @param {quat} b the second operand |
| * @param {Number} t interpolation amount between the two inputs |
| * @returns {quat} out |
| */ |
| quat.slerp = function (out, a, b, t) { |
| // benchmarks: |
| // http://jsperf.com/quaternion-slerp-implementations |
| |
| 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]; |
| |
| var omega, cosom, sinom, scale0, scale1; |
| |
| // calc cosine |
| cosom = ax * bx + ay * by + az * bz + aw * bw; |
| // adjust signs (if necessary) |
| if ( cosom < 0.0 ) { |
| cosom = -cosom; |
| bx = - bx; |
| by = - by; |
| bz = - bz; |
| bw = - bw; |
| } |
| // calculate coefficients |
| if ( (1.0 - cosom) > 0.000001 ) { |
| // standard case (slerp) |
| omega = Math.acos(cosom); |
| sinom = Math.sin(omega); |
| scale0 = Math.sin((1.0 - t) * omega) / sinom; |
| scale1 = Math.sin(t * omega) / sinom; |
| } else { |
| // "from" and "to" quaternions are very close |
| // ... so we can do a linear interpolation |
| scale0 = 1.0 - t; |
| scale1 = t; |
| } |
| // calculate final values |
| out[0] = scale0 * ax + scale1 * bx; |
| out[1] = scale0 * ay + scale1 * by; |
| out[2] = scale0 * az + scale1 * bz; |
| out[3] = scale0 * aw + scale1 * bw; |
| |
| return out; |
| }; |
| |
| /** |
| * Performs a spherical linear interpolation with two control points |
| * |
| * @param {quat} out the receiving quaternion |
| * @param {quat} a the first operand |
| * @param {quat} b the second operand |
| * @param {quat} c the third operand |
| * @param {quat} d the fourth operand |
| * @param {Number} t interpolation amount |
| * @returns {quat} out |
| */ |
| quat.sqlerp = (function () { |
| var temp1 = quat.create(); |
| var temp2 = quat.create(); |
| |
| return function (out, a, b, c, d, t) { |
| quat.slerp(temp1, a, d, t); |
| quat.slerp(temp2, b, c, t); |
| quat.slerp(out, temp1, temp2, 2 * t * (1 - t)); |
| |
| return out; |
| }; |
| }()); |
| |
| /** |
| * Calculates the inverse of a quat |
| * |
| * @param {quat} out the receiving quaternion |
| * @param {quat} a quat to calculate inverse of |
| * @returns {quat} out |
| */ |
| quat.invert = function(out, a) { |
| var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], |
| dot = a0*a0 + a1*a1 + a2*a2 + a3*a3, |
| invDot = dot ? 1.0/dot : 0; |
| |
| // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0 |
| |
| out[0] = -a0*invDot; |
| out[1] = -a1*invDot; |
| out[2] = -a2*invDot; |
| out[3] = a3*invDot; |
| 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; |
| }; |
| |
| /** |
| * Calculates the length of a quat |
| * |
| * @param {quat} a vector to calculate length of |
| * @returns {Number} length of a |
| * @function |
| */ |
| quat.length = vec4.length; |
| |
| /** |
| * Alias for {@link quat.length} |
| * @function |
| */ |
| quat.len = quat.length; |
| |
| /** |
| * Calculates the squared length of a quat |
| * |
| * @param {quat} a vector to calculate squared length of |
| * @returns {Number} squared length of a |
| * @function |
| */ |
| quat.squaredLength = vec4.squaredLength; |
| |
| /** |
| * Alias for {@link quat.squaredLength} |
| * @function |
| */ |
| quat.sqrLen = quat.squaredLength; |
| |
| /** |
| * Normalize a quat |
| * |
| * @param {quat} out the receiving quaternion |
| * @param {quat} a quaternion to normalize |
| * @returns {quat} out |
| * @function |
| */ |
| quat.normalize = vec4.normalize; |
| |
| /** |
| * Creates a quaternion from the given 3x3 rotation matrix. |
| * |
| * NOTE: The resultant quaternion is not normalized, so you should be sure |
| * to renormalize the quaternion yourself where necessary. |
| * |
| * @param {quat} out the receiving quaternion |
| * @param {mat3} m rotation matrix |
| * @returns {quat} out |
| * @function |
| */ |
| quat.fromMat3 = function(out, m) { |
| // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes |
| // article "Quaternion Calculus and Fast Animation". |
| var fTrace = m[0] + m[4] + m[8]; |
| var fRoot; |
| |
| if ( fTrace > 0.0 ) { |
| // |w| > 1/2, may as well choose w > 1/2 |
| fRoot = Math.sqrt(fTrace + 1.0); // 2w |
| out[3] = 0.5 * fRoot; |
| fRoot = 0.5/fRoot; // 1/(4w) |
| out[0] = (m[5]-m[7])*fRoot; |
| out[1] = (m[6]-m[2])*fRoot; |
| out[2] = (m[1]-m[3])*fRoot; |
| } else { |
| // |w| <= 1/2 |
| var i = 0; |
| if ( m[4] > m[0] ) |
| i = 1; |
| if ( m[8] > m[i*3+i] ) |
| i = 2; |
| var j = (i+1)%3; |
| var k = (i+2)%3; |
| |
| fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0); |
| out[i] = 0.5 * fRoot; |
| fRoot = 0.5 / fRoot; |
| out[3] = (m[j*3+k] - m[k*3+j]) * fRoot; |
| out[j] = (m[j*3+i] + m[i*3+j]) * fRoot; |
| out[k] = (m[k*3+i] + m[i*3+k]) * fRoot; |
| } |
| |
| return out; |
| }; |
| |
| /** |
| * Returns a string representation of a quatenion |
| * |
| * @param {quat} vec vector to represent as a string |
| * @returns {String} string representation of the vector |
| */ |
| quat.str = function (a) { |
| return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; |
| }; |
| |
| module.exports = quat; |