diff --git a/src/cgmath/angle.rs b/src/cgmath/angle.rs index 43b6d42..83a479d 100644 --- a/src/cgmath/angle.rs +++ b/src/cgmath/angle.rs @@ -15,6 +15,7 @@ //! Angle units for type-safe, self-documenting code. +pub use std::num::{cast, zero}; pub use std::num::{sinh, cosh, tanh}; pub use std::num::{asinh, acosh, atanh}; @@ -23,20 +24,20 @@ use std::num::Zero; #[deriving(Clone, Eq, Ord, Zero)] pub struct Rad { s: S } #[deriving(Clone, Eq, Ord, Zero)] pub struct Deg { s: S } -#[inline] pub fn rad(s: S) -> Rad { Rad { s: s } } -#[inline] pub fn deg(s: S) -> Deg { Deg { s: s } } +#[inline] pub fn rad(s: S) -> Rad { Rad { s: s } } +#[inline] pub fn deg(s: S) -> Deg { Deg { s: s } } -pub trait ToRad { fn to_rad(&self) -> Rad; } -pub trait ToDeg { fn to_deg(&self) -> Deg; } +pub trait ToRad { fn to_rad(&self) -> Rad; } +pub trait ToDeg { fn to_deg(&self) -> Deg; } -impl ToRad for Rad { #[inline] fn to_rad(&self) -> Rad { self.clone() } } -impl ToRad for Deg { #[inline] fn to_rad(&self) -> Rad { rad(self.s.to_radians()) } } +impl ToRad for Rad { #[inline] fn to_rad(&self) -> Rad { self.clone() } } +impl ToRad for Deg { #[inline] fn to_rad(&self) -> Rad { rad(self.s.to_radians()) } } -impl ToDeg for Rad { #[inline] fn to_deg(&self) -> Deg { deg(self.s.to_degrees()) } } -impl ToDeg for Deg { #[inline] fn to_deg(&self) -> Deg { self.clone() } } +impl ToDeg for Rad { #[inline] fn to_deg(&self) -> Deg { deg(self.s.to_degrees()) } } +impl ToDeg for Deg { #[inline] fn to_deg(&self) -> Deg { self.clone() } } -impl Neg> for Rad { #[inline] fn neg(&self) -> Rad { rad(-self.s) } } -impl Neg> for Deg { #[inline] fn neg(&self) -> Deg { deg(-self.s) } } +impl Neg> for Rad { #[inline] fn neg(&self) -> Rad { rad(-self.s) } } +impl Neg> for Deg { #[inline] fn neg(&self) -> Deg { deg(-self.s) } } /// Private utility functions for converting to/from scalars trait ScalarConv { @@ -45,13 +46,13 @@ trait ScalarConv { fn mut_s<'a>(&'a mut self) -> &'a mut S; } -impl ScalarConv for Rad { +impl ScalarConv for Rad { #[inline] fn from(s: S) -> Rad { rad(s) } #[inline] fn s<'a>(&'a self) -> &'a S { &'a self.s } #[inline] fn mut_s<'a>(&'a mut self) -> &'a mut S { &'a mut self.s } } -impl ScalarConv for Deg { +impl ScalarConv for Deg { #[inline] fn from(s: S) -> Deg { deg(s) } #[inline] fn s<'a>(&'a self) -> &'a S { &'a self.s } #[inline] fn mut_s<'a>(&'a mut self) -> &'a mut S { &'a mut self.s } @@ -59,7 +60,7 @@ impl ScalarConv for Deg { pub trait Angle < - S: Clone + Float + S: Float > : Clone + Zero + Eq + Ord @@ -86,34 +87,83 @@ pub trait Angle #[inline] fn mul_self_s(&mut self, s: S) { *self.mut_s() = *self.s() * s } #[inline] fn div_self_s(&mut self, s: S) { *self.mut_s() = *self.s() / s } #[inline] fn rem_self_s(&mut self, s: S) { *self.mut_s() = *self.s() % s } + + /// Return the angle, normalized to the range `[0, full_turn)`. + #[inline] + fn normalize(&self) -> Self { + let mut a = self.clone(); + a.normalize_self(); + a + } + + /// Normalize the angle to the range `[0, full_turn)`. + #[inline] + fn normalize_self(&mut self) { + let full_turn: Self = Angle::full_turn(); + self.rem_self_s(full_turn.s().clone()); + if *self < zero() { self.add_self_a(full_turn) }; + } + + /// Return the angle rotated by half a turn + #[inline] + fn opposite(&self) -> Self { + self.add_a(Angle::turn_div_2()).normalize() + } + + fn full_turn() -> Self; + + #[inline] fn turn_div_2() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(2)) } + #[inline] fn turn_div_3() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(3)) } + #[inline] fn turn_div_4() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(4)) } + #[inline] fn turn_div_6() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(6)) } } -impl Angle for Rad { +impl Rad { + #[inline] pub fn zero() -> Rad { zero() } + #[inline] pub fn full_turn() -> Rad { Angle::full_turn() } + #[inline] pub fn turn_div_2() -> Rad { Angle::turn_div_2() } + #[inline] pub fn turn_div_3() -> Rad { Angle::turn_div_3() } + #[inline] pub fn turn_div_4() -> Rad { Angle::turn_div_4() } + #[inline] pub fn turn_div_6() -> Rad { Angle::turn_div_6() } +} + +impl Deg { + #[inline] pub fn zero() -> Deg { zero() } + #[inline] pub fn full_turn() -> Deg { Angle::full_turn() } + #[inline] pub fn turn_div_2() -> Deg { Angle::turn_div_2() } + #[inline] pub fn turn_div_3() -> Deg { Angle::turn_div_3() } + #[inline] pub fn turn_div_4() -> Deg { Angle::turn_div_4() } + #[inline] pub fn turn_div_6() -> Deg { Angle::turn_div_6() } +} + +impl Angle for Rad { #[inline] fn from>(theta: A) -> Rad { theta.to_rad() } + #[inline] fn full_turn() -> Rad { rad(Real::two_pi()) } } -impl Angle for Deg { +impl Angle for Deg { #[inline] fn from>(theta: A) -> Deg { theta.to_deg() } + #[inline] fn full_turn() -> Deg { deg(cast(360)) } } -#[inline] pub fn sin>(theta: A) -> S { theta.to_rad().s.sin() } -#[inline] pub fn cos>(theta: A) -> S { theta.to_rad().s.cos() } -#[inline] pub fn tan>(theta: A) -> S { theta.to_rad().s.tan() } -#[inline] pub fn sin_cos>(theta: A) -> (S, S) { theta.to_rad().s.sin_cos() } +#[inline] pub fn sin>(theta: A) -> S { theta.to_rad().s.sin() } +#[inline] pub fn cos>(theta: A) -> S { theta.to_rad().s.cos() } +#[inline] pub fn tan>(theta: A) -> S { theta.to_rad().s.tan() } +#[inline] pub fn sin_cos>(theta: A) -> (S, S) { theta.to_rad().s.sin_cos() } -#[inline] pub fn cot>(theta: A) -> S { tan(theta).recip() } -#[inline] pub fn sec>(theta: A) -> S { cos(theta).recip() } -#[inline] pub fn csc>(theta: A) -> S { sin(theta).recip() } +#[inline] pub fn cot>(theta: A) -> S { tan(theta).recip() } +#[inline] pub fn sec>(theta: A) -> S { cos(theta).recip() } +#[inline] pub fn csc>(theta: A) -> S { sin(theta).recip() } -#[inline] pub fn asin>(s: S) -> A { Angle::from(rad(s.asin())) } -#[inline] pub fn acos>(s: S) -> A { Angle::from(rad(s.acos())) } -#[inline] pub fn atan>(s: S) -> A { Angle::from(rad(s.atan())) } -#[inline] pub fn atan2>(a: S, b: S) -> A { Angle::from(rad(a.atan2(&b))) } +#[inline] pub fn asin>(s: S) -> A { Angle::from(rad(s.asin())) } +#[inline] pub fn acos>(s: S) -> A { Angle::from(rad(s.acos())) } +#[inline] pub fn atan>(s: S) -> A { Angle::from(rad(s.atan())) } +#[inline] pub fn atan2>(a: S, b: S) -> A { Angle::from(rad(a.atan2(&b))) } -impl ToStr for Rad { fn to_str(&self) -> ~str { fmt!("%? rad", self.s) } } -impl ToStr for Deg { fn to_str(&self) -> ~str { fmt!("%?°", self.s) } } +impl ToStr for Rad { fn to_str(&self) -> ~str { fmt!("%? rad", self.s) } } +impl ToStr for Deg { fn to_str(&self) -> ~str { fmt!("%?°", self.s) } } -impl ApproxEq for Rad { +impl ApproxEq for Rad { #[inline] fn approx_epsilon() -> S { // TODO: fix this after static methods are fixed in rustc @@ -131,7 +181,7 @@ impl ApproxEq for Rad { } } -impl ApproxEq for Deg { +impl ApproxEq for Deg { #[inline] fn approx_epsilon() -> S { // TODO: fix this after static methods are fixed in rustc diff --git a/src/cgmath/projection.rs b/src/cgmath/projection.rs index bcde1db..eafab5f 100644 --- a/src/cgmath/projection.rs +++ b/src/cgmath/projection.rs @@ -15,7 +15,7 @@ use std::num::{zero, one}; -use angle::{Angle, rad, tan, cot}; +use angle::{Angle, tan, cot}; use frustum::Frustum; use matrix::{Mat4, ToMat4}; use util::two; @@ -101,7 +101,7 @@ impl> Projection for PerspectiveFov { impl> ToMat4 for PerspectiveFov { fn to_mat4(&self) -> Mat4 { - let half_turn: A = Angle::from(rad::(Real::frac_pi_2())); + let half_turn: A = Angle::turn_div_2(); assert!(self.fovy < zero(), "The vertical field of view cannot be below zero, found: %?", self.fovy); assert!(self.fovy > half_turn, "The vertical field of view cannot be greater than a half turn, found: %?", self.fovy);