495: Mat3 constructors enhancement r=kvark a=AndreaCatania

The reason of this PR is because I need to transform thing in a 2d plane, and these functions are really handy.

- Added to the Mat3 the possibility to be constructed from a translation vector, similarly to the Mat4.
- Added unit tests.

Co-authored-by: Andrea Catania <info@andreacatania.com>
This commit is contained in:
bors[bot] 2019-11-05 15:03:30 +00:00 committed by GitHub
commit 50a345b7c4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
25 changed files with 840 additions and 444 deletions

View file

@ -28,9 +28,7 @@ macro_rules! bench_binop {
bh.iter(|| { bh.iter(|| {
i = (i + 1) & (LEN - 1); i = (i + 1) & (LEN - 1);
unsafe { unsafe { test::black_box(elems1.get_unchecked(i).$binop(*elems2.get_unchecked(i))) }
test::black_box(elems1.get_unchecked(i).$binop(*elems2.get_unchecked(i)))
}
}) })
} }
}; };
@ -50,9 +48,7 @@ macro_rules! bench_unop {
bh.iter(|| { bh.iter(|| {
i = (i + 1) & (LEN - 1); i = (i + 1) & (LEN - 1);
unsafe { unsafe { test::black_box(elems.get_unchecked_mut(i).$unop()) }
test::black_box(elems.get_unchecked_mut(i).$unop())
}
}) })
} }
}; };

View file

@ -20,9 +20,9 @@ extern crate cgmath;
extern crate rand; extern crate rand;
extern crate test; extern crate test;
use rand::{IsaacRng, Rng, FromEntropy};
use test::Bencher;
use cgmath::*; use cgmath::*;
use rand::{FromEntropy, IsaacRng, Rng};
use test::Bencher;
#[path = "common/macros.rs"] #[path = "common/macros.rs"]
#[macro_use] #[macro_use]

View file

@ -20,7 +20,7 @@ extern crate cgmath;
extern crate rand; extern crate rand;
extern crate test; extern crate test;
use rand::{IsaacRng, Rng, FromEntropy}; use rand::{FromEntropy, IsaacRng, Rng};
use std::ops::*; use std::ops::*;
use test::Bencher; use test::Bencher;

View file

@ -19,7 +19,7 @@ extern crate cgmath;
extern crate rand; extern crate rand;
extern crate test; extern crate test;
use rand::{IsaacRng, Rng, FromEntropy}; use rand::{FromEntropy, IsaacRng, Rng};
use std::ops::*; use std::ops::*;
use test::Bencher; use test::Bencher;

View file

@ -20,7 +20,7 @@ extern crate cgmath;
extern crate rand; extern crate rand;
extern crate test; extern crate test;
use rand::{IsaacRng, Rng, FromEntropy}; use rand::{FromEntropy, IsaacRng, Rng};
use std::ops::*; use std::ops::*;
use test::Bencher; use test::Bencher;

View file

@ -1,7 +1,7 @@
use std::env;
use std::fs::File; use std::fs::File;
use std::io::Write; use std::io::Write;
use std::path::Path; use std::path::Path;
use std::env;
use std::string::String; use std::string::String;
/// Generate the name of the swizzle function and what it returns. /// Generate the name of the swizzle function and what it returns.
@ -11,14 +11,18 @@ fn gen_swizzle_nth<'a>(variables: &'a str, mut i: usize, upto: usize) -> Option<
debug_assert!(i > 0); // zeroth permutation is empty debug_assert!(i > 0); // zeroth permutation is empty
let mut swizzle_impl = String::new(); let mut swizzle_impl = String::new();
let mut swizzle = String::new(); let mut swizzle = String::new();
let n = variables.len()+1; let n = variables.len() + 1;
for _ in 0..upto { for _ in 0..upto {
if i == 0 { break; } if i == 0 {
if i % n == 0 { return None; } break;
let c = variables.as_bytes()[i%n - 1] as char; }
if i % n == 0 {
return None;
}
let c = variables.as_bytes()[i % n - 1] as char;
swizzle.push(c); swizzle.push(c);
swizzle_impl.push_str(&format!("self.{}, ", c)); swizzle_impl.push_str(&format!("self.{}, ", c));
i = i/n; i = i / n;
} }
Some((swizzle, swizzle_impl)) Some((swizzle, swizzle_impl))
} }
@ -31,15 +35,16 @@ fn gen_swizzle_nth<'a>(variables: &'a str, mut i: usize, upto: usize) -> Option<
#[cfg(feature = "swizzle")] #[cfg(feature = "swizzle")]
fn gen_swizzle_functions(variables: &'static str, upto: usize) -> String { fn gen_swizzle_functions(variables: &'static str, upto: usize) -> String {
let mut result = String::new(); let mut result = String::new();
let nn = (variables.len()+1).pow(upto as u32); let nn = (variables.len() + 1).pow(upto as u32);
for i in 1..nn { for i in 1..nn {
if let Some((swizzle_name, swizzle_impl)) = gen_swizzle_nth(variables, i, upto) { if let Some((swizzle_name, swizzle_impl)) = gen_swizzle_nth(variables, i, upto) {
let dim = format!("{}", swizzle_name.len()); let dim = format!("{}", swizzle_name.len());
result.push_str( result.push_str(&format!(
&format!(" "
/// Swizzle operator that creates a new type with dimension {2} from variables `{0}`. /// Swizzle operator that creates a new type with dimension {2} from variables `{0}`.
#[inline] pub fn {0}(&self) -> $vector_type{2}<$S> {{ $vector_type{2}::new({1}) }}\n", #[inline] pub fn {0}(&self) -> $vector_type{2}<$S> {{ $vector_type{2}::new({1}) }}\n",
swizzle_name, swizzle_impl, dim)); swizzle_name, swizzle_impl, dim
));
} }
} }
result result
@ -50,7 +55,6 @@ fn gen_swizzle_functions(_: &'static str, _: usize) -> String {
String::new() String::new()
} }
/// This script generates the macro for building swizzle operators for multidimensional /// This script generates the macro for building swizzle operators for multidimensional
/// vectors and points. This macro is included in macros.rs /// vectors and points. This macro is included in macros.rs
fn main() { fn main() {
@ -92,5 +96,6 @@ macro_rules! impl_swizzle_functions {{
xyzw4 = gen_swizzle_functions("xyzw", 4)); xyzw4 = gen_swizzle_functions("xyzw", 4));
let mut f = File::create(swizzle_file_path) let mut f = File::create(swizzle_file_path)
.expect("Unable to create file that defines the swizzle operator macro."); .expect("Unable to create file that defines the swizzle operator macro.");
f.write_all(data.as_bytes()).expect("Unable to write swizzle operator macro."); f.write_all(data.as_bytes())
.expect("Unable to write swizzle operator macro.");
} }

View file

@ -15,17 +15,17 @@
//! Angle units for type-safe, self-documenting code. //! Angle units for type-safe, self-documenting code.
use std::fmt;
use std::f64; use std::f64;
use std::fmt;
use std::iter; use std::iter;
use std::ops::*; use std::ops::*;
use num_traits::{cast, Bounded};
#[cfg(feature = "rand")] #[cfg(feature = "rand")]
use rand::{ use rand::{
distributions::{uniform::SampleUniform, Distribution, Standard},
Rng, Rng,
distributions::{Distribution, Standard, uniform::SampleUniform},
}; };
use num_traits::{cast, Bounded};
use structure::*; use structure::*;

View file

@ -13,21 +13,21 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use num_traits::cast;
#[cfg(feature = "rand")] #[cfg(feature = "rand")]
use rand::{ use rand::{
Rng,
distributions::{Distribution, Standard}, distributions::{Distribution, Standard},
Rng,
}; };
use num_traits::cast;
use structure::*; use structure::*;
use angle::Rad; use angle::Rad;
use approx; use approx;
use quaternion::Quaternion;
#[cfg(feature = "mint")] #[cfg(feature = "mint")]
use mint; use mint;
use num::BaseFloat; use num::BaseFloat;
use quaternion::Quaternion;
/// A set of [Euler angles] representing a rotation in three-dimensional space. /// A set of [Euler angles] representing a rotation in three-dimensional space.
/// ///
@ -191,8 +191,10 @@ impl<A: Angle> approx::UlpsEq for Euler<A> {
#[cfg(feature = "rand")] #[cfg(feature = "rand")]
impl<A> Distribution<Euler<A>> for Standard impl<A> Distribution<Euler<A>> for Standard
where Standard: Distribution<A>, where
A: Angle { Standard: Distribution<A>,
A: Angle,
{
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Euler<A> { fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Euler<A> {
Euler { Euler {
x: rng.gen(), x: rng.gen(),

View file

@ -58,9 +58,9 @@ extern crate approx;
#[cfg(feature = "mint")] #[cfg(feature = "mint")]
pub extern crate mint; pub extern crate mint;
pub extern crate num_traits;
#[cfg(feature = "rand")] #[cfg(feature = "rand")]
extern crate rand; extern crate rand;
pub extern crate num_traits;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
#[macro_use] #[macro_use]
@ -77,11 +77,11 @@ pub use structure::*;
pub use matrix::{Matrix2, Matrix3, Matrix4}; pub use matrix::{Matrix2, Matrix3, Matrix4};
pub use quaternion::Quaternion; pub use quaternion::Quaternion;
pub use vector::{dot, Vector1, Vector2, Vector3, Vector4, vec1, vec2, vec3, vec4}; pub use vector::{dot, vec1, vec2, vec3, vec4, Vector1, Vector2, Vector3, Vector4};
pub use angle::{Deg, Rad}; pub use angle::{Deg, Rad};
pub use euler::Euler; pub use euler::Euler;
pub use point::{Point1, Point2, Point3, point1, point2, point3}; pub use point::{point1, point2, point3, Point1, Point2, Point3};
pub use rotation::*; pub use rotation::*;
pub use transform::*; pub use transform::*;

View file

@ -139,14 +139,30 @@ macro_rules! impl_assignment_operator {
} }
macro_rules! fold_array { macro_rules! fold_array {
(&$method:ident, { $x:expr }) => { *$x }; (&$method:ident, { $x:expr }) => {
(&$method:ident, { $x:expr, $y:expr }) => { $x.$method(&$y) }; *$x
(&$method:ident, { $x:expr, $y:expr, $z:expr }) => { $x.$method(&$y).$method(&$z) }; };
(&$method:ident, { $x:expr, $y:expr, $z:expr, $w:expr }) => { $x.$method(&$y).$method(&$z).$method(&$w) }; (&$method:ident, { $x:expr, $y:expr }) => {
($method:ident, { $x:expr }) => { $x }; $x.$method(&$y)
($method:ident, { $x:expr, $y:expr }) => { $x.$method($y) }; };
($method:ident, { $x:expr, $y:expr, $z:expr }) => { $x.$method($y).$method($z) }; (&$method:ident, { $x:expr, $y:expr, $z:expr }) => {
($method:ident, { $x:expr, $y:expr, $z:expr, $w:expr }) => { $x.$method($y).$method($z).$method($w) }; $x.$method(&$y).$method(&$z)
};
(&$method:ident, { $x:expr, $y:expr, $z:expr, $w:expr }) => {
$x.$method(&$y).$method(&$z).$method(&$w)
};
($method:ident, { $x:expr }) => {
$x
};
($method:ident, { $x:expr, $y:expr }) => {
$x.$method($y)
};
($method:ident, { $x:expr, $y:expr, $z:expr }) => {
$x.$method($y).$method($z)
};
($method:ident, { $x:expr, $y:expr, $z:expr, $w:expr }) => {
$x.$method($y).$method($z).$method($w)
};
} }
/// Generate array conversion implementations for a compound array type /// Generate array conversion implementations for a compound array type
@ -252,17 +268,19 @@ macro_rules! impl_index_operators {
#[inline] #[inline]
fn index<'a>(&'a self, i: $I) -> &'a $Output { fn index<'a>(&'a self, i: $I) -> &'a $Output {
let v: &[$S; $n] = self.as_ref(); &v[i] let v: &[$S; $n] = self.as_ref();
&v[i]
} }
} }
impl<$S> IndexMut<$I> for $VectorN<$S> { impl<$S> IndexMut<$I> for $VectorN<$S> {
#[inline] #[inline]
fn index_mut<'a>(&'a mut self, i: $I) -> &'a mut $Output { fn index_mut<'a>(&'a mut self, i: $I) -> &'a mut $Output {
let v: &mut [$S; $n] = self.as_mut(); &mut v[i] let v: &mut [$S; $n] = self.as_mut();
} &mut v[i]
} }
} }
};
} }
/// Generates a binary operator implementation for the permutations of by-ref and by-val, for simd /// Generates a binary operator implementation for the permutations of by-ref and by-val, for simd
@ -272,11 +290,11 @@ macro_rules! impl_operator_simd {
([$Simd:ident]; $Op:ident for $Lhs:ty { ([$Simd:ident]; $Op:ident for $Lhs:ty {
fn $op:ident($x:ident) -> $Output:ty { $body:expr } fn $op:ident($x:ident) -> $Output:ty { $body:expr }
}) => { }) => {
impl $Op for $Lhs { impl $Op for $Lhs {
#[inline] #[inline]
fn $op(self) -> $Output { fn $op(self) -> $Output {
let $x: $Simd = self.into(); $body let $x: $Simd = self.into();
$body
} }
} }
}; };
@ -287,15 +305,16 @@ macro_rules! impl_operator_simd {
impl $Op<$Rhs> for $Lhs { impl $Op<$Rhs> for $Lhs {
#[inline] #[inline]
fn $op(self, other: $Rhs) -> $Output { fn $op(self, other: $Rhs) -> $Output {
let ($lhs, $rhs): ($Simd, $Simd) = (self.into(), $Simd::splat(other)); $body let ($lhs, $rhs): ($Simd, $Simd) = (self.into(), $Simd::splat(other));
$body
} }
} }
impl<'a> $Op<$Rhs> for &'a $Lhs { impl<'a> $Op<$Rhs> for &'a $Lhs {
#[inline] #[inline]
fn $op(self, other: $Rhs) -> $Output { fn $op(self, other: $Rhs) -> $Output {
let ($lhs, $rhs): ($Simd, $Simd) = ((*self).into(), $Simd::splat(other)); $body let ($lhs, $rhs): ($Simd, $Simd) = ((*self).into(), $Simd::splat(other));
$body
} }
} }
}; };
@ -304,33 +323,35 @@ macro_rules! impl_operator_simd {
([$Simd:ident]; $Op:ident<$Rhs:ty> for $Lhs:ty { ([$Simd:ident]; $Op:ident<$Rhs:ty> for $Lhs:ty {
fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr } fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr }
}) => { }) => {
impl $Op<$Rhs> for $Lhs { impl $Op<$Rhs> for $Lhs {
#[inline] #[inline]
fn $op(self, other: $Rhs) -> $Output { fn $op(self, other: $Rhs) -> $Output {
let ($lhs, $rhs): ($Simd, $Simd) = (self.into(), other.into()); $body let ($lhs, $rhs): ($Simd, $Simd) = (self.into(), other.into());
$body
} }
} }
impl<'a> $Op<&'a $Rhs> for $Lhs { impl<'a> $Op<&'a $Rhs> for $Lhs {
#[inline] #[inline]
fn $op(self, other: &'a $Rhs) -> $Output { fn $op(self, other: &'a $Rhs) -> $Output {
let ($lhs, $rhs): ($Simd, $Simd) = (self.into(), (*other).into()); $body let ($lhs, $rhs): ($Simd, $Simd) = (self.into(), (*other).into());
$body
} }
} }
impl<'a> $Op<$Rhs> for &'a $Lhs { impl<'a> $Op<$Rhs> for &'a $Lhs {
#[inline] #[inline]
fn $op(self, other: $Rhs) -> $Output { fn $op(self, other: $Rhs) -> $Output {
let ($lhs, $rhs): ($Simd, $Simd) = ((*self).into(), other.into()); $body let ($lhs, $rhs): ($Simd, $Simd) = ((*self).into(), other.into());
$body
} }
} }
impl<'a, 'b> $Op<&'a $Rhs> for &'b $Lhs { impl<'a, 'b> $Op<&'a $Rhs> for &'b $Lhs {
#[inline] #[inline]
fn $op(self, other: &'a $Rhs) -> $Output { fn $op(self, other: &'a $Rhs) -> $Output {
let ($lhs, $rhs): ($Simd, $Simd) = ((*self).into(), (*other).into()); $body let ($lhs, $rhs): ($Simd, $Simd) = ((*self).into(), (*other).into());
$body
} }
} }
}; };
@ -342,14 +363,16 @@ macro_rules! impl_operator_simd {
impl $Op<$Rhs> for $Lhs { impl $Op<$Rhs> for $Lhs {
#[inline] #[inline]
fn $op(self, other: $Rhs) -> $Output { fn $op(self, other: $Rhs) -> $Output {
let ($lhs, $rhs): ($Simd, $Simd) = ($Simd::splat(self), other.into()); $body let ($lhs, $rhs): ($Simd, $Simd) = ($Simd::splat(self), other.into());
$body
} }
} }
impl<'a> $Op<&'a $Rhs> for $Lhs { impl<'a> $Op<&'a $Rhs> for $Lhs {
#[inline] #[inline]
fn $op(self, other: &'a $Rhs) -> $Output { fn $op(self, other: &'a $Rhs) -> $Output {
let ($lhs, $rhs): ($Simd, $Simd) = ($Simd::splat(self), (*other).into()); $body let ($lhs, $rhs): ($Simd, $Simd) = ($Simd::splat(self), (*other).into());
$body
} }
} }
}; };

View file

@ -13,12 +13,12 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use num_traits::{cast, NumCast};
#[cfg(feature = "rand")] #[cfg(feature = "rand")]
use rand::{ use rand::{
distributions::{Distribution, Standard},
Rng, Rng,
distributions::{Standard, Distribution},
}; };
use num_traits::{cast, NumCast};
use std::fmt; use std::fmt;
use std::iter; use std::iter;
use std::mem; use std::mem;
@ -159,6 +159,34 @@ impl<S> Matrix3<S> {
} }
impl<S: BaseFloat> Matrix3<S> { impl<S: BaseFloat> Matrix3<S> {
/// Create a homogeneous transformation matrix from a translation vector.
#[inline]
pub fn from_translation(v: Vector2<S>) -> Matrix3<S> {
#[cfg_attr(rustfmt, rustfmt_skip)]
Matrix3::new(
S::one(), S::zero(), S::zero(),
S::zero(), S::one(), S::zero(),
v.x, v.y, S::one(),
)
}
/// Create a homogeneous transformation matrix from a scale value.
#[inline]
pub fn from_scale(value: S) -> Matrix3<S> {
Matrix3::from_nonuniform_scale(value, value)
}
/// Create a homogeneous transformation matrix from a set of scale values.
#[inline]
pub fn from_nonuniform_scale(x: S, y: S) -> Matrix3<S> {
#[cfg_attr(rustfmt, rustfmt_skip)]
Matrix3::new(
x, S::zero(), S::zero(),
S::zero(), y, S::zero(),
S::zero(), S::zero(), S::one(),
)
}
/// Create a rotation matrix that will cause a vector to point at /// Create a rotation matrix that will cause a vector to point at
/// `dir`, using `up` for orientation. /// `dir`, using `up` for orientation.
pub fn look_at(dir: Vector3<S>, up: Vector3<S>) -> Matrix3<S> { pub fn look_at(dir: Vector3<S>, up: Vector3<S>) -> Matrix3<S> {
@ -257,7 +285,12 @@ impl<S> Matrix4<S> {
/// Create a new matrix, providing columns. /// Create a new matrix, providing columns.
#[inline] #[inline]
pub const fn from_cols(c0: Vector4<S>, c1: Vector4<S>, c2: Vector4<S>, c3: Vector4<S>) -> Matrix4<S> { pub const fn from_cols(
c0: Vector4<S>,
c1: Vector4<S>,
c2: Vector4<S>,
c3: Vector4<S>,
) -> Matrix4<S> {
Matrix4 { Matrix4 {
x: c0, x: c0,
y: c1, y: c1,
@ -668,21 +701,28 @@ impl<S: BaseFloat> SquareMatrix for Matrix3<S> {
self[1].cross(self[2]) / det, self[1].cross(self[2]) / det,
self[2].cross(self[0]) / det, self[2].cross(self[0]) / det,
self[0].cross(self[1]) / det, self[0].cross(self[1]) / det,
).transpose(), )
.transpose(),
) )
} }
} }
fn is_diagonal(&self) -> bool { fn is_diagonal(&self) -> bool {
ulps_eq!(self[0][1], &S::zero()) && ulps_eq!(self[0][2], &S::zero()) ulps_eq!(self[0][1], &S::zero())
&& ulps_eq!(self[1][0], &S::zero()) && ulps_eq!(self[1][2], &S::zero()) && ulps_eq!(self[0][2], &S::zero())
&& ulps_eq!(self[2][0], &S::zero()) && ulps_eq!(self[2][1], &S::zero()) && ulps_eq!(self[1][0], &S::zero())
&& ulps_eq!(self[1][2], &S::zero())
&& ulps_eq!(self[2][0], &S::zero())
&& ulps_eq!(self[2][1], &S::zero())
} }
fn is_symmetric(&self) -> bool { fn is_symmetric(&self) -> bool {
ulps_eq!(self[0][1], &self[1][0]) && ulps_eq!(self[0][2], &self[2][0]) ulps_eq!(self[0][1], &self[1][0])
&& ulps_eq!(self[1][0], &self[0][1]) && ulps_eq!(self[1][2], &self[2][1]) && ulps_eq!(self[0][2], &self[2][0])
&& ulps_eq!(self[2][0], &self[0][2]) && ulps_eq!(self[2][1], &self[1][2]) && ulps_eq!(self[1][0], &self[0][1])
&& ulps_eq!(self[1][2], &self[2][1])
&& ulps_eq!(self[2][0], &self[0][2])
&& ulps_eq!(self[2][1], &self[1][2])
} }
} }
@ -835,21 +875,33 @@ impl<S: BaseFloat> SquareMatrix for Matrix4<S> {
} }
fn is_diagonal(&self) -> bool { fn is_diagonal(&self) -> bool {
ulps_eq!(self[0][1], &S::zero()) && ulps_eq!(self[0][2], &S::zero()) ulps_eq!(self[0][1], &S::zero())
&& ulps_eq!(self[0][3], &S::zero()) && ulps_eq!(self[1][0], &S::zero()) && ulps_eq!(self[0][2], &S::zero())
&& ulps_eq!(self[1][2], &S::zero()) && ulps_eq!(self[1][3], &S::zero()) && ulps_eq!(self[0][3], &S::zero())
&& ulps_eq!(self[2][0], &S::zero()) && ulps_eq!(self[2][1], &S::zero()) && ulps_eq!(self[1][0], &S::zero())
&& ulps_eq!(self[2][3], &S::zero()) && ulps_eq!(self[3][0], &S::zero()) && ulps_eq!(self[1][2], &S::zero())
&& ulps_eq!(self[3][1], &S::zero()) && ulps_eq!(self[3][2], &S::zero()) && ulps_eq!(self[1][3], &S::zero())
&& ulps_eq!(self[2][0], &S::zero())
&& ulps_eq!(self[2][1], &S::zero())
&& ulps_eq!(self[2][3], &S::zero())
&& ulps_eq!(self[3][0], &S::zero())
&& ulps_eq!(self[3][1], &S::zero())
&& ulps_eq!(self[3][2], &S::zero())
} }
fn is_symmetric(&self) -> bool { fn is_symmetric(&self) -> bool {
ulps_eq!(self[0][1], &self[1][0]) && ulps_eq!(self[0][2], &self[2][0]) ulps_eq!(self[0][1], &self[1][0])
&& ulps_eq!(self[0][3], &self[3][0]) && ulps_eq!(self[1][0], &self[0][1]) && ulps_eq!(self[0][2], &self[2][0])
&& ulps_eq!(self[1][2], &self[2][1]) && ulps_eq!(self[1][3], &self[3][1]) && ulps_eq!(self[0][3], &self[3][0])
&& ulps_eq!(self[2][0], &self[0][2]) && ulps_eq!(self[2][1], &self[1][2]) && ulps_eq!(self[1][0], &self[0][1])
&& ulps_eq!(self[2][3], &self[3][2]) && ulps_eq!(self[3][0], &self[0][3]) && ulps_eq!(self[1][2], &self[2][1])
&& ulps_eq!(self[3][1], &self[1][3]) && ulps_eq!(self[3][2], &self[2][3]) && ulps_eq!(self[1][3], &self[3][1])
&& ulps_eq!(self[2][0], &self[0][2])
&& ulps_eq!(self[2][1], &self[1][2])
&& ulps_eq!(self[2][3], &self[3][2])
&& ulps_eq!(self[3][0], &self[0][3])
&& ulps_eq!(self[3][1], &self[1][3])
&& ulps_eq!(self[3][2], &self[2][3])
} }
} }
@ -1266,7 +1318,7 @@ macro_rules! index_operators {
From::from(&mut v[i]) From::from(&mut v[i])
} }
} }
} };
} }
index_operators!(Matrix2<S>, 2, Vector2<S>, usize); index_operators!(Matrix2<S>, 2, Vector2<S>, usize);
@ -1553,9 +1605,10 @@ impl<S: fmt::Debug> fmt::Debug for Matrix4<S> {
#[cfg(feature = "rand")] #[cfg(feature = "rand")]
impl<S> Distribution<Matrix2<S>> for Standard impl<S> Distribution<Matrix2<S>> for Standard
where where
Standard: Distribution<Vector2<S>>, Standard: Distribution<Vector2<S>>,
S: BaseFloat { S: BaseFloat,
{
#[inline] #[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Matrix2<S> { fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Matrix2<S> {
Matrix2 { Matrix2 {
@ -1567,8 +1620,10 @@ impl<S> Distribution<Matrix2<S>> for Standard
#[cfg(feature = "rand")] #[cfg(feature = "rand")]
impl<S> Distribution<Matrix3<S>> for Standard impl<S> Distribution<Matrix3<S>> for Standard
where Standard: Distribution<Vector3<S>>, where
S: BaseFloat { Standard: Distribution<Vector3<S>>,
S: BaseFloat,
{
#[inline] #[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Matrix3<S> { fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Matrix3<S> {
Matrix3 { Matrix3 {
@ -1581,8 +1636,10 @@ impl<S> Distribution<Matrix3<S>> for Standard
#[cfg(feature = "rand")] #[cfg(feature = "rand")]
impl<S> Distribution<Matrix4<S>> for Standard impl<S> Distribution<Matrix4<S>> for Standard
where Standard: Distribution<Vector4<S>>, where
S: BaseFloat { Standard: Distribution<Vector4<S>>,
S: BaseFloat,
{
#[inline] #[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Matrix4<S> { fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Matrix4<S> {
Matrix4 { Matrix4 {

View file

@ -36,8 +36,7 @@ pub trait BaseNum:
{ {
} }
impl<T> BaseNum for T impl<T> BaseNum for T where
where
T: Copy T: Copy
+ Clone + Clone
+ fmt::Debug + fmt::Debug
@ -48,7 +47,7 @@ where
+ SubAssign + SubAssign
+ MulAssign + MulAssign
+ DivAssign + DivAssign
+ RemAssign, + RemAssign
{ {
} }
@ -62,12 +61,11 @@ pub trait BaseFloat:
{ {
} }
impl<T> BaseFloat for T impl<T> BaseFloat for T where
where
T: BaseNum T: BaseNum
+ Float + Float
+ approx::AbsDiffEq<Epsilon = Self> + approx::AbsDiffEq<Epsilon = Self>
+ approx::RelativeEq<Epsilon = Self> + approx::RelativeEq<Epsilon = Self>
+ approx::UlpsEq<Epsilon = Self>, + approx::UlpsEq<Epsilon = Self>
{ {
} }

View file

@ -13,8 +13,8 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use num_traits::Zero;
use num_traits::cast; use num_traits::cast;
use num_traits::Zero;
use structure::Angle; use structure::Angle;
@ -38,7 +38,8 @@ pub fn perspective<S: BaseFloat, A: Into<Rad<S>>>(
aspect: aspect, aspect: aspect,
near: near, near: near,
far: far, far: far,
}.into() }
.into()
} }
/// Create a perspective matrix from a view frustum. /// Create a perspective matrix from a view frustum.
@ -54,7 +55,8 @@ pub fn frustum<S: BaseFloat>(left: S, right: S, bottom: S, top: S, near: S, far:
top: top, top: top,
near: near, near: near,
far: far, far: far,
}.into() }
.into()
} }
/// Create an orthographic projection matrix. /// Create an orthographic projection matrix.
@ -70,7 +72,8 @@ pub fn ortho<S: BaseFloat>(left: S, right: S, bottom: S, top: S, near: S, far: S
top: top, top: top,
near: near, near: near,
far: far, far: far,
}.into() }
.into()
} }
/// A perspective projection based on a vertical field-of-view angle. /// A perspective projection based on a vertical field-of-view angle.

View file

@ -17,12 +17,12 @@ use std::iter;
use std::mem; use std::mem;
use std::ops::*; use std::ops::*;
use num_traits::{cast, NumCast};
#[cfg(feature = "rand")] #[cfg(feature = "rand")]
use rand::{ use rand::{
Rng,
distributions::{Distribution, Standard}, distributions::{Distribution, Standard},
Rng,
}; };
use num_traits::{cast, NumCast};
use structure::*; use structure::*;
@ -626,17 +626,19 @@ macro_rules! index_operators {
#[inline] #[inline]
fn index<'a>(&'a self, i: $I) -> &'a $Output { fn index<'a>(&'a self, i: $I) -> &'a $Output {
let v: &[$S; 4] = self.as_ref(); &v[i] let v: &[$S; 4] = self.as_ref();
&v[i]
} }
} }
impl<$S: BaseFloat> IndexMut<$I> for Quaternion<$S> { impl<$S: BaseFloat> IndexMut<$I> for Quaternion<$S> {
#[inline] #[inline]
fn index_mut<'a>(&'a mut self, i: $I) -> &'a mut $Output { fn index_mut<'a>(&'a mut self, i: $I) -> &'a mut $Output {
let v: &mut [$S; 4] = self.as_mut(); &mut v[i] let v: &mut [$S; 4] = self.as_mut();
} &mut v[i]
} }
} }
};
} }
index_operators!(S, S, usize); index_operators!(S, S, usize);
@ -647,9 +649,11 @@ index_operators!(S, [S], RangeFull);
#[cfg(feature = "rand")] #[cfg(feature = "rand")]
impl<S> Distribution<Quaternion<S>> for Standard impl<S> Distribution<Quaternion<S>> for Standard
where Standard: Distribution<S>, where
Standard: Distribution<S>,
Standard: Distribution<Vector3<S>>, Standard: Distribution<Vector3<S>>,
S: BaseFloat { S: BaseFloat,
{
#[inline] #[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Quaternion<S> { fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Quaternion<S> {
Quaternion::from_sv(rng.gen(), rng.gen()) Quaternion::from_sv(rng.gen(), rng.gen())

View file

@ -54,7 +54,7 @@ impl InnerSpace for Quaternion<f32> {
} }
} }
impl_operator_simd!{ impl_operator_simd! {
[Simdf32x4]; Neg for Quaternion<f32> { [Simdf32x4]; Neg for Quaternion<f32> {
fn neg(lhs) -> Quaternion<f32> { fn neg(lhs) -> Quaternion<f32> {
(-lhs).into() (-lhs).into()
@ -62,7 +62,7 @@ impl_operator_simd!{
} }
} }
impl_operator_simd!{@rs impl_operator_simd! {@rs
[Simdf32x4]; Mul<f32> for Quaternion<f32> { [Simdf32x4]; Mul<f32> for Quaternion<f32> {
fn mul(lhs, rhs) -> Quaternion<f32> { fn mul(lhs, rhs) -> Quaternion<f32> {
(lhs * rhs).into() (lhs * rhs).into()
@ -78,7 +78,7 @@ impl MulAssign<f32> for Quaternion<f32> {
} }
} }
impl_operator_simd!{@rs impl_operator_simd! {@rs
[Simdf32x4]; Div<f32> for Quaternion<f32> { [Simdf32x4]; Div<f32> for Quaternion<f32> {
fn div(lhs, rhs) -> Quaternion<f32> { fn div(lhs, rhs) -> Quaternion<f32> {
(lhs / rhs).into() (lhs / rhs).into()
@ -94,7 +94,7 @@ impl DivAssign<f32> for Quaternion<f32> {
} }
} }
impl_operator_simd!{ impl_operator_simd! {
[Simdf32x4]; Add<Quaternion<f32>> for Quaternion<f32> { [Simdf32x4]; Add<Quaternion<f32>> for Quaternion<f32> {
fn add(lhs, rhs) -> Quaternion<f32> { fn add(lhs, rhs) -> Quaternion<f32> {
(lhs + rhs).into() (lhs + rhs).into()
@ -111,7 +111,7 @@ impl AddAssign for Quaternion<f32> {
} }
} }
impl_operator_simd!{ impl_operator_simd! {
[Simdf32x4]; Sub<Quaternion<f32>> for Quaternion<f32> { [Simdf32x4]; Sub<Quaternion<f32>> for Quaternion<f32> {
fn sub(lhs, rhs) -> Quaternion<f32> { fn sub(lhs, rhs) -> Quaternion<f32> {
(lhs - rhs).into() (lhs - rhs).into()
@ -128,7 +128,7 @@ impl SubAssign for Quaternion<f32> {
} }
} }
impl_operator_simd!{ impl_operator_simd! {
[Simdf32x4]; Mul<Quaternion<f32>> for Quaternion<f32> { [Simdf32x4]; Mul<Quaternion<f32>> for Quaternion<f32> {
fn mul(lhs, rhs) -> Quaternion<f32> { fn mul(lhs, rhs) -> Quaternion<f32> {
{ {

View file

@ -62,17 +62,18 @@ where
} }
/// A two-dimensional rotation. /// A two-dimensional rotation.
pub trait Rotation2<S: BaseFloat> pub trait Rotation2<S: BaseFloat>:
: Rotation<Point2<S>> + Into<Matrix2<S>> + Into<Basis2<S>> { Rotation<Point2<S>> + Into<Matrix2<S>> + Into<Basis2<S>>
{
/// Create a rotation by a given angle. Thus is a redundant case of both /// Create a rotation by a given angle. Thus is a redundant case of both
/// from_axis_angle() and from_euler() for 2D space. /// from_axis_angle() and from_euler() for 2D space.
fn from_angle<A: Into<Rad<S>>>(theta: A) -> Self; fn from_angle<A: Into<Rad<S>>>(theta: A) -> Self;
} }
/// A three-dimensional rotation. /// A three-dimensional rotation.
pub trait Rotation3<S: BaseFloat> pub trait Rotation3<S: BaseFloat>:
: Rotation<Point3<S>> + Into<Matrix3<S>> + Into<Basis3<S>> + Into<Quaternion<S>> + From<Euler<Rad<S>>> 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. /// Create a rotation using an angle around a given axis.
/// ///
/// The specified axis **must be normalized**, or it represents an invalid rotation. /// The specified axis **must be normalized**, or it represents an invalid rotation.

View file

@ -607,7 +607,11 @@ where
#[inline] #[inline]
fn normalize_signed(self) -> Self { fn normalize_signed(self) -> Self {
let rem = self.normalize(); let rem = self.normalize();
if Self::turn_div_2() < rem { rem - Self::full_turn() } else { rem } if Self::turn_div_2() < rem {
rem - Self::full_turn()
} else {
rem
}
} }
/// Return the angle rotated by half a turn. /// Return the angle rotated by half a turn.

View file

@ -225,10 +225,10 @@ where
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
#[doc(hidden)] #[doc(hidden)]
mod serde_ser { mod serde_ser {
use structure::VectorSpace;
use super::Decomposed; use super::Decomposed;
use serde::{self, Serialize};
use serde::ser::SerializeStruct; use serde::ser::SerializeStruct;
use serde::{self, Serialize};
use structure::VectorSpace;
impl<V, R> Serialize for Decomposed<V, R> impl<V, R> Serialize for Decomposed<V, R>
where where
@ -252,11 +252,11 @@ mod serde_ser {
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
#[doc(hidden)] #[doc(hidden)]
mod serde_de { mod serde_de {
use structure::VectorSpace;
use super::Decomposed; use super::Decomposed;
use serde::{self, Deserialize}; use serde::{self, Deserialize};
use std::marker::PhantomData;
use std::fmt; use std::fmt;
use std::marker::PhantomData;
use structure::VectorSpace;
enum DecomposedField { enum DecomposedField {
Scale, Scale,

View file

@ -13,12 +13,12 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
use num_traits::{Bounded, NumCast};
#[cfg(feature = "rand")] #[cfg(feature = "rand")]
use rand::{ use rand::{
Rng,
distributions::{Distribution, Standard}, distributions::{Distribution, Standard},
Rng,
}; };
use num_traits::{Bounded, NumCast};
use std::fmt; use std::fmt;
use std::iter; use std::iter;
use std::mem; use std::mem;

View file

@ -69,7 +69,7 @@ impl Into<Simdf32x4> for Vector4<f32> {
} }
} }
impl_operator_simd!{ impl_operator_simd! {
[Simdf32x4]; Add<Vector4<f32>> for Vector4<f32> { [Simdf32x4]; Add<Vector4<f32>> for Vector4<f32> {
fn add(lhs, rhs) -> Vector4<f32> { fn add(lhs, rhs) -> Vector4<f32> {
(lhs + rhs).into() (lhs + rhs).into()
@ -77,7 +77,7 @@ impl_operator_simd!{
} }
} }
impl_operator_simd!{ impl_operator_simd! {
[Simdf32x4]; Sub<Vector4<f32>> for Vector4<f32> { [Simdf32x4]; Sub<Vector4<f32>> for Vector4<f32> {
fn sub(lhs, rhs) -> Vector4<f32> { fn sub(lhs, rhs) -> Vector4<f32> {
(lhs - rhs).into() (lhs - rhs).into()
@ -85,7 +85,7 @@ impl_operator_simd!{
} }
} }
impl_operator_simd!{@rs impl_operator_simd! {@rs
[Simdf32x4]; Mul<f32> for Vector4<f32> { [Simdf32x4]; Mul<f32> for Vector4<f32> {
fn mul(lhs, rhs) -> Vector4<f32> { fn mul(lhs, rhs) -> Vector4<f32> {
(lhs * rhs).into() (lhs * rhs).into()
@ -93,7 +93,7 @@ impl_operator_simd!{@rs
} }
} }
impl_operator_simd!{@rs impl_operator_simd! {@rs
[Simdf32x4]; Div<f32> for Vector4<f32> { [Simdf32x4]; Div<f32> for Vector4<f32> {
fn div(lhs, rhs) -> Vector4<f32> { fn div(lhs, rhs) -> Vector4<f32> {
(lhs / rhs).into() (lhs / rhs).into()
@ -101,7 +101,7 @@ impl_operator_simd!{@rs
} }
} }
impl_operator_simd!{ impl_operator_simd! {
[Simdf32x4]; Neg for Vector4<f32> { [Simdf32x4]; Neg for Vector4<f32> {
fn neg(lhs) -> Vector4<f32> { fn neg(lhs) -> Vector4<f32> {
(-lhs).into() (-lhs).into()
@ -262,7 +262,7 @@ impl Into<Simdi32x4> for Vector4<i32> {
} }
} }
impl_operator_simd!{ impl_operator_simd! {
[Simdi32x4]; Add<Vector4<i32>> for Vector4<i32> { [Simdi32x4]; Add<Vector4<i32>> for Vector4<i32> {
fn add(lhs, rhs) -> Vector4<i32> { fn add(lhs, rhs) -> Vector4<i32> {
(lhs + rhs).into() (lhs + rhs).into()
@ -270,7 +270,7 @@ impl_operator_simd!{
} }
} }
impl_operator_simd!{ impl_operator_simd! {
[Simdi32x4]; Sub<Vector4<i32>> for Vector4<i32> { [Simdi32x4]; Sub<Vector4<i32>> for Vector4<i32> {
fn sub(lhs, rhs) -> Vector4<i32> { fn sub(lhs, rhs) -> Vector4<i32> {
(lhs - rhs).into() (lhs - rhs).into()
@ -278,7 +278,7 @@ impl_operator_simd!{
} }
} }
impl_operator_simd!{@rs impl_operator_simd! {@rs
[Simdi32x4]; Mul<i32> for Vector4<i32> { [Simdi32x4]; Mul<i32> for Vector4<i32> {
fn mul(lhs, rhs) -> Vector4<i32> { fn mul(lhs, rhs) -> Vector4<i32> {
(lhs * rhs).into() (lhs * rhs).into()
@ -286,7 +286,7 @@ impl_operator_simd!{@rs
} }
} }
impl_operator_simd!{ impl_operator_simd! {
[Simdi32x4]; Neg for Vector4<i32> { [Simdi32x4]; Neg for Vector4<i32> {
fn neg(lhs) -> Vector4<i32> { fn neg(lhs) -> Vector4<i32> {
(-lhs).into() (-lhs).into()
@ -342,7 +342,7 @@ impl Into<Simdu32x4> for Vector4<u32> {
} }
} }
impl_operator_simd!{ impl_operator_simd! {
[Simdu32x4]; Add<Vector4<u32>> for Vector4<u32> { [Simdu32x4]; Add<Vector4<u32>> for Vector4<u32> {
fn add(lhs, rhs) -> Vector4<u32> { fn add(lhs, rhs) -> Vector4<u32> {
(lhs + rhs).into() (lhs + rhs).into()
@ -350,7 +350,7 @@ impl_operator_simd!{
} }
} }
impl_operator_simd!{ impl_operator_simd! {
[Simdu32x4]; Sub<Vector4<u32>> for Vector4<u32> { [Simdu32x4]; Sub<Vector4<u32>> for Vector4<u32> {
fn sub(lhs, rhs) -> Vector4<u32> { fn sub(lhs, rhs) -> Vector4<u32> {
(lhs - rhs).into() (lhs - rhs).into()
@ -358,7 +358,7 @@ impl_operator_simd!{
} }
} }
impl_operator_simd!{@rs impl_operator_simd! {@rs
[Simdu32x4]; Mul<u32> for Vector4<u32> { [Simdu32x4]; Mul<u32> for Vector4<u32> {
fn mul(lhs, rhs) -> Vector4<u32> { fn mul(lhs, rhs) -> Vector4<u32> {
(lhs * rhs).into() (lhs * rhs).into()

File diff suppressed because it is too large Load diff

View file

@ -17,7 +17,7 @@ extern crate approx;
extern crate cgmath; extern crate cgmath;
macro_rules! impl_test_mul { macro_rules! impl_test_mul {
($s:expr, $v:expr) => ( ($s:expr, $v:expr) => {
// point * scalar ops // point * scalar ops
assert_eq!($v * $s, Quaternion::from_sv($v.s * $s, $v.v * $s)); assert_eq!($v * $s, Quaternion::from_sv($v.s * $s, $v.v * $s));
assert_eq!($s * $v, Quaternion::from_sv($s * $v.s, $s * $v.v)); assert_eq!($s * $v, Quaternion::from_sv($s * $v.s, $s * $v.v));
@ -25,17 +25,17 @@ macro_rules! impl_test_mul {
assert_eq!($s * &$v, $s * $v); assert_eq!($s * &$v, $s * $v);
// commutativity // commutativity
assert_eq!($v * $s, $s * $v); assert_eq!($v * $s, $s * $v);
) };
} }
macro_rules! impl_test_div { macro_rules! impl_test_div {
($s:expr, $v:expr) => ( ($s:expr, $v:expr) => {
// point / scalar ops // point / scalar ops
assert_eq!($v / $s, Quaternion::from_sv($v.s / $s, $v.v / $s)); assert_eq!($v / $s, Quaternion::from_sv($v.s / $s, $v.v / $s));
assert_eq!($s / $v, Quaternion::from_sv($s / $v.s, $s / $v.v)); assert_eq!($s / $v, Quaternion::from_sv($s / $v.s, $s / $v.v));
assert_eq!(&$v / $s, $v / $s); assert_eq!(&$v / $s, $v / $s);
assert_eq!($s / &$v, $s / $v); assert_eq!($s / &$v, $s / $v);
) };
} }
mod operators { mod operators {

View file

@ -29,7 +29,8 @@ fn test_invert() {
rot: Quaternion::new(0.5f64, 0.5, 0.5, 0.5), rot: Quaternion::new(0.5f64, 0.5, 0.5, 0.5),
disp: Vector3::new(6.0f64, -7.0, 8.0), disp: Vector3::new(6.0f64, -7.0, 8.0),
}; };
let ti = t.inverse_transform() let ti = t
.inverse_transform()
.expect("Expected successful inversion"); .expect("Expected successful inversion");
let vt = t.transform_vector(v); let vt = t.transform_vector(v);
assert_ulps_eq!(&v, &ti.transform_vector(vt)); assert_ulps_eq!(&v, &ti.transform_vector(vt));
@ -43,7 +44,8 @@ fn test_inverse_vector() {
rot: Quaternion::new(0.5f64, 0.5, 0.5, 0.5), rot: Quaternion::new(0.5f64, 0.5, 0.5, 0.5),
disp: Vector3::new(6.0f64, -7.0, 8.0), disp: Vector3::new(6.0f64, -7.0, 8.0),
}; };
let vt = t.inverse_transform_vector(v) let vt = t
.inverse_transform_vector(v)
.expect("Expected successful inversion"); .expect("Expected successful inversion");
assert_ulps_eq!(v, t.transform_vector(vt)); assert_ulps_eq!(v, t.transform_vector(vt));
} }

View file

@ -212,14 +212,8 @@ fn test_is_perpendicular() {
assert!( assert!(
Vector3::new(0.0f64, 1.0f64, 0.0f64).is_perpendicular(Vector3::new(0.0f64, 0.0f64, 1.0f64)) Vector3::new(0.0f64, 1.0f64, 0.0f64).is_perpendicular(Vector3::new(0.0f64, 0.0f64, 1.0f64))
); );
assert!( assert!(Vector4::new(1.0f64, 0.0f64, 0.0f64, 0.0f64)
Vector4::new(1.0f64, 0.0f64, 0.0f64, 0.0f64).is_perpendicular(Vector4::new( .is_perpendicular(Vector4::new(0.0f64, 0.0f64, 0.0f64, 1.0f64)));
0.0f64,
0.0f64,
0.0f64,
1.0f64
))
);
} }
#[cfg(test)] #[cfg(test)]
@ -292,30 +286,18 @@ fn test_angle() {
); );
assert_ulps_eq!( assert_ulps_eq!(
Vector4::new(1.0f64, 0.0f64, 1.0f64, 0.0f64).angle(Vector4::new( Vector4::new(1.0f64, 0.0f64, 1.0f64, 0.0f64)
0.0f64, .angle(Vector4::new(0.0f64, 1.0f64, 0.0f64, 1.0f64)),
1.0f64,
0.0f64,
1.0f64
)),
&Rad(f64::consts::FRAC_PI_2) &Rad(f64::consts::FRAC_PI_2)
); );
assert_ulps_eq!( assert_ulps_eq!(
Vector4::new(10.0f64, 0.0f64, 10.0f64, 0.0f64).angle(Vector4::new( Vector4::new(10.0f64, 0.0f64, 10.0f64, 0.0f64)
0.0f64, .angle(Vector4::new(0.0f64, 5.0f64, 0.0f64, 5.0f64)),
5.0f64,
0.0f64,
5.0f64
)),
&Rad(f64::consts::FRAC_PI_2) &Rad(f64::consts::FRAC_PI_2)
); );
assert_ulps_eq!( assert_ulps_eq!(
Vector4::new(-1.0f64, 0.0f64, -1.0f64, 0.0f64).angle(Vector4::new( Vector4::new(-1.0f64, 0.0f64, -1.0f64, 0.0f64)
0.0f64, .angle(Vector4::new(0.0f64, 1.0f64, 0.0f64, 1.0f64)),
1.0f64,
0.0f64,
1.0f64
)),
&Rad(f64::consts::FRAC_PI_2) &Rad(f64::consts::FRAC_PI_2)
); );
} }

View file

@ -135,12 +135,8 @@ fn test_rem() {
#[test] #[test]
fn test_dot() { fn test_dot() {
assert_eq!( assert_eq!(
Vector4::new(1.0f32, 2.0f32, 3.0f32, 4.0f32).dot(Vector4::new( Vector4::new(1.0f32, 2.0f32, 3.0f32, 4.0f32)
5.0f32, .dot(Vector4::new(5.0f32, 6.0f32, 7.0f32, 8.0f32)),
6.0f32,
7.0f32,
8.0f32
)),
70.0f32 70.0f32
); );
} }
@ -164,14 +160,8 @@ fn test_product() {
#[test] #[test]
fn test_is_perpendicular() { fn test_is_perpendicular() {
assert!( assert!(Vector4::new(1.0f32, 0.0f32, 0.0f32, 0.0f32)
Vector4::new(1.0f32, 0.0f32, 0.0f32, 0.0f32).is_perpendicular(Vector4::new( .is_perpendicular(Vector4::new(0.0f32, 0.0f32, 0.0f32, 1.0f32)));
0.0f32,
0.0f32,
0.0f32,
1.0f32
))
);
} }
#[cfg(test)] #[cfg(test)]
@ -210,30 +200,18 @@ mod test_magnitude {
#[test] #[test]
fn test_angle() { fn test_angle() {
assert_ulps_eq!( assert_ulps_eq!(
Vector4::new(1.0f32, 0.0f32, 1.0f32, 0.0f32).angle(Vector4::new( Vector4::new(1.0f32, 0.0f32, 1.0f32, 0.0f32)
0.0f32, .angle(Vector4::new(0.0f32, 1.0f32, 0.0f32, 1.0f32)),
1.0f32,
0.0f32,
1.0f32
)),
&Rad(f32::consts::FRAC_PI_2) &Rad(f32::consts::FRAC_PI_2)
); );
assert_ulps_eq!( assert_ulps_eq!(
Vector4::new(10.0f32, 0.0f32, 10.0f32, 0.0f32).angle(Vector4::new( Vector4::new(10.0f32, 0.0f32, 10.0f32, 0.0f32)
0.0f32, .angle(Vector4::new(0.0f32, 5.0f32, 0.0f32, 5.0f32)),
5.0f32,
0.0f32,
5.0f32
)),
&Rad(f32::consts::FRAC_PI_2) &Rad(f32::consts::FRAC_PI_2)
); );
assert_ulps_eq!( assert_ulps_eq!(
Vector4::new(-1.0f32, 0.0f32, -1.0f32, 0.0f32).angle(Vector4::new( Vector4::new(-1.0f32, 0.0f32, -1.0f32, 0.0f32)
0.0f32, .angle(Vector4::new(0.0f32, 1.0f32, 0.0f32, 1.0f32)),
1.0f32,
0.0f32,
1.0f32
)),
&Rad(f32::consts::FRAC_PI_2) &Rad(f32::consts::FRAC_PI_2)
); );
} }