topical media & game development

talk show tell print

graphic-o3d-samples-o3djs-quaternions.js / js



  /*
   * Copyright 2009, Google Inc.
   * All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions are
   * met:
   *
   *     * Redistributions of source code must retain the above copyright
   * notice, this list of conditions and the following disclaimer.
   *     * Redistributions in binary form must reproduce the above
   * copyright notice, this list of conditions and the following disclaimer
   * in the documentation and/or other materials provided with the
   * distribution.
   *     * Neither the name of Google Inc. nor the names of its
   * contributors may be used to endorse or promote products derived from
   * this software without specific prior written permission.
   *
   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
   * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
   * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
   * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
   * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
   * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   */
  
  
@fileoverview This file contains various functions for quaternion arithmetic and converting between rotation matrices and quaternions. It adds them to the "quaternions" module on the o3djs object. Javascript arrays with four entries are used to represent quaternions, and functions are provided for doing operations on those. Operations are done assuming quaternions are of the form: q[0] + q[1]i + q[2]j + q[3]k and using the hamiltonian rules for multiplication as described on Brougham Bridge: i^2 = j^2 = k^2 = ijk = -1.

  
  
  o3djs.provide('o3djs.quaternions');
  
  
A Module for quaternion math. @namespace

  
  o3djs.quaternions = o3djs.quaternions || {};
  
  
A Quaternion. @type {!Array.<number>}

  
  o3djs.quaternions.Quaterion = goog.typedef;
  
  
Quickly determines if the object a is a scalar or a quaternion; assumes that the argument is either a number (scalar), or an array of numbers.
parameter: {(number|!o3djs.quaternions.Quaterion)} a A number or array the type of which is in question.
returns: {string} Either the string 'Scalar' or 'Quaternion'.

  
  o3djs.quaternions.mathType = function(a) {
    if (typeof(a) === 'number')
      return 'Scalar';
    return 'Quaternion';
  };
  
  
Copies a quaternion.
parameter: {!o3djs.quaternions.Quaterion} q The quaternion.
returns: {!o3djs.quaternions.Quaterion} A new quaternion identical to q.

  
  o3djs.quaternions.copy = function(q) {
    return q.slice();
  };
  
  
Negates a quaternion.
parameter: {!o3djs.quaternions.Quaterion} q The quaternion.
returns: {!o3djs.quaternions.Quaterion} -q.

  
  o3djs.quaternions.negative = function(q) {
    return [-q[0], -q[1], -q[2], -q[3]];
  };
  
  
Adds two Quaternions.
parameter: {!o3djs.quaternions.Quaterion} a Operand Quaternion.
parameter: {!o3djs.quaternions.Quaterion} b Operand Quaternion.
returns: {!o3djs.quaternions.Quaterion} The sum of a and b.

  
  o3djs.quaternions.addQuaternionQuaternion = function(a, b) {
    return [a[0] + b[0],
            a[1] + b[1],
            a[2] + b[2],
            a[3] + b[3]];
  };
  
  
Adds a quaternion to a scalar.
parameter: {!o3djs.quaternions.Quaterion} a Operand Quaternion.
parameter: {numbers} b Operand Scalar.
returns: {!o3djs.quaternions.Quaterion} The sum of a and b.

  
  o3djs.quaternions.addQuaternionScalar = function(a, b) {
    return [a[0] + b].concat(a.slice(1, 4));
  };
  
  
Adds a scalar to a quaternion.
parameter: {number} a Operand scalar.
parameter: {!o3djs.quaternions.Quaterion} b Operand quaternion.
returns: {!o3djs.quaternions.Quaterion} The sum of a and b.

  
  o3djs.quaternions.addScalarQuaternion = function(a, b) {
    return [a + b[0]].concat(b.slice(1, 4));
  };
  
  
Subtracts two quaternions.
parameter: {!o3djs.quaternions.Quaterion} a Operand quaternion.
parameter: {!o3djs.quaternions.Quaterion} b Operand quaternion.
returns: {!o3djs.quaternions.Quaterion} The difference a - b.

  
  o3djs.quaternions.subQuaternionQuaternion = function(a, b) {
    return [a[0] - b[0],
            a[1] - b[1],
            a[2] - b[2],
            a[3] - b[3]];
  };
  
  
Subtracts a scalar from a quaternion.
parameter: {!o3djs.quaternions.Quaterion} a Operand quaternion.
parameter: {number} b Operand scalar.
returns: {!o3djs.quaternions.Quaterion} The difference a - b.

  
  o3djs.quaternions.subQuaternionScalar = function(a, b) {
    return [a[0] - b].concat(a.slice(1, 4));
  };
  
  
Subtracts a quaternion from a scalar.
parameter: {number} a Operand scalar.
parameter: {!o3djs.quaternions.Quaterion} b Operand quaternion.
returns: {!o3djs.quaternions.Quaterion} The difference a - b.

  
  o3djs.quaternions.subScalarQuaternion = function(a, b) {
    return [a - b[0], -b[1], -b[2], -b[3]];
  };
  
  
Multiplies a scalar by a quaternion.
parameter: {Array} k The scalar.
parameter: {Array} q The quaternion.
returns: {Array} The product of k and q.

  
  o3djs.quaternions.mulScalarQuaternion = function(k, q) {
    return [k * q[0], k * q[1], k * q[2], k * q[3]];
  };
  
  
Multiplies a quaternion by a scalar.
parameter: {!o3djs.quaternions.Quaterion} q The Quaternion.
parameter: {number} k The scalar.
returns: {!o3djs.quaternions.Quaterion} The product of k and v.

  
  o3djs.quaternions.mulQuaternionScalar = function(q, k) {
    return [k * q[0], k * q[1], k * q[2], k * q[3]];
  };
  
  
Multiplies two quaternions.
parameter: {!o3djs.quaternions.Quaterion} a Operand quaternion.
parameter: {!o3djs.quaternions.Quaterion} b Operand quaternion.
returns: {!o3djs.quaternions.Quaterion} The quaternion product a * b.

  
  o3djs.quaternions.mulQuaternionQuaternion = function(a, b) {
    var a0 = a[0];
    var a1 = a[1];
    var a2 = a[2];
    var a3 = a[3];
    var b0 = b[0];
    var b1 = b[1];
    var b2 = b[2];
    var b3 = b[3];
  
    return [
      a0 * b0 - a1 * b1 - a2 * b2 - a3 * b3,
      a0 * b1 + a1 * b0 + a2 * b3 - a3 * b2,
      a0 * b2 - a1 * b3 + a2 * b0 + a3 * b1,
      a0 * b3 + a1 * b2 - a2 * b1 + a3 * b0];
  };
  
  
Divides two quaternions; assumes the convention that a/b = a*(1/b).
parameter: {!o3djs.quaternions.Quaterion} a Operand quaternion.
parameter: {!o3djs.quaternions.Quaterion} b Operand quaternion.
returns: {!o3djs.quaternions.Quaterion} The quaternion quotient a / b.

  
  o3djs.quaternions.divQuaternionQuaternion = function(a, b) {
    var a0 = a[0];
    var a1 = a[1];
    var a2 = a[2];
    var a3 = a[3];
    var b0 = b[0];
    var b1 = b[1];
    var b2 = b[2];
    var b3 = b[3];
  
    var d = b0 * b0 + b1 * b1 + b2 * b2 + b3 * b3;
    return [
        (a0 * b0 + a1 * b1 + a2 * b2 + a3 * b3) / d,
        (a1 * b0 - a0 * b1 - a2 * b3 + a3 * b2) / d,
        (a1 * b3 - a0 * b2 + a2 * b0 - a3 * b1) / d,
        (a2 * b1 + a3 * b0 - a0 * b3 - a1 * b2) / d];
  };
  
  
Divides a Quaternion by a scalar.
parameter: {!o3djs.quaternions.Quaterion} q The quaternion.
parameter: {number} k The scalar.
returns: {!o3djs.quaternions.Quaterion} q The quaternion q divided by k.

  
  o3djs.quaternions.divQuaternionScalar = function(q, k) {
    return [q[0] / k, q[1] / k, q[2] / k, q[3] / k];
  };
  
  
Divides a scalar by a quaternion.
parameter: {number} a Operand scalar.
parameter: {!o3djs.quaternions.Quaterion} b Operand quaternion.
returns: {!o3djs.quaternions.Quaterion} The quaternion product.

  
  o3djs.quaternions.divScalarQuaternion = function(a, b) {
    var b0 = b[0];
    var b1 = b[1];
    var b2 = b[2];
    var b3 = b[3];
  
    var d = b0 * b0 + b1 * b1 + b2 * b2 + b3 * b3;
    return [a * b0 / d, -a * b[1] / d, -a * b[2] / d, -a * b[3] / d];
  };
  
  
Computes the multiplicative inverse of a quaternion.
parameter: {!o3djs.quaternions.Quaterion} q The quaternion.
returns: {!o3djs.quaternions.Quaterion} The multiplicative inverse of q.

  
  o3djs.quaternions.inverse = function(q) {
    var q0 = q[0];
    var q1 = q[1];
    var q2 = q[2];
    var q3 = q[3];
  
    var d = q0 * q0 + q1 * q1 + q2 * q2 + q3 * q3;
    return [q0 / d, -q[1] / d, -q[2] / d, -q[3] / d];
  };
  
  
Multiplies two objects which are either scalars or quaternions.
parameter: {(!o3djs.quaternions.Quaterion|number)} a Operand.
parameter: {(!o3djs.quaternions.Quaterion|number)} b Operand.
returns: {(!o3djs.quaternions.Quaterion|number)} The product of a and b.

  
  o3djs.quaternions.mul = function(a, b) {
    return o3djs.quaternions['mul' + o3djs.quaternions.mathType(a) +
        o3djs.quaternions.mathType(b)](a, b);
  };
  
  
Divides two objects which are either scalars or quaternions.
parameter: {(!o3djs.quaternions.Quaterion|number)} a Operand.
parameter: {(!o3djs.quaternions.Quaterion|number)} b Operand.
returns: {(!o3djs.quaternions.Quaterion|number)} The quotient of a and b.

  
  o3djs.quaternions.div = function(a, b) {
    return o3djs.quaternions['div' + o3djs.quaternions.mathType(a) +
        o3djs.quaternions.mathType(b)](a, b);
  };
  
  
Adds two objects which are either scalars or quaternions.
parameter: {(!o3djs.quaternions.Quaterion|number)} a Operand.
parameter: {(!o3djs.quaternions.Quaterion|number)} b Operand.
returns: {(!o3djs.quaternions.Quaterion|number)} The sum of a and b.

  
  o3djs.quaternions.add = function(a, b) {
    return o3djs.quaternions['add' + o3djs.quaternions.mathType(a) +
        o3djs.quaternions.mathType(b)](a, b);
  };
  
  
Subtracts two objects which are either scalars or quaternions.
parameter: {(!o3djs.quaternions.Quaterion|number)} a Operand.
parameter: {(!o3djs.quaternions.Quaterion|number)} b Operand.
returns: {(!o3djs.quaternions.Quaterion|number)} The difference of a and b.

  
  o3djs.quaternions.sub = function(a, b) {
    return o3djs.quaternions['sub' + o3djs.quaternions.mathType(a) +
        o3djs.quaternions.mathType(b)](a, b);
  };
  
  
Computes the length of a Quaternion, i.e. the square root of the sum of the squares of the coefficients.
parameter: {!o3djs.quaternions.Quaterion} a The Quaternion.
returns: {number} The length of a.

  
  o3djs.quaternions.length = function(a) {
    return Math.sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2] + a[3] * a[3]);
  };
  
  
Computes the square of the length of a quaternion, i.e. the sum of the squares of the coefficients.
parameter: {!o3djs.quaternions.Quaterion} a The quaternion.
returns: {number} The square of the length of a.

  
  o3djs.quaternions.lengthSquared = function(a) {
    return a[0] * a[0] + a[1] * a[1] + a[2] * a[2] + a[3] * a[3];
  };
  
  
Divides a Quaternion by its length and returns the quotient.
parameter: {!o3djs.quaternions.Quaterion} a The Quaternion.
returns: {!o3djs.quaternions.Quaterion} A unit length quaternion pointing in the same direction as a.

  
  o3djs.quaternions.normalize = function(a) {
    var d = Math.sqrt(a[0] * a[0] + a[1] * a[1] + a[2] * a[2] + a[3] * a[3]);
    return [a[0] / d, a[1] / d, a[2] / d, a[3] / d];
  };
  
  
Computes the conjugate of the given quaternion.
parameter: {!o3djs.quaternions.Quaterion} q The quaternion.
returns: {!o3djs.quaternions.Quaterion} The conjugate of q.

  
  o3djs.quaternions.conjugate = function(q) {
    return [q[0], -q[1], -q[2], -q[3]];
  };
  
  
Creates a quaternion which rotates around the x-axis by the given angle.
parameter: {number} angle The angle by which to rotate (in radians).
returns: {!o3djs.quaternions.Quaterion} The quaternion.

  
  o3djs.quaternions.rotationX = function(angle) {
    return [Math.cos(angle / 2), Math.sin(angle / 2), 0, 0];
  };
  
  
Creates a quaternion which rotates around the y-axis by the given angle.
parameter: {number} angle The angle by which to rotate (in radians).
returns: {!o3djs.quaternions.Quaterion} The quaternion.

  
  o3djs.quaternions.rotationY = function(angle) {
    return [Math.cos(angle / 2), 0, Math.sin(angle / 2), 0];
  };
  
  
Creates a quaternion which rotates around the z-axis by the given angle.
parameter: {number} angle The angle by which to rotate (in radians).
returns: {!o3djs.quaternions.Quaterion} The quaternion.

  
  o3djs.quaternions.rotationZ = function(angle) {
    return [Math.cos(angle / 2), 0, 0, Math.sin(angle / 2)];
  };
  
  
Creates a quaternion which rotates around the given axis by the given angle.
parameter: {!o3djs.math.Vector3} axis The axis about which to rotate.
parameter: {number} angle The angle by which to rotate (in radians).
returns: {!o3djs.quaternions.Quaterion} A quaternion which rotates angle radians around the axis.

  
  o3djs.quaternions.axisRotation = function(axis, angle) {
    var d = Math.sqrt(axis[0] * axis[0] +
                      axis[1] * axis[1] +
                      axis[2] * axis[2]);
    var sin = Math.sin(angle / 2);
    var cos = Math.cos(angle / 2);
    return [cos, sin * axis[0] / d, sin * axis[1] / d, sin * axis[2] / d];
  };
  
  
Computes a 4-by-4 rotation matrix (with trivial translation component) given a quaternion. We assume the convention that to rotate a vector v by a quaternion r means to express that vector as a quaternion q by letting q = [0, v[0], v[1], v[2]] and then obtain the rotated vector by evaluating the expression (r * q) / r.
parameter: {!o3djs.quaternions.Quaterion} q The quaternion.
returns: {!o3djs.math.Matrix4} A 4-by-4 rotation matrix.

  
  o3djs.quaternions.quaternionToRotation = function(q) {
    var q0 = q[0];
    var q1 = q[1];
    var q2 = q[2];
    var q3 = q[3];
  
    var q0q0 = q0 * q0;
    var q0q1 = q0 * q1;
    var q0q2 = q0 * q2;
    var q0q3 = q0 * q3;
    var q1q0 = q1 * q0;
    var q1q1 = q1 * q1;
    var q1q2 = q1 * q2;
    var q1q3 = q1 * q3;
    var q2q0 = q2 * q0;
    var q2q1 = q2 * q1;
    var q2q2 = q2 * q2;
    var q2q3 = q2 * q3;
    var q3q0 = q3 * q0;
    var q3q1 = q3 * q1;
    var q3q2 = q3 * q2;
    var q3q3 = q3 * q3;
  
    var d = q0q0 + q1q1 + q2q2 + q3q3;
  
    return [
      [(q0q0 + q1q1 - q2q2 - q3q3) / d,
       2 * (q0q3 + q1q2) / d,
       2 * (q1q3 - q0q2) / d, 0],
      [2 * (q1q2 - q0q3) / d,
       (q0q0 - q1q1 + q2q2 - q3q3) / d,
       2 * (q0q1 + q2q3) / d, 0],
      [2 * (q0q2 + q1q3) / d,
       2 * (q2q3 - q0q1) / d,
       (q0q0 - q1q1 - q2q2 + q3q3) / d, 0],
      [0, 0, 0, 1]];
  };
  
  
Computes a quaternion whose rotation is equivalent to the given matrix.
parameter: {!o3djs.math.Matrix4} m A 3-by-3 or 4-by-4 rotation matrix.
returns: {!o3djs.quaternions.Quaterion} A quaternion q such that quaternions.quaternionToRotation(q) is m.

  
  o3djs.quaternions.rotationToQuaternion = function(m) {
    var u;
    var v;
    var w;
  
    // Choose u, v, and w such that u is the index of the biggest diagonal entry
    // of m, and u v w is an even permutation of 0 1 and 2.
    if (m[0][0] > m[1][1] && m[0][0] > m[2][2]) {
      u = 0;
      v = 1;
      w = 2;
    } else if (m[1][1] > m[0][0] && m[1][1] > m[2][2]) {
      u = 1;
      v = 2;
      w = 0;
    } else {
      u = 2;
      v = 0;
      w = 1;
    }
  
    var r = Math.sqrt(1 + m[u][u] - m[v][v] - m[w][w]);
    var q = [];
    q[0] = 0.5 * (m[v][w] - m[w][v]) / r;
    q[u + 1] = 0.5 * r;
    q[v + 1] = 0.5 * (m[v][u] + m[u][v]) / r;
    q[w + 1] = 0.5 * (m[u][w] + m[w][u]) / r;
  
    return q;
  };
  
  


(C) Æliens 20/2/2008

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.