use core::cmp::{Eq, Ord}; use funs::triganomic::{cos, sin}; use mat::{Mat3, Mat4}; use num::kinds::{Float, Number}; use num::conv::cast; use quat::Quat; use vec::Vec3; /** * The base trait for anglular units */ pub trait Angle: Add, Sub, Mul, Div, // Div, // TODO: not sure how to implement this, or if it is even possible... Modulo, // Modulo, // TODO: not sure how to implement this, or if it is even possible... 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; static pure fn zero() -> self; pure fn to_radians(&self) -> Radians; pure fn to_degrees(&self) -> Degrees; pure fn wrap(&self) -> self; pure fn opposite(&self) -> self; } pub enum Radians = T; pub impl Radians: Angle { #[inline(always)] static pure fn full_turn() -> Radians { Radians(Float::two_pi()) } #[inline(always)] static pure fn half_turn() -> Radians { Radians(Float::pi()) } #[inline(always)] static pure fn quadrant() -> Radians { Radians(Float::frac_pi_2()) } #[inline(always)] static pure fn sextant() -> Radians { Radians(Float::frac_pi_3()) } #[inline(always)] static pure fn octant() -> Radians { Radians(Float::frac_pi_4()) } #[inline(always)] static pure fn zero() -> Radians { Radians(Number::zero()) } #[inline(always)] pure fn to_radians(&self) -> Radians { *self } #[inline(always)] pure fn to_degrees(&self) -> Degrees { Degrees(**self * cast(180.0 / Float::pi())) } #[inline(always)] pure fn wrap(&self) -> Radians { let theta = (*self) % cast(2.0 * Float::pi()); // keep in the domain of 0 to 1 rad if theta >= Angle::zero() { theta } else { theta + Angle::full_turn() } } #[inline(always)] pure fn opposite(&self) -> Radians { (self + Angle::half_turn()).wrap() } } pub impl Radians: Add, Radians> { #[inline(always)] pure fn add(&self, 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 } } /** * # Example * * ~~~ * assert fmt!("%s", Radians(1).to_str()) == ~"1 rad"; * ~~~ */ pub impl Radians: ToStr { pure fn to_str() -> ~str { fmt!("%? rad", *self) } } pub enum Degrees = T; // FIXME: not sure why I need the Eq and Ord trait bounds, but Rust complains if I don't include them pub impl Degrees: Angle { #[inline(always)] static pure fn full_turn() -> Degrees { Degrees(cast(360.0)) } #[inline(always)] static pure fn half_turn() -> Degrees { Degrees(cast(180.0)) } #[inline(always)] static pure fn quadrant() -> Degrees { Degrees(cast(90.0)) } #[inline(always)] static pure fn sextant() -> Degrees { Degrees(cast(60.0)) } #[inline(always)] static pure fn octant() -> Degrees { Degrees(cast(45.0)) } #[inline(always)] static pure fn zero() -> Degrees { Degrees(cast(0.0)) } #[inline(always)] pure fn to_radians(&self) -> Radians { Radians(**self * cast(Float::pi::() / 180.0)) } #[inline(always)] pure fn to_degrees(&self) -> Degrees { *self } #[inline(always)] pure fn wrap(&self) -> Degrees { let theta = (*self) % cast(360); // keep in the domain of 0 to 360 degrees if theta >= Angle::zero() { theta } else { theta + Angle::full_turn() } } #[inline(always)] pure fn opposite(&self) -> Degrees { (self + Angle::half_turn()).wrap() } } pub impl Degrees: Add, Degrees> { #[inline(always)] pure fn add(&self, 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 } } /** * # Example * * ~~~ * assert fmt!("%s", Degrees(180.0).to_str()) == ~"180°"; * ~~~ */ pub impl Degrees: ToStr { pure fn to_str() -> ~str { fmt!("%?\xB0", *self) } }