commit
32a981161a
8 changed files with 202 additions and 289 deletions
33
CHANGELOG.md
33
CHANGELOG.md
|
@ -7,20 +7,29 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
### Added
|
### 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
|
- Ease lifetime constraints by removing `'static` from some scalar type
|
||||||
parameters.
|
parameters.
|
||||||
- Weaken type constraints on `perspective` function to take an `Into<Rad<S>>`.
|
- Weaken type constraints on `perspective` function to take an `Into<Rad<S>>`.
|
||||||
|
- Add `Angle::new` for constructing angles from a unitless scalar.
|
||||||
|
|
||||||
### Changed
|
### 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
|
- Take a `Rad` for `ProjectionFov::fovy`, rather than arbitrary `Angle`s. This
|
||||||
simplifies the signature of `PerspectiveFov` from `PerspectiveFov<S, A>` to
|
simplifies the signature of `PerspectiveFov` from `PerspectiveFov<S, A>` to
|
||||||
`PerspectiveFov<S>`.
|
`PerspectiveFov<S>`.
|
||||||
|
- The following trait constraints were removed from `Angle`: `Debug`,
|
||||||
### Changed
|
`ScalarConv`, `Into<Rad<S>>`, `Into<Deg<S>>`.
|
||||||
- `Vector` and `Point` are now constrained to require specific operators to be
|
- `Angle` no longer requires `One`, and the implementations have been removed
|
||||||
overloaded. This means that generic code can now use operators, instead of
|
from `Deg` and `Rad`. This is because angles do not close over multiplication,
|
||||||
the operator methods.
|
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
|
### Removed
|
||||||
- Remove redundant `Point::{min, max}` methods - these are now covered by the
|
- 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.
|
- Remove `Vector::one`. Vectors don't really have a multiplicative identity.
|
||||||
If you really want a `one` vector, you can do something like:
|
If you really want a `one` vector, you can do something like:
|
||||||
`Vector::from_value(1.0)`.
|
`Vector::from_value(1.0)`.
|
||||||
- Remove operator methods from `Vector` and `Point` traits in favor of operator
|
- Remove operator methods from `Vector`, `Point`, and `Angle` traits in favor of
|
||||||
overloading.
|
operator overloading.
|
||||||
- Remove `*_self` methods from `Vector` and `Point`. These were of little
|
- Remove `*_self` methods from `Vector`, `Point`, and `Angle`. These were of
|
||||||
performance benefit, and assignment operator overloading will be coming soon!
|
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
|
## [v0.6.0] - 2015-12-12
|
||||||
|
|
||||||
|
|
349
src/angle.rs
349
src/angle.rs
|
@ -22,17 +22,17 @@ use std::ops::*;
|
||||||
use rand::{Rand, Rng};
|
use rand::{Rand, Rng};
|
||||||
use rand::distributions::range::SampleRange;
|
use rand::distributions::range::SampleRange;
|
||||||
|
|
||||||
use rust_num::{Float, One, Zero};
|
use rust_num::{Float, Zero};
|
||||||
use rust_num::traits::cast;
|
use rust_num::traits::cast;
|
||||||
|
|
||||||
use approx::ApproxEq;
|
use approx::ApproxEq;
|
||||||
use num::BaseFloat;
|
use num::BaseFloat;
|
||||||
|
|
||||||
/// An angle, in radians
|
/// 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 }
|
pub struct Rad<S> { pub s: S }
|
||||||
/// An angle, in degrees
|
/// 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 }
|
pub struct Deg<S> { pub s: S }
|
||||||
|
|
||||||
/// Create a new angle, in radians
|
/// 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 {
|
impl<S> From<Rad<S>> for Deg<S> where S: BaseFloat {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(r: Rad<S>) -> Deg<S> {
|
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 {
|
impl<S> From<Deg<S>> for Rad<S> where S: BaseFloat {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from(d: Deg<S>) -> Rad<S> {
|
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.
|
/// Operations on angles.
|
||||||
pub trait Angle
|
pub trait Angle where
|
||||||
<
|
Self: Copy + Clone,
|
||||||
S: BaseFloat
|
Self: PartialEq + PartialOrd,
|
||||||
>
|
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
|
||||||
: Clone + Zero
|
Self: ApproxEq<Epsilon = <Self as Angle>::Unitless>,
|
||||||
+ PartialEq + PartialOrd
|
|
||||||
+ ApproxEq<Epsilon = S>
|
Self: Neg<Output = Self>,
|
||||||
+ Neg<Output=Self>
|
Self: Add<Self, Output = Self>,
|
||||||
+ Into<Rad<S>>
|
Self: Sub<Self, Output = Self>,
|
||||||
+ Into<Deg<S>>
|
Self: Rem<Self, Output = Self>,
|
||||||
+ ScalarConv<S>
|
Self: Mul<<Self as Angle>::Unitless, Output = Self>,
|
||||||
+ fmt::Debug
|
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.
|
type Unitless: BaseFloat;
|
||||||
fn from<A: Angle<S>>(theta: A) -> Self;
|
|
||||||
|
|
||||||
/// Negate this angle, in-place.
|
/// Create an angle from a unitless value.
|
||||||
#[inline] fn neg_self(&mut self) { *self = -(*self).clone() }
|
fn new(value: Self::Unitless) -> Self;
|
||||||
|
|
||||||
/// 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 }
|
|
||||||
|
|
||||||
/// Return the angle, normalized to the range `[0, full_turn)`.
|
/// Return the angle, normalized to the range `[0, full_turn)`.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn normalize(&self) -> Self {
|
fn normalize(self) -> Self {
|
||||||
let mut a = self.clone();
|
let rem = self % Self::full_turn();
|
||||||
a.normalize_self();
|
if rem < Self::zero() { rem + Self::full_turn() } else { rem }
|
||||||
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) };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the angle rotated by half a turn
|
/// Return the angle rotated by half a turn
|
||||||
#[inline]
|
#[inline]
|
||||||
fn opposite(&self) -> Self {
|
fn opposite(self) -> Self {
|
||||||
self.add_a(Self::turn_div_2()).normalize()
|
Self::normalize(self + Self::turn_div_2())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the interior bisector of the two angles
|
/// Returns the interior bisector of the two angles
|
||||||
#[inline]
|
#[inline]
|
||||||
fn bisect(&self, other: Self) -> Self {
|
fn bisect(self, other: Self) -> Self {
|
||||||
self.add_a(self.sub_a(other).mul_s(cast(0.5f64).unwrap())).normalize()
|
let half = cast(0.5f64).unwrap();
|
||||||
|
Self::normalize((self - other) * half + self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn zero() -> Self;
|
||||||
fn full_turn() -> Self;
|
fn full_turn() -> Self;
|
||||||
|
fn turn_div_2() -> Self;
|
||||||
#[inline] fn turn_div_2() -> Self { Self::full_turn().div_s(cast(2i8).unwrap()) }
|
fn turn_div_3() -> Self;
|
||||||
#[inline] fn turn_div_3() -> Self { Self::full_turn().div_s(cast(3i8).unwrap()) }
|
fn turn_div_4() -> Self;
|
||||||
#[inline] fn turn_div_4() -> Self { Self::full_turn().div_s(cast(4i8).unwrap()) }
|
fn turn_div_6() -> Self;
|
||||||
#[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>;
|
|
||||||
|
|
||||||
#[inline]
|
#[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> {
|
macro_rules! impl_angle {
|
||||||
type Output = Deg<S>;
|
($Angle:ident, $fmt:expr, $full_turn:expr, $hi:expr) => {
|
||||||
|
impl<S: BaseFloat> Angle for $Angle<S> {
|
||||||
|
type Unitless = S;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn add(self, other: R) -> Deg<S> { deg(self.s + other.into().s) }
|
fn new(value: S) -> $Angle<S> {
|
||||||
}
|
$Angle { s: value }
|
||||||
|
}
|
||||||
|
|
||||||
impl<R: Into<Rad<S>>, S: BaseFloat> Sub<R> for Rad<S> {
|
#[inline]
|
||||||
type Output = Rad<S>;
|
fn zero() -> $Angle<S> {
|
||||||
|
$Angle::new(S::zero())
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline] fn full_turn() -> $Angle<S> { $Angle::new(cast($full_turn).unwrap()) }
|
||||||
fn sub(self, other: R) -> Rad<S> { rad(self.s - other.into().s) }
|
#[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> {
|
#[inline] fn sin(self) -> S { Rad::from(self).s.sin() }
|
||||||
type Output = Deg<S>;
|
#[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]
|
#[inline] fn asin(a: S) -> $Angle<S> { Rad::new(a.asin()).into() }
|
||||||
fn sub(self, other: R) -> Deg<S> { deg(self.s - other.into().s) }
|
#[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> {
|
impl<S: BaseFloat> Neg for $Angle<S> {
|
||||||
type Output = Rad<S>;
|
type Output = $Angle<S>;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn neg(self) -> Rad<S> { rad(-self.s) }
|
fn neg(self) -> $Angle<S> { $Angle::new(-self.s) }
|
||||||
}
|
}
|
||||||
impl<S: BaseFloat> Neg for Deg<S> {
|
|
||||||
type Output = Deg<S>;
|
|
||||||
|
|
||||||
#[inline]
|
impl<'a, S: BaseFloat> Neg for &'a $Angle<S> {
|
||||||
fn neg(self) -> Deg<S> { deg(-self.s) }
|
type Output = $Angle<S>;
|
||||||
}
|
|
||||||
|
|
||||||
impl<S: BaseFloat> Zero for Rad<S> {
|
#[inline]
|
||||||
#[inline]
|
fn neg(self) -> $Angle<S> { $Angle::new(-self.s) }
|
||||||
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() }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<R: Into<Rad<S>>, S: BaseFloat> Mul<R> for Rad<S> {
|
impl_binary_operator!(<S: BaseFloat> Add<$Angle<S> > for $Angle<S> {
|
||||||
type Output = Rad<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]
|
impl_binary_operator!(<S: BaseFloat> Mul<S> for $Angle<S> {
|
||||||
fn mul(self, other: R) -> Rad<S> { rad(self.s * other.into().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> {
|
impl<S: BaseFloat> ApproxEq for $Angle<S> {
|
||||||
type Output = Deg<S>;
|
type Epsilon = S;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul(self, other: R) -> Deg<S> { deg(self.s * other.into().s) }
|
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> {
|
impl<S: BaseFloat + SampleRange> Rand for $Angle<S> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn one() -> Rad<S> { rad(S::one()) }
|
fn rand<R: Rng>(rng: &mut R) -> $Angle<S> {
|
||||||
}
|
$Angle::new(rng.gen_range(cast(-$hi).unwrap(), cast($hi).unwrap()))
|
||||||
impl<S: BaseFloat> One for Deg<S> {
|
}
|
||||||
#[inline]
|
}
|
||||||
fn one() -> Deg<S> { deg(S::one()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
const PI_2: f64 = f64::consts::PI * 2f64;
|
impl<S: BaseFloat> fmt::Debug for $Angle<S> {
|
||||||
impl<S: BaseFloat>
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
Angle<S> for Rad<S> {
|
write!(f, $fmt, self.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>
|
impl_angle!(Rad, "{:?} rad", f64::consts::PI * 2.0, f64::consts::PI);
|
||||||
fmt::Debug for Deg<S> {
|
impl_angle!(Deg, "{:?}°", 360, 180);
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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,18 +151,18 @@ 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,
|
||||||
sx * sz + cx * sy * cz, -sx * cz + cx * sy * sz, cx * cy)
|
sx * sz + cx * sy * cz, -sx * cz + cx * sy * sz, cx * cy)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
@ -74,8 +74,9 @@ pub struct PerspectiveFov<S> {
|
||||||
|
|
||||||
impl<S: BaseFloat> PerspectiveFov<S> {
|
impl<S: BaseFloat> PerspectiveFov<S> {
|
||||||
pub fn to_perspective(&self) -> Perspective<S> {
|
pub fn to_perspective(&self) -> Perspective<S> {
|
||||||
let angle = self.fovy.div_s(cast(2i8).unwrap());
|
let two: S = cast(2).unwrap();
|
||||||
let ymax = self.near * tan(angle);
|
let angle = self.fovy / two;
|
||||||
|
let ymax = self.near * Rad::tan(angle);
|
||||||
let xmax = ymax * self.aspect;
|
let xmax = ymax * self.aspect;
|
||||||
|
|
||||||
Perspective {
|
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 > 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);
|
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(2).unwrap();
|
||||||
let two: S = cast(2i8).unwrap();
|
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();
|
||||||
|
@ -187,7 +188,7 @@ pub struct Ortho<S> {
|
||||||
|
|
||||||
impl<S: BaseFloat> From<Ortho<S>> for Matrix4<S> {
|
impl<S: BaseFloat> From<Ortho<S>> for Matrix4<S> {
|
||||||
fn from(ortho: Ortho<S>) -> 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 c0r0 = two / (ortho.right - ortho.left);
|
||||||
let c0r1 = S::zero();
|
let c0r1 = S::zero();
|
||||||
|
|
|
@ -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.mul_s(S::one() - amount));
|
let scale1 = Rad::sin(theta * (S::one() - amount));
|
||||||
let scale2 = sin(theta.mul_s(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.mul_s(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.mul_s(cast(0.5f64).unwrap()));
|
let (s1, c1) = Rad::sin_cos(x * cast(0.5f64).unwrap());
|
||||||
let (s2, c2) = sin_cos(y.mul_s(cast(0.5f64).unwrap()));
|
let (s2, c2) = Rad::sin_cos(y * cast(0.5f64).unwrap());
|
||||||
let (s3, c3) = sin_cos(z.mul_s(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,
|
||||||
|
|
|
@ -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]
|
||||||
|
|
|
@ -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()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,9 +41,9 @@ fn conv() {
|
||||||
fn equiv() {
|
fn equiv() {
|
||||||
assert!(Deg::<f32>::full_turn().equiv(&-Deg::<f32>::full_turn()));
|
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_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>::full_turn().equiv(&-Rad::<f32>::full_turn()));
|
||||||
assert!(Rad::<f32>::turn_div_2().equiv(&-Rad::<f32>::turn_div_2()));
|
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()));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue