org.proteinshader.math
Class Quaternion

java.lang.Object
  extended by org.proteinshader.math.Quaternion
All Implemented Interfaces:
Cloneable

public class Quaternion
extends Object
implements Cloneable

This class is used to create a quaternion, a four-dimensional complex number that is typically used to represent a rotation in three-dimensional space.

The reason for using Quaternions to represent rotations is that there is a very useful algorithm for interpolating between a start and an end quaternion. This algorithm is called SLERP (Spherical Linear intERPolation), and the primary reference is a paper by Ken Shoemake, "Animating Rotation with Quaternion Curves" SIGGRAPH 85, Proc. Computer Graphics Vol 19 No. 3, (1985), pp. 245-254.

SLERP ALGORITHM:

The equation for interpolating between quaternions q1 and q2 to obtain q3 is given as

q3 = slerp(q1, q2; t), 0 <= t <= 1
q3 = q1 * (sin((1-t)*theta)) / sin(theta)) + q2 * (sin(t*theta) / sin(theta))

where cos(theta) = q1.dot(q2), so
theta = acos(q1.dot(q2))
theta = acos(q1.x*q2.x + q1.y*q2.y + q1.z*q2.z + q1.w*q2.w)

For SLERP to give the shortest path, the angle theta should be between 0 and 90 degrees (positive cosine theta). If theta is between 90 and 180 degrees (negative cosine theta), then quaternion q2 should be converted to the quaternion q = (-q2.x, -q2.y, -q2.z, -q2.w). This new quaternion represents the same rotation as q2, but the angle theta is now between 0 and 90 degrees.

ROTATION MATRIX TO QUATERNION CONVERSION:

For converting a rotation matrix to a quaternion (and for other basic quaternion operations), three references were consulted:

1. "Rotating Objects using Quaternions" by Nick Bobick on the Gamasutra web site. Registration (which is free) and a password are needed for this link:
http://www.gamasutra.com/features/19980703/quaternions_01.htm (cited December 2006).

This tutorial gives a good introduction to why quaternions are useful for computer graphics and animation. Example C code is given for converting a rotation matrix to a quaternion, converting a quaternion back to a rotation matrix, and for doing SLERP. When interpreting the example code, it is important to realize that the matrices appear to all be given in terms of column major notation rather than the usual row major notation used in C/C++/Java code. If this issue is not accounted for, the quaternion produced from the rotation matrix to quaternion code would end up rotating in the opposite direction as expected.

2. The derivation of the equations used for a rotation matrix to quaternion conversion (along with additional example code) can be found at the "EuclideanSpace - building a 3D world" web site by Martin Baker. The site also has numerous pages dealing with other aspects of quaternion math, and 3D math in general.

http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm (cited December 2006).

3. The "Sacred Software" web site by Alex Diener was also very useful for a general introduction to quaternions, and includes very readable example code for several common quaternion operations, including SLERP.

http://www.sacredsoftware.net/tutorials/Quaternions/Quaternions.xhtml (cited December 2006).

MATRIX NOTATION:

For matrix->quaternion and quaternion->matrix conversions in this class, three column vectors are used to represent the matrix M:

M = [N B T]

N = normal = [N.x, N.y, N.z]
B = binormal = [B.x, B.y, B.z]
T = tangent = [T.x, T.y, T.z]

If a matrix was given in row major format with a shorthand notation of m00 for m[0][0], the positions of a matrix could be represented as

-------------
|m00 m01 m02|
|m10 m11 m12|
|m20 m21 m22|
-------------

which is equivalent to

-------------
|N.x B.x T.x|
|N.y B.y T.y|
|N.z B.z T.z|
-------------

in the notation used in class Quaternion, so

N = [m00, m10, m20] = [N.x, N.y, N.z]
B = [m01, m11, m21] = [B.x, B.y, B.z]
T = [m02, m12, m22] = [T.x, T.y, T.z]


Field Summary
static String DECIMAL_FORMAT
          As a convenience for debugging, the toString() method will return a representation of a quaternion in the general form "(x, y, z, w)", where the number of decimal places for each value will be determined this decimal format String, which is "0.000".
static double MIN_THETA
          If theta is too close to zero for a SLERP calculation, then a clone of the start Quaternion will be returned.
static double ONE_DEGREE
          1 degree given in radians is PI / 180.
 double w
          The public w-component.
 double x
          The public x-component.
 double y
          The public y-component.
 double z
          The public z-component.
 
Constructor Summary
Quaternion()
          Constructs the multiplication identity quaternion (x, y, z, w) = (0, 0, 0, 1).
Quaternion(double x, double y, double z, double w)
          Constructs a quaternion.
Quaternion(Vec3d axis, double angle)
          Creates a quaternion that is equivalent to the rotation specified by the axis and angle (in radians) given as aguments.
Quaternion(Vec3d N, Vec3d B, Vec3d T)
          Creates a quaternion that is equivalent to the rotation contained in the 3 x 3 matrix [N B T].
 
Method Summary
 void adjustMyTangent(Vec3d tangent)
          Modifies this quaternion by rotating it such that if it is converted into a rotation matrix [N B T], the T vector will match the tangent given as an argument.
 Quaternion adjustTangent(Vec3d tangent)
          Returns a copy of this quaternion that has been rotated such that if it is converted into a rotation matrix [N B T], the T vector will match the tangent given as an argument.
 double angleBetweenNormals(Quaternion quat)
          Returns the angle between the normals of the calling and argument quaternions, where the normal is the first column vector of the rotation matrix [N B T] that is the equivalent of a quaternion.
 Quaternion clone()
          Creates a clone of this quaternion and returns it.
 Quaternion conjugate()
          Creates a clone of the calling Quaternion and then converts it to the conjugate, q'.
 void conjugateMe()
          Converts the calling Quaternion to its conjugate.
 double generateAxisAndAngle(Vec3d axis)
          Converts the Quaternion to an axis of rotation and an angle.
 double[] generateMatrix()
          Generates a 4 x 4 rotation matrix that is equivalent to this quaternion, but returns it as a linear array of 16 elements so that it can be used with Java Bindings for OpenGL.
 void generateMatrix(Vec3d N, Vec3d B, Vec3d T)
          Generates a 3 x 3 rotation matrix (actually 3 column vectors) that is equivalent to this quaternion, assuming that the quaternion has already been normalized (such that x^2 + y^2 + z^2 + w^2 = 1).
 Vec3d getBinormal()
          Converts the Quaternion into a 3 x 3 rotation matrix and the returns the second column vector (the Binormal).
 Vec3d getNormal()
          Converts the Quaternion into a 3 x 3 rotation matrix and the returns the first column vector (the Normal).
 Vec3d getTangent()
          Converts the Quaternion into a 3 x 3 rotation matrix and the returns the third column vector (the Tangent).
 Quaternion invert()
          Creates a clone of the calling Quaternion and inverts it.
 void invertMe()
          Inverts the calling Quaternion.
 double magnitude()
          Returns the magnitude (length) of this quaternion.
 Point3d multiply(Point3d p)
          Multiplies a point by this quaternion and returns the resulting point.
 Quaternion multiply(Quaternion quat)
          Creates a clone of the calling Quaternion and multiplies it by the Quaternion given as an argument.
 Vec3d multiply(Vec3d v)
          Multiplies a vector by this quaternion and returns the resulting vector.
 void multiplyMe(Quaternion quat)
          Multiplies the calling Quaternion by the argument Quaternion and stores the result in the calling Quaternion.
 Quaternion normalize()
          Creates and returns a new quaternion that is equivalent to the calling quaternion, but is guaranteed to be of unit length.
 void normalizeMe()
          Normalizes the calling quaternion object by dividing each component of the quaternion by the magnitude of the quaternion.
 void setXYZW(double x, double y, double z, double w)
          Sets the xyzw-values of the quaternion.
 void setXYZW(Quaternion quat)
          Sets the xyzw-values of the quaternion to the xyzw-values of the quaternion given as an argument.
 void setXYZW(Vec3d axis, double angle)
          Calculates and sets (x, y, z, w) of this quaternion based on the axis and angle (in radians) given as aguments.
 void setXYZW(Vec3d N, Vec3d B, Vec3d T)
          Calculates and sets (x, y, z, w) of this quaternion based on the rotation contained in the 3 x 3 matrix [N B T].
 Quaternion slerp(Quaternion end, double t)
          Uses SLERP (Spherical Linear intERPolation) to calculate a Quaternion (a rotation) at any point t between the calling Quaternion and the argument Quaternion.
 String toString()
          As a convenience for debugging, the toString() method returns the xyzw-components of the quaternion in the form "(x, y, z, w)".
 
Methods inherited from class java.lang.Object
equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
 

Field Detail

MIN_THETA

public static final double MIN_THETA
If theta is too close to zero for a SLERP calculation, then a clone of the start Quaternion will be returned. The minimum absolute value of theta is set at 0.01.

See Also:
Constant Field Values

ONE_DEGREE

public static final double ONE_DEGREE
1 degree given in radians is PI / 180.

See Also:
Constant Field Values

DECIMAL_FORMAT

public static final String DECIMAL_FORMAT
As a convenience for debugging, the toString() method will return a representation of a quaternion in the general form "(x, y, z, w)", where the number of decimal places for each value will be determined this decimal format String, which is "0.000".

See Also:
Constant Field Values

x

public double x
The public x-component.


y

public double y
The public y-component.


z

public double z
The public z-component.


w

public double w
The public w-component.

Constructor Detail

Quaternion

public Quaternion()
Constructs the multiplication identity quaternion (x, y, z, w) = (0, 0, 0, 1).

For multiplication, the identity quaternion is (0, 0, 0, 1), but for addition, the identity quaternion is (0, 0, 0, 0).


Quaternion

public Quaternion(double x,
                  double y,
                  double z,
                  double w)
Constructs a quaternion.

Parameters:
x - the x-component.
y - the y-component.
z - the z-component.
w - the w-component.

Quaternion

public Quaternion(Vec3d N,
                  Vec3d B,
                  Vec3d T)
Creates a quaternion that is equivalent to the rotation contained in the 3 x 3 matrix [N B T].

Parameters:
N - a normal vector with components N.x, N.y, and N.z.
B - a binormal vector with components B.x, B.y, and B.z.
T - a tangent vector with components T.x, T.y, and T.z.

Quaternion

public Quaternion(Vec3d axis,
                  double angle)
Creates a quaternion that is equivalent to the rotation specified by the axis and angle (in radians) given as aguments.

Parameters:
axis - the axis to rotate about.
angle - the rotation angle in radians.
Method Detail

slerp

public Quaternion slerp(Quaternion end,
                        double t)
Uses SLERP (Spherical Linear intERPolation) to calculate a Quaternion (a rotation) at any point t between the calling Quaternion and the argument Quaternion.

The parameter t varies from 0.0 to 1.0, with t = 0.0 corresponding to the start (calling) Quaternion, and t = 1.0 corresponding to the end (argument) Quaternion. If t is less than zero or more that one, than the result will be an extrapolation rather than an interpolation.

The algorithm is given in the comments near the top of this class. The interpolated Quaternion will be normalized.

Parameters:
end - the end Quaternion.
t - a parameter that can vary from 0.0 to 1.0.
Returns:
The result Quaternion resulting from slerp.

adjustMyTangent

public void adjustMyTangent(Vec3d tangent)
Modifies this quaternion by rotating it such that if it is converted into a rotation matrix [N B T], the T vector will match the tangent given as an argument.

Parameters:
tangent - the target tangent.

adjustTangent

public Quaternion adjustTangent(Vec3d tangent)
Returns a copy of this quaternion that has been rotated such that if it is converted into a rotation matrix [N B T], the T vector will match the tangent given as an argument.

Parameters:
tangent - the target tangent.

angleBetweenNormals

public double angleBetweenNormals(Quaternion quat)
Returns the angle between the normals of the calling and argument quaternions, where the normal is the first column vector of the rotation matrix [N B T] that is the equivalent of a quaternion.

Before comparing the normals, the quaternions are aligned such that if they were converted to [N B T] matrices, their tangents (the third column vector) would be parallel.

This method is needed by the BetaStrandSegmentFactory.

Parameters:
quat - the quaterion to compare.
Returns:
The angle (in radians) between the normals.

conjugate

public Quaternion conjugate()
Creates a clone of the calling Quaternion and then converts it to the conjugate, q'. The calling Quaternion is not modified.

q' = (-q.x, -q.y, -q.z, q.w), where q is the original quaternion.

Returns:
The conjugate of the calling Quaternion.

conjugateMe

public void conjugateMe()
Converts the calling Quaternion to its conjugate.

q' = (-q.x, -q.y, -q.z, q.w), where q was the original quaternion.


clone

public Quaternion clone()
Creates a clone of this quaternion and returns it.

The clone is a deep clone (in the sense of being completely independent of the original).

Overrides:
clone in class Object
Returns:
A clone of the calling Quaternion object.

generateMatrix

public double[] generateMatrix()
Generates a 4 x 4 rotation matrix that is equivalent to this quaternion, but returns it as a linear array of 16 elements so that it can be used with Java Bindings for OpenGL. The 4th row of the 4th column will be set to 1.0 (as in the identity matrix).

Java 2D arrays are not accepted as input to JOGL methods such as glMultMatrixd(). Only linear arrays can be plugged in. The first four elements of the linear array is considered to be the first column of the equivalent 4 x 4 matrix, the next four elements form the second column, etc.

This method assumes that the quaternion has already been normalized (such that x^2 + y^2 + z^2 + w^2 = 1).

Returns:
A linear array of 16 elements that represent a 4 by 4 matrix.

generateMatrix

public void generateMatrix(Vec3d N,
                           Vec3d B,
                           Vec3d T)
Generates a 3 x 3 rotation matrix (actually 3 column vectors) that is equivalent to this quaternion, assuming that the quaternion has already been normalized (such that x^2 + y^2 + z^2 + w^2 = 1).

Parameters:
N - a normal vector (N.x, N.y, N.z) to fill with values.
B - a binormal vector (B.x, B.y, B.z) to fill with values.
T - a tangent vector (T.x, T.y, T.z) to fill with values.

generateAxisAndAngle

public double generateAxisAndAngle(Vec3d axis)
Converts the Quaternion to an axis of rotation and an angle.

Parameters:
axis - a vector to store the (x, y, z) axis in.
Returns:
The angle of rotation in radians.

getNormal

public Vec3d getNormal()
Converts the Quaternion into a 3 x 3 rotation matrix and the returns the first column vector (the Normal).

Returns:
The Normal vector (N.x, N.y, N.z).

getBinormal

public Vec3d getBinormal()
Converts the Quaternion into a 3 x 3 rotation matrix and the returns the second column vector (the Binormal).

Returns:
The Binormal vector (B.x, B.y, Z.z).

getTangent

public Vec3d getTangent()
Converts the Quaternion into a 3 x 3 rotation matrix and the returns the third column vector (the Tangent).

Returns:
The Tangent vector (T.x, T.y, T.z).

invert

public Quaternion invert()
Creates a clone of the calling Quaternion and inverts it. The calling Quaternion is not modified.

The inverse of a quaternion is similar to the conjugate, but its length is adjusted so that

(inverse quaternion) * quaternion = 1

Returns:
The inverse of the calling Quaternion.

invertMe

public void invertMe()
Inverts the calling Quaternion.

The inverse of a quaternion is similar to the conjugate, but its length is adjusted so that

(inverse quaternion) * quaternion = 1


magnitude

public double magnitude()
Returns the magnitude (length) of this quaternion. The length is calculated by taking the square root of the sum of each component squared.

Returns:
The magnitude of this quaternion.

multiply

public Point3d multiply(Point3d p)
Multiplies a point by this quaternion and returns the resulting point. The original point is not modified.

Result point = quaternion * (argument point) (inverse quaternion)

Parameters:
p - The point to rotate.
Returns:
The point resulting from the rotation.

multiply

public Vec3d multiply(Vec3d v)
Multiplies a vector by this quaternion and returns the resulting vector. The original vector is not modified.

Result vector = (quaternion) * (argument vector) (inverse quaternion)

Parameters:
v - The vector to rotate.
Returns:
The vector resulting from the rotation.

multiply

public Quaternion multiply(Quaternion quat)
Creates a clone of the calling Quaternion and multiplies it by the Quaternion given as an argument. The calling Quaterion is not modified.

Quaternion multiplication is not commutative. The order used here is

Result Quaternion = (calling Quaternion) x (argument Quaternion)

Parameters:
quat - the Quaternion to multiply by.
Returns:
The result Quaternion.

multiplyMe

public void multiplyMe(Quaternion quat)
Multiplies the calling Quaternion by the argument Quaternion and stores the result in the calling Quaternion.

Quaternion multiplication is not commutative. The order used here is

Calling Quaternion = (calling Quaternion) x (argument Quaternion)

Parameters:
quat - the Quaternion to multiply by.

normalize

public Quaternion normalize()
Creates and returns a new quaternion that is equivalent to the calling quaternion, but is guaranteed to be of unit length. The calling quaternion is not modified.

Quaternion normalization means that (x^2 + y^2 + z^2 + w^2) = 1

Returns:
A normalized clone of the calling quaternion.

normalizeMe

public void normalizeMe()
Normalizes the calling quaternion object by dividing each component of the quaternion by the magnitude of the quaternion.

Quaternion normalization means that (x^2 + y^2 + z^2 + w^2) = 1


setXYZW

public void setXYZW(double x,
                    double y,
                    double z,
                    double w)
Sets the xyzw-values of the quaternion.

Parameters:
x - the x-component
y - the y-component
z - the z-component
w - the w-component

setXYZW

public void setXYZW(Quaternion quat)
Sets the xyzw-values of the quaternion to the xyzw-values of the quaternion given as an argument.

Parameters:
quat - the quaternion to copy xyzw-values from.

setXYZW

public void setXYZW(Vec3d N,
                    Vec3d B,
                    Vec3d T)
Calculates and sets (x, y, z, w) of this quaternion based on the rotation contained in the 3 x 3 matrix [N B T].

Parameters:
N - a normal vector with components N.x, N.y, and N.z.
B - a binormal vector with components B.x, B.y, and B.z.
T - a tangent vector with components T.x, T.y, and T.z.

setXYZW

public void setXYZW(Vec3d axis,
                    double angle)
Calculates and sets (x, y, z, w) of this quaternion based on the axis and angle (in radians) given as aguments.

The axis vector given as an argument will not be modifed. The axis does not need to be normalized, as this method will obtain a normalized clone of the axis vector.

Parameters:
axis - the axis to rotate about.
angle - the rotation angle in radians.

toString

public String toString()
As a convenience for debugging, the toString() method returns the xyzw-components of the quaternion in the form "(x, y, z, w)". The number of digits after the decimal place will be determined by the DECIMAL_FORMAT constant for this class.

Overrides:
toString in class Object
Returns:
A String representation of this quaternion.


Copyright © 2007-2008