// Copyright 2013-2014 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. //! Angle units for type-safe, self-documenting code. use std::fmt; use std::f64; use std::num::{cast, Float}; use approx::ApproxEq; use num::{BaseFloat, One, one, Zero, zero}; /// An angle, in radians #[deriving(Copy, Clone, PartialEq, PartialOrd, Hash, RustcEncodable, RustcDecodable, Rand)] pub struct Rad { pub s: S } /// An angle, in degrees #[deriving(Copy, Clone, PartialEq, PartialOrd, Hash, RustcEncodable, RustcDecodable, Rand)] pub struct Deg { pub s: S } /// Create a new angle, in radians #[inline] pub fn rad(s: S) -> Rad { Rad { s: s } } /// Create a new angle, in degrees #[inline] pub fn deg(s: S) -> Deg { Deg { s: s } } /// Represents types that can be converted to radians. pub trait ToRad { /// Convert this value to radians. fn to_rad(&self) -> Rad; } /// Represents types that can be converted to degrees. pub trait ToDeg { /// Convert this value to degrees. 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() } } /// Private utility functions for converting to/from scalars trait ScalarConv { fn from(s: S) -> Self; fn s<'a>(&'a self) -> &'a S; fn mut_s<'a>(&'a mut self) -> &'a mut S; } impl ScalarConv for Rad { #[inline] fn from(s: S) -> Rad { rad(s) } #[inline] fn s<'a>(&'a self) -> &'a S { &self.s } #[inline] fn mut_s<'a>(&'a mut self) -> &'a mut S { &mut self.s } } impl ScalarConv for Deg { #[inline] fn from(s: S) -> Deg { deg(s) } #[inline] fn s<'a>(&'a self) -> &'a S { &self.s } #[inline] fn mut_s<'a>(&'a mut self) -> &'a mut S { &mut self.s } } /// Operations on angles. pub trait Angle < S: BaseFloat > : Clone + Zero + PartialEq + PartialOrd + ApproxEq + Neg + ToRad + ToDeg + ScalarConv + fmt::Show { /// Create a new angle from any other valid angle. fn from>(theta: A) -> Self; /// Negate this angle, in-place. #[inline] fn neg_self(&mut self) { *self = -(*self).clone() } /// Add this angle with another, returning the new angle. #[inline] fn add_a(&self, other: Self) -> Self { ScalarConv::from(*self.s() + *other.s()) } /// Subtract another angle from this one, returning the new angle. #[inline] fn sub_a(&self, other: Self) -> Self { ScalarConv::from(*self.s() - *other.s()) } /// Divide this angle by another, returning the ratio. #[inline] fn div_a(&self, other: Self) -> S { *self.s() / *other.s() } /// Take the remainder of this angle with another. #[inline] fn rem_a(&self, other: Self) -> S { *self.s() % *other.s() } /// Multiply this angle by a scalar, returning the new angle. #[inline] fn mul_s(&self, s: S) -> Self { ScalarConv::from(*self.s() * s) } /// Divide this angle by a scalar, returing the new angle. #[inline] fn div_s(&self, s: S) -> Self { ScalarConv::from(*self.s() / s) } /// Take the remainder of this angle by a scalar, returning the new angle. #[inline] fn rem_s(&self, s: S) -> Self { ScalarConv::from(*self.s() % s) } /// Add this angle with another, in-place. #[inline] fn add_self_a(&mut self, other: Self) { *self.mut_s() = *self.s() + *other.s() } /// Subtract another angle from this one, in-place. #[inline] fn sub_self_a(&mut self, other: Self) { *self.mut_s() = *self.s() - *other.s() } /// Multiply this angle by a scalar, in-place. #[inline] fn mul_self_s(&mut self, s: S) { *self.mut_s() = *self.s() * s } /// Divide this angle by a scalar, in-place. #[inline] fn div_self_s(&mut self, s: S) { *self.mut_s() = *self.s() / s } /// Take the remainder of this angle by a scalar, in-place. #[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() } /// Returns the interior bisector of the two angles #[inline] fn bisect(&self, other: Self) -> Self { self.add_a(self.sub_a(other).mul_s(cast(0.5f64).unwrap())).normalize() } fn full_turn() -> Self; #[inline] fn turn_div_2() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(2i).unwrap()) } #[inline] fn turn_div_3() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(3i).unwrap()) } #[inline] fn turn_div_4() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(4i).unwrap()) } #[inline] fn turn_div_6() -> Self { let full_turn: Self = Angle::full_turn(); full_turn.div_s(cast(6i).unwrap()) } #[inline] fn equiv(&self, other: &Self) -> bool { self.normalize() == other.normalize() } } #[inline] pub fn bisect>(a: A, b: A) -> A { a.bisect(b) } 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 Add, Rad> for Rad { #[inline] fn add(self, other: Rad) -> Rad { rad(self.s + other.s) } } impl Add, Deg> for Deg { #[inline] fn add(self, other: Deg) -> Deg { deg(self.s + other.s) } } impl Sub, Rad> for Rad { #[inline] fn sub(self, other: Rad) -> Rad { rad(self.s - other.s) } } impl Sub, Deg> for Deg { #[inline] fn sub(self, other: Deg) -> Deg { deg(self.s - other.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) } } impl Zero for Rad { #[inline] fn zero() -> Rad { rad(zero()) } #[inline] fn is_zero(&self) -> bool { *self == zero() } } impl Zero for Deg { #[inline] fn zero() -> Deg { deg(zero()) } #[inline] fn is_zero(&self) -> bool { *self == zero() } } impl Mul, Rad> for Rad { #[inline] fn mul(self, other: Rad) -> Rad { rad(self.s * other.s) } } impl Mul, Deg> for Deg { #[inline] fn mul(self, other: Deg) -> Deg { deg(self.s * other.s) } } impl One for Rad { #[inline] fn one() -> Rad { rad(one()) } } impl One for Deg { #[inline] fn one() -> Deg { deg(one()) } } impl Angle for Rad { #[inline] fn from>(theta: A) -> Rad { theta.to_rad() } #[inline] fn full_turn() -> Rad { rad(cast(f64::consts::PI_2).unwrap()) } } impl Angle for Deg { #[inline] fn from>(theta: A) -> Deg { theta.to_deg() } #[inline] fn full_turn() -> Deg { deg(cast(360i).unwrap()) } } #[inline] pub fn sin(theta: Rad) -> S { theta.s.sin() } #[inline] pub fn cos(theta: Rad) -> S { theta.s.cos() } #[inline] pub fn tan(theta: Rad) -> S { theta.s.tan() } #[inline] pub fn sin_cos(theta: Rad) -> (S, S) { theta.s.sin_cos() } #[inline] pub fn cot(theta: Rad) -> S { tan(theta).recip() } #[inline] pub fn sec(theta: Rad) -> S { cos(theta).recip() } #[inline] pub fn csc(theta: Rad) -> S { sin(theta).recip() } #[inline] pub fn asin(s: S) -> Rad { rad(s.asin()) } #[inline] pub fn acos(s: S) -> Rad { rad(s.acos()) } #[inline] pub fn atan(s: S) -> Rad { rad(s.atan()) } #[inline] pub fn atan2(a: S, b: S) -> Rad { rad(a.atan2(b)) } impl fmt::Show for Rad { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{} rad", self.s) } } impl fmt::Show for Deg { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}°", self.s) } } impl ApproxEq for Rad { #[inline] fn approx_eq_eps(&self, other: &Rad, epsilon: &S) -> bool { self.s.approx_eq_eps(&other.s, epsilon) } } impl ApproxEq for Deg { #[inline] fn approx_eq_eps(&self, other: &Deg, epsilon: &S) -> bool { self.s.approx_eq_eps(&other.s, epsilon) } }