import { IClone } from "./IClone" ; import { MathUtil } from "./MathUtil" ; import { Matrix3x3 } from "./Matrix3x3" ; import { Vector3 } from "./Vector3" ; /**
 * Represents a four dimensional mathematical quaternion.
 */ export class Quaternion implements IClone { internal static readonly _tempVector3 = new Vector3 ( ) ; internal static readonly _tempQuat1 = new Quaternion ( ) ; param left param right param out static add ( left , right , out ) { out . x = left . x + right . x ; out . y = left . y + right . y ; out . z = left . z + right . z ; out . w = left . w + right . w ; } param left param right param out static multiply ( left , right , out ) { const ax = left . x , ay = left . y , az = left . z , aw = left . w ; const bx = right . x , by = right . y , bz = right . z , bw = right . w ; out . x = ax * bw + aw * bx + ay * bz - az * by ; out . y = ay * bw + aw * by + az * bx - ax * bz ; out . z = az * bw + aw * bz + ax * by - ay * bx ; out . w = aw * bw - ax * bx - ay * by - az * bz ; } param a param out static conjugate ( a , out ) { out . x = - a . x ; out . y = - a . y ; out . z = - a . z ; out . w = a . w ; } param left param right returns static dot ( left , right ) { return left . x * right . x + left . y * right . y + left . z * right . z + left . w * right . w ; } param left param right returns static equals ( left , right ) { return ( MathUtil . equals ( left . x , right . x ) && MathUtil . equals ( left . y , right . y ) && MathUtil . equals ( left . z , right . z ) && MathUtil . equals ( left . w , right . w ) ) ; } param axis param rad param out static rotationAxisAngle ( axis , rad , out ) { const normalAxis = Quaternion . _tempVector3 ; Vector3 . normalize ( axis , normalAxis ) ; rad *= 0.5 ; const s = Math . sin ( rad ) ; out . x = normalAxis . x * s ; out . y = normalAxis . y * s ; out . z = normalAxis . z * s ; out . w = Math . cos ( rad ) ; } param x param y param z param out static rotationEuler ( x , y , z , out ) { Quaternion . rotationYawPitchRoll ( y , x , z , out ) ; } param yaw param pitch param roll param out static rotationYawPitchRoll ( yaw , pitch , roll , out ) { const halfRoll = roll * 0.5 ; const halfPitch = pitch * 0.5 ; const halfYaw = yaw * 0.5 ; const sinRoll = Math . sin ( halfRoll ) ; const cosRoll = Math . cos ( halfRoll ) ; const sinPitch = Math . sin ( halfPitch ) ; const cosPitch = Math . cos ( halfPitch ) ; const sinYaw = Math . sin ( halfYaw ) ; const cosYaw = Math . cos ( halfYaw ) ; const cosYawPitch = cosYaw * cosPitch ; const sinYawPitch = sinYaw * sinPitch ; out . x = cosYaw * sinPitch * cosRoll + sinYaw * cosPitch * sinRoll ; out . y = sinYaw * cosPitch * cosRoll - cosYaw * sinPitch * sinRoll ; out . z = cosYawPitch * sinRoll - sinYawPitch * cosRoll ; out . w = cosYawPitch * cosRoll + sinYawPitch * sinRoll ; } param m param out static rotationMatrix3x3 ( m , out ) { const me = m . elements ; const m11 = me [ 0 ] , m12 = me [ 1 ] , m13 = me [ 2 ] ; const m21 = me [ 3 ] , m22 = me [ 4 ] , m23 = me [ 5 ] ; const m31 = me [ 6 ] , m32 = me [ 7 ] , m33 = me [ 8 ] ; const scale = m11 + m22 + m33 ; let sqrt , half ; if ( scale > 0 ) { sqrt = Math . sqrt ( scale + 1.0 ) ; out . w = sqrt * 0.5 ; sqrt = 0.5 / sqrt ; out . x = ( m23 - m32 ) * sqrt ; out . y = ( m31 - m13 ) * sqrt ; out . z = ( m12 - m21 ) * sqrt ; } else if ( m11 >= m22 && m11 >= m33 ) { sqrt = Math . sqrt ( 1.0 + m11 - m22 - m33 ) ; half = 0.5 / sqrt ; out . x = 0.5 * sqrt ; out . y = ( m12 + m21 ) * half ; out . z = ( m13 + m31 ) * half ; out . w = ( m23 - m32 ) * half ; } else if ( m22 > m33 ) { sqrt = Math . sqrt ( 1.0 + m22 - m11 - m33 ) ; half = 0.5 / sqrt ; out . x = ( m21 + m12 ) * half ; out . y = 0.5 * sqrt ; out . z = ( m32 + m23 ) * half ; out . w = ( m31 - m13 ) * half ; } else { sqrt = Math . sqrt ( 1.0 + m33 - m11 - m22 ) ; half = 0.5 / sqrt ; out . x = ( m13 + m31 ) * half ; out . y = ( m23 + m32 ) * half ; out . z = 0.5 * sqrt ; out . w = ( m12 - m21 ) * half ; } } param a param out static invert ( a , out ) { const { x , y , z , w } = a ; const dot = x * x + y * y + z * z + w * w ; if ( dot > MathUtil . zeroTolerance ) { const invDot = 1.0 / dot ; out . x = - x * invDot ; out . y = - y * invDot ; out . z = - z * invDot ; out . w = w * invDot ; } } param start param end param t param out static lerp ( start , end , t , out ) { const inv = 1.0 - t ; if ( Quaternion . dot ( start , end ) >= 0 ) { out . x = start . x * inv + end . x * t ; out . y = start . y * inv + end . y * t ; out . z = start . z * inv + end . z * t ; out . w = start . w * inv + end . w * t ; } else { out . x = start . x * inv - end . x * t ; out . y = start . y * inv - end . y * t ; out . z = start . z * inv - end . z * t ; out . w = start . w * inv - end . w * t ; } out . normalize ( ) ; } param start param end param t param out static slerp ( start , end , t , out ) { const ax = start . x ; const ay = start . y ; const az = start . z ; const aw = start . w ; let bx = end . x ; let by = end . y ; let bz = end . z ; let bw = end . w ; let scale0 , scale1 ; let cosom = ax * bx + ay * by + az * bz + aw * bw ; if ( cosom < 0.0 ) { cosom = - cosom ; bx = - bx ; by = - by ; bz = - bz ; bw = - bw ; } if ( 1.0 - cosom > MathUtil . zeroTolerance ) { const omega = Math . acos ( cosom ) ; const sinom = Math . sin ( omega ) ; scale0 = Math . sin ( ( 1.0 - t ) * omega ) / sinom ; scale1 = Math . sin ( t * omega ) / sinom ; } else { scale0 = 1.0 - t ; scale1 = t ; } out . x = scale0 * ax + scale1 * bx ; out . y = scale0 * ay + scale1 * by ; out . z = scale0 * az + scale1 * bz ; out . w = scale0 * aw + scale1 * bw ; } param a param out static normalize ( a , out ) { const { x , y , z , w } = a ; let len = Math . sqrt ( x * x + y * y + z * z + w * w ) ; if ( len > MathUtil . zeroTolerance ) { len = 1 / len ; out . x = x * len ; out . y = y * len ; out . z = z * len ; out . w = w * len ; } } param rad param out static rotationX ( rad , out ) { rad *= 0.5 ; const s = Math . sin ( rad ) ; const c = Math . cos ( rad ) ; out . x = s ; out . y = 0 ; out . z = 0 ; out . w = c ; } param rad param out static rotationY ( rad , out ) { rad *= 0.5 ; const s = Math . sin ( rad ) ; const c = Math . cos ( rad ) ; out . x = 0 ; out . y = s ; out . z = 0 ; out . w = c ; } param rad param out static rotationZ ( rad , out ) { rad *= 0.5 ; const s = Math . sin ( rad ) ; const c = Math . cos ( rad ) ; out . x = 0 ; out . y = 0 ; out . z = s ; out . w = c ; } param quaternion param rad param out static rotateX ( quaternion , rad , out ) { const { x , y , z , w } = quaternion ; rad *= 0.5 ; const bx = Math . sin ( rad ) ; const bw = Math . cos ( rad ) ; out . x = x * bw + w * bx ; out . y = y * bw + z * bx ; out . z = z * bw - y * bx ; out . w = w * bw - x * bx ; } param quaternion param rad param out static rotateY ( quaternion , rad , out ) { const { x , y , z , w } = quaternion ; rad *= 0.5 ; const by = Math . sin ( rad ) ; const bw = Math . cos ( rad ) ; out . x = x * bw - z * by ; out . y = y * bw + w * by ; out . z = z * bw + x * by ; out . w = w * bw - y * by ; } param quaternion param rad param out static rotateZ ( quaternion , rad , out ) { const { x , y , z , w } = quaternion ; rad *= 0.5 ; const bz = Math . sin ( rad ) ; const bw = Math . cos ( rad ) ; out . x = x * bw + y * bz ; out . y = y * bw - x * bz ; out . z = z * bw + w * bz ; out . w = w * bw - z * bz ; } param a param s param out static scale ( a , s , out ) { out . x = a . x * s ; out . y = a . y * s ; out . z = a . z * s ; out . w = a . w * s ; } /** The x component of the quaternion. */ x : number ; /** The y component of the quaternion. */ y : number ; /** The z component of the quaternion. */ z : number ; /** The w component of the quaternion. */ w : number ; param x param y param z param w constructor ( x = 0 , y = 0 , z = 0 , w = 1 ) { this . x = x ; this . y = y ; this . z = z ; this . w = w ; } param x param y param z param w returns setValue ( x , y , z , w ) { this . x = x ; this . y = y ; this . z = z ; this . w = w ; return this ; } param array param offset returns setValueByArray ( array , offset = 0 ) { this . x = array [ offset ] ; this . y = array [ offset + 1 ] ; this . z = array [ offset + 2 ] ; this . w = array [ offset + 3 ] ; return this ; } returns conjugate ( ) { this . x *= - 1 ; this . y *= - 1 ; this . z *= - 1 ; return this ; } param out returns getAxisAngle ( out ) { const { x , y , z } = this ; const length = x * x + y * y + z * z ; if ( length < MathUtil . zeroTolerance ) { out . x = 1 ; out . y = 0 ; out . z = 0 ; return 0 ; } else { const inv = 1.0 / length ; out . x = this . x * inv ; out . y = this . y * inv ; out . z = this . z * inv ; return Math . acos ( this . w ) * 2.0 ; } } returns identity ( ) { this . x = 0 ; this . y = 0 ; this . z = 0 ; this . w = 1 ; return this ; } returns length ( ) { const { x , y , z , w } = this ; return Math . sqrt ( x * x + y * y + z * z + w * w ) ; } returns lengthSquared ( ) { const { x , y , z , w } = this ; return x * x + y * y + z * z + w * w ; } returns normalize ( ) { Quaternion . normalize ( this , this ) ; return this ; } param out returns toEuler ( out ) { this . toYawPitchRoll ( out ) ; const t = out . x ; out . x = out . y ; out . y = t ; return out ; } param out returns toYawPitchRoll ( out ) { const { x , y , z , w } = this ; const xx = x * x ; const yy = y * y ; const zz = z * z ; const xy = x * y ; const zw = z * w ; const zx = z * x ; const yw = y * w ; const yz = y * z ; const xw = x * w ; out . y = Math . asin ( 2.0 * ( xw - yz ) ) ; if ( Math . cos ( out . y ) > MathUtil . zeroTolerance ) { out . z = Math . atan2 ( 2.0 * ( xy + zw ) , 1.0 - 2.0 * ( zz + xx ) ) ; out . x = Math . atan2 ( 2.0 * ( zx + yw ) , 1.0 - 2.0 * ( yy + xx ) ) ; } else { out . z = Math . atan2 ( - 2.0 * ( xy - zw ) , 1.0 - 2.0 * ( yy + zz ) ) ; out . x = 0.0 ; } return out ; } param out param outOffset toArray ( out , outOffset = 0 ) { out [ outOffset ] = this . x ; out [ outOffset + 1 ] = this . y ; out [ outOffset + 2 ] = this . z ; out [ outOffset + 3 ] = this . w ; } returns clone ( ) { return new Quaternion ( this . x , this . y , this . z , this . w ) ; } param out returns cloneTo ( out ) { out . x = this . x ; out . y = this . y ; out . z = this . z ; out . w = this . w ; return out ; } param rad returns rotateX ( rad ) { Quaternion . rotateX ( this , rad , this ) ; return this ; } param rad returns rotateY ( rad ) { Quaternion . rotateY ( this , rad , this ) ; return this ; } param rad returns rotateZ ( rad ) { Quaternion . rotateZ ( this , rad , this ) ; return this ; } param axis param rad returns rotationAxisAngle ( axis , rad ) { Quaternion . rotationAxisAngle ( axis , rad , this ) ; return this ; } param quat returns multiply ( quat ) { Quaternion . multiply ( this , quat , this ) ; return this ; } returns invert ( ) { Quaternion . invert ( this , this ) ; return this ; } param quat returns dot ( quat ) { return Quaternion . dot ( this , quat ) ; } param quat param t returns lerp ( quat , t ) { Quaternion . lerp ( this , quat , t , this ) ; return this ; } param axis param rad returns rotateAxisAngle ( axis , rad ) { Quaternion . _tempQuat1 . rotationAxisAngle ( axis , rad ) ; this . multiply ( Quaternion . _tempQuat1 ) ; return this ; } }