# lua-carbon/carbon

Switch branches/tags
Nothing to show
Fetching contributors…
Cannot retrieve contributors at this time
264 lines (216 sloc) 7.93 KB
 --[[ Carbon for Lua #class Math.Quaternion #inherits Math.Vector<4> #description { Provides a quaternion object for representing rotations. The loose form of a @Quaternion, `@loose<@Quaternion>` is of the form `(x, y, z, w)` } #alias Vector3 Math.Vector3 ]] local Carbon = (...) local OOP = Carbon.OOP local Vector3 = Carbon.Math.Vector3 local Vector4 = Carbon.Math.Vector4 local sin, cos = math.sin, math.cos local asin, acos = math.asin, math.acos local sqrt = math.sqrt local abs = math.abs local Quaternion = OOP:Class(Vector4) --[[#method 1 { \$constructor_init_pair(FromAngles Quaternion(@Vector3 angles)) required angles: A @Vector3 containing the angles to convert. Converts a @Vector3 containing Euler angles into a @Quaternion. }]] function Quaternion:NewFromAngles(angles) return self:New(self:NewLooseFromLooseAngles(angles[1], angles[2], angles[3])) end function Quaternion:InitFromAngles(angles) return self:Init(self:NewLooseFromLooseAngles(angles[1], angles[2], angles[3])) end --[[#method 1 { class public @loose<@Quaternion> Quaternion:NewLooseFromAngles(@Vector3 angles) required angles: A @Vector3 containing the angles to convert. Converts a @Vector3 containing Euler angles into a loose @Quaternion. }]] function Quaternion:NewLooseFromAngles(angles) return self:NewLooseFromLooseAngles(angles[1], angles[2], angles[3]) end --[[#method 1 { \$constructor_init_pair(FromLooseAngles Quaternion(@number x, @number y, @number z)) required x: The x component of the angles. required y: The y component of the angles. required z: The z component of the angles. Converts a @loose<@Vector3> containing Euler angles into a @Quaternion. }]] function Quaternion:NewFromLooseAngles(x, y, z) return self:New(self:NewLooseFromLooseAngles(x, y, z)) end function Quaternion:InitFromLooseAngles(x, y, z) return self:Init(self:NewLooseFromLooseAngles(x, y, z)) end --[[#method 1 { class public @loose<@Quaternion> Quaternion:NewLooseFromLooseAngles(@number x, @number y, @number z) required x: The x component of the angles. required y: The y component of the angles. required z: The z component of the angles. Converts a @loose<@Vector3> containing Euler angles into a loose @Quaternion. }]] function Quaternion:NewLooseFromLooseAngles(x, y, z) local c1 = cos(x / 2) local c2 = cos(y / 2) local c3 = cos(z / 2) local s1 = sin(x / 2) local s2 = sin(y / 2) local s3 = sin(z / 2) return (s1 * s2 * c3) + (c1 * c2 * s3), (s1 * c2 * c3) + (c1 * s2 * s3), (c1 * s2 * c3) - (s1 * c2 * s3), (c1 * c2 * c3) - (s1 * s2 * s3) end --[[#method { object public @loose<@Quaternion> Quaternion:LooseConjugate() Returns the conjugate of the quaternion in loose form. }]] function Quaternion:LooseConjugate() return -self[1], -self[2], -self[3], self[4] end --[[#method { object public @Quaternion Quaternion:Conjugate([@Quaternion out]) optional out: Where to put the resulting data. Returns the conjugate of the @Quaternion, `(-i, -j, -k, w)`. }]] function Quaternion:Conjugate(out) if (out) then out:Init(self:LooseConjugate()) else self.class:New(self:LooseConjugate()) end end --[[#method { object public @Quaternion Quaternion:Conjugate!() -alias: object public @Quaternion Quaternion:ConjugateInPlace() Conjugates the @Quaternion in-place. }]] function Quaternion:ConjugateInPlace() return self:Conjugate(self) end --[[#method { class public @loose<@Quaternion> Quaternion:LooseMultiplyLooseLoose(@loose<@Quaternion> a, @loose<@Quaternion> b) required a: The left operand on the multiply. required b: The right operand on the multiply. Multiplies two loose quaternions together and returns the result in loose form. }]] function Quaternion:LooseMultiplyLooseLoose(x1, y1, z1, w1, x2, y2, z2, w2) return w1*x2 + x1*w2 + y1*z2 - z1*y2, w1*y2 - x1*z2 + y1*w2 + z1*x2, w1*z2 + x1*y2 - y1*x2 + z1*w2, w1*w2 - x1*x2 - y1*y2 - z1*z2 end --[[#method { object public @loose<@Quaternion> @Quaternion:LooseMultiplyLoose(@loose<@Quaternion> quaternion) required quaternion: The quaternion to multiply with. Multiplies the quaternion with a loose @Quaternion, yielding a @loose<@Quaternion>. }]] function Quaternion:LooseMultiplyLoose(x2, y2, z2, w2) local x1, y1, z1, w1 = self:GetComponents() return self:LooseMultiplyLooseLoose(x1, y1, z1, w1, x2, y2, z2, w2) end --[[#method { object public @Quaternion Quaternion:MultiplyLoose(@loose<@Quaternion> quaternion, [@Quaternion out]) required quaternion: The loose quaternion to multiply with. optional out: Where to put the resulting data. Multiplies the quaternion with a loose @Quaternion. }]] function Quaternion:MultiplyLoose(x2, y2, z2, w2, out) return self.class:PlacementNew(out, self:LooseMultiplyLoose(x2, y2, z2, w2)) end --[[#method { object public @Quaternion Quaternion:MultiplyLoose!(@loose<@Quaternion> quaternion) required quaternion: The loose quaternion to multiply with. Multiplies this quaternion with another loose @Quaternion in-place. }]] function Quaternion:MultiplyLooseInPlace(x2, y2, z2, w2) return self:MultiplyLoose(x2, y2, z2, w2, self) end --[[#method { object public @Quaternion Quaternion:Multiply(@Quaternion other, [@Quaternion out]) required other: The quaternion to multiply with. optional out: Where to put the resulting data. Multiplies the quaternion with another @Quaternion. }]] function Quaternion:Multiply(other, out) local x2, y2, z2, w2 = other:GetComponents() return self.class:PlacementNew(out, self:LooseMultiplyLoose(x2, y2, z2, w2)) end --[[#method { object public self Quaternion:Multiply!(@Quaternion other) -alias: object public self Quaternion:MultiplyInPlace(@Quaternion other) required other: The quaternion to multiply with. Multiplies the quaternion with another @Quaternion and puts the result in the first @Quaternion. }]] function Quaternion:MultiplyInPlace(other) return self:Multiply(other, self) end --[[#method { object public self @Quaternion:Slerp(@Quaternion other, @number t, [@Quaternion out]) required other: The @Quaternion to slerp with. required t: A number, normally on [0, 1], that determines the mixing ratio of the quaternions. optional out: Where to put the resulting slerped @Quaternion. Performs a @Quaternion slerp (spherical interpolation). }]] function Quaternion:Slerp(other, t, out) local cos_half_theta = self:DotProduct(other) if (abs(cos_half_theta) >= 1) then return self.class:PlacementNew(out, self[1], self[2], self[3], self[4]) end local half_theta = acos(cos_half_theta) local sin_half_theta = sqrt(1 - cos_half_theta^2) if (abs(sin_half_theta) < 1e-4) then return self.class:PlacementNew(out, self[1] * 0.5 + other[1] * 0.5, self[2] * 0.5 + other[2] * 0.5, self[3] * 0.5 + other[3] * 0.5, self[4] * 0.5 + other[4] * 0.5 ) end local r_a = sin((1 - t) * half_theta) / sin_half_theta local r_b = sin(t * half_theta) / sin_half_theta return self.class:PlacementNew(out, self[1] * r_a + other[1] * r_b, self[2] * r_a + other[2] * r_b, self[3] * r_a + other[3] * r_b, self[4] * r_a + other[4] * r_b ) end --[[#method { object public self Quaternion:Slerp!(@Quaternion other, @number t) -alias: object public self @Quaternion:SlerpInPlace(@Quaternion other, @number t) required other: The @Quaternion to slerp with. required t: A number, normally on [0, 1], that determines the mixing ratio of the quaternions. Performs a @Quaternion slerp (spherical interpolation) in place. }]] function Quaternion:SlerpInPlace(other, t, out) return self:Slerp(other, t, self) end --[[#method { object public self Quaternion:TransformVector(@Vector3 vec, [@Vector3 out]) required vec: The vector to rotate. optional out: Where to put the resulting data. Transforms a vector by rotating it. }]] function Quaternion:TransformVector(vec, out) local x, y, z, w = self:LooseMultiplyLoose(vec[1], vec[2], vec[3], 0) x, y, z = self.class:LooseMultiplyLooseLoose( x, y, z, w, self:LooseConjugate() ) if (out) then out:Init(x, y, z) else return Vector3(x, y, z) end end return Quaternion