some more quat routines

BlitzMax Modules Forums/MiniB3D/some more quat routines

The forum is locked. These are the original blitzbasic.com forums, kept so they can still be read. No new topics, replies or edits can be made here. To join in, head over to the Blitz3D+ forums.

I notice that my old quat type has a few more utility functions

If anyone maintaining minib3d wants to use them feel free, they will need a *slight* adaptation as i was using a flat matrix [0..15] instead of [0..3,0..3]

it has the following methods

FromMatrix
ToMatrix
Normalise
FromAxisAngle
Multiply
GetEuler
Copy
FromEuler
Set
Invert

Type TQuat

	Field x!,y!,z!,w!

	Method FromMatrix(mat:Double[])

		Local T:Float= 1 + mat[0] + mat[5] + mat[10]

		Local S:Float

		If ( T > 0.00000001 ) Then

			S = Sqr(T) * 2

      		X = ( mat[6] - mat[9] ) / S

      		Y = ( mat[8] - mat[2] ) / S

      		Z = ( mat[1] - mat[4] ) / S

      		W = 0.25 * S

			Return

		EndIf

		

		If mat[0] > mat[5] And mat[0] > mat[10] Then	'Column 0: 

        	S  = Sqr( 1.0 + mat[0] - mat[5] - mat[10] ) * 2

        	X = 0.25 * S

        	Y = (mat[1] + mat[4] ) / S

        	Z = (mat[8] + mat[2] ) / S

        	W = (mat[6] - mat[9] ) / S

		ElseIf mat[5] > mat[10]							'Column 1: 

	        S  = Sqr( 1.0 + mat[5] - mat[0] - mat[10] ) * 2

	        X = (mat[1] + mat[4] ) / S

	        Y = 0.25 * S

	        Z = (mat[6] + mat[9] ) / S

	        W = (mat[8] - mat[2] ) / S

		Else											'Column 2:

	        S  = Sqr( 1.0 + mat[10] - mat[0] - mat[5] ) * 2

	        X = (mat[8] + mat[2] ) / S

	        Y = (mat[6] + mat[9] ) / S

	        Z = 0.25 * S

	        W = (mat[1] - mat[4] ) / S

    	EndIf



	EndMethod

	

	Method ToMatrix:Double[]()

		Local xx!=x*x

		Local xy!=x*y

		Local xz!=x*z

		Local xw!=x*w

		

		Local yy!=y*y

		Local yz!=y*z

		Local yw!=y*w

		

		Local zz!=z*z

		Local zw!=z*w

		

		Local m:Double[16]

		m[0]= 1-2*(yy+zz)

		m[4]=   2*(xy-zw)

		m[8]=   2*(xz+yw)

		

		m[1]=   2*(xy+zw)

		m[5]= 1-2*(xx+zz)

		m[9]=   2*(yz-xw)

		

		m[2]=   2*(xz-yw)

		m[6]=   2*(yz+xw)

		m[10]=1-2*(xx+yy)

		

		m[12]=0;m[13]=0;m[14]=0

		m[3]=0;m[7]=0;m[11]=0

		m[15]=1

		

		Return m

		

	EndMethod

	

	Method Normalise()

		Local m:Double

		m=Sqr(w*w+x*x+y*y+z*z)

		If m=1 Then Return ' is exactly 1 more often than you'd think...

		w:/m

		x:/m

		y:/m

		z:/m

	EndMethod

	

	Method FromAxisAngle(a!,axis:TVec3)

		Local sin_a! = Sin( a / 2 )

    	Local cos_a! = Cos( a / 2 )



    	X    = axis.x * sin_a

    	Y    = axis.y * sin_a

    	Z    = axis.z * sin_a

    	W    = cos_a



	    Normalise()

		Return

	EndMethod



	

	Method Multiply:TQuat(q:TQuat)

		Local a#, b#, c#, d#, e#, f#, g#, h#



		a = (w + x) * (q.w + q.x)

		b = (z - y) * (q.y - q.z)

		c = (w - x) * (q.y + q.z)

		d = (y + z) * (q.w - q.x)

		e = (x + z) * (q.x + q.y)

		f = (x - z) * (q.x - q.y)

		g = (w + y) * (q.w - q.z)

		h = (w - y) * (q.w + q.z)

		

		w = b + (-e - f + g + h) / 2

		x = a - ( e + f + g + h) / 2

		y = c + ( e - f + g - h) / 2

		z = d + ( e - f - g + h) / 2

		

	End Method

	

	

	Const QuatToEulerAccuracy# = 0.000000000001

		

	Method GetEuler:TVec3()		' using vec3 to hold eulers

		Local sint!, cost!, sinv!, cosv!, sinf!, cosf!

		Local cost_temp!

		normalise()

		sint = (2 * w * y) - (2 * x * z)

		cost_temp = 1.0 - (sint * sint)



		If Abs(cost_temp) > QuatToEulerAccuracy

			cost = Sqr(cost_temp)

		Else

			cost = 0

		EndIf



		If Abs(cost) > QuatToEulerAccuracy

			sinv = ((2 * y * z) + (2 * w * x)) / cost

			cosv = (1 - (2 * x * x) - (2 * y * y)) / cost

			sinf = ((2 * x * y) + (2 * w * z)) / cost

			cosf = (1 - (2 * y * y) - (2 * z * z)) / cost

		Else

			sinv = (2 * w * x) - (2 * y * z)

			cosv = 1 - (2 * x * x) - (2 * z * z)

			sinf = 0

			cosf = 1

		EndIf

	

		Local out:TVec3=New Tvec3		

		out.x = ATan2(sinv, cosv)

		out.y = ATan2(sint, cost)

		out.z = ATan2(sinf, cosf)

'		out.x=bound(out.x)

'		out.y=bound(out.y)

'		out.z=bound(out.z)

			

		Return out



	EndMethod

	

	Method Copy(q:TQuat)

		w=q.w

		x=q.x

		y=q.y

		z=q.z

	EndMethod

	

	

	Method FromEuler(src:TVec3)

	

		Local cr! = Cos(src.x/2)

		Local cp! = Cos(src.y/2)

		Local cy! = Cos(src.z/2)

	

		Local sr! = Sin(src.x/2)

		Local sp! = Sin(src.y/2)

		Local sy! = Sin(src.z/2)

	

		'; These variables are only here To cut down on the number of multiplications

		Local cpcy! = cp * cy

		Local spsy! = sp * sy

		Local spcy! = sp * cy

		Local cpsy! = cp * sy

	

		w = cr * cpcy + sr * spsy

		x = sr * cpcy - cr * spsy

		y = cr * spcy + sr * cpsy

		z = cr * cpsy - sr * spcy

		normalise()

	EndMethod

	

	Method Set(nw!,nx!,ny!,nz!)

		w=nw;x=nx;y=ny;z=nz

	EndMethod

	

	Method Invert()

		x=-x;y=-y;z=-z

	EndMethod 

EndType