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 { fn equiv(&self, other: &Self) -> bool {
self.normalize() == other.normalize() 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 { 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 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_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_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 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> { 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::{Zero, One};
use rust_num::traits::cast; use rust_num::traits::cast;
use angle::{Rad, sin, cos, sin_cos}; use angle::{Angle, Rad};
use approx::ApproxEq; use approx::ApproxEq;
use array::Array; use array::Array;
use num::BaseFloat; use num::BaseFloat;
@ -71,11 +71,11 @@ impl<S: BaseFloat> Matrix2<S> {
#[inline] #[inline]
pub fn from_angle(theta: Rad<S>) -> Matrix2<S> { pub fn from_angle(theta: Rad<S>) -> Matrix2<S> {
let cos_theta = cos(theta.clone()); let cos_theta = Rad::cos(theta);
let sin_theta = sin(theta.clone()); let sin_theta = Rad::sin(theta);
Matrix2::new(cos_theta.clone(), sin_theta.clone(), Matrix2::new(cos_theta, sin_theta,
-sin_theta.clone(), cos_theta.clone()) -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). /// Create a rotation matrix from a rotation around the `x` axis (pitch).
pub fn from_angle_x(theta: Rad<S>) -> Matrix3<S> { pub fn from_angle_x(theta: Rad<S>) -> Matrix3<S> {
// http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations // 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(), Matrix3::new(S::one(), S::zero(), S::zero(),
S::zero(), c.clone(), s.clone(), S::zero(), c, s,
S::zero(), -s.clone(), c.clone()) S::zero(), -s, c)
} }
/// Create a rotation matrix from a rotation around the `y` axis (yaw). /// Create a rotation matrix from a rotation around the `y` axis (yaw).
pub fn from_angle_y(theta: Rad<S>) -> Matrix3<S> { pub fn from_angle_y(theta: Rad<S>) -> Matrix3<S> {
// http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
let (s, c) = sin_cos(theta); let (s, c) = Rad::sin_cos(theta);
Matrix3::new(c.clone(), S::zero(), -s.clone(), Matrix3::new(c, S::zero(), -s,
S::zero(), S::one(), S::zero(), 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). /// Create a rotation matrix from a rotation around the `z` axis (roll).
pub fn from_angle_z(theta: Rad<S>) -> Matrix3<S> { pub fn from_angle_z(theta: Rad<S>) -> Matrix3<S> {
// http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
let (s, c) = sin_cos(theta); let (s, c) = Rad::sin_cos(theta);
Matrix3::new( c.clone(), s.clone(), S::zero(), Matrix3::new( c, s, S::zero(),
-s.clone(), c.clone(), S::zero(), -s, c, S::zero(),
S::zero(), S::zero(), S::one()) S::zero(), S::zero(), S::one())
} }
@ -151,9 +151,9 @@ impl<S: BaseFloat> Matrix3<S> {
/// - `z`: the angular rotation around the `z` axis (roll). /// - `z`: the angular rotation around the `z` axis (roll).
pub fn from_euler(x: Rad<S>, y: Rad<S>, z: Rad<S>) -> Matrix3<S> { pub fn from_euler(x: Rad<S>, y: Rad<S>, z: Rad<S>) -> Matrix3<S> {
// http://en.wikipedia.org/wiki/Rotation_matrix#General_rotations // http://en.wikipedia.org/wiki/Rotation_matrix#General_rotations
let (sx, cx) = sin_cos(x); let (sx, cx) = Rad::sin_cos(x);
let (sy, cy) = sin_cos(y); let (sy, cy) = Rad::sin_cos(y);
let (sz, cz) = sin_cos(z); let (sz, cz) = Rad::sin_cos(z);
Matrix3::new(cy * cz, cy * sz, -sy, Matrix3::new(cy * cz, cy * sz, -sy,
-cx * sz + sx * sy * cz, cx * cz + sx * sy * sz, sx * cy, -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. /// Create a rotation matrix from an angle around an arbitrary axis.
pub fn from_axis_angle(axis: Vector3<S>, angle: Rad<S>) -> Matrix3<S> { 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; let _1subc = S::one() - c;
Matrix3::new(_1subc * axis.x * axis.x + c, Matrix3::new(_1subc * axis.x * axis.x + c,

View file

@ -16,7 +16,7 @@
use rust_num::{Zero, One}; use rust_num::{Zero, One};
use rust_num::traits::cast; use rust_num::traits::cast;
use angle::{Angle, Rad, tan, cot}; use angle::{Angle, Rad};
use matrix::Matrix4; use matrix::Matrix4;
use num::BaseFloat; use num::BaseFloat;
@ -76,7 +76,7 @@ impl<S: BaseFloat> PerspectiveFov<S> {
pub fn to_perspective(&self) -> Perspective<S> { pub fn to_perspective(&self) -> Perspective<S> {
let two: S = cast(2).unwrap(); let two: S = cast(2).unwrap();
let angle = self.fovy / two; let angle = self.fovy / two;
let ymax = self.near * tan(angle); let ymax = self.near * Rad::tan(angle);
let xmax = ymax * self.aspect; let xmax = ymax * self.aspect;
Perspective { 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); 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 two: S = cast(2).unwrap();
let f = cot(persp.fovy / two); let f = Rad::cot(persp.fovy / two);
let c0r0 = f / persp.aspect; let c0r0 = f / persp.aspect;
let c0r1 = S::zero(); let c0r1 = S::zero();

View file

@ -13,7 +13,6 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use std::f64;
use std::fmt; use std::fmt;
use std::mem; use std::mem;
use std::ops::*; use std::ops::*;
@ -22,7 +21,7 @@ use rand::{Rand, Rng};
use rust_num::{Float, One, Zero}; use rust_num::{Float, One, Zero};
use rust_num::traits::cast; use rust_num::traits::cast;
use angle::{Angle, Rad, acos, sin, sin_cos, rad}; use angle::{Angle, Rad};
use approx::ApproxEq; use approx::ApproxEq;
use matrix::{Matrix3, Matrix4}; use matrix::{Matrix3, Matrix4};
use num::BaseFloat; use num::BaseFloat;
@ -210,12 +209,12 @@ impl<S: BaseFloat> Quaternion<S> {
dot dot
}; };
let theta: Rad<S> = acos(robust_dot.clone()); let theta = Rad::acos(robust_dot.clone());
let scale1 = sin(theta * (S::one() - amount)); let scale1 = Rad::sin(theta * (S::one() - amount));
let scale2 = sin(theta * 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 { if test > sig * unit {
( (
rad(S::zero()), Rad::zero(),
rad(cast(f64::consts::FRAC_PI_2).unwrap()), Rad::turn_div_4(),
rad(two * qx.atan2(qw)), Rad::atan2(qx, qw) * two,
) )
} else if test < -sig * unit { } else if test < -sig * unit {
let y: S = cast(f64::consts::FRAC_PI_2).unwrap();
( (
rad(S::zero()), Rad::zero(),
rad(-y), -Rad::turn_div_4(),
rad(two * qx.atan2(qw)), Rad::atan2(qx, qw) * two,
) )
} else { } else {
( (
rad((two * (qy * qw - qx * qz)).atan2(one - two * (sqy + sqz))), Rad::atan2(two * (qy * qw - qx * qz), one - two * (sqy + sqz)),
rad((two * (qx * qy + qz * qw)).asin()), Rad::asin(two * (qx * qy + qz * qw)),
rad((two * (qx * qw - qy * qz)).atan2(one - two * (sqx + sqz))), 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> { impl<S: BaseFloat> Rotation3<S> for Quaternion<S> {
#[inline] #[inline]
fn from_axis_angle(axis: Vector3<S>, angle: Rad<S>) -> Quaternion<S> { 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) Quaternion::from_sv(c, axis * s)
} }
/// - [Maths - Conversion Euler to Quaternion] /// - [Maths - Conversion Euler to Quaternion]
/// (http://www.euclideanspace.com/maths/geometry/rotations/conversions/eulerToQuaternion/index.htm) /// (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> { 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 (s1, c1) = Rad::sin_cos(x * cast(0.5f64).unwrap());
let (s2, c2) = sin_cos(y * cast(0.5f64).unwrap()); let (s2, c2) = Rad::sin_cos(y * cast(0.5f64).unwrap());
let (s3, c3) = sin_cos(z * cast(0.5f64).unwrap()); let (s3, c3) = Rad::sin_cos(z * cast(0.5f64).unwrap());
Quaternion::new(c1 * c2 * c3 - s1 * s2 * s3, Quaternion::new(c1 * c2 * c3 - s1 * s2 * s3,
s1 * s2 * c3 + c1 * c2 * s3, s1 * s2 * c3 + c1 * c2 * s3,

View file

@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use angle::{Rad, acos}; use angle::{Angle, Rad};
use approx::ApproxEq; use approx::ApproxEq;
use matrix::{Matrix, SquareMatrix}; use matrix::{Matrix, SquareMatrix};
use matrix::{Matrix2, Matrix3}; use matrix::{Matrix2, Matrix3};
@ -186,7 +186,7 @@ impl<S: BaseFloat> Rotation<Point2<S>> for Basis2<S> {
#[inline] #[inline]
fn between_vectors(a: Vector2<S>, b: Vector2<S>) -> Basis2<S> { 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] #[inline]

View file

@ -95,7 +95,7 @@ use rand::{Rand, Rng};
use rust_num::{NumCast, Zero, One}; use rust_num::{NumCast, Zero, One};
use angle::{Rad, atan2, acos}; use angle::{Angle, Rad};
use approx::ApproxEq; use approx::ApproxEq;
use array::Array; use array::Array;
use num::{BaseNum, BaseFloat, PartialOrd}; use num::{BaseNum, BaseFloat, PartialOrd};
@ -441,21 +441,21 @@ pub trait EuclideanVector: Vector + Sized where
impl<S: BaseFloat> EuclideanVector for Vector2<S> { impl<S: BaseFloat> EuclideanVector for Vector2<S> {
#[inline] #[inline]
fn angle(self, other: Vector2<S>) -> Rad<S> { 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> { impl<S: BaseFloat> EuclideanVector for Vector3<S> {
#[inline] #[inline]
fn angle(self, other: Vector3<S>) -> Rad<S> { 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> { impl<S: BaseFloat> EuclideanVector for Vector4<S> {
#[inline] #[inline]
fn angle(self, other: Vector4<S>) -> Rad<S> { 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()))
} }
} }