From 37826e56bca0151b73f849741f27de0685fb3940 Mon Sep 17 00:00:00 2001 From: Brendan Zabarauskas Date: Wed, 4 Sep 2013 12:20:53 +1000 Subject: [PATCH] Add angle unit types --- src/cgmath/angle.rs | 144 ++++++++++++++++++++++++++++++++++++++++++++ src/cgmath/lib.rs | 3 +- 2 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 src/cgmath/angle.rs diff --git a/src/cgmath/angle.rs b/src/cgmath/angle.rs new file mode 100644 index 0000000..be3fce5 --- /dev/null +++ b/src/cgmath/angle.rs @@ -0,0 +1,144 @@ +// Copyright 2013 The CGMath Developers. For a full listing of the authors, +// refer to the AUTHORS file at the top-level directory of this distribution. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::num::Zero; + +#[deriving(Clone, Eq, Ord, Zero)] struct Rad { s: S } +#[deriving(Clone, Eq, Ord, Zero)] struct 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; } + +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 Neg> for Rad { #[inline] fn neg(&self) -> Rad { rad(-self.s) } } +impl Neg> for Deg { #[inline] fn neg(&self) -> Deg { deg(-self.s) } } + +pub trait Angle +< + S: Clone + Float +> +: Clone + Zero ++ Eq + Ord ++ ApproxEq ++ Neg ++ ToRad ++ ToDeg +{ + fn from_s(s: S) -> Self; + fn from>(theta: A) -> Self; + fn s<'a>(&'a self) -> &'a S; + fn mut_s<'a>(&'a mut self) -> &'a mut S; + + #[inline] fn neg_self(&mut self) { *self = -*self } + + #[inline] fn add_a(&self, other: Self) -> Self { Angle::from_s(*self.s() + *other.s()) } + #[inline] fn sub_a(&self, other: Self) -> Self { Angle::from_s(*self.s() - *other.s()) } + #[inline] fn div_a(&self, other: Self) -> S { *self.s() / *other.s() } + #[inline] fn rem_a(&self, other: Self) -> S { *self.s() % *other.s() } + #[inline] fn mul_s(&self, s: S) -> Self { Angle::from_s(*self.s() * s) } + #[inline] fn div_s(&self, s: S) -> Self { Angle::from_s(*self.s() / s) } + #[inline] fn rem_s(&self, s: S) -> Self { Angle::from_s(*self.s() % s) } + + #[inline] fn add_self_a(&mut self, other: Self) { *self.mut_s() = *self.s() + *other.s() } + #[inline] fn sub_self_a(&mut self, other: Self) { *self.mut_s() = *self.s() - *other.s() } + #[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 } + + #[inline] fn sin(&self) -> S { self.s().sin() } + #[inline] fn cos(&self) -> S { self.s().cos() } + #[inline] fn tan(&self) -> S { self.s().tan() } +} + +#[inline] fn sin>(theta: A) -> S { theta.sin() } +#[inline] fn cos>(theta: A) -> S { theta.cos() } +#[inline] fn tan>(theta: A) -> S { theta.tan() } + +impl Angle for Rad { + #[inline] fn from_s(s: S) -> Rad { rad(s) } + #[inline] fn from>(theta: A) -> Rad { theta.to_rad() } + #[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 Angle for Deg { + #[inline] fn from_s(s: S) -> Deg { deg(s) } + #[inline] fn from>(theta: A) -> Deg { theta.to_deg() } + #[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 } +} + +pub trait ScalarTrig: Clone + Float { + #[inline] fn asin_>(&self) -> A { Angle::from(rad(self.asin())) } + #[inline] fn acos_>(&self) -> A { Angle::from(rad(self.acos())) } + #[inline] fn atan_>(&self) -> A { Angle::from(rad(self.atan())) } + #[inline] fn atan2_>(&self, other: &Self) -> A { Angle::from(rad(self.atan2(other))) } +} + +#[inline] fn asin>(s: S) -> A { s.asin_() } +#[inline] fn acos>(s: S) -> A { s.acos_() } +#[inline] fn atan>(s: S) -> A { s.atan_() } +#[inline] fn atan2>(a: S, b: S) -> A { a.atan2_(&b) } + +impl ScalarTrig for f32; +impl ScalarTrig for f64; +impl ScalarTrig for float; + +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 { + #[inline] + fn approx_epsilon() -> S { + // TODO: fix this after static methods are fixed in rustc + fail!(~"Doesn't work!"); + } + + #[inline] + fn approx_eq(&self, other: &Rad) -> bool { + self.s.approx_eq(&other.s) + } + + #[inline] + fn approx_eq_eps(&self, other: &Rad, approx_epsilon: &S) -> bool { + self.s.approx_eq_eps(&other.s, approx_epsilon) + } +} + +impl ApproxEq for Deg { + #[inline] + fn approx_epsilon() -> S { + // TODO: fix this after static methods are fixed in rustc + fail!(~"Doesn't work!"); + } + + #[inline] + fn approx_eq(&self, other: &Deg) -> bool { + self.s.approx_eq(&other.s) + } + + #[inline] + fn approx_eq_eps(&self, other: &Deg, approx_epsilon: &S) -> bool { + self.s.approx_eq_eps(&other.s, approx_epsilon) + } +} diff --git a/src/cgmath/lib.rs b/src/cgmath/lib.rs index eace56f..d876b0f 100644 --- a/src/cgmath/lib.rs +++ b/src/cgmath/lib.rs @@ -24,10 +24,11 @@ pub mod array; pub mod matrix; -pub mod point; pub mod quaternion; pub mod vector; +pub mod angle; +pub mod point; pub mod ray; pub mod projection;