Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // https://github.com/codewithnnamdi/vacuum
- // vacuum-1.lua - A numerica computation library for building games.
- // TODO:handle inputs as well
- local matrix = {}
- function matrix:new(n,m)
- -- Create a new matrix
- local matt = {}
- for i = 1, n do
- matt[i] = {}
- for j = 1, m do
- matt[i][j] = 0
- end
- end
- setmetatable(matt, self)
- self.__index = self
- return matt
- end
- function matrix:__tostring()
- -- Print a matrix
- local str = ""
- for i = 1, #self do
- for j = 1, #self[i] do
- str = str .. self[i][j] .. " "
- end
- str = str .. "" .. "" .. ""
- end
- return str
- end
- function matrix:__add(other)
- -- Add two matrices
- local matt = matrix:new(#self, #self[1])
- for i = 1, #self do
- for j = 1, #self[i] do
- matt[i][j] = self[i][j] + other[i][j]
- end
- end
- return matt
- end
- function matrix:__sub(other)
- -- Subtract two matrices
- local matt = matrix:new(#self, #self[1])
- for i = 1, #self do
- for j = 1, #self[i] do
- matt[i][j] = self[i][j] - other[i][j]
- end
- end
- return matt
- end
- function matrix:__mul(other)
- -- Multiply two matrices
- local matt = matrix:new(#self, #self[1])
- for i = 1, #self do
- for j = 1, #self[i] do
- matt[i][j] = self[i][j] * other[i][j]
- end
- end
- return matt
- end
- function matrix:__div(other)
- -- Divide two matrices
- local matt = matrix:new(#self, #self[1])
- for i = 1, #self do
- for j = 1, #self[i] do
- matt[i][j] = self[i][j] / other[i][j]
- end
- end
- return matt
- end
- function matrix:__unm()
- -- Unary minus
- local matt = matrix:new(#self, #self[1])
- for i = 1, #self do
- for j = 1, #self[i] do
- matt[i][j] = -self[i][j]
- end
- end
- return matt
- end
- function matrix:__eq(other)
- -- Check if two matrices are equal
- for i = 1, #self do
- for j = 1, #self[i] do
- if self[i][j] ~= other[i][j] then
- return false
- end
- end
- end
- return true
- end
- function matrix:__lt(other)
- -- Check if one matrix is less than another
- for i = 1, #self do
- for j = 1, #self[i] do
- if self[i][j] >= other[i][j] then
- return false
- end
- end
- end
- return true
- end
- function matrix:__le(other)
- -- Check if one matrix is less than or equal to another
- for i = 1, #self do
- for j = 1, #self[i] do
- if self[i][j] > other[i][j] then
- return false
- end
- end
- end
- return true
- end
- function matrix:__pow(other)
- -- Raise a matrix to a power
- local matt = matrix:new(#self, #self[1])
- for i = 1, #self do
- for j = 1, #self[i] do
- matt[i][j] = self[i][j] ^ other[i][j]
- end
- end
- return matt
- end
- function matrix:__mod(other)
- -- Modulo a matrix
- local matt = matrix:new(#self, #self[1])
- for i = 1, #self do
- for j = 1, #self[i] do
- matt[i][j] = self[i][j] % other[i][j]
- end
- end
- return matt
- end
- function matrix:__concat(other)
- -- Concatenate two matrices
- local matt = matrix:new(#self, #self[1])
- for i = 1, #self do
- for j = 1, #self[i] do
- matt[i][j] = self[i][j] .. other[i][j]
- end
- end
- return matt
- end
- function matrix:__len()
- -- Get the length of a matrix
- return #self * #self[1]
- end
- function matrix:__call(...)
- -- Call a matrix
- local matt = matrix:new(#self, #self[1])
- for i = 1, #self do
- for j = 1, #self[i] do
- matt[i][j] = self[i][j](...)
- end
- end
- return matt
- end
- function matrix:__index(key)
- -- Get a matrix element
- return self[key[1]][key[2]]
- end
- function matrix:__newindex(key, value)
- -- Set a matrix element
- self[key[1]][key[2]] = value
- end
- function matrix:__pairs()
- -- Iterate over a matrix
- local i = 0
- local j = 0
- return function()
- i = i + 1
- if i > #self then
- i = 1
- j = j + 1
- end
- if j > #self[1] then
- return nil
- end
- return {i, j}, self[i][j]
- end
- end
- local vec2 = {}
- function vec2:new(x, y)
- local o = {x = x or 0, y = y or 0}
- setmetatable(o, self)
- self.__index = self
- return o
- end
- function vec2:__tostring()
- return "(" .. self.x .. ", " .. self.y .. ")"
- end
- function vec2:__add(other)
- return vec2:new(self.x + other.x, self.y + other.y)
- end
- function vec2:__sub(other)
- return vec2:new(self.x - other.x, self.y - other.y)
- end
- function vec2:__mul(other)
- return vec2:new(self.x * other, self.y * other)
- end
- function vec2:__div(other)
- return vec2:new(self.x / other, self.y / other)
- end
- -- unary minus
- function vec2:__unm()
- return vec2:new(-self.x, -self.y)
- end
- function vec2:__eq(other)
- return self.x == other.x and self.y == other.y
- end
- function vec2:__lt(other)
- return self.x < other.x and self.y < other.y
- end
- function vec2:__le(other)
- return self.x <= other.x and self.y <= other.y
- end
- function vec2:__len()
- return math.sqrt(self.x * self.x + self.y * self.y)
- end
- function vec2:__call(x, y)
- self.x = x
- self.y = y
- end
- function vec2:clone()
- return vec2:new(self.x, self.y)
- end
- function vec2:unpack()
- return self.x, self.y
- end
- function vec2:rotate(angle)
- local c = math.cos(angle)
- local s = math.sin(angle)
- self.x, self.y = self.x * c - self.y * s, self.x * s + self.y * c
- end
- function vec2:normalized()
- local len = #self
- return vec2:new(self.x / len, self.y / len)
- end
- function vec2:normalize_inplace()
- local len = #self
- self.x = self.x / len
- self.y = self.y / len
- end
- function vec2:perpendicular()
- return vec2:new(-self.y, self.x)
- end
- function vec2:dot(other)
- return self.x * other.x + self.y * other.y
- end
- function vec2:cross(other)
- return self.x * other.y - self.y * other.x
- end
- function vec2:project_on(other)
- local k = self:dot(other) / other:dot(other)
- return vec2:new(other.x * k, other.y * k)
- end
- local vec3 = {}
- function vec3:new(x, y, z)
- local o = {x = x or 0, y = y or 0, z = z or 0}
- setmetatable(o, self)
- self.__index = self
- return o
- end
- function vec3:__tostring()
- return "(" .. self.x .. ", " .. self.y .. ", " .. self.z .. ")"
- end
- function vec3:__add(other)
- return vec3:new(self.x + other.x, self.y + other.y, self.z + other.z)
- end
- function vec3:__sub(other)
- return vec3:new(self.x - other.x, self.y - other.y, self.z - other.z)
- end
- function vec3:__mul(other)
- return vec3:new(self.x * other, self.y * other, self.z * other)
- end
- function vec3:__div(other)
- return vec3:new(self.x / other, self.y / other, self.z / other)
- end
- -- unary minus
- function vec3:__unm()
- return vec3:new(-self.x, -self.y, -self.z)
- end
- function vec3:__eq(other)
- return self.x == other.x and self.y == other.y and self.z == other.z
- end
- function vec3:__lt(other)
- return self.x < other.x and self.y < other.y and self.z < other.z
- end
- -- less than or equal
- function vec3:__le(other)
- return self.x <= other.x and self.y <= other.y and self.z <= other.z
- end
- function vec3:__len()
- return math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z)
- end
- function vec3:__call(x, y, z)
- self.x = x
- self.y = y
- self.z = z
- end
- function vec3:clone()
- return vec3:new(self.x, self.y, self.z)
- end
- function vec3:unpack()
- return self.x, self.y, self.z
- end
- function vec3:rotatex(theta)
- local c = math.cos(theta)
- local s = math.sin(theta)
- self.y, self.z = self.y * c - self.z * s, self.y * s + self.z * c
- end
- function vec3:rotatey(theta)
- local c = math.cos(theta)
- local s = math.sin(theta)
- self.x, self.z = self.x * c - self.z * s, self.x * s + self.z * c
- end
- function vec3:rotatez(theta)
- local c = math.cos(theta)
- local s = math.sin(theta)
- self.x, self.y = self.x * c - self.y * s, self.x * s + self.y * c
- end
- function vec3:normalized()
- local len = #self
- return vec3:new(self.x / len, self.y / len, self.z / len)
- end
- function vec3:normalize_inplace()
- local len = #self
- self.x = self.x / len
- self.y = self.y / len
- self.z = self.z / len
- end
- local vec4 = {}
- function vec4:new(x, y, z, w)
- -- use a vec3 as a base
- local o = vec3:new(x, y, z)
- o.w = w or 0
- setmetatable(o, self)
- self.__index = self
- return o
- end
- local vector = { vec2 = vec2, vec3 = vec3, vec4 = vec4 }
- local mt = {
- -- abstract call method in a metatable
- __call = function(_, ...)
- local n = select("#", ...)
- return vmt[n](...)
- end
- }
- setmetatable(vector, mt)
- return vector
- -- destructuring assignment for namespace
- local vec2, vec3, vec4 = vector.vec2, vector.vec3, vector.vec4
- -- Quaternion class
- local Quaternion = {};
- function Quaternion:new(x, y, z, w)
- -- a Quaternion is a 4D vector
- -- - inherits from vec4
- local o = vec4:new(x, y, z,w)
- setmetatable(o, self)
- self.__index = self
- return o
- end
- function Quaternion:__tostring()
- return "(" .. self.x .. ", " .. self.y .. ", " .. self.z .. ", " .. self.w .. ")"
- end
- function Quaternion:__mul(other)
- -- Quaternion multiplication
- -- is not commutative
- -- (a * b) != (b * a)
- return Quaternion:new(
- self.w * other.x + self.x * other.w + self.y * other.z - self.z * other.y,
- self.w * other.y - self.x * other.z + self.y * other.w + self.z * other.x,
- self.w * other.z + self.x * other.y - self.y * other.x + self.z * other.w,
- self.w * other.w - self.x * other.x - self.y * other.y - self.z * other.z
- )
- end
- function Quaternion:__div(other)
- -- Quaternion division
- -- is not commutative
- -- (a / b) != (b / a)
- return Quaternion:new(
- self.w * other.x - self.x * other.w - self.y * other.z + self.z * other.y,
- self.w * other.y + self.x * other.z - self.y * other.w - self.z * other.x,
- self.w * other.z - self.x * other.y + self.y * other.x - self.z * other.w,
- self.w * other.w + self.x * other.x + self.y * other.y + self.z * other.z
- )
- end
- function Quaternion:__unm()
- -- Quaternion negation
- return Quaternion:new(-self.x, -self.y, -self.z, -self.w)
- end
- function Quaternion:__eq(other)
- return self.x == other.x and self.y == other.y and self.z == other.z and self.w == other.w
- end
- function Quaternion:conjugate()
- -- Quaternion conjugate
- return Quaternion:new(-self.x, -self.y, -self.z, self.w)
- end
- function Quaternion:inverse()
- -- Quaternion inverse
- return self:conjugate() / self:dot(self)
- end
- function Quaternion:dot(other)
- -- Quaternion dot product
- return self.x * other.x + self.y * other.y + self.z * other.z + self.w * other.w
- end
- function Quaternion:normalize()
- -- Quaternion normalization
- local len = self:dot(self)
- self.x = self.x / len
- self.y = self.y / len
- self.z = self.z / len
- self.w = self.w / len
- end
- function Quaternion:rotate_vector(vector)
- -- Rotate a vector by a quaternion
- -- (q * v * q^-1)
- return (self * Quaternion:new(vector.x, vector.y, vector.z, 0) * self:inverse()).xyz
- end
- function Quaternion:rotate_point(point)
- -- Rotate a point by a quaternion
- -- (q * p * q^-1)
- return (self * Quaternion:new(point.x, point.y, point.z, 0) * self:inverse()).xyz
- end
- function Quaternion:rotate_quaternion(quaternion)
- -- Rotate a quaternion by a quaternion
- -- (q * r * q^-1)
- return self * quaternion * self:inverse()
- end
- function Quaternion:from_axis_angle(axis, angle)
- -- Create a quaternion from an axis and an angle
- local half_angle = angle / 2
- local sin = math.sin(half_angle)
- self.x = axis.x * sin
- self.y = axis.y * sin
- self.z = axis.z * sin
- self.w = math.cos(half_angle)
- end
- function Quaternion:from_euler_angles(roll, pitch, yaw)
- -- Create a quaternion from euler angles
- local cr = math.cos(roll / 2)
- local cp = math.cos(pitch / 2)
- local cy = math.cos(yaw / 2)
- local sr = math.sin(roll / 2)
- local sp = math.sin(pitch / 2)
- local sy = math.sin(yaw / 2)
- self.x = sr * cp * cy - cr * sp * sy
- self.y = cr * sp * cy + sr * cp * sy
- self.z = cr * cp * sy - sr * sp * cy
- self.w = cr * cp * cy + sr * sp * sy
- end
- function Quaternion:to_axis_angle()
- -- Convert a quaternion to an axis and an angle
- local axis = vec3:new(self.x, self.y, self.z)
- local angle = 2 * math.acos(self.w)
- axis:normalize()
- return axis, angle
- end
- function Quaternion:to_euler_angles()
- -- Convert a quaternion to euler angles
- local roll = math.atan2(2 * (self.w * self.x + self.y * self.z), 1 - 2 * (self.x * self.x + self.y * self.y))
- local pitch = math.asin(2 * (self.w * self.y - self.z * self.x))
- local yaw = math.atan2(2 * (self.w * self.z + self.x * self.y), 1 - 2 * (self.y * self.y + self.z * self.z))
- return roll, pitch, yaw
- end
- function Quaternion:to_matrix()
- -- Convert a quaternion to a matrix
- local matrix = Matrix:new()
- matrix[1][1] = 1 - 2 * (self.y * self.y + self.z * self.z)
- matrix[1][2] = 2 * (self.x * self.y + self.z * self.w)
- matrix[1][3] = 2 * (self.x * self.z - self.y * self.w)
- matrix[2][1] = 2 * (self.x * self.y - self.z * self.w)
- matrix[2][2] = 1 - 2 * (self.x * self.x + self.z * self.z)
- matrix[2][3] = 2 * (self.y * self.z + self.x * self.w)
- matrix[3][1] = 2 * (self.x * self.z + self.y * self.w)
- matrix[3][2] = 2 * (self.y * self.z - self.x * self.w)
- matrix[3][3] = 1 - 2 * (self.x * self.x + self.y * self.y)
- return matrix
- end
- function Quaternion:to_string()
- -- Convert a quaternion to a string
- return string.format("Quaternion(%f, %f, %f, %f)", self.x, self.y, self.z, self.w)
- end
- function Quaternion:to_table()
- -- Convert a quaternion to a table
- return {self.x, self.y, self.z, self.w}
- end
- function Quaternion:to_vec3()
- -- Convert a quaternion to a vec3
- return vec3:new(self.x, self.y, self.z)
- end
- function Quaternion:to_vec2()
- -- Convert a quaternion to a vec2
- return vec2:new(self.x, self.y)
- end
- function Quaternion:to_vec4()
- -- Convert a quaternion to a vec4
- return vec4:new(self.x, self.y, self.z, self.w)
- end
- return Quaternion
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement