use angle::{Rad, acos};
use approx::ApproxEq;
use matrix::Matrix;
use matrix::{Matrix2, ToMatrix2};
use matrix::{Matrix3, ToMatrix3};
use num::{BaseNum, BaseFloat};
use point::{Point, Point2, Point3};
use quaternion::{Quaternion, ToQuaternion};
use ray::Ray;
use vector::{Vector, Vector2, Vector3};
pub trait Rotation<S: BaseNum, V: Vector<S>, P: Point<S, V>>: PartialEq + ApproxEq<S> + Sized {
fn identity() -> Self;
fn look_at(dir: &V, up: &V) -> Self;
fn between_vectors(a: &V, b: &V) -> Self;
fn rotate_vector(&self, vec: &V) -> V;
#[inline]
fn rotate_point(&self, point: &P) -> P {
Point::from_vec( &self.rotate_vector( &point.to_vec() ) )
}
#[inline]
fn rotate_ray(&self, ray: &Ray<S, P, V>) -> Ray<S, P,V> {
Ray::new(ray.origin.clone(), self.rotate_vector(&ray.direction))
}
fn concat(&self, other: &Self) -> Self;
fn invert(&self) -> Self;
#[inline]
fn concat_self(&mut self, other: &Self) {
*self = Rotation::concat(self, other);
}
#[inline]
fn invert_self(&mut self) {
*self = self.invert();
}
}
pub trait Rotation2<S>: Rotation<S, Vector2<S>, Point2<S>>
+ ToMatrix2<S>
+ ToBasis2<S> {
fn from_angle(theta: Rad<S>) -> Self;
}
pub trait Rotation3<S: BaseNum>: Rotation<S, Vector3<S>, Point3<S>>
+ ToMatrix3<S>
+ ToBasis3<S>
+ ToQuaternion<S>{
fn from_axis_angle(axis: &Vector3<S>, angle: Rad<S>) -> Self;
fn from_euler(x: Rad<S>, y: Rad<S>, z: Rad<S>) -> Self;
#[inline]
fn from_angle_x(theta: Rad<S>) -> Self {
Rotation3::from_axis_angle( &Vector3::unit_x(), theta )
}
#[inline]
fn from_angle_y(theta: Rad<S>) -> Self {
Rotation3::from_axis_angle( &Vector3::unit_y(), theta )
}
#[inline]
fn from_angle_z(theta: Rad<S>) -> Self {
Rotation3::from_axis_angle( &Vector3::unit_z(), theta )
}
}
#[derive(PartialEq, Copy, Clone, RustcEncodable, RustcDecodable)]
pub struct Basis2<S> {
mat: Matrix2<S>
}
impl<S: BaseFloat> Basis2<S> {
#[inline]
pub fn as_matrix2<'a>(&'a self) -> &'a Matrix2<S> { &self.mat }
}
pub trait ToBasis2<S: BaseFloat> {
fn to_rot2(&self) -> Basis2<S>;
}
impl<S: BaseFloat> ToBasis2<S> for Basis2<S> {
#[inline]
fn to_rot2(&self) -> Basis2<S> { self.clone() }
}
impl<S: BaseFloat> ToMatrix2<S> for Basis2<S> {
#[inline]
fn to_matrix2(&self) -> Matrix2<S> { self.mat.clone() }
}
impl<S: BaseFloat + 'static> Rotation<S, Vector2<S>, Point2<S>> for Basis2<S> {
#[inline]
fn identity() -> Basis2<S> { Basis2{ mat: Matrix2::identity() } }
#[inline]
fn look_at(dir: &Vector2<S>, up: &Vector2<S>) -> Basis2<S> {
Basis2 { mat: Matrix2::look_at(dir, up) }
}
#[inline]
fn between_vectors(a: &Vector2<S>, b: &Vector2<S>) -> Basis2<S> {
Rotation2::from_angle( acos(a.dot(b)) )
}
#[inline]
fn rotate_vector(&self, vec: &Vector2<S>) -> Vector2<S> { self.mat.mul_v(vec) }
#[inline]
fn concat(&self, other: &Basis2<S>) -> Basis2<S> { Basis2 { mat: self.mat.mul_m(&other.mat) } }
#[inline]
fn concat_self(&mut self, other: &Basis2<S>) { self.mat.mul_self_m(&other.mat); }
#[inline]
fn invert(&self) -> Basis2<S> { Basis2 { mat: self.mat.invert().unwrap() } }
#[inline]
fn invert_self(&mut self) { self.mat.invert_self(); }
}
impl<S: BaseFloat> ApproxEq<S> for Basis2<S> {
#[inline]
fn approx_eq_eps(&self, other: &Basis2<S>, epsilon: &S) -> bool {
self.mat.approx_eq_eps(&other.mat, epsilon)
}
}
impl<S: BaseFloat + 'static> Rotation2<S> for Basis2<S> {
fn from_angle(theta: Rad<S>) -> Basis2<S> { Basis2 { mat: Matrix2::from_angle(theta) } }
}
#[derive(PartialEq, Copy, Clone, RustcEncodable, RustcDecodable)]
pub struct Basis3<S> {
mat: Matrix3<S>
}
impl<S: BaseFloat> Basis3<S> {
#[inline]
pub fn from_quaternion(quaternion: &Quaternion<S>) -> Basis3<S> {
Basis3 { mat: quaternion.to_matrix3() }
}
#[inline]
pub fn as_matrix3<'a>(&'a self) -> &'a Matrix3<S> { &self.mat }
}
pub trait ToBasis3<S: BaseFloat> {
fn to_rot3(&self) -> Basis3<S>;
}
impl<S: BaseFloat> ToBasis3<S> for Basis3<S> {
#[inline]
fn to_rot3(&self) -> Basis3<S> { self.clone() }
}
impl<S: BaseFloat> ToMatrix3<S> for Basis3<S> {
#[inline]
fn to_matrix3(&self) -> Matrix3<S> { self.mat.clone() }
}
impl<S: BaseFloat + 'static> ToQuaternion<S> for Basis3<S> {
#[inline]
fn to_quaternion(&self) -> Quaternion<S> { self.mat.to_quaternion() }
}
impl<S: BaseFloat + 'static> Rotation<S, Vector3<S>, Point3<S>> for Basis3<S> {
#[inline]
fn identity() -> Basis3<S> { Basis3{ mat: Matrix3::identity() } }
#[inline]
fn look_at(dir: &Vector3<S>, up: &Vector3<S>) -> Basis3<S> {
Basis3 { mat: Matrix3::look_at(dir, up) }
}
#[inline]
fn between_vectors(a: &Vector3<S>, b: &Vector3<S>) -> Basis3<S> {
let q: Quaternion<S> = Rotation::between_vectors(a, b);
q.to_rot3()
}
#[inline]
fn rotate_vector(&self, vec: &Vector3<S>) -> Vector3<S> { self.mat.mul_v(vec) }
#[inline]
fn concat(&self, other: &Basis3<S>) -> Basis3<S> { Basis3 { mat: self.mat.mul_m(&other.mat) } }
#[inline]
fn concat_self(&mut self, other: &Basis3<S>) { self.mat.mul_self_m(&other.mat); }
#[inline]
fn invert(&self) -> Basis3<S> { Basis3 { mat: self.mat.invert().unwrap() } }
#[inline]
fn invert_self(&mut self) { self.mat.invert_self(); }
}
impl<S: BaseFloat> ApproxEq<S> for Basis3<S> {
#[inline]
fn approx_eq_eps(&self, other: &Basis3<S>, epsilon: &S) -> bool {
self.mat.approx_eq_eps(&other.mat, epsilon)
}
}
impl<S: BaseFloat + 'static> Rotation3<S> for Basis3<S> {
fn from_axis_angle(axis: &Vector3<S>, angle: Rad<S>) -> Basis3<S> {
Basis3 { mat: Matrix3::from_axis_angle(axis, angle) }
}
fn from_euler(x: Rad<S>, y: Rad<S>, z: Rad<S>) -> Basis3<S> {
Basis3 { mat: Matrix3::from_euler(x, y ,z) }
}
fn from_angle_x(theta: Rad<S>) -> Basis3<S> {
Basis3 { mat: Matrix3::from_angle_x(theta) }
}
fn from_angle_y(theta: Rad<S>) -> Basis3<S> {
Basis3 { mat: Matrix3::from_angle_y(theta) }
}
fn from_angle_z(theta: Rad<S>) -> Basis3<S> {
Basis3 { mat: Matrix3::from_angle_z(theta) }
}
}