Merge pull request #443 from brendanzab/v0.16

Release v0.16
This commit is contained in:
Brendan Zabarauskas 2018-01-05 15:25:41 +11:00 committed by GitHub
commit 863d21be9a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 1423 additions and 677 deletions

View file

@ -6,6 +6,21 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## [Unreleased]
## [v0.16.0] - 2018-01-03
### Added
- Add `InnerSpace::project_on`
- Add `Array::len`
- Re-export `Bounded` and implement for vectors, points, and angles
- Add vector subtraction to `EuclideanSpace`
- Add swizzle functions behinde that `"swizzle"` feature
- Add `Matrix4::look_at_dir`
### Changed
- Return `Option` from cast functions
## [v0.15.0] - 2017-07-30
### Added
@ -274,7 +289,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
## v0.0.1 - 2014-06-24
[Unreleased]: https://github.com/brendanzab/cgmath/compare/v0.15.0...HEAD
[Unreleased]: https://github.com/brendanzab/cgmath/compare/v0.16.0...HEAD
[v0.16.0]: https://github.com/brendanzab/cgmath/compare/v0.15.0...v0.16.0
[v0.15.0]: https://github.com/brendanzab/cgmath/compare/v0.14.1...v0.15.0
[v0.14.1]: https://github.com/brendanzab/cgmath/compare/v0.14.0...v0.14.1
[v0.14.0]: https://github.com/brendanzab/cgmath/compare/v0.13.1...v0.14.0

View file

@ -1,7 +1,7 @@
[package]
name = "cgmath"
version = "0.15.0"
version = "0.16.0"
authors = ["Brendan Zabarauskas <bjzaba@yahoo.com.au>"]
license = "Apache-2.0"
description = "A linear algebra and mathematics library for computer graphics."
@ -22,12 +22,12 @@ swizzle = []
[dependencies]
approx = "0.1"
mint = { version = "0.4.1", optional = true }
mint = { version = "0.5", optional = true }
num-traits = "0.1"
rand = "0.4"
serde = { version = "1.0", features = ["serde_derive"], optional = true }
simd = { version = "0.2", optional = true }
[dev-dependencies]
glium = "0.17"
glium = "0.19"
serde_json = "1.0"

View file

@ -15,16 +15,17 @@
#![feature(test)]
extern crate cgmath;
extern crate rand;
extern crate test;
extern crate cgmath;
use rand::{IsaacRng, Rng};
use test::Bencher;
use cgmath::*;
#[path = "common/macros.rs"]
#[macro_use] mod macros;
#[macro_use]
mod macros;
fn bench_from_axis_angle<T: Rotation3<f32>>(bh: &mut Bencher) {
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);
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)
}
})
@ -55,7 +57,19 @@ fn _bench_rot3_from_axisangle(bh: &mut Bencher) {
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_rot3_from_euler_angles, Basis3<f32>, Basis3::from [src: Euler<Rad<f32>>]);
bench_construction!(
_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)]
extern crate cgmath;
extern crate rand;
extern crate test;
extern crate cgmath;
use rand::{IsaacRng, Rng};
use std::ops::*;
@ -26,7 +26,8 @@ use test::Bencher;
use cgmath::*;
#[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_matrix3_mul_m, Matrix3<f32>, Matrix3<f32>, mul);

View file

@ -15,9 +15,9 @@
#![feature(test)]
extern crate cgmath;
extern crate rand;
extern crate test;
extern crate cgmath;
use rand::{IsaacRng, Rng};
use std::ops::*;
@ -26,7 +26,8 @@ use test::Bencher;
use cgmath::*;
#[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_sub_q, Quaternion<f32>, Quaternion<f32>, sub);

View file

@ -15,9 +15,9 @@
#![feature(test)]
extern crate cgmath;
extern crate rand;
extern crate test;
extern crate cgmath;
use rand::{IsaacRng, Rng};
use std::ops::*;
@ -26,7 +26,8 @@ use test::Bencher;
use cgmath::*;
#[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_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))]
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]
fn from(rad: Rad<S>) -> Deg<S> {
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]
fn from(deg: Deg<S>) -> Rad<S> {
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
/// [convert]: #defining-rotations-using-euler-angles
#[repr(C)]
#[derive(Copy, Clone, Debug)]
#[derive(PartialEq, Eq)]
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Euler<A: Angle> {
/// 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]
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.y, &other.y, epsilon, max_relative) &&
A::relative_eq(&self.z, &other.z, 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.z, &other.z, epsilon, max_relative)
}
#[inline]
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.y, &other.y, epsilon, max_ulps) &&
A::ulps_eq(&self.z, &other.z, 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.z, &other.z, epsilon, max_ulps)
}
}
impl<A: Angle + Rand> Rand for Euler<A> {
#[inline]
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")]
pub extern crate mint;
pub extern crate num_traits;
extern crate rand;
pub extern crate num_traits;
#[cfg(feature = "serde")]
#[macro_use]
@ -76,7 +76,7 @@ pub use structure::*;
pub use matrix::{Matrix2, Matrix3, Matrix4};
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 euler::Euler;

View file

@ -80,14 +80,11 @@ pub struct Matrix4<S> {
pub w: Vector4<S>,
}
impl<S: BaseFloat> Matrix2<S> {
/// Create a new matrix, providing values for each index.
#[inline]
pub fn new(c0r0: S, c0r1: S,
c1r0: S, c1r1: S) -> Matrix2<S> {
Matrix2::from_cols(Vector2::new(c0r0, c0r1),
Vector2::new(c1r0, c1r1))
pub fn new(c0r0: S, c0r1: S, c1r0: S, c1r1: S) -> Matrix2<S> {
Matrix2::from_cols(Vector2::new(c0r0, c0r1), Vector2::new(c1r0, c1r1))
}
/// 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> {
let (s, c) = Rad::sin_cos(theta.into());
Matrix2::new(c, s,
-s, c)
Matrix2::new(c, s, -s, c)
}
}
impl<S: BaseFloat> Matrix3<S> {
/// Create a new matrix, providing values for each index.
#[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,
c2r0:S, c2r1:S, c2r2:S) -> Matrix3<S> {
Matrix3::from_cols(Vector3::new(c0r0, c0r1, c0r2),
c2r0:S, c2r1:S, c2r2:S,
) -> Matrix3<S> {
Matrix3::from_cols(
Vector3::new(c0r0, c0r1, c0r2),
Vector3::new(c1r0, c1r1, c1r2),
Vector3::new(c2r0, c2r1, c2r2))
Vector3::new(c2r0, c2r1, c2r2),
)
}
/// Create a new matrix, providing columns.
#[inline]
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
@ -143,27 +148,39 @@ impl<S: BaseFloat> Matrix3<S> {
pub fn from_angle_x<A: Into<Rad<S>>>(theta: A) -> Matrix3<S> {
// http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
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(), -s, c)
S::zero(), -s, c,
)
}
/// 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> {
// http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
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, S::zero(), c)
s, S::zero(), c,
)
}
/// 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> {
// http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
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::zero(), S::zero(), S::one())
S::zero(), S::zero(), S::one(),
)
}
/// 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 _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.z - s * axis.y,
@ -183,36 +202,50 @@ impl<S: BaseFloat> Matrix3<S> {
_1subc * axis.x * axis.z + s * axis.y,
_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> {
/// Create a new matrix, providing values for each index.
#[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,
c2r0: S, c2r1: S, c2r2: S, c2r3: S,
c3r0: S, c3r1: S, c3r2: S, c3r3: S) -> Matrix4<S> {
Matrix4::from_cols(Vector4::new(c0r0, c0r1, c0r2, c0r3),
c3r0: S, c3r1: S, c3r2: S, c3r3: S,
) -> Matrix4<S> {
Matrix4::from_cols(
Vector4::new(c0r0, c0r1, c0r2, c0r3),
Vector4::new(c1r0, c1r1, c1r2, c1r3),
Vector4::new(c2r0, c2r1, c2r2, c2r3),
Vector4::new(c3r0, c3r1, c3r2, c3r3))
Vector4::new(c3r0, c3r1, c3r2, c3r3),
)
}
/// Create a new matrix, providing columns.
#[inline]
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.
#[inline]
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::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.
@ -224,10 +257,13 @@ impl<S: BaseFloat> Matrix4<S> {
/// Create a homogeneous transformation matrix from a set of scale values.
#[inline]
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(), 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
@ -237,10 +273,13 @@ impl<S: BaseFloat> Matrix4<S> {
let s = f.cross(up).normalize();
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.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
@ -253,30 +292,42 @@ impl<S: BaseFloat> Matrix4<S> {
pub fn from_angle_x<A: Into<Rad<S>>>(theta: A) -> Matrix4<S> {
// http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
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(), -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).
pub fn from_angle_y<A: Into<Rad<S>>>(theta: A) -> Matrix4<S> {
// http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
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, 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).
pub fn from_angle_z<A: Into<Rad<S>>>(theta: A) -> Matrix4<S> {
// http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
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::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.
@ -286,7 +337,9 @@ impl<S: BaseFloat> Matrix4<S> {
let (s, c) = Rad::sin_cos(angle.into());
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.z - s * axis.y,
S::zero(),
@ -301,18 +354,19 @@ impl<S: BaseFloat> Matrix4<S> {
_1subc * axis.z * axis.z + c,
S::zero(),
S::zero(),
S::zero(),
S::zero(),
S::one())
S::zero(), S::zero(), S::zero(), S::one(),
)
}
}
impl<S: BaseFloat> Zero for Matrix2<S> {
#[inline]
fn zero() -> Matrix2<S> {
Matrix2::new(S::zero(), S::zero(),
S::zero(), S::zero())
#[cfg_attr(rustfmt, rustfmt_skip)]
Matrix2::new(
S::zero(), S::zero(),
S::zero(), S::zero(),
)
}
#[inline]
@ -324,9 +378,12 @@ impl<S: BaseFloat> Zero for Matrix2<S> {
impl<S: BaseFloat> Zero for Matrix3<S> {
#[inline]
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(),
)
}
#[inline]
@ -338,10 +395,13 @@ impl<S: BaseFloat> Zero for Matrix3<S> {
impl<S: BaseFloat> Zero for Matrix4<S> {
#[inline]
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(),
)
}
#[inline]
@ -390,8 +450,7 @@ impl<S: BaseFloat> Matrix for Matrix2<S> {
#[inline]
fn row(&self, r: usize) -> Vector2<S> {
Vector2::new(self[0][r],
self[1][r])
Vector2::new(self[0][r], self[1][r])
}
#[inline]
@ -413,8 +472,11 @@ impl<S: BaseFloat> Matrix for Matrix2<S> {
}
fn transpose(&self) -> Matrix2<S> {
Matrix2::new(self[0][0], self[1][0],
self[0][1], self[1][1])
#[cfg_attr(rustfmt, rustfmt_skip)]
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]
fn from_value(value: S) -> Matrix2<S> {
Matrix2::new(value, S::zero(),
S::zero(), value)
#[cfg_attr(rustfmt, rustfmt_skip)]
Matrix2::new(
value, S::zero(),
S::zero(), value,
)
}
#[inline]
fn from_diagonal(value: Vector2<S>) -> Matrix2<S> {
Matrix2::new(value.x, S::zero(),
S::zero(), value.y)
#[cfg_attr(rustfmt, rustfmt_skip)]
Matrix2::new(
value.x, S::zero(),
S::zero(), value.y,
)
}
#[inline]
@ -445,8 +513,7 @@ impl<S: BaseFloat> SquareMatrix for Matrix2<S> {
#[inline]
fn diagonal(&self) -> Vector2<S> {
Vector2::new(self[0][0],
self[1][1])
Vector2::new(self[0][0], self[1][1])
}
#[inline]
@ -455,24 +522,22 @@ impl<S: BaseFloat> SquareMatrix for Matrix2<S> {
if det == S::zero() {
None
} else {
Some(Matrix2::new(self[1][1] / det,
-self[0][1] / det,
-self[1][0] / det,
self[0][0] / det))
#[cfg_attr(rustfmt, rustfmt_skip)]
Some(Matrix2::new(
self[1][1] / det, -self[0][1] / det,
-self[1][0] / det, self[0][0] / det,
))
}
}
#[inline]
fn is_diagonal(&self) -> bool {
ulps_eq!(self[0][1], &S::zero()) &&
ulps_eq!(self[1][0], &S::zero())
ulps_eq!(self[0][1], &S::zero()) && ulps_eq!(self[1][0], &S::zero())
}
#[inline]
fn is_symmetric(&self) -> bool {
ulps_eq!(self[0][1], &self[1][0]) &&
ulps_eq!(self[1][0], &self[0][1])
ulps_eq!(self[0][1], &self[1][0]) && ulps_eq!(self[1][0], &self[0][1])
}
}
@ -483,9 +548,7 @@ impl<S: BaseFloat> Matrix for Matrix3<S> {
#[inline]
fn row(&self, r: usize) -> Vector3<S> {
Vector3::new(self[0][r],
self[1][r],
self[2][r])
Vector3::new(self[0][r], self[1][r], self[2][r])
}
#[inline]
@ -508,9 +571,12 @@ impl<S: BaseFloat> Matrix for 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][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]
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(), S::zero(), value)
S::zero(), S::zero(), value,
)
}
#[inline]
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(), S::zero(), value.z)
S::zero(), S::zero(), value.z,
)
}
#[inline]
@ -539,16 +611,14 @@ impl<S: BaseFloat> SquareMatrix for Matrix3<S> {
}
fn determinant(&self) -> S {
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[2][0] * (self[0][1] * self[1][2] - self[1][1] * self[0][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[2][0] * (self[0][1] * self[1][2] - self[1][1] * self[0][2])
}
#[inline]
fn diagonal(&self) -> Vector3<S> {
Vector3::new(self[0][0],
self[1][1],
self[2][2])
Vector3::new(self[0][0], self[1][1], self[2][2])
}
fn invert(&self) -> Option<Matrix3<S>> {
@ -556,32 +626,26 @@ impl<S: BaseFloat> SquareMatrix for Matrix3<S> {
if det == S::zero() {
None
} 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[0].cross(self[1]) / det).transpose())
self[0].cross(self[1]) / det,
).transpose(),
)
}
}
fn is_diagonal(&self) -> bool {
ulps_eq!(self[0][1], &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[0][1], &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())
}
fn is_symmetric(&self) -> bool {
ulps_eq!(self[0][1], &self[1][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[0][1], &self[1][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])
}
}
@ -592,10 +656,7 @@ impl<S: BaseFloat> Matrix for Matrix4<S> {
#[inline]
fn row(&self, r: usize) -> Vector4<S> {
Vector4::new(self[0][r],
self[1][r],
self[2][r],
self[3][r])
Vector4::new(self[0][r], self[1][r], self[2][r], self[3][r])
}
#[inline]
@ -619,31 +680,39 @@ impl<S: BaseFloat> Matrix for 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][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> {
type ColumnRow = Vector4<S>;
#[inline]
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(), S::zero(), value, S::zero(),
S::zero(), S::zero(), S::zero(), value)
S::zero(), S::zero(), S::zero(), value,
)
}
#[inline]
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(), 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) {
@ -656,18 +725,13 @@ impl<S: BaseFloat> SquareMatrix for Matrix4<S> {
}
fn determinant(&self) -> S {
let tmp = unsafe {
det_sub_proc_unsafe(self, 1, 2, 3)
};
let tmp = unsafe { det_sub_proc_unsafe(self, 1, 2, 3) };
tmp.dot(Vector4::new(self[0][0], self[1][0], self[2][0], self[3][0]))
}
#[inline]
fn diagonal(&self) -> Vector4<S> {
Vector4::new(self[0][0],
self[1][1],
self[2][2],
self[3][3])
Vector4::new(self[0][0], self[1][1], self[2][2], self[3][3])
}
// 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 cf = |i, j| {
let mat = match i {
0 => Matrix3::from_cols(t.y.truncate_n(j), t.z.truncate_n(j), t.w.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)),
0 => {
Matrix3::from_cols(t.y.truncate_n(j), t.z.truncate_n(j), t.w.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"),
};
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
};
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(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")]
fn invert(&self) -> Option<Matrix4<S>> {
let tmp0 = unsafe {
det_sub_proc_unsafe(self, 1, 2, 3)
};
let tmp0 = unsafe { 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]));
if det == S::zero() {
@ -713,53 +790,29 @@ impl<S: BaseFloat> SquareMatrix for Matrix4<S> {
} else {
let inv_det = S::one() / det;
let tmp0 = tmp0 * inv_det;
let tmp1 = unsafe {
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 tmp1 = unsafe { 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 };
Some(Matrix4::from_cols(tmp0, tmp1, tmp2, tmp3))
}
}
fn is_diagonal(&self) -> bool {
ulps_eq!(self[0][1], &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[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[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())
ulps_eq!(self[0][1], &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[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[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 {
ulps_eq!(self[0][1], &self[1][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[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[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])
ulps_eq!(self[0][1], &self[1][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[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[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]
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[1], &other[1], epsilon, max_relative)
Vector2::relative_eq(&self[0], &other[0], epsilon, max_relative)
&& Vector2::relative_eq(&self[1], &other[1], epsilon, max_relative)
}
#[inline]
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[1], &other[1], epsilon, max_ulps)
Vector2::ulps_eq(&self[0], &other[0], 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]
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[1], &other[1], epsilon, max_relative) &&
Vector3::relative_eq(&self[2], &other[2], 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[2], &other[2], epsilon, max_relative)
}
#[inline]
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[1], &other[1], epsilon, max_ulps) &&
Vector3::ulps_eq(&self[2], &other[2], 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[2], &other[2], epsilon, max_ulps)
}
}
@ -847,18 +900,18 @@ impl<S: BaseFloat> ApproxEq for Matrix4<S> {
#[inline]
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[1], &other[1], 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[0], &other[0], 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[3], &other[3], epsilon, max_relative)
}
#[inline]
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[1], &other[1], 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[0], &other[0], 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[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!(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 });
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!(Matrix3, Vector3 { x: 0, y: 1, z: 2 });
#[cfg(not(feature = "simd"))]
#[cfg_attr(rustfmt, rustfmt_skip)]
impl_mv_operator!(Matrix4, Vector4 { x: 0, y: 1, z: 2, w: 3 });
#[cfg(feature = "simd")]
impl_operator!(<S: BaseFloat> Mul<Vector4<S> > for Matrix4<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 c = lhs[2];
let d = lhs[3];
#[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::from_cols(
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],
@ -1157,7 +1215,8 @@ index_operators!(Matrix4<S>, 4, Vector4<S>, usize);
// index_operators!(Matrix3<S>, 3, [Vector3<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>>,
{
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 (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,
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>>,
{
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 (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(),
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
/// of a 3-dimensional identity matrix.
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(),
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
/// of a 4-dimensional identity matrix.
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(),
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
/// of a 4-dimensional identity matrix.
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[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> {
#[inline]
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> {
#[inline]
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> {
#[inline]
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
#[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 a = Vector4::new(*s.get_unchecked(4 + x), *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 a = Vector4::new(
*s.get_unchecked(4 + x),
*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 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 d = Vector4::new(
*s.get_unchecked(8 + x),
*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 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 g = Vector4::new(
*s.get_unchecked(12 + x),
*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));
tmp += d.mul_element_wise(e.mul_element_wise(f));
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};
/// 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
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
//! not have a fixed position.
use num_traits::{NumCast, Bounded};
use num_traits::{Bounded, NumCast};
use std::fmt;
use std::mem;
use std::ops::*;
@ -25,7 +25,7 @@ use std::ops::*;
use structure::*;
use approx::ApproxEq;
use num::{BaseNum, BaseFloat};
use num::{BaseFloat, BaseNum};
use vector::{Vector1, Vector2, Vector3, Vector4};
#[cfg(feature = "mint")]

View file

@ -13,7 +13,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use num_traits::{Zero};
use num_traits::Zero;
use num_traits::cast;
use structure::Angle;
@ -26,7 +26,12 @@ use num::BaseFloat;
///
/// This is the equivalent to the [gluPerspective]
/// (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 {
fovy: fovy.into(),
aspect: aspect,
@ -96,12 +101,37 @@ impl<S: BaseFloat> PerspectiveFov<S> {
impl<S: BaseFloat> From<PerspectiveFov<S>> for 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!(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);
assert!(
persp.fovy > Rad::zero(),
"The vertical field of view cannot be below zero, found: {:?}",
persp.fovy
);
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 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 c3r3 = S::zero();
Matrix4::new(c0r0, c0r1, c0r2, c0r3,
#[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
c0r0, c0r1, c0r2, c0r3,
c1r0, c1r1, c1r2, c1r3,
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> {
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!(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);
assert!(
persp.left <= persp.right,
"`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();
@ -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 c3r3 = S::zero();
Matrix4::new(c0r0, c0r1, c0r2, c0r3,
#[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
c0r0, c0r1, c0r2, c0r3,
c1r0, c1r1, c1r2, c1r3,
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 c3r3 = S::one();
Matrix4::new(c0r0, c0r1, c0r2, c0r3,
#[cfg_attr(rustfmt, rustfmt_skip)]
Matrix4::new(
c0r0, c0r1, c0r2, c0r3,
c1r0, c1r1, c1r2, c1r3,
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 rand::{Rand, Rng};
use num_traits::{NumCast, cast};
use num_traits::{cast, NumCast};
use structure::*;
@ -28,7 +28,7 @@ use euler::Euler;
use matrix::{Matrix3, Matrix4};
use num::BaseFloat;
use point::Point3;
use rotation::{Rotation, Rotation3, Basis3};
use rotation::{Basis3, Rotation, Rotation3};
use vector::Vector3;
#[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)
/// - [Ogre implementation for normalized vectors]
/// (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>>)
-> Quaternion<S> {
pub fn from_arc(
src: Vector3<S>,
dst: Vector3<S>,
fallback: Option<Vector3<S>>,
) -> Quaternion<S> {
let mag_avg = (src.magnitude2() * dst.magnitude2()).sqrt();
let dot = src.dot(dst);
if ulps_eq!(dot, &mag_avg) {
@ -237,11 +240,11 @@ impl<S: NumCast + Copy> Quaternion<S> {
pub fn cast<T: BaseFloat>(&self) -> Option<Quaternion<T>> {
let s = match NumCast::from(self.s) {
Some(s) => s,
None => return None
None => return None,
};
let v = match self.v.cast() {
Some(v) => v,
None => return None
None => return None,
};
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>>,
{
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_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 * 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"))]
impl_operator!(<S: BaseFloat> Mul<Quaternion<S> > for 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.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")]
impl_operator_default!(<S: BaseFloat> Mul<Quaternion<S> > for 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.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]
fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool {
S::relative_eq(&self.s, &other.s, epsilon, max_relative) &&
Vector3::relative_eq(&self.v, &other.v, epsilon, max_relative)
S::relative_eq(&self.s, &other.s, epsilon, max_relative)
&& Vector3::relative_eq(&self.v, &other.v, epsilon, max_relative)
}
#[inline]
fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool {
S::ulps_eq(&self.s, &other.s, epsilon, max_ulps) &&
Vector3::ulps_eq(&self.v, &other.v, epsilon, max_ulps)
S::ulps_eq(&self.s, &other.s, 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 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,
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 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(),
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> {
#[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> {
@ -695,10 +713,14 @@ impl<S: BaseFloat> Rotation<Point3<S>> for Quaternion<S> {
}
#[inline]
fn rotate_vector(&self, vec: Vector3<S>) -> Vector3<S> { self * vec }
fn rotate_vector(&self, vec: Vector3<S>) -> Vector3<S> {
self * vec
}
#[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> {
@ -712,7 +734,9 @@ impl<S: BaseFloat> Rotation3<S> for Quaternion<S> {
impl<S: BaseFloat> Into<[S; 4]> for Quaternion<S> {
#[inline]
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> {
#[inline]
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> {
#[inline]
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)]
mod tests {
use quaternion::*;
@ -854,7 +884,11 @@ mod tests {
const QUATERNION: Quaternion<f32> = Quaternion {
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]

View file

@ -30,7 +30,8 @@ use vector::{Vector2, Vector3};
/// 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.
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
Self: ApproxEq<Epsilon = P::Scalar>,
P::Scalar: BaseFloat,
@ -59,20 +60,17 @@ pub trait Rotation<P: EuclideanSpace>: Sized + Copy + One where
}
/// A two-dimensional rotation.
pub trait Rotation2<S: BaseFloat>: Rotation<Point2<S>>
+ Into<Matrix2<S>>
+ Into<Basis2<S>> {
pub trait Rotation2<S: BaseFloat>
: Rotation<Point2<S>> + Into<Matrix2<S>> + Into<Basis2<S>> {
/// Create a rotation by a given angle. Thus is a redundant case of both
/// from_axis_angle() and from_euler() for 2D space.
fn from_angle<A: Into<Rad<S>>>(theta: A) -> Self;
}
/// A three-dimensional rotation.
pub trait Rotation3<S: BaseFloat>: Rotation<Point3<S>>
+ Into<Matrix3<S>>
+ Into<Basis3<S>>
+ Into<Quaternion<S>>
+ From<Euler<Rad<S>>> {
pub trait Rotation3<S: BaseFloat>
: Rotation<Point3<S>> + Into<Matrix3<S>> + Into<Basis3<S>> + Into<Quaternion<S>> + From<Euler<Rad<S>>>
{
/// Create a rotation using an angle around a given axis.
///
/// 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.
///
/// 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)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Basis2<S> {
mat: Matrix2<S>
mat: Matrix2<S>,
}
impl<S: BaseFloat> AsRef<Matrix2<S>> for Basis2<S> {
@ -156,7 +153,9 @@ impl<S: BaseFloat> AsRef<Matrix2<S>> for Basis2<S> {
impl<S: BaseFloat> From<Basis2<S>> for Matrix2<S> {
#[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> {
@ -176,7 +175,9 @@ impl<'a, S: 'a + BaseFloat> iter::Product<&'a Basis2<S>> for Basis2<S> {
impl<S: BaseFloat> Rotation<Point2<S>> for Basis2<S> {
#[inline]
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]
@ -185,17 +186,27 @@ impl<S: BaseFloat> Rotation<Point2<S>> for Basis2<S> {
}
#[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
// to be faster
#[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> {
#[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> {
@ -232,7 +243,11 @@ impl<S: BaseFloat> ApproxEq 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> {
@ -251,14 +266,16 @@ impl<S: fmt::Debug> fmt::Debug for Basis2<S> {
#[derive(PartialEq, Copy, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Basis3<S> {
mat: Matrix3<S>
mat: Matrix3<S>,
}
impl<S: BaseFloat> Basis3<S> {
/// Create a new rotation matrix from a quaternion.
#[inline]
pub fn from_quaternion(quaternion: &Quaternion<S>) -> Basis3<S> {
Basis3 { mat: quaternion.clone().into() }
Basis3 {
mat: quaternion.clone().into(),
}
}
}
@ -271,12 +288,16 @@ impl<S> AsRef<Matrix3<S>> for Basis3<S> {
impl<S: BaseFloat> From<Basis3<S>> for Matrix3<S> {
#[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> {
#[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> {
@ -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> {
#[inline]
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]
@ -306,17 +329,27 @@ impl<S: BaseFloat> Rotation<Point3<S>> for Basis3<S> {
}
#[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
// to be faster
#[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> {
#[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> {
@ -354,23 +387,32 @@ impl<S: BaseFloat> ApproxEq 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> {
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> {
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> {
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> {
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>>,
{
/// 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 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`
pub trait Array where
pub trait Array
where
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
Self: Index<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.
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.
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
@ -156,7 +161,8 @@ pub trait ElementWise<Rhs = Self> {
/// let upscaled_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: Add<Self, Output = Self>,
@ -199,7 +205,8 @@ pub trait MetricSpace: Sized {
/// finding the magnitude of a vector or normalizing it.
///
/// 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
<Self as VectorSpace>::Scalar: BaseFloat,
Self: MetricSpace<Metric = <Self as VectorSpace>::Scalar>,
@ -237,14 +244,12 @@ pub trait InnerSpace: VectorSpace where
/// Returns a vector with the same direction, but with a magnitude of `1`.
#[inline]
#[must_use]
fn normalize(self) -> Self {
self.normalize_to(Self::Scalar::one())
}
/// Returns a vector with the same direction and a given magnitude.
#[inline]
#[must_use]
fn normalize_to(self, magnitude: Self::Scalar) -> Self {
self * (magnitude / self.magnitude())
}
@ -252,7 +257,6 @@ pub trait InnerSpace: VectorSpace where
/// Returns the result of linearly interpolating the magnitude of the vector
/// towards the magnitude of `other` by the specified amount.
#[inline]
#[must_use]
fn lerp(self, other: Self, amount: Self::Scalar) -> Self {
self + ((other - self) * amount)
}
@ -261,7 +265,6 @@ pub trait InnerSpace: VectorSpace where
/// [vector projection](https://en.wikipedia.org/wiki/Vector_projection)
/// of the current inner space projected onto the supplied argument.
#[inline]
#[must_use]
fn project_on(self, other: Self) -> Self {
other * (self.dot(other) / other.magnitude2())
}
@ -314,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)
/// - [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
Self: Array<Element = <Self as EuclideanSpace>::Scalar>,
@ -382,10 +386,9 @@ pub trait EuclideanSpace: Copy + Clone where
/// ```
#[inline]
fn centroid(points: &[Self]) -> Self {
let total_displacement =
points.iter().fold(Self::Diff::zero(), |acc, p| {
acc + p.to_vec()
});
let total_displacement = points
.iter()
.fold(Self::Diff::zero(), |acc, p| acc + p.to_vec());
Self::from_vec(total_displacement / cast(points.len()).unwrap())
}
@ -415,7 +418,8 @@ pub trait EuclideanSpace: Copy + Clone where
/// trait. This is due to the complexities of implementing these operators with
/// Rust's current type system. For the multiplication of square matrices,
/// see `SquareMatrix`.
pub trait Matrix: VectorSpace where
pub trait Matrix: VectorSpace
where
Self::Scalar: BaseFloat,
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
@ -467,7 +471,8 @@ pub trait Matrix: VectorSpace where
}
/// 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: One,
@ -518,22 +523,27 @@ pub trait SquareMatrix where
/// Return the trace of this matrix. That is, the sum of the diagonal.
#[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
/// the identity matrix. Returns `None` if this matrix is not invertible
/// (has a determinant of zero).
#[must_use]
fn invert(&self) -> Option<Self>;
/// Test if this matrix is invertible.
#[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
/// and every element in the diagonal is one.
#[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
/// the diagonal is 0.
@ -550,7 +560,8 @@ pub trait SquareMatrix where
/// clear when semantic violations have occured - for example, adding degrees to
/// radians, or adding a number to an angle.
///
pub trait Angle where
pub trait Angle
where
Self: Copy + Clone,
Self: PartialEq + cmp::PartialOrd,
// FIXME: Ugly type signatures - blocked by rust-lang/rust#24092
@ -574,7 +585,11 @@ pub trait Angle where
#[inline]
fn normalize(self) -> Self {
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.

View file

@ -39,7 +39,8 @@ pub trait Transform<P: EuclideanSpace>: Sized {
/// Inverse transform a vector using this transform
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.
@ -69,9 +70,10 @@ pub struct Decomposed<V: VectorSpace, 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!
P::Diff: VectorSpace
P::Diff: VectorSpace,
{
#[inline]
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: VectorSpace, R, E: BaseFloat> ApproxEq for Decomposed<S, R>
where S: ApproxEq<Epsilon = E>,
where
S: ApproxEq<Epsilon = E>,
S::Scalar: ApproxEq<Epsilon = E>,
R: ApproxEq<Epsilon = E>
R: ApproxEq<Epsilon = E>,
{
type Epsilon = E;
@ -185,16 +188,16 @@ impl<S: VectorSpace, R, E: BaseFloat> ApproxEq for Decomposed<S, R>
#[inline]
fn relative_eq(&self, other: &Self, epsilon: E, max_relative: E) -> bool {
S::Scalar::relative_eq(&self.scale, &other.scale, epsilon, max_relative) &&
R::relative_eq(&self.rot, &other.rot, epsilon, max_relative) &&
S::relative_eq(&self.disp, &other.disp, epsilon, max_relative)
S::Scalar::relative_eq(&self.scale, &other.scale, epsilon, max_relative)
&& R::relative_eq(&self.rot, &other.rot, epsilon, max_relative)
&& S::relative_eq(&self.disp, &other.disp, epsilon, max_relative)
}
#[inline]
fn ulps_eq(&self, other: &Self, epsilon: E, max_ulps: u32) -> bool {
S::Scalar::ulps_eq(&self.scale, &other.scale, epsilon, max_ulps) &&
R::ulps_eq(&self.rot, &other.rot, epsilon, max_ulps) &&
S::ulps_eq(&self.disp, &other.disp, epsilon, max_ulps)
S::Scalar::ulps_eq(&self.scale, &other.scale, epsilon, max_ulps)
&& R::ulps_eq(&self.rot, &other.rot, epsilon, max_ulps)
&& S::ulps_eq(&self.disp, &other.disp, epsilon, max_ulps)
}
}
@ -207,12 +210,14 @@ mod serde_ser {
use serde::ser::SerializeStruct;
impl<V, R> Serialize for Decomposed<V, R>
where V: Serialize + VectorSpace,
where
V: Serialize + VectorSpace,
V::Scalar: Serialize,
R: Serialize
R: Serialize,
{
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)?;
struc.serialize_field("scale", &self.scale)?;
@ -240,7 +245,8 @@ mod serde_de {
impl<'a> Deserialize<'a> for DecomposedField {
fn deserialize<D>(deserializer: D) -> Result<DecomposedField, D::Error>
where D: serde::Deserializer<'a>
where
D: serde::Deserializer<'a>,
{
struct DecomposedFieldVisitor;
@ -252,7 +258,8 @@ mod serde_de {
}
fn visit_str<E>(self, value: &str) -> Result<DecomposedField, E>
where E: serde::de::Error
where
E: serde::de::Error,
{
match value {
"scale" => Ok(DecomposedField::Scale),
@ -268,12 +275,14 @@ mod serde_de {
}
impl<'a, S: VectorSpace, R> Deserialize<'a> for Decomposed<S, R>
where S: Deserialize<'a>,
where
S: Deserialize<'a>,
S::Scalar: Deserialize<'a>,
R: Deserialize<'a>
R: Deserialize<'a>,
{
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"];
deserializer.deserialize_struct("Decomposed", FIELDS, DecomposedVisitor(PhantomData))
@ -283,9 +292,10 @@ mod serde_de {
struct DecomposedVisitor<S: VectorSpace, R>(PhantomData<(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>,
R: Deserialize<'a>
R: Deserialize<'a>,
{
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>
where V: serde::de::MapAccess<'a>
where
V: serde::de::MapAccess<'a>,
{
let mut scale = None;
let mut rot = None;

View file

@ -14,7 +14,7 @@
// limitations under the License.
use rand::{Rand, Rng};
use num_traits::{NumCast, Bounded};
use num_traits::{Bounded, NumCast};
use std::fmt;
use std::iter;
use std::mem;
@ -24,7 +24,7 @@ use structure::*;
use angle::Rad;
use approx::ApproxEq;
use num::{BaseNum, BaseFloat};
use num::{BaseFloat, BaseNum};
#[cfg(feature = "simd")]
use simd::f32x4 as Simdf32x4;
@ -659,11 +659,12 @@ impl<S: BaseNum> Vector3<S> {
/// Returns the cross product of the vector and `other`.
#[inline]
#[must_use]
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.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
@ -731,7 +732,8 @@ impl<S: BaseNum> Vector4<S> {
/// Dot product of two vectors.
#[inline]
pub fn dot<V: InnerSpace>(a: V, b: V) -> V::Scalar
where V::Scalar: BaseFloat
where
V::Scalar: BaseFloat,
{
V::dot(a, b)
}
@ -841,8 +843,6 @@ impl Vector4<f32> {
}
}
#[cfg(feature = "simd")]
impl Into<Simdf32x4> for Vector4<f32> {
#[inline]
@ -888,8 +888,6 @@ impl_operator_simd!{@rs
}
}
#[cfg(feature = "simd")]
impl_operator_simd!{
[Simdf32x4]; Neg for Vector4<f32> {
@ -939,27 +937,46 @@ impl DivAssign<f32> for Vector4<f32> {
#[cfg(feature = "simd")]
impl ElementWise for Vector4<f32> {
#[inline] fn add_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> {
#[inline]
fn add_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 rhs: Simdf32x4 = 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 rhs: Simdf32x4 = rhs.into();
(s / rhs).into()
}
#[inline] fn add_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>) {
#[inline]
fn add_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 rhs: Simdf32x4 = 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 rhs: Simdf32x4 = rhs.into();
*self = (s * rhs).into();
@ -968,31 +985,53 @@ impl ElementWise for Vector4<f32> {
#[cfg(feature = "simd")]
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 rhs = Simdf32x4::splat(rhs);
(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 rhs = Simdf32x4::splat(rhs);
(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 rhs = Simdf32x4::splat(rhs);
*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 rhs = Simdf32x4::splat(rhs);
*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")]
@ -1171,7 +1210,6 @@ impl_mint_conversions!(Vector3 { x, y, z }, Vector3);
#[cfg(feature = "mint")]
impl_mint_conversions!(Vector4 { x, y, z, w }, Vector4);
#[cfg(test)]
mod tests {
mod vector2 {

View file

@ -17,7 +17,7 @@
extern crate approx;
extern crate cgmath;
use cgmath::{Rad, Deg};
use cgmath::{Deg, Rad};
#[test]
fn test_conv() {
@ -43,8 +43,14 @@ mod rad {
#[test]
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!(Rad(2.0) + Rad(3.0) + Rad(4.0), [Rad(2.0), Rad(3.0), Rad(4.0)].iter().cloned().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!(
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]
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!(Deg(2.0) + Deg(3.0) + Deg(4.0), [Deg(2.0), Deg(3.0), Deg(4.0)].iter().cloned().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!(
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]
fn test_cast() {
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!(Point3::new(1.0f64, 2.4, -3.13).cast().unwrap(), Point3::new(1.0f32, 2.4, -3.13));
assert_ulps_eq!(
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;
use cgmath::{Vector4, ortho, Matrix4};
use cgmath::{ortho, Matrix4, Vector4};
#[test]
fn test_ortho_scale() {
@ -36,7 +36,6 @@ fn test_ortho_scale() {
assert_eq!(orig, Vector4::new(0f32, 0., 0., 1.));
assert_eq!(far, Vector4::new(1f32, 1., -1., 1.));
let o: Matrix4<f32> = ortho(-2., 2., -2., 2., -2., 2.);
let near = o * vec_near;
let orig = o * vec_orig;

View file

@ -44,19 +44,45 @@ mod operators {
#[test]
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]
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]
fn test_iter_sum() {
let q1 = Quaternion::from(Euler { x: 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) });
let q1 = Quaternion::from(Euler {
x: 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().cloned().sum());
@ -64,9 +90,21 @@ mod operators {
#[test]
fn test_iter_product() {
let q1 = Quaternion::from(Euler { x: 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) });
let q1 = Quaternion::from(Euler {
x: 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().cloned().product());
@ -79,22 +117,103 @@ mod to_from_euler {
use cgmath::*;
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;
#[test] fn test_zero() { check_euler(Euler { x: Rad( 0f32), y: Rad( 0f32), z: Rad( 0f32) }); }
#[test] fn test_yaw_pos_1() { 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) }); }
#[test]
fn test_zero() {
check_euler(Euler {
x: Rad(0f32),
y: Rad(0f32),
z: Rad(0f32),
});
}
#[test]
fn test_yaw_pos_1() {
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 {
@ -206,7 +325,6 @@ mod rotate_from_euler {
assert_ulps_eq!(vec3(0.0, -1.0, 0.0), rot * vec);
}
// tests that the Y rotation is done after the X
#[test]
fn test_x_then_y() {
@ -258,7 +376,10 @@ mod rotate_from_axis_angle {
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));
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]
@ -266,7 +387,10 @@ mod rotate_from_axis_angle {
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));
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]
@ -274,7 +398,10 @@ mod rotate_from_axis_angle {
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));
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]
fn test_cast() {
assert_ulps_eq!(Quaternion::new(0.9f64, 1.5, 2.4, 7.6).cast().unwrap(),
Quaternion::new(0.9f32, 1.5, 2.4, 7.6));
assert_ulps_eq!(
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),
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);
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),
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));
}
@ -68,7 +70,8 @@ fn test_serialize() {
};
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);
}

View file

@ -25,14 +25,26 @@ use std::iter;
fn test_constructor() {
assert_eq!(vec2(1f32, 2f32), Vector2::new(1f32, 2f32));
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]
fn test_from_value() {
assert_eq!(Vector2::from_value(102isize), 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));
assert_eq!(
Vector2::from_value(102isize),
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 {
@ -132,8 +144,14 @@ fn test_rem() {
#[test]
fn test_dot() {
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!(Vector4::new(1.0, 2.0, 3.0, 4.0).dot(Vector4::new(5.0, 6.0, 7.0, 8.0)), 70.0);
assert_eq!(
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]
@ -149,7 +167,12 @@ fn test_sum() {
#[test]
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!(Vector2 { x, y }, f32, 2.0f32, vec2(2.0f32, 4.0));
@ -162,11 +185,17 @@ fn test_iter_sum() {
fn test_product() {
assert_eq!(Vector2::new(1isize, 2isize).product(), 2isize);
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!(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]
@ -180,8 +209,17 @@ fn test_cross() {
#[test]
fn test_is_perpendicular() {
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!(Vector4::new(1.0f64, 0.0f64, 0.0f64, 0.0f64).is_perpendicular(Vector4::new(0.0f64, 0.0f64, 0.0f64, 1.0f64)));
assert!(
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)]
@ -227,37 +265,106 @@ mod test_magnitude {
#[test]
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!(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!(
Vector2::new(1.0f64, 0.0f64).angle(Vector2::new(0.0f64, 1.0f64)),
&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!(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!(
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!(
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!(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));
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!(
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]
fn test_normalize() {
// 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!(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));
assert_ulps_eq!(
Vector2::new(3.0f64, 4.0f64).normalize(),
&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]
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!(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));
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!(
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]
fn test_cast() {
assert_ulps_eq!(Vector2::new(0.9f64, 1.5).cast().unwrap(), 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));
assert_ulps_eq!(
Vector2::new(0.9f64, 1.5).cast().unwrap(),
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]
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]
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 {
@ -84,32 +90,60 @@ macro_rules! impl_test_rem {
#[test]
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]
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]
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]
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]
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]
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]
@ -123,12 +157,22 @@ fn test_sum() {
fn test_product() {
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]
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)]
@ -150,26 +194,69 @@ mod test_magnitude {
{
let a = Vector4::new(1f32, 4f32, 9f32, 16f32);
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!(a.rsqrt_element_wide(), Vector4::new(1f32, 1f32/2f32, 1f32/3f32, 1f32/4f32), max_relative= 0.005f32);
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!(
a.rsqrt_element_wide(),
Vector4::new(1f32, 1f32 / 2f32, 1f32 / 3f32, 1f32 / 4f32),
max_relative = 0.005f32
);
}
}
}
#[test]
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!(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));
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!(
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]
fn test_normalize() {
// 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]
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)
);
}