All I did was change the functions a little to work with my VectorX(),Y,Z conventions, which I find a little more robust. Since these return four values, the w value is returned by the function itself. This will be rewritten as a userlib, eventually, to go with the vector3D and plane3D libs.
; Quat.bb : v1.0 : 15/11/02
; A tutorial on how to use this file is at http://www.dscho.co.uk/blitz/tutorials/quaternions.shtml
Global vectorx#,vectory#,vectorz#
Function VectorX#()
Return vectorx#
End Function
Function VectorY#()
Return vectory#
End Function
Function VectorZ#()
Return vectorz#
End Function
; Change these constants if you notice slips in accuracy
Const QuatToEulerAccuracy# = 0.001
Const QuatSlerpAccuracy# = 0.0001
;convert a Rotation to a Quat
Function EulerToQuat(pitch#,yaw#,roll#)
;NB roll is inverted due to change in handedness of coordinate systems
Local cr# = Cos(-roll/2)
Local cp# = Cos(pitch/2)
Local cy# = Cos(yaw/2)
Local sr# = Sin(-roll/2)
Local sp# = Sin(pitch/2)
Local sy# = Sin(yaw/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
;Generate the output quat
w# = cr * cpcy + sr * spsy
vectorx = sr * cpcy - cr * spsy
vectory = cr * spcy + sr * cpsy
vectorz = cr * cpsy - sr * spcy
End Function
; convert a Quat to a Rotation
Function QuatToEuler(quatx#,quaty#,quatz#,quatw#)
Local sint#, cost#, sinv#, cosv#, sinf#, cosf#
Local cost_temp#
sint = (2 * quatw * quaty) - (2 * quatx * quatz)
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 * quaty * quatz) + (2 * quatw * quatx)) / cost
cosv = (1 - (2 * quatx * quatx) - (2 * quaty * quaty)) / cost
sinf = ((2 * quatx * quaty) + (2 * quatw * quatz)) / cost
cosf = (1 - (2 * quaty * quaty) - (2 * quatz * quatz)) / cost
Else
sinv = (2 * quatw * quatx) - (2 * quaty * quatz)
cosv = 1 - (2 * quatx * quatx) - (2 * quatz * quatz)
sinf = 0
cosf = 1
EndIf
;Generate the output rotation
vectorx = -ATan2(sinv, cosv) ; inverted due to change in handedness of coordinate system
vectory = ATan2(sint, cost)
vectorz = ATan2(sinf, cosf)
End Function
;use this to interpolate between quaternions
Function QuatSlerp(Ax#,Ay#,Az#,Aw#,Bx#,By#,Bz#,Bw#,t#)
Local scaler_w#, scaler_x#, scaler_y#, scaler_z#
Local omega#, cosom#, sinom#, scale0#, scale1#
cosom = Ax * Bx + Ay * By + Az * Bz + Aw * Bw
If cosom <= 0.0
cosom = -cosom
scaler_w = -Bw
scaler_x = -Bx
scaler_y = -By
scaler_z = -Bz
Else
scaler_w = Bw
scaler_x = Bx
scaler_y = By
scaler_z = Bz
EndIf
If (1 - cosom) > QuatSlerpAccuracy
omega = ACos(cosom)
sinom = Sin(omega)
scale0 = Sin((1 - t) * omega) / sinom
scale1 = Sin(t * omega) / sinom
Else
;Angle too small: use linear interpolation instead
scale0 = 1 - t
scale1 = t
EndIf
vectorx# = scale0 * start\x + scale1 * scaler_x
vectory# = scale0 * start\y + scale1 * scaler_y
vectorz# = scale0 * start\z + scale1 * scaler_z
w# = scale0 * start\w + scale1 * scaler_w
Return w#
End Function
; result will be the same rotation as doing q1 then q2 (order matters!)
Function MultiplyQuat#(Ax#,Ay#,Az#,Aw#,Bx#,By#,Bz#,Bw#)
Local a#, b#, c#, d#, e#, f#, g#, h#
a = (Aw + Ax) * (Bw + Bx)
b = (Az - Ay) * (By - Bz)
c = (Aw - Ax) * (By + Bz)
d = (Ay + Az) * (Bw - Bx)
e = (Ax + Az) * (Bx + By)
f = (Ax - Az) * (Bx - By)
g = (Aw + Ay) * (Bw - Bz)
h = (Aw - Ay) * (Bw + Bz)
w# = b + (-e - f + g + h) / 2
vectorx# = a - ( e + f + g + h) / 2
vectory# = c + ( e - f + g - h) / 2
vectorz# = d + ( e - f - g + h) / 2
Return w#
End Function
|