commit
84c2c0ff8a
3 changed files with 161 additions and 33 deletions
|
@ -21,11 +21,13 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
formatting.
|
formatting.
|
||||||
- Marks vectors, points, matrices, and angles as `#[repr(C, packed)]`.
|
- Marks vectors, points, matrices, and angles as `#[repr(C, packed)]`.
|
||||||
- Renames the `Vector::{length, length2}` functions to `Vector::{magnitude, magnitude2}`.
|
- Renames the `Vector::{length, length2}` functions to `Vector::{magnitude, magnitude2}`.
|
||||||
|
- Moved `Angle::new` to be directly implemented on the `Rad` and `Deg` types.
|
||||||
|
|
||||||
### Removed
|
### Removed
|
||||||
|
|
||||||
- The non-mathematical operator trait implementations have been removed from
|
- The non-mathematical operator trait implementations have been removed from
|
||||||
the `Vector` trait, in favor of the `ElementWise` trait.
|
the `Vector` trait, in favor of the `ElementWise` trait.
|
||||||
|
- `Angle::equiv`.
|
||||||
|
|
||||||
## [v0.7.0] - 2015-12-23
|
## [v0.7.0] - 2015-12-23
|
||||||
|
|
||||||
|
|
179
src/angle.rs
179
src/angle.rs
|
@ -34,6 +34,7 @@ use num::BaseFloat;
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
#[derive(Copy, Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)]
|
#[derive(Copy, Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)]
|
||||||
pub struct Rad<S> { pub s: S }
|
pub struct Rad<S> { pub s: S }
|
||||||
|
|
||||||
/// An angle, in degrees.
|
/// An angle, in degrees.
|
||||||
///
|
///
|
||||||
/// This type is marked as `#[repr(C, packed)]`.
|
/// This type is marked as `#[repr(C, packed)]`.
|
||||||
|
@ -60,7 +61,12 @@ impl<S> From<Deg<S>> for Rad<S> where S: BaseFloat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Operations on angles.
|
/// Angles and their associated trigonometric functions.
|
||||||
|
///
|
||||||
|
/// Typed angles allow for the writing of self-documenting code that makes it
|
||||||
|
/// clear when semantic violations have occured - for example, adding degrees to
|
||||||
|
/// radians, or adding a number to an angle.
|
||||||
|
///
|
||||||
pub trait Angle where
|
pub trait Angle where
|
||||||
Self: Copy + Clone,
|
Self: Copy + Clone,
|
||||||
Self: PartialEq + PartialOrd,
|
Self: PartialEq + PartialOrd,
|
||||||
|
@ -77,9 +83,6 @@ pub trait Angle where
|
||||||
{
|
{
|
||||||
type Unitless: BaseFloat;
|
type Unitless: BaseFloat;
|
||||||
|
|
||||||
/// Create an angle from a unitless value.
|
|
||||||
fn new(value: Self::Unitless) -> Self;
|
|
||||||
|
|
||||||
/// Return the angle, normalized to the range `[0, full_turn)`.
|
/// Return the angle, normalized to the range `[0, full_turn)`.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn normalize(self) -> Self {
|
fn normalize(self) -> Self {
|
||||||
|
@ -87,55 +90,189 @@ pub trait Angle where
|
||||||
if rem < Self::zero() { rem + Self::full_turn() } else { rem }
|
if rem < Self::zero() { rem + Self::full_turn() } else { rem }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the angle rotated by half a turn
|
/// Return the angle rotated by half a turn.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn opposite(self) -> Self {
|
fn opposite(self) -> Self {
|
||||||
Self::normalize(self + Self::turn_div_2())
|
Self::normalize(self + Self::turn_div_2())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the interior bisector of the two angles
|
/// Returns the interior bisector of the two angles.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn bisect(self, other: Self) -> Self {
|
fn bisect(self, other: Self) -> Self {
|
||||||
let half = cast(0.5f64).unwrap();
|
let half = cast(0.5f64).unwrap();
|
||||||
Self::normalize((self - other) * half + self)
|
Self::normalize((self - other) * half + self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The additive identity.
|
||||||
|
///
|
||||||
|
/// Adding this to another angle has no affect.
|
||||||
|
///
|
||||||
|
/// For example:
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use cgmath::prelude::*;
|
||||||
|
/// use cgmath::Deg;
|
||||||
|
///
|
||||||
|
/// let v = Deg::new(180.0);
|
||||||
|
/// assert_eq!(v + Deg::zero(), v);
|
||||||
|
/// ```
|
||||||
fn zero() -> Self;
|
fn zero() -> Self;
|
||||||
|
|
||||||
|
/// A full rotation.
|
||||||
fn full_turn() -> Self;
|
fn full_turn() -> Self;
|
||||||
|
|
||||||
|
/// Half of a full rotation.
|
||||||
fn turn_div_2() -> Self;
|
fn turn_div_2() -> Self;
|
||||||
|
|
||||||
|
/// A third of a full rotation.
|
||||||
fn turn_div_3() -> Self;
|
fn turn_div_3() -> Self;
|
||||||
|
|
||||||
|
/// A quarter of a full rotation.
|
||||||
fn turn_div_4() -> Self;
|
fn turn_div_4() -> Self;
|
||||||
|
|
||||||
|
/// A sixth of a full rotation.
|
||||||
fn turn_div_6() -> Self;
|
fn turn_div_6() -> Self;
|
||||||
|
|
||||||
#[inline]
|
/// Compute the sine of the angle, returning a unitless ratio.
|
||||||
fn equiv(&self, other: &Self) -> bool {
|
///
|
||||||
self.normalize() == other.normalize()
|
/// ```rust
|
||||||
}
|
/// use cgmath::prelude::*;
|
||||||
|
/// use cgmath::Rad;
|
||||||
|
///
|
||||||
|
/// let angle = Rad::new(35.0);
|
||||||
|
/// let ratio: f32 = Rad::sin(angle);
|
||||||
|
/// ```
|
||||||
fn sin(self) -> Self::Unitless;
|
fn sin(self) -> Self::Unitless;
|
||||||
|
|
||||||
|
/// Compute the cosine of the angle, returning a unitless ratio.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use cgmath::prelude::*;
|
||||||
|
/// use cgmath::Rad;
|
||||||
|
///
|
||||||
|
/// let angle = Rad::new(35.0);
|
||||||
|
/// let ratio: f32 = Rad::cos(angle);
|
||||||
|
/// ```
|
||||||
fn cos(self) -> Self::Unitless;
|
fn cos(self) -> Self::Unitless;
|
||||||
|
|
||||||
|
/// Compute the tangent of the angle, returning a unitless ratio.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use cgmath::prelude::*;
|
||||||
|
/// use cgmath::Rad;
|
||||||
|
///
|
||||||
|
/// let angle = Rad::new(35.0);
|
||||||
|
/// let ratio: f32 = Rad::tan(angle);
|
||||||
|
/// ```
|
||||||
fn tan(self) -> Self::Unitless;
|
fn tan(self) -> Self::Unitless;
|
||||||
|
|
||||||
|
/// Compute the sine and cosine of the angle, returning the result as a
|
||||||
|
/// pair.
|
||||||
|
///
|
||||||
|
/// This does not have any performance benefits, but calculating both the
|
||||||
|
/// sine and cosine of a single angle is a common operation.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use cgmath::prelude::*;
|
||||||
|
/// use cgmath::Rad;
|
||||||
|
///
|
||||||
|
/// let angle = Rad::new(35.0);
|
||||||
|
/// let (s, c) = Rad::sin_cos(angle);
|
||||||
|
/// ```
|
||||||
fn sin_cos(self) -> (Self::Unitless, Self::Unitless);
|
fn sin_cos(self) -> (Self::Unitless, Self::Unitless);
|
||||||
|
|
||||||
#[inline] fn cot(self) -> Self::Unitless { Self::tan(self).recip() }
|
/// Compute the cosecant of the angle.
|
||||||
#[inline] fn sec(self) -> Self::Unitless { Self::cos(self).recip() }
|
///
|
||||||
#[inline] fn csc(self) -> Self::Unitless { Self::sin(self).recip() }
|
/// This is the same as computing the reciprocal of `Self::sin`.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use cgmath::prelude::*;
|
||||||
|
/// use cgmath::Rad;
|
||||||
|
///
|
||||||
|
/// let angle = Rad::new(35.0);
|
||||||
|
/// let ratio: f32 = Rad::csc(angle);
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
fn csc(self) -> Self::Unitless {
|
||||||
|
Self::sin(self).recip()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute the secant of the angle.
|
||||||
|
///
|
||||||
|
/// This is the same as computing the reciprocal of `Self::tan`.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use cgmath::prelude::*;
|
||||||
|
/// use cgmath::Rad;
|
||||||
|
///
|
||||||
|
/// let angle = Rad::new(35.0);
|
||||||
|
/// let ratio: f32 = Rad::cot(angle);
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
fn cot(self) -> Self::Unitless {
|
||||||
|
Self::tan(self).recip()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute the cotatangent of the angle.
|
||||||
|
///
|
||||||
|
/// This is the same as computing the reciprocal of `Self::cos`.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use cgmath::prelude::*;
|
||||||
|
/// use cgmath::Rad;
|
||||||
|
///
|
||||||
|
/// let angle = Rad::new(35.0);
|
||||||
|
/// let ratio: f32 = Rad::sec(angle);
|
||||||
|
/// ```
|
||||||
|
#[inline]
|
||||||
|
fn sec(self) -> Self::Unitless {
|
||||||
|
Self::cos(self).recip()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute the arcsine of the ratio, returning the resulting angle.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use cgmath::prelude::*;
|
||||||
|
/// use cgmath::Rad;
|
||||||
|
///
|
||||||
|
/// let angle: Rad<f32> = Rad::asin(0.5);
|
||||||
|
/// ```
|
||||||
|
fn asin(ratio: Self::Unitless) -> Self;
|
||||||
|
|
||||||
|
/// Compute the arccosine of the ratio, returning the resulting angle.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use cgmath::prelude::*;
|
||||||
|
/// use cgmath::Rad;
|
||||||
|
///
|
||||||
|
/// let angle: Rad<f32> = Rad::acos(0.5);
|
||||||
|
/// ```
|
||||||
|
fn acos(ratio: Self::Unitless) -> Self;
|
||||||
|
|
||||||
|
/// Compute the arctangent of the ratio, returning the resulting angle.
|
||||||
|
///
|
||||||
|
/// ```rust
|
||||||
|
/// use cgmath::prelude::*;
|
||||||
|
/// use cgmath::Rad;
|
||||||
|
///
|
||||||
|
/// let angle: Rad<f32> = Rad::atan(0.5);
|
||||||
|
/// ```
|
||||||
|
fn atan(ratio: Self::Unitless) -> Self;
|
||||||
|
|
||||||
fn asin(a: Self::Unitless) -> Self;
|
|
||||||
fn acos(a: Self::Unitless) -> Self;
|
|
||||||
fn atan(a: Self::Unitless) -> Self;
|
|
||||||
fn atan2(a: Self::Unitless, b: Self::Unitless) -> Self;
|
fn atan2(a: Self::Unitless, b: Self::Unitless) -> Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! impl_angle {
|
macro_rules! impl_angle {
|
||||||
($Angle:ident, $fmt:expr, $full_turn:expr, $hi:expr) => {
|
($Angle:ident, $fmt:expr, $full_turn:expr, $hi:expr) => {
|
||||||
impl<S: BaseFloat> Angle for $Angle<S> {
|
impl<S: BaseFloat> $Angle<S> {
|
||||||
type Unitless = S;
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn new(value: S) -> $Angle<S> {
|
pub fn new(value: S) -> $Angle<S> {
|
||||||
$Angle { s: value }
|
$Angle { s: value }
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: BaseFloat> Angle for $Angle<S> {
|
||||||
|
type Unitless = S;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn zero() -> $Angle<S> {
|
fn zero() -> $Angle<S> {
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
|
|
||||||
extern crate cgmath;
|
extern crate cgmath;
|
||||||
|
|
||||||
use cgmath::{Angle, Rad, Deg, rad, deg};
|
use cgmath::{Rad, Deg, rad, deg};
|
||||||
use cgmath::ApproxEq;
|
use cgmath::ApproxEq;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -36,14 +36,3 @@ fn conv() {
|
||||||
let angle: Rad<_> = angle.into();
|
let angle: Rad<_> = angle.into();
|
||||||
assert!(angle.approx_eq(&rad(30.0f64)));
|
assert!(angle.approx_eq(&rad(30.0f64)));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn equiv() {
|
|
||||||
assert!(Deg::<f32>::full_turn().equiv(&-Deg::<f32>::full_turn()));
|
|
||||||
assert!(Deg::<f32>::turn_div_2().equiv(&-Deg::<f32>::turn_div_2()));
|
|
||||||
assert!((Deg::<f32>::turn_div_3() - Deg::<f32>::full_turn()).equiv(&Deg::<f32>::turn_div_3()));
|
|
||||||
|
|
||||||
assert!(Rad::<f32>::full_turn().equiv(&-Rad::<f32>::full_turn()));
|
|
||||||
assert!(Rad::<f32>::turn_div_2().equiv(&-Rad::<f32>::turn_div_2()));
|
|
||||||
assert!((Rad::<f32>::turn_div_3() - Rad::<f32>::full_turn()).equiv(&Rad::<f32>::turn_div_3()));
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue