182 lines
5.0 KiB
Lua
182 lines
5.0 KiB
Lua
---@class Quat
|
|
---@field x number
|
|
---@field y number
|
|
---@field z number
|
|
---@field w number
|
|
Quat = { x = 0.0, y = 0.0, z = 0.0, w = 0.0 }
|
|
Quat.__index = Quat
|
|
Quat.__name = "Quat"
|
|
|
|
--- Constructs a new Quaternion from x, y, z, and w.
|
|
---@param x number
|
|
---@param y number
|
|
---@param z number
|
|
---@param w number
|
|
---@return Quat
|
|
function Quat:new(x, y, z, w)
|
|
local q = {}
|
|
setmetatable(q, Quat)
|
|
|
|
q.x = x
|
|
q.y = y
|
|
q.z = z
|
|
q.w = w
|
|
|
|
return q
|
|
end
|
|
|
|
Quat.IDENTITY = Quat:new(0, 0, 0, 1)
|
|
|
|
function Quat:clone()
|
|
return Quat:new(self.x, self.y, self.z, self.w)
|
|
end
|
|
|
|
--- Creates a quaternion from the angle, in radians, around the x axis.
|
|
--- @param rad number
|
|
--- @return Quat
|
|
function Quat:from_rotation_x(rad)
|
|
local sin = math.sin(rad * 0.5)
|
|
local cos = math.cos(rad * 0.5)
|
|
return Quat:new(sin, 0, 0, cos)
|
|
end
|
|
|
|
--- Creates a quaternion from the angle, in radians, around the y axis.
|
|
--- @param rad number
|
|
--- @return Quat
|
|
function Quat:from_rotation_y(rad)
|
|
local sin = math.sin(rad * 0.5)
|
|
local cos = math.cos(rad * 0.5)
|
|
return Quat:new(0, sin, 0, cos)
|
|
end
|
|
|
|
--- Creates a quaternion from the angle, in radians, around the z axis.
|
|
--- @param rad number
|
|
--- @return Quat
|
|
function Quat:from_rotation_z(rad)
|
|
local sin = math.sin(rad * 0.5)
|
|
local cos = math.cos(rad * 0.5)
|
|
return Quat:new(0, 0, sin, cos)
|
|
end
|
|
|
|
--- Computes the dot product of `self`.
|
|
---@param rhs Quat
|
|
---@return number
|
|
function Quat:dot(rhs)
|
|
return (self.x * rhs.x) + (self.y * rhs.y) + (self.z * rhs.z) + (self.w * rhs.w)
|
|
end
|
|
|
|
--- Computes the length of `self`.
|
|
---@return number
|
|
function Quat:length()
|
|
return math.sqrt(self:dot(self))
|
|
end
|
|
|
|
--- Compute the length of `self` squared.
|
|
---@return number
|
|
function Quat:length_squared()
|
|
return self:length() ^ 2
|
|
end
|
|
|
|
--- Normalizes `self` and returns the new Quat
|
|
---@return unknown
|
|
function Quat:normalize()
|
|
local length = self:length()
|
|
return self / length
|
|
end
|
|
|
|
--- Multiplies two Quaternions together. Keep in mind that Quaternion multiplication is NOT
|
|
--- commutative so the order in which you multiply the quaternions matters.
|
|
---@param rhs Quat
|
|
---@return Quat
|
|
function Quat:mult_quat(rhs)
|
|
local x1, y1, z1, w1 = self.x, self.y, self.z, self.w
|
|
local x2, y2, z2, w2 = rhs.x, rhs.y, rhs.z, rhs.w
|
|
|
|
local x = w1 * x2 + x1 * w2 + y1 * z2 - z1 * y2
|
|
local y = w1 * y2 - x1 * z2 + y1 * w2 + z1 * x2
|
|
local z = w1 * z2 + x1 * y2 - y1 * x2 + z1 * w2
|
|
local w = w1 * w2 - x1 * x2 - y1 * y2 - z1 * x2
|
|
|
|
return Quat:new(x, y, z, w)
|
|
end
|
|
|
|
--- Multiplies `self` by a Vec3, returning the rotated Vec3
|
|
---@param vec Vec3
|
|
---@return Vec3
|
|
function Quat:mult_vec3(vec)
|
|
local vec_quat = Quat:new(vec.x, vec.y, vec.z, 0)
|
|
local quat = self:mult_quat(vec_quat)
|
|
return Vec3:new(quat.x, quat.y, quat.z)
|
|
end
|
|
|
|
--- Calculates the linear iterpolation between `self` and `rhs` based on the `alpha`.
|
|
--- When `alpha` is `0`, the result will be equal to `self`. When `s` is `1`, the result
|
|
--- will be equal to `rhs`
|
|
--- @param rhs Quat
|
|
--- @param alpha number
|
|
--- @return Quat
|
|
function Quat:lerp(rhs, alpha)
|
|
-- ensure alpha is [0, 1]
|
|
local alpha = math.max(0, math.min(1, alpha))
|
|
|
|
local x1, y1, z1, w1 = self.x, self.y, self.z, self.w
|
|
local x2, y2, z2, w2 = rhs.x, rhs.y, rhs.z, rhs.w
|
|
|
|
local x = (1 - alpha) * x1 + alpha * x2
|
|
local y = (1 - alpha) * y1 + alpha * y2
|
|
local z = (1 - alpha) * z1 + alpha * z2
|
|
local w = (1 - alpha) * w1 + alpha * w2
|
|
|
|
return Quat:new(x, y, z, w):normalize()
|
|
end
|
|
|
|
function Quat:__add(rhs)
|
|
return Quat:new(self.x + rhs.x, self.y + rhs.y, self.z + rhs.z, self.w + rhs.w)
|
|
end
|
|
|
|
function Quat:__sub(rhs)
|
|
return Quat:new(self.x - rhs.x, self.y - rhs.y, self.z - rhs.z, self.w - rhs.w)
|
|
end
|
|
|
|
function Quat:__mul(rhs)
|
|
if type(rhs) == "number" then
|
|
return Quat:new(self.x * rhs, self.y * rhs, self.z * rhs, self.w * rhs)
|
|
elseif type(rhs) == "table" then
|
|
local name = rhs.__name
|
|
|
|
if name == "Vec3" then
|
|
return self:mult_vec3(rhs)
|
|
elseif name == "Quat" then
|
|
return self:mult_quat(rhs)
|
|
else
|
|
assert(false, "Unknown usertype of rhs" .. name)
|
|
end
|
|
else
|
|
assert(false, "Unknown type of rhs" .. type(rhs))
|
|
end
|
|
end
|
|
|
|
function Quat:__div(rhs)
|
|
if type(rhs) == "number" then
|
|
return Quat:new(self.x / rhs, self.y / rhs, self.z / rhs, self.w / rhs)
|
|
else
|
|
assert(rhs.__name == "Quat", "Attempted to divide Quat by unknown type " .. rhs.__name)
|
|
return Quat:new(self.x / rhs.x, self.y / rhs.y, self.z / rhs.z, self.w / rhs.w)
|
|
end
|
|
end
|
|
|
|
function Quat:__eq(rhs)
|
|
return self.x == rhs.x and self.y == rhs.y and self.z == rhs.z and self.w == rhs.w
|
|
end
|
|
|
|
function Quat:__lt(rhs)
|
|
return self.x < rhs.x and self.y < rhs.y and self.z < rhs.z and self.w < rhs.w
|
|
end
|
|
|
|
function Quat:__le(rhs)
|
|
return self.x <= rhs.x and self.y <= rhs.y and self.z <= rhs.z and self.w <= rhs.w
|
|
end
|
|
|
|
function Quat:__tostring()
|
|
return "Quat(" .. self.x .. ", " .. self.y .. ", " .. self.z .. ", " .. self.w .. ")"
|
|
end |