extern crate num;
use num::traits::*;
use std::ops::*;
use std::mem;
use vector::*;
use matrix::*;
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(C)]
pub struct Quaternion<T> { pub x:T, pub y:T, pub z:T, pub w:T }
pub type Quaternionf = Quaternion<f32>;
pub type Quaterniond = Quaternion<f32>;
impl<T:Copy> Quaternion<T> {
pub fn new(x:T, y:T, z:T, w:T ) -> Quaternion<T> {
Quaternion{ w:w, x:x, y:y, z:z }
}
pub fn new_s(s:T) -> Quaternion<T> {
Quaternion{ x:s, y:s, z:s, w:s }
}
pub fn new_v3(v:Vector3<T>, w:T ) -> Quaternion<T> {
Quaternion{ x:v.x, y:v.y, z:v.z, w:w }
}
pub fn len(self) -> usize { 4 }
}
impl<T:Copy + Zero + One> Default for Quaternion<T> {
fn default() -> Quaternion<T> {
Quaternion{ x:T::zero(),
y:T::zero(),
z:T::zero(),
w:T::one() }
}
}
impl<T:Copy + Zero + One> Quaternion<T> {
pub fn identity() -> Quaternion<T> {
Quaternion{ x:T::zero(),
y:T::zero(),
z:T::zero(),
w:T::one() }
}
}
impl<T:Copy + Zero + PartialEq> Zero for Quaternion<T> {
fn zero() -> Quaternion<T> {
Quaternion{ x:T::zero(),
y:T::zero(),
z:T::zero(),
w:T::zero() }
}
fn is_zero(&self) -> bool {
self.x == T::zero() &&
self.y == T::zero() &&
self.z == T::zero() &&
self.w == T::zero()
}
}
impl<T:Copy + Num> One for Quaternion<T> {
fn one() -> Quaternion<T> {
Quaternion{ x: T::one(), y: T::one(), z: T::one(), w: T::one() }
}
}
impl<T:Copy> Index<usize> for Quaternion<T> {
type Output = T;
fn index<'a>(&'a self, idx:usize) -> &'a T {
let s: &[T;4] = unsafe { mem::transmute(self) };
&s[idx]
}
}
impl<T:Copy> IndexMut<usize> for Quaternion<T> {
fn index_mut<'a>(&'a mut self, idx:usize) -> &'a mut T {
let s: &'a mut [T;4] = unsafe { mem::transmute(self) };
&mut s[idx]
}
}
impl<T:Add<Output = T> + Zero + Copy> Add<Quaternion<T>> for Quaternion<T> {
type Output = Quaternion<T>;
fn add(self, rhs:Quaternion<T>) -> Quaternion<T> {
Quaternion{x:self.x + rhs.x,
y:self.y + rhs.y,
z:self.z + rhs.z,
w:self.w + rhs.w }
}
}
impl<T: Add<Output=T> + Zero + Copy> Add<T> for Quaternion<T> {
type Output = Quaternion<T>;
fn add(self, s:T) -> Quaternion<T> {
Quaternion{x:self.x + s,
y:self.y + s,
z:self.z + s,
w:self.w + s }
}
}
impl<T:Copy + Num> Mul<Quaternion<T>> for Quaternion<T> {
type Output = Quaternion<T>;
fn mul(self, rhs:Quaternion<T>) -> Quaternion<T> {
Quaternion{x: self.w * rhs.x + self.x * rhs.w + self.y * rhs.z - self.z * rhs.y,
y: self.w * rhs.y + self.y * rhs.w + self.z * rhs.x - self.x * rhs.z,
z: self.w * rhs.z + self.z * rhs.w + self.x * rhs.y - self.y * rhs.x,
w: self.w * rhs.w - self.x * rhs.x - self.y * rhs.y - self.z * rhs.z
}
}
}
fn mul_v3<T:Copy + Num>(q:Quaternion<T>, v:Vector3<T>) -> Vector3<T> {
let qv = Vector3::new(q.x, q.y, q.z);
let uv = qv.cross(v);
let uuv = qv.cross(uv);
let two = T::one() + T::one();
v + ((uv * q.w) + uuv) * two
}
impl<T:Copy + Num> Mul<Vector3<T>> for Quaternion<T> {
type Output = Vector3<T>;
fn mul(self, v:Vector3<T>) -> Vector3<T> {
mul_v3(self, v)
}
}
impl<T:Copy + Num> Mul<Vector4<T>> for Quaternion<T> {
type Output = Vector4<T>;
fn mul(self, v:Vector4<T>) -> Vector4<T> {
Vector4::new_v3( self * Vector3::new_v4(v), v.w )
}
}
impl<T:Mul<Output = T> + Zero + Copy> Mul<T> for Quaternion<T> {
type Output = Quaternion<T>;
fn mul(self, s:T) -> Quaternion<T> {
Quaternion{x:self.x * s,
y:self.y * s,
z:self.z * s,
w:self.w * s }
}
}
impl<T:Copy + Float> Div<T> for Quaternion<T> {
type Output = Quaternion<T>;
fn div(self, s:T) -> Quaternion<T> {
Quaternion{x:self.x / s,
y:self.y / s,
z:self.z / s,
w:self.w / s }
}
}
impl<T:Copy + Neg<Output=T> > Neg for Quaternion<T> {
type Output = Quaternion<T>;
fn neg(self) -> Quaternion<T> {
Quaternion{x: -self.x,
y: -self.y,
z: -self.z,
w: -self.w }
}
}
impl<T:Copy + Mul<Output = T> + Add<Output = T> + Sub<Output = T> + PartialEq> Quaternion<T> {
pub fn dot(self, rhs:Quaternion<T>) -> T {
self.x * rhs.x +
self.y * rhs.y +
self.z * rhs.z +
self.w * rhs.w
}
pub fn cross(self, rhs:Quaternion<T>) -> Quaternion<T> {
Quaternion{
x:self.w * rhs.x + self.x * rhs.w + self.y * rhs.z - self.z * rhs.y,
y:self.w * rhs.y + self.y * rhs.w + self.z * rhs.x - self.x * rhs.z,
z:self.w * rhs.z + self.z * rhs.w + self.x * rhs.y - self.y * rhs.x,
w:self.w * rhs.w - self.x * rhs.x - self.y * rhs.y - self.z * rhs.z }
}
}
impl<T:Copy + Float> Quaternion<T> {
pub fn new_axis(u:Vector3<T>, v:Vector3<T>) -> Quaternion<T> {
let w = u.cross(v);
Quaternion::new(w[0], w[1], w[2], T::one() + u.dot(v)).normalize()
}
pub fn new_angle_axis(angle:T, axis:Vector3<T>) -> Quaternion<T> {
let mut result = Quaternion::default();
let a = angle;
let s = (a * T::from(0.5).unwrap()).sin();
result.w = (a * T::from(0.5).unwrap()).cos();
result.x = axis.x * s;
result.y = axis.y * s;
result.z = axis.z * s;
return result;
}
pub fn new_euler(euler_angles:Vector3<T>) -> Quaternion<T> {
let euler_half = euler_angles / T::from(2).unwrap();
let c = euler_half.cos();
let s = euler_half.sin();
Quaternion{x: s.x * c.y * c.z - c.x * s.y * s.z,
y: c.x * s.y * c.z + s.x * c.y * s.z,
z: c.x * c.y * s.z - s.x * s.y * c.z,
w: c.x * c.y * c.z + s.x * s.y * s.z }
}
pub fn new_m3(m:Matrix3x3<T>) -> Quaternion<T> {
let four_x_squared_minus_1 = m[0][0] - m[1][1] - m[2][2];
let four_y_squared_minus_1 = m[1][1] - m[0][0] - m[2][2];
let four_z_squared_minus_1 = m[2][2] - m[0][0] - m[1][1];
let four_w_squared_minus_1 = m[0][0] + m[1][1] + m[2][2];
let mut biggest_index = 0;
let mut four_biggest_squared_minus_1 = four_w_squared_minus_1;
if four_x_squared_minus_1 > four_biggest_squared_minus_1 {
four_biggest_squared_minus_1 = four_x_squared_minus_1;
biggest_index = 1;
}
if four_y_squared_minus_1 > four_biggest_squared_minus_1 {
four_biggest_squared_minus_1 = four_y_squared_minus_1;
biggest_index = 2;
}
if four_z_squared_minus_1 > four_biggest_squared_minus_1 {
four_biggest_squared_minus_1 = four_z_squared_minus_1;
biggest_index = 3;
}
let biggest_val = (four_biggest_squared_minus_1 + T::one()).sqrt() * T::from(0.5).unwrap();
let mult = T::from(0.25).unwrap() / biggest_val;
let mut result = Quaternion::zero();
match biggest_index {
0 => { result.w = biggest_val;
result.x = (m[1][2] - m[2][1]) * mult;
result.y = (m[2][0] - m[0][2]) * mult;
result.z = (m[0][1] - m[1][0]) * mult;
}
1 => { result.w = (m[1][2] - m[2][1]) * mult;
result.x = biggest_val;
result.y = (m[0][1] + m[1][0]) * mult;
result.z = (m[2][0] + m[0][2]) * mult;
}
2 => { result.w = (m[2][0] - m[0][2]) * mult;
result.x = (m[0][1] + m[1][0]) * mult;
result.y = biggest_val;
result.z = (m[1][2] + m[2][1]) * mult;
}
3 => { result.w = (m[0][1] - m[1][0]) * mult;
result.x = (m[2][0] + m[0][2]) * mult;
result.y = (m[1][2] + m[2][1]) * mult;
result.z = biggest_val;
}
_ => {
unreachable!();
}
}
return result;
}
pub fn new_m4(m:Matrix4x4<T>) -> Quaternion<T> {
Quaternion::new_m3( Matrix3x3::new_m4x4(m) )
}
pub fn length(self) -> T {
self.dot(self).sqrt()
}
pub fn normalize(self) -> Quaternion<T> {
let len = self.length();
if len <= T::zero() { return Quaternion{x:T::one(), y:T::zero(), z:T::zero(), w:T::zero()};
}
let one_over_len = T::one() / len;
return Quaternion{x:self.x * one_over_len,
y:self.y * one_over_len,
z:self.z * one_over_len,
w:self.w * one_over_len };
}
fn mix_t(x:T, y:T, a:T) -> T {
x * (T::one() - a) + y * a
}
pub fn mix(self, y:Quaternion<T>, a:T) -> Quaternion<T> {
let cos_theta = self.dot(y);
if cos_theta > T::one() - T::one() {
return Quaternion{
x: Quaternion::mix_t(self.x, y.x, a),
y: Quaternion::mix_t(self.y, y.y, a),
z: Quaternion::mix_t(self.z, y.z, a),
w: Quaternion::mix_t(self.w, y.w, a) };
}
let angle = cos_theta.acos();
return (self * ((T::one() - a) * angle).sin() + y * (a * angle).sin()) / angle.sin();
}
pub fn lerp(self, y:Quaternion<T>, a:T) -> Quaternion<T> {
assert!(a >= T::zero());
assert!(a <= T::one());
return self * (T::one() - a) + (y * a);
}
pub fn slerp(self, y:Quaternion<T>, a:T) -> Quaternion<T> {
let mut z = y;
let mut cos_theta = self.dot(y);
if cos_theta < T::zero() {
z = -y;
cos_theta = -cos_theta;
}
if cos_theta > T::one() - T::one() {
return Quaternion{ x: Quaternion::mix_t(self.x, z.x, a),
y: Quaternion::mix_t(self.y, z.y, a),
z: Quaternion::mix_t(self.z, z.z, a),
w: Quaternion::mix_t(self.w, z.w, a) };
}
let angle = cos_theta.acos();
return (self * ((T::one() - a).sin() * angle) + z * (a * angle).sin()) / angle.sin();
}
pub fn conjugate(self) -> Quaternion<T> {
Quaternion{ x: -self.x,
y: -self.y,
z: -self.z,
w: self.w }
}
pub fn inverse(self) -> Quaternion<T> {
self.conjugate() / self.dot(self)
}
pub fn rotate(self, angle:T, axis:Vector3<T>) -> Quaternion<T> {
let mut tmp = axis;
let len = tmp.length();
if (len - T::one()).abs() > T::from(0.001).unwrap() {
let one_over_len = T::one() / len;
tmp.x = tmp.x * one_over_len;
tmp.y = tmp.y * one_over_len;
tmp.z = tmp.z * one_over_len;
}
let angle_rad = angle;
let sin = (angle_rad * T::from(0.5).unwrap()).sin();
return self * Quaternion{x: tmp.x * sin,
y: tmp.y * sin,
z: tmp.z * sin,
w: (angle_rad * T::from(0.5).unwrap()).cos() };
}
pub fn euler_angles(self) -> Vector3<T> {
Vector3::new(self.pitch(), self.yaw(), self.roll())
}
pub fn pitch(self) -> T {
let y = T::from(2).unwrap() * (self.y * self.z + self.w * self.x);
let x = self.w * self.w - self.x * self.x - self.y * self.y + self.z * self.z;
return y.atan2(x);
}
pub fn yaw(self) -> T {
(T::from(-2).unwrap() * (self.x * self.z - self.w * self.y)).asin()
}
pub fn roll(self) -> T {
let y = T::from(2).unwrap() * (self.x * self.y + self.w * self.z);
let x = self.w * self.w + self.x * self.x - self.y * self.y - self.z * self.z;
return y.atan2(x);
}
pub fn m3_cast(self) -> Matrix3<T> {
let mut result = Matrix3::one();
let qxx = self.x * self.x;
let qyy = self.y * self.y;
let qzz = self.z * self.z;
let qxz = self.x * self.z;
let qxy = self.x * self.y;
let qyz = self.y * self.z;
let qwx = self.w * self.x;
let qwy = self.w * self.y;
let qwz = self.w * self.z;
let one = T::one();
let two = T::from(2).unwrap();
result[0][0] = one - two * (qyy + qzz);
result[0][1] = two * (qxy + qwz);
result[0][2] = two * (qxz - qwy);
result[1][0] = two * (qxy - qwz);
result[1][1] = one - two * (qxx + qzz);
result[1][2] = two * (qyz + qwx);
result[2][0] = two * (qxz + qwy);
result[2][1] = two * (qyz - qwx);
result[2][2] = one - two * (qxx + qyy);
return result;
}
pub fn m4_cast(self) -> Matrix4<T> {
Matrix4x4::new_m3x3( self.m3_cast() )
}
pub fn angle(self) -> T {
self.w.acos() * T::from(2).unwrap()
}
pub fn axis(self) -> Vector3<T> {
let tmp1 = T::one() - self.w * self.w;
if tmp1 <= T::zero() {
return Vector3::new(T::zero(), T::zero(), T::one());
}
let tmp2 = T::one() / tmp1.sqrt();
return Vector3::new(self.x * tmp2, self.y * tmp2, self.z * tmp2);
}
pub fn lt(self, y:Quaternion<T>) -> Vector4b {
let mut result = Vector4b::new( false, false, false, false );
for i in 0..4 {
result[i] = self[i] < y[i];
}
return result;
}
pub fn le(self, y:Quaternion<T>) -> Vector4b {
let mut result = Vector4b::new( false, false, false, false );
for i in 0..4 {
result[i] = self[i] <= y[i];
}
return result;
}
pub fn gt(self, y:Quaternion<T>) -> Vector4b {
let mut result = Vector4b::new( false, false, false, false );
for i in 0..4 {
result[i] = self[i] > y[i];
}
return result;
}
pub fn ge(self, y:Quaternion<T>) -> Vector4b {
let mut result = Vector4b::new( false, false, false, false );
for i in 0..4 {
result[i] = self[i] >= y[i];
}
return result;
}
pub fn eq(self, y:Quaternion<T>) -> Vector4b {
let mut result = Vector4b::new( false, false, false, false );
for i in 0..4 {
result[i] = self[i] == y[i];
}
return result;
}
pub fn ne(self, y:Quaternion<T>) -> Vector4b {
let mut result = Vector4b::new( false, false, false, false );
for i in 0..4 {
result[i] = self[i] != y[i];
}
return result;
}
}