AlignToVector()

BlitzMax Forums/BlitzMax Programming/AlignToVector()

I took the working code from MiniB3D for aligning the z axis, then I swapped the matrix rows to add correct calculation for x and y. It's pretty powerful because you can specify a roll value for any axis, and the rate/smoothing works as well.

However, this is extremely bloated and does not seem to work with scaling:
Method AlignToVector(dir:TVec3,axis=3,rate#=1.0,roll_value#=0.0)
		Local pitch#,yaw#,roll#,dist#
		Local i:TVec3,j:TVec3,k:TVec3
		dist#=Sqr(dir.x#*dir.x#+dir.z#*dir.z#)
		pitch#=ATan2(-dir.y#,dist#)
		yaw#=ATan2(-dir.x#,dir.z#)
		roll#=roll_value
		If rate=1.0
			SetRotation vec3(pitch,yaw,roll),1
		Else
			Select axis
				Case 1
					i:TVec3=mat.i()
					k:TVec3=mat.k()
					mat.kx=i.x
					mat.ky=i.y
					mat.kz=i.z
					mat.ix=k.x
					mat.iy=k.y
					mat.iz=k.z
					mat.jx:*-1.0
					mat.jy:*-1.0
					mat.jz:*-1.0
				Case 2
					j:TVec3=mat.j()
					k:TVec3=mat.k()
					mat.kx=j.x
					mat.ky=j.y
					mat.kz=j.z
					mat.jx=k.x
					mat.jy=k.y
					mat.jz=k.z
					mat.ix:*-1.0
					mat.iy:*-1.0
					mat.iz:*-1.0
			EndSelect
			quaternion=mat.rotation().slerp(vec3(pitch,yaw,roll).toquat(),rate)
			SetRotation quaternion.toeuler(),1
		EndIf
		Select axis
			Case 1
				i:TVec3=mat.i()
				k:TVec3=mat.k()
				mat.kx=i.x
				mat.ky=i.y
				mat.kz=i.z
				mat.ix=k.x
				mat.iy=k.y
				mat.iz=k.z
				mat.jx:*-1.0
				mat.jy:*-1.0
				mat.jz:*-1.0
			Case 2
				j:TVec3=mat.j()
				k:TVec3=mat.k()
				mat.kx=j.x
				mat.ky=j.y
				mat.kz=j.z
				mat.jx=k.x
				mat.jy=k.y
				mat.jz=k.z
				mat.ix:*-1.0
				mat.iy:*-1.0
				mat.iz:*-1.0
			Case 3
				Return
		EndSelect
		quaternion=TFormQuat(mat.rotation(),Null,parent)
		SetRotation quaternion.toeuler()
	EndMethod


Tried to just normaly the vectors?
Especially the higher performant vector operations depend on them and break if you try to use them on non normalized vectors.

If I just normalize the matrix at the beginning, the scale values get added back in when the rotation is performed.

This is awesome! You can align any axis, control the angle along the aligned axis, and use a rate:
	Method AlignToVector(dir:TVec3,axis=3,rate#=1.0,roll_value#=0.0)
		Local pitch#,yaw#,roll#,dist#
		Local i:TVec3,j:TVec3,k:TVec3
		Local mscale:TVec3=New TVec3
		dist#=Sqr(dir.x#*dir.x#+dir.z#*dir.z#)
		pitch#=ATan2(-dir.y#,dist#)
		yaw#=ATan2(-dir.x#,dir.z#)
		roll#=roll_value
		mat=mat.normalize()
		i=mat.i()
		j=mat.j()
		k=mat.k()
		If rate=1.0
			SetRotation vec3(pitch,yaw,roll),1
		Else
			Select axis
				Case 1
					mat.kx=i.x
					mat.ky=i.y
					mat.kz=i.z
					mat.ix=k.x
					mat.iy=k.y
					mat.iz=k.z
					mat.jx:*-1.0
					mat.jy:*-1.0
					mat.jz:*-1.0
				Case 2
					mat.kx=j.x
					mat.ky=j.y
					mat.kz=j.z
					mat.jx=k.x
					mat.jy=k.y
					mat.jz=k.z
					mat.ix:*-1.0
					mat.iy:*-1.0
					mat.iz:*-1.0
			EndSelect
			quaternion=mat.rotation().slerp(vec3(pitch,yaw,roll).toquat(),rate)
			SetRotation quaternion.toeuler(),1
		EndIf
		i=mat.i()
		j=mat.j()
		k=mat.k()
		Select axis
			Case 1
				mat.kx=i.x
				mat.ky=i.y
				mat.kz=i.z
				mat.ix=k.x
				mat.iy=k.y
				mat.iz=k.z
				mat.jx:*-1.0
				mat.jy:*-1.0
				mat.jz:*-1.0
			Case 2
				mat.kx=j.x
				mat.ky=j.y
				mat.kz=j.z
				mat.jx=k.x
				mat.jy=k.y
				mat.jz=k.z
				mat.ix:*-1.0
				mat.iy:*-1.0
				mat.iz:*-1.0
			Case 3
				Return
		EndSelect
		'Retrieve the local rotation and fill in the values:
		quaternion=TFormQuat(mat.rotation(),Null,parent)
		rotation=quaternion.toeuler()
	EndMethod