diff --git a/src/angle.rs b/src/angle.rs index 94dbf05..3998c75 100644 --- a/src/angle.rs +++ b/src/angle.rs @@ -104,24 +104,22 @@ pub trait Angle where 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; } -#[inline] pub fn bisect(a: A, b: A) -> A { a.bisect(b) } - -#[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() } - macro_rules! impl_angle { ($Angle:ident, $fmt:expr, $full_turn:expr, $hi:expr) => { impl Angle for $Angle { @@ -148,6 +146,16 @@ macro_rules! impl_angle { #[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 } + + #[inline] fn sin(self) -> S { let rad: Rad = self.into(); rad.s.sin() } + #[inline] fn cos(self) -> S { let rad: Rad = self.into(); rad.s.cos() } + #[inline] fn tan(self) -> S { let rad: Rad = self.into(); rad.s.tan() } + #[inline] fn sin_cos(self) -> (S, S) { let rad: Rad = self.into(); rad.s.sin_cos() } + + #[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 $Angle { 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 4987c63..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; @@ -76,7 +76,7 @@ impl PerspectiveFov { pub fn to_perspective(&self) -> Perspective { let two: S = cast(2).unwrap(); let angle = self.fovy / two; - let ymax = self.near * tan(angle); + let ymax = self.near * Rad::tan(angle); let xmax = ymax * self.aspect; Perspective { @@ -100,7 +100,7 @@ impl From> for Matrix4 { assert!(persp.far > persp.near, "The far plane cannot be closer than the near plane, found: far: {:?}, near: {:?}", persp.far, persp.near); let two: S = cast(2).unwrap(); - let f = cot(persp.fovy / two); + let f = Rad::cot(persp.fovy / two); let c0r0 = f / persp.aspect; let c0r1 = S::zero(); diff --git a/src/quaternion.rs b/src/quaternion.rs index f0816c3..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 * (S::one() - amount)); - let scale2 = sin(theta * 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 * 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 * cast(0.5f64).unwrap()); - let (s2, c2) = sin_cos(y * cast(0.5f64).unwrap()); - let (s3, c3) = sin_cos(z * 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())) } }