Merge pull request #279 from bjz/angle-api-cleanups

Angle api cleanups
This commit is contained in:
Brendan Zabarauskas 2015-12-14 07:13:51 +11:00
commit 32a981161a
8 changed files with 202 additions and 289 deletions

View file

@ -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<Rad<S>>`.
- 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<S, A>` to
`PerspectiveFov<S>`.
### 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<Rad<S>>`, `Into<Deg<S>>`.
- `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

View file

@ -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<S> { 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<S> { pub s: S }
/// Create a new angle, in radians
@ -43,272 +43,173 @@ pub struct Deg<S> { pub s: S }
impl<S> From<Rad<S>> for Deg<S> where S: BaseFloat {
#[inline]
fn from(r: Rad<S>) -> Deg<S> {
deg(r.s * cast(180.0 / f64::consts::PI).unwrap())
Deg::new(r.s * cast(180.0 / f64::consts::PI).unwrap())
}
}
impl<S> From<Deg<S>> for Rad<S> where S: BaseFloat {
#[inline]
fn from(d: Deg<S>) -> Rad<S> {
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<S> {
fn from(s: S) -> Self;
fn s<'a>(&'a self) -> &'a S;
fn mut_s<'a>(&'a mut self) -> &'a mut S;
}
impl<S: BaseFloat> ScalarConv<S> for Rad<S> {
#[inline] fn from(s: S) -> Rad<S> { 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<S: BaseFloat> ScalarConv<S> for Deg<S> {
#[inline] fn from(s: S) -> Deg<S> { 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<Epsilon = S>
+ Neg<Output=Self>
+ Into<Rad<S>>
+ Into<Deg<S>>
+ ScalarConv<S>
+ fmt::Debug
pub trait Angle where
Self: Copy + Clone,
Self: PartialEq + PartialOrd,
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
Self: ApproxEq<Epsilon = <Self as Angle>::Unitless>,
Self: Neg<Output = Self>,
Self: Add<Self, Output = Self>,
Self: Sub<Self, Output = Self>,
Self: Rem<Self, Output = Self>,
Self: Mul<<Self as Angle>::Unitless, Output = Self>,
Self: Div<Self, Output = <Self as Angle>::Unitless>,
Self: Div<<Self as Angle>::Unitless, Output = Self>,
{
/// Create a new angle from any other valid angle.
fn from<A: Angle<S>>(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<S: BaseFloat, A: Angle<S>>(a: A, b: A) -> A { a.bisect(b) }
impl<R: Into<Rad<S>>, S: BaseFloat> Add<R> for Rad<S> {
type Output = Rad<S>;
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<S> { 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<R: Into<Rad<S>>, S: BaseFloat> Add<R> for Deg<S> {
type Output = Deg<S>;
macro_rules! impl_angle {
($Angle:ident, $fmt:expr, $full_turn:expr, $hi:expr) => {
impl<S: BaseFloat> Angle for $Angle<S> {
type Unitless = S;
#[inline]
fn add(self, other: R) -> Deg<S> { deg(self.s + other.into().s) }
}
#[inline]
fn new(value: S) -> $Angle<S> {
$Angle { s: value }
}
impl<R: Into<Rad<S>>, S: BaseFloat> Sub<R> for Rad<S> {
type Output = Rad<S>;
#[inline]
fn zero() -> $Angle<S> {
$Angle::new(S::zero())
}
#[inline]
fn sub(self, other: R) -> Rad<S> { rad(self.s - other.into().s) }
}
#[inline] fn full_turn() -> $Angle<S> { $Angle::new(cast($full_turn).unwrap()) }
#[inline] fn turn_div_2() -> $Angle<S> { let factor: S = cast(2).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_6() -> $Angle<S> { let factor: S = cast(6).unwrap(); $Angle::full_turn() / factor }
impl<R: Into<Rad<S>>, S: BaseFloat> Sub<R> for Deg<S> {
type Output = Deg<S>;
#[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<S> { deg(self.s - other.into().s) }
}
#[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 Rad<S> {
type Output = Rad<S>;
impl<S: BaseFloat> Neg for $Angle<S> {
type Output = $Angle<S>;
#[inline]
fn neg(self) -> Rad<S> { rad(-self.s) }
}
impl<S: BaseFloat> Neg for Deg<S> {
type Output = Deg<S>;
#[inline]
fn neg(self) -> $Angle<S> { $Angle::new(-self.s) }
}
#[inline]
fn neg(self) -> Deg<S> { deg(-self.s) }
}
impl<'a, S: BaseFloat> Neg for &'a $Angle<S> {
type Output = $Angle<S>;
impl<S: BaseFloat> Zero for Rad<S> {
#[inline]
fn zero() -> Rad<S> { rad(S::zero()) }
#[inline]
fn is_zero(&self) -> bool { *self == Self::zero() }
}
impl<S: BaseFloat> Zero for Deg<S> {
#[inline]
fn zero() -> Deg<S> { deg(S::zero()) }
#[inline]
fn is_zero(&self) -> bool { *self == Self::zero() }
}
#[inline]
fn neg(self) -> $Angle<S> { $Angle::new(-self.s) }
}
impl<R: Into<Rad<S>>, S: BaseFloat> Mul<R> for Rad<S> {
type Output = Rad<S>;
impl_binary_operator!(<S: BaseFloat> Add<$Angle<S> > for $Angle<S> {
fn add(lhs, rhs) -> $Angle<S> { $Angle::new(lhs.s + rhs.s) }
});
impl_binary_operator!(<S: BaseFloat> Sub<$Angle<S> > for $Angle<S> {
fn sub(lhs, rhs) -> $Angle<S> { $Angle::new(lhs.s - rhs.s) }
});
impl_binary_operator!(<S: BaseFloat> Div<$Angle<S> > for $Angle<S> {
fn div(lhs, rhs) -> S { lhs.s / rhs.s }
});
impl_binary_operator!(<S: BaseFloat> Rem<$Angle<S> > for $Angle<S> {
fn rem(lhs, rhs) -> $Angle<S> { $Angle::new(lhs.s % rhs.s) }
});
#[inline]
fn mul(self, other: R) -> Rad<S> { rad(self.s * other.into().s) }
}
impl_binary_operator!(<S: BaseFloat> Mul<S> for $Angle<S> {
fn mul(lhs, scalar) -> $Angle<S> { $Angle::new(lhs.s * scalar) }
});
impl_binary_operator!(<S: BaseFloat> Div<S> for $Angle<S> {
fn div(lhs, scalar) -> $Angle<S> { $Angle::new(lhs.s / scalar) }
});
impl<R: Into<Rad<S>>, S: BaseFloat> Mul<R> for Deg<S> {
type Output = Deg<S>;
impl<S: BaseFloat> ApproxEq for $Angle<S> {
type Epsilon = S;
#[inline]
fn mul(self, other: R) -> Deg<S> { deg(self.s * other.into().s) }
}
#[inline]
fn approx_eq_eps(&self, other: &$Angle<S>, epsilon: &S) -> bool {
self.s.approx_eq_eps(&other.s, epsilon)
}
}
impl<S: BaseFloat> One for Rad<S> {
#[inline]
fn one() -> Rad<S> { rad(S::one()) }
}
impl<S: BaseFloat> One for Deg<S> {
#[inline]
fn one() -> Deg<S> { deg(S::one()) }
}
impl<S: BaseFloat + SampleRange> Rand for $Angle<S> {
#[inline]
fn rand<R: Rng>(rng: &mut R) -> $Angle<S> {
$Angle::new(rng.gen_range(cast(-$hi).unwrap(), cast($hi).unwrap()))
}
}
const PI_2: f64 = f64::consts::PI * 2f64;
impl<S: BaseFloat>
Angle<S> for Rad<S> {
#[inline] fn from<A: Angle<S>>(theta: A) -> Rad<S> { theta.into() }
#[inline] fn full_turn() -> Rad<S> { rad(cast(PI_2).unwrap()) }
}
impl<S: BaseFloat>
Angle<S> for Deg<S> {
#[inline] fn from<A: Angle<S>>(theta: A) -> Deg<S> { theta.into() }
#[inline] fn full_turn() -> Deg<S> { deg(cast(360i32).unwrap()) }
}
#[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() }
impl<S: BaseFloat + fmt::Debug>
fmt::Debug for Rad<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?} rad", self.s)
impl<S: BaseFloat> fmt::Debug for $Angle<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, $fmt, self.s)
}
}
}
}
impl<S: BaseFloat + fmt::Debug>
fmt::Debug for Deg<S> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:?}°", self.s)
}
}
impl<S: BaseFloat> ApproxEq for Rad<S> {
type Epsilon = S;
#[inline]
fn approx_eq_eps(&self, other: &Rad<S>, epsilon: &S) -> bool {
self.s.approx_eq_eps(&other.s, epsilon)
}
}
impl<S: BaseFloat> ApproxEq for Deg<S> {
type Epsilon = S;
#[inline]
fn approx_eq_eps(&self, other: &Deg<S>, epsilon: &S) -> bool {
self.s.approx_eq_eps(&other.s, epsilon)
}
}
impl<S: BaseFloat + PartialOrd + SampleRange + Rand> Rand for Rad<S> {
#[inline]
fn rand<R: Rng>(rng: &mut R) -> Rad<S> {
let angle: S = rng.gen_range(cast(-f64::consts::PI).unwrap(), cast(f64::consts::PI).unwrap());
rad(angle)
}
}
impl<S: BaseFloat + PartialOrd + SampleRange + Rand> Rand for Deg<S> {
#[inline]
fn rand<R: Rng>(rng: &mut R) -> Deg<S> {
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);

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,18 +151,18 @@ 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,
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<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;
@ -74,8 +74,9 @@ pub struct PerspectiveFov<S> {
impl<S: BaseFloat> PerspectiveFov<S> {
pub fn to_perspective(&self) -> Perspective<S> {
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<S: BaseFloat> From<PerspectiveFov<S>> for Matrix4<S> {
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<S> {
impl<S: BaseFloat> From<Ortho<S>> for Matrix4<S> {
fn from(ortho: Ortho<S>) -> Matrix4<S> {
let two: S = cast(2i8).unwrap();
let two: S = cast(2).unwrap();
let c0r0 = two / (ortho.right - ortho.left);
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.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<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.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<S>, y: Rad<S>, z: Rad<S>) -> Quaternion<S> {
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,

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()))
}
}

View file

@ -41,9 +41,9 @@ fn conv() {
fn equiv() {
assert!(Deg::<f32>::full_turn().equiv(&-Deg::<f32>::full_turn()));
assert!(Deg::<f32>::turn_div_2().equiv(&-Deg::<f32>::turn_div_2()));
assert!(Deg::<f32>::turn_div_3().sub_a(Deg::<f32>::full_turn()).equiv(&Deg::<f32>::turn_div_3()));
assert!((Deg::<f32>::turn_div_3() - Deg::<f32>::full_turn()).equiv(&Deg::<f32>::turn_div_3()));
assert!(Rad::<f32>::full_turn().equiv(&-Rad::<f32>::full_turn()));
assert!(Rad::<f32>::turn_div_2().equiv(&-Rad::<f32>::turn_div_2()));
assert!(Rad::<f32>::turn_div_3().sub_a(Rad::<f32>::full_turn()).equiv(&Rad::<f32>::turn_div_3()));
assert!((Rad::<f32>::turn_div_3() - Rad::<f32>::full_turn()).equiv(&Rad::<f32>::turn_div_3()));
}