Run rustfmt on most files

This commit is contained in:
Brendan Zabarauskas 2018-01-03 13:01:02 +11:00
parent 68b9052be1
commit 574dd3b972
23 changed files with 1403 additions and 667 deletions

View file

@ -15,16 +15,17 @@
#![feature(test)] #![feature(test)]
extern crate cgmath;
extern crate rand; extern crate rand;
extern crate test; extern crate test;
extern crate cgmath;
use rand::{IsaacRng, Rng}; use rand::{IsaacRng, Rng};
use test::Bencher; use test::Bencher;
use cgmath::*; use cgmath::*;
#[path="common/macros.rs"] #[path = "common/macros.rs"]
#[macro_use] mod macros; #[macro_use]
mod macros;
fn bench_from_axis_angle<T: Rotation3<f32>>(bh: &mut Bencher) { fn bench_from_axis_angle<T: Rotation3<f32>>(bh: &mut Bencher) {
const LEN: usize = 1 << 13; const LEN: usize = 1 << 13;
@ -39,7 +40,8 @@ fn bench_from_axis_angle<T: Rotation3<f32>>(bh: &mut Bencher) {
i = (i + 1) & (LEN - 1); i = (i + 1) & (LEN - 1);
unsafe { unsafe {
let res: T = Rotation3::from_axis_angle(*axis.get_unchecked(i), *angle.get_unchecked(i)); let res: T =
Rotation3::from_axis_angle(*axis.get_unchecked(i), *angle.get_unchecked(i));
test::black_box(res) test::black_box(res)
} }
}) })
@ -55,7 +57,19 @@ fn _bench_rot3_from_axisangle(bh: &mut Bencher) {
bench_from_axis_angle::<Basis3<f32>>(bh) bench_from_axis_angle::<Basis3<f32>>(bh)
} }
bench_construction!(_bench_rot2_from_axisangle, Basis2<f32>, Basis2::from_angle [ angle: Rad<f32> ]); bench_construction!(
_bench_rot2_from_axisangle,
Basis2<f32>,
Basis2::from_angle[angle: Rad<f32>]
);
bench_construction!(_bench_quat_from_euler_angles, Quaternion<f32>, Quaternion::from [src: Euler<Rad<f32>>]); bench_construction!(
bench_construction!(_bench_rot3_from_euler_angles, Basis3<f32>, Basis3::from [src: Euler<Rad<f32>>]); _bench_quat_from_euler_angles,
Quaternion<f32>,
Quaternion::from[src: Euler<Rad<f32>>]
);
bench_construction!(
_bench_rot3_from_euler_angles,
Basis3<f32>,
Basis3::from[src: Euler<Rad<f32>>]
);

View file

@ -15,9 +15,9 @@
#![feature(test)] #![feature(test)]
extern crate cgmath;
extern crate rand; extern crate rand;
extern crate test; extern crate test;
extern crate cgmath;
use rand::{IsaacRng, Rng}; use rand::{IsaacRng, Rng};
use std::ops::*; use std::ops::*;
@ -25,8 +25,9 @@ use test::Bencher;
use cgmath::*; use cgmath::*;
#[path="common/macros.rs"] #[path = "common/macros.rs"]
#[macro_use] mod macros; #[macro_use]
mod macros;
bench_binop!(_bench_matrix2_mul_m, Matrix2<f32>, Matrix2<f32>, mul); bench_binop!(_bench_matrix2_mul_m, Matrix2<f32>, Matrix2<f32>, mul);
bench_binop!(_bench_matrix3_mul_m, Matrix3<f32>, Matrix3<f32>, mul); bench_binop!(_bench_matrix3_mul_m, Matrix3<f32>, Matrix3<f32>, mul);

View file

@ -15,9 +15,9 @@
#![feature(test)] #![feature(test)]
extern crate cgmath;
extern crate rand; extern crate rand;
extern crate test; extern crate test;
extern crate cgmath;
use rand::{IsaacRng, Rng}; use rand::{IsaacRng, Rng};
use std::ops::*; use std::ops::*;
@ -25,8 +25,9 @@ use test::Bencher;
use cgmath::*; use cgmath::*;
#[path="common/macros.rs"] #[path = "common/macros.rs"]
#[macro_use] mod macros; #[macro_use]
mod macros;
bench_binop!(_bench_quat_add_q, Quaternion<f32>, Quaternion<f32>, add); bench_binop!(_bench_quat_add_q, Quaternion<f32>, Quaternion<f32>, add);
bench_binop!(_bench_quat_sub_q, Quaternion<f32>, Quaternion<f32>, sub); bench_binop!(_bench_quat_sub_q, Quaternion<f32>, Quaternion<f32>, sub);

View file

@ -15,9 +15,9 @@
#![feature(test)] #![feature(test)]
extern crate cgmath;
extern crate rand; extern crate rand;
extern crate test; extern crate test;
extern crate cgmath;
use rand::{IsaacRng, Rng}; use rand::{IsaacRng, Rng};
use std::ops::*; use std::ops::*;
@ -25,8 +25,9 @@ use test::Bencher;
use cgmath::*; use cgmath::*;
#[path="common/macros.rs"] #[path = "common/macros.rs"]
#[macro_use] mod macros; #[macro_use]
mod macros;
bench_binop!(_bench_vector2_add_v, Vector2<f32>, Vector2<f32>, add); bench_binop!(_bench_vector2_add_v, Vector2<f32>, Vector2<f32>, add);
bench_binop!(_bench_vector3_add_v, Vector3<f32>, Vector3<f32>, add); bench_binop!(_bench_vector3_add_v, Vector3<f32>, Vector3<f32>, add);

View file

@ -45,14 +45,20 @@ pub struct Rad<S>(pub S);
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Deg<S>(pub S); pub struct Deg<S>(pub 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(rad: Rad<S>) -> Deg<S> { fn from(rad: Rad<S>) -> Deg<S> {
Deg(rad.0 * cast(180.0 / f64::consts::PI).unwrap()) Deg(rad.0 * 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(deg: Deg<S>) -> Rad<S> { fn from(deg: Deg<S>) -> Rad<S> {
Rad(deg.0 * cast(f64::consts::PI / 180.0).unwrap()) Rad(deg.0 * cast(f64::consts::PI / 180.0).unwrap())

View file

@ -75,8 +75,7 @@ use num::BaseFloat;
/// [gimbal lock]: https://en.wikipedia.org/wiki/Gimbal_lock#Gimbal_lock_in_applied_mathematics /// [gimbal lock]: https://en.wikipedia.org/wiki/Gimbal_lock#Gimbal_lock_in_applied_mathematics
/// [convert]: #defining-rotations-using-euler-angles /// [convert]: #defining-rotations-using-euler-angles
#[repr(C)] #[repr(C)]
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Euler<A: Angle> { pub struct Euler<A: Angle> {
/// The angle to apply around the _x_ axis. Also known at the _pitch_. /// The angle to apply around the _x_ axis. Also known at the _pitch_.
@ -162,23 +161,27 @@ impl<A: Angle> ApproxEq for Euler<A> {
#[inline] #[inline]
fn relative_eq(&self, other: &Self, epsilon: A::Epsilon, max_relative: A::Epsilon) -> bool { fn relative_eq(&self, other: &Self, epsilon: A::Epsilon, max_relative: A::Epsilon) -> bool {
A::relative_eq(&self.x, &other.x, epsilon, max_relative) && A::relative_eq(&self.x, &other.x, epsilon, max_relative)
A::relative_eq(&self.y, &other.y, epsilon, max_relative) && && A::relative_eq(&self.y, &other.y, epsilon, max_relative)
A::relative_eq(&self.z, &other.z, epsilon, max_relative) && A::relative_eq(&self.z, &other.z, epsilon, max_relative)
} }
#[inline] #[inline]
fn ulps_eq(&self, other: &Self, epsilon: A::Epsilon, max_ulps: u32) -> bool { fn ulps_eq(&self, other: &Self, epsilon: A::Epsilon, max_ulps: u32) -> bool {
A::ulps_eq(&self.x, &other.x, epsilon, max_ulps) && A::ulps_eq(&self.x, &other.x, epsilon, max_ulps)
A::ulps_eq(&self.y, &other.y, epsilon, max_ulps) && && A::ulps_eq(&self.y, &other.y, epsilon, max_ulps)
A::ulps_eq(&self.z, &other.z, epsilon, max_ulps) && A::ulps_eq(&self.z, &other.z, epsilon, max_ulps)
} }
} }
impl<A: Angle + Rand> Rand for Euler<A> { impl<A: Angle + Rand> Rand for Euler<A> {
#[inline] #[inline]
fn rand<R: Rng>(rng: &mut R) -> Euler<A> { fn rand<R: Rng>(rng: &mut R) -> Euler<A> {
Euler { x: rng.gen(), y: rng.gen(), z: rng.gen() } Euler {
x: rng.gen(),
y: rng.gen(),
z: rng.gen(),
}
} }
} }

View file

@ -58,8 +58,8 @@ extern crate approx;
#[cfg(feature = "mint")] #[cfg(feature = "mint")]
pub extern crate mint; pub extern crate mint;
pub extern crate num_traits;
extern crate rand; extern crate rand;
pub extern crate num_traits;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
#[macro_use] #[macro_use]
@ -76,7 +76,7 @@ pub use structure::*;
pub use matrix::{Matrix2, Matrix3, Matrix4}; pub use matrix::{Matrix2, Matrix3, Matrix4};
pub use quaternion::Quaternion; pub use quaternion::Quaternion;
pub use vector::{Vector1, Vector2, Vector3, Vector4, dot, vec1, vec2, vec3, vec4}; pub use vector::{dot, Vector1, Vector2, Vector3, Vector4, vec1, vec2, vec3, vec4};
pub use angle::{Deg, Rad}; pub use angle::{Deg, Rad};
pub use euler::Euler; pub use euler::Euler;

View file

@ -80,14 +80,11 @@ pub struct Matrix4<S> {
pub w: Vector4<S>, pub w: Vector4<S>,
} }
impl<S: BaseFloat> Matrix2<S> { impl<S: BaseFloat> Matrix2<S> {
/// Create a new matrix, providing values for each index. /// Create a new matrix, providing values for each index.
#[inline] #[inline]
pub fn new(c0r0: S, c0r1: S, pub fn new(c0r0: S, c0r1: S, c1r0: S, c1r1: S) -> Matrix2<S> {
c1r0: S, c1r1: S) -> Matrix2<S> { Matrix2::from_cols(Vector2::new(c0r0, c0r1), Vector2::new(c1r0, c1r1))
Matrix2::from_cols(Vector2::new(c0r0, c0r1),
Vector2::new(c1r0, c1r1))
} }
/// Create a new matrix, providing columns. /// Create a new matrix, providing columns.
@ -107,26 +104,34 @@ impl<S: BaseFloat> Matrix2<S> {
pub fn from_angle<A: Into<Rad<S>>>(theta: A) -> Matrix2<S> { pub fn from_angle<A: Into<Rad<S>>>(theta: A) -> Matrix2<S> {
let (s, c) = Rad::sin_cos(theta.into()); let (s, c) = Rad::sin_cos(theta.into());
Matrix2::new(c, s, Matrix2::new(c, s, -s, c)
-s, c)
} }
} }
impl<S: BaseFloat> Matrix3<S> { impl<S: BaseFloat> Matrix3<S> {
/// Create a new matrix, providing values for each index. /// Create a new matrix, providing values for each index.
#[inline] #[inline]
pub fn new(c0r0:S, c0r1:S, c0r2:S, #[cfg_attr(rustfmt, rustfmt_skip)]
pub fn new(
c0r0:S, c0r1:S, c0r2:S,
c1r0:S, c1r1:S, c1r2:S, c1r0:S, c1r1:S, c1r2:S,
c2r0:S, c2r1:S, c2r2:S) -> Matrix3<S> { c2r0:S, c2r1:S, c2r2:S,
Matrix3::from_cols(Vector3::new(c0r0, c0r1, c0r2), ) -> Matrix3<S> {
Matrix3::from_cols(
Vector3::new(c0r0, c0r1, c0r2),
Vector3::new(c1r0, c1r1, c1r2), Vector3::new(c1r0, c1r1, c1r2),
Vector3::new(c2r0, c2r1, c2r2)) Vector3::new(c2r0, c2r1, c2r2),
)
} }
/// Create a new matrix, providing columns. /// Create a new matrix, providing columns.
#[inline] #[inline]
pub fn from_cols(c0: Vector3<S>, c1: Vector3<S>, c2: Vector3<S>) -> Matrix3<S> { pub fn from_cols(c0: Vector3<S>, c1: Vector3<S>, c2: Vector3<S>) -> Matrix3<S> {
Matrix3 { x: c0, y: c1, z: c2 } Matrix3 {
x: c0,
y: c1,
z: c2,
}
} }
/// Create a rotation matrix that will cause a vector to point at /// Create a rotation matrix that will cause a vector to point at
@ -143,27 +148,39 @@ impl<S: BaseFloat> Matrix3<S> {
pub fn from_angle_x<A: Into<Rad<S>>>(theta: A) -> Matrix3<S> { pub fn from_angle_x<A: Into<Rad<S>>>(theta: A) -> Matrix3<S> {
// http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
let (s, c) = Rad::sin_cos(theta.into()); let (s, c) = Rad::sin_cos(theta.into());
Matrix3::new(S::one(), S::zero(), S::zero(),
#[cfg_attr(rustfmt, rustfmt_skip)]
Matrix3::new(
S::one(), S::zero(), S::zero(),
S::zero(), c, s, S::zero(), c, s,
S::zero(), -s, c) 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<A: Into<Rad<S>>>(theta: A) -> Matrix3<S> { pub fn from_angle_y<A: Into<Rad<S>>>(theta: A) -> Matrix3<S> {
// http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
let (s, c) = Rad::sin_cos(theta.into()); let (s, c) = Rad::sin_cos(theta.into());
Matrix3::new(c, S::zero(), -s,
#[cfg_attr(rustfmt, rustfmt_skip)]
Matrix3::new(
c, S::zero(), -s,
S::zero(), S::one(), S::zero(), S::zero(), S::one(), S::zero(),
s, S::zero(), c) 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<A: Into<Rad<S>>>(theta: A) -> Matrix3<S> { pub fn from_angle_z<A: Into<Rad<S>>>(theta: A) -> Matrix3<S> {
// http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
let (s, c) = Rad::sin_cos(theta.into()); let (s, c) = Rad::sin_cos(theta.into());
Matrix3::new( c, s, S::zero(),
#[cfg_attr(rustfmt, rustfmt_skip)]
Matrix3::new(
c, s, S::zero(),
-s, c, S::zero(), -s, c, S::zero(),
S::zero(), S::zero(), S::one()) S::zero(), S::zero(), S::one(),
)
} }
/// Create a rotation matrix from an angle around an arbitrary axis. /// Create a rotation matrix from an angle around an arbitrary axis.
@ -173,7 +190,9 @@ impl<S: BaseFloat> Matrix3<S> {
let (s, c) = Rad::sin_cos(angle.into()); let (s, c) = Rad::sin_cos(angle.into());
let _1subc = S::one() - c; let _1subc = S::one() - c;
Matrix3::new(_1subc * axis.x * axis.x + c, #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix3::new(
_1subc * axis.x * axis.x + c,
_1subc * axis.x * axis.y + s * axis.z, _1subc * axis.x * axis.y + s * axis.z,
_1subc * axis.x * axis.z - s * axis.y, _1subc * axis.x * axis.z - s * axis.y,
@ -183,36 +202,50 @@ impl<S: BaseFloat> Matrix3<S> {
_1subc * axis.x * axis.z + s * axis.y, _1subc * axis.x * axis.z + s * axis.y,
_1subc * axis.y * axis.z - s * axis.x, _1subc * axis.y * axis.z - s * axis.x,
_1subc * axis.z * axis.z + c) _1subc * axis.z * axis.z + c,
)
} }
} }
impl<S: BaseFloat> Matrix4<S> { impl<S: BaseFloat> Matrix4<S> {
/// Create a new matrix, providing values for each index. /// Create a new matrix, providing values for each index.
#[inline] #[inline]
pub fn new(c0r0: S, c0r1: S, c0r2: S, c0r3: S, #[cfg_attr(rustfmt, rustfmt_skip)]
pub fn new(
c0r0: S, c0r1: S, c0r2: S, c0r3: S,
c1r0: S, c1r1: S, c1r2: S, c1r3: S, c1r0: S, c1r1: S, c1r2: S, c1r3: S,
c2r0: S, c2r1: S, c2r2: S, c2r3: S, c2r0: S, c2r1: S, c2r2: S, c2r3: S,
c3r0: S, c3r1: S, c3r2: S, c3r3: S) -> Matrix4<S> { c3r0: S, c3r1: S, c3r2: S, c3r3: S,
Matrix4::from_cols(Vector4::new(c0r0, c0r1, c0r2, c0r3), ) -> Matrix4<S> {
Matrix4::from_cols(
Vector4::new(c0r0, c0r1, c0r2, c0r3),
Vector4::new(c1r0, c1r1, c1r2, c1r3), Vector4::new(c1r0, c1r1, c1r2, c1r3),
Vector4::new(c2r0, c2r1, c2r2, c2r3), Vector4::new(c2r0, c2r1, c2r2, c2r3),
Vector4::new(c3r0, c3r1, c3r2, c3r3)) Vector4::new(c3r0, c3r1, c3r2, c3r3),
)
} }
/// Create a new matrix, providing columns. /// Create a new matrix, providing columns.
#[inline] #[inline]
pub fn from_cols(c0: Vector4<S>, c1: Vector4<S>, c2: Vector4<S>, c3: Vector4<S>) -> Matrix4<S> { pub fn from_cols(c0: Vector4<S>, c1: Vector4<S>, c2: Vector4<S>, c3: Vector4<S>) -> Matrix4<S> {
Matrix4 { x: c0, y: c1, z: c2, w: c3 } Matrix4 {
x: c0,
y: c1,
z: c2,
w: c3,
}
} }
/// Create a homogeneous transformation matrix from a translation vector. /// Create a homogeneous transformation matrix from a translation vector.
#[inline] #[inline]
pub fn from_translation(v: Vector3<S>) -> Matrix4<S> { pub fn from_translation(v: Vector3<S>) -> Matrix4<S> {
Matrix4::new(S::one(), S::zero(), S::zero(), S::zero(), #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
S::one(), S::zero(), S::zero(), S::zero(),
S::zero(), S::one(), S::zero(), S::zero(), S::zero(), S::one(), S::zero(), S::zero(),
S::zero(), S::zero(), S::one(), S::zero(), S::zero(), S::zero(), S::one(), S::zero(),
v.x, v.y, v.z, S::one()) v.x, v.y, v.z, S::one(),
)
} }
/// Create a homogeneous transformation matrix from a scale value. /// Create a homogeneous transformation matrix from a scale value.
@ -224,10 +257,13 @@ impl<S: BaseFloat> Matrix4<S> {
/// Create a homogeneous transformation matrix from a set of scale values. /// Create a homogeneous transformation matrix from a set of scale values.
#[inline] #[inline]
pub fn from_nonuniform_scale(x: S, y: S, z: S) -> Matrix4<S> { pub fn from_nonuniform_scale(x: S, y: S, z: S) -> Matrix4<S> {
Matrix4::new(x, S::zero(), S::zero(), S::zero(), #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
x, S::zero(), S::zero(), S::zero(),
S::zero(), y, S::zero(), S::zero(), S::zero(), y, S::zero(), S::zero(),
S::zero(), S::zero(), z, S::zero(), S::zero(), S::zero(), z, S::zero(),
S::zero(), S::zero(), S::zero(), S::one()) S::zero(), S::zero(), S::zero(), S::one(),
)
} }
/// Create a homogeneous transformation matrix that will cause a vector to point at /// Create a homogeneous transformation matrix that will cause a vector to point at
@ -237,10 +273,13 @@ impl<S: BaseFloat> Matrix4<S> {
let s = f.cross(up).normalize(); let s = f.cross(up).normalize();
let u = s.cross(f); let u = s.cross(f);
Matrix4::new(s.x.clone(), u.x.clone(), -f.x.clone(), S::zero(), #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
s.x.clone(), u.x.clone(), -f.x.clone(), S::zero(),
s.y.clone(), u.y.clone(), -f.y.clone(), S::zero(), s.y.clone(), u.y.clone(), -f.y.clone(), S::zero(),
s.z.clone(), u.z.clone(), -f.z.clone(), S::zero(), s.z.clone(), u.z.clone(), -f.z.clone(), S::zero(),
-eye.dot(s), -eye.dot(u), eye.dot(f), S::one()) -eye.dot(s), -eye.dot(u), eye.dot(f), S::one(),
)
} }
/// Create a homogeneous transformation matrix that will cause a vector to point at /// Create a homogeneous transformation matrix that will cause a vector to point at
@ -253,30 +292,42 @@ impl<S: BaseFloat> Matrix4<S> {
pub fn from_angle_x<A: Into<Rad<S>>>(theta: A) -> Matrix4<S> { pub fn from_angle_x<A: Into<Rad<S>>>(theta: A) -> Matrix4<S> {
// http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
let (s, c) = Rad::sin_cos(theta.into()); let (s, c) = Rad::sin_cos(theta.into());
Matrix4::new(S::one(), S::zero(), S::zero(), S::zero(),
#[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
S::one(), S::zero(), S::zero(), S::zero(),
S::zero(), c, s, S::zero(), S::zero(), c, s, S::zero(),
S::zero(), -s, c, S::zero(), S::zero(), -s, c, S::zero(),
S::zero(), S::zero(), S::zero(), S::one()) S::zero(), S::zero(), S::zero(), S::one(),
)
} }
/// Create a homogeneous transformation matrix from a rotation around the `y` axis (yaw). /// Create a homogeneous transformation matrix from a rotation around the `y` axis (yaw).
pub fn from_angle_y<A: Into<Rad<S>>>(theta: A) -> Matrix4<S> { pub fn from_angle_y<A: Into<Rad<S>>>(theta: A) -> Matrix4<S> {
// http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
let (s, c) = Rad::sin_cos(theta.into()); let (s, c) = Rad::sin_cos(theta.into());
Matrix4::new(c, S::zero(), -s, S::zero(),
#[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
c, S::zero(), -s, S::zero(),
S::zero(), S::one(), S::zero(), S::zero(), S::zero(), S::one(), S::zero(), S::zero(),
s, S::zero(), c, S::zero(), s, S::zero(), c, S::zero(),
S::zero(), S::zero(), S::zero(), S::one()) S::zero(), S::zero(), S::zero(), S::one(),
)
} }
/// Create a homogeneous transformation matrix from a rotation around the `z` axis (roll). /// Create a homogeneous transformation matrix from a rotation around the `z` axis (roll).
pub fn from_angle_z<A: Into<Rad<S>>>(theta: A) -> Matrix4<S> { pub fn from_angle_z<A: Into<Rad<S>>>(theta: A) -> Matrix4<S> {
// http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
let (s, c) = Rad::sin_cos(theta.into()); let (s, c) = Rad::sin_cos(theta.into());
Matrix4::new( c, s, S::zero(), S::zero(),
#[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
c, s, S::zero(), S::zero(),
-s, c, S::zero(), S::zero(), -s, c, S::zero(), S::zero(),
S::zero(), S::zero(), S::one(), S::zero(), S::zero(), S::zero(), S::one(), S::zero(),
S::zero(), S::zero(), S::zero(), S::one()) S::zero(), S::zero(), S::zero(), S::one(),
)
} }
/// Create a homogeneous transformation matrix from an angle around an arbitrary axis. /// Create a homogeneous transformation matrix from an angle around an arbitrary axis.
@ -286,7 +337,9 @@ impl<S: BaseFloat> Matrix4<S> {
let (s, c) = Rad::sin_cos(angle.into()); let (s, c) = Rad::sin_cos(angle.into());
let _1subc = S::one() - c; let _1subc = S::one() - c;
Matrix4::new(_1subc * axis.x * axis.x + c, #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
_1subc * axis.x * axis.x + c,
_1subc * axis.x * axis.y + s * axis.z, _1subc * axis.x * axis.y + s * axis.z,
_1subc * axis.x * axis.z - s * axis.y, _1subc * axis.x * axis.z - s * axis.y,
S::zero(), S::zero(),
@ -301,18 +354,19 @@ impl<S: BaseFloat> Matrix4<S> {
_1subc * axis.z * axis.z + c, _1subc * axis.z * axis.z + c,
S::zero(), S::zero(),
S::zero(), S::zero(), S::zero(), S::zero(), S::one(),
S::zero(), )
S::zero(),
S::one())
} }
} }
impl<S: BaseFloat> Zero for Matrix2<S> { impl<S: BaseFloat> Zero for Matrix2<S> {
#[inline] #[inline]
fn zero() -> Matrix2<S> { fn zero() -> Matrix2<S> {
Matrix2::new(S::zero(), S::zero(), #[cfg_attr(rustfmt, rustfmt_skip)]
S::zero(), S::zero()) Matrix2::new(
S::zero(), S::zero(),
S::zero(), S::zero(),
)
} }
#[inline] #[inline]
@ -324,9 +378,12 @@ impl<S: BaseFloat> Zero for Matrix2<S> {
impl<S: BaseFloat> Zero for Matrix3<S> { impl<S: BaseFloat> Zero for Matrix3<S> {
#[inline] #[inline]
fn zero() -> Matrix3<S> { fn zero() -> Matrix3<S> {
Matrix3::new(S::zero(), S::zero(), S::zero(), #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix3::new(
S::zero(), S::zero(), S::zero(), S::zero(), S::zero(), S::zero(),
S::zero(), S::zero(), S::zero()) S::zero(), S::zero(), S::zero(),
S::zero(), S::zero(), S::zero(),
)
} }
#[inline] #[inline]
@ -338,10 +395,13 @@ impl<S: BaseFloat> Zero for Matrix3<S> {
impl<S: BaseFloat> Zero for Matrix4<S> { impl<S: BaseFloat> Zero for Matrix4<S> {
#[inline] #[inline]
fn zero() -> Matrix4<S> { fn zero() -> Matrix4<S> {
Matrix4::new(S::zero(), S::zero(), S::zero(), S::zero(), #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
S::zero(), S::zero(), S::zero(), S::zero(), S::zero(), S::zero(), S::zero(), S::zero(),
S::zero(), S::zero(), S::zero(), S::zero(), S::zero(), S::zero(), S::zero(), S::zero(),
S::zero(), S::zero(), S::zero(), S::zero()) S::zero(), S::zero(), S::zero(), S::zero(),
S::zero(), S::zero(), S::zero(), S::zero(),
)
} }
#[inline] #[inline]
@ -390,8 +450,7 @@ impl<S: BaseFloat> Matrix for Matrix2<S> {
#[inline] #[inline]
fn row(&self, r: usize) -> Vector2<S> { fn row(&self, r: usize) -> Vector2<S> {
Vector2::new(self[0][r], Vector2::new(self[0][r], self[1][r])
self[1][r])
} }
#[inline] #[inline]
@ -413,8 +472,11 @@ impl<S: BaseFloat> Matrix for Matrix2<S> {
} }
fn transpose(&self) -> Matrix2<S> { fn transpose(&self) -> Matrix2<S> {
Matrix2::new(self[0][0], self[1][0], #[cfg_attr(rustfmt, rustfmt_skip)]
self[0][1], self[1][1]) Matrix2::new(
self[0][0], self[1][0],
self[0][1], self[1][1],
)
} }
} }
@ -423,14 +485,20 @@ impl<S: BaseFloat> SquareMatrix for Matrix2<S> {
#[inline] #[inline]
fn from_value(value: S) -> Matrix2<S> { fn from_value(value: S) -> Matrix2<S> {
Matrix2::new(value, S::zero(), #[cfg_attr(rustfmt, rustfmt_skip)]
S::zero(), value) Matrix2::new(
value, S::zero(),
S::zero(), value,
)
} }
#[inline] #[inline]
fn from_diagonal(value: Vector2<S>) -> Matrix2<S> { fn from_diagonal(value: Vector2<S>) -> Matrix2<S> {
Matrix2::new(value.x, S::zero(), #[cfg_attr(rustfmt, rustfmt_skip)]
S::zero(), value.y) Matrix2::new(
value.x, S::zero(),
S::zero(), value.y,
)
} }
#[inline] #[inline]
@ -445,8 +513,7 @@ impl<S: BaseFloat> SquareMatrix for Matrix2<S> {
#[inline] #[inline]
fn diagonal(&self) -> Vector2<S> { fn diagonal(&self) -> Vector2<S> {
Vector2::new(self[0][0], Vector2::new(self[0][0], self[1][1])
self[1][1])
} }
#[inline] #[inline]
@ -455,24 +522,22 @@ impl<S: BaseFloat> SquareMatrix for Matrix2<S> {
if det == S::zero() { if det == S::zero() {
None None
} else { } else {
Some(Matrix2::new(self[1][1] / det, #[cfg_attr(rustfmt, rustfmt_skip)]
-self[0][1] / det, Some(Matrix2::new(
-self[1][0] / det, self[1][1] / det, -self[0][1] / det,
self[0][0] / det)) -self[1][0] / det, self[0][0] / det,
))
} }
} }
#[inline] #[inline]
fn is_diagonal(&self) -> bool { fn is_diagonal(&self) -> bool {
ulps_eq!(self[0][1], &S::zero()) && ulps_eq!(self[0][1], &S::zero()) && ulps_eq!(self[1][0], &S::zero())
ulps_eq!(self[1][0], &S::zero())
} }
#[inline] #[inline]
fn is_symmetric(&self) -> bool { fn is_symmetric(&self) -> bool {
ulps_eq!(self[0][1], &self[1][0]) && ulps_eq!(self[0][1], &self[1][0]) && ulps_eq!(self[1][0], &self[0][1])
ulps_eq!(self[1][0], &self[0][1])
} }
} }
@ -483,9 +548,7 @@ impl<S: BaseFloat> Matrix for Matrix3<S> {
#[inline] #[inline]
fn row(&self, r: usize) -> Vector3<S> { fn row(&self, r: usize) -> Vector3<S> {
Vector3::new(self[0][r], Vector3::new(self[0][r], self[1][r], self[2][r])
self[1][r],
self[2][r])
} }
#[inline] #[inline]
@ -508,9 +571,12 @@ impl<S: BaseFloat> Matrix for Matrix3<S> {
} }
fn transpose(&self) -> Matrix3<S> { fn transpose(&self) -> Matrix3<S> {
Matrix3::new(self[0][0], self[1][0], self[2][0], #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix3::new(
self[0][0], self[1][0], self[2][0],
self[0][1], self[1][1], self[2][1], self[0][1], self[1][1], self[2][1],
self[0][2], self[1][2], self[2][2]) self[0][2], self[1][2], self[2][2],
)
} }
} }
@ -519,16 +585,22 @@ impl<S: BaseFloat> SquareMatrix for Matrix3<S> {
#[inline] #[inline]
fn from_value(value: S) -> Matrix3<S> { fn from_value(value: S) -> Matrix3<S> {
Matrix3::new(value, S::zero(), S::zero(), #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix3::new(
value, S::zero(), S::zero(),
S::zero(), value, S::zero(), S::zero(), value, S::zero(),
S::zero(), S::zero(), value) S::zero(), S::zero(), value,
)
} }
#[inline] #[inline]
fn from_diagonal(value: Vector3<S>) -> Matrix3<S> { fn from_diagonal(value: Vector3<S>) -> Matrix3<S> {
Matrix3::new(value.x, S::zero(), S::zero(), #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix3::new(
value.x, S::zero(), S::zero(),
S::zero(), value.y, S::zero(), S::zero(), value.y, S::zero(),
S::zero(), S::zero(), value.z) S::zero(), S::zero(), value.z,
)
} }
#[inline] #[inline]
@ -539,16 +611,14 @@ impl<S: BaseFloat> SquareMatrix for Matrix3<S> {
} }
fn determinant(&self) -> S { fn determinant(&self) -> S {
self[0][0] * (self[1][1] * self[2][2] - self[2][1] * self[1][2]) - self[0][0] * (self[1][1] * self[2][2] - self[2][1] * self[1][2])
self[1][0] * (self[0][1] * self[2][2] - self[2][1] * self[0][2]) + - self[1][0] * (self[0][1] * self[2][2] - self[2][1] * self[0][2])
self[2][0] * (self[0][1] * self[1][2] - self[1][1] * self[0][2]) + self[2][0] * (self[0][1] * self[1][2] - self[1][1] * self[0][2])
} }
#[inline] #[inline]
fn diagonal(&self) -> Vector3<S> { fn diagonal(&self) -> Vector3<S> {
Vector3::new(self[0][0], Vector3::new(self[0][0], self[1][1], self[2][2])
self[1][1],
self[2][2])
} }
fn invert(&self) -> Option<Matrix3<S>> { fn invert(&self) -> Option<Matrix3<S>> {
@ -556,32 +626,26 @@ impl<S: BaseFloat> SquareMatrix for Matrix3<S> {
if det == S::zero() { if det == S::zero() {
None None
} else { } else {
Some(Matrix3::from_cols(self[1].cross(self[2]) / det, Some(
Matrix3::from_cols(
self[1].cross(self[2]) / det,
self[2].cross(self[0]) / det, self[2].cross(self[0]) / det,
self[0].cross(self[1]) / det).transpose()) self[0].cross(self[1]) / det,
).transpose(),
)
} }
} }
fn is_diagonal(&self) -> bool { fn is_diagonal(&self) -> bool {
ulps_eq!(self[0][1], &S::zero()) && ulps_eq!(self[0][1], &S::zero()) && ulps_eq!(self[0][2], &S::zero())
ulps_eq!(self[0][2], &S::zero()) && && ulps_eq!(self[1][0], &S::zero()) && ulps_eq!(self[1][2], &S::zero())
&& ulps_eq!(self[2][0], &S::zero()) && ulps_eq!(self[2][1], &S::zero())
ulps_eq!(self[1][0], &S::zero()) &&
ulps_eq!(self[1][2], &S::zero()) &&
ulps_eq!(self[2][0], &S::zero()) &&
ulps_eq!(self[2][1], &S::zero())
} }
fn is_symmetric(&self) -> bool { fn is_symmetric(&self) -> bool {
ulps_eq!(self[0][1], &self[1][0]) && ulps_eq!(self[0][1], &self[1][0]) && ulps_eq!(self[0][2], &self[2][0])
ulps_eq!(self[0][2], &self[2][0]) && && ulps_eq!(self[1][0], &self[0][1]) && ulps_eq!(self[1][2], &self[2][1])
&& ulps_eq!(self[2][0], &self[0][2]) && ulps_eq!(self[2][1], &self[1][2])
ulps_eq!(self[1][0], &self[0][1]) &&
ulps_eq!(self[1][2], &self[2][1]) &&
ulps_eq!(self[2][0], &self[0][2]) &&
ulps_eq!(self[2][1], &self[1][2])
} }
} }
@ -592,10 +656,7 @@ impl<S: BaseFloat> Matrix for Matrix4<S> {
#[inline] #[inline]
fn row(&self, r: usize) -> Vector4<S> { fn row(&self, r: usize) -> Vector4<S> {
Vector4::new(self[0][r], Vector4::new(self[0][r], self[1][r], self[2][r], self[3][r])
self[1][r],
self[2][r],
self[3][r])
} }
#[inline] #[inline]
@ -619,31 +680,39 @@ impl<S: BaseFloat> Matrix for Matrix4<S> {
} }
fn transpose(&self) -> Matrix4<S> { fn transpose(&self) -> Matrix4<S> {
Matrix4::new(self[0][0], self[1][0], self[2][0], self[3][0], #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
self[0][0], self[1][0], self[2][0], self[3][0],
self[0][1], self[1][1], self[2][1], self[3][1], self[0][1], self[1][1], self[2][1], self[3][1],
self[0][2], self[1][2], self[2][2], self[3][2], self[0][2], self[1][2], self[2][2], self[3][2],
self[0][3], self[1][3], self[2][3], self[3][3]) self[0][3], self[1][3], self[2][3], self[3][3],
)
} }
} }
impl<S: BaseFloat> SquareMatrix for Matrix4<S> { impl<S: BaseFloat> SquareMatrix for Matrix4<S> {
type ColumnRow = Vector4<S>; type ColumnRow = Vector4<S>;
#[inline] #[inline]
fn from_value(value: S) -> Matrix4<S> { fn from_value(value: S) -> Matrix4<S> {
Matrix4::new(value, S::zero(), S::zero(), S::zero(), #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
value, S::zero(), S::zero(), S::zero(),
S::zero(), value, S::zero(), S::zero(), S::zero(), value, S::zero(), S::zero(),
S::zero(), S::zero(), value, S::zero(), S::zero(), S::zero(), value, S::zero(),
S::zero(), S::zero(), S::zero(), value) S::zero(), S::zero(), S::zero(), value,
)
} }
#[inline] #[inline]
fn from_diagonal(value: Vector4<S>) -> Matrix4<S> { fn from_diagonal(value: Vector4<S>) -> Matrix4<S> {
Matrix4::new(value.x, S::zero(), S::zero(), S::zero(), #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
value.x, S::zero(), S::zero(), S::zero(),
S::zero(), value.y, S::zero(), S::zero(), S::zero(), value.y, S::zero(), S::zero(),
S::zero(), S::zero(), value.z, S::zero(), S::zero(), S::zero(), value.z, S::zero(),
S::zero(), S::zero(), S::zero(), value.w) S::zero(), S::zero(), S::zero(), value.w,
)
} }
fn transpose_self(&mut self) { fn transpose_self(&mut self) {
@ -656,18 +725,13 @@ impl<S: BaseFloat> SquareMatrix for Matrix4<S> {
} }
fn determinant(&self) -> S { fn determinant(&self) -> S {
let tmp = unsafe { let tmp = unsafe { det_sub_proc_unsafe(self, 1, 2, 3) };
det_sub_proc_unsafe(self, 1, 2, 3)
};
tmp.dot(Vector4::new(self[0][0], self[1][0], self[2][0], self[3][0])) tmp.dot(Vector4::new(self[0][0], self[1][0], self[2][0], self[3][0]))
} }
#[inline] #[inline]
fn diagonal(&self) -> Vector4<S> { fn diagonal(&self) -> Vector4<S> {
Vector4::new(self[0][0], Vector4::new(self[0][0], self[1][1], self[2][2], self[3][3])
self[1][1],
self[2][2],
self[3][3])
} }
// The new implementation results in negative optimization when used // The new implementation results in negative optimization when used
@ -685,27 +749,40 @@ impl<S: BaseFloat> SquareMatrix for Matrix4<S> {
let t = self.transpose(); let t = self.transpose();
let cf = |i, j| { let cf = |i, j| {
let mat = match i { let mat = match i {
0 => Matrix3::from_cols(t.y.truncate_n(j), t.z.truncate_n(j), t.w.truncate_n(j)), 0 => {
1 => Matrix3::from_cols(t.x.truncate_n(j), t.z.truncate_n(j), t.w.truncate_n(j)), Matrix3::from_cols(t.y.truncate_n(j), t.z.truncate_n(j), t.w.truncate_n(j))
2 => Matrix3::from_cols(t.x.truncate_n(j), t.y.truncate_n(j), t.w.truncate_n(j)), }
3 => Matrix3::from_cols(t.x.truncate_n(j), t.y.truncate_n(j), t.z.truncate_n(j)), 1 => {
Matrix3::from_cols(t.x.truncate_n(j), t.z.truncate_n(j), t.w.truncate_n(j))
}
2 => {
Matrix3::from_cols(t.x.truncate_n(j), t.y.truncate_n(j), t.w.truncate_n(j))
}
3 => {
Matrix3::from_cols(t.x.truncate_n(j), t.y.truncate_n(j), t.z.truncate_n(j))
}
_ => panic!("out of range"), _ => panic!("out of range"),
}; };
let sign = if (i + j) & 1 == 1 { -S::one() } else { S::one() }; let sign = if (i + j) & 1 == 1 {
-S::one()
} else {
S::one()
};
mat.determinant() * sign * inv_det mat.determinant() * sign * inv_det
}; };
Some(Matrix4::new(cf(0, 0), cf(0, 1), cf(0, 2), cf(0, 3), #[cfg_attr(rustfmt, rustfmt_skip)]
Some(Matrix4::new(
cf(0, 0), cf(0, 1), cf(0, 2), cf(0, 3),
cf(1, 0), cf(1, 1), cf(1, 2), cf(1, 3), cf(1, 0), cf(1, 1), cf(1, 2), cf(1, 3),
cf(2, 0), cf(2, 1), cf(2, 2), cf(2, 3), cf(2, 0), cf(2, 1), cf(2, 2), cf(2, 3),
cf(3, 0), cf(3, 1), cf(3, 2), cf(3, 3))) cf(3, 0), cf(3, 1), cf(3, 2), cf(3, 3),
))
} }
} }
#[cfg(feature = "simd")] #[cfg(feature = "simd")]
fn invert(&self) -> Option<Matrix4<S>> { fn invert(&self) -> Option<Matrix4<S>> {
let tmp0 = unsafe { let tmp0 = unsafe { det_sub_proc_unsafe(self, 1, 2, 3) };
det_sub_proc_unsafe(self, 1, 2, 3)
};
let det = tmp0.dot(Vector4::new(self[0][0], self[1][0], self[2][0], self[3][0])); let det = tmp0.dot(Vector4::new(self[0][0], self[1][0], self[2][0], self[3][0]));
if det == S::zero() { if det == S::zero() {
@ -713,53 +790,29 @@ impl<S: BaseFloat> SquareMatrix for Matrix4<S> {
} else { } else {
let inv_det = S::one() / det; let inv_det = S::one() / det;
let tmp0 = tmp0 * inv_det; let tmp0 = tmp0 * inv_det;
let tmp1 = unsafe { let tmp1 = unsafe { det_sub_proc_unsafe(self, 0, 3, 2) * inv_det };
det_sub_proc_unsafe(self, 0, 3, 2) * inv_det let tmp2 = unsafe { det_sub_proc_unsafe(self, 0, 1, 3) * inv_det };
}; let tmp3 = unsafe { det_sub_proc_unsafe(self, 0, 2, 1) * inv_det };
let tmp2 = unsafe {
det_sub_proc_unsafe(self, 0, 1, 3) * inv_det
};
let tmp3 = unsafe {
det_sub_proc_unsafe(self, 0, 2, 1) * inv_det
};
Some(Matrix4::from_cols(tmp0, tmp1, tmp2, tmp3)) Some(Matrix4::from_cols(tmp0, tmp1, tmp2, tmp3))
} }
} }
fn is_diagonal(&self) -> bool { fn is_diagonal(&self) -> bool {
ulps_eq!(self[0][1], &S::zero()) && ulps_eq!(self[0][1], &S::zero()) && ulps_eq!(self[0][2], &S::zero())
ulps_eq!(self[0][2], &S::zero()) && && ulps_eq!(self[0][3], &S::zero()) && ulps_eq!(self[1][0], &S::zero())
ulps_eq!(self[0][3], &S::zero()) && && ulps_eq!(self[1][2], &S::zero()) && ulps_eq!(self[1][3], &S::zero())
&& ulps_eq!(self[2][0], &S::zero()) && ulps_eq!(self[2][1], &S::zero())
ulps_eq!(self[1][0], &S::zero()) && && ulps_eq!(self[2][3], &S::zero()) && ulps_eq!(self[3][0], &S::zero())
ulps_eq!(self[1][2], &S::zero()) && && ulps_eq!(self[3][1], &S::zero()) && ulps_eq!(self[3][2], &S::zero())
ulps_eq!(self[1][3], &S::zero()) &&
ulps_eq!(self[2][0], &S::zero()) &&
ulps_eq!(self[2][1], &S::zero()) &&
ulps_eq!(self[2][3], &S::zero()) &&
ulps_eq!(self[3][0], &S::zero()) &&
ulps_eq!(self[3][1], &S::zero()) &&
ulps_eq!(self[3][2], &S::zero())
} }
fn is_symmetric(&self) -> bool { fn is_symmetric(&self) -> bool {
ulps_eq!(self[0][1], &self[1][0]) && ulps_eq!(self[0][1], &self[1][0]) && ulps_eq!(self[0][2], &self[2][0])
ulps_eq!(self[0][2], &self[2][0]) && && ulps_eq!(self[0][3], &self[3][0]) && ulps_eq!(self[1][0], &self[0][1])
ulps_eq!(self[0][3], &self[3][0]) && && ulps_eq!(self[1][2], &self[2][1]) && ulps_eq!(self[1][3], &self[3][1])
&& ulps_eq!(self[2][0], &self[0][2]) && ulps_eq!(self[2][1], &self[1][2])
ulps_eq!(self[1][0], &self[0][1]) && && ulps_eq!(self[2][3], &self[3][2]) && ulps_eq!(self[3][0], &self[0][3])
ulps_eq!(self[1][2], &self[2][1]) && && ulps_eq!(self[3][1], &self[1][3]) && ulps_eq!(self[3][2], &self[2][3])
ulps_eq!(self[1][3], &self[3][1]) &&
ulps_eq!(self[2][0], &self[0][2]) &&
ulps_eq!(self[2][1], &self[1][2]) &&
ulps_eq!(self[2][3], &self[3][2]) &&
ulps_eq!(self[3][0], &self[0][3]) &&
ulps_eq!(self[3][1], &self[1][3]) &&
ulps_eq!(self[3][2], &self[2][3])
} }
} }
@ -783,14 +836,14 @@ impl<S: BaseFloat> ApproxEq for Matrix2<S> {
#[inline] #[inline]
fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool {
Vector2::relative_eq(&self[0], &other[0], epsilon, max_relative) && Vector2::relative_eq(&self[0], &other[0], epsilon, max_relative)
Vector2::relative_eq(&self[1], &other[1], epsilon, max_relative) && Vector2::relative_eq(&self[1], &other[1], epsilon, max_relative)
} }
#[inline] #[inline]
fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool {
Vector2::ulps_eq(&self[0], &other[0], epsilon, max_ulps) && Vector2::ulps_eq(&self[0], &other[0], epsilon, max_ulps)
Vector2::ulps_eq(&self[1], &other[1], epsilon, max_ulps) && Vector2::ulps_eq(&self[1], &other[1], epsilon, max_ulps)
} }
} }
@ -814,16 +867,16 @@ impl<S: BaseFloat> ApproxEq for Matrix3<S> {
#[inline] #[inline]
fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool {
Vector3::relative_eq(&self[0], &other[0], epsilon, max_relative) && Vector3::relative_eq(&self[0], &other[0], epsilon, max_relative)
Vector3::relative_eq(&self[1], &other[1], epsilon, max_relative) && && Vector3::relative_eq(&self[1], &other[1], epsilon, max_relative)
Vector3::relative_eq(&self[2], &other[2], epsilon, max_relative) && Vector3::relative_eq(&self[2], &other[2], epsilon, max_relative)
} }
#[inline] #[inline]
fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool {
Vector3::ulps_eq(&self[0], &other[0], epsilon, max_ulps) && Vector3::ulps_eq(&self[0], &other[0], epsilon, max_ulps)
Vector3::ulps_eq(&self[1], &other[1], epsilon, max_ulps) && && Vector3::ulps_eq(&self[1], &other[1], epsilon, max_ulps)
Vector3::ulps_eq(&self[2], &other[2], epsilon, max_ulps) && Vector3::ulps_eq(&self[2], &other[2], epsilon, max_ulps)
} }
} }
@ -847,18 +900,18 @@ impl<S: BaseFloat> ApproxEq for Matrix4<S> {
#[inline] #[inline]
fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool {
Vector4::relative_eq(&self[0], &other[0], epsilon, max_relative) && Vector4::relative_eq(&self[0], &other[0], epsilon, max_relative)
Vector4::relative_eq(&self[1], &other[1], epsilon, max_relative) && && Vector4::relative_eq(&self[1], &other[1], epsilon, max_relative)
Vector4::relative_eq(&self[2], &other[2], epsilon, max_relative) && && Vector4::relative_eq(&self[2], &other[2], epsilon, max_relative)
Vector4::relative_eq(&self[3], &other[3], epsilon, max_relative) && Vector4::relative_eq(&self[3], &other[3], epsilon, max_relative)
} }
#[inline] #[inline]
fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool {
Vector4::ulps_eq(&self[0], &other[0], epsilon, max_ulps) && Vector4::ulps_eq(&self[0], &other[0], epsilon, max_ulps)
Vector4::ulps_eq(&self[1], &other[1], epsilon, max_ulps) && && Vector4::ulps_eq(&self[1], &other[1], epsilon, max_ulps)
Vector4::ulps_eq(&self[2], &other[2], epsilon, max_ulps) && && Vector4::ulps_eq(&self[2], &other[2], epsilon, max_ulps)
Vector4::ulps_eq(&self[3], &other[3], epsilon, max_ulps) && Vector4::ulps_eq(&self[3], &other[3], epsilon, max_ulps)
} }
} }
@ -1060,6 +1113,7 @@ macro_rules! impl_scalar_ops {
impl_matrix!(Matrix2, Vector2 { x: 0, y: 1 }); impl_matrix!(Matrix2, Vector2 { x: 0, y: 1 });
impl_matrix!(Matrix3, Vector3 { x: 0, y: 1, z: 2 }); impl_matrix!(Matrix3, Vector3 { x: 0, y: 1, z: 2 });
#[cfg_attr(rustfmt, rustfmt_skip)]
impl_matrix!(Matrix4, Vector4 { x: 0, y: 1, z: 2, w: 3 }); impl_matrix!(Matrix4, Vector4 { x: 0, y: 1, z: 2, w: 3 });
macro_rules! impl_mv_operator { macro_rules! impl_mv_operator {
@ -1073,7 +1127,9 @@ macro_rules! impl_mv_operator {
impl_mv_operator!(Matrix2, Vector2 { x: 0, y: 1 }); impl_mv_operator!(Matrix2, Vector2 { x: 0, y: 1 });
impl_mv_operator!(Matrix3, Vector3 { x: 0, y: 1, z: 2 }); impl_mv_operator!(Matrix3, Vector3 { x: 0, y: 1, z: 2 });
#[cfg(not(feature = "simd"))] #[cfg(not(feature = "simd"))]
#[cfg_attr(rustfmt, rustfmt_skip)]
impl_mv_operator!(Matrix4, Vector4 { x: 0, y: 1, z: 2, w: 3 }); impl_mv_operator!(Matrix4, Vector4 { x: 0, y: 1, z: 2, w: 3 });
#[cfg(feature = "simd")] #[cfg(feature = "simd")]
impl_operator!(<S: BaseFloat> Mul<Vector4<S> > for Matrix4<S> { impl_operator!(<S: BaseFloat> Mul<Vector4<S> > for Matrix4<S> {
fn mul(matrix, vector) -> Vector4<S> { fn mul(matrix, vector) -> Vector4<S> {
@ -1109,6 +1165,8 @@ impl_operator!(<S: BaseFloat> Mul<Matrix4<S> > for Matrix4<S> {
let b = lhs[1]; let b = lhs[1];
let c = lhs[2]; let c = lhs[2];
let d = lhs[3]; let d = lhs[3];
#[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::from_cols( Matrix4::from_cols(
a*rhs[0][0] + b*rhs[0][1] + c*rhs[0][2] + d*rhs[0][3], a*rhs[0][0] + b*rhs[0][1] + c*rhs[0][2] + d*rhs[0][3],
a*rhs[1][0] + b*rhs[1][1] + c*rhs[1][2] + d*rhs[1][3], a*rhs[1][0] + b*rhs[1][1] + c*rhs[1][2] + d*rhs[1][3],
@ -1157,7 +1215,8 @@ index_operators!(Matrix4<S>, 4, Vector4<S>, usize);
// index_operators!(Matrix3<S>, 3, [Vector3<S>], RangeFull); // index_operators!(Matrix3<S>, 3, [Vector3<S>], RangeFull);
// index_operators!(Matrix4<S>, 4, [Vector4<S>], RangeFull); // index_operators!(Matrix4<S>, 4, [Vector4<S>], RangeFull);
impl<A> From<Euler<A>> for Matrix3<A::Unitless> where impl<A> From<Euler<A>> for Matrix3<A::Unitless>
where
A: Angle + Into<Rad<<A as Angle>::Unitless>>, A: Angle + Into<Rad<<A as Angle>::Unitless>>,
{ {
fn from(src: Euler<A>) -> Matrix3<A::Unitless> { fn from(src: Euler<A>) -> Matrix3<A::Unitless> {
@ -1166,13 +1225,17 @@ impl<A> From<Euler<A>> for Matrix3<A::Unitless> where
let (sy, cy) = Rad::sin_cos(src.y.into()); let (sy, cy) = Rad::sin_cos(src.y.into());
let (sz, cz) = Rad::sin_cos(src.z.into()); let (sz, cz) = Rad::sin_cos(src.z.into());
Matrix3::new(cy * cz, cx * sz + sx * sy * cz, sx * sz - cx * sy * cz, #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix3::new(
cy * cz, cx * sz + sx * sy * cz, sx * sz - cx * sy * cz,
-cy * sz, cx * cz - sx * sy * sz, sx * cz + cx * sy * sz, -cy * sz, cx * cz - sx * sy * sz, sx * cz + cx * sy * sz,
sy, -sx * cy, cx * cy) sy, -sx * cy, cx * cy,
)
} }
} }
impl<A> From<Euler<A>> for Matrix4<A::Unitless> where impl<A> From<Euler<A>> for Matrix4<A::Unitless>
where
A: Angle + Into<Rad<<A as Angle>::Unitless>>, A: Angle + Into<Rad<<A as Angle>::Unitless>>,
{ {
fn from(src: Euler<A>) -> Matrix4<A::Unitless> { fn from(src: Euler<A>) -> Matrix4<A::Unitless> {
@ -1181,10 +1244,13 @@ impl<A> From<Euler<A>> for Matrix4<A::Unitless> where
let (sy, cy) = Rad::sin_cos(src.y.into()); let (sy, cy) = Rad::sin_cos(src.y.into());
let (sz, cz) = Rad::sin_cos(src.z.into()); let (sz, cz) = Rad::sin_cos(src.z.into());
Matrix4::new(cy * cz, cx * sz + sx * sy * cz, sx * sz - cx * sy * cz, A::Unitless::zero(), #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
cy * cz, cx * sz + sx * sy * cz, sx * sz - cx * sy * cz, A::Unitless::zero(),
-cy * sz, cx * cz - sx * sy * sz, sx * cz + cx * sy * sz, A::Unitless::zero(), -cy * sz, cx * cz - sx * sy * sz, sx * cz + cx * sy * sz, A::Unitless::zero(),
sy, -sx * cy, cx * cy, A::Unitless::zero(), sy, -sx * cy, cx * cy, A::Unitless::zero(),
A::Unitless::zero(), A::Unitless::zero(), A::Unitless::zero(), A::Unitless::one()) A::Unitless::zero(), A::Unitless::zero(), A::Unitless::zero(), A::Unitless::one(),
)
} }
} }
@ -1314,9 +1380,12 @@ impl<S: BaseFloat> From<Matrix2<S>> for Matrix3<S> {
/// Clone the elements of a 2-dimensional matrix into the top-left corner /// Clone the elements of a 2-dimensional matrix into the top-left corner
/// of a 3-dimensional identity matrix. /// of a 3-dimensional identity matrix.
fn from(m: Matrix2<S>) -> Matrix3<S> { fn from(m: Matrix2<S>) -> Matrix3<S> {
Matrix3::new(m[0][0], m[0][1], S::zero(), #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix3::new(
m[0][0], m[0][1], S::zero(),
m[1][0], m[1][1], S::zero(), m[1][0], m[1][1], S::zero(),
S::zero(), S::zero(), S::one()) S::zero(), S::zero(), S::one(),
)
} }
} }
@ -1324,10 +1393,13 @@ impl<S: BaseFloat> From<Matrix2<S>> for Matrix4<S> {
/// Clone the elements of a 2-dimensional matrix into the top-left corner /// Clone the elements of a 2-dimensional matrix into the top-left corner
/// of a 4-dimensional identity matrix. /// of a 4-dimensional identity matrix.
fn from(m: Matrix2<S>) -> Matrix4<S> { fn from(m: Matrix2<S>) -> Matrix4<S> {
Matrix4::new(m[0][0], m[0][1], S::zero(), S::zero(), #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
m[0][0], m[0][1], S::zero(), S::zero(),
m[1][0], m[1][1], S::zero(), S::zero(), m[1][0], m[1][1], S::zero(), S::zero(),
S::zero(), S::zero(), S::one(), S::zero(), S::zero(), S::zero(), S::one(), S::zero(),
S::zero(), S::zero(), S::zero(), S::one()) S::zero(), S::zero(), S::zero(), S::one(),
)
} }
} }
@ -1335,10 +1407,13 @@ impl<S: BaseFloat> From<Matrix3<S>> for Matrix4<S> {
/// Clone the elements of a 3-dimensional matrix into the top-left corner /// Clone the elements of a 3-dimensional matrix into the top-left corner
/// of a 4-dimensional identity matrix. /// of a 4-dimensional identity matrix.
fn from(m: Matrix3<S>) -> Matrix4<S> { fn from(m: Matrix3<S>) -> Matrix4<S> {
Matrix4::new(m[0][0], m[0][1], m[0][2], S::zero(), #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
m[0][0], m[0][1], m[0][2], S::zero(),
m[1][0], m[1][1], m[1][2], S::zero(), m[1][0], m[1][1], m[1][2], S::zero(),
m[2][0], m[2][1], m[2][2], S::zero(), m[2][0], m[2][1], m[2][2], S::zero(),
S::zero(), S::zero(), S::zero(), S::one()) S::zero(), S::zero(), S::zero(), S::one(),
)
} }
} }
@ -1409,39 +1484,101 @@ impl<S: fmt::Debug> fmt::Debug for Matrix4<S> {
impl<S: BaseFloat + Rand> Rand for Matrix2<S> { impl<S: BaseFloat + Rand> Rand for Matrix2<S> {
#[inline] #[inline]
fn rand<R: Rng>(rng: &mut R) -> Matrix2<S> { fn rand<R: Rng>(rng: &mut R) -> Matrix2<S> {
Matrix2{ x: rng.gen(), y: rng.gen() } Matrix2 {
x: rng.gen(),
y: rng.gen(),
}
} }
} }
impl<S: BaseFloat + Rand> Rand for Matrix3<S> { impl<S: BaseFloat + Rand> Rand for Matrix3<S> {
#[inline] #[inline]
fn rand<R: Rng>(rng: &mut R) -> Matrix3<S> { fn rand<R: Rng>(rng: &mut R) -> Matrix3<S> {
Matrix3{ x: rng.gen(), y: rng.gen(), z: rng.gen() } Matrix3 {
x: rng.gen(),
y: rng.gen(),
z: rng.gen(),
}
} }
} }
impl<S: BaseFloat + Rand> Rand for Matrix4<S> { impl<S: BaseFloat + Rand> Rand for Matrix4<S> {
#[inline] #[inline]
fn rand<R: Rng>(rng: &mut R) -> Matrix4<S> { fn rand<R: Rng>(rng: &mut R) -> Matrix4<S> {
Matrix4{ x: rng.gen(), y: rng.gen(), z: rng.gen(), w: rng.gen() } Matrix4 {
x: rng.gen(),
y: rng.gen(),
z: rng.gen(),
w: rng.gen(),
}
} }
} }
// Sub procedure for SIMD when dealing with determinant and inversion // Sub procedure for SIMD when dealing with determinant and inversion
#[inline] #[inline]
unsafe fn det_sub_proc_unsafe<S: BaseFloat>(m: &Matrix4<S>, x: usize, y: usize, z: usize) -> Vector4<S> { unsafe fn det_sub_proc_unsafe<S: BaseFloat>(
m: &Matrix4<S>,
x: usize,
y: usize,
z: usize,
) -> Vector4<S> {
let s: &[S; 16] = m.as_ref(); let s: &[S; 16] = m.as_ref();
let a = Vector4::new(*s.get_unchecked(4 + x), *s.get_unchecked(12 + x), *s.get_unchecked(x), *s.get_unchecked(8 + x)); let a = Vector4::new(
let b = Vector4::new(*s.get_unchecked(8 + y), *s.get_unchecked(8 + y), *s.get_unchecked(4 + y), *s.get_unchecked(4 + y)); *s.get_unchecked(4 + x),
let c = Vector4::new(*s.get_unchecked(12 + z), *s.get_unchecked(z), *s.get_unchecked(12 + z), *s.get_unchecked(z)); *s.get_unchecked(12 + x),
*s.get_unchecked(x),
*s.get_unchecked(8 + x),
);
let b = Vector4::new(
*s.get_unchecked(8 + y),
*s.get_unchecked(8 + y),
*s.get_unchecked(4 + y),
*s.get_unchecked(4 + y),
);
let c = Vector4::new(
*s.get_unchecked(12 + z),
*s.get_unchecked(z),
*s.get_unchecked(12 + z),
*s.get_unchecked(z),
);
let d = Vector4::new(*s.get_unchecked(8 + x), *s.get_unchecked(8 + x), *s.get_unchecked(4 + x), *s.get_unchecked(4 + x)); let d = Vector4::new(
let e = Vector4::new(*s.get_unchecked(12 + y), *s.get_unchecked(y), *s.get_unchecked(12 + y), *s.get_unchecked(y)); *s.get_unchecked(8 + x),
let f = Vector4::new(*s.get_unchecked(4 + z), *s.get_unchecked(12 + z), *s.get_unchecked(z), *s.get_unchecked(8 + z)); *s.get_unchecked(8 + x),
*s.get_unchecked(4 + x),
*s.get_unchecked(4 + x),
);
let e = Vector4::new(
*s.get_unchecked(12 + y),
*s.get_unchecked(y),
*s.get_unchecked(12 + y),
*s.get_unchecked(y),
);
let f = Vector4::new(
*s.get_unchecked(4 + z),
*s.get_unchecked(12 + z),
*s.get_unchecked(z),
*s.get_unchecked(8 + z),
);
let g = Vector4::new(*s.get_unchecked(12 + x), *s.get_unchecked(x), *s.get_unchecked(12 + x), *s.get_unchecked(x)); let g = Vector4::new(
let h = Vector4::new(*s.get_unchecked(4 + y), *s.get_unchecked(12 + y), *s.get_unchecked(y), *s.get_unchecked(8 + y)); *s.get_unchecked(12 + x),
let i = Vector4::new(*s.get_unchecked(8 + z), *s.get_unchecked(8 + z), *s.get_unchecked(4 + z), *s.get_unchecked(4 + z)); *s.get_unchecked(x),
*s.get_unchecked(12 + x),
*s.get_unchecked(x),
);
let h = Vector4::new(
*s.get_unchecked(4 + y),
*s.get_unchecked(12 + y),
*s.get_unchecked(y),
*s.get_unchecked(8 + y),
);
let i = Vector4::new(
*s.get_unchecked(8 + z),
*s.get_unchecked(8 + z),
*s.get_unchecked(4 + z),
*s.get_unchecked(4 + z),
);
let mut tmp = a.mul_element_wise(b.mul_element_wise(c)); let mut tmp = a.mul_element_wise(b.mul_element_wise(c));
tmp += d.mul_element_wise(e.mul_element_wise(f)); tmp += d.mul_element_wise(e.mul_element_wise(f));
tmp += g.mul_element_wise(h.mul_element_wise(i)); tmp += g.mul_element_wise(h.mul_element_wise(i));

View file

@ -21,11 +21,41 @@ use std::ops::*;
use num_traits::{Float, Num, NumCast}; use num_traits::{Float, Num, NumCast};
/// Base numeric types with partial ordering /// Base numeric types with partial ordering
pub trait BaseNum: Copy + Clone + fmt::Debug + Num + NumCast + PartialOrd + AddAssign + SubAssign + MulAssign + DivAssign + RemAssign {} pub trait BaseNum
: Copy
+ Clone
+ fmt::Debug
+ Num
+ NumCast
+ PartialOrd
+ AddAssign
+ SubAssign
+ MulAssign
+ DivAssign
+ RemAssign {
}
impl<T> BaseNum for T where T: Copy + Clone + fmt::Debug + Num + NumCast + PartialOrd + AddAssign + SubAssign + MulAssign + DivAssign + RemAssign {} impl<T> BaseNum for T
where
T: Copy
+ Clone
+ fmt::Debug
+ Num
+ NumCast
+ PartialOrd
+ AddAssign
+ SubAssign
+ MulAssign
+ DivAssign
+ RemAssign,
{
}
/// Base floating point types /// Base floating point types
pub trait BaseFloat: BaseNum + Float + ApproxEq<Epsilon = Self> {} pub trait BaseFloat: BaseNum + Float + ApproxEq<Epsilon = Self> {}
impl<T> BaseFloat for T where T: BaseNum + Float + ApproxEq<Epsilon = Self> {} impl<T> BaseFloat for T
where
T: BaseNum + Float + ApproxEq<Epsilon = Self>,
{
}

View file

@ -17,7 +17,7 @@
//! distinguishes them from vectors, which have a length and direction, but do //! distinguishes them from vectors, which have a length and direction, but do
//! not have a fixed position. //! not have a fixed position.
use num_traits::{NumCast, Bounded}; use num_traits::{Bounded, NumCast};
use std::fmt; use std::fmt;
use std::mem; use std::mem;
use std::ops::*; use std::ops::*;
@ -25,7 +25,7 @@ use std::ops::*;
use structure::*; use structure::*;
use approx::ApproxEq; use approx::ApproxEq;
use num::{BaseNum, BaseFloat}; use num::{BaseFloat, BaseNum};
use vector::{Vector1, Vector2, Vector3, Vector4}; use vector::{Vector1, Vector2, Vector3, Vector4};
#[cfg(feature = "mint")] #[cfg(feature = "mint")]

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 num_traits::{Zero}; use num_traits::Zero;
use num_traits::cast; use num_traits::cast;
use structure::Angle; use structure::Angle;
@ -26,7 +26,12 @@ use num::BaseFloat;
/// ///
/// This is the equivalent to the [gluPerspective] /// This is the equivalent to the [gluPerspective]
/// (http://www.opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml) function. /// (http://www.opengl.org/sdk/docs/man2/xhtml/gluPerspective.xml) function.
pub fn perspective<S: BaseFloat, A: Into<Rad<S>>>(fovy: A, aspect: S, near: S, far: S) -> Matrix4<S> { pub fn perspective<S: BaseFloat, A: Into<Rad<S>>>(
fovy: A,
aspect: S,
near: S,
far: S,
) -> Matrix4<S> {
PerspectiveFov { PerspectiveFov {
fovy: fovy.into(), fovy: fovy.into(),
aspect: aspect, aspect: aspect,
@ -96,12 +101,37 @@ impl<S: BaseFloat> PerspectiveFov<S> {
impl<S: BaseFloat> From<PerspectiveFov<S>> for Matrix4<S> { impl<S: BaseFloat> From<PerspectiveFov<S>> for Matrix4<S> {
fn from(persp: PerspectiveFov<S>) -> Matrix4<S> { fn from(persp: PerspectiveFov<S>) -> Matrix4<S> {
assert!(persp.fovy > Rad::zero(), "The vertical field of view cannot be below zero, found: {:?}", persp.fovy); assert!(
assert!(persp.fovy < Rad::turn_div_2(), "The vertical field of view cannot be greater than a half turn, found: {:?}", persp.fovy); persp.fovy > Rad::zero(),
assert!(persp.aspect > S::zero(), "The aspect ratio cannot be below zero, found: {:?}", persp.aspect); "The vertical field of view cannot be below zero, found: {:?}",
assert!(persp.near > S::zero(), "The near plane distance cannot be below zero, found: {:?}", persp.near); persp.fovy
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.fovy < Rad::turn_div_2(),
"The vertical field of view cannot be greater than a half turn, found: {:?}",
persp.fovy
);
assert!(
persp.aspect > S::zero(),
"The aspect ratio cannot be below zero, found: {:?}",
persp.aspect
);
assert!(
persp.near > S::zero(),
"The near plane distance cannot be below zero, found: {:?}",
persp.near
);
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 two: S = cast(2).unwrap(); let two: S = cast(2).unwrap();
let f = Rad::cot(persp.fovy / two); let f = Rad::cot(persp.fovy / two);
@ -126,10 +156,13 @@ impl<S: BaseFloat> From<PerspectiveFov<S>> for Matrix4<S> {
let c3r2 = (two * persp.far * persp.near) / (persp.near - persp.far); let c3r2 = (two * persp.far * persp.near) / (persp.near - persp.far);
let c3r3 = S::zero(); let c3r3 = S::zero();
Matrix4::new(c0r0, c0r1, c0r2, c0r3, #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
c0r0, c0r1, c0r2, c0r3,
c1r0, c1r1, c1r2, c1r3, c1r0, c1r1, c1r2, c1r3,
c2r0, c2r1, c2r2, c2r3, c2r0, c2r1, c2r2, c2r3,
c3r0, c3r1, c3r2, c3r3) c3r0, c3r1, c3r2, c3r3,
)
} }
} }
@ -147,9 +180,24 @@ pub struct Perspective<S> {
impl<S: BaseFloat> From<Perspective<S>> for Matrix4<S> { impl<S: BaseFloat> From<Perspective<S>> for Matrix4<S> {
fn from(persp: Perspective<S>) -> Matrix4<S> { fn from(persp: Perspective<S>) -> Matrix4<S> {
assert!(persp.left <= persp.right, "`left` cannot be greater than `right`, found: left: {:?} right: {:?}", persp.left, persp.right); assert!(
assert!(persp.bottom <= persp.top, "`bottom` cannot be greater than `top`, found: bottom: {:?} top: {:?}", persp.bottom, persp.top); persp.left <= persp.right,
assert!(persp.near <= persp.far, "`near` cannot be greater than `far`, found: near: {:?} far: {:?}", persp.near, persp.far); "`left` cannot be greater than `right`, found: left: {:?} right: {:?}",
persp.left,
persp.right
);
assert!(
persp.bottom <= persp.top,
"`bottom` cannot be greater than `top`, found: bottom: {:?} top: {:?}",
persp.bottom,
persp.top
);
assert!(
persp.near <= persp.far,
"`near` cannot be greater than `far`, found: near: {:?} far: {:?}",
persp.near,
persp.far
);
let two: S = cast(2i8).unwrap(); let two: S = cast(2i8).unwrap();
@ -173,10 +221,13 @@ impl<S: BaseFloat> From<Perspective<S>> for Matrix4<S> {
let c3r2 = -(two * persp.far * persp.near) / (persp.far - persp.near); let c3r2 = -(two * persp.far * persp.near) / (persp.far - persp.near);
let c3r3 = S::zero(); let c3r3 = S::zero();
Matrix4::new(c0r0, c0r1, c0r2, c0r3, #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
c0r0, c0r1, c0r2, c0r3,
c1r0, c1r1, c1r2, c1r3, c1r0, c1r1, c1r2, c1r3,
c2r0, c2r1, c2r2, c2r3, c2r0, c2r1, c2r2, c2r3,
c3r0, c3r1, c3r2, c3r3) c3r0, c3r1, c3r2, c3r3,
)
} }
} }
@ -216,9 +267,12 @@ impl<S: BaseFloat> From<Ortho<S>> for Matrix4<S> {
let c3r2 = -(ortho.far + ortho.near) / (ortho.far - ortho.near); let c3r2 = -(ortho.far + ortho.near) / (ortho.far - ortho.near);
let c3r3 = S::one(); let c3r3 = S::one();
Matrix4::new(c0r0, c0r1, c0r2, c0r3, #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
c0r0, c0r1, c0r2, c0r3,
c1r0, c1r1, c1r2, c1r3, c1r0, c1r1, c1r2, c1r3,
c2r0, c2r1, c2r2, c2r3, c2r0, c2r1, c2r2, c2r3,
c3r0, c3r1, c3r2, c3r3) c3r0, c3r1, c3r2, c3r3,
)
} }
} }

View file

@ -18,7 +18,7 @@ use std::mem;
use std::ops::*; use std::ops::*;
use rand::{Rand, Rng}; use rand::{Rand, Rng};
use num_traits::{NumCast, cast}; use num_traits::{cast, NumCast};
use structure::*; use structure::*;
@ -28,7 +28,7 @@ use euler::Euler;
use matrix::{Matrix3, Matrix4}; use matrix::{Matrix3, Matrix4};
use num::BaseFloat; use num::BaseFloat;
use point::Point3; use point::Point3;
use rotation::{Rotation, Rotation3, Basis3}; use rotation::{Basis3, Rotation, Rotation3};
use vector::Vector3; use vector::Vector3;
#[cfg(feature = "simd")] #[cfg(feature = "simd")]
@ -97,8 +97,11 @@ impl<S: BaseFloat> Quaternion<S> {
/// (http://stackoverflow.com/questions/1171849/finding-quaternion-representing-the-rotation-from-one-vector-to-another) /// (http://stackoverflow.com/questions/1171849/finding-quaternion-representing-the-rotation-from-one-vector-to-another)
/// - [Ogre implementation for normalized vectors] /// - [Ogre implementation for normalized vectors]
/// (https://bitbucket.org/sinbad/ogre/src/9db75e3ba05c/OgreMain/include/OgreVector3.h?fileviewer=file-view-default#cl-651) /// (https://bitbucket.org/sinbad/ogre/src/9db75e3ba05c/OgreMain/include/OgreVector3.h?fileviewer=file-view-default#cl-651)
pub fn from_arc(src: Vector3<S>, dst: Vector3<S>, fallback: Option<Vector3<S>>) pub fn from_arc(
-> Quaternion<S> { src: Vector3<S>,
dst: Vector3<S>,
fallback: Option<Vector3<S>>,
) -> Quaternion<S> {
let mag_avg = (src.magnitude2() * dst.magnitude2()).sqrt(); let mag_avg = (src.magnitude2() * dst.magnitude2()).sqrt();
let dot = src.dot(dst); let dot = src.dot(dst);
if ulps_eq!(dot, &mag_avg) { if ulps_eq!(dot, &mag_avg) {
@ -193,28 +196,28 @@ impl<S: BaseFloat> One for Quaternion<S> {
impl<S: BaseFloat> iter::Sum<Quaternion<S>> for Quaternion<S> { impl<S: BaseFloat> iter::Sum<Quaternion<S>> for Quaternion<S> {
#[inline] #[inline]
fn sum<I: Iterator<Item=Quaternion<S>>>(iter: I) -> Quaternion<S> { fn sum<I: Iterator<Item = Quaternion<S>>>(iter: I) -> Quaternion<S> {
iter.fold(Quaternion::<S>::zero(), Add::add) iter.fold(Quaternion::<S>::zero(), Add::add)
} }
} }
impl<'a, S: 'a + BaseFloat> iter::Sum<&'a Quaternion<S>> for Quaternion<S> { impl<'a, S: 'a + BaseFloat> iter::Sum<&'a Quaternion<S>> for Quaternion<S> {
#[inline] #[inline]
fn sum<I: Iterator<Item=&'a Quaternion<S>>>(iter: I) -> Quaternion<S> { fn sum<I: Iterator<Item = &'a Quaternion<S>>>(iter: I) -> Quaternion<S> {
iter.fold(Quaternion::<S>::zero(), Add::add) iter.fold(Quaternion::<S>::zero(), Add::add)
} }
} }
impl<S: BaseFloat> iter::Product<Quaternion<S>> for Quaternion<S> { impl<S: BaseFloat> iter::Product<Quaternion<S>> for Quaternion<S> {
#[inline] #[inline]
fn product<I: Iterator<Item=Quaternion<S>>>(iter: I) -> Quaternion<S> { fn product<I: Iterator<Item = Quaternion<S>>>(iter: I) -> Quaternion<S> {
iter.fold(Quaternion::<S>::one(), Mul::mul) iter.fold(Quaternion::<S>::one(), Mul::mul)
} }
} }
impl<'a, S: 'a + BaseFloat> iter::Product<&'a Quaternion<S>> for Quaternion<S> { impl<'a, S: 'a + BaseFloat> iter::Product<&'a Quaternion<S>> for Quaternion<S> {
#[inline] #[inline]
fn product<I: Iterator<Item=&'a Quaternion<S>>>(iter: I) -> Quaternion<S> { fn product<I: Iterator<Item = &'a Quaternion<S>>>(iter: I) -> Quaternion<S> {
iter.fold(Quaternion::<S>::one(), Mul::mul) iter.fold(Quaternion::<S>::one(), Mul::mul)
} }
} }
@ -237,11 +240,11 @@ impl<S: NumCast + Copy> Quaternion<S> {
pub fn cast<T: BaseFloat>(&self) -> Option<Quaternion<T>> { pub fn cast<T: BaseFloat>(&self) -> Option<Quaternion<T>> {
let s = match NumCast::from(self.s) { let s = match NumCast::from(self.s) {
Some(s) => s, Some(s) => s,
None => return None None => return None,
}; };
let v = match self.v.cast() { let v = match self.v.cast() {
Some(v) => v, Some(v) => v,
None => return None None => return None,
}; };
Some(Quaternion::from_sv(s, v)) Some(Quaternion::from_sv(s, v))
} }
@ -274,7 +277,8 @@ impl InnerSpace for Quaternion<f32> {
} }
} }
impl<A> From<Euler<A>> for Quaternion<A::Unitless> where impl<A> From<Euler<A>> for Quaternion<A::Unitless>
where
A: Angle + Into<Rad<<A as Angle>::Unitless>>, A: Angle + Into<Rad<<A as Angle>::Unitless>>,
{ {
fn from(src: Euler<A>) -> Quaternion<A::Unitless> { fn from(src: Euler<A>) -> Quaternion<A::Unitless> {
@ -288,10 +292,12 @@ impl<A> From<Euler<A>> for Quaternion<A::Unitless> where
let (s_y, c_y) = Rad::sin_cos(src.y.into() * half); let (s_y, c_y) = Rad::sin_cos(src.y.into() * half);
let (s_z, c_z) = Rad::sin_cos(src.z.into() * half); let (s_z, c_z) = Rad::sin_cos(src.z.into() * half);
Quaternion::new(-s_x * s_y * s_z + c_x * c_y * c_z, Quaternion::new(
-s_x * s_y * s_z + c_x * c_y * c_z,
s_x * c_y * c_z + s_y * s_z * c_x, s_x * c_y * c_z + s_y * s_z * c_x,
-s_x * s_z * c_y + s_y * c_x * c_z, -s_x * s_z * c_y + s_y * c_x * c_z,
s_x * s_y * c_z + s_z * c_x * c_y) s_x * s_y * c_z + s_z * c_x * c_y,
)
} }
} }
@ -510,20 +516,24 @@ impl SubAssign for Quaternion<f32> {
#[cfg(not(feature = "simd"))] #[cfg(not(feature = "simd"))]
impl_operator!(<S: BaseFloat> Mul<Quaternion<S> > for Quaternion<S> { impl_operator!(<S: BaseFloat> Mul<Quaternion<S> > for Quaternion<S> {
fn mul(lhs, rhs) -> Quaternion<S> { fn mul(lhs, rhs) -> Quaternion<S> {
Quaternion::new(lhs.s * rhs.s - lhs.v.x * rhs.v.x - lhs.v.y * rhs.v.y - lhs.v.z * rhs.v.z, Quaternion::new(
lhs.s * rhs.s - lhs.v.x * rhs.v.x - lhs.v.y * rhs.v.y - lhs.v.z * rhs.v.z,
lhs.s * rhs.v.x + lhs.v.x * rhs.s + lhs.v.y * rhs.v.z - lhs.v.z * rhs.v.y, lhs.s * rhs.v.x + lhs.v.x * rhs.s + lhs.v.y * rhs.v.z - lhs.v.z * rhs.v.y,
lhs.s * rhs.v.y + lhs.v.y * rhs.s + lhs.v.z * rhs.v.x - lhs.v.x * rhs.v.z, lhs.s * rhs.v.y + lhs.v.y * rhs.s + lhs.v.z * rhs.v.x - lhs.v.x * rhs.v.z,
lhs.s * rhs.v.z + lhs.v.z * rhs.s + lhs.v.x * rhs.v.y - lhs.v.y * rhs.v.x) lhs.s * rhs.v.z + lhs.v.z * rhs.s + lhs.v.x * rhs.v.y - lhs.v.y * rhs.v.x,
)
} }
}); });
#[cfg(feature = "simd")] #[cfg(feature = "simd")]
impl_operator_default!(<S: BaseFloat> Mul<Quaternion<S> > for Quaternion<S> { impl_operator_default!(<S: BaseFloat> Mul<Quaternion<S> > for Quaternion<S> {
fn mul(lhs, rhs) -> Quaternion<S> { fn mul(lhs, rhs) -> Quaternion<S> {
Quaternion::new(lhs.s * rhs.s - lhs.v.x * rhs.v.x - lhs.v.y * rhs.v.y - lhs.v.z * rhs.v.z, Quaternion::new(
lhs.s * rhs.s - lhs.v.x * rhs.v.x - lhs.v.y * rhs.v.y - lhs.v.z * rhs.v.z,
lhs.s * rhs.v.x + lhs.v.x * rhs.s + lhs.v.y * rhs.v.z - lhs.v.z * rhs.v.y, lhs.s * rhs.v.x + lhs.v.x * rhs.s + lhs.v.y * rhs.v.z - lhs.v.z * rhs.v.y,
lhs.s * rhs.v.y + lhs.v.y * rhs.s + lhs.v.z * rhs.v.x - lhs.v.x * rhs.v.z, lhs.s * rhs.v.y + lhs.v.y * rhs.s + lhs.v.z * rhs.v.x - lhs.v.x * rhs.v.z,
lhs.s * rhs.v.z + lhs.v.z * rhs.s + lhs.v.x * rhs.v.y - lhs.v.y * rhs.v.x) lhs.s * rhs.v.z + lhs.v.z * rhs.s + lhs.v.x * rhs.v.y - lhs.v.y * rhs.v.x,
)
} }
}); });
@ -593,14 +603,14 @@ impl<S: BaseFloat> ApproxEq for Quaternion<S> {
#[inline] #[inline]
fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool { fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool {
S::relative_eq(&self.s, &other.s, epsilon, max_relative) && S::relative_eq(&self.s, &other.s, epsilon, max_relative)
Vector3::relative_eq(&self.v, &other.v, epsilon, max_relative) && Vector3::relative_eq(&self.v, &other.v, epsilon, max_relative)
} }
#[inline] #[inline]
fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool { fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool {
S::ulps_eq(&self.s, &other.s, epsilon, max_ulps) && S::ulps_eq(&self.s, &other.s, epsilon, max_ulps)
Vector3::ulps_eq(&self.v, &other.v, epsilon, max_ulps) && Vector3::ulps_eq(&self.v, &other.v, epsilon, max_ulps)
} }
} }
@ -623,9 +633,12 @@ impl<S: BaseFloat> From<Quaternion<S>> for Matrix3<S> {
let sz2 = z2 * quat.s; let sz2 = z2 * quat.s;
let sx2 = x2 * quat.s; let sx2 = x2 * quat.s;
Matrix3::new(S::one() - yy2 - zz2, xy2 + sz2, xz2 - sy2, #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix3::new(
S::one() - yy2 - zz2, xy2 + sz2, xz2 - sy2,
xy2 - sz2, S::one() - xx2 - zz2, yz2 + sx2, xy2 - sz2, S::one() - xx2 - zz2, yz2 + sx2,
xz2 + sy2, yz2 - sx2, S::one() - xx2 - yy2) xz2 + sy2, yz2 - sx2, S::one() - xx2 - yy2,
)
} }
} }
@ -648,10 +661,13 @@ impl<S: BaseFloat> From<Quaternion<S>> for Matrix4<S> {
let sz2 = z2 * quat.s; let sz2 = z2 * quat.s;
let sx2 = x2 * quat.s; let sx2 = x2 * quat.s;
Matrix4::new(S::one() - yy2 - zz2, xy2 + sz2, xz2 - sy2, S::zero(), #[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
S::one() - yy2 - zz2, xy2 + sz2, xz2 - sy2, S::zero(),
xy2 - sz2, S::one() - xx2 - zz2, yz2 + sx2, S::zero(), xy2 - sz2, S::one() - xx2 - zz2, yz2 + sx2, S::zero(),
xz2 + sy2, yz2 - sx2, S::one() - xx2 - yy2, S::zero(), xz2 + sy2, yz2 - sx2, S::one() - xx2 - yy2, S::zero(),
S::zero(), S::zero(), S::zero(), S::one()) S::zero(), S::zero(), S::zero(), S::one(),
)
} }
} }
@ -659,7 +675,9 @@ impl<S: BaseFloat> From<Quaternion<S>> for Matrix4<S> {
impl<S: BaseFloat> From<Quaternion<S>> for Basis3<S> { impl<S: BaseFloat> From<Quaternion<S>> for Basis3<S> {
#[inline] #[inline]
fn from(quat: Quaternion<S>) -> Basis3<S> { Basis3::from_quaternion(&quat) } fn from(quat: Quaternion<S>) -> Basis3<S> {
Basis3::from_quaternion(&quat)
}
} }
impl<S: BaseFloat> Rotation<Point3<S>> for Quaternion<S> { impl<S: BaseFloat> Rotation<Point3<S>> for Quaternion<S> {
@ -695,10 +713,14 @@ impl<S: BaseFloat> Rotation<Point3<S>> for Quaternion<S> {
} }
#[inline] #[inline]
fn rotate_vector(&self, vec: Vector3<S>) -> Vector3<S> { self * vec } fn rotate_vector(&self, vec: Vector3<S>) -> Vector3<S> {
self * vec
}
#[inline] #[inline]
fn invert(&self) -> Quaternion<S> { self.conjugate() / self.magnitude2() } fn invert(&self) -> Quaternion<S> {
self.conjugate() / self.magnitude2()
}
} }
impl<S: BaseFloat> Rotation3<S> for Quaternion<S> { impl<S: BaseFloat> Rotation3<S> for Quaternion<S> {
@ -712,7 +734,9 @@ impl<S: BaseFloat> Rotation3<S> for Quaternion<S> {
impl<S: BaseFloat> Into<[S; 4]> for Quaternion<S> { impl<S: BaseFloat> Into<[S; 4]> for Quaternion<S> {
#[inline] #[inline]
fn into(self) -> [S; 4] { fn into(self) -> [S; 4] {
match self.into() { (w, xi, yj, zk) => [w, xi, yj, zk] } match self.into() {
(w, xi, yj, zk) => [w, xi, yj, zk],
}
} }
} }
@ -754,7 +778,12 @@ impl<'a, S: BaseFloat> From<&'a mut [S; 4]> for &'a mut Quaternion<S> {
impl<S: BaseFloat> Into<(S, S, S, S)> for Quaternion<S> { impl<S: BaseFloat> Into<(S, S, S, S)> for Quaternion<S> {
#[inline] #[inline]
fn into(self) -> (S, S, S, S) { fn into(self) -> (S, S, S, S) {
match self { Quaternion { s, v: Vector3 { x, y, z } } => (s, x, y, z) } match self {
Quaternion {
s,
v: Vector3 { x, y, z },
} => (s, x, y, z),
}
} }
} }
@ -775,7 +804,9 @@ impl<S: BaseFloat> AsMut<(S, S, S, S)> for Quaternion<S> {
impl<S: BaseFloat> From<(S, S, S, S)> for Quaternion<S> { impl<S: BaseFloat> From<(S, S, S, S)> for Quaternion<S> {
#[inline] #[inline]
fn from(v: (S, S, S, S)) -> Quaternion<S> { fn from(v: (S, S, S, S)) -> Quaternion<S> {
match v { (w, xi, yj, zk) => Quaternion::new(w, xi, yj, zk) } match v {
(w, xi, yj, zk) => Quaternion::new(w, xi, yj, zk),
}
} }
} }
@ -846,7 +877,6 @@ impl<S: Clone> Into<mint::Quaternion<S>> for Quaternion<S> {
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use quaternion::*; use quaternion::*;
@ -854,7 +884,11 @@ mod tests {
const QUATERNION: Quaternion<f32> = Quaternion { const QUATERNION: Quaternion<f32> = Quaternion {
s: 1.0, s: 1.0,
v: Vector3 { x: 2.0, y: 3.0, z: 4.0 }, v: Vector3 {
x: 2.0,
y: 3.0,
z: 4.0,
},
}; };
#[test] #[test]
@ -887,11 +921,11 @@ mod tests {
fn test_as_mut() { fn test_as_mut() {
let mut v = QUATERNION; let mut v = QUATERNION;
{ {
let v: &mut[f32; 4] = v.as_mut(); let v: &mut [f32; 4] = v.as_mut();
assert_eq!(v, &mut [1.0, 2.0, 3.0, 4.0]); assert_eq!(v, &mut [1.0, 2.0, 3.0, 4.0]);
} }
{ {
let v: &mut(f32, f32, f32, f32) = v.as_mut(); let v: &mut (f32, f32, f32, f32) = v.as_mut();
assert_eq!(v, &mut (1.0, 2.0, 3.0, 4.0)); assert_eq!(v, &mut (1.0, 2.0, 3.0, 4.0));
} }
} }

View file

@ -30,7 +30,8 @@ use vector::{Vector2, Vector3};
/// A trait for a generic rotation. A rotation is a transformation that /// A trait for a generic rotation. A rotation is a transformation that
/// creates a circular motion, and preserves at least one point in the space. /// creates a circular motion, and preserves at least one point in the space.
pub trait Rotation<P: EuclideanSpace>: Sized + Copy + One where pub trait Rotation<P: EuclideanSpace>: Sized + Copy + One
where
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
Self: ApproxEq<Epsilon = P::Scalar>, Self: ApproxEq<Epsilon = P::Scalar>,
P::Scalar: BaseFloat, P::Scalar: BaseFloat,
@ -59,20 +60,17 @@ pub trait Rotation<P: EuclideanSpace>: Sized + Copy + One where
} }
/// A two-dimensional rotation. /// A two-dimensional rotation.
pub trait Rotation2<S: BaseFloat>: Rotation<Point2<S>> pub trait Rotation2<S: BaseFloat>
+ Into<Matrix2<S>> : Rotation<Point2<S>> + Into<Matrix2<S>> + Into<Basis2<S>> {
+ Into<Basis2<S>> {
/// Create a rotation by a given angle. Thus is a redundant case of both /// Create a rotation by a given angle. Thus is a redundant case of both
/// from_axis_angle() and from_euler() for 2D space. /// from_axis_angle() and from_euler() for 2D space.
fn from_angle<A: Into<Rad<S>>>(theta: A) -> Self; fn from_angle<A: Into<Rad<S>>>(theta: A) -> Self;
} }
/// A three-dimensional rotation. /// A three-dimensional rotation.
pub trait Rotation3<S: BaseFloat>: Rotation<Point3<S>> pub trait Rotation3<S: BaseFloat>
+ Into<Matrix3<S>> : Rotation<Point3<S>> + Into<Matrix3<S>> + Into<Basis3<S>> + Into<Quaternion<S>> + From<Euler<Rad<S>>>
+ Into<Basis3<S>> {
+ Into<Quaternion<S>>
+ From<Euler<Rad<S>>> {
/// Create a rotation using an angle around a given axis. /// Create a rotation using an angle around a given axis.
/// ///
/// The specified axis **must be normalized**, or it represents an invalid rotation. /// The specified axis **must be normalized**, or it represents an invalid rotation.
@ -97,7 +95,6 @@ pub trait Rotation3<S: BaseFloat>: Rotation<Point3<S>>
} }
} }
/// A two-dimensional rotation matrix. /// A two-dimensional rotation matrix.
/// ///
/// The matrix is guaranteed to be orthogonal, so some operations can be /// The matrix is guaranteed to be orthogonal, so some operations can be
@ -144,7 +141,7 @@ pub trait Rotation3<S: BaseFloat>: Rotation<Point3<S>>
#[derive(PartialEq, Copy, Clone)] #[derive(PartialEq, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Basis2<S> { pub struct Basis2<S> {
mat: Matrix2<S> mat: Matrix2<S>,
} }
impl<S: BaseFloat> AsRef<Matrix2<S>> for Basis2<S> { impl<S: BaseFloat> AsRef<Matrix2<S>> for Basis2<S> {
@ -156,19 +153,21 @@ impl<S: BaseFloat> AsRef<Matrix2<S>> for Basis2<S> {
impl<S: BaseFloat> From<Basis2<S>> for Matrix2<S> { impl<S: BaseFloat> From<Basis2<S>> for Matrix2<S> {
#[inline] #[inline]
fn from(b: Basis2<S>) -> Matrix2<S> { b.mat } fn from(b: Basis2<S>) -> Matrix2<S> {
b.mat
}
} }
impl<S: BaseFloat> iter::Product<Basis2<S>> for Basis2<S> { impl<S: BaseFloat> iter::Product<Basis2<S>> for Basis2<S> {
#[inline] #[inline]
fn product<I: Iterator<Item=Basis2<S>>>(iter: I) -> Basis2<S> { fn product<I: Iterator<Item = Basis2<S>>>(iter: I) -> Basis2<S> {
iter.fold(Basis2::one(), Mul::mul) iter.fold(Basis2::one(), Mul::mul)
} }
} }
impl<'a, S: 'a + BaseFloat> iter::Product<&'a Basis2<S>> for Basis2<S> { impl<'a, S: 'a + BaseFloat> iter::Product<&'a Basis2<S>> for Basis2<S> {
#[inline] #[inline]
fn product<I: Iterator<Item=&'a Basis2<S>>>(iter: I) -> Basis2<S> { fn product<I: Iterator<Item = &'a Basis2<S>>>(iter: I) -> Basis2<S> {
iter.fold(Basis2::one(), Mul::mul) iter.fold(Basis2::one(), Mul::mul)
} }
} }
@ -176,26 +175,38 @@ impl<'a, S: 'a + BaseFloat> iter::Product<&'a Basis2<S>> for Basis2<S> {
impl<S: BaseFloat> Rotation<Point2<S>> for Basis2<S> { impl<S: BaseFloat> Rotation<Point2<S>> for Basis2<S> {
#[inline] #[inline]
fn look_at(dir: Vector2<S>, up: Vector2<S>) -> Basis2<S> { fn look_at(dir: Vector2<S>, up: Vector2<S>) -> Basis2<S> {
Basis2 { mat: Matrix2::look_at(dir, up) } Basis2 {
mat: Matrix2::look_at(dir, up),
}
} }
#[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(Rad::acos(a.dot(b)) ) Rotation2::from_angle(Rad::acos(a.dot(b)))
} }
#[inline] #[inline]
fn rotate_vector(&self, vec: Vector2<S>) -> Vector2<S> { self.mat * vec } fn rotate_vector(&self, vec: Vector2<S>) -> Vector2<S> {
self.mat * vec
}
// TODO: we know the matrix is orthogonal, so this could be re-written // TODO: we know the matrix is orthogonal, so this could be re-written
// to be faster // to be faster
#[inline] #[inline]
fn invert(&self) -> Basis2<S> { Basis2 { mat: self.mat.invert().unwrap() } } fn invert(&self) -> Basis2<S> {
Basis2 {
mat: self.mat.invert().unwrap(),
}
}
} }
impl<S: BaseFloat> One for Basis2<S> { impl<S: BaseFloat> One for Basis2<S> {
#[inline] #[inline]
fn one() -> Basis2<S> { Basis2 { mat: Matrix2::one() } } fn one() -> Basis2<S> {
Basis2 {
mat: Matrix2::one(),
}
}
} }
impl_operator!(<S: BaseFloat> Mul<Basis2<S> > for Basis2<S> { impl_operator!(<S: BaseFloat> Mul<Basis2<S> > for Basis2<S> {
@ -232,7 +243,11 @@ impl<S: BaseFloat> ApproxEq for Basis2<S> {
} }
impl<S: BaseFloat> Rotation2<S> for Basis2<S> { impl<S: BaseFloat> Rotation2<S> for Basis2<S> {
fn from_angle<A: Into<Rad<S>>>(theta: A) -> Basis2<S> { Basis2 { mat: Matrix2::from_angle(theta) } } fn from_angle<A: Into<Rad<S>>>(theta: A) -> Basis2<S> {
Basis2 {
mat: Matrix2::from_angle(theta),
}
}
} }
impl<S: fmt::Debug> fmt::Debug for Basis2<S> { impl<S: fmt::Debug> fmt::Debug for Basis2<S> {
@ -251,14 +266,16 @@ impl<S: fmt::Debug> fmt::Debug for Basis2<S> {
#[derive(PartialEq, Copy, Clone)] #[derive(PartialEq, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Basis3<S> { pub struct Basis3<S> {
mat: Matrix3<S> mat: Matrix3<S>,
} }
impl<S: BaseFloat> Basis3<S> { impl<S: BaseFloat> Basis3<S> {
/// Create a new rotation matrix from a quaternion. /// Create a new rotation matrix from a quaternion.
#[inline] #[inline]
pub fn from_quaternion(quaternion: &Quaternion<S>) -> Basis3<S> { pub fn from_quaternion(quaternion: &Quaternion<S>) -> Basis3<S> {
Basis3 { mat: quaternion.clone().into() } Basis3 {
mat: quaternion.clone().into(),
}
} }
} }
@ -271,24 +288,28 @@ impl<S> AsRef<Matrix3<S>> for Basis3<S> {
impl<S: BaseFloat> From<Basis3<S>> for Matrix3<S> { impl<S: BaseFloat> From<Basis3<S>> for Matrix3<S> {
#[inline] #[inline]
fn from(b: Basis3<S>) -> Matrix3<S> { b.mat } fn from(b: Basis3<S>) -> Matrix3<S> {
b.mat
}
} }
impl<S: BaseFloat> From<Basis3<S>> for Quaternion<S> { impl<S: BaseFloat> From<Basis3<S>> for Quaternion<S> {
#[inline] #[inline]
fn from(b: Basis3<S>) -> Quaternion<S> { b.mat.into() } fn from(b: Basis3<S>) -> Quaternion<S> {
b.mat.into()
}
} }
impl<S: BaseFloat> iter::Product<Basis3<S>> for Basis3<S> { impl<S: BaseFloat> iter::Product<Basis3<S>> for Basis3<S> {
#[inline] #[inline]
fn product<I: Iterator<Item=Basis3<S>>>(iter: I) -> Basis3<S> { fn product<I: Iterator<Item = Basis3<S>>>(iter: I) -> Basis3<S> {
iter.fold(Basis3::one(), Mul::mul) iter.fold(Basis3::one(), Mul::mul)
} }
} }
impl<'a, S: 'a + BaseFloat> iter::Product<&'a Basis3<S>> for Basis3<S> { impl<'a, S: 'a + BaseFloat> iter::Product<&'a Basis3<S>> for Basis3<S> {
#[inline] #[inline]
fn product<I: Iterator<Item=&'a Basis3<S>>>(iter: I) -> Basis3<S> { fn product<I: Iterator<Item = &'a Basis3<S>>>(iter: I) -> Basis3<S> {
iter.fold(Basis3::one(), Mul::mul) iter.fold(Basis3::one(), Mul::mul)
} }
} }
@ -296,7 +317,9 @@ impl<'a, S: 'a + BaseFloat> iter::Product<&'a Basis3<S>> for Basis3<S> {
impl<S: BaseFloat> Rotation<Point3<S>> for Basis3<S> { impl<S: BaseFloat> Rotation<Point3<S>> for Basis3<S> {
#[inline] #[inline]
fn look_at(dir: Vector3<S>, up: Vector3<S>) -> Basis3<S> { fn look_at(dir: Vector3<S>, up: Vector3<S>) -> Basis3<S> {
Basis3 { mat: Matrix3::look_at(dir, up) } Basis3 {
mat: Matrix3::look_at(dir, up),
}
} }
#[inline] #[inline]
@ -306,17 +329,27 @@ impl<S: BaseFloat> Rotation<Point3<S>> for Basis3<S> {
} }
#[inline] #[inline]
fn rotate_vector(&self, vec: Vector3<S>) -> Vector3<S> { self.mat * vec } fn rotate_vector(&self, vec: Vector3<S>) -> Vector3<S> {
self.mat * vec
}
// TODO: we know the matrix is orthogonal, so this could be re-written // TODO: we know the matrix is orthogonal, so this could be re-written
// to be faster // to be faster
#[inline] #[inline]
fn invert(&self) -> Basis3<S> { Basis3 { mat: self.mat.invert().unwrap() } } fn invert(&self) -> Basis3<S> {
Basis3 {
mat: self.mat.invert().unwrap(),
}
}
} }
impl<S: BaseFloat> One for Basis3<S> { impl<S: BaseFloat> One for Basis3<S> {
#[inline] #[inline]
fn one() -> Basis3<S> { Basis3 { mat: Matrix3::one() } } fn one() -> Basis3<S> {
Basis3 {
mat: Matrix3::one(),
}
}
} }
impl_operator!(<S: BaseFloat> Mul<Basis3<S> > for Basis3<S> { impl_operator!(<S: BaseFloat> Mul<Basis3<S> > for Basis3<S> {
@ -354,23 +387,32 @@ impl<S: BaseFloat> ApproxEq for Basis3<S> {
impl<S: BaseFloat> Rotation3<S> for Basis3<S> { impl<S: BaseFloat> Rotation3<S> for Basis3<S> {
fn from_axis_angle<A: Into<Rad<S>>>(axis: Vector3<S>, angle: A) -> Basis3<S> { fn from_axis_angle<A: Into<Rad<S>>>(axis: Vector3<S>, angle: A) -> Basis3<S> {
Basis3 { mat: Matrix3::from_axis_angle(axis, angle) } Basis3 {
mat: Matrix3::from_axis_angle(axis, angle),
}
} }
fn from_angle_x<A: Into<Rad<S>>>(theta: A) -> Basis3<S> { fn from_angle_x<A: Into<Rad<S>>>(theta: A) -> Basis3<S> {
Basis3 { mat: Matrix3::from_angle_x(theta) } Basis3 {
mat: Matrix3::from_angle_x(theta),
}
} }
fn from_angle_y<A: Into<Rad<S>>>(theta: A) -> Basis3<S> { fn from_angle_y<A: Into<Rad<S>>>(theta: A) -> Basis3<S> {
Basis3 { mat: Matrix3::from_angle_y(theta) } Basis3 {
mat: Matrix3::from_angle_y(theta),
}
} }
fn from_angle_z<A: Into<Rad<S>>>(theta: A) -> Basis3<S> { fn from_angle_z<A: Into<Rad<S>>>(theta: A) -> Basis3<S> {
Basis3 { mat: Matrix3::from_angle_z(theta) } Basis3 {
mat: Matrix3::from_angle_z(theta),
}
} }
} }
impl<A: Angle> From<Euler<A>> for Basis3<A::Unitless> where impl<A: Angle> From<Euler<A>> for Basis3<A::Unitless>
where
A: Into<Rad<<A as Angle>::Unitless>>, A: Into<Rad<<A as Angle>::Unitless>>,
{ {
/// Create a three-dimensional rotation matrix from a set of euler angles. /// Create a three-dimensional rotation matrix from a set of euler angles.

View file

@ -23,12 +23,13 @@ use std::ops::*;
use approx::ApproxEq; use approx::ApproxEq;
use angle::Rad; use angle::Rad;
use num::{BaseNum, BaseFloat}; use num::{BaseFloat, BaseNum};
pub use num_traits::{One, Zero, Bounded}; pub use num_traits::{Bounded, One, Zero};
/// An array containing elements of type `Element` /// An array containing elements of type `Element`
pub trait Array where pub trait Array
where
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
Self: Index<usize, Output = <Self as Array>::Element>, Self: Index<usize, Output = <Self as Array>::Element>,
Self: IndexMut<usize, Output = <Self as Array>::Element>, Self: IndexMut<usize, Output = <Self as Array>::Element>,
@ -78,10 +79,14 @@ pub trait Array where
} }
/// The sum of the elements of the array. /// The sum of the elements of the array.
fn sum(self) -> Self::Element where Self::Element: Add<Output = <Self as Array>::Element>; fn sum(self) -> Self::Element
where
Self::Element: Add<Output = <Self as Array>::Element>;
/// The product of the elements of the array. /// The product of the elements of the array.
fn product(self) -> Self::Element where Self::Element: Mul<Output = <Self as Array>::Element>; fn product(self) -> Self::Element
where
Self::Element: Mul<Output = <Self as Array>::Element>;
} }
/// Element-wise arithmetic operations. These are supplied for pragmatic /// Element-wise arithmetic operations. These are supplied for pragmatic
@ -156,7 +161,8 @@ pub trait ElementWise<Rhs = Self> {
/// let upscaled_translation = translation * scale_factor; /// let upscaled_translation = translation * scale_factor;
/// let downscaled_translation = translation / scale_factor; /// let downscaled_translation = translation / scale_factor;
/// ``` /// ```
pub trait VectorSpace: Copy + Clone where pub trait VectorSpace: Copy + Clone
where
Self: Zero, Self: Zero,
Self: Add<Self, Output = Self>, Self: Add<Self, Output = Self>,
@ -199,7 +205,8 @@ pub trait MetricSpace: Sized {
/// finding the magnitude of a vector or normalizing it. /// finding the magnitude of a vector or normalizing it.
/// ///
/// Examples include vectors and quaternions. /// Examples include vectors and quaternions.
pub trait InnerSpace: VectorSpace where pub trait InnerSpace: VectorSpace
where
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
<Self as VectorSpace>::Scalar: BaseFloat, <Self as VectorSpace>::Scalar: BaseFloat,
Self: MetricSpace<Metric = <Self as VectorSpace>::Scalar>, Self: MetricSpace<Metric = <Self as VectorSpace>::Scalar>,
@ -310,7 +317,8 @@ pub trait InnerSpace: VectorSpace where
/// - [CGAL 4.7 - 2D and 3D Linear Geometry Kernel: 3.1 Points and Vectors](http://doc.cgal.org/latest/Kernel_23/index.html#Kernel_23PointsandVectors) /// - [CGAL 4.7 - 2D and 3D Linear Geometry Kernel: 3.1 Points and Vectors](http://doc.cgal.org/latest/Kernel_23/index.html#Kernel_23PointsandVectors)
/// - [What is the difference between a point and a vector](http://math.stackexchange.com/q/645827) /// - [What is the difference between a point and a vector](http://math.stackexchange.com/q/645827)
/// ///
pub trait EuclideanSpace: Copy + Clone where pub trait EuclideanSpace: Copy + Clone
where
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
Self: Array<Element = <Self as EuclideanSpace>::Scalar>, Self: Array<Element = <Self as EuclideanSpace>::Scalar>,
@ -378,10 +386,9 @@ pub trait EuclideanSpace: Copy + Clone where
/// ``` /// ```
#[inline] #[inline]
fn centroid(points: &[Self]) -> Self { fn centroid(points: &[Self]) -> Self {
let total_displacement = let total_displacement = points
points.iter().fold(Self::Diff::zero(), |acc, p| { .iter()
acc + p.to_vec() .fold(Self::Diff::zero(), |acc, p| acc + p.to_vec());
});
Self::from_vec(total_displacement / cast(points.len()).unwrap()) Self::from_vec(total_displacement / cast(points.len()).unwrap())
} }
@ -411,7 +418,8 @@ pub trait EuclideanSpace: Copy + Clone where
/// trait. This is due to the complexities of implementing these operators with /// trait. This is due to the complexities of implementing these operators with
/// Rust's current type system. For the multiplication of square matrices, /// Rust's current type system. For the multiplication of square matrices,
/// see `SquareMatrix`. /// see `SquareMatrix`.
pub trait Matrix: VectorSpace where pub trait Matrix: VectorSpace
where
Self::Scalar: BaseFloat, Self::Scalar: BaseFloat,
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
@ -463,7 +471,8 @@ pub trait Matrix: VectorSpace where
} }
/// A column-major major matrix where the rows and column vectors are of the same dimensions. /// A column-major major matrix where the rows and column vectors are of the same dimensions.
pub trait SquareMatrix where pub trait SquareMatrix
where
Self::Scalar: BaseFloat, Self::Scalar: BaseFloat,
Self: One, Self: One,
@ -514,7 +523,9 @@ pub trait SquareMatrix where
/// Return the trace of this matrix. That is, the sum of the diagonal. /// Return the trace of this matrix. That is, the sum of the diagonal.
#[inline] #[inline]
fn trace(&self) -> Self::Scalar { self.diagonal().sum() } fn trace(&self) -> Self::Scalar {
self.diagonal().sum()
}
/// Invert this matrix, returning a new matrix. `m.mul_m(m.invert())` is /// Invert this matrix, returning a new matrix. `m.mul_m(m.invert())` is
/// the identity matrix. Returns `None` if this matrix is not invertible /// the identity matrix. Returns `None` if this matrix is not invertible
@ -523,12 +534,16 @@ pub trait SquareMatrix where
/// Test if this matrix is invertible. /// Test if this matrix is invertible.
#[inline] #[inline]
fn is_invertible(&self) -> bool { ulps_ne!(self.determinant(), &Self::Scalar::zero()) } fn is_invertible(&self) -> bool {
ulps_ne!(self.determinant(), &Self::Scalar::zero())
}
/// Test if this matrix is the identity matrix. That is, it is diagonal /// Test if this matrix is the identity matrix. That is, it is diagonal
/// and every element in the diagonal is one. /// and every element in the diagonal is one.
#[inline] #[inline]
fn is_identity(&self) -> bool { ulps_eq!(self, &Self::identity()) } fn is_identity(&self) -> bool {
ulps_eq!(self, &Self::identity())
}
/// Test if this is a diagonal matrix. That is, every element outside of /// Test if this is a diagonal matrix. That is, every element outside of
/// the diagonal is 0. /// the diagonal is 0.
@ -545,7 +560,8 @@ pub trait SquareMatrix where
/// clear when semantic violations have occured - for example, adding degrees to /// clear when semantic violations have occured - for example, adding degrees to
/// radians, or adding a number to an angle. /// radians, or adding a number to an angle.
/// ///
pub trait Angle where pub trait Angle
where
Self: Copy + Clone, Self: Copy + Clone,
Self: PartialEq + cmp::PartialOrd, Self: PartialEq + cmp::PartialOrd,
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092 // FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
@ -569,7 +585,11 @@ pub trait Angle where
#[inline] #[inline]
fn normalize(self) -> Self { fn normalize(self) -> Self {
let rem = self % Self::full_turn(); let rem = self % Self::full_turn();
if rem < Self::zero() { rem + Self::full_turn() } else { rem } if rem < Self::zero() {
rem + Self::full_turn()
} else {
rem
}
} }
/// Return the angle rotated by half a turn. /// Return the angle rotated by half a turn.

View file

@ -39,7 +39,8 @@ pub trait Transform<P: EuclideanSpace>: Sized {
/// Inverse transform a vector using this transform /// Inverse transform a vector using this transform
fn inverse_transform_vector(&self, vec: P::Diff) -> Option<P::Diff> { fn inverse_transform_vector(&self, vec: P::Diff) -> Option<P::Diff> {
self.inverse_transform().and_then(|inverse| Some(inverse.transform_vector(vec))) self.inverse_transform()
.and_then(|inverse| Some(inverse.transform_vector(vec)))
} }
/// Transform a point using this transform. /// Transform a point using this transform.
@ -69,9 +70,10 @@ pub struct Decomposed<V: VectorSpace, R> {
} }
impl<P: EuclideanSpace, R: Rotation<P>> Transform<P> for Decomposed<P::Diff, R> impl<P: EuclideanSpace, R: Rotation<P>> Transform<P> for Decomposed<P::Diff, R>
where P::Scalar: BaseFloat, where
P::Scalar: BaseFloat,
// FIXME: Investigate why this is needed! // FIXME: Investigate why this is needed!
P::Diff: VectorSpace P::Diff: VectorSpace,
{ {
#[inline] #[inline]
fn one() -> Decomposed<P::Diff, R> { fn one() -> Decomposed<P::Diff, R> {
@ -162,9 +164,10 @@ impl<S: BaseFloat, R: Rotation2<S>> Transform2<S> for Decomposed<Vector2<S>, R>
impl<S: BaseFloat, R: Rotation3<S>> Transform3<S> for Decomposed<Vector3<S>, R> {} impl<S: BaseFloat, R: Rotation3<S>> Transform3<S> for Decomposed<Vector3<S>, R> {}
impl<S: VectorSpace, R, E: BaseFloat> ApproxEq for Decomposed<S, R> impl<S: VectorSpace, R, E: BaseFloat> ApproxEq for Decomposed<S, R>
where S: ApproxEq<Epsilon = E>, where
S: ApproxEq<Epsilon = E>,
S::Scalar: ApproxEq<Epsilon = E>, S::Scalar: ApproxEq<Epsilon = E>,
R: ApproxEq<Epsilon = E> R: ApproxEq<Epsilon = E>,
{ {
type Epsilon = E; type Epsilon = E;
@ -185,16 +188,16 @@ impl<S: VectorSpace, R, E: BaseFloat> ApproxEq for Decomposed<S, R>
#[inline] #[inline]
fn relative_eq(&self, other: &Self, epsilon: E, max_relative: E) -> bool { fn relative_eq(&self, other: &Self, epsilon: E, max_relative: E) -> bool {
S::Scalar::relative_eq(&self.scale, &other.scale, epsilon, max_relative) && S::Scalar::relative_eq(&self.scale, &other.scale, epsilon, max_relative)
R::relative_eq(&self.rot, &other.rot, epsilon, max_relative) && && R::relative_eq(&self.rot, &other.rot, epsilon, max_relative)
S::relative_eq(&self.disp, &other.disp, epsilon, max_relative) && S::relative_eq(&self.disp, &other.disp, epsilon, max_relative)
} }
#[inline] #[inline]
fn ulps_eq(&self, other: &Self, epsilon: E, max_ulps: u32) -> bool { fn ulps_eq(&self, other: &Self, epsilon: E, max_ulps: u32) -> bool {
S::Scalar::ulps_eq(&self.scale, &other.scale, epsilon, max_ulps) && S::Scalar::ulps_eq(&self.scale, &other.scale, epsilon, max_ulps)
R::ulps_eq(&self.rot, &other.rot, epsilon, max_ulps) && && R::ulps_eq(&self.rot, &other.rot, epsilon, max_ulps)
S::ulps_eq(&self.disp, &other.disp, epsilon, max_ulps) && S::ulps_eq(&self.disp, &other.disp, epsilon, max_ulps)
} }
} }
@ -207,12 +210,14 @@ mod serde_ser {
use serde::ser::SerializeStruct; use serde::ser::SerializeStruct;
impl<V, R> Serialize for Decomposed<V, R> impl<V, R> Serialize for Decomposed<V, R>
where V: Serialize + VectorSpace, where
V: Serialize + VectorSpace,
V::Scalar: Serialize, V::Scalar: Serialize,
R: Serialize R: Serialize,
{ {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: serde::Serializer where
S: serde::Serializer,
{ {
let mut struc = serializer.serialize_struct("Decomposed", 3)?; let mut struc = serializer.serialize_struct("Decomposed", 3)?;
struc.serialize_field("scale", &self.scale)?; struc.serialize_field("scale", &self.scale)?;
@ -240,7 +245,8 @@ mod serde_de {
impl<'a> Deserialize<'a> for DecomposedField { impl<'a> Deserialize<'a> for DecomposedField {
fn deserialize<D>(deserializer: D) -> Result<DecomposedField, D::Error> fn deserialize<D>(deserializer: D) -> Result<DecomposedField, D::Error>
where D: serde::Deserializer<'a> where
D: serde::Deserializer<'a>,
{ {
struct DecomposedFieldVisitor; struct DecomposedFieldVisitor;
@ -252,7 +258,8 @@ mod serde_de {
} }
fn visit_str<E>(self, value: &str) -> Result<DecomposedField, E> fn visit_str<E>(self, value: &str) -> Result<DecomposedField, E>
where E: serde::de::Error where
E: serde::de::Error,
{ {
match value { match value {
"scale" => Ok(DecomposedField::Scale), "scale" => Ok(DecomposedField::Scale),
@ -268,12 +275,14 @@ mod serde_de {
} }
impl<'a, S: VectorSpace, R> Deserialize<'a> for Decomposed<S, R> impl<'a, S: VectorSpace, R> Deserialize<'a> for Decomposed<S, R>
where S: Deserialize<'a>, where
S: Deserialize<'a>,
S::Scalar: Deserialize<'a>, S::Scalar: Deserialize<'a>,
R: Deserialize<'a> R: Deserialize<'a>,
{ {
fn deserialize<D>(deserializer: D) -> Result<Decomposed<S, R>, D::Error> fn deserialize<D>(deserializer: D) -> Result<Decomposed<S, R>, D::Error>
where D: serde::de::Deserializer<'a> where
D: serde::de::Deserializer<'a>,
{ {
const FIELDS: &'static [&'static str] = &["scale", "rot", "disp"]; const FIELDS: &'static [&'static str] = &["scale", "rot", "disp"];
deserializer.deserialize_struct("Decomposed", FIELDS, DecomposedVisitor(PhantomData)) deserializer.deserialize_struct("Decomposed", FIELDS, DecomposedVisitor(PhantomData))
@ -283,9 +292,10 @@ mod serde_de {
struct DecomposedVisitor<S: VectorSpace, R>(PhantomData<(S, R)>); struct DecomposedVisitor<S: VectorSpace, R>(PhantomData<(S, R)>);
impl<'a, S: VectorSpace, R> serde::de::Visitor<'a> for DecomposedVisitor<S, R> impl<'a, S: VectorSpace, R> serde::de::Visitor<'a> for DecomposedVisitor<S, R>
where S: Deserialize<'a>, where
S: Deserialize<'a>,
S::Scalar: Deserialize<'a>, S::Scalar: Deserialize<'a>,
R: Deserialize<'a> R: Deserialize<'a>,
{ {
type Value = Decomposed<S, R>; type Value = Decomposed<S, R>;
@ -294,7 +304,8 @@ mod serde_de {
} }
fn visit_map<V>(self, mut visitor: V) -> Result<Decomposed<S, R>, V::Error> fn visit_map<V>(self, mut visitor: V) -> Result<Decomposed<S, R>, V::Error>
where V: serde::de::MapAccess<'a> where
V: serde::de::MapAccess<'a>,
{ {
let mut scale = None; let mut scale = None;
let mut rot = None; let mut rot = None;

View file

@ -14,7 +14,7 @@
// limitations under the License. // limitations under the License.
use rand::{Rand, Rng}; use rand::{Rand, Rng};
use num_traits::{NumCast, Bounded}; use num_traits::{Bounded, NumCast};
use std::fmt; use std::fmt;
use std::iter; use std::iter;
use std::mem; use std::mem;
@ -24,7 +24,7 @@ use structure::*;
use angle::Rad; use angle::Rad;
use approx::ApproxEq; use approx::ApproxEq;
use num::{BaseNum, BaseFloat}; use num::{BaseFloat, BaseNum};
#[cfg(feature = "simd")] #[cfg(feature = "simd")]
use simd::f32x4 as Simdf32x4; use simd::f32x4 as Simdf32x4;
@ -660,9 +660,11 @@ impl<S: BaseNum> Vector3<S> {
/// Returns the cross product of the vector and `other`. /// Returns the cross product of the vector and `other`.
#[inline] #[inline]
pub fn cross(self, other: Vector3<S>) -> Vector3<S> { pub fn cross(self, other: Vector3<S>) -> Vector3<S> {
Vector3::new((self.y * other.z) - (self.z * other.y), Vector3::new(
(self.y * other.z) - (self.z * other.y),
(self.z * other.x) - (self.x * other.z), (self.z * other.x) - (self.x * other.z),
(self.x * other.y) - (self.y * other.x)) (self.x * other.y) - (self.y * other.x),
)
} }
/// Create a `Vector4`, using the `x`, `y` and `z` values from this vector, and the /// Create a `Vector4`, using the `x`, `y` and `z` values from this vector, and the
@ -730,7 +732,8 @@ impl<S: BaseNum> Vector4<S> {
/// Dot product of two vectors. /// Dot product of two vectors.
#[inline] #[inline]
pub fn dot<V: InnerSpace>(a: V, b: V) -> V::Scalar pub fn dot<V: InnerSpace>(a: V, b: V) -> V::Scalar
where V::Scalar: BaseFloat where
V::Scalar: BaseFloat,
{ {
V::dot(a, b) V::dot(a, b)
} }
@ -840,8 +843,6 @@ impl Vector4<f32> {
} }
} }
#[cfg(feature = "simd")] #[cfg(feature = "simd")]
impl Into<Simdf32x4> for Vector4<f32> { impl Into<Simdf32x4> for Vector4<f32> {
#[inline] #[inline]
@ -887,8 +888,6 @@ impl_operator_simd!{@rs
} }
} }
#[cfg(feature = "simd")] #[cfg(feature = "simd")]
impl_operator_simd!{ impl_operator_simd!{
[Simdf32x4]; Neg for Vector4<f32> { [Simdf32x4]; Neg for Vector4<f32> {
@ -938,27 +937,46 @@ impl DivAssign<f32> for Vector4<f32> {
#[cfg(feature = "simd")] #[cfg(feature = "simd")]
impl ElementWise for Vector4<f32> { impl ElementWise for Vector4<f32> {
#[inline] fn add_element_wise(self, rhs: Vector4<f32>) -> Vector4<f32> { self + rhs } #[inline]
#[inline] fn sub_element_wise(self, rhs: Vector4<f32>) -> Vector4<f32> { self - rhs } fn add_element_wise(self, rhs: Vector4<f32>) -> Vector4<f32> {
#[inline] fn mul_element_wise(self, rhs: Vector4<f32>) -> Vector4<f32> { self + rhs
}
#[inline]
fn sub_element_wise(self, rhs: Vector4<f32>) -> Vector4<f32> {
self - rhs
}
#[inline]
fn mul_element_wise(self, rhs: Vector4<f32>) -> Vector4<f32> {
let s: Simdf32x4 = self.into(); let s: Simdf32x4 = self.into();
let rhs: Simdf32x4 = rhs.into(); let rhs: Simdf32x4 = rhs.into();
(s * rhs).into() (s * rhs).into()
} }
#[inline] fn div_element_wise(self, rhs: Vector4<f32>) -> Vector4<f32> { #[inline]
fn div_element_wise(self, rhs: Vector4<f32>) -> Vector4<f32> {
let s: Simdf32x4 = self.into(); let s: Simdf32x4 = self.into();
let rhs: Simdf32x4 = rhs.into(); let rhs: Simdf32x4 = rhs.into();
(s / rhs).into() (s / rhs).into()
} }
#[inline] fn add_assign_element_wise(&mut self, rhs: Vector4<f32>) { (*self) += rhs; } #[inline]
#[inline] fn sub_assign_element_wise(&mut self, rhs: Vector4<f32>) { (*self) -= rhs; } fn add_assign_element_wise(&mut self, rhs: Vector4<f32>) {
#[inline] fn mul_assign_element_wise(&mut self, rhs: Vector4<f32>) { (*self) += rhs;
}
#[inline]
fn sub_assign_element_wise(&mut self, rhs: Vector4<f32>) {
(*self) -= rhs;
}
#[inline]
fn mul_assign_element_wise(&mut self, rhs: Vector4<f32>) {
let s: Simdf32x4 = (*self).into(); let s: Simdf32x4 = (*self).into();
let rhs: Simdf32x4 = rhs.into(); let rhs: Simdf32x4 = rhs.into();
*self = (s * rhs).into(); *self = (s * rhs).into();
} }
#[inline] fn div_assign_element_wise(&mut self, rhs: Vector4<f32>) {
#[inline]
fn div_assign_element_wise(&mut self, rhs: Vector4<f32>) {
let s: Simdf32x4 = (*self).into(); let s: Simdf32x4 = (*self).into();
let rhs: Simdf32x4 = rhs.into(); let rhs: Simdf32x4 = rhs.into();
*self = (s * rhs).into(); *self = (s * rhs).into();
@ -967,31 +985,53 @@ impl ElementWise for Vector4<f32> {
#[cfg(feature = "simd")] #[cfg(feature = "simd")]
impl ElementWise<f32> for Vector4<f32> { impl ElementWise<f32> for Vector4<f32> {
#[inline] fn add_element_wise(self, rhs: f32) -> Vector4<f32> { #[inline]
fn add_element_wise(self, rhs: f32) -> Vector4<f32> {
let s: Simdf32x4 = self.into(); let s: Simdf32x4 = self.into();
let rhs = Simdf32x4::splat(rhs); let rhs = Simdf32x4::splat(rhs);
(s + rhs).into() (s + rhs).into()
} }
#[inline] fn sub_element_wise(self, rhs: f32) -> Vector4<f32> {
#[inline]
fn sub_element_wise(self, rhs: f32) -> Vector4<f32> {
let s: Simdf32x4 = self.into(); let s: Simdf32x4 = self.into();
let rhs = Simdf32x4::splat(rhs); let rhs = Simdf32x4::splat(rhs);
(s - rhs).into() (s - rhs).into()
} }
#[inline] fn mul_element_wise(self, rhs: f32) -> Vector4<f32> { self * rhs }
#[inline] fn div_element_wise(self, rhs: f32) -> Vector4<f32> { self / rhs }
#[inline] fn add_assign_element_wise(&mut self, rhs: f32) { #[inline]
fn mul_element_wise(self, rhs: f32) -> Vector4<f32> {
self * rhs
}
#[inline]
fn div_element_wise(self, rhs: f32) -> Vector4<f32> {
self / rhs
}
#[inline]
fn add_assign_element_wise(&mut self, rhs: f32) {
let s: Simdf32x4 = (*self).into(); let s: Simdf32x4 = (*self).into();
let rhs = Simdf32x4::splat(rhs); let rhs = Simdf32x4::splat(rhs);
*self = (s + rhs).into(); *self = (s + rhs).into();
} }
#[inline] fn sub_assign_element_wise(&mut self, rhs: f32) {
#[inline]
fn sub_assign_element_wise(&mut self, rhs: f32) {
let s: Simdf32x4 = (*self).into(); let s: Simdf32x4 = (*self).into();
let rhs = Simdf32x4::splat(rhs); let rhs = Simdf32x4::splat(rhs);
*self = (s - rhs).into(); *self = (s - rhs).into();
} }
#[inline] fn mul_assign_element_wise(&mut self, rhs: f32) { (*self) *= rhs; }
#[inline] fn div_assign_element_wise(&mut self, rhs: f32) { (*self) /= rhs; } #[inline]
fn mul_assign_element_wise(&mut self, rhs: f32) {
(*self) *= rhs;
}
#[inline]
fn div_assign_element_wise(&mut self, rhs: f32) {
(*self) /= rhs;
}
} }
#[cfg(feature = "simd")] #[cfg(feature = "simd")]
@ -1170,7 +1210,6 @@ impl_mint_conversions!(Vector3 { x, y, z }, Vector3);
#[cfg(feature = "mint")] #[cfg(feature = "mint")]
impl_mint_conversions!(Vector4 { x, y, z, w }, Vector4); impl_mint_conversions!(Vector4 { x, y, z, w }, Vector4);
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
mod vector2 { mod vector2 {

View file

@ -17,7 +17,7 @@
extern crate approx; extern crate approx;
extern crate cgmath; extern crate cgmath;
use cgmath::{Rad, Deg}; use cgmath::{Deg, Rad};
#[test] #[test]
fn test_conv() { fn test_conv() {
@ -43,8 +43,14 @@ mod rad {
#[test] #[test]
fn test_iter_sum() { fn test_iter_sum() {
assert_eq!(Rad(2.0) + Rad(3.0) + Rad(4.0), [Rad(2.0), Rad(3.0), Rad(4.0)].iter().sum()); assert_eq!(
assert_eq!(Rad(2.0) + Rad(3.0) + Rad(4.0), [Rad(2.0), Rad(3.0), Rad(4.0)].iter().cloned().sum()); Rad(2.0) + Rad(3.0) + Rad(4.0),
[Rad(2.0), Rad(3.0), Rad(4.0)].iter().sum()
);
assert_eq!(
Rad(2.0) + Rad(3.0) + Rad(4.0),
[Rad(2.0), Rad(3.0), Rad(4.0)].iter().cloned().sum()
);
} }
} }
@ -53,7 +59,13 @@ mod deg {
#[test] #[test]
fn test_iter_sum() { fn test_iter_sum() {
assert_eq!(Deg(2.0) + Deg(3.0) + Deg(4.0), [Deg(2.0), Deg(3.0), Deg(4.0)].iter().sum()); assert_eq!(
assert_eq!(Deg(2.0) + Deg(3.0) + Deg(4.0), [Deg(2.0), Deg(3.0), Deg(4.0)].iter().cloned().sum()); Deg(2.0) + Deg(3.0) + Deg(4.0),
[Deg(2.0), Deg(3.0), Deg(4.0)].iter().sum()
);
assert_eq!(
Deg(2.0) + Deg(3.0) + Deg(4.0),
[Deg(2.0), Deg(3.0), Deg(4.0)].iter().cloned().sum()
);
} }
} }

View file

@ -78,6 +78,12 @@ fn test_rem() {
#[test] #[test]
fn test_cast() { fn test_cast() {
assert_ulps_eq!(Point1::new(0.9f64).cast().unwrap(), Point1::new(0.9f32)); assert_ulps_eq!(Point1::new(0.9f64).cast().unwrap(), Point1::new(0.9f32));
assert_ulps_eq!(Point2::new(0.9f64, 1.5).cast().unwrap(), Point2::new(0.9f32, 1.5)); assert_ulps_eq!(
assert_ulps_eq!(Point3::new(1.0f64, 2.4, -3.13).cast().unwrap(), Point3::new(1.0f32, 2.4, -3.13)); Point2::new(0.9f64, 1.5).cast().unwrap(),
Point2::new(0.9f32, 1.5)
);
assert_ulps_eq!(
Point3::new(1.0f64, 2.4, -3.13).cast().unwrap(),
Point3::new(1.0f32, 2.4, -3.13)
);
} }

View file

@ -15,7 +15,7 @@
extern crate cgmath; extern crate cgmath;
use cgmath::{Vector4, ortho, Matrix4}; use cgmath::{ortho, Matrix4, Vector4};
#[test] #[test]
fn test_ortho_scale() { fn test_ortho_scale() {
@ -36,7 +36,6 @@ fn test_ortho_scale() {
assert_eq!(orig, Vector4::new(0f32, 0., 0., 1.)); assert_eq!(orig, Vector4::new(0f32, 0., 0., 1.));
assert_eq!(far, Vector4::new(1f32, 1., -1., 1.)); assert_eq!(far, Vector4::new(1f32, 1., -1., 1.));
let o: Matrix4<f32> = ortho(-2., 2., -2., 2., -2., 2.); let o: Matrix4<f32> = ortho(-2., 2., -2., 2., -2., 2.);
let near = o * vec_near; let near = o * vec_near;
let orig = o * vec_orig; let orig = o * vec_orig;

View file

@ -44,19 +44,45 @@ mod operators {
#[test] #[test]
fn test_mul() { fn test_mul() {
impl_test_mul!(2.0f32, Quaternion::from(Euler { x: Rad(1f32), y: Rad(1f32), z: Rad(1f32) })); impl_test_mul!(
2.0f32,
Quaternion::from(Euler {
x: Rad(1f32),
y: Rad(1f32),
z: Rad(1f32),
})
);
} }
#[test] #[test]
fn test_div() { fn test_div() {
impl_test_div!(2.0f32, Quaternion::from(Euler { x: Rad(1f32), y: Rad(1f32), z: Rad(1f32) })); impl_test_div!(
2.0f32,
Quaternion::from(Euler {
x: Rad(1f32),
y: Rad(1f32),
z: Rad(1f32),
})
);
} }
#[test] #[test]
fn test_iter_sum() { fn test_iter_sum() {
let q1 = Quaternion::from(Euler { x: Rad(2f32), y: Rad(1f32), z: Rad(1f32) }); let q1 = Quaternion::from(Euler {
let q2 = Quaternion::from(Euler { x: Rad(1f32), y: Rad(2f32), z: Rad(1f32) }); x: Rad(2f32),
let q3 = Quaternion::from(Euler { x: Rad(1f32), y: Rad(1f32), z: Rad(2f32) }); y: Rad(1f32),
z: Rad(1f32),
});
let q2 = Quaternion::from(Euler {
x: Rad(1f32),
y: Rad(2f32),
z: Rad(1f32),
});
let q3 = Quaternion::from(Euler {
x: Rad(1f32),
y: Rad(1f32),
z: Rad(2f32),
});
assert_eq!(q1 + q2 + q3, [q1, q2, q3].iter().sum()); assert_eq!(q1 + q2 + q3, [q1, q2, q3].iter().sum());
assert_eq!(q1 + q2 + q3, [q1, q2, q3].iter().cloned().sum()); assert_eq!(q1 + q2 + q3, [q1, q2, q3].iter().cloned().sum());
@ -64,9 +90,21 @@ mod operators {
#[test] #[test]
fn test_iter_product() { fn test_iter_product() {
let q1 = Quaternion::from(Euler { x: Rad(2f32), y: Rad(1f32), z: Rad(1f32) }); let q1 = Quaternion::from(Euler {
let q2 = Quaternion::from(Euler { x: Rad(1f32), y: Rad(2f32), z: Rad(1f32) }); x: Rad(2f32),
let q3 = Quaternion::from(Euler { x: Rad(1f32), y: Rad(1f32), z: Rad(2f32) }); y: Rad(1f32),
z: Rad(1f32),
});
let q2 = Quaternion::from(Euler {
x: Rad(1f32),
y: Rad(2f32),
z: Rad(1f32),
});
let q3 = Quaternion::from(Euler {
x: Rad(1f32),
y: Rad(1f32),
z: Rad(2f32),
});
assert_eq!(q1 * q2 * q3, [q1, q2, q3].iter().product()); assert_eq!(q1 * q2 * q3, [q1, q2, q3].iter().product());
assert_eq!(q1 * q2 * q3, [q1, q2, q3].iter().cloned().product()); assert_eq!(q1 * q2 * q3, [q1, q2, q3].iter().cloned().product());
@ -79,22 +117,103 @@ mod to_from_euler {
use cgmath::*; use cgmath::*;
fn check_euler(rotation: Euler<Rad<f32>>) { fn check_euler(rotation: Euler<Rad<f32>>) {
assert_relative_eq!(Euler::from(Quaternion::from(rotation)), rotation, epsilon = 0.001); assert_relative_eq!(
Euler::from(Quaternion::from(rotation)),
rotation,
epsilon = 0.001
);
} }
const HPI: f32 = f32::consts::FRAC_PI_2; const HPI: f32 = f32::consts::FRAC_PI_2;
#[test] fn test_zero() { check_euler(Euler { x: Rad( 0f32), y: Rad( 0f32), z: Rad( 0f32) }); } #[test]
#[test] fn test_yaw_pos_1() { check_euler(Euler { x: Rad( 0f32), y: Rad( 1f32), z: Rad( 0f32) }); } fn test_zero() {
#[test] fn test_yaw_neg_1() { check_euler(Euler { x: Rad( 0f32), y: Rad(-1f32), z: Rad( 0f32) }); } check_euler(Euler {
#[test] fn test_pitch_pos_1() { check_euler(Euler { x: Rad( 1f32), y: Rad( 0f32), z: Rad( 0f32) }); } x: Rad(0f32),
#[test] fn test_pitch_neg_1() { check_euler(Euler { x: Rad(-1f32), y: Rad( 0f32), z: Rad( 0f32) }); } y: Rad(0f32),
#[test] fn test_roll_pos_1() { check_euler(Euler { x: Rad( 0f32), y: Rad( 0f32), z: Rad( 1f32) }); } z: Rad(0f32),
#[test] fn test_roll_neg_1() { check_euler(Euler { x: Rad( 0f32), y: Rad( 0f32), z: Rad(-1f32) }); } });
#[test] fn test_pitch_yaw_roll_pos_1() { check_euler(Euler { x: Rad( 1f32), y: Rad( 1f32), z: Rad( 1f32) }); } }
#[test] fn test_pitch_yaw_roll_neg_1() { check_euler(Euler { x: Rad(-1f32), y: Rad(-1f32), z: Rad(-1f32) }); } #[test]
#[test] fn test_pitch_yaw_roll_pos_hp() { check_euler(Euler { x: Rad( 0f32), y: Rad( HPI), z: Rad( 1f32) }); } fn test_yaw_pos_1() {
#[test] fn test_pitch_yaw_roll_neg_hp() { check_euler(Euler { x: Rad( 0f32), y: Rad( -HPI), z: Rad( 1f32) }); } check_euler(Euler {
x: Rad(0f32),
y: Rad(1f32),
z: Rad(0f32),
});
}
#[test]
fn test_yaw_neg_1() {
check_euler(Euler {
x: Rad(0f32),
y: Rad(-1f32),
z: Rad(0f32),
});
}
#[test]
fn test_pitch_pos_1() {
check_euler(Euler {
x: Rad(1f32),
y: Rad(0f32),
z: Rad(0f32),
});
}
#[test]
fn test_pitch_neg_1() {
check_euler(Euler {
x: Rad(-1f32),
y: Rad(0f32),
z: Rad(0f32),
});
}
#[test]
fn test_roll_pos_1() {
check_euler(Euler {
x: Rad(0f32),
y: Rad(0f32),
z: Rad(1f32),
});
}
#[test]
fn test_roll_neg_1() {
check_euler(Euler {
x: Rad(0f32),
y: Rad(0f32),
z: Rad(-1f32),
});
}
#[test]
fn test_pitch_yaw_roll_pos_1() {
check_euler(Euler {
x: Rad(1f32),
y: Rad(1f32),
z: Rad(1f32),
});
}
#[test]
fn test_pitch_yaw_roll_neg_1() {
check_euler(Euler {
x: Rad(-1f32),
y: Rad(-1f32),
z: Rad(-1f32),
});
}
#[test]
fn test_pitch_yaw_roll_pos_hp() {
check_euler(Euler {
x: Rad(0f32),
y: Rad(HPI),
z: Rad(1f32),
});
}
#[test]
fn test_pitch_yaw_roll_neg_hp() {
check_euler(Euler {
x: Rad(0f32),
y: Rad(-HPI),
z: Rad(1f32),
});
}
} }
mod from { mod from {
@ -206,7 +325,6 @@ mod rotate_from_euler {
assert_ulps_eq!(vec3(0.0, -1.0, 0.0), rot * vec); assert_ulps_eq!(vec3(0.0, -1.0, 0.0), rot * vec);
} }
// tests that the Y rotation is done after the X // tests that the Y rotation is done after the X
#[test] #[test]
fn test_x_then_y() { fn test_x_then_y() {
@ -258,7 +376,10 @@ mod rotate_from_axis_angle {
let vec = vec3(0.0, 0.0, 1.0); let vec = vec3(0.0, 0.0, 1.0);
let rot = Quaternion::from_axis_angle(vec3(1.0, 1.0, 0.0).normalize(), Deg(90.0)); let rot = Quaternion::from_axis_angle(vec3(1.0, 1.0, 0.0).normalize(), Deg(90.0));
assert_ulps_eq!(vec3(2.0f32.sqrt() / 2.0, -2.0f32.sqrt() / 2.0, 0.0), rot * vec); assert_ulps_eq!(
vec3(2.0f32.sqrt() / 2.0, -2.0f32.sqrt() / 2.0, 0.0),
rot * vec
);
} }
#[test] #[test]
@ -266,7 +387,10 @@ mod rotate_from_axis_angle {
let vec = vec3(1.0, 0.0, 0.0); let vec = vec3(1.0, 0.0, 0.0);
let rot = Quaternion::from_axis_angle(vec3(0.0, 1.0, 1.0).normalize(), Deg(-90.0)); let rot = Quaternion::from_axis_angle(vec3(0.0, 1.0, 1.0).normalize(), Deg(-90.0));
assert_ulps_eq!(vec3(0.0, -2.0f32.sqrt() / 2.0, 2.0f32.sqrt() / 2.0), rot * vec); assert_ulps_eq!(
vec3(0.0, -2.0f32.sqrt() / 2.0, 2.0f32.sqrt() / 2.0),
rot * vec
);
} }
#[test] #[test]
@ -274,7 +398,10 @@ mod rotate_from_axis_angle {
let vec = vec3(0.0, 1.0, 0.0); let vec = vec3(0.0, 1.0, 0.0);
let rot = Quaternion::from_axis_angle(vec3(1.0, 0.0, 1.0).normalize(), Deg(90.0)); let rot = Quaternion::from_axis_angle(vec3(1.0, 0.0, 1.0).normalize(), Deg(90.0));
assert_ulps_eq!(vec3(-2.0f32.sqrt() / 2.0, 0.0, 2.0f32.sqrt() / 2.0), rot * vec); assert_ulps_eq!(
vec3(-2.0f32.sqrt() / 2.0, 0.0, 2.0f32.sqrt() / 2.0),
rot * vec
);
} }
} }
@ -337,7 +464,9 @@ mod cast {
#[test] #[test]
fn test_cast() { fn test_cast() {
assert_ulps_eq!(Quaternion::new(0.9f64, 1.5, 2.4, 7.6).cast().unwrap(), assert_ulps_eq!(
Quaternion::new(0.9f32, 1.5, 2.4, 7.6)); Quaternion::new(0.9f64, 1.5, 2.4, 7.6).cast().unwrap(),
Quaternion::new(0.9f32, 1.5, 2.4, 7.6)
);
} }
} }

View file

@ -30,7 +30,8 @@ fn test_invert() {
rot: Quaternion::new(0.5f64, 0.5, 0.5, 0.5), rot: Quaternion::new(0.5f64, 0.5, 0.5, 0.5),
disp: Vector3::new(6.0f64, -7.0, 8.0), disp: Vector3::new(6.0f64, -7.0, 8.0),
}; };
let ti = t.inverse_transform().expect("Expected successful inversion"); let ti = t.inverse_transform()
.expect("Expected successful inversion");
let vt = t.transform_vector(v); let vt = t.transform_vector(v);
assert_ulps_eq!(&v, &ti.transform_vector(vt)); assert_ulps_eq!(&v, &ti.transform_vector(vt));
} }
@ -43,7 +44,8 @@ fn test_inverse_vector() {
rot: Quaternion::new(0.5f64, 0.5, 0.5, 0.5), rot: Quaternion::new(0.5f64, 0.5, 0.5, 0.5),
disp: Vector3::new(6.0f64, -7.0, 8.0), disp: Vector3::new(6.0f64, -7.0, 8.0),
}; };
let vt = t.inverse_transform_vector(v).expect("Expected successful inversion"); let vt = t.inverse_transform_vector(v)
.expect("Expected successful inversion");
assert_ulps_eq!(v, t.transform_vector(vt)); assert_ulps_eq!(v, t.transform_vector(vt));
} }
@ -68,7 +70,8 @@ fn test_serialize() {
}; };
let serialized = serde_json::to_string(&t).unwrap(); let serialized = serde_json::to_string(&t).unwrap();
let deserialized: Decomposed<Vector3<f64>, Quaternion<f64>> = serde_json::from_str(&serialized).unwrap(); let deserialized: Decomposed<Vector3<f64>, Quaternion<f64>> =
serde_json::from_str(&serialized).unwrap();
assert_ulps_eq!(&t, &deserialized); assert_ulps_eq!(&t, &deserialized);
} }

View file

@ -25,14 +25,26 @@ use std::iter;
fn test_constructor() { fn test_constructor() {
assert_eq!(vec2(1f32, 2f32), Vector2::new(1f32, 2f32)); assert_eq!(vec2(1f32, 2f32), Vector2::new(1f32, 2f32));
assert_eq!(vec3(1f64, 2f64, 3f64), Vector3::new(1f64, 2f64, 3f64)); assert_eq!(vec3(1f64, 2f64, 3f64), Vector3::new(1f64, 2f64, 3f64));
assert_eq!(vec4(1isize, 2isize, 3isize, 4isize), Vector4::new(1isize, 2isize, 3isize, 4isize)); assert_eq!(
vec4(1isize, 2isize, 3isize, 4isize),
Vector4::new(1isize, 2isize, 3isize, 4isize)
);
} }
#[test] #[test]
fn test_from_value() { fn test_from_value() {
assert_eq!(Vector2::from_value(102isize), Vector2::new(102isize, 102isize)); assert_eq!(
assert_eq!(Vector3::from_value(22isize), Vector3::new(22isize, 22isize, 22isize)); Vector2::from_value(102isize),
assert_eq!(Vector4::from_value(76.5f64), Vector4::new(76.5f64, 76.5f64, 76.5f64, 76.5f64)); Vector2::new(102isize, 102isize)
);
assert_eq!(
Vector3::from_value(22isize),
Vector3::new(22isize, 22isize, 22isize)
);
assert_eq!(
Vector4::from_value(76.5f64),
Vector4::new(76.5f64, 76.5f64, 76.5f64, 76.5f64)
);
} }
macro_rules! impl_test_add { macro_rules! impl_test_add {
@ -132,8 +144,14 @@ fn test_rem() {
#[test] #[test]
fn test_dot() { fn test_dot() {
assert_eq!(Vector2::new(1.0, 2.0).dot(Vector2::new(3.0, 4.0)), 11.0); assert_eq!(Vector2::new(1.0, 2.0).dot(Vector2::new(3.0, 4.0)), 11.0);
assert_eq!(Vector3::new(1.0, 2.0, 3.0).dot(Vector3::new(4.0, 5.0, 6.0)), 32.0); assert_eq!(
assert_eq!(Vector4::new(1.0, 2.0, 3.0, 4.0).dot(Vector4::new(5.0, 6.0, 7.0, 8.0)), 70.0); Vector3::new(1.0, 2.0, 3.0).dot(Vector3::new(4.0, 5.0, 6.0)),
32.0
);
assert_eq!(
Vector4::new(1.0, 2.0, 3.0, 4.0).dot(Vector4::new(5.0, 6.0, 7.0, 8.0)),
70.0
);
} }
#[test] #[test]
@ -149,7 +167,12 @@ fn test_sum() {
#[test] #[test]
fn test_iter_sum() { fn test_iter_sum() {
impl_test_iter_sum!(Vector4 { x, y, z, w }, f32, 2.0f32, vec4(2.0f32, 4.0, 6.0, 8.0)); impl_test_iter_sum!(
Vector4 { x, y, z, w },
f32,
2.0f32,
vec4(2.0f32, 4.0, 6.0, 8.0)
);
impl_test_iter_sum!(Vector3 { x, y, z }, f32, 2.0f32, vec3(2.0f32, 4.0, 6.0)); impl_test_iter_sum!(Vector3 { x, y, z }, f32, 2.0f32, vec3(2.0f32, 4.0, 6.0));
impl_test_iter_sum!(Vector2 { x, y }, f32, 2.0f32, vec2(2.0f32, 4.0)); impl_test_iter_sum!(Vector2 { x, y }, f32, 2.0f32, vec2(2.0f32, 4.0));
@ -162,11 +185,17 @@ fn test_iter_sum() {
fn test_product() { fn test_product() {
assert_eq!(Vector2::new(1isize, 2isize).product(), 2isize); assert_eq!(Vector2::new(1isize, 2isize).product(), 2isize);
assert_eq!(Vector3::new(1isize, 2isize, 3isize).product(), 6isize); assert_eq!(Vector3::new(1isize, 2isize, 3isize).product(), 6isize);
assert_eq!(Vector4::new(1isize, 2isize, 3isize, 4isize).product(), 24isize); assert_eq!(
Vector4::new(1isize, 2isize, 3isize, 4isize).product(),
24isize
);
assert_eq!(Vector2::new(3.0f64, 4.0f64).product(), 12.0f64); assert_eq!(Vector2::new(3.0f64, 4.0f64).product(), 12.0f64);
assert_eq!(Vector3::new(4.0f64, 5.0f64, 6.0f64).product(), 120.0f64); assert_eq!(Vector3::new(4.0f64, 5.0f64, 6.0f64).product(), 120.0f64);
assert_eq!(Vector4::new(5.0f64, 6.0f64, 7.0f64, 8.0f64).product(), 1680.0f64); assert_eq!(
Vector4::new(5.0f64, 6.0f64, 7.0f64, 8.0f64).product(),
1680.0f64
);
} }
#[test] #[test]
@ -180,8 +209,17 @@ fn test_cross() {
#[test] #[test]
fn test_is_perpendicular() { fn test_is_perpendicular() {
assert!(Vector2::new(1.0f64, 0.0f64).is_perpendicular(Vector2::new(0.0f64, 1.0f64))); assert!(Vector2::new(1.0f64, 0.0f64).is_perpendicular(Vector2::new(0.0f64, 1.0f64)));
assert!(Vector3::new(0.0f64, 1.0f64, 0.0f64).is_perpendicular(Vector3::new(0.0f64, 0.0f64, 1.0f64))); assert!(
assert!(Vector4::new(1.0f64, 0.0f64, 0.0f64, 0.0f64).is_perpendicular(Vector4::new(0.0f64, 0.0f64, 0.0f64, 1.0f64))); Vector3::new(0.0f64, 1.0f64, 0.0f64).is_perpendicular(Vector3::new(0.0f64, 0.0f64, 1.0f64))
);
assert!(
Vector4::new(1.0f64, 0.0f64, 0.0f64, 0.0f64).is_perpendicular(Vector4::new(
0.0f64,
0.0f64,
0.0f64,
1.0f64
))
);
} }
#[cfg(test)] #[cfg(test)]
@ -189,7 +227,7 @@ mod test_magnitude {
use cgmath::*; use cgmath::*;
#[test] #[test]
fn test_vector2(){ fn test_vector2() {
let (a, a_res) = (Vector2::new(3.0f64, 4.0f64), 5.0f64); // (3, 4, 5) Pythagorean triple let (a, a_res) = (Vector2::new(3.0f64, 4.0f64), 5.0f64); // (3, 4, 5) Pythagorean triple
let (b, b_res) = (Vector2::new(5.0f64, 12.0f64), 13.0f64); // (5, 12, 13) Pythagorean triple let (b, b_res) = (Vector2::new(5.0f64, 12.0f64), 13.0f64); // (5, 12, 13) Pythagorean triple
@ -201,7 +239,7 @@ mod test_magnitude {
} }
#[test] #[test]
fn test_vector3(){ fn test_vector3() {
let (a, a_res) = (Vector3::new(2.0f64, 3.0f64, 6.0f64), 7.0f64); // (2, 3, 6, 7) Pythagorean quadruple let (a, a_res) = (Vector3::new(2.0f64, 3.0f64, 6.0f64), 7.0f64); // (2, 3, 6, 7) Pythagorean quadruple
let (b, b_res) = (Vector3::new(1.0f64, 4.0f64, 8.0f64), 9.0f64); // (1, 4, 8, 9) Pythagorean quadruple let (b, b_res) = (Vector3::new(1.0f64, 4.0f64, 8.0f64), 9.0f64); // (1, 4, 8, 9) Pythagorean quadruple
@ -213,7 +251,7 @@ mod test_magnitude {
} }
#[test] #[test]
fn test_vector4(){ fn test_vector4() {
let (a, a_res) = (Vector4::new(1.0f64, 2.0f64, 4.0f64, 10.0f64), 11.0f64); // (1, 2, 4, 10, 11) Pythagorean quintuple let (a, a_res) = (Vector4::new(1.0f64, 2.0f64, 4.0f64, 10.0f64), 11.0f64); // (1, 2, 4, 10, 11) Pythagorean quintuple
let (b, b_res) = (Vector4::new(1.0f64, 2.0f64, 8.0f64, 10.0f64), 13.0f64); // (1, 2, 8, 10, 13) Pythagorean quintuple let (b, b_res) = (Vector4::new(1.0f64, 2.0f64, 8.0f64, 10.0f64), 13.0f64); // (1, 2, 8, 10, 13) Pythagorean quintuple
@ -227,37 +265,106 @@ mod test_magnitude {
#[test] #[test]
fn test_angle() { fn test_angle() {
assert_ulps_eq!(Vector2::new(1.0f64, 0.0f64).angle(Vector2::new(0.0f64, 1.0f64)), &Rad(f64::consts::FRAC_PI_2)); assert_ulps_eq!(
assert_ulps_eq!(Vector2::new(10.0f64, 0.0f64).angle(Vector2::new(0.0f64, 5.0f64)), &Rad(f64::consts::FRAC_PI_2)); Vector2::new(1.0f64, 0.0f64).angle(Vector2::new(0.0f64, 1.0f64)),
assert_ulps_eq!(Vector2::new(-1.0f64, 0.0f64).angle(Vector2::new(0.0f64, 1.0f64)), &-Rad(f64::consts::FRAC_PI_2)); &Rad(f64::consts::FRAC_PI_2)
);
assert_ulps_eq!(
Vector2::new(10.0f64, 0.0f64).angle(Vector2::new(0.0f64, 5.0f64)),
&Rad(f64::consts::FRAC_PI_2)
);
assert_ulps_eq!(
Vector2::new(-1.0f64, 0.0f64).angle(Vector2::new(0.0f64, 1.0f64)),
&-Rad(f64::consts::FRAC_PI_2)
);
assert_ulps_eq!(Vector3::new(1.0f64, 0.0f64, 1.0f64).angle(Vector3::new(1.0f64, 1.0f64, 0.0f64)), &Rad(f64::consts::FRAC_PI_3)); assert_ulps_eq!(
assert_ulps_eq!(Vector3::new(10.0f64, 0.0f64, 10.0f64).angle(Vector3::new(5.0f64, 5.0f64, 0.0f64)), &Rad(f64::consts::FRAC_PI_3)); Vector3::new(1.0f64, 0.0f64, 1.0f64).angle(Vector3::new(1.0f64, 1.0f64, 0.0f64)),
assert_ulps_eq!(Vector3::new(-1.0f64, 0.0f64, -1.0f64).angle(Vector3::new(1.0f64, -1.0f64, 0.0f64)), &Rad(2.0f64 * f64::consts::FRAC_PI_3)); &Rad(f64::consts::FRAC_PI_3)
);
assert_ulps_eq!(
Vector3::new(10.0f64, 0.0f64, 10.0f64).angle(Vector3::new(5.0f64, 5.0f64, 0.0f64)),
&Rad(f64::consts::FRAC_PI_3)
);
assert_ulps_eq!(
Vector3::new(-1.0f64, 0.0f64, -1.0f64).angle(Vector3::new(1.0f64, -1.0f64, 0.0f64)),
&Rad(2.0f64 * f64::consts::FRAC_PI_3)
);
assert_ulps_eq!(Vector4::new(1.0f64, 0.0f64, 1.0f64, 0.0f64).angle(Vector4::new(0.0f64, 1.0f64, 0.0f64, 1.0f64)), &Rad(f64::consts::FRAC_PI_2)); assert_ulps_eq!(
assert_ulps_eq!(Vector4::new(10.0f64, 0.0f64, 10.0f64, 0.0f64).angle(Vector4::new(0.0f64, 5.0f64, 0.0f64, 5.0f64)), &Rad(f64::consts::FRAC_PI_2)); Vector4::new(1.0f64, 0.0f64, 1.0f64, 0.0f64).angle(Vector4::new(
assert_ulps_eq!(Vector4::new(-1.0f64, 0.0f64, -1.0f64, 0.0f64).angle(Vector4::new(0.0f64, 1.0f64, 0.0f64, 1.0f64)), &Rad(f64::consts::FRAC_PI_2)); 0.0f64,
1.0f64,
0.0f64,
1.0f64
)),
&Rad(f64::consts::FRAC_PI_2)
);
assert_ulps_eq!(
Vector4::new(10.0f64, 0.0f64, 10.0f64, 0.0f64).angle(Vector4::new(
0.0f64,
5.0f64,
0.0f64,
5.0f64
)),
&Rad(f64::consts::FRAC_PI_2)
);
assert_ulps_eq!(
Vector4::new(-1.0f64, 0.0f64, -1.0f64, 0.0f64).angle(Vector4::new(
0.0f64,
1.0f64,
0.0f64,
1.0f64
)),
&Rad(f64::consts::FRAC_PI_2)
);
} }
#[test] #[test]
fn test_normalize() { fn test_normalize() {
// TODO: test normalize_to, normalize_sel.0, and normalize_self_to // TODO: test normalize_to, normalize_sel.0, and normalize_self_to
assert_ulps_eq!(Vector2::new(3.0f64, 4.0f64).normalize(), &Vector2::new(3.0/5.0, 4.0/5.0)); assert_ulps_eq!(
assert_ulps_eq!(Vector3::new(2.0f64, 3.0f64, 6.0f64).normalize(), &Vector3::new(2.0/7.0, 3.0/7.0, 6.0/7.0)); Vector2::new(3.0f64, 4.0f64).normalize(),
assert_ulps_eq!(Vector4::new(1.0f64, 2.0f64, 4.0f64, 10.0f64).normalize(), &Vector4::new(1.0/11.0, 2.0/11.0, 4.0/11.0, 10.0/11.0)); &Vector2::new(3.0 / 5.0, 4.0 / 5.0)
);
assert_ulps_eq!(
Vector3::new(2.0f64, 3.0f64, 6.0f64).normalize(),
&Vector3::new(2.0 / 7.0, 3.0 / 7.0, 6.0 / 7.0)
);
assert_ulps_eq!(
Vector4::new(1.0f64, 2.0f64, 4.0f64, 10.0f64).normalize(),
&Vector4::new(1.0 / 11.0, 2.0 / 11.0, 4.0 / 11.0, 10.0 / 11.0)
);
} }
#[test] #[test]
fn test_project_on() { fn test_project_on() {
assert_ulps_eq!(Vector2::new(-1.0f64, 5.0).project_on(Vector2::new(2.0, 4.0)), &Vector2::new(9.0/5.0, 18.0/5.0)); assert_ulps_eq!(
assert_ulps_eq!(Vector3::new(5.0f64, 6.0, 7.0).project_on(Vector3::new(1.0, 1.0, 1.0)), &Vector3::new(6.0, 6.0, 6.0)); Vector2::new(-1.0f64, 5.0).project_on(Vector2::new(2.0, 4.0)),
assert_ulps_eq!(Vector4::new(0.0f64, -5.0, 5.0, 5.0).project_on(Vector4::new(0.0, 1.0, 0.0, 0.5)), &Vector4::new(0.0, -2.0, 0.0, -1.0)); &Vector2::new(9.0 / 5.0, 18.0 / 5.0)
);
assert_ulps_eq!(
Vector3::new(5.0f64, 6.0, 7.0).project_on(Vector3::new(1.0, 1.0, 1.0)),
&Vector3::new(6.0, 6.0, 6.0)
);
assert_ulps_eq!(
Vector4::new(0.0f64, -5.0, 5.0, 5.0).project_on(Vector4::new(0.0, 1.0, 0.0, 0.5)),
&Vector4::new(0.0, -2.0, 0.0, -1.0)
);
} }
#[test] #[test]
fn test_cast() { fn test_cast() {
assert_ulps_eq!(Vector2::new(0.9f64, 1.5).cast().unwrap(), Vector2::new(0.9f32, 1.5)); assert_ulps_eq!(
assert_ulps_eq!(Vector3::new(1.0f64, 2.4, -3.13).cast().unwrap(), Vector3::new(1.0f32, 2.4, -3.13)); Vector2::new(0.9f64, 1.5).cast().unwrap(),
assert_ulps_eq!(Vector4::new(13.5f64, -4.6, -8.3, 2.41).cast().unwrap(), Vector4::new(13.5f32, -4.6, -8.3, 2.41)); Vector2::new(0.9f32, 1.5)
);
assert_ulps_eq!(
Vector3::new(1.0f64, 2.4, -3.13).cast().unwrap(),
Vector3::new(1.0f32, 2.4, -3.13)
);
assert_ulps_eq!(
Vector4::new(13.5f64, -4.6, -8.3, 2.41).cast().unwrap(),
Vector4::new(13.5f32, -4.6, -8.3, 2.41)
);
} }

View file

@ -22,12 +22,18 @@ use std::f32;
#[test] #[test]
fn test_constructor() { fn test_constructor() {
assert_eq!(vec4(1f32, 2f32, 3f32, 4f32), Vector4::new(1f32, 2f32, 3f32, 4f32)); assert_eq!(
vec4(1f32, 2f32, 3f32, 4f32),
Vector4::new(1f32, 2f32, 3f32, 4f32)
);
} }
#[test] #[test]
fn test_from_value() { fn test_from_value() {
assert_eq!(Vector4::from_value(76.5f32), Vector4::new(76.5f32, 76.5f32, 76.5f32, 76.5f32)); assert_eq!(
Vector4::from_value(76.5f32),
Vector4::new(76.5f32, 76.5f32, 76.5f32, 76.5f32)
);
} }
macro_rules! impl_test_add { macro_rules! impl_test_add {
@ -84,32 +90,60 @@ macro_rules! impl_test_rem {
#[test] #[test]
fn test_add() { fn test_add() {
impl_test_add!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0f32, 6.0f32, 8.0f32)); impl_test_add!(
Vector4 { x, y, z, w },
2.0f32,
vec4(2.0f32, 4.0f32, 6.0f32, 8.0f32)
);
} }
#[test] #[test]
fn test_sub() { fn test_sub() {
impl_test_sub!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0f32, 6.0f32, 8.0f32)); impl_test_sub!(
Vector4 { x, y, z, w },
2.0f32,
vec4(2.0f32, 4.0f32, 6.0f32, 8.0f32)
);
} }
#[test] #[test]
fn test_mul() { fn test_mul() {
impl_test_mul!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0f32, 6.0f32, 8.0f32)); impl_test_mul!(
Vector4 { x, y, z, w },
2.0f32,
vec4(2.0f32, 4.0f32, 6.0f32, 8.0f32)
);
} }
#[test] #[test]
fn test_div() { fn test_div() {
impl_test_div!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0f32, 6.0f32, 8.0f32)); impl_test_div!(
Vector4 { x, y, z, w },
2.0f32,
vec4(2.0f32, 4.0f32, 6.0f32, 8.0f32)
);
} }
#[test] #[test]
fn test_rem() { fn test_rem() {
impl_test_rem!(Vector4 { x, y, z, w }, 2.0f32, vec4(2.0f32, 4.0f32, 6.0f32, 8.0f32)); impl_test_rem!(
Vector4 { x, y, z, w },
2.0f32,
vec4(2.0f32, 4.0f32, 6.0f32, 8.0f32)
);
} }
#[test] #[test]
fn test_dot() { fn test_dot() {
assert_eq!(Vector4::new(1.0f32, 2.0f32, 3.0f32, 4.0f32).dot(Vector4::new(5.0f32, 6.0f32, 7.0f32, 8.0f32)), 70.0f32); assert_eq!(
Vector4::new(1.0f32, 2.0f32, 3.0f32, 4.0f32).dot(Vector4::new(
5.0f32,
6.0f32,
7.0f32,
8.0f32
)),
70.0f32
);
} }
#[test] #[test]
@ -123,12 +157,22 @@ fn test_sum() {
fn test_product() { fn test_product() {
assert_eq!(Vector4::new(1f32, 2f32, 3f32, 4f32).product(), 24f32); assert_eq!(Vector4::new(1f32, 2f32, 3f32, 4f32).product(), 24f32);
assert_eq!(Vector4::new(5.0f32, 6.0f32, 7.0f32, 8.0f32).product(), 1680.0f32); assert_eq!(
Vector4::new(5.0f32, 6.0f32, 7.0f32, 8.0f32).product(),
1680.0f32
);
} }
#[test] #[test]
fn test_is_perpendicular() { fn test_is_perpendicular() {
assert!(Vector4::new(1.0f32, 0.0f32, 0.0f32, 0.0f32).is_perpendicular(Vector4::new(0.0f32, 0.0f32, 0.0f32, 1.0f32))); assert!(
Vector4::new(1.0f32, 0.0f32, 0.0f32, 0.0f32).is_perpendicular(Vector4::new(
0.0f32,
0.0f32,
0.0f32,
1.0f32
))
);
} }
#[cfg(test)] #[cfg(test)]
@ -136,7 +180,7 @@ mod test_magnitude {
use cgmath::*; use cgmath::*;
#[test] #[test]
fn test_vector4(){ fn test_vector4() {
let (a, a_res) = (Vector4::new(1.0f32, 2.0f32, 4.0f32, 10.0f32), 11.0f32); // (1, 2, 4, 10, 11) Pythagorean quintuple let (a, a_res) = (Vector4::new(1.0f32, 2.0f32, 4.0f32, 10.0f32), 11.0f32); // (1, 2, 4, 10, 11) Pythagorean quintuple
let (b, b_res) = (Vector4::new(1.0f32, 2.0f32, 8.0f32, 10.0f32), 13.0f32); // (1, 2, 8, 10, 13) Pythagorean quintuple let (b, b_res) = (Vector4::new(1.0f32, 2.0f32, 8.0f32, 10.0f32), 13.0f32); // (1, 2, 8, 10, 13) Pythagorean quintuple
@ -150,26 +194,69 @@ mod test_magnitude {
{ {
let a = Vector4::new(1f32, 4f32, 9f32, 16f32); let a = Vector4::new(1f32, 4f32, 9f32, 16f32);
assert_ulps_eq!(a.sqrt_element_wide(), Vector4::new(1f32, 2f32, 3f32, 4f32)); assert_ulps_eq!(a.sqrt_element_wide(), Vector4::new(1f32, 2f32, 3f32, 4f32));
assert_relative_eq!(a.sqrt_element_wide().recip_element_wide(), Vector4::new(1f32, 1f32/2f32, 1f32/3f32, 1f32/4f32), max_relative = 0.005f32); assert_relative_eq!(
assert_relative_eq!(a.rsqrt_element_wide(), Vector4::new(1f32, 1f32/2f32, 1f32/3f32, 1f32/4f32), max_relative= 0.005f32); a.sqrt_element_wide().recip_element_wide(),
Vector4::new(1f32, 1f32 / 2f32, 1f32 / 3f32, 1f32 / 4f32),
max_relative = 0.005f32
);
assert_relative_eq!(
a.rsqrt_element_wide(),
Vector4::new(1f32, 1f32 / 2f32, 1f32 / 3f32, 1f32 / 4f32),
max_relative = 0.005f32
);
} }
} }
} }
#[test] #[test]
fn test_angle() { fn test_angle() {
assert_ulps_eq!(Vector4::new(1.0f32, 0.0f32, 1.0f32, 0.0f32).angle(Vector4::new(0.0f32, 1.0f32, 0.0f32, 1.0f32)), &Rad(f32::consts::FRAC_PI_2)); assert_ulps_eq!(
assert_ulps_eq!(Vector4::new(10.0f32, 0.0f32, 10.0f32, 0.0f32).angle(Vector4::new(0.0f32, 5.0f32, 0.0f32, 5.0f32)), &Rad(f32::consts::FRAC_PI_2)); Vector4::new(1.0f32, 0.0f32, 1.0f32, 0.0f32).angle(Vector4::new(
assert_ulps_eq!(Vector4::new(-1.0f32, 0.0f32, -1.0f32, 0.0f32).angle(Vector4::new(0.0f32, 1.0f32, 0.0f32, 1.0f32)), &Rad(f32::consts::FRAC_PI_2)); 0.0f32,
1.0f32,
0.0f32,
1.0f32
)),
&Rad(f32::consts::FRAC_PI_2)
);
assert_ulps_eq!(
Vector4::new(10.0f32, 0.0f32, 10.0f32, 0.0f32).angle(Vector4::new(
0.0f32,
5.0f32,
0.0f32,
5.0f32
)),
&Rad(f32::consts::FRAC_PI_2)
);
assert_ulps_eq!(
Vector4::new(-1.0f32, 0.0f32, -1.0f32, 0.0f32).angle(Vector4::new(
0.0f32,
1.0f32,
0.0f32,
1.0f32
)),
&Rad(f32::consts::FRAC_PI_2)
);
} }
#[test] #[test]
fn test_normalize() { fn test_normalize() {
// TODO: test normalize_to, normalize_sel.0f32, and normalize_self_to // TODO: test normalize_to, normalize_sel.0f32, and normalize_self_to
assert_ulps_eq!(Vector4::new(1.0f32, 2.0f32, 4.0f32, 10.0f32).normalize(), &Vector4::new(1.0f32/11.0f32, 2.0f32/11.0f32, 4.0f32/11.0f32, 10.0f32/11.0f32)); assert_ulps_eq!(
Vector4::new(1.0f32, 2.0f32, 4.0f32, 10.0f32).normalize(),
&Vector4::new(
1.0f32 / 11.0f32,
2.0f32 / 11.0f32,
4.0f32 / 11.0f32,
10.0f32 / 11.0f32
)
);
} }
#[test] #[test]
fn test_cast() { fn test_cast() {
assert_ulps_eq!(Vector4::new(13.5f32, -4.6, -8.3, 2.41).cast().unwrap(), Vector4::new(13.5f32, -4.6, -8.3, 2.41)); assert_ulps_eq!(
Vector4::new(13.5f32, -4.6, -8.3, 2.41).cast().unwrap(),
Vector4::new(13.5f32, -4.6, -8.3, 2.41)
);
} }