Skip to content
Extraits de code Groupes Projets
Valider 1fd93b96 rédigé par ultrakatiz's avatar ultrakatiz
Parcourir les fichiers

cleaned quaternion.lua, transform.lua and vector.lua

parent 1a0a252c
Aucune branche associée trouvée
Aucune étiquette associée trouvée
Aucune requête de fusion associée trouvée
require("kara3d.vector")
require("kara3d.matrix")
-- ********** DEFINITION AND GENERIC FUNCTIONS **********
quaternion = {class = "quaternion"}
quaternion.__index = quaternion
-- Creates the quaternion ai + bj + dk + d
function quaternion.new(a, b, c, d)
local q = {x = a or 0, y = b or 0, z = c or 0, w = d or 1}
setmetatable(q, quaternion)
return q
end
function quaternion:inv()
return quaternion.new(-self.x, -self.y, -self.z, -self.w)
-- Clones this quaternion
function quaternion:clone()
return quaternion.new(self.x, self.y, self.z, self.w)
end
-- Returns this quaternion's coordinates, separated by commas
function quaternion:tostring()
return self.x .. ", " .. self.y .. ", " .. self.z .. ", " .. self.w
end
function quaternion:set(x, y, z, w)
if (type(x) == "table" and x.class == "quaternion") then
self.x = x.x
self.y = x.y
self.z = x.z
self.w = x.w
else
self.x = x or 0
self.y = y or 0
self.z = z or 0
self.w = w or 1
end
return self
end
-- ********** STATIC FUNCTIONS **********
-- Returns the quaternion 0i + 0j + 0k + 1, which is no rotation
function quaternion.identity() return quaternion.new() end
-- Returns the product of two (normalized) quaternions
function quaternion.mul_quaternion(q1, q2)
local b, c, d, a = q1:unpack()
local f, g, h, e = q2:unpack()
local b, c, d, a = q1:normalized():unpack()
local f, g, h, e = q2:normalized():unpack()
return quaternion.new(a*e - b*f - c*g - d*h,
a*f + b*e + c*h - d*g,
a*g + c*e + d*f - b*h,
a*h + d*e + b*g - c*f)
end
-- Returns a vector equal to the vector v (size >= 3)
-- rotated by the quaternion q
function quaternion.mul_vector(q, v)
local v3 = vector.new(3, v.values)
local u1 = vector.new(3, {q.x, q.y, q.z})
......@@ -51,6 +49,7 @@ function quaternion.mul_vector(q, v)
return 2*d * u1 + (q.w*q.w - u1:length2()) * v3 + 2*q.w * c
end
-- Returns a quaternion representing the rotation from -> to (size = 3)
function quaternion.from_to_rotation(from, to)
local v0 = from:normalized()
local v1 = to:normalized()
......@@ -61,6 +60,8 @@ function quaternion.from_to_rotation(from, to)
return quaternion.axis_angle(vector.cross(v0, v1):normalize(), math.acos(d))
end
-- Returns a quaternion representing the rotation of angle around axis
-- If angle is nil, then the norm of axis will be used as the angle
function quaternion.axis_angle(axis, angle)
angle = angle or axis:length()
......@@ -71,10 +72,36 @@ function quaternion.axis_angle(axis, angle)
return quaternion.new(naxis:x() * hsin, naxis:y() * hsin, naxis:z() * hsin, hcos)
end
-- ********** INSTANCE FUNCTIONS **********
-- Sets this quaternion's coordinates to these values
-- Arguments may be 4 numbers or 1 table with indexes x, y, z and w
function quaternion:set(x, y, z, w)
if (type(x) == "table" and x.class == "quaternion") then
self.x = x.x
self.y = x.y
self.z = x.z
self.w = x.w
else
self.x = x or 0
self.y = y or 0
self.z = z or 0
self.w = w or 1
end
return self
end
-- Returns the inverse of this quaternion
function quaternion:inv()
return quaternion.new(-self.x, -self.y, -self.z, -self.w)
end
-- Returns the 4 coordinates of this quaternion
function quaternion:unpack()
return self.x, self.y, self.z, self.w
end
-- Normalizes this quaternion, so that its norm is 1
function quaternion:normalize()
local len = self:length()
if len ~= 0 and len ~= 1 then
......@@ -86,26 +113,24 @@ function quaternion:normalize()
return self
end
-- Returns a quaternion which is equal to this quaternion, normalized
function quaternion:normalized()
local q = self:clone()
q:normalize()
return q
end
function quaternion:clone()
return quaternion.new(self.x, self.y, self.z, self.w)
end
-- Returns the square of the norm of this quaternion
function quaternion:length2()
return self.x * self.x + self.y * self.y + self.z * self.z + self.w * self.w
end
-- Returns the norm of this quaternion
function quaternion:length()
return math.sqrt(self:length2())
end
function quaternion.identity() return quaternion.new() end
-- Returns the rotation matrix (4x4) corresponding to this quaternion
function quaternion:to_matrix()
local x, y, z, w = self:unpack()
local m = matrix.new(4, 4,
......
......@@ -2,9 +2,13 @@ require("kara3d.vector")
require("kara3d.matrix")
require("kara3d.quaternion")
-- ********** DEFINITION AND GENERIC FUNCTIONS **********
transform = {class = "transform"}
transform.__index = transform
-- Creates a new transform with position p, rotation r, scale s and parent par
-- p and s should be of size 3, r is a quaternion, and par may be nil
function transform.new(p, r, s, par)
p = p or vector.zero(3)
r = r or quaternion.identity()
......@@ -14,6 +18,7 @@ function transform.new(p, r, s, par)
return t
end
-- Returns a string that represents this transform
function transform:tostring()
return "(pos = (" .. self.pos:tostring() .. "), "
.. "rot = (" .. self.rot:tostring() .. "), "
......@@ -21,11 +26,15 @@ function transform:tostring()
.. (self.parent and "has parent" or "no parent") .. ")"
end
-- ********** INSTANCE FUNCTIONS **********
-- Rotates this transform by angle around axis
function transform:rotate(axis, angle)
self.rot = quaternion.axis_angle(axis, angle) * self.rot
return self
end
-- Returns the local or global position of this transform
function transform:position(global)
local p = self.pos:clone()
if (p.size > 4) then p:set_size(4) end
......@@ -36,6 +45,7 @@ function transform:position(global)
return p:set_size(3)
end
-- Returns the local or global rotation of this transform
function transform:rotation(global)
local q = self.rot:normalized()
if (global and self.parent) then
......@@ -44,6 +54,7 @@ function transform:rotation(global)
return q
end
-- Returns the local or global scale of this transform
function transform:scale(global)
local s = self.scl:clone()
if (global and self.parent) then
......@@ -55,6 +66,7 @@ function transform:scale(global)
return s
end
-- Returns the transformation matrix corresponding to this transform
function transform:matrix(global)
local translation = matrix.new(4, 4,
{1, 0, 0, self.pos:get(1),
......
-- ********** DEFINITION AND GENERIC FUNCTIONS **********
vector = {class = "vector"}
vector.__index = vector
-- Creates a vector of size n, initialized with values vals
-- Uninitialized values are set to 0
function vector.new(n, vals)
if (type(n) == "table") then vals = n n = #n end
vals = vals or {}
......@@ -12,53 +16,10 @@ function vector.new(n, vals)
return v
end
-- operator overloading
function vector.__add(a, b)
local small = a.size < b.size and a or b
local big = a.size < b.size and b or a
local r = big:clone()
for i = 1, small.size do r:set(i, r:get(i) + small:get(i)) end
return r
end
function vector.__unm(a)
local r = vector.new(a.size)
for i = 1, r.size do r:set(i, -(a:get(i))) end
return r
end
function vector.__sub(a, b)
local oppb = -b
return a + oppb
end
function vector.__mul(a, b)
if type(a) == "number" and type(b) ~= "number" then
local r = vector.new(b.size)
for i = 1, r.size do r:set(i, a * b:get(i)) end
return r
elseif type(a) ~= "number" and type(b) == "number" then
local r = vector.new(a.size)
for i = 1, r.size do r:set(i, a:get(i) * b) end
return r
elseif type(a) ~= "number" and type(b) ~= "number" then
local small = a.size < b.size and a or b
local big = a.size < b.size and b or a
local r = vector.new(big.size)
for i = 1, small.size do r:set(i, small:get(i) * big:get(i)) end
return r
else
return a * b
end
end
function vector.__eq(a, b)
if (a.size ~= b.size) then return false end
for i = 1, a.size do if (a:get(i) ~= b:get(i)) then return false end end
return true
end
-- Clones this vector
function vector:clone() return vector.new(self.size, self.values) end
-- Returns this vector's coordinates, separated by commas
function vector:tostring()
local str = ""
for i = 1, self.size - 1 do
......@@ -67,30 +28,26 @@ function vector:tostring()
return str .. self:get(self.size)
end
function vector:clone() return vector.new(self.size, self.values) end
function vector:length2()
local sum = 0
for i = 1, self.size do sum = sum + self:get(i) * self:get(i) end
return sum
end
function vector:length() return math.sqrt(self:length2()) end
-- ********** STATIC FUNCTIONS **********
function vector:is_unit() return self:length2() == 1 end
-- Returns a vector full of 0s, with size size
function vector.zero(size) return vector.new(size) end
function vector:normalize()
local len = self:length()
if len == 0 or len == 1 then return self end
for i = 1, self.size do self:set(i, self:get(i) / len) end
return self
-- Returns a vector full of 1s, with size size
function vector.one(size)
local vals = {}
for i = 1, size do vals[i] = 1 end
return vector.new(size, vals)
end
function vector:normalized() return self:clone():normalize() end
function vector.project_vector(from, to) return (vector.dot(from, to) / to:length2()) * to end
function vector.project_plane(from, normal) return from - vector.project_vector(from, normal) end
-- Returns a vector of size size, filled with 0s and a 1 at index
function vector.cardinal(size, index)
local vals = {}
for i = 1, size do vals[i] = i == index and 1 or 0 end
return vector.new(size, vals)
end
-- Returns the dot product of two vectors
function vector.dot(a, b)
local min_size = math.min(a.size, b.size)
local sum = 0
......@@ -98,20 +55,41 @@ function vector.dot(a, b)
return sum
end
-- Returns the cross product of two vectors of size 3
function vector.cross(a, b)
return vector.new(3, {a.values[2] * b.values[3] - a.values[3] * b.values[2],
a.values[3] * b.values[1] - a.values[1] * b.values[3],
a.values[1] * b.values[2] - a.values[2] * b.values[1]})
end
-- Returns a vector which is the projection of the vector from to the vector to
function vector.project_vector(from, to) return (vector.dot(from, to) / to:length2()) * to end
-- Returns a vector which is the projection of the vector from to the plane of normal normal
function vector.project_plane(from, normal) return from - vector.project_vector(from, normal) end
-- Returns the square of the distance between two vectors
function vector.distance2(a, b) return (a - b):length2() end
-- Returns the distance between two vectors
function vector.distance(a, b) return (a - b):length() end
-- Returns the angle between two vectors
function vector.angle(from, to) return math.acos(vector.dot(from, to) / (from:length() * to:length())) end
-- Returns a vector lerped between from and to, with parameter t
function vector.lerp(from, to, t) return t * from + (1 - t) * to end
function vector:set_values(vals)
vals = vals or {}
for i = 1, #vals do self.values[i] = vals[i] end
for i = #vals + 1, self.size do self.values[i] = nil end
self.size = #vals
return self
end
-- ********** INSTANCE FUNCTIONS **********
-- Sets the ith cell of this vector to value
function vector:set(i, value) self.values[i] = value return self end
-- Returns the ith value of this vector
function vector:get(i) return self.values[i] end
-- Sets the size of this vector to n
-- Uninitialized values are set to 0, and overflowing values are set to nil
function vector:set_size(n)
if (self.size == n) then return self end
for i = n + 1, self.size do self:set(i, nil) end
......@@ -120,31 +98,101 @@ function vector:set_size(n)
return self
end
function vector.cross(a, b)
return vector.new(3, {a.values[2] * b.values[3] - a.values[3] * b.values[2],
a.values[3] * b.values[1] - a.values[1] * b.values[3],
a.values[1] * b.values[2] - a.values[2] * b.values[1]})
-- Sets the values of this vector to vals
-- Uninitialized values are set to 0
function vector:set_values(vals)
vals = vals or {}
for i = 1, #vals do self:set(i, vals[i]) end
for i = #vals + 1, self.size do self:set(i, 0) end
self.size = #vals
return self
end
function vector.zero(size) return vector.new(size) end
function vector.one(size)
local vals = {}
for i = 1, size do vals[i] = 1 end
return vector.new(size, vals)
end
function vector.cardinal(size, index)
local vals = {}
for i = 1, size do vals[i] = i == index and 1 or 0 end
return vector.new(size, vals)
-- Returns the square of the norm of this vector
function vector:length2()
local sum = 0
for i = 1, self.size do sum = sum + self:get(i) * self:get(i) end
return sum
end
function vector:get(index) return self.values[index] end
function vector:set(index, value)
self.values[index] = value
-- Returns the norm of this vector
function vector:length() return math.sqrt(self:length2()) end
-- Returns ||v|| == 1, v being this vector
function vector:is_unit() return self:length2() == 1 end
-- Sets the coordinates of this vector so that it has the same direction,
-- but has a norm equal to 1
function vector:normalize()
local len = self:length()
if len == 0 or len == 1 then return self end
for i = 1, self.size do self:set(i, self:get(i) / len) end
return self
end
-- Returns a vector with the same direction as this vector, but with norm 1
function vector:normalized() return self:clone():normalize() end
-- Convenience functions that return the first four coordinates
function vector:x() return self.values[1] end
function vector:y() return self.values[2] end
function vector:z() return self.values[3] end
function vector:w() return self.values[4] end
-- ********** OPERATOR OVERLOADING **********
-- + binary operator overload
-- Returns a vector c such that for all i, c(i) = a(i) + b(i)
function vector.__add(a, b)
local small = a.size < b.size and a or b
local big = a.size < b.size and b or a
local r = big:clone()
for i = 1, small.size do r:set(i, r:get(i) + small:get(i)) end
return r
end
-- - unary operator overload
-- Returns a vector c such that for all i, c(i) = -a(i)
function vector.__unm(a)
local r = vector.new(a.size)
for i = 1, r.size do r:set(i, -(a:get(i))) end
return r
end
-- - binary operator overload
-- Returns a vector c such that for all i, c(i) = a(i) - b(i)
function vector.__sub(a, b)
local oppb = -b
return a + oppb
end
-- * binary operator overload
-- If one of the arguments is a scalar, scales the other argument by it
-- Else, returns a vector c such that for all i, c(i) = a(i) * b(i)
function vector.__mul(a, b)
if type(a) == "number" and type(b) ~= "number" then
local r = vector.new(b.size)
for i = 1, r.size do r:set(i, a * b:get(i)) end
return r
elseif type(a) ~= "number" and type(b) == "number" then
local r = vector.new(a.size)
for i = 1, r.size do r:set(i, a:get(i) * b) end
return r
elseif type(a) ~= "number" and type(b) ~= "number" then
local small = a.size < b.size and a or b
local big = a.size < b.size and b or a
local r = vector.new(big.size)
for i = 1, small.size do r:set(i, small:get(i) * big:get(i)) end
return r
else
return a * b
end
end
-- == binary operator overload
-- Returns "for all i, a(i) == b(i)""
function vector.__eq(a, b)
if (a.size ~= b.size) then return false end
for i = 1, a.size do if (a:get(i) ~= b:get(i)) then return false end end
return true
end
0% Chargement en cours ou .
You are about to add 0 people to the discussion. Proceed with caution.
Terminez d'abord l'édition de ce message.
Veuillez vous inscrire ou vous pour commenter