cgmath/src/angle.rs

235 lines
8.5 KiB
Rust
Raw Normal View History

2014-05-26 17:10:04 +00:00
// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors,
2015-03-14 02:49:46 +00:00
// refer to the Cargo.toml file at the top-level directory of this distribution.
2013-09-04 02:20:53 +00:00
//
// 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.
2013-10-19 14:00:44 +00:00
use std::fmt;
use std::f64;
2015-01-03 21:29:26 +00:00
use std::ops::*;
2013-09-04 02:20:53 +00:00
2015-03-15 02:53:57 +00:00
use rand::{Rand, Rng};
use rand::distributions::range::SampleRange;
use rust_num::{Float, Zero};
2015-04-25 03:28:31 +00:00
use rust_num::traits::cast;
2015-04-05 01:19:11 +00:00
2014-01-09 00:26:50 +00:00
use approx::ApproxEq;
2015-04-05 01:19:11 +00:00
use num::BaseFloat;
2014-01-09 00:26:50 +00:00
2014-05-25 10:00:52 +00:00
/// An angle, in radians
#[derive(Copy, Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)]
pub struct Rad<S> { pub s: S }
2014-05-25 10:00:52 +00:00
/// An angle, in degrees
#[derive(Copy, Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)]
pub struct Deg<S> { pub s: S }
2013-09-04 02:20:53 +00:00
2014-05-25 10:00:52 +00:00
/// Create a new angle, in radians
2014-05-26 17:10:04 +00:00
#[inline] pub fn rad<S: BaseFloat>(s: S) -> Rad<S> { Rad { s: s } }
2014-05-25 10:00:52 +00:00
/// Create a new angle, in degrees
2014-05-26 17:10:04 +00:00
#[inline] pub fn deg<S: BaseFloat>(s: S) -> Deg<S> { Deg { s: s } }
2013-09-04 02:20:53 +00:00
2015-05-06 08:10:26 +00:00
impl<S> From<Rad<S>> for Deg<S> where S: BaseFloat {
2015-04-05 01:32:12 +00:00
#[inline]
2015-05-06 08:10:26 +00:00
fn from(r: Rad<S>) -> Deg<S> {
deg(r.s * cast(180.0 / f64::consts::PI).unwrap())
2015-04-05 01:32:12 +00:00
}
}
2013-09-04 02:20:53 +00:00
2015-05-06 08:10:26 +00:00
impl<S> From<Deg<S>> for Rad<S> where S: BaseFloat {
2015-04-05 01:32:12 +00:00
#[inline]
2015-05-06 08:10:26 +00:00
fn from(d: Deg<S>) -> Rad<S> {
rad(d.s * cast(f64::consts::PI / 180.0).unwrap())
2015-04-05 01:32:12 +00:00
}
}
2013-09-04 02:20:53 +00:00
/// Private utility functions for converting to/from scalars
trait ScalarConv<S> {
fn from(s: S) -> Self;
fn s<'a>(&'a self) -> &'a S;
fn mut_s<'a>(&'a mut self) -> &'a mut S;
}
2014-05-26 17:10:04 +00:00
impl<S: BaseFloat> ScalarConv<S> for Rad<S> {
#[inline] fn from(s: S) -> Rad<S> { 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 }
}
2014-05-26 17:10:04 +00:00
impl<S: BaseFloat> ScalarConv<S> for Deg<S> {
#[inline] fn from(s: S) -> Deg<S> { 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 }
}
2014-05-25 10:00:52 +00:00
/// Operations on angles.
pub trait Angle where
Self: Copy + Clone,
Self: PartialEq + PartialOrd,
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
Self: ApproxEq<Epsilon = <Self as Angle>::Unitless>,
Self: Into<Rad<<Self as Angle>::Unitless>>,
Self: Into<Deg<<Self as Angle>::Unitless>>,
Self: ScalarConv<<Self as Angle>::Unitless>,
Self: fmt::Debug,
2015-12-13 05:15:37 +00:00
Self: Neg<Output = Self>,
Self: Add<Self, Output = Self>,
Self: Sub<Self, Output = Self>,
Self: Div<Self, Output = <Self as Angle>::Unitless>,
Self: Rem<Self, Output = <Self as Angle>::Unitless>,
Self: Mul<<Self as Angle>::Unitless, Output = Self>,
Self: Div<<Self as Angle>::Unitless, Output = Self>,
Self: Rem<<Self as Angle>::Unitless, Output = Self>,
2013-09-04 02:20:53 +00:00
{
type Unitless: BaseFloat;
2014-05-25 10:00:52 +00:00
/// Create a new angle from any other valid angle.
fn from<A: Angle<Unitless = Self::Unitless>>(theta: A) -> Self;
2013-09-04 02:20:53 +00:00
/// Return the angle, normalized to the range `[0, full_turn)`.
2015-12-13 07:13:11 +00:00
fn normalize(self) -> Self;
/// Return the angle rotated by half a turn
#[inline]
2015-12-13 05:15:37 +00:00
fn opposite(self) -> Self {
Self::normalize(self + Self::turn_div_2())
}
2013-09-17 06:40:29 +00:00
/// Returns the interior bisector of the two angles
#[inline]
2015-12-13 05:15:37 +00:00
fn bisect(self, other: Self) -> Self {
let half = cast(0.5f64).unwrap();
Self::normalize((self - other) * half + self)
2013-09-17 06:40:29 +00:00
}
fn zero() -> Self;
fn full_turn() -> Self;
2015-12-13 05:15:37 +00:00
fn turn_div_2() -> Self;
fn turn_div_3() -> Self;
fn turn_div_4() -> Self;
fn turn_div_6() -> Self;
2015-12-13 05:15:37 +00:00
#[inline]
fn equiv(&self, other: &Self) -> bool {
self.normalize() == other.normalize()
}
}
#[inline] pub fn bisect<A: Angle>(a: A, b: A) -> A { a.bisect(b) }
2013-09-17 06:40:29 +00:00
#[inline] pub fn sin<S: BaseFloat, R: Into<Rad<S>>>(theta: R) -> S { theta.into().s.sin() }
#[inline] pub fn cos<S: BaseFloat, R: Into<Rad<S>>>(theta: R) -> S { theta.into().s.cos() }
#[inline] pub fn tan<S: BaseFloat, R: Into<Rad<S>>>(theta: R) -> S { theta.into().s.tan() }
#[inline] pub fn sin_cos<S: BaseFloat, R: Into<Rad<S>>>(theta: R) -> (S, S) { theta.into().s.sin_cos() }
#[inline] pub fn cot<S: BaseFloat, R: Into<Rad<S>>>(theta: R) -> S { tan(theta.into()).recip() }
#[inline] pub fn sec<S: BaseFloat, R: Into<Rad<S>>>(theta: R) -> S { cos(theta.into()).recip() }
#[inline] pub fn csc<S: BaseFloat, R: Into<Rad<S>>>(theta: R) -> S { sin(theta.into()).recip() }
#[inline] pub fn asin<S: BaseFloat, R: From<Rad<S>>>(s: S) -> R { rad(s.asin()).into() }
#[inline] pub fn acos<S: BaseFloat, R: From<Rad<S>>>(s: S) -> R { rad(s.acos()).into() }
#[inline] pub fn atan<S: BaseFloat, R: From<Rad<S>>>(s: S) -> R { rad(s.atan()).into() }
#[inline] pub fn atan2<S: BaseFloat, R: From<Rad<S>>>(a: S, b: S) -> R { rad(a.atan2(b)).into() }
2013-09-04 02:20:53 +00:00
macro_rules! impl_angle {
($Angle:ident, $fmt:expr, $full_turn:expr, $hi:expr) => {
impl<S: BaseFloat> Angle for $Angle<S> {
type Unitless = S;
#[inline]
fn zero() -> $Angle<S> { ScalarConv::from(S::zero()) }
#[inline]
fn from<A: Angle<Unitless = S>>(theta: A) -> $Angle<S> { theta.into() }
2015-12-13 07:13:11 +00:00
#[inline]
fn normalize(self) -> Self {
let tmp = self % Self::full_turn().s;
if tmp < Self::zero() { tmp + Self::full_turn() } else { tmp }
}
2015-12-13 05:15:37 +00:00
#[inline] fn full_turn() -> $Angle<S> { ScalarConv::from(cast($full_turn).unwrap()) }
#[inline] fn turn_div_2() -> $Angle<S> { let factor: S = cast(2).unwrap(); $Angle::full_turn() / factor }
#[inline] fn turn_div_3() -> $Angle<S> { let factor: S = cast(3).unwrap(); $Angle::full_turn() / factor }
#[inline] fn turn_div_4() -> $Angle<S> { let factor: S = cast(4).unwrap(); $Angle::full_turn() / factor }
#[inline] fn turn_div_6() -> $Angle<S> { let factor: S = cast(6).unwrap(); $Angle::full_turn() / factor }
}
impl<S: BaseFloat> Neg for $Angle<S> {
type Output = $Angle<S>;
#[inline]
fn neg(self) -> $Angle<S> { ScalarConv::from(-self.s) }
}
impl<'a, S: BaseFloat> Neg for &'a $Angle<S> {
type Output = $Angle<S>;
#[inline]
fn neg(self) -> $Angle<S> { ScalarConv::from(-self.s) }
}
impl_binary_operator!(<S: BaseFloat> Add<$Angle<S> > for $Angle<S> {
fn add(lhs, rhs) -> $Angle<S> { ScalarConv::from(lhs.s + rhs.s) }
});
impl_binary_operator!(<S: BaseFloat> Sub<$Angle<S> > for $Angle<S> {
fn sub(lhs, rhs) -> $Angle<S> { ScalarConv::from(lhs.s - rhs.s) }
});
impl_binary_operator!(<S: BaseFloat> Div<$Angle<S> > for $Angle<S> {
fn div(lhs, rhs) -> S { lhs.s / rhs.s }
});
impl_binary_operator!(<S: BaseFloat> Rem<$Angle<S> > for $Angle<S> {
fn rem(lhs, rhs) -> S { lhs.s % rhs.s }
});
impl_binary_operator!(<S: BaseFloat> Mul<S> for $Angle<S> {
fn mul(lhs, scalar) -> $Angle<S> { ScalarConv::from(lhs.s * scalar) }
});
impl_binary_operator!(<S: BaseFloat> Div<S> for $Angle<S> {
fn div(lhs, scalar) -> $Angle<S> { ScalarConv::from(lhs.s / scalar) }
});
impl_binary_operator!(<S: BaseFloat> Rem<S> for $Angle<S> {
fn rem(lhs, scalar) -> $Angle<S> { ScalarConv::from(lhs.s % scalar) }
});
impl<S: BaseFloat> ApproxEq for $Angle<S> {
type Epsilon = S;
#[inline]
fn approx_eq_eps(&self, other: &$Angle<S>, epsilon: &S) -> bool {
self.s.approx_eq_eps(&other.s, epsilon)
}
}
impl<S: BaseFloat + SampleRange> Rand for $Angle<S> {
#[inline]
fn rand<R: Rng>(rng: &mut R) -> $Angle<S> {
2015-12-13 07:13:11 +00:00
ScalarConv::from(rng.gen_range(cast(-$hi).unwrap(), cast($hi).unwrap()))
}
}
impl<S: BaseFloat> fmt::Debug for $Angle<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, $fmt, self.s)
}
}
}
}
2013-09-04 02:20:53 +00:00
impl_angle!(Rad, "{:?} rad", f64::consts::PI * 2.0, f64::consts::PI);
impl_angle!(Deg, "{:?}°", 360, 180);