Move free trigonometric functions onto Angle trait

This commit is contained in:
Brendan Zabarauskas 2015-12-13 21:33:37 +11:00
parent 5b9eeb15a0
commit 612be7fecc
6 changed files with 72 additions and 66 deletions

View file

@ -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: Angle>(a: A, b: A) -> A { a.bisect(b) }
#[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() }
macro_rules! impl_angle {
($Angle:ident, $fmt:expr, $full_turn:expr, $hi:expr) => {
impl<S: BaseFloat> Angle for $Angle<S> {
@ -148,6 +146,16 @@ macro_rules! impl_angle {
#[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 }
#[inline] fn sin(self) -> S { let rad: Rad<S> = self.into(); rad.s.sin() }
#[inline] fn cos(self) -> S { let rad: Rad<S> = self.into(); rad.s.cos() }
#[inline] fn tan(self) -> S { let rad: Rad<S> = self.into(); rad.s.tan() }
#[inline] fn sin_cos(self) -> (S, S) { let rad: Rad<S> = self.into(); rad.s.sin_cos() }
#[inline] fn asin(a: S) -> $Angle<S> { Rad::new(a.asin()).into() }
#[inline] fn acos(a: S) -> $Angle<S> { Rad::new(a.acos()).into() }
#[inline] fn atan(a: S) -> $Angle<S> { Rad::new(a.atan()).into() }
#[inline] fn atan2(a: S, b: S) -> $Angle<S> { Rad::new(a.atan2(b)).into() }
}
impl<S: BaseFloat> Neg for $Angle<S> {

View file

@ -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<S: BaseFloat> Matrix2<S> {
#[inline]
pub fn from_angle(theta: Rad<S>) -> Matrix2<S> {
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<S: BaseFloat> Matrix3<S> {
/// Create a rotation matrix from a rotation around the `x` axis (pitch).
pub fn from_angle_x(theta: Rad<S>) -> Matrix3<S> {
// 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<S>) -> Matrix3<S> {
// 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<S>) -> Matrix3<S> {
// 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,9 +151,9 @@ impl<S: BaseFloat> Matrix3<S> {
/// - `z`: the angular rotation around the `z` axis (roll).
pub fn from_euler(x: Rad<S>, y: Rad<S>, z: Rad<S>) -> Matrix3<S> {
// 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,
@ -162,7 +162,7 @@ impl<S: BaseFloat> Matrix3<S> {
/// Create a rotation matrix from an angle around an arbitrary axis.
pub fn from_axis_angle(axis: Vector3<S>, angle: Rad<S>) -> Matrix3<S> {
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,

View file

@ -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<S: BaseFloat> PerspectiveFov<S> {
pub fn to_perspective(&self) -> Perspective<S> {
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<S: BaseFloat> From<PerspectiveFov<S>> for Matrix4<S> {
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();

View file

@ -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<S: BaseFloat> Quaternion<S> {
dot
};
let theta: Rad<S> = 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<S: BaseFloat> Quaternion<S> {
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<S: BaseFloat> Rotation<Point3<S>> for Quaternion<S> {
impl<S: BaseFloat> Rotation3<S> for Quaternion<S> {
#[inline]
fn from_axis_angle(axis: Vector3<S>, angle: Rad<S>) -> Quaternion<S> {
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<S>, y: Rad<S>, z: Rad<S>) -> Quaternion<S> {
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,

View file

@ -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<S: BaseFloat> Rotation<Point2<S>> for Basis2<S> {
#[inline]
fn between_vectors(a: Vector2<S>, b: Vector2<S>) -> Basis2<S> {
Rotation2::from_angle(acos(a.dot(b)) )
Rotation2::from_angle(Rad::acos(a.dot(b)) )
}
#[inline]

View file

@ -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<S: BaseFloat> EuclideanVector for Vector2<S> {
#[inline]
fn angle(self, other: Vector2<S>) -> Rad<S> {
atan2(self.perp_dot(other), self.dot(other))
Rad::atan2(self.perp_dot(other), self.dot(other))
}
}
impl<S: BaseFloat> EuclideanVector for Vector3<S> {
#[inline]
fn angle(self, other: Vector3<S>) -> Rad<S> {
atan2(self.cross(other).length(), self.dot(other))
Rad::atan2(self.cross(other).length(), self.dot(other))
}
}
impl<S: BaseFloat> EuclideanVector for Vector4<S> {
#[inline]
fn angle(self, other: Vector4<S>) -> Rad<S> {
acos(self.dot(other) / (self.length() * other.length()))
Rad::acos(self.dot(other) / (self.length() * other.length()))
}
}