diff --git a/CHANGELOG.md b/CHANGELOG.md index 55886ec..e8d9a2b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,20 +7,29 @@ This project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Added -- Add missing by-ref and by-val permutations of `Quaternion` operators. +- Add missing by-ref and by-val permutations of `Quaternion` and `Angle` + operators. - Ease lifetime constraints by removing `'static` from some scalar type parameters. - Weaken type constraints on `perspective` function to take an `Into>`. +- Add `Angle::new` for constructing angles from a unitless scalar. ### Changed +- `Vector`, `Point`, and `Angle` are now constrained to require specific + operators to be overloaded. This means that generic code can now use + operators, instead of the operator methods. - Take a `Rad` for `ProjectionFov::fovy`, rather than arbitrary `Angle`s. This simplifies the signature of `PerspectiveFov` from `PerspectiveFov` to `PerspectiveFov`. - -### Changed -- `Vector` and `Point` are now constrained to require specific operators to be - overloaded. This means that generic code can now use operators, instead of - the operator methods. +- The following trait constraints were removed from `Angle`: `Debug`, + `ScalarConv`, `Into>`, `Into>`. +- `Angle` no longer requires `One`, and the implementations have been removed + from `Deg` and `Rad`. This is because angles do not close over multiplication, + and therefore cannot have a multiplicative identity. If we were truly accurate, + `Angle * Angle` would return an `Angle^2` (not supported by the current api). +- Make remainder operators on `Angle`s make sense from the perspective of + dimensional analysis. +- Moved free trigonometric functions onto `Angle`. ### Removed - Remove redundant `Point::{min, max}` methods - these are now covered by the @@ -33,10 +42,14 @@ This project adheres to [Semantic Versioning](http://semver.org/). - Remove `Vector::one`. Vectors don't really have a multiplicative identity. If you really want a `one` vector, you can do something like: `Vector::from_value(1.0)`. -- Remove operator methods from `Vector` and `Point` traits in favor of operator - overloading. -- Remove `*_self` methods from `Vector` and `Point`. These were of little - performance benefit, and assignment operator overloading will be coming soon! +- Remove operator methods from `Vector`, `Point`, and `Angle` traits in favor of + operator overloading. +- Remove `*_self` methods from `Vector`, `Point`, and `Angle`. These were of + little performance benefit, and assignment operator overloading will be + coming soon! +- Remove `#[derive(Hash)]` from `Deg` and `Rad`. This could never really be used + these types, because they expect to be given a `BaseFloat` under normal + circumstances. ## [v0.6.0] - 2015-12-12 diff --git a/src/angle.rs b/src/angle.rs index 51a48dd..7a322ea 100644 --- a/src/angle.rs +++ b/src/angle.rs @@ -22,17 +22,17 @@ use std::ops::*; use rand::{Rand, Rng}; use rand::distributions::range::SampleRange; -use rust_num::{Float, One, Zero}; +use rust_num::{Float, Zero}; use rust_num::traits::cast; use approx::ApproxEq; use num::BaseFloat; /// An angle, in radians -#[derive(Copy, Clone, PartialEq, PartialOrd, Hash, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)] pub struct Rad { pub s: S } /// An angle, in degrees -#[derive(Copy, Clone, PartialEq, PartialOrd, Hash, RustcEncodable, RustcDecodable)] +#[derive(Copy, Clone, PartialEq, PartialOrd, RustcEncodable, RustcDecodable)] pub struct Deg { pub s: S } /// Create a new angle, in radians @@ -43,272 +43,173 @@ pub struct Deg { pub s: S } impl From> for Deg where S: BaseFloat { #[inline] fn from(r: Rad) -> Deg { - deg(r.s * cast(180.0 / f64::consts::PI).unwrap()) + Deg::new(r.s * cast(180.0 / f64::consts::PI).unwrap()) } } impl From> for Rad where S: BaseFloat { #[inline] fn from(d: Deg) -> Rad { - rad(d.s * cast(f64::consts::PI / 180.0).unwrap()) + Rad::new(d.s * cast(f64::consts::PI / 180.0).unwrap()) } } -/// 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 -+ Into> -+ Into> -+ ScalarConv -+ fmt::Debug +pub trait Angle where + Self: Copy + Clone, + Self: PartialEq + PartialOrd, + // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 + Self: ApproxEq::Unitless>, + + Self: Neg, + Self: Add, + Self: Sub, + Self: Rem, + Self: Mul<::Unitless, Output = Self>, + Self: Div::Unitless>, + Self: Div<::Unitless, Output = Self>, { - /// Create a new angle from any other valid angle. - fn from>(theta: A) -> Self; + type Unitless: BaseFloat; - /// 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 } + /// Create an angle from a unitless value. + fn new(value: Self::Unitless) -> Self; /// 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::full_turn(); - self.rem_self_s(full_turn.s().clone()); - if *self < Self::zero() { self.add_self_a(full_turn) }; + fn normalize(self) -> Self { + let rem = self % Self::full_turn(); + if rem < Self::zero() { rem + Self::full_turn() } else { rem } } /// Return the angle rotated by half a turn #[inline] - fn opposite(&self) -> Self { - self.add_a(Self::turn_div_2()).normalize() + fn opposite(self) -> Self { + Self::normalize(self + Self::turn_div_2()) } /// 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 bisect(self, other: Self) -> Self { + let half = cast(0.5f64).unwrap(); + Self::normalize((self - other) * half + self) } + fn zero() -> Self; fn full_turn() -> Self; - - #[inline] fn turn_div_2() -> Self { Self::full_turn().div_s(cast(2i8).unwrap()) } - #[inline] fn turn_div_3() -> Self { Self::full_turn().div_s(cast(3i8).unwrap()) } - #[inline] fn turn_div_4() -> Self { Self::full_turn().div_s(cast(4i8).unwrap()) } - #[inline] fn turn_div_6() -> Self { Self::full_turn().div_s(cast(6i8).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>, S: BaseFloat> Add for Rad { - type Output = Rad; + fn turn_div_2() -> Self; + fn turn_div_3() -> Self; + fn turn_div_4() -> Self; + fn turn_div_6() -> Self; #[inline] - fn add(self, other: R) -> Rad { rad(self.s + other.into().s) } + fn equiv(&self, other: &Self) -> bool { + self.normalize() == other.normalize() + } + + fn sin(self) -> Self::Unitless; + fn cos(self) -> Self::Unitless; + fn tan(self) -> Self::Unitless; + fn sin_cos(self) -> (Self::Unitless, Self::Unitless); + + #[inline] fn cot(self) -> Self::Unitless { Self::tan(self).recip() } + #[inline] fn sec(self) -> Self::Unitless { Self::cos(self).recip() } + #[inline] fn csc(self) -> Self::Unitless { Self::sin(self).recip() } + + 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; } -impl>, S: BaseFloat> Add for Deg { - type Output = Deg; +macro_rules! impl_angle { + ($Angle:ident, $fmt:expr, $full_turn:expr, $hi:expr) => { + impl Angle for $Angle { + type Unitless = S; - #[inline] - fn add(self, other: R) -> Deg { deg(self.s + other.into().s) } -} + #[inline] + fn new(value: S) -> $Angle { + $Angle { s: value } + } -impl>, S: BaseFloat> Sub for Rad { - type Output = Rad; + #[inline] + fn zero() -> $Angle { + $Angle::new(S::zero()) + } - #[inline] - fn sub(self, other: R) -> Rad { rad(self.s - other.into().s) } -} + #[inline] fn full_turn() -> $Angle { $Angle::new(cast($full_turn).unwrap()) } + #[inline] fn turn_div_2() -> $Angle { let factor: S = cast(2).unwrap(); $Angle::full_turn() / factor } + #[inline] fn turn_div_3() -> $Angle { let factor: S = cast(3).unwrap(); $Angle::full_turn() / factor } + #[inline] fn turn_div_4() -> $Angle { let factor: S = cast(4).unwrap(); $Angle::full_turn() / factor } + #[inline] fn turn_div_6() -> $Angle { let factor: S = cast(6).unwrap(); $Angle::full_turn() / factor } -impl>, S: BaseFloat> Sub for Deg { - type Output = Deg; + #[inline] fn sin(self) -> S { Rad::from(self).s.sin() } + #[inline] fn cos(self) -> S { Rad::from(self).s.cos() } + #[inline] fn tan(self) -> S { Rad::from(self).s.tan() } + #[inline] fn sin_cos(self) -> (S, S) { Rad::from(self).s.sin_cos() } - #[inline] - fn sub(self, other: R) -> Deg { deg(self.s - other.into().s) } -} + #[inline] fn asin(a: S) -> $Angle { Rad::new(a.asin()).into() } + #[inline] fn acos(a: S) -> $Angle { Rad::new(a.acos()).into() } + #[inline] fn atan(a: S) -> $Angle { Rad::new(a.atan()).into() } + #[inline] fn atan2(a: S, b: S) -> $Angle { Rad::new(a.atan2(b)).into() } + } -impl Neg for Rad { - type Output = Rad; + impl Neg for $Angle { + type Output = $Angle; - #[inline] - fn neg(self) -> Rad { rad(-self.s) } -} -impl Neg for Deg { - type Output = Deg; + #[inline] + fn neg(self) -> $Angle { $Angle::new(-self.s) } + } - #[inline] - fn neg(self) -> Deg { deg(-self.s) } -} + impl<'a, S: BaseFloat> Neg for &'a $Angle { + type Output = $Angle; -impl Zero for Rad { - #[inline] - fn zero() -> Rad { rad(S::zero()) } - #[inline] - fn is_zero(&self) -> bool { *self == Self::zero() } -} -impl Zero for Deg { - #[inline] - fn zero() -> Deg { deg(S::zero()) } - #[inline] - fn is_zero(&self) -> bool { *self == Self::zero() } -} + #[inline] + fn neg(self) -> $Angle { $Angle::new(-self.s) } + } -impl>, S: BaseFloat> Mul for Rad { - type Output = Rad; + impl_binary_operator!( Add<$Angle > for $Angle { + fn add(lhs, rhs) -> $Angle { $Angle::new(lhs.s + rhs.s) } + }); + impl_binary_operator!( Sub<$Angle > for $Angle { + fn sub(lhs, rhs) -> $Angle { $Angle::new(lhs.s - rhs.s) } + }); + impl_binary_operator!( Div<$Angle > for $Angle { + fn div(lhs, rhs) -> S { lhs.s / rhs.s } + }); + impl_binary_operator!( Rem<$Angle > for $Angle { + fn rem(lhs, rhs) -> $Angle { $Angle::new(lhs.s % rhs.s) } + }); - #[inline] - fn mul(self, other: R) -> Rad { rad(self.s * other.into().s) } -} + impl_binary_operator!( Mul for $Angle { + fn mul(lhs, scalar) -> $Angle { $Angle::new(lhs.s * scalar) } + }); + impl_binary_operator!( Div for $Angle { + fn div(lhs, scalar) -> $Angle { $Angle::new(lhs.s / scalar) } + }); -impl>, S: BaseFloat> Mul for Deg { - type Output = Deg; + impl ApproxEq for $Angle { + type Epsilon = S; - #[inline] - fn mul(self, other: R) -> Deg { deg(self.s * other.into().s) } -} + #[inline] + fn approx_eq_eps(&self, other: &$Angle, epsilon: &S) -> bool { + self.s.approx_eq_eps(&other.s, epsilon) + } + } -impl One for Rad { - #[inline] - fn one() -> Rad { rad(S::one()) } -} -impl One for Deg { - #[inline] - fn one() -> Deg { deg(S::one()) } -} + impl Rand for $Angle { + #[inline] + fn rand(rng: &mut R) -> $Angle { + $Angle::new(rng.gen_range(cast(-$hi).unwrap(), cast($hi).unwrap())) + } + } -const PI_2: f64 = f64::consts::PI * 2f64; -impl -Angle for Rad { - #[inline] fn from>(theta: A) -> Rad { theta.into() } - #[inline] fn full_turn() -> Rad { rad(cast(PI_2).unwrap()) } -} - -impl -Angle for Deg { - #[inline] fn from>(theta: A) -> Deg { theta.into() } - #[inline] fn full_turn() -> Deg { deg(cast(360i32).unwrap()) } -} - -#[inline] pub fn sin>>(theta: R) -> S { theta.into().s.sin() } -#[inline] pub fn cos>>(theta: R) -> S { theta.into().s.cos() } -#[inline] pub fn tan>>(theta: R) -> S { theta.into().s.tan() } -#[inline] pub fn sin_cos>>(theta: R) -> (S, S) { theta.into().s.sin_cos() } - -#[inline] pub fn cot>>(theta: R) -> S { tan(theta.into()).recip() } -#[inline] pub fn sec>>(theta: R) -> S { cos(theta.into()).recip() } -#[inline] pub fn csc>>(theta: R) -> S { sin(theta.into()).recip() } - -#[inline] pub fn asin>>(s: S) -> R { rad(s.asin()).into() } -#[inline] pub fn acos>>(s: S) -> R { rad(s.acos()).into() } -#[inline] pub fn atan>>(s: S) -> R { rad(s.atan()).into() } -#[inline] pub fn atan2>>(a: S, b: S) -> R { rad(a.atan2(b)).into() } - -impl -fmt::Debug for Rad { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?} rad", self.s) + impl fmt::Debug for $Angle { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, $fmt, self.s) + } + } } } -impl -fmt::Debug for Deg { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}°", self.s) - } -} - -impl ApproxEq for Rad { - type Epsilon = S; - - #[inline] - fn approx_eq_eps(&self, other: &Rad, epsilon: &S) -> bool { - self.s.approx_eq_eps(&other.s, epsilon) - } -} - -impl ApproxEq for Deg { - type Epsilon = S; - - #[inline] - fn approx_eq_eps(&self, other: &Deg, epsilon: &S) -> bool { - self.s.approx_eq_eps(&other.s, epsilon) - } -} - -impl Rand for Rad { - #[inline] - fn rand(rng: &mut R) -> Rad { - let angle: S = rng.gen_range(cast(-f64::consts::PI).unwrap(), cast(f64::consts::PI).unwrap()); - rad(angle) - } -} - -impl Rand for Deg { - #[inline] - fn rand(rng: &mut R) -> Deg { - let angle: S = rng.gen_range(cast(-180f64).unwrap(), cast(180f64).unwrap()); - deg(angle) - } -} +impl_angle!(Rad, "{:?} rad", f64::consts::PI * 2.0, f64::consts::PI); +impl_angle!(Deg, "{:?}°", 360, 180); diff --git a/src/matrix.rs b/src/matrix.rs index 03faba0..399e0a2 100644 --- a/src/matrix.rs +++ b/src/matrix.rs @@ -25,7 +25,7 @@ use rand::{Rand, Rng}; use rust_num::{Zero, One}; use rust_num::traits::cast; -use angle::{Rad, sin, cos, sin_cos}; +use angle::{Angle, Rad}; use approx::ApproxEq; use array::Array; use num::BaseFloat; @@ -71,11 +71,11 @@ impl Matrix2 { #[inline] pub fn from_angle(theta: Rad) -> Matrix2 { - let cos_theta = cos(theta.clone()); - let sin_theta = sin(theta.clone()); + let cos_theta = Rad::cos(theta); + let sin_theta = Rad::sin(theta); - Matrix2::new(cos_theta.clone(), sin_theta.clone(), - -sin_theta.clone(), cos_theta.clone()) + Matrix2::new(cos_theta, sin_theta, + -sin_theta, cos_theta) } } @@ -118,27 +118,27 @@ impl Matrix3 { /// Create a rotation matrix from a rotation around the `x` axis (pitch). pub fn from_angle_x(theta: Rad) -> Matrix3 { // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations - let (s, c) = sin_cos(theta); + let (s, c) = Rad::sin_cos(theta); Matrix3::new(S::one(), S::zero(), S::zero(), - S::zero(), c.clone(), s.clone(), - S::zero(), -s.clone(), c.clone()) + S::zero(), c, s, + S::zero(), -s, c) } /// Create a rotation matrix from a rotation around the `y` axis (yaw). pub fn from_angle_y(theta: Rad) -> Matrix3 { // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations - let (s, c) = sin_cos(theta); - Matrix3::new(c.clone(), S::zero(), -s.clone(), + let (s, c) = Rad::sin_cos(theta); + Matrix3::new(c, S::zero(), -s, S::zero(), S::one(), S::zero(), - s.clone(), S::zero(), c.clone()) + s, S::zero(), c) } /// Create a rotation matrix from a rotation around the `z` axis (roll). pub fn from_angle_z(theta: Rad) -> Matrix3 { // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations - let (s, c) = sin_cos(theta); - Matrix3::new( c.clone(), s.clone(), S::zero(), - -s.clone(), c.clone(), S::zero(), + let (s, c) = Rad::sin_cos(theta); + Matrix3::new( c, s, S::zero(), + -s, c, S::zero(), S::zero(), S::zero(), S::one()) } @@ -151,18 +151,18 @@ impl Matrix3 { /// - `z`: the angular rotation around the `z` axis (roll). pub fn from_euler(x: Rad, y: Rad, z: Rad) -> Matrix3 { // http://en.wikipedia.org/wiki/Rotation_matrix#General_rotations - let (sx, cx) = sin_cos(x); - let (sy, cy) = sin_cos(y); - let (sz, cz) = sin_cos(z); + let (sx, cx) = Rad::sin_cos(x); + let (sy, cy) = Rad::sin_cos(y); + let (sz, cz) = Rad::sin_cos(z); - Matrix3::new( cy * cz, cy * sz, -sy, - -cx * sz + sx * sy * cz, cx * cz + sx * sy * sz, sx * cy, - sx * sz + cx * sy * cz, -sx * cz + cx * sy * sz, cx * cy) + Matrix3::new(cy * cz, cy * sz, -sy, + -cx * sz + sx * sy * cz, cx * cz + sx * sy * sz, sx * cy, + sx * sz + cx * sy * cz, -sx * cz + cx * sy * sz, cx * cy) } /// Create a rotation matrix from an angle around an arbitrary axis. pub fn from_axis_angle(axis: Vector3, angle: Rad) -> Matrix3 { - let (s, c) = sin_cos(angle); + let (s, c) = Rad::sin_cos(angle); let _1subc = S::one() - c; Matrix3::new(_1subc * axis.x * axis.x + c, diff --git a/src/projection.rs b/src/projection.rs index e583930..4aaee72 100644 --- a/src/projection.rs +++ b/src/projection.rs @@ -16,7 +16,7 @@ use rust_num::{Zero, One}; use rust_num::traits::cast; -use angle::{Angle, Rad, tan, cot}; +use angle::{Angle, Rad}; use matrix::Matrix4; use num::BaseFloat; @@ -74,8 +74,9 @@ pub struct PerspectiveFov { impl PerspectiveFov { pub fn to_perspective(&self) -> Perspective { - let angle = self.fovy.div_s(cast(2i8).unwrap()); - let ymax = self.near * tan(angle); + let two: S = cast(2).unwrap(); + let angle = self.fovy / two; + let ymax = self.near * Rad::tan(angle); let xmax = ymax * self.aspect; Perspective { @@ -98,8 +99,8 @@ impl From> for Matrix4 { assert!(persp.far > S::zero(), "The far plane distance cannot be below zero, found: {:?}", persp.far); assert!(persp.far > persp.near, "The far plane cannot be closer than the near plane, found: far: {:?}, near: {:?}", persp.far, persp.near); - let f = cot(persp.fovy.div_s(cast(2i8).unwrap())); - let two: S = cast(2i8).unwrap(); + let two: S = cast(2).unwrap(); + let f = Rad::cot(persp.fovy / two); let c0r0 = f / persp.aspect; let c0r1 = S::zero(); @@ -187,7 +188,7 @@ pub struct Ortho { impl From> for Matrix4 { fn from(ortho: Ortho) -> Matrix4 { - let two: S = cast(2i8).unwrap(); + let two: S = cast(2).unwrap(); let c0r0 = two / (ortho.right - ortho.left); let c0r1 = S::zero(); diff --git a/src/quaternion.rs b/src/quaternion.rs index d770885..3d57ef3 100644 --- a/src/quaternion.rs +++ b/src/quaternion.rs @@ -13,7 +13,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use std::f64; use std::fmt; use std::mem; use std::ops::*; @@ -22,7 +21,7 @@ use rand::{Rand, Rng}; use rust_num::{Float, One, Zero}; use rust_num::traits::cast; -use angle::{Angle, Rad, acos, sin, sin_cos, rad}; +use angle::{Angle, Rad}; use approx::ApproxEq; use matrix::{Matrix3, Matrix4}; use num::BaseFloat; @@ -210,12 +209,12 @@ impl Quaternion { dot }; - let theta: Rad = acos(robust_dot.clone()); + let theta = Rad::acos(robust_dot.clone()); - let scale1 = sin(theta.mul_s(S::one() - amount)); - let scale2 = sin(theta.mul_s(amount)); + let scale1 = Rad::sin(theta * (S::one() - amount)); + let scale2 = Rad::sin(theta * amount); - (self * scale1 + other * scale2) * sin(theta).recip() + (self * scale1 + other * scale2) * Rad::sin(theta).recip() } } @@ -238,22 +237,21 @@ impl Quaternion { if test > sig * unit { ( - rad(S::zero()), - rad(cast(f64::consts::FRAC_PI_2).unwrap()), - rad(two * qx.atan2(qw)), + Rad::zero(), + Rad::turn_div_4(), + Rad::atan2(qx, qw) * two, ) } else if test < -sig * unit { - let y: S = cast(f64::consts::FRAC_PI_2).unwrap(); ( - rad(S::zero()), - rad(-y), - rad(two * qx.atan2(qw)), + Rad::zero(), + -Rad::turn_div_4(), + Rad::atan2(qx, qw) * two, ) } else { ( - rad((two * (qy * qw - qx * qz)).atan2(one - two * (sqy + sqz))), - rad((two * (qx * qy + qz * qw)).asin()), - rad((two * (qx * qw - qy * qz)).atan2(one - two * (sqx + sqz))), + Rad::atan2(two * (qy * qw - qx * qz), one - two * (sqy + sqz)), + Rad::asin(two * (qx * qy + qz * qw)), + Rad::atan2(two * (qx * qw - qy * qz), one - two * (sqx + sqz)), ) } } @@ -362,16 +360,16 @@ impl Rotation> for Quaternion { impl Rotation3 for Quaternion { #[inline] fn from_axis_angle(axis: Vector3, angle: Rad) -> Quaternion { - let (s, c) = sin_cos(angle.mul_s(cast(0.5f64).unwrap())); + let (s, c) = Rad::sin_cos(angle * cast(0.5f64).unwrap()); Quaternion::from_sv(c, axis * s) } /// - [Maths - Conversion Euler to Quaternion] /// (http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm) fn from_euler(x: Rad, y: Rad, z: Rad) -> Quaternion { - let (s1, c1) = sin_cos(x.mul_s(cast(0.5f64).unwrap())); - let (s2, c2) = sin_cos(y.mul_s(cast(0.5f64).unwrap())); - let (s3, c3) = sin_cos(z.mul_s(cast(0.5f64).unwrap())); + let (s1, c1) = Rad::sin_cos(x * cast(0.5f64).unwrap()); + let (s2, c2) = Rad::sin_cos(y * cast(0.5f64).unwrap()); + let (s3, c3) = Rad::sin_cos(z * cast(0.5f64).unwrap()); Quaternion::new(c1 * c2 * c3 - s1 * s2 * s3, s1 * s2 * c3 + c1 * c2 * s3, diff --git a/src/rotation.rs b/src/rotation.rs index d30e556..9efd908 100644 --- a/src/rotation.rs +++ b/src/rotation.rs @@ -13,7 +13,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -use angle::{Rad, acos}; +use angle::{Angle, Rad}; use approx::ApproxEq; use matrix::{Matrix, SquareMatrix}; use matrix::{Matrix2, Matrix3}; @@ -186,7 +186,7 @@ impl Rotation> for Basis2 { #[inline] fn between_vectors(a: Vector2, b: Vector2) -> Basis2 { - Rotation2::from_angle(acos(a.dot(b)) ) + Rotation2::from_angle(Rad::acos(a.dot(b)) ) } #[inline] diff --git a/src/vector.rs b/src/vector.rs index 407602a..6b4fcf6 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -95,7 +95,7 @@ use rand::{Rand, Rng}; use rust_num::{NumCast, Zero, One}; -use angle::{Rad, atan2, acos}; +use angle::{Angle, Rad}; use approx::ApproxEq; use array::Array; use num::{BaseNum, BaseFloat, PartialOrd}; @@ -441,21 +441,21 @@ pub trait EuclideanVector: Vector + Sized where impl EuclideanVector for Vector2 { #[inline] fn angle(self, other: Vector2) -> Rad { - atan2(self.perp_dot(other), self.dot(other)) + Rad::atan2(self.perp_dot(other), self.dot(other)) } } impl EuclideanVector for Vector3 { #[inline] fn angle(self, other: Vector3) -> Rad { - atan2(self.cross(other).length(), self.dot(other)) + Rad::atan2(self.cross(other).length(), self.dot(other)) } } impl EuclideanVector for Vector4 { #[inline] fn angle(self, other: Vector4) -> Rad { - acos(self.dot(other) / (self.length() * other.length())) + Rad::acos(self.dot(other) / (self.length() * other.length())) } } diff --git a/tests/angle.rs b/tests/angle.rs index 02bf6f0..6a5643d 100644 --- a/tests/angle.rs +++ b/tests/angle.rs @@ -41,9 +41,9 @@ fn conv() { fn equiv() { assert!(Deg::::full_turn().equiv(&-Deg::::full_turn())); assert!(Deg::::turn_div_2().equiv(&-Deg::::turn_div_2())); - assert!(Deg::::turn_div_3().sub_a(Deg::::full_turn()).equiv(&Deg::::turn_div_3())); + assert!((Deg::::turn_div_3() - Deg::::full_turn()).equiv(&Deg::::turn_div_3())); assert!(Rad::::full_turn().equiv(&-Rad::::full_turn())); assert!(Rad::::turn_div_2().equiv(&-Rad::::turn_div_2())); - assert!(Rad::::turn_div_3().sub_a(Rad::::full_turn()).equiv(&Rad::::turn_div_3())); + assert!((Rad::::turn_div_3() - Rad::::full_turn()).equiv(&Rad::::turn_div_3())); }