#### Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

# quats

in General Posts: 490

As I adapt my legacy code to the new `quat` type, I'm experimenting with what's already implemented and what I'd like implemented. There'll probably be lots of things so I'm going to collect them in a single thread. Others are welcome to contribute.

First up, the oddity of printing:

``````print(quat(1,0,0,0))
``````

produces

``````(0,0,0,1)
``````

(or rather floats to that effect).

I get that it is more intuitive to use `.x` for the x-axis, `.y` for the y-axis, and `.z` for the z-axis, whence `.w` is the real part, but I would expect the input and output to match up.

• edited October 2017 Posts: 175

A couple of things that I'd like to see added that I mentioned in one of the beta threads.
* Rotate vec3 with multiply operator.
* A toMatrix() function

``````-- https://gamedev.stackexchange.com/questions/28395/rotating-vector3-by-a-quaternion.

function hook(base,func)
return function(...) return func(base,...) end
end

function setup()
local types = {}
types[vec3] = getmetatable(vec3())
types[quat] = quat.___class
quat.___class.__mul = hook(quat.___class.__mul,function(base,left,right)

local mt = getmetatable(right)
local result, isQuat = xpcall(function() return mt == types[quat] end,
function() end)
isQuat = result and isQuat

if isQuat then
return base(left,right)
elseif mt == types[vec3] then
local u = vec3(left.x,left.y,left.z)
local s = left.w
return 2 * u:dot(right) * u + (s*s - u:dot(u)) * right + 2 * s * right:cross(u)
end
end)
end

-- http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/geometric/orthogonal/index.htm
-- http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/
function quaternionToMatrix(q)
local x,y,z,w = q.x,q.y,q.z,q.w

local xs2 = 2*(x*x)
local ys2 = 2*(y*y)
local zs2 = 2*(z*z)

local xy2 = 2*(x*y)
local xz2 = 2*(x*z)
local yz2 = 2*(y*z)

local wx2 = 2*(w*x)
local wy2 = 2*(w*y)
local wz2 = 2*(w*z)

return matrix(
1-ys2-zs2,xy2-wz2,xz2+wy2,0,
xy2+wz2,1-xs2-zs2,yz2-wx2,0,
xz2-wy2,yz2+wx2,1-xs2-ys2,0,
0,0,0,1
)
end
``````
• Posts: 5,386

I've added these to our internal bug and feature tracker for @john to look at.

• edited October 2017 Posts: 490

My extensions to the `quat` class can be found on github as part of the Craft Coaster project.

• Arithmetic operators: `quat`s can only be multiplied, so I define addition, subtraction, more multiplication (ie including by numbers), division, and powers. Division in particular is important for `quat`, but addition and subtraction are quite useful in constructing particular `quat`s. Also defined is conjugation, both as a method and as exponentiation via a non-numerical power, eg `q^""` produces the conjugate of `q`.

• Distance and length operators: `len`, `lenSqr`, `dist`, `distSqr`, `normalize`, using several different definitions of length: normal Euclidean, spherical, the 1-norm, the sup-norm. Also a few useful bits and bobs like `is_finite`, `is_real`, `is_imaginary`.

• Application to other objects: can multiply a matrix by a quaternion (result is a matrix) both left and right, can apply a quaternion to a vec3, either via the method `applyquat` or via exponentiation: `v^q` is the application of `q` to `v`.

• In addition to the native `slerp`, there is `lerp`, `make_slerp`, and `make_lerp`. The latter two do a bit of caching to make the slerp/lerp more efficient. (lerps go linearly from one quaternion to another, but are normalised to lie on the quaternion sphere)

• There's also another way to define a quat as `quat.tangent` which is useful for converting a touch into a rotation.

• Probably more that I've forgotten, as this was originally written for the `vec4` class and I've just adapted it to `quat`.