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

View file

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

View file

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

View file

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

View file

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

View file

@ -1,7 +1,7 @@
use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use std::env;
use std::string::String;
/// Generate the name of the swizzle function and what it returns.
@ -13,8 +13,12 @@ fn gen_swizzle_nth<'a>(variables: &'a str, mut i: usize, upto: usize) -> Option<
let mut swizzle = String::new();
let n = variables.len() + 1;
for _ in 0..upto {
if i == 0 { break; }
if i % n == 0 { return None; }
if i == 0 {
break;
}
if i % n == 0 {
return None;
}
let c = variables.as_bytes()[i % n - 1] as char;
swizzle.push(c);
swizzle_impl.push_str(&format!("self.{}, ", c));
@ -35,11 +39,12 @@ fn gen_swizzle_functions(variables: &'static str, upto: usize) -> String {
for i in 1..nn {
if let Some((swizzle_name, swizzle_impl)) = gen_swizzle_nth(variables, i, upto) {
let dim = format!("{}", swizzle_name.len());
result.push_str(
&format!("
result.push_str(&format!(
"
/// 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",
swizzle_name, swizzle_impl, dim));
swizzle_name, swizzle_impl, dim
));
}
}
result
@ -50,7 +55,6 @@ fn gen_swizzle_functions(_: &'static str, _: usize) -> String {
String::new()
}
/// This script generates the macro for building swizzle operators for multidimensional
/// vectors and points. This macro is included in macros.rs
fn main() {
@ -92,5 +96,6 @@ macro_rules! impl_swizzle_functions {{
xyzw4 = gen_swizzle_functions("xyzw", 4));
let mut f = File::create(swizzle_file_path)
.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.
use std::fmt;
use std::f64;
use std::fmt;
use std::iter;
use std::ops::*;
use num_traits::{cast, Bounded};
#[cfg(feature = "rand")]
use rand::{
distributions::{uniform::SampleUniform, Distribution, Standard},
Rng,
distributions::{Distribution, Standard, uniform::SampleUniform},
};
use num_traits::{cast, Bounded};
use structure::*;

View file

@ -13,21 +13,21 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use num_traits::cast;
#[cfg(feature = "rand")]
use rand::{
Rng,
distributions::{Distribution, Standard},
Rng,
};
use num_traits::cast;
use structure::*;
use angle::Rad;
use approx;
use quaternion::Quaternion;
#[cfg(feature = "mint")]
use mint;
use num::BaseFloat;
use quaternion::Quaternion;
/// 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")]
impl<A> Distribution<Euler<A>> for Standard
where Standard: Distribution<A>,
A: Angle {
where
Standard: Distribution<A>,
A: Angle,
{
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Euler<A> {
Euler {
x: rng.gen(),

View file

@ -58,9 +58,9 @@ extern crate approx;
#[cfg(feature = "mint")]
pub extern crate mint;
pub extern crate num_traits;
#[cfg(feature = "rand")]
extern crate rand;
pub extern crate num_traits;
#[cfg(feature = "serde")]
#[macro_use]
@ -77,11 +77,11 @@ pub use structure::*;
pub use matrix::{Matrix2, Matrix3, Matrix4};
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 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 transform::*;

View file

@ -139,14 +139,30 @@ macro_rules! impl_assignment_operator {
}
macro_rules! fold_array {
(&$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) };
($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) };
(&$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)
};
($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
@ -252,17 +268,19 @@ macro_rules! impl_index_operators {
#[inline]
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> {
#[inline]
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
@ -272,11 +290,11 @@ macro_rules! impl_operator_simd {
([$Simd:ident]; $Op:ident for $Lhs:ty {
fn $op:ident($x:ident) -> $Output:ty { $body:expr }
}) => {
impl $Op for $Lhs {
#[inline]
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 {
#[inline]
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 {
#[inline]
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 {
fn $op:ident($lhs:ident, $rhs:ident) -> $Output:ty { $body:expr }
}) => {
impl $Op<$Rhs> for $Lhs {
#[inline]
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 {
#[inline]
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 {
#[inline]
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 {
#[inline]
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 {
#[inline]
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 {
#[inline]
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
// limitations under the License.
use num_traits::{cast, NumCast};
#[cfg(feature = "rand")]
use rand::{
distributions::{Distribution, Standard},
Rng,
distributions::{Standard, Distribution},
};
use num_traits::{cast, NumCast};
use std::fmt;
use std::iter;
use std::mem;
@ -159,6 +159,34 @@ impl<S> 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
/// `dir`, using `up` for orientation.
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.
#[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 {
x: c0,
y: c1,
@ -668,21 +701,28 @@ impl<S: BaseFloat> SquareMatrix for Matrix3<S> {
self[1].cross(self[2]) / det,
self[2].cross(self[0]) / det,
self[0].cross(self[1]) / det,
).transpose(),
)
.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])
}
}
@ -835,21 +875,33 @@ impl<S: BaseFloat> SquareMatrix for Matrix4<S> {
}
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])
}
}
@ -1266,7 +1318,7 @@ macro_rules! index_operators {
From::from(&mut v[i])
}
}
}
};
}
index_operators!(Matrix2<S>, 2, Vector2<S>, usize);
@ -1555,7 +1607,8 @@ impl<S: fmt::Debug> fmt::Debug for Matrix4<S> {
impl<S> Distribution<Matrix2<S>> for Standard
where
Standard: Distribution<Vector2<S>>,
S: BaseFloat {
S: BaseFloat,
{
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Matrix2<S> {
Matrix2 {
@ -1567,8 +1620,10 @@ impl<S> Distribution<Matrix2<S>> for Standard
#[cfg(feature = "rand")]
impl<S> Distribution<Matrix3<S>> for Standard
where Standard: Distribution<Vector3<S>>,
S: BaseFloat {
where
Standard: Distribution<Vector3<S>>,
S: BaseFloat,
{
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Matrix3<S> {
Matrix3 {
@ -1581,8 +1636,10 @@ impl<S> Distribution<Matrix3<S>> for Standard
#[cfg(feature = "rand")]
impl<S> Distribution<Matrix4<S>> for Standard
where Standard: Distribution<Vector4<S>>,
S: BaseFloat {
where
Standard: Distribution<Vector4<S>>,
S: BaseFloat,
{
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Matrix4<S> {
Matrix4 {

View file

@ -36,8 +36,7 @@ pub trait BaseNum:
{
}
impl<T> BaseNum for T
where
impl<T> BaseNum for T where
T: Copy
+ Clone
+ fmt::Debug
@ -48,7 +47,7 @@ where
+ SubAssign
+ MulAssign
+ DivAssign
+ RemAssign,
+ RemAssign
{
}
@ -62,12 +61,11 @@ pub trait BaseFloat:
{
}
impl<T> BaseFloat for T
where
impl<T> BaseFloat for T where
T: BaseNum
+ Float
+ approx::AbsDiffEq<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
// limitations under the License.
use num_traits::Zero;
use num_traits::cast;
use num_traits::Zero;
use structure::Angle;
@ -38,7 +38,8 @@ pub fn perspective<S: BaseFloat, A: Into<Rad<S>>>(
aspect: aspect,
near: near,
far: far,
}.into()
}
.into()
}
/// 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,
near: near,
far: far,
}.into()
}
.into()
}
/// 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,
near: near,
far: far,
}.into()
}
.into()
}
/// 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::ops::*;
use num_traits::{cast, NumCast};
#[cfg(feature = "rand")]
use rand::{
Rng,
distributions::{Distribution, Standard},
Rng,
};
use num_traits::{cast, NumCast};
use structure::*;
@ -626,17 +626,19 @@ macro_rules! index_operators {
#[inline]
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> {
#[inline]
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);
@ -647,9 +649,11 @@ index_operators!(S, [S], RangeFull);
#[cfg(feature = "rand")]
impl<S> Distribution<Quaternion<S>> for Standard
where Standard: Distribution<S>,
where
Standard: Distribution<S>,
Standard: Distribution<Vector3<S>>,
S: BaseFloat {
S: BaseFloat,
{
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Quaternion<S> {
Quaternion::from_sv(rng.gen(), rng.gen())

View file

@ -62,16 +62,17 @@ 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.
///

View file

@ -607,7 +607,11 @@ where
#[inline]
fn normalize_signed(self) -> Self {
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.

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

@ -29,7 +29,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()
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)
let vt = t
.inverse_transform_vector(v)
.expect("Expected successful inversion");
assert_ulps_eq!(v, t.transform_vector(vt));
}

View file

@ -212,14 +212,8 @@ fn test_is_perpendicular() {
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!(Vector4::new(1.0f64, 0.0f64, 0.0f64, 0.0f64)
.is_perpendicular(Vector4::new(0.0f64, 0.0f64, 0.0f64, 1.0f64)));
}
#[cfg(test)]
@ -292,30 +286,18 @@ fn test_angle() {
);
assert_ulps_eq!(
Vector4::new(1.0f64, 0.0f64, 1.0f64, 0.0f64).angle(Vector4::new(
0.0f64,
1.0f64,
0.0f64,
1.0f64
)),
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
)),
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
)),
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)
);
}

View file

@ -135,12 +135,8 @@ fn test_rem() {
#[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
)),
Vector4::new(1.0f32, 2.0f32, 3.0f32, 4.0f32)
.dot(Vector4::new(5.0f32, 6.0f32, 7.0f32, 8.0f32)),
70.0f32
);
}
@ -164,14 +160,8 @@ fn test_product() {
#[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)]
@ -210,30 +200,18 @@ mod test_magnitude {
#[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
)),
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
)),
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
)),
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)
);
}