topical media & game development
student-ar-org-papervision3d-core-math-Quaternion.ax
student-ar-org-papervision3d-core-math-Quaternion.ax
[swf]
[flash]
flex
package org.papervision3d.core.math
{
author: Tim Knip
public class @ax-student-ar-org-papervision3d-core-math-Quaternion
{
private var _matrix:Matrix3D;
public static const EPSILON:Number = 0.000001;
public static const DEGTORAD:Number = (Math.PI/180.0);
public static const RADTODEG:Number = (180.0/Math.PI);
public var x:Number;
public var y:Number;
public var z:Number;
public var w:Number;
constructor.
@param x
@param y
@param z
@param w
@return
public function @ax-student-ar-org-papervision3d-core-math-Quaternion( x:Number = 0, y:Number = 0, z:Number = 0, w:Number = 1 )
{
this.x = x;
this.y = y;
this.z = z;
this.w = w;
_matrix = Matrix3D.IDENTITY;
}
Clone.
public function clone():@ax-student-ar-org-papervision3d-core-math-Quaternion
{
return new @ax-student-ar-org-papervision3d-core-math-Quaternion(this.x, this.y, this.z, this.w);
}
Multiply.
@param a
@param b
public function calculateMultiply( a:@ax-student-ar-org-papervision3d-core-math-Quaternion, b:@ax-student-ar-org-papervision3d-core-math-Quaternion ):void
{
this.x = a.w*b.x + a.x*b.w + a.y*b.z - a.z*b.y;
this.y = a.w*b.y - a.x*b.z + a.y*b.w + a.z*b.x;
this.z = a.w*b.z + a.x*b.y - a.y*b.x + a.z*b.w;
this.w = a.w*b.w - a.x*b.x - a.y*b.y - a.z*b.z;
}
Creates a @ax-student-ar-org-papervision3d-core-math-Quaternion from a axis and a angle.
@param x X-axis
@param y Y-axis
@param z Z-axis
@param angle angle in radians.
@return
public function setFromAxisAngle( x:Number, y:Number, z:Number, angle:Number ):void
{
var sin:Number = Math.sin( angle / 2 );
var cos:Number = Math.cos( angle / 2 );
this.x = x * sin;
this.y = y * sin;
this.z = z * sin;
this.w = cos;
this.normalize();
}
Sets this @ax-student-ar-org-papervision3d-core-math-Quaternion from Euler angles.
@param ax X-angle in radians.
@param ay Y-angle in radians.
@param az Z-angle in radians.
public function setFromEuler(ax:Number, ay:Number, az:Number, useDegrees:Boolean=false):void
{
if( useDegrees )
{
ax *= DEGTORAD;
ay *= DEGTORAD;
az *= DEGTORAD;
}
var fSinPitch :Number = Math.sin( ax * 0.5 );
var fCosPitch :Number = Math.cos( ax * 0.5 );
var fSinYaw :Number = Math.sin( ay * 0.5 );
var fCosYaw :Number = Math.cos( ay * 0.5 );
var fSinRoll :Number = Math.sin( az * 0.5 );
var fCosRoll :Number = Math.cos( az * 0.5 );
var fCosPitchCosYaw :Number = fCosPitch * fCosYaw;
var fSinPitchSinYaw :Number = fSinPitch * fSinYaw;
this.x = fSinRoll * fCosPitchCosYaw - fCosRoll * fSinPitchSinYaw;
this.y = fCosRoll * fSinPitch * fCosYaw + fSinRoll * fCosPitch * fSinYaw;
this.z = fCosRoll * fCosPitch * fSinYaw - fSinRoll * fSinPitch * fCosYaw;
this.w = fCosRoll * fCosPitchCosYaw + fSinRoll * fSinPitchSinYaw;
}
Modulo.
@param a
@return
public function get modulo():Number
{
return Math.sqrt(x*x + y*y + z*z + w*w);
}
Conjugate.
@param a
@return
public static function conjugate( a:@ax-student-ar-org-papervision3d-core-math-Quaternion ):@ax-student-ar-org-papervision3d-core-math-Quaternion
{
var q:@ax-student-ar-org-papervision3d-core-math-Quaternion = new @ax-student-ar-org-papervision3d-core-math-Quaternion();
q.x = -a.x;
q.y = -a.y;
q.z = -a.z;
q.w = a.w;
return q;
}
Creates a @ax-student-ar-org-papervision3d-core-math-Quaternion from a axis and a angle.
@param x X-axis
@param y Y-axis
@param z Z-axis
@param angle angle in radians.
@return
public static function createFromAxisAngle( x:Number, y:Number, z:Number, angle:Number ):@ax-student-ar-org-papervision3d-core-math-Quaternion
{
var q:@ax-student-ar-org-papervision3d-core-math-Quaternion = new @ax-student-ar-org-papervision3d-core-math-Quaternion();
q.setFromAxisAngle(x, y, z, angle);
return q;
}
Creates a @ax-student-ar-org-papervision3d-core-math-Quaternion from Euler angles.
@param ax X-angle in radians.
@param ay Y-angle in radians.
@param az Z-angle in radians.
@return
public static function createFromEuler( ax:Number, ay:Number, az:Number, useDegrees:Boolean = false ):@ax-student-ar-org-papervision3d-core-math-Quaternion
{
if( useDegrees )
{
ax *= DEGTORAD;
ay *= DEGTORAD;
az *= DEGTORAD;
}
var fSinPitch :Number = Math.sin( ax * 0.5 );
var fCosPitch :Number = Math.cos( ax * 0.5 );
var fSinYaw :Number = Math.sin( ay * 0.5 );
var fCosYaw :Number = Math.cos( ay * 0.5 );
var fSinRoll :Number = Math.sin( az * 0.5 );
var fCosRoll :Number = Math.cos( az * 0.5 );
var fCosPitchCosYaw :Number = fCosPitch * fCosYaw;
var fSinPitchSinYaw :Number = fSinPitch * fSinYaw;
var q:@ax-student-ar-org-papervision3d-core-math-Quaternion = new @ax-student-ar-org-papervision3d-core-math-Quaternion();
q.x = fSinRoll * fCosPitchCosYaw - fCosRoll * fSinPitchSinYaw;
q.y = fCosRoll * fSinPitch * fCosYaw + fSinRoll * fCosPitch * fSinYaw;
q.z = fCosRoll * fCosPitch * fSinYaw - fSinRoll * fSinPitch * fCosYaw;
q.w = fCosRoll * fCosPitchCosYaw + fSinRoll * fSinPitchSinYaw;
return q;
}
Creates a @ax-student-ar-org-papervision3d-core-math-Quaternion from a matrix.
@param matrix a matrix.
see: org.papervision3d.core.Matrix3D
@return the created @ax-student-ar-org-papervision3d-core-math-Quaternion
public static function createFromMatrix( matrix:Matrix3D ):@ax-student-ar-org-papervision3d-core-math-Quaternion
{
var quat:@ax-student-ar-org-papervision3d-core-math-Quaternion = new @ax-student-ar-org-papervision3d-core-math-Quaternion();
var s:Number;
var q:Array = new Array(4);
var i:int, j:int, k:int;
var tr:Number = matrix.n11 + matrix.n22 + matrix.n33;
// check the diagonal
if (tr > 0.0)
{
s = Math.sqrt(tr + 1.0);
quat.w = s / 2.0;
s = 0.5 / s;
quat.x = (matrix.n32 - matrix.n23) * s;
quat.y = (matrix.n13 - matrix.n31) * s;
quat.z = (matrix.n21 - matrix.n12) * s;
}
else
{
// diagonal is negative
var nxt:Array = [1, 2, 0];
var m:Array = [
[matrix.n11, matrix.n12, matrix.n13, matrix.n14],
[matrix.n21, matrix.n22, matrix.n23, matrix.n24],
[matrix.n31, matrix.n32, matrix.n33, matrix.n34]
];
i = 0;
if (m[1][1] > m[0][0]) i = 1;
if (m[2][2] > m[i][i]) i = 2;
j = nxt[i];
k = nxt[j];
s = Math.sqrt((m[i][i] - (m[j][j] + m[k][k])) + 1.0);
q[i] = s * 0.5;
if (s != 0.0) s = 0.5 / s;
q[3] = (m[k][j] - m[j][k]) * s;
q[j] = (m[j][i] + m[i][j]) * s;
q[k] = (m[k][i] + m[i][k]) * s;
quat.x = q[0];
quat.y = q[1];
quat.z = q[2];
quat.w = q[3];
}
return quat;
}
Creates a @ax-student-ar-org-papervision3d-core-math-Quaternion from a orthonormal matrix.
@param m a orthonormal matrix.
see: org.papervision3d.core.Matrix3D
returns: the created @ax-student-ar-org-papervision3d-core-math-Quaternion
public static function createFromOrthoMatrix( m:Matrix3D ):@ax-student-ar-org-papervision3d-core-math-Quaternion
{
var q:@ax-student-ar-org-papervision3d-core-math-Quaternion = new @ax-student-ar-org-papervision3d-core-math-Quaternion();
q.w = Math.sqrt( Math.max(0, 1 + m.n11 + m.n22 + m.n33) ) / 2;
q.x = Math.sqrt( Math.max(0, 1 + m.n11 - m.n22 - m.n33) ) / 2;
q.y = Math.sqrt( Math.max(0, 1 - m.n11 + m.n22 - m.n33) ) / 2;
q.z = Math.sqrt( Math.max(0, 1 - m.n11 - m.n22 + m.n33) ) / 2;
// recover signs
q.x = m.n32 - m.n23 < 0 ? (q.x < 0 ? q.x : -q.x) : (q.x < 0 ? -q.x : q.x);
q.y = m.n13 - m.n31 < 0 ? (q.y < 0 ? q.y : -q.y) : (q.y < 0 ? -q.y : q.y);
q.z = m.n21 - m.n12 < 0 ? (q.z < 0 ? q.z : -q.z) : (q.z < 0 ? -q.z : q.z);
return q;
}
Dot product.
@param a
@param b
@return
public static function dot( a:@ax-student-ar-org-papervision3d-core-math-Quaternion, b:@ax-student-ar-org-papervision3d-core-math-Quaternion ):Number
{
return (a.x * b.x) + (a.y * b.y) + (a.z * b.z) + (a.w * b.w);
}
Multiply.
@param a
@param b
@return
public static function multiply( a:@ax-student-ar-org-papervision3d-core-math-Quaternion, b:@ax-student-ar-org-papervision3d-core-math-Quaternion ):@ax-student-ar-org-papervision3d-core-math-Quaternion
{
var c:@ax-student-ar-org-papervision3d-core-math-Quaternion = new @ax-student-ar-org-papervision3d-core-math-Quaternion();
c.x = a.w*b.x + a.x*b.w + a.y*b.z - a.z*b.y;
c.y = a.w*b.y - a.x*b.z + a.y*b.w + a.z*b.x;
c.z = a.w*b.z + a.x*b.y - a.y*b.x + a.z*b.w;
c.w = a.w*b.w - a.x*b.x - a.y*b.y - a.z*b.z;
return c;
}
Multiply by another @ax-student-ar-org-papervision3d-core-math-Quaternion.
@param b The @ax-student-ar-org-papervision3d-core-math-Quaternion to multiply by.
public function mult( b:@ax-student-ar-org-papervision3d-core-math-Quaternion ):void
{
var aw:Number = this.w,
ax:Number = this.x,
ay:Number = this.y,
az:Number = this.z;
x = aw*b.x + ax*b.w + ay*b.z - az*b.y;
y = aw*b.y - ax*b.z + ay*b.w + az*b.x;
z = aw*b.z + ax*b.y - ay*b.x + az*b.w;
w = aw*b.w - ax*b.x - ay*b.y - az*b.z;
}
public function toString():String{
return "@ax-student-ar-org-papervision3d-core-math-Quaternion: x:"+this.x+" y:"+this.y+" z:"+this.z+" w:"+this.w;
}
Normalize.
@param a
@return
public function normalize():void
{
var len:Number = this.modulo;
if( Math.abs(len) < EPSILON )
{
x = y = z = 0.0;
w = 1.0;
}
else
{
var m:Number = 1 / len;
x *= m;
y *= m;
z *= m;
w *= m;
}
}
SLERP (Spherical Linear intERPolation).
author: Trevor Burton
@param qa start quaternion
@param qb end quaternion
@param alpha a value between 0 and 1
returns: the interpolated quaternion.
public static function slerp( qa:@ax-student-ar-org-papervision3d-core-math-Quaternion, qb:@ax-student-ar-org-papervision3d-core-math-Quaternion, alpha:Number ):@ax-student-ar-org-papervision3d-core-math-Quaternion
{
var angle:Number = qa.w * qb.w + qa.x * qb.x + qa.y * qb.y + qa.z * qb.z;
if (angle < 0.0)
{
qa.x *= -1.0;
qa.y *= -1.0;
qa.z *= -1.0;
qa.w *= -1.0;
angle *= -1.0;
}
var scale:Number;
var invscale:Number;
if ((angle + 1.0) > EPSILON) // Take the shortest path
{
if ((1.0 - angle) >= EPSILON) // spherical interpolation
{
var theta:Number = Math.acos(angle);
var invsintheta:Number = 1.0 / Math.sin(theta);
scale = Math.sin(theta * (1.0-alpha)) * invsintheta;
invscale = Math.sin(theta * alpha) * invsintheta;
}
else // linear interploation
{
scale = 1.0 - alpha;
invscale = alpha;
}
}
else // long way to go...
{
qb.y = -qa.y;
qb.x = qa.x;
qb.w = -qa.w;
qb.z = qa.z;
scale = Math.sin(Math.PI * (0.5 - alpha));
invscale = Math.sin(Math.PI * alpha);
}
return new @ax-student-ar-org-papervision3d-core-math-Quaternion( scale * qa.x + invscale * qb.x,
scale * qa.y + invscale * qb.y,
scale * qa.z + invscale * qb.z,
scale * qa.w + invscale * qb.w );
}
SLERP (Spherical Linear intERPolation).
@param qa start quaternion
@param qb end quaternion
@param alpha a value between 0 and 1
returns: the interpolated quaternion.
public static function slerpOld( qa:@ax-student-ar-org-papervision3d-core-math-Quaternion, qb:@ax-student-ar-org-papervision3d-core-math-Quaternion, alpha:Number ):@ax-student-ar-org-papervision3d-core-math-Quaternion
{
var qm:@ax-student-ar-org-papervision3d-core-math-Quaternion = new @ax-student-ar-org-papervision3d-core-math-Quaternion();
// Calculate angle between them.
var cosHalfTheta:Number = qa.w * qb.w + qa.x * qb.x + qa.y * qb.y + qa.z * qb.z;
// if qa=qb or qa=-qb then theta = 0 and we can return qa
if(Math.abs(cosHalfTheta) >= 1.0)
{
qm.w = qa.w;
qm.x = qa.x;
qm.y = qa.y;
qm.z = qa.z;
return qm;
}
// Calculate temporary values.
var halfTheta:Number = Math.acos(cosHalfTheta);
var sinHalfTheta:Number = Math.sqrt(1.0 - cosHalfTheta*cosHalfTheta);
// if theta = 180 degrees then result is not fully defined
// we could rotate around any axis normal to qa or qb
if(Math.abs(sinHalfTheta) < 0.001)
{
qm.w = (qa.w * 0.5 + qb.w * 0.5);
qm.x = (qa.x * 0.5 + qb.x * 0.5);
qm.y = (qa.y * 0.5 + qb.y * 0.5);
qm.z = (qa.z * 0.5 + qb.z * 0.5);
return qm;
}
var ratioA:Number = Math.sin((1 - alpha) * halfTheta) / sinHalfTheta;
var ratioB:Number = Math.sin(alpha * halfTheta) / sinHalfTheta;
//calculate @ax-student-ar-org-papervision3d-core-math-Quaternion.
qm.w = (qa.w * ratioA + qb.w * ratioB);
qm.x = (qa.x * ratioA + qb.x * ratioB);
qm.y = (qa.y * ratioA + qb.y * ratioB);
qm.z = (qa.z * ratioA + qb.z * ratioB);
return qm;
}
public function toEuler():Number3D
{
var euler :Number3D = new Number3D();
var q1 :@ax-student-ar-org-papervision3d-core-math-Quaternion = this;
var test :Number = q1.x*q1.y + q1.z*q1.w;
if (test > 0.499) { // singularity at north pole
euler.x = 2 * Math.atan2(q1.x,q1.w);
euler.y = Math.PI/2;
euler.z = 0;
return euler;
}
if (test < -0.499) { // singularity at south pole
euler.x = -2 * Math.atan2(q1.x,q1.w);
euler.y = - Math.PI/2;
euler.z = 0;
return euler;
}
var sqx :Number = q1.x*q1.x;
var sqy :Number = q1.y*q1.y;
var sqz :Number = q1.z*q1.z;
euler.x = Math.atan2(2*q1.y*q1.w-2*q1.x*q1.z , 1 - 2*sqy - 2*sqz);
euler.y = Math.asin(2*test);
euler.z = Math.atan2(2*q1.x*q1.w-2*q1.y*q1.z , 1 - 2*sqx - 2*sqz);
return euler;
}
Gets the matrix representation of this @ax-student-ar-org-papervision3d-core-math-Quaternion.
returns: matrix. @see org.papervision3d.core.Matrix3D
public function get matrix():Matrix3D
{
var xx:Number = x * x;
var xy:Number = x * y;
var xz:Number = x * z;
var xw:Number = x * w;
var yy:Number = y * y;
var yz:Number = y * z;
var yw:Number = y * w;
var zz:Number = z * z;
var zw:Number = z * w;
_matrix.n11 = 1 - 2 * ( yy + zz );
_matrix.n12 = 2 * ( xy - zw );
_matrix.n13 = 2 * ( xz + yw );
_matrix.n21 = 2 * ( xy + zw );
_matrix.n22 = 1 - 2 * ( xx + zz );
_matrix.n23 = 2 * ( yz - xw );
_matrix.n31 = 2 * ( xz - yw );
_matrix.n32 = 2 * ( yz + xw );
_matrix.n33 = 1 - 2 * ( xx + yy );
return _matrix;
}
public static function sub(a:@ax-student-ar-org-papervision3d-core-math-Quaternion, b:@ax-student-ar-org-papervision3d-core-math-Quaternion):@ax-student-ar-org-papervision3d-core-math-Quaternion
{
return new @ax-student-ar-org-papervision3d-core-math-Quaternion(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
}
public static function add(a:@ax-student-ar-org-papervision3d-core-math-Quaternion, b:@ax-student-ar-org-papervision3d-core-math-Quaternion):@ax-student-ar-org-papervision3d-core-math-Quaternion
{
return new @ax-student-ar-org-papervision3d-core-math-Quaternion(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
}
}
}
(C) Æliens
04/09/2009
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.