{- Quaternion.hs; Mun Hon Cheong (mhch295@cse.unsw.edu.au) 2005 This module just performs some basic converions between quaternions and matrices -} module Quaternion where import Graphics.UI.GLUT -- (GLmatrix, GLfloat, newMatrix, ColumnMajor) type Quaternion = (Float,Float,Float,Float) type Matrix3x3 = ((Float,Float,Float), (Float,Float,Float), (Float,Float,Float)) -- converts from quaternion to matrix quat2Mat :: Quaternion -> (Float,Float,Float) -> IO (GLmatrix GLfloat) quat2Mat (x,y,z,w) (t1,t2,t3)= newMatrix ColumnMajor [(r00 :: GLfloat),r01,r02,r03, r10,r11,r12,r13, r20,r21,r22,r23, r30,r31,r32,r33] where r00 = 1 - (2*((y*y)+(z*z))) r01 = 2 * ((x*y)-(w*z)) r02 = 2 * ((x*z)+(w*y)) r03 = 0 r10 = 2 * ((x*y)+(w*z)) r11 = 1 - (2*((x*x)+(z*z))) r12 = 2 * ((y*z)-(w*x)) r13 = 0 r20 = 2 * ((x*z)-(w*y)) r21 = 2 * ((y*z)+(w*x)) r22 = 1 - (2*((x*x)+(y*y))) r23 = 0 r30 = t1 r31 = t2 r32 = t3 r33 = 1 -- converts from matrix to quaternion mat2Quat :: Matrix3x3 -> Quaternion mat2Quat ((r00,r01,r02), (r10,r11,r12), (r20,r21,r22)) | diag > 0.00000001 = ((r21-r12)/scale0, (r02-r20)/scale0, (r10-r01)/scale0, 0.25*scale0) | r00 > r11 && r00 > r22 = (0.25*scale1, (r10+r01)/scale1, (r02+r20)/scale1, (r21-r12)/scale1) | r11 > r22 = ((r10+r01)/scale2, 0.25*scale2, (r21+r12)/scale2, (r02-r20)/scale2) | otherwise = ((r02+r20)/scale3, (r21+r12)/scale3, 0.25*scale3, (r10-r01)/scale3) where diag = r00+r11+r22+1 scale0 = 2*(sqrt diag) scale1 = 2*(sqrt (r00-r11-r22+1)) scale2 = 2*(sqrt (r11-r00-r22+1)) scale3 = 2*(sqrt (r22-r00-r11+1)) -- does not really perform spherical linaer interpolation -- but the difference isn't really noticeable slerp :: Quaternion -> Quaternion -> Float -> Quaternion slerp q1@(x0,y0,z0,w0) q2@(x1,y1,z1,w1) t | q1 == q2 = q1 |otherwise = ((scale0*x0)+(scale1*x1), (scale0*y0)+(scale1*y1), (scale0*z0)+(scale1*z1), (scale0*w0)+(scale1*w1)) where scale0 = 1 - t scale1 = t