1/* Copyright (c) 2013, Brandon Jones, Colin MacKenzie IV. All rights reserved. 2 3Redistribution and use in source and binary forms, with or without modification, 4are permitted provided that the following conditions are met: 5 6 * Redistributions of source code must retain the above copyright notice, this 7 list of conditions and the following disclaimer. 8 * Redistributions in binary form must reproduce the above copyright notice, 9 this list of conditions and the following disclaimer in the documentation 10 and/or other materials provided with the distribution. 11 12THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 13ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 14WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 15DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 16ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 17(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 18LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 19ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 20(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 21SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 22 23/** 24 * @class Quaternion 25 * @name quat 26 */ 27var quat = {}; 28 29/** 30 * Creates a new identity quat 31 * 32 * @returns {quat} a new quaternion 33 */ 34quat.create = function() { 35 var out = new GLMAT_ARRAY_TYPE(4); 36 out[0] = 0; 37 out[1] = 0; 38 out[2] = 0; 39 out[3] = 1; 40 return out; 41}; 42 43/** 44 * Creates a new quat initialized with values from an existing quaternion 45 * 46 * @param {quat} a quaternion to clone 47 * @returns {quat} a new quaternion 48 * @function 49 */ 50quat.clone = vec4.clone; 51 52/** 53 * Creates a new quat initialized with the given values 54 * 55 * @param {Number} x X component 56 * @param {Number} y Y component 57 * @param {Number} z Z component 58 * @param {Number} w W component 59 * @returns {quat} a new quaternion 60 * @function 61 */ 62quat.fromValues = vec4.fromValues; 63 64/** 65 * Copy the values from one quat to another 66 * 67 * @param {quat} out the receiving quaternion 68 * @param {quat} a the source quaternion 69 * @returns {quat} out 70 * @function 71 */ 72quat.copy = vec4.copy; 73 74/** 75 * Set the components of a quat to the given values 76 * 77 * @param {quat} out the receiving quaternion 78 * @param {Number} x X component 79 * @param {Number} y Y component 80 * @param {Number} z Z component 81 * @param {Number} w W component 82 * @returns {quat} out 83 * @function 84 */ 85quat.set = vec4.set; 86 87/** 88 * Set a quat to the identity quaternion 89 * 90 * @param {quat} out the receiving quaternion 91 * @returns {quat} out 92 */ 93quat.identity = function(out) { 94 out[0] = 0; 95 out[1] = 0; 96 out[2] = 0; 97 out[3] = 1; 98 return out; 99}; 100 101/** 102 * Sets a quat from the given angle and rotation axis, 103 * then returns it. 104 * 105 * @param {quat} out the receiving quaternion 106 * @param {vec3} axis the axis around which to rotate 107 * @param {Number} rad the angle in radians 108 * @returns {quat} out 109 **/ 110quat.setAxisAngle = function(out, axis, rad) { 111 rad = rad * 0.5; 112 var s = Math.sin(rad); 113 out[0] = s * axis[0]; 114 out[1] = s * axis[1]; 115 out[2] = s * axis[2]; 116 out[3] = Math.cos(rad); 117 return out; 118}; 119 120/** 121 * Adds two quat's 122 * 123 * @param {quat} out the receiving quaternion 124 * @param {quat} a the first operand 125 * @param {quat} b the second operand 126 * @returns {quat} out 127 * @function 128 */ 129quat.add = vec4.add; 130 131/** 132 * Multiplies two quat's 133 * 134 * @param {quat} out the receiving quaternion 135 * @param {quat} a the first operand 136 * @param {quat} b the second operand 137 * @returns {quat} out 138 */ 139quat.multiply = function(out, a, b) { 140 var ax = a[0], ay = a[1], az = a[2], aw = a[3], 141 bx = b[0], by = b[1], bz = b[2], bw = b[3]; 142 143 out[0] = ax * bw + aw * bx + ay * bz - az * by; 144 out[1] = ay * bw + aw * by + az * bx - ax * bz; 145 out[2] = az * bw + aw * bz + ax * by - ay * bx; 146 out[3] = aw * bw - ax * bx - ay * by - az * bz; 147 return out; 148}; 149 150/** 151 * Alias for {@link quat.multiply} 152 * @function 153 */ 154quat.mul = quat.multiply; 155 156/** 157 * Scales a quat by a scalar number 158 * 159 * @param {quat} out the receiving vector 160 * @param {quat} a the vector to scale 161 * @param {Number} b amount to scale the vector by 162 * @returns {quat} out 163 * @function 164 */ 165quat.scale = vec4.scale; 166 167/** 168 * Rotates a quaternion by the given angle around the X axis 169 * 170 * @param {quat} out quat receiving operation result 171 * @param {quat} a quat to rotate 172 * @param {number} rad angle (in radians) to rotate 173 * @returns {quat} out 174 */ 175quat.rotateX = function (out, a, rad) { 176 rad *= 0.5; 177 178 var ax = a[0], ay = a[1], az = a[2], aw = a[3], 179 bx = Math.sin(rad), bw = Math.cos(rad); 180 181 out[0] = ax * bw + aw * bx; 182 out[1] = ay * bw + az * bx; 183 out[2] = az * bw - ay * bx; 184 out[3] = aw * bw - ax * bx; 185 return out; 186}; 187 188/** 189 * Rotates a quaternion by the given angle around the Y axis 190 * 191 * @param {quat} out quat receiving operation result 192 * @param {quat} a quat to rotate 193 * @param {number} rad angle (in radians) to rotate 194 * @returns {quat} out 195 */ 196quat.rotateY = function (out, a, rad) { 197 rad *= 0.5; 198 199 var ax = a[0], ay = a[1], az = a[2], aw = a[3], 200 by = Math.sin(rad), bw = Math.cos(rad); 201 202 out[0] = ax * bw - az * by; 203 out[1] = ay * bw + aw * by; 204 out[2] = az * bw + ax * by; 205 out[3] = aw * bw - ay * by; 206 return out; 207}; 208 209/** 210 * Rotates a quaternion by the given angle around the Z axis 211 * 212 * @param {quat} out quat receiving operation result 213 * @param {quat} a quat to rotate 214 * @param {number} rad angle (in radians) to rotate 215 * @returns {quat} out 216 */ 217quat.rotateZ = function (out, a, rad) { 218 rad *= 0.5; 219 220 var ax = a[0], ay = a[1], az = a[2], aw = a[3], 221 bz = Math.sin(rad), bw = Math.cos(rad); 222 223 out[0] = ax * bw + ay * bz; 224 out[1] = ay * bw - ax * bz; 225 out[2] = az * bw + aw * bz; 226 out[3] = aw * bw - az * bz; 227 return out; 228}; 229 230/** 231 * Calculates the W component of a quat from the X, Y, and Z components. 232 * Assumes that quaternion is 1 unit in length. 233 * Any existing W component will be ignored. 234 * 235 * @param {quat} out the receiving quaternion 236 * @param {quat} a quat to calculate W component of 237 * @returns {quat} out 238 */ 239quat.calculateW = function (out, a) { 240 var x = a[0], y = a[1], z = a[2]; 241 242 out[0] = x; 243 out[1] = y; 244 out[2] = z; 245 out[3] = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z)); 246 return out; 247}; 248 249/** 250 * Calculates the dot product of two quat's 251 * 252 * @param {quat} a the first operand 253 * @param {quat} b the second operand 254 * @returns {Number} dot product of a and b 255 * @function 256 */ 257quat.dot = vec4.dot; 258 259/** 260 * Performs a linear interpolation between two quat's 261 * 262 * @param {quat} out the receiving quaternion 263 * @param {quat} a the first operand 264 * @param {quat} b the second operand 265 * @param {Number} t interpolation amount between the two inputs 266 * @returns {quat} out 267 * @function 268 */ 269quat.lerp = vec4.lerp; 270 271/** 272 * Performs a spherical linear interpolation between two quat 273 * 274 * @param {quat} out the receiving quaternion 275 * @param {quat} a the first operand 276 * @param {quat} b the second operand 277 * @param {Number} t interpolation amount between the two inputs 278 * @returns {quat} out 279 */ 280quat.slerp = function (out, a, b, t) { 281 var ax = a[0], ay = a[1], az = a[2], aw = a[3], 282 bx = b[0], by = b[1], bz = b[2], bw = b[3]; 283 284 var cosHalfTheta = ax * bx + ay * by + az * bz + aw * bw, 285 halfTheta, 286 sinHalfTheta, 287 ratioA, 288 ratioB; 289 290 if (Math.abs(cosHalfTheta) >= 1.0) { 291 if (out !== a) { 292 out[0] = ax; 293 out[1] = ay; 294 out[2] = az; 295 out[3] = aw; 296 } 297 return out; 298 } 299 300 halfTheta = Math.acos(cosHalfTheta); 301 sinHalfTheta = Math.sqrt(1.0 - cosHalfTheta * cosHalfTheta); 302 303 if (Math.abs(sinHalfTheta) < 0.001) { 304 out[0] = (ax * 0.5 + bx * 0.5); 305 out[1] = (ay * 0.5 + by * 0.5); 306 out[2] = (az * 0.5 + bz * 0.5); 307 out[3] = (aw * 0.5 + bw * 0.5); 308 return out; 309 } 310 311 ratioA = Math.sin((1 - t) * halfTheta) / sinHalfTheta; 312 ratioB = Math.sin(t * halfTheta) / sinHalfTheta; 313 314 out[0] = (ax * ratioA + bx * ratioB); 315 out[1] = (ay * ratioA + by * ratioB); 316 out[2] = (az * ratioA + bz * ratioB); 317 out[3] = (aw * ratioA + bw * ratioB); 318 319 return out; 320}; 321 322/** 323 * Calculates the inverse of a quat 324 * 325 * @param {quat} out the receiving quaternion 326 * @param {quat} a quat to calculate inverse of 327 * @returns {quat} out 328 */ 329quat.invert = function(out, a) { 330 var a0 = a[0], a1 = a[1], a2 = a[2], a3 = a[3], 331 dot = a0*a0 + a1*a1 + a2*a2 + a3*a3, 332 invDot = dot ? 1.0/dot : 0; 333 334 // TODO: Would be faster to return [0,0,0,0] immediately if dot == 0 335 336 out[0] = -a0*invDot; 337 out[1] = -a1*invDot; 338 out[2] = -a2*invDot; 339 out[3] = a3*invDot; 340 return out; 341}; 342 343/** 344 * Calculates the conjugate of a quat 345 * If the quaternion is normalized, this function is faster than quat.inverse and produces the same result. 346 * 347 * @param {quat} out the receiving quaternion 348 * @param {quat} a quat to calculate conjugate of 349 * @returns {quat} out 350 */ 351quat.conjugate = function (out, a) { 352 out[0] = -a[0]; 353 out[1] = -a[1]; 354 out[2] = -a[2]; 355 out[3] = a[3]; 356 return out; 357}; 358 359/** 360 * Calculates the length of a quat 361 * 362 * @param {quat} a vector to calculate length of 363 * @returns {Number} length of a 364 * @function 365 */ 366quat.length = vec4.length; 367 368/** 369 * Alias for {@link quat.length} 370 * @function 371 */ 372quat.len = quat.length; 373 374/** 375 * Calculates the squared length of a quat 376 * 377 * @param {quat} a vector to calculate squared length of 378 * @returns {Number} squared length of a 379 * @function 380 */ 381quat.squaredLength = vec4.squaredLength; 382 383/** 384 * Alias for {@link quat.squaredLength} 385 * @function 386 */ 387quat.sqrLen = quat.squaredLength; 388 389/** 390 * Normalize a quat 391 * 392 * @param {quat} out the receiving quaternion 393 * @param {quat} a quaternion to normalize 394 * @returns {quat} out 395 * @function 396 */ 397quat.normalize = vec4.normalize; 398 399/** 400 * Creates a quaternion from the given 3x3 rotation matrix. 401 * 402 * @param {quat} out the receiving quaternion 403 * @param {mat3} m rotation matrix 404 * @returns {quat} out 405 * @function 406 */ 407quat.fromMat3 = (function() { 408 var s_iNext = [1,2,0]; 409 return function(out, m) { 410 // Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes 411 // article "Quaternion Calculus and Fast Animation". 412 var fTrace = m[0] + m[4] + m[8]; 413 var fRoot; 414 415 if ( fTrace > 0.0 ) { 416 // |w| > 1/2, may as well choose w > 1/2 417 fRoot = Math.sqrt(fTrace + 1.0); // 2w 418 out[3] = 0.5 * fRoot; 419 fRoot = 0.5/fRoot; // 1/(4w) 420 out[0] = (m[7]-m[5])*fRoot; 421 out[1] = (m[2]-m[6])*fRoot; 422 out[2] = (m[3]-m[1])*fRoot; 423 } else { 424 // |w| <= 1/2 425 var i = 0; 426 if ( m[4] > m[0] ) 427 i = 1; 428 if ( m[8] > m[i*3+i] ) 429 i = 2; 430 var j = s_iNext[i]; 431 var k = s_iNext[j]; 432 433 fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0); 434 out[i] = 0.5 * fRoot; 435 fRoot = 0.5 / fRoot; 436 out[3] = (m[k*3+j] - m[j*3+k]) * fRoot; 437 out[j] = (m[j*3+i] + m[i*3+j]) * fRoot; 438 out[k] = (m[k*3+i] + m[i*3+k]) * fRoot; 439 } 440 441 return out; 442 }; 443})(); 444 445/** 446 * Returns a string representation of a quatenion 447 * 448 * @param {quat} vec vector to represent as a string 449 * @returns {String} string representation of the vector 450 */ 451quat.str = function (a) { 452 return 'quat(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ')'; 453}; 454 455if(typeof(exports) !== 'undefined') { 456 exports.quat = quat; 457} 458