Added Radians and Degrees to the trig module.

These types allow the correct tracking of the type of angle measurement
being used.
This commit is contained in:
Myrddin Dundragon 2016-12-01 01:15:24 -05:00
parent b51a93fc01
commit 40f5c0f462
6 changed files with 982 additions and 221 deletions

View File

@ -236,6 +236,30 @@ pub trait Constants
/// # assert_eq!(val64, 2.0f64 * (std::f64::consts::PI).sqrt().recip()); /// # assert_eq!(val64, 2.0f64 * (std::f64::consts::PI).sqrt().recip());
///``` ///```
const TWO_INVERSE_SQRT_PI: Self; const TWO_INVERSE_SQRT_PI: Self;
/// PI divided by 180. This is used for radian and degree conversions.
///
///```
/// use sigils::Constants;
///
/// let val32: f32 = Constants::PI_DIVIDED_BY_180;
/// let val64: f64 = Constants::PI_DIVIDED_BY_180;
/// # assert_eq!(val32, (std::f32::consts::PI) / 180.0f32);
/// # assert_eq!(val64, (std::f64::consts::PI) / 180.0f64);
///```
const PI_DIVIDED_BY_180: Self;
/// 180 divided by PI. This is used for radian and degree conversions.
///
///```
/// use sigils::Constants;
///
/// let val32: f32 = Constants::INVERSE_PI_DIVIDED_BY_180;
/// let val64: f64 = Constants::INVERSE_PI_DIVIDED_BY_180;
/// # assert_eq!(val32, 180.0f32 / (std::f32::consts::PI));
/// # assert_eq!(val64, 180.0f64 / (std::f64::consts::PI));
///```
const INVERSE_PI_DIVIDED_BY_180: Self;
} }
@ -271,6 +295,8 @@ macro_rules! constants_trait_impl
const INVERSE_PI: $T = 1.0 / $pi; const INVERSE_PI: $T = 1.0 / $pi;
const TWO_INVERSE_PI: $T = 2.0 / $pi; const TWO_INVERSE_PI: $T = 2.0 / $pi;
const TWO_INVERSE_SQRT_PI: $T = 2.0 / $sqrtPI; const TWO_INVERSE_SQRT_PI: $T = 2.0 / $sqrtPI;
const PI_DIVIDED_BY_180: $T = $pi / 180.0;
const INVERSE_PI_DIVIDED_BY_180: $T = 180.0 / $pi;
} }
} }
} }

View File

@ -6,6 +6,9 @@
#![feature(associated_consts)] #![feature(associated_consts)]
#[macro_use]
mod macros;
mod zero; mod zero;
mod one; mod one;
mod bounded; mod bounded;
@ -15,7 +18,7 @@ mod integer;
mod real; mod real;
mod constants; mod constants;
pub mod trig; mod trig;
pub mod vector; pub mod vector;
pub mod matrix; pub mod matrix;
pub mod quaternion; pub mod quaternion;
@ -28,3 +31,4 @@ pub use self::whole::Whole;
pub use self::integer::Integer; pub use self::integer::Integer;
pub use self::real::Real; pub use self::real::Real;
pub use self::constants::Constants; pub use self::constants::Constants;
pub use self::trig::{Degree, Radian};

143
src/macros.rs Normal file
View File

@ -0,0 +1,143 @@
/// A macro that will define a binary operation for
/// a structure and its components.
macro_rules! binary_operator_impl
{
($traitName: ident :: $funcName: ident,
$structName: ident {$($field: ident),+},
$generic_type: ident) =>
{
impl<T> $traitName<T> for $structName<T>
where T: $generic_type
{
type Output = $structName<T>;
fn $funcName(self, val: T) -> $structName<T>
{
$structName::new($(self.$field.$funcName(val)),+)
}
}
impl<'a, T> $traitName<T> for &'a $structName<T>
where T: $generic_type
{
type Output = $structName<T>;
fn $funcName(self, val: T) -> $structName<T>
{
$structName::new($(self.$field.$funcName(val)),+)
}
}
impl<'a, T> $traitName<&'a T> for $structName<T>
where T: $generic_type
{
type Output = $structName<T>;
fn $funcName(self, val: &'a T) -> $structName<T>
{
$structName::new($(self.$field.$funcName(*val)),+)
}
}
impl<'a, 'b, T> $traitName<&'b T> for &'a $structName<T>
where T: $generic_type
{
type Output = $structName<T>;
fn $funcName(self, val: &'b T) -> $structName<T>
{
$structName::new($(self.$field.$funcName(*val)),+)
}
}
impl<T> $traitName<$structName<T>> for $structName<T>
where T: $generic_type
{
type Output = $structName<T>;
fn $funcName(self, other: $structName<T>) -> $structName<T>
{
$structName::new($(self.$field.$funcName(other.$field)),+)
}
}
impl<'a, T> $traitName<$structName<T>> for &'a $structName<T>
where T: $generic_type
{
type Output = $structName<T>;
fn $funcName(self, other: $structName<T>) -> $structName<T>
{
$structName::new($(self.$field.$funcName(other.$field)),+)
}
}
impl<'a, T> $traitName<&'a $structName<T>> for $structName<T>
where T: $generic_type
{
type Output = $structName<T>;
fn $funcName(self, other: &'a $structName<T>) -> $structName<T>
{
$structName::new($(self.$field.$funcName(other.$field)),+)
}
}
impl<'a, 'b, T> $traitName<&'a $structName<T>> for &'b $structName<T>
where T: $generic_type
{
type Output = $structName<T>;
fn $funcName(self, other: &'a $structName<T>) -> $structName<T>
{
$structName::new($(self.$field.$funcName(other.$field)),+)
}
}
}
}
/// A macro that will define an assignment binary operation for
/// a structure and its components.
macro_rules! binary_operator_assign_impl
{
($traitName: ident :: $funcName: ident,
$structName: ident {$($field: ident),+},
$generic_type: ident) =>
{
impl<T> $traitName<$structName<T>> for $structName<T>
where T: $generic_type
{
fn $funcName(&mut self, rhs: $structName<T>)
{
$(self.$field.$funcName(rhs.$field);)+
}
}
impl<T> $traitName<T> for $structName<T>
where T: $generic_type
{
fn $funcName(&mut self, rhs: T)
{
$(self.$field.$funcName(rhs);)+
}
}
impl<'a, T> $traitName<&'a $structName<T>> for $structName<T>
where T: $generic_type
{
fn $funcName(&mut self, rhs: &'a $structName<T>)
{
$(self.$field.$funcName(rhs.$field);)+
}
}
impl<'a, T> $traitName<&'a T> for $structName<T>
where T: $generic_type
{
fn $funcName(&mut self, rhs: &'a T)
{
$(self.$field.$funcName(*rhs);)+
}
}
}
}

View File

@ -1,7 +1,8 @@
use std::num::FpCategory; use std::num::FpCategory;
use std::ops::Neg; use std::ops::Neg;
use super::number::Number; use ::number::Number;
use ::trig::Radian;
// TODO: Double check these examples. Most are OK, // TODO: Double check these examples. Most are OK,
@ -730,7 +731,7 @@ pub trait Real : Number + Neg<Output=Self>
/// ///
/// assert!(abs_difference < 1e-10); /// assert!(abs_difference < 1e-10);
/// ``` /// ```
fn asin(self) -> Self; fn asin(self) -> Radian<Self>;
/// Computes the arccosine of a number. Return value is in radians in /// Computes the arccosine of a number. Return value is in radians in
/// the range [0, pi] or NaN if the number is outside the range /// the range [0, pi] or NaN if the number is outside the range
@ -747,7 +748,7 @@ pub trait Real : Number + Neg<Output=Self>
/// ///
/// assert!(abs_difference < 1e-10); /// assert!(abs_difference < 1e-10);
/// ``` /// ```
fn acos(self) -> Self; fn acos(self) -> Radian<Self>;
/// Computes the arctangent of a number. Return value is in radians in the /// Computes the arctangent of a number. Return value is in radians in the
/// range [-pi/2, pi/2]; /// range [-pi/2, pi/2];
@ -762,7 +763,7 @@ pub trait Real : Number + Neg<Output=Self>
/// ///
/// assert!(abs_difference < 1e-10); /// assert!(abs_difference < 1e-10);
/// ``` /// ```
fn atan(self) -> Self; fn atan(self) -> Radian<Self>;
/// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`). /// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`).
/// ///
@ -791,7 +792,7 @@ pub trait Real : Number + Neg<Output=Self>
/// assert!(abs_difference_1 < 1e-10); /// assert!(abs_difference_1 < 1e-10);
/// assert!(abs_difference_2 < 1e-10); /// assert!(abs_difference_2 < 1e-10);
/// ``` /// ```
fn atan2(self, other: Self) -> Self; fn atan2(self, other: Self) -> Radian<Self>;
/// Simultaneously computes the sine and cosine of the number, `x`. Returns /// Simultaneously computes the sine and cosine of the number, `x`. Returns
/// `(sin(x), cos(x))`. /// `(sin(x), cos(x))`.
@ -935,7 +936,7 @@ pub trait Real : Number + Neg<Output=Self>
/// ///
/// assert!(abs_difference < 1.0e-10); /// assert!(abs_difference < 1.0e-10);
/// ``` /// ```
fn asinh(self) -> Self; fn asinh(self) -> Radian<Self>;
/// Inverse hyperbolic cosine function. /// Inverse hyperbolic cosine function.
/// ///
@ -949,7 +950,7 @@ pub trait Real : Number + Neg<Output=Self>
/// ///
/// assert!(abs_difference < 1.0e-10); /// assert!(abs_difference < 1.0e-10);
/// ``` /// ```
fn acosh(self) -> Self; fn acosh(self) -> Radian<Self>;
/// Inverse hyperbolic tangent function. /// Inverse hyperbolic tangent function.
/// ///
@ -968,7 +969,7 @@ pub trait Real : Number + Neg<Output=Self>
/// //assert!(abs_difference32 < 1.0e-10); /// //assert!(abs_difference32 < 1.0e-10);
/// assert!(abs_difference64 < 1.0e-10); /// assert!(abs_difference64 < 1.0e-10);
/// ``` /// ```
fn atanh(self) -> Self; fn atanh(self) -> Radian<Self>;
} }
@ -997,6 +998,18 @@ macro_rules! define_self_bool_func
} }
} }
///
macro_rules! define_self_rad_func
{
($varType: ident, $funcName: ident) =>
{
fn $funcName(self) -> Radian<$varType>
{
Radian::new(<$varType>::$funcName(self))
}
}
}
/// ///
macro_rules! define_self_other_func macro_rules! define_self_other_func
{ {
@ -1009,6 +1022,18 @@ macro_rules! define_self_other_func
} }
} }
///
macro_rules! define_self_other_rad_func
{
($varType: ident, $funcName: ident) =>
{
fn $funcName(self, other: $varType) -> Radian<$varType>
{
Radian::new(<$varType>::$funcName(self, other))
}
}
}
/// A macro to make implementing the trait easier for all the /// A macro to make implementing the trait easier for all the
/// base float types in rust. /// base float types in rust.
macro_rules! real_trait_impl macro_rules! real_trait_impl
@ -1097,16 +1122,16 @@ macro_rules! real_trait_impl
define_self_func!($varType, cos); define_self_func!($varType, cos);
define_self_func!($varType, sin); define_self_func!($varType, sin);
define_self_func!($varType, tan); define_self_func!($varType, tan);
define_self_func!($varType, acos); define_self_rad_func!($varType, acos);
define_self_func!($varType, asin); define_self_rad_func!($varType, asin);
define_self_func!($varType, atan); define_self_rad_func!($varType, atan);
define_self_func!($varType, cosh); define_self_func!($varType, cosh);
define_self_func!($varType, sinh); define_self_func!($varType, sinh);
define_self_func!($varType, tanh); define_self_func!($varType, tanh);
define_self_func!($varType, acosh); define_self_rad_func!($varType, acosh);
define_self_func!($varType, asinh); define_self_rad_func!($varType, asinh);
define_self_func!($varType, atanh); define_self_rad_func!($varType, atanh);
define_self_other_func!($varType, atan2); define_self_other_rad_func!($varType, atan2);
} }
)*) )*)
} }

View File

@ -1,26 +1,716 @@
//use super::constants::Constants; use std::ops::{Add, Sub, Mul, Div, Rem, Neg};
use super::real::Real; use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
use ::constants::Constants;
use ::real::Real;
/*
pub struct Radians<T> where T: Real /// A degree usually denoted by ° (the degree symbol),
/// is a measurement of a plane angle, defined so that a
/// full rotation is 360 degrees.
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
pub struct Degree<T>
{ {
pub value: T value: T
} }
pub struct Degrees<T> where T: Real /// A unit of angle, equal to an angle at the center of
/// a circle whose arc is equal in length to the radius.
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
pub struct Radian<T>
{ {
pub value: T value: T
}
*/
pub fn acos<T>(x: T) -> T where T: Real
{
x.acos()
} }
pub fn atan2<T>(x: T, y: T) -> T where T: Real
impl<T> Degree<T> where T: Real
{ {
x.atan2(y) /// Create a new Degree structure with the given value.
pub fn new(val: T) -> Degree<T>
{
Degree
{
value: val
}
}
/// Computes the arccosine of a number. Return value is in Degrees in
/// the range [0, 180] or NaN if the number is outside the range
/// [-1, 1].
///
///```
/// use sigils::{Degree, Real};
///
/// let f: Degree<f64>;
///
/// f = Degree::from(45.0f64);
/// assert!((45.0f64 - *Degree::acos(f.cos())) < 1e-10);
///```
pub fn acos(val: T) -> Degree<T>
{
let radians: Radian<T>;
radians = val.acos();
Degree::from(radians)
}
/// Computes the arcsine of a number. Return value is in Degrees in
/// the range [-57.2957795/2, 57.2957795/2] or NaN if the number is
/// outside the range [-1, 1].
///
///```
/// use sigils::{Degree, Real};
///
/// let f: Degree<f64>;
///
/// f = Degree::from(45.0f64);
/// assert!((45.0f64 - *Degree::asin(f.sin())) < 1e-10);
///```
pub fn asin(val: T) -> Degree<T>
{
let radians: Radian<T>;
radians = val.asin();
Degree::from(radians)
}
/// Computes the arctangent of a number. Return value is in degrees in the
/// range [-57.2957795/2, 57.2957795/2];
///
///```
/// use sigils::{Degree, Real};
///
/// let f: Degree<f64>;
///
/// f = Degree::from(45.0f64);
/// assert!((45.0f64 - *Degree::atan(f.tan())) < 1e-10);
///```
pub fn atan(val: T) -> Degree<T>
{
let radians: Radian<T>;
radians = val.atan();
Degree::from(radians)
}
/// Inverse hyperbolic cosine function.
pub fn acosh(val: T) -> Degree<T>
{
let radians: Radian<T>;
radians = val.acosh();
Degree::from(radians)
}
/// Inverse hyperbolic sine function.
pub fn asinh(val: T) -> Degree<T>
{
let radians: Radian<T>;
radians = val.asinh();
Degree::from(radians)
}
/// Inverse hyperbolic tangent function.
pub fn atanh(val: T) -> Degree<T>
{
let radians: Radian<T>;
radians = val.atanh();
Degree::from(radians)
}
/// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`).
pub fn atan2(y: T, x: T) -> Degree<T>
{
let radians: Radian<T>;
radians = y.atan2(x);
Degree::from(radians)
}
/// Computes the cosine of this angle.
///
/// ```
/// use sigils::Degree;
/// use std::f64;
///
/// let x: Degree<f64> = Degree::from(360.0f64);
///
/// let abs_difference = (x.cos() - 1.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
pub fn cos(&self) -> T
{
let radians: Radian<T>;
radians = Radian::from(*self);
radians.cos()
}
/// Computes the sine of this angle.
///
/// ```
/// use sigils::Degree;
/// use std::f64;
///
/// let x: Degree<f64> = Degree::from(90.0f64);
///
/// let abs_difference = (x.sin() - 1.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
pub fn sin(&self) -> T
{
let radians: Radian<T>;
radians = Radian::from(*self);
radians.sin()
}
/// Computes the tangent of this angle.
///
/// ```
/// use sigils::Degree;
/// use std::f64;
///
/// let x: Degree<f64> = Degree::from(45.0f64);
///
/// let abs_difference = (x.tan() - 1.0).abs();
///
/// assert!(abs_difference < 1e-14);
/// ```
pub fn tan(&self) -> T
{
let radians: Radian<T>;
radians = Radian::from(*self);
radians.tan()
}
/// Hyperbolic cosine function.
///
/// ```
/// use sigils::Degree;
/// use sigils::Constants;
///
/// let e32: f32 = Constants::E;
/// let x32: Degree<f32> = Degree::from(f32::INVERSE_PI_DIVIDED_BY_180);
/// let f_val32 = x32.cosh();
/// let g_val32 = (e32*e32 + 1.0f32)/(2.0f32*e32);
/// let abs_difference32 = (f_val32 - g_val32).abs();
///
/// let e64: f64 = Constants::E;
/// let x64: Degree<f64> = Degree::from(f64::INVERSE_PI_DIVIDED_BY_180);
/// let f_val64 = x64.cosh();
/// let g_val64 = (e64*e64 + 1.0f64)/(2.0f64*e64);
/// let abs_difference64 = (f_val64 - g_val64).abs();
///
/// // Solving cosh() at 1 gives this result
/// //assert!(abs_difference32 < 1.0e-10);
/// assert!(abs_difference64 < 1.0e-10);
/// ```
pub fn cosh(&self) -> T
{
let radians: Radian<T>;
radians = Radian::from(*self);
radians.cosh()
}
/// Hyperbolic sine function.
///
/// ```
/// use sigils::Degree;
/// use sigils::Constants;
///
/// let e32: f32 = Constants::E;
/// let x32: Degree<f32> = Degree::from(f32::INVERSE_PI_DIVIDED_BY_180);
///
/// let f_val32 = x32.sinh();
/// let g_val32 = (e32*e32 - 1.0f32)/(2.0f32*e32);
/// let abs_difference32 = (f_val32 - g_val32).abs();
///
/// let e64: f64 = Constants::E;
/// let x64: Degree<f64> = Degree::from(f64::INVERSE_PI_DIVIDED_BY_180);
///
/// let f_val64 = x64.sinh();
/// let g_val64 = (e64*e64 - 1.0f64)/(2.0f64*e64);
/// let abs_difference64 = (f_val64 - g_val64).abs();
///
/// // Solving sinh() at 1 gives `(e^2-1)/(2e)`
/// //assert!(abs_difference32 < 1e-10);
/// assert!(abs_difference64 < 1e-10);
/// ```
pub fn sinh(&self) -> T
{
let radians: Radian<T>;
radians = Radian::from(*self);
radians.sinh()
}
/// Hyperbolic tangent function.
///
/// ```
/// use sigils::Degree;
/// use sigils::Constants;
///
/// let e32: f32 = Constants::E;
/// let x32: Degree<f32> = Degree::from(f32::INVERSE_PI_DIVIDED_BY_180);
///
/// let f_val32 = x32.tanh();
/// let g_val32 = (1.0f32 - e32.powi(-2i32))/(1.0f32 + e32.powi(-2i32));
/// let abs_difference32 = (f_val32 - g_val32).abs();
///
/// let e64: f64 = Constants::E;
/// let x64: Degree<f64> = Degree::from(f64::INVERSE_PI_DIVIDED_BY_180);
///
/// let f_val64 = x64.tanh();
/// let g_val64 = (1.0f64 - e64.powi(-2i32))/(1.0f64 + e64.powi(-2i32));
/// let abs_difference64 = (f_val64 - g_val64).abs();
///
/// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))`
/// //assert!(abs_difference32 < 1.0e-10);
/// assert!(abs_difference64 < 1.0e-10);
/// ```
pub fn tanh(&self) -> T
{
let radians: Radian<T>;
radians = Radian::from(*self);
radians.tanh()
}
}
impl<T> ::std::ops::Deref for Degree<T> where T: Real
{
type Target = T;
fn deref(&self) -> &T
{
&self.value
}
}
impl<T> ::std::ops::DerefMut for Degree<T> where T: Real
{
fn deref_mut<'a>(&'a mut self) -> &'a mut T
{
&mut self.value
}
}
binary_operator_impl!(Add::add, Degree {value}, Real);
binary_operator_impl!(Sub::sub, Degree {value}, Real);
binary_operator_impl!(Mul::mul, Degree {value}, Real);
binary_operator_impl!(Div::div, Degree {value}, Real);
binary_operator_impl!(Rem::rem, Degree {value}, Real);
impl<T> ::std::ops::Neg for Degree<T>
where T: Neg<Output = T>
{
type Output = Degree<T>;
fn neg(self) -> Degree<T>
{
let mut degrees: Degree<T>;
degrees = self;
degrees.value = degrees.value.neg();
degrees
}
}
binary_operator_assign_impl!(AddAssign::add_assign,
Degree {value}, Real);
binary_operator_assign_impl!(SubAssign::sub_assign,
Degree {value}, Real);
binary_operator_assign_impl!(MulAssign::mul_assign,
Degree {value}, Real);
binary_operator_assign_impl!(DivAssign::div_assign,
Degree {value}, Real);
binary_operator_assign_impl!(RemAssign::rem_assign,
Degree {value}, Real);
impl ::std::convert::From<Degree<f32>> for f32
{
fn from(degrees: Degree<f32>) -> f32
{
degrees.value
}
}
impl ::std::convert::From<Degree<f64>> for f64
{
fn from(degrees: Degree<f64>) -> f64
{
degrees.value
}
}
impl<T> ::std::convert::From<T> for Degree<T> where T: Real
{
fn from(val: T) -> Degree<T>
{
Degree::new(val)
}
}
impl<T> ::std::convert::From<Radian<T>> for Degree<T> where T: Real
{
fn from(radians: Radian<T>) -> Degree<T>
{
let degs: T;
degs = radians.value * Constants::INVERSE_PI_DIVIDED_BY_180;
Degree::new(degs)
}
}
impl<T> ::std::fmt::Debug for Degree<T>
where T: Real
{
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
{
::std::fmt::Display::fmt(self, f)
}
}
impl<T> ::std::fmt::Display for Degree<T>
where T: Real
{
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
{
write!(f, "{}", self.value)
}
}
impl<T> Radian<T> where T: Real
{
/// Create a new Radian structure with the given value.
pub fn new(val: T) -> Radian<T>
{
Radian
{
value: val
}
}
/// Computes the arccosine of a number. Return value is in Degrees in
/// the range [0, pi] or NaN if the number is outside the range
/// [-1, 1].
///
///```
/// use sigils::{Constants, Radian, Real};
///
/// let f: Radian<f64>;
///
/// f = Radian::from(f64::PI / 4.0f64);
/// assert!(((f64::PI / 4.0f64) - *Radian::acos(f.cos())) < 1e-10);
///```
pub fn acos(val: T) -> Radian<T>
{
val.acos()
}
/// Computes the arcsine of a number. Return value is in Degrees in
/// the range [-pi/2, pi/2] or NaN if the number is
/// outside the range [-1, 1].
///
///```
/// use sigils::{Constants, Radian, Real};
///
/// let f: Radian<f64>;
///
/// f = Radian::from(f64::PI / 4.0f64);
/// assert!(((f64::PI / 4.0f64) - *Radian::asin(f.sin())) < 1e-10);
///```
pub fn asin(val: T) -> Radian<T>
{
val.asin()
}
/// Computes the arctangent of a number. Return value is in degrees in the
/// range [-pi/2, pi/2];
///
///```
/// use sigils::{Constants, Radian, Real};
///
/// let f: Radian<f64>;
///
/// f = Radian::from(f64::PI / 4.0f64);
/// assert!(((f64::PI / 4.0f64) - *Radian::atan(f.tan())) < 1e-10);
///```
pub fn atan(val: T) -> Radian<T>
{
val.atan()
}
/// Inverse hyperbolic cosine function.
pub fn acosh(val: T) -> Radian<T>
{
val.acosh()
}
/// Inverse hyperbolic sine function.
pub fn asinh(val: T) -> Radian<T>
{
val.asinh()
}
/// Inverse hyperbolic tangent function.
pub fn atanh(val: T) -> Radian<T>
{
val.atanh()
}
/// Computes the four quadrant arctangent of `self` (`y`) and `other` (`x`).
pub fn atan2(y: T, x: T) -> Radian<T>
{
y.atan2(x)
}
/// Computes the cosine of this angle.
///
/// ```
/// use sigils::Radian;
/// use std::f64;
///
/// let x: Radian<f64> = Radian::from(2.0*f64::consts::PI);
///
/// let abs_difference = (x.cos() - 1.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
pub fn cos(&self) -> T
{
self.value.cos()
}
/// Computes the sine of this angle.
///
/// ```
/// use sigils::Radian;
/// use std::f64;
///
/// let x: Radian<f64> = Radian::from(f64::consts::PI/2.0);
///
/// let abs_difference = (x.sin() - 1.0).abs();
///
/// assert!(abs_difference < 1e-10);
/// ```
pub fn sin(&self) -> T
{
self.value.sin()
}
/// Computes the tangent of this angle.
///
/// ```
/// use sigils::Radian;
/// use std::f64;
///
/// let x: Radian<f64> = Radian::from(f64::consts::PI/4.0);
///
/// let abs_difference = (x.tan() - 1.0).abs();
///
/// assert!(abs_difference < 1e-14);
/// ```
pub fn tan(&self) -> T
{
self.value.tan()
}
/// Hyperbolic cosine function.
///
/// ```
/// use sigils::Radian;
/// use sigils::Constants;
///
/// let e32: f32 = Constants::E;
/// let x32: Radian<f32> = Radian::new(1.0f32);
/// let f_val32 = x32.cosh();
/// let g_val32 = (e32*e32 + 1.0f32)/(2.0f32*e32);
/// let abs_difference32 = (f_val32 - g_val32).abs();
///
/// let e64: f64 = Constants::E;
/// let x64: Radian<f64> = Radian::new(1.0f64);
/// let f_val64 = x64.cosh();
/// let g_val64 = (e64*e64 + 1.0f64)/(2.0f64*e64);
/// let abs_difference64 = (f_val64 - g_val64).abs();
///
/// // Solving cosh() at 1 gives this result
/// //assert!(abs_difference32 < 1.0e-10);
/// assert!(abs_difference64 < 1.0e-10);
/// ```
pub fn cosh(&self) -> T
{
self.value.cosh()
}
/// Hyperbolic sine function.
///
/// ```
/// use sigils::Radian;
/// use sigils::Constants;
///
/// let e32: f32 = Constants::E;
/// let x32: Radian<f32> = Radian::from(1.0f32);
///
/// let f_val32 = x32.sinh();
/// let g_val32 = (e32*e32 - 1.0f32)/(2.0f32*e32);
/// let abs_difference32 = (f_val32 - g_val32).abs();
///
/// let e64: f64 = Constants::E;
/// let x64: Radian<f64> = Radian::from(1.0f64);
///
/// let f_val64 = x64.sinh();
/// let g_val64 = (e64*e64 - 1.0f64)/(2.0f64*e64);
/// let abs_difference64 = (f_val64 - g_val64).abs();
///
/// // Solving sinh() at 1 gives `(e^2-1)/(2e)`
/// //assert!(abs_difference32 < 1e-10);
/// assert!(abs_difference64 < 1e-10);
/// ```
pub fn sinh(&self) -> T
{
self.value.sinh()
}
/// Hyperbolic tangent function.
///
/// ```
/// use sigils::Radian;
/// use sigils::Constants;
///
/// let e32: f32 = Constants::E;
/// let x32: Radian<f32> = Radian::from(1.0f32);
///
/// let f_val32 = x32.tanh();
/// let g_val32 = (1.0f32 - e32.powi(-2i32))/(1.0f32 + e32.powi(-2i32));
/// let abs_difference32 = (f_val32 - g_val32).abs();
///
/// let e64: f64 = Constants::E;
/// let x64: Radian<f64> = Radian::from(1.0f64);
///
/// let f_val64 = x64.tanh();
/// let g_val64 = (1.0f64 - e64.powi(-2i32))/(1.0f64 + e64.powi(-2i32));
/// let abs_difference64 = (f_val64 - g_val64).abs();
///
/// // Solving tanh() at 1 gives `(1 - e^(-2))/(1 + e^(-2))`
/// //assert!(abs_difference32 < 1.0e-10);
/// assert!(abs_difference64 < 1.0e-10);
/// ```
pub fn tanh(&self) -> T
{
self.value.tanh()
}
}
impl<T> ::std::ops::Deref for Radian<T> where T: Real
{
type Target = T;
fn deref(&self) -> &T
{
&self.value
}
}
impl<T> ::std::ops::DerefMut for Radian<T> where T: Real
{
fn deref_mut<'a>(&'a mut self) -> &'a mut T
{
&mut self.value
}
}
binary_operator_impl!(Add::add, Radian {value}, Real);
binary_operator_impl!(Sub::sub, Radian {value}, Real);
binary_operator_impl!(Mul::mul, Radian {value}, Real);
binary_operator_impl!(Div::div, Radian {value}, Real);
binary_operator_impl!(Rem::rem, Radian {value}, Real);
impl<T> ::std::ops::Neg for Radian<T>
where T: Neg<Output = T>
{
type Output = Radian<T>;
fn neg(self) -> Radian<T>
{
let mut radians: Radian<T>;
radians = self;
radians.value = radians.value.neg();
radians
}
}
binary_operator_assign_impl!(AddAssign::add_assign,
Radian {value}, Real);
binary_operator_assign_impl!(SubAssign::sub_assign,
Radian {value}, Real);
binary_operator_assign_impl!(MulAssign::mul_assign,
Radian {value}, Real);
binary_operator_assign_impl!(DivAssign::div_assign,
Radian {value}, Real);
binary_operator_assign_impl!(RemAssign::rem_assign,
Radian {value}, Real);
impl ::std::convert::From<Radian<f32>> for f32
{
fn from(radians: Radian<f32>) -> f32
{
radians.value
}
}
impl ::std::convert::From<Radian<f64>> for f64
{
fn from(radians: Radian<f64>) -> f64
{
radians.value
}
}
impl<T> ::std::convert::From<T> for Radian<T> where T: Real
{
fn from(val: T) -> Radian<T>
{
Radian::new(val)
}
}
impl<T> ::std::convert::From<Degree<T>> for Radian<T>
where T: Real
{
fn from(degrees: Degree<T>) -> Radian<T>
{
let rads: T;
rads = degrees.value * Constants::PI_DIVIDED_BY_180;
Radian::new(rads)
}
}
impl<T> ::std::fmt::Debug for Radian<T>
where T: Real
{
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
{
::std::fmt::Display::fmt(self, f)
}
}
impl<T> ::std::fmt::Display for Radian<T>
where T: Real
{
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
{
write!(f, "{}", self.value)
}
} }

View File

@ -9,7 +9,7 @@ use ::zero::Zero;
use ::one::One; use ::one::One;
use ::number::Number; use ::number::Number;
use ::real::Real; use ::real::Real;
use ::trig::{acos, atan2}; use ::trig::Radian;
@ -264,13 +264,15 @@ pub trait Vector<T>: Debug + Display + Clone + Default + Zero + One
/// // the components are 3. Then get the /// // the components are 3. Then get the
/// // dot product of the two Vectors. /// // dot product of the two Vectors.
/// use sigils::vector::*; /// use sigils::vector::*;
/// use sigils::Radian;
/// ///
/// let vector: Vector3<i64> = Vector3::<i64>::from_value(3i64); /// let vector: Vector3<i32> = Vector3::<i32>::from_value(3i32);
/// let vector_two: Vector3<i64> = Vector3::<i64>::from_value(3i64); /// let vector_two: Vector3<i32> = Vector3::<i32>::from_value(3i32);
/// let dotProduct: i64 = vector.dot(&vector_two); /// let dotProduct: Radian<f64> = vector.dot(&vector_two);
/// # assert_eq!(dotProduct, 27i64); /// # assert_eq!(*dotProduct, 27f64);
///``` ///```
fn dot(&self, vector: &Self) -> T; fn dot<R>(&self, vector: &Self) -> Radian<R>
where R: Real + ::std::convert::From<T>;
} }
/// Defines the [EuclideanVector][1] trait. /// Defines the [EuclideanVector][1] trait.
@ -290,12 +292,14 @@ pub trait EuclideanVector<T> : Vector<T> where T: Real
///``` ///```
fn get_length(&self) -> T fn get_length(&self) -> T
{ {
let length: T; let sq_rt: T;
let length: Radian<T>;
length = self.dot(self).sqrt(); length = self.dot(self);
assert!(length.is_finite()); sq_rt = (*length).sqrt();
assert!(sq_rt.is_finite());
length sq_rt
} }
/// Get the squared length of the Vector. /// Get the squared length of the Vector.
@ -310,7 +314,10 @@ pub trait EuclideanVector<T> : Vector<T> where T: Real
///``` ///```
fn get_length_squared(&self) -> T fn get_length_squared(&self) -> T
{ {
self.dot(self) let radians: Radian<T>;
radians = self.dot(self);
*radians
} }
/// Normalizes the Vector by multplying all the /// Normalizes the Vector by multplying all the
@ -362,15 +369,18 @@ pub trait EuclideanVector<T> : Vector<T> where T: Real
// TODO: Add an example here. // TODO: Add an example here.
fn is_perpendicular_to(&self, vector: &Self) -> bool fn is_perpendicular_to(&self, vector: &Self) -> bool
{ {
let dot: T;
// TODO: Make this work with a fudge factor since floats // TODO: Make this work with a fudge factor since floats
// are tricky. // are tricky.
self.dot(vector) == T::zero() dot = *self.dot(vector);
dot == T::zero()
} }
/// Calculates the angle between this vector and /// Calculates the angle between this vector and
/// another Vector, in radians. /// another Vector, in radians.
// TODO: Add an example here. // TODO: Add an example here.
fn angle(&self, vector: &Self) -> T; fn angle(&self, vector: &Self) -> Radian<T>;
/// Linearly interpolate the length of this Vector /// Linearly interpolate the length of this Vector
/// towards the length of another Vector by a given amount. /// towards the length of another Vector by a given amount.
@ -425,141 +435,6 @@ macro_rules! perform_method_on_components
}; };
} }
/// A macro that will define a binary operation for
/// a Vector and its components.
macro_rules! binary_operator_impl
{
($traitName: ident :: $funcName: ident,
$structName: ident {$($field: ident),+}) =>
{
impl<T> $traitName<T> for $structName<T> where T: Number
{
type Output = $structName<T>;
fn $funcName(self, scalar: T) -> $structName<T>
{
$structName::new($(self.$field.$funcName(scalar)),+)
}
}
impl<'a, T> $traitName<T> for &'a $structName<T> where T: Number
{
type Output = $structName<T>;
fn $funcName(self, scalar: T) -> $structName<T>
{
$structName::new($(self.$field.$funcName(scalar)),+)
}
}
impl<'a, T> $traitName<&'a T> for $structName<T> where T: Number
{
type Output = $structName<T>;
fn $funcName(self, scalar: &'a T) -> $structName<T>
{
$structName::new($(self.$field.$funcName(*scalar)),+)
}
}
impl<'a, 'b, T> $traitName<&'b T> for &'a $structName<T> where T: Number
{
type Output = $structName<T>;
fn $funcName(self, scalar: &'b T) -> $structName<T>
{
$structName::new($(self.$field.$funcName(*scalar)),+)
}
}
impl<T> $traitName<$structName<T>> for $structName<T>
where T: Number
{
type Output = $structName<T>;
fn $funcName(self, vector: $structName<T>) -> $structName<T>
{
$structName::new($(self.$field.$funcName(vector.$field)),+)
}
}
impl<'a, T> $traitName<$structName<T>> for &'a $structName<T>
where T: Number
{
type Output = $structName<T>;
fn $funcName(self, vector: $structName<T>) -> $structName<T>
{
$structName::new($(self.$field.$funcName(vector.$field)),+)
}
}
impl<'a, T> $traitName<&'a $structName<T>> for $structName<T>
where T: Number
{
type Output = $structName<T>;
fn $funcName(self, vector: &'a $structName<T>) -> $structName<T>
{
$structName::new($(self.$field.$funcName(vector.$field)),+)
}
}
impl<'a, 'b, T> $traitName<&'a $structName<T>> for &'b $structName<T>
where T: Number
{
type Output = $structName<T>;
fn $funcName(self, vector: &'a $structName<T>) -> $structName<T>
{
$structName::new($(self.$field.$funcName(vector.$field)),+)
}
}
}
}
/// A macro that will define a binary operation for
/// a Vector and its components.
macro_rules! binary_operator_assign_impl
{
($traitName: ident :: $funcName: ident,
$structName: ident {$($field: ident),+}) =>
{
impl<T> $traitName<$structName<T>> for $structName<T> where T: Number
{
fn $funcName(&mut self, rhs: $structName<T>)
{
$(self.$field.$funcName(rhs.$field);)+
}
}
impl<T> $traitName<T> for $structName<T> where T: Number
{
fn $funcName(&mut self, rhs: T)
{
$(self.$field.$funcName(rhs);)+
}
}
impl<'a, T> $traitName<&'a $structName<T>> for $structName<T>
where T: Number
{
fn $funcName(&mut self, rhs: &'a $structName<T>)
{
$(self.$field.$funcName(rhs.$field);)+
}
}
impl<'a, T> $traitName<&'a T> for $structName<T> where T: Number
{
fn $funcName(&mut self, rhs: &'a T)
{
$(self.$field.$funcName(*rhs);)+
}
}
}
}
/// A macro that defines a Vector structure /// A macro that defines a Vector structure
/// that implements the Vector trait. /// that implements the Vector trait.
macro_rules! define_vector macro_rules! define_vector
@ -589,21 +464,6 @@ macro_rules! define_vector
} }
} }
// Give this vector a negation function when the
// type stored in it is negatable.
impl<$T> $structName<$T> where T: Copy + Neg<Output = $T>
{
/// Negate this vector in-place (multiply by -1).
///
///```
///
///```
pub fn negate(&mut self)
{
$(self.$field = -self.$field);+
}
}
impl<T> Vector<T> for $structName<T> where T: Number impl<T> Vector<T> for $structName<T> where T: Number
{ {
fn from_value(val: T) -> $structName<T> fn from_value(val: T) -> $structName<T>
@ -678,15 +538,19 @@ macro_rules! define_vector
perform_method_on_components!(mul, {$(self.$field),+}) perform_method_on_components!(mul, {$(self.$field),+})
} }
fn dot(&self, vector: &$structName<T>) -> T fn dot<R>(&self, vector: &$structName<T>) -> Radian<R>
where R: Real + ::std::convert::From<T>
{ {
self.mul(vector).get_sum() let dot: R;
dot = R::from(self.mul(vector).get_sum());
Radian::new(dot)
} }
} }
// Implement the Debug trait for the Vector. // Implement the Debug trait for the Vector.
impl<T> Debug for $structName<T> where T: Number impl<T> Debug for $structName<T> where T: Number
{ {
#[allow(unused_assignments)]
fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error>
{ {
let mut count: u8; let mut count: u8;
@ -695,12 +559,12 @@ macro_rules! define_vector
// pretty up the printing. // pretty up the printing.
count = self.get_size(); count = self.get_size();
write!(formatter, "<"); try!(write!(formatter, "<"));
$( $(
write!(formatter, "{:?}", self.$field); try!(write!(formatter, "{:?}", self.$field));
if count > 0 if count > 0
{ {
write!(formatter, ", "); try!(write!(formatter, ", "));
} }
count -= 1; count -= 1;
)* )*
@ -711,6 +575,7 @@ macro_rules! define_vector
// Implement the Display trait for the Vector. // Implement the Display trait for the Vector.
impl<T> Display for $structName<T> where T: Number impl<T> Display for $structName<T> where T: Number
{ {
#[allow(unused_assignments)]
fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error> fn fmt(&self, formatter: &mut Formatter) -> Result<(), Error>
{ {
let mut count: u8; let mut count: u8;
@ -719,12 +584,12 @@ macro_rules! define_vector
// pretty up the printing. // pretty up the printing.
count = self.get_size(); count = self.get_size();
write!(formatter, "<"); try!(write!(formatter, "<"));
$( $(
write!(formatter, "{}", self.$field); try!(write!(formatter, "{}", self.$field));
if count > 1 if count > 1
{ {
write!(formatter, ", "); try!(write!(formatter, ", "));
} }
count -= 1; count -= 1;
)* )*
@ -770,23 +635,23 @@ macro_rules! define_vector
} }
// Implement the binary operations for this Vector structure. // Implement the binary operations for this Vector structure.
binary_operator_impl!(Add::add, $structName {$($field),+}); binary_operator_impl!(Add::add, $structName {$($field),+}, Number);
binary_operator_impl!(Sub::sub, $structName {$($field),+}); binary_operator_impl!(Sub::sub, $structName {$($field),+}, Number);
binary_operator_impl!(Mul::mul, $structName {$($field),+}); binary_operator_impl!(Mul::mul, $structName {$($field),+}, Number);
binary_operator_impl!(Div::div, $structName {$($field),+}); binary_operator_impl!(Div::div, $structName {$($field),+}, Number);
binary_operator_impl!(Rem::rem, $structName {$($field),+}); binary_operator_impl!(Rem::rem, $structName {$($field),+}, Number);
// Handle the assignment operators. // Handle the assignment operators.
binary_operator_assign_impl!(AddAssign::add_assign, binary_operator_assign_impl!(AddAssign::add_assign,
$structName {$($field),+}); $structName {$($field),+}, Number);
binary_operator_assign_impl!(SubAssign::sub_assign, binary_operator_assign_impl!(SubAssign::sub_assign,
$structName {$($field),+}); $structName {$($field),+}, Number);
binary_operator_assign_impl!(MulAssign::mul_assign, binary_operator_assign_impl!(MulAssign::mul_assign,
$structName {$($field),+}); $structName {$($field),+}, Number);
binary_operator_assign_impl!(DivAssign::div_assign, binary_operator_assign_impl!(DivAssign::div_assign,
$structName {$($field),+}); $structName {$($field),+}, Number);
binary_operator_assign_impl!(RemAssign::rem_assign, binary_operator_assign_impl!(RemAssign::rem_assign,
$structName {$($field),+}); $structName {$($field),+}, Number);
} }
} }
@ -797,6 +662,7 @@ define_vector!(Vector3<T> {x, y, z}, 3u8);
define_vector!(Vector4<T> {x, y, z, w}, 4u8); define_vector!(Vector4<T> {x, y, z, w}, 4u8);
// Implements operations specific to the different // Implements operations specific to the different
// Vector structure sizes. // Vector structure sizes.
impl<T> Vector2<T> where T: Number impl<T> Vector2<T> where T: Number
@ -833,9 +699,13 @@ impl<T> Vector2<T> where T: Number
/// Calculate the perpendicular dot product. /// Calculate the perpendicular dot product.
// TODO: Add an example. // TODO: Add an example.
pub fn perpendicular_dot(&self, vector: &Vector2<T>) -> T pub fn perpendicular_dot<R>(&self, vector: &Vector2<T>) -> Radian<R>
where R: Real + ::std::convert::From<T>
{ {
(self.x * vector.y) - (self.y * vector.x) let val: R;
val = R::from((self.x * vector.y) - (self.y * vector.x));
Radian::new(val)
} }
/// Adds a z component with the given value to the Vector. /// Adds a z component with the given value to the Vector.
@ -1056,24 +926,27 @@ impl<T> Vector4<T> where T: Number
// Implement the angle specific portion of the EuclideanVector. // Implement the angle specific portion of the EuclideanVector.
impl<T> EuclideanVector<T> for Vector2<T> where T: Real impl<T> EuclideanVector<T> for Vector2<T> where T: Real
{ {
fn angle(&self, vector: &Vector2<T>) -> T fn angle(&self, vector: &Vector2<T>) -> Radian<T>
{ {
atan2(self.perpendicular_dot(vector), self.dot(vector)) Radian::atan2((*self.perpendicular_dot(vector)), (*self.dot(vector)))
} }
} }
impl<T> EuclideanVector<T> for Vector3<T> where T: Real impl<T> EuclideanVector<T> for Vector3<T> where T: Real
{ {
fn angle(&self, vector: &Vector3<T>) -> T fn angle(&self, vector: &Vector3<T>) -> Radian<T>
{ {
atan2(self.cross(vector).get_length(), self.dot(vector)) Radian::atan2(self.cross(vector).get_length(), (*self.dot(vector)))
} }
} }
impl<T> EuclideanVector<T> for Vector4<T> where T: Real impl<T> EuclideanVector<T> for Vector4<T> where T: Real
{ {
fn angle(&self, vector: &Vector4<T>) -> T fn angle(&self, vector: &Vector4<T>) -> Radian<T>
{ {
acos(self.dot(vector) / (self.get_length() * vector.get_length())) let dot: T;
dot = *self.dot(vector);
Radian::acos(dot / self.get_length() * vector.get_length())
} }
} }