use core::cmp::{Eq, Ord}; use core::f64::consts::pi; use funs::triganomic::{cos, sin}; use mat::{Mat3, Mat4}; use num::cast::{NumCast, cast}; use quat::Quat; use vec::Vec3; /** * The base trait for anglular units */ pub trait Angle: Add , Sub , Mul , Div , Modulo , Neg , Eq, Ord { static pure fn full_turn() -> self; static pure fn half_turn() -> self; static pure fn quadrant() -> self; static pure fn sextant() -> self; static pure fn octant() -> self; pure fn to_radians(&self) -> Radians; pure fn to_degrees(&self) -> Degrees; pure fn wrap(&self) -> self; } pub enum Radians = T; pub impl Radians: Angle { #[inline(always)] static pure fn full_turn() -> Radians { Radians(move cast(2.0 * pi)) } // TODO: calculate absolute values #[inline(always)] static pure fn half_turn() -> Radians { Radians(move cast(pi)) } #[inline(always)] static pure fn quadrant() -> Radians { Radians(move cast(pi / 2.0)) } #[inline(always)] static pure fn sextant() -> Radians { Radians(move cast(pi / 3.0)) } #[inline(always)] static pure fn octant() -> Radians { Radians(move cast(pi / 4.0)) } #[inline(always)] pure fn to_radians(&self) -> Radians { *self } #[inline(always)] pure fn to_degrees(&self) -> Degrees { Degrees(**self * cast(180.0 / pi)) } #[inline(always)] pure fn wrap(&self) -> Radians { (*self) % cast(2.0 * pi) // TODO: keep in the domain of 0 to two_pi } } pub impl Radians: Add, Radians> { #[inline(always)] pure fn add(rhs: &Radians) -> Radians { Radians(*self + **rhs) } } pub impl Radians: Sub, Radians> { #[inline(always)] pure fn sub(&self, rhs: &Radians) -> Radians { Radians(**self - **rhs) } } pub impl Radians: Mul> { #[inline(always)] pure fn mul(&self, rhs: &T) -> Radians { Radians(**self * *rhs) } } pub impl Radians: Div> { #[inline(always)] pure fn div(&self, rhs: &T) -> Radians { Radians(**self / *rhs) } } pub impl Radians: Modulo> { #[inline(always)] pure fn modulo(&self, rhs: &T) -> Radians { Radians(**self % *rhs) } } pub impl Radians: Neg> { #[inline(always)] pure fn neg(&self) -> Radians { Radians(-**self) } } pub impl Radians: Eq { #[inline(always)] pure fn eq(&self, other: &Radians) -> bool { **self == **other } #[inline(always)] pure fn ne(&self, other: &Radians) -> bool { **self != **other } } pub impl Radians: Ord { #[inline(always)] pure fn lt(&self, other: &Radians) -> bool { **self < **other } #[inline(always)] pure fn le(&self, other: &Radians) -> bool { **self <= **other } #[inline(always)] pure fn ge(&self, other: &Radians) -> bool { **self >= **other } #[inline(always)] pure fn gt(&self, other: &Radians) -> bool { **self > **other } } pub impl Radians: ToStr { pure fn to_str() -> ~str { fmt!("%? rad", *self) } } pub enum Degrees = T; pub impl Degrees: Angle { #[inline(always)] static pure fn full_turn() -> Degrees { Degrees(move cast(360.0)) } #[inline(always)] static pure fn half_turn() -> Degrees { Degrees(move cast(180.0)) } #[inline(always)] static pure fn quadrant() -> Degrees { Degrees(move cast(90.0)) } #[inline(always)] static pure fn sextant() -> Degrees { Degrees(move cast(60.0)) } #[inline(always)] static pure fn octant() -> Degrees { Degrees(move cast(45.0)) } #[inline(always)] pure fn to_radians(&self) -> Radians { Radians(**self * cast(pi / 180.0)) } #[inline(always)] pure fn to_degrees(&self) -> Degrees { *self } #[inline(always)] pure fn wrap(&self) -> Degrees { (*self) % cast(360) // TODO: keep in the domain of 0 to 360 } } pub impl Degrees: Add, Degrees> { #[inline(always)] pure fn add(rhs: &Degrees) -> Degrees { Degrees(*self + **rhs) } } pub impl Degrees: Sub, Degrees> { #[inline(always)] pure fn sub(&self, rhs: &Degrees) -> Degrees { Degrees(**self - **rhs) } } pub impl Degrees: Mul> { #[inline(always)] pure fn mul(&self, rhs: &T) -> Degrees { Degrees(**self * *rhs) } } pub impl Degrees: Div> { #[inline(always)] pure fn div(&self, rhs: &T) -> Degrees { Degrees(**self / *rhs) } } pub impl Degrees: Modulo> { #[inline(always)] pure fn modulo(&self, rhs: &T) -> Degrees { Degrees(**self % *rhs) } } pub impl Degrees: Neg> { #[inline(always)] pure fn neg(&self) -> Degrees { Degrees(-**self) } } pub impl Degrees: Eq { #[inline(always)] pure fn eq(&self, other: &Degrees) -> bool { **self == **other } #[inline(always)] pure fn ne(&self, other: &Degrees) -> bool { **self != **other } } pub impl Degrees: Ord { #[inline(always)] pure fn lt(&self, other: &Degrees) -> bool { **self < **other } #[inline(always)] pure fn le(&self, other: &Degrees) -> bool { **self <= **other } #[inline(always)] pure fn ge(&self, other: &Degrees) -> bool { **self >= **other } #[inline(always)] pure fn gt(&self, other: &Degrees) -> bool { **self > **other } } pub impl Degrees: ToStr { pure fn to_str() -> ~str { fmt!("%?\xB0", *self) } } /** * An angular rotation around an arbitary axis */ pub struct Rotation { theta: Radians, axis: Vec3, } pub impl Rotation { #[inline(always)] static pure fn new(theta: Radians, axis: Vec3) -> Rotation { Rotation { theta: move theta, axis: move axis } } #[inline(always)] pure fn to_mat3() -> Mat3 { let c: T = cos(&self.theta); let s: T = sin(&self.theta); let _0: T = cast(0); let _1: T = cast(1); let t: T = _1 - c; let x = self.axis.x; let y = self.axis.y; let z = self.axis.z; Mat3::new(t * x * x + c, t * x * y + s * z, t * x * z - s * y, t * x * y - s * z, t * y * y + c, t * y * z + s * x, t * x * z - s - y, t * y * z - s * x, t * z * z + c) } #[inline(always)] pure fn to_mat4() -> Mat4 { self.to_mat3().to_mat4() } #[inline(always)] pure fn to_quat() -> Quat { let half = self.theta / cast(2); Quat::from_sv(cos(&half), self.axis.mul_t(sin(&half))) } } pub struct Euler { x: Radians, // pitch y: Radians, // yaw z: Radians, // roll }