Fix look_at matrices + implement Display for statically sized structures.
This commit is contained in:
parent
60c0f32e1c
commit
02001667f7
|
@ -1,3 +1,4 @@
|
||||||
|
use std::fmt;
|
||||||
use std::ops::{Add, Sub, Mul, Neg};
|
use std::ops::{Add, Sub, Mul, Neg};
|
||||||
|
|
||||||
use rand::{Rand, Rng};
|
use rand::{Rand, Rng};
|
||||||
|
@ -44,33 +45,37 @@ pub struct Iso3<N> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Clone + BaseFloat> Iso3<N> {
|
impl<N: Clone + BaseFloat> Iso3<N> {
|
||||||
/// Reorient and translate this transformation such that its local `x` axis points to a given
|
/// Creates an isometry that corresponds to the local frame of an observer standing at the
|
||||||
/// direction. Note that the usually known `look_at` function does the same thing but with the
|
/// point `eye` and looking toward `target`.
|
||||||
/// `z` axis. See `look_at_z` for that.
|
///
|
||||||
|
/// It maps the view direction `target - eye` to the positive `z` axis and the origin to the
|
||||||
|
/// `eye`.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * eye - The new translation of the transformation.
|
/// * eye - The observer position.
|
||||||
/// * at - The point to look at. `at - eye` is the direction the matrix `x` axis will be
|
/// * target - The target position.
|
||||||
/// aligned with.
|
/// * up - Vertical direction. The only requirement of this parameter is to not be collinear
|
||||||
/// * up - Vector pointing up. The only requirement of this parameter is to not be colinear
|
/// to `eye - at`. Non-collinearity is not checked.
|
||||||
/// with `at`. Non-colinearity is not checked.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn look_at(eye: &Pnt3<N>, at: &Pnt3<N>, up: &Vec3<N>) -> Iso3<N> {
|
pub fn new_observer_frame(eye: &Pnt3<N>, target: &Pnt3<N>, up: &Vec3<N>) -> Iso3<N> {
|
||||||
Iso3::new_with_rotmat(eye.as_vec().clone(), Rot3::look_at(&(*at - *eye), up))
|
let new_rotmat = Rot3::new_observer_frame(&(*target - *eye), up);
|
||||||
|
Iso3::new_with_rotmat(eye.as_vec().clone(), new_rotmat)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reorient and translate this transformation such that its local `z` axis points to a given
|
/// Builds a look-at view matrix.
|
||||||
/// direction.
|
///
|
||||||
|
/// This conforms to the common notion of "look-at" matrix from the computer graphics
|
||||||
|
/// community. Its maps the view direction `target - eye` to the **negative** `z` axis and the
|
||||||
|
/// `eye` to the origin.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * eye - The new translation of the transformation.
|
/// * eye - The eye position.
|
||||||
/// * at - The point to look at. `at - eye` is the direction the matrix `x` axis will be
|
/// * target - The target position.
|
||||||
/// aligned with
|
/// * up - The vertical view direction. It must not be to collinear to `eye - target`.
|
||||||
/// * up - Vector pointing `up`. The only requirement of this parameter is to not be colinear
|
|
||||||
/// with `at`. Non-colinearity is not checked.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn look_at_z(eye: &Pnt3<N>, at: &Pnt3<N>, up: &Vec3<N>) -> Iso3<N> {
|
pub fn new_look_at(eye: &Pnt3<N>, target: &Pnt3<N>, up: &Vec3<N>) -> Iso3<N> {
|
||||||
Iso3::new_with_rotmat(eye.as_vec().clone(), Rot3::look_at_z(&(*at - *eye), up))
|
let new_rotmat = Rot3::new_look_at(&(*target - *eye), up);
|
||||||
|
Iso3::new_with_rotmat(new_rotmat * (-*eye.as_vec()), new_rotmat)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,6 +100,7 @@ pnt_mul_iso_impl!(Iso2, Pnt2);
|
||||||
iso_mul_vec_impl!(Iso2, Vec2);
|
iso_mul_vec_impl!(Iso2, Vec2);
|
||||||
vec_mul_iso_impl!(Iso2, Vec2);
|
vec_mul_iso_impl!(Iso2, Vec2);
|
||||||
arbitrary_iso_impl!(Iso2);
|
arbitrary_iso_impl!(Iso2);
|
||||||
|
iso_display_impl!(Iso2);
|
||||||
|
|
||||||
iso_impl!(Iso3, Rot3, Vec3, Vec3);
|
iso_impl!(Iso3, Rot3, Vec3, Vec3);
|
||||||
rotation_matrix_impl!(Iso3, Rot3, Vec3, Vec3);
|
rotation_matrix_impl!(Iso3, Rot3, Vec3, Vec3);
|
||||||
|
@ -117,3 +123,4 @@ pnt_mul_iso_impl!(Iso3, Pnt3);
|
||||||
iso_mul_vec_impl!(Iso3, Vec3);
|
iso_mul_vec_impl!(Iso3, Vec3);
|
||||||
vec_mul_iso_impl!(Iso3, Vec3);
|
vec_mul_iso_impl!(Iso3, Vec3);
|
||||||
arbitrary_iso_impl!(Iso3);
|
arbitrary_iso_impl!(Iso3);
|
||||||
|
iso_display_impl!(Iso3);
|
||||||
|
|
|
@ -403,3 +403,26 @@ macro_rules! arbitrary_iso_impl(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
macro_rules! iso_display_impl(
|
||||||
|
($t: ident) => (
|
||||||
|
impl<N: fmt::Display + BaseFloat> fmt::Display for $t<N> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
try!(writeln!(f, "Isometry {{"));
|
||||||
|
|
||||||
|
if let Some(precision) = f.precision() {
|
||||||
|
try!(writeln!(f, "... translation: {:.*}", precision, self.translation));
|
||||||
|
try!(writeln!(f, "... rotation matrix:"));
|
||||||
|
try!(write!(f, "{:.*}", precision, *self.rotation.submat()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
try!(writeln!(f, "... translation: {}", self.translation));
|
||||||
|
try!(writeln!(f, "... rotation matrix:"));
|
||||||
|
try!(write!(f, "{}", *self.rotation.submat()));
|
||||||
|
}
|
||||||
|
|
||||||
|
writeln!(f, "}}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#![allow(missing_docs)] // we allow missing to avoid having to document the mij components.
|
#![allow(missing_docs)] // we allow missing to avoid having to document the mij components.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
use std::ops::{Add, Sub, Mul, Div, Index, IndexMut};
|
use std::ops::{Add, Sub, Mul, Div, Index, IndexMut};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::slice::{Iter, IterMut};
|
use std::slice::{Iter, IterMut};
|
||||||
|
@ -82,6 +83,7 @@ eigen_qr_impl!(Mat1, Vec1);
|
||||||
arbitrary_impl!(Mat1, m11);
|
arbitrary_impl!(Mat1, m11);
|
||||||
rand_impl!(Mat1, m11);
|
rand_impl!(Mat1, m11);
|
||||||
mean_impl!(Mat1, Vec1, 1);
|
mean_impl!(Mat1, Vec1, 1);
|
||||||
|
mat_display_impl!(Mat1, 1);
|
||||||
|
|
||||||
/// Square matrix of dimension 2.
|
/// Square matrix of dimension 2.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -136,6 +138,7 @@ eigen_qr_impl!(Mat2, Vec2);
|
||||||
arbitrary_impl!(Mat2, m11, m12, m21, m22);
|
arbitrary_impl!(Mat2, m11, m12, m21, m22);
|
||||||
rand_impl!(Mat2, m11, m12, m21, m22);
|
rand_impl!(Mat2, m11, m12, m21, m22);
|
||||||
mean_impl!(Mat2, Vec2, 2);
|
mean_impl!(Mat2, Vec2, 2);
|
||||||
|
mat_display_impl!(Mat2, 2);
|
||||||
|
|
||||||
/// Square matrix of dimension 3.
|
/// Square matrix of dimension 3.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -233,6 +236,7 @@ rand_impl!(Mat3,
|
||||||
m31, m32, m33
|
m31, m32, m33
|
||||||
);
|
);
|
||||||
mean_impl!(Mat3, Vec3, 3);
|
mean_impl!(Mat3, Vec3, 3);
|
||||||
|
mat_display_impl!(Mat3, 3);
|
||||||
|
|
||||||
/// Square matrix of dimension 4.
|
/// Square matrix of dimension 4.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -353,6 +357,7 @@ rand_impl!(Mat4,
|
||||||
m41, m42, m43, m44
|
m41, m42, m43, m44
|
||||||
);
|
);
|
||||||
mean_impl!(Mat4, Vec4, 4);
|
mean_impl!(Mat4, Vec4, 4);
|
||||||
|
mat_display_impl!(Mat4, 4);
|
||||||
|
|
||||||
/// Square matrix of dimension 5.
|
/// Square matrix of dimension 5.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -490,6 +495,7 @@ rand_impl!(Mat5,
|
||||||
m51, m52, m53, m54, m55
|
m51, m52, m53, m54, m55
|
||||||
);
|
);
|
||||||
mean_impl!(Mat5, Vec5, 5);
|
mean_impl!(Mat5, Vec5, 5);
|
||||||
|
mat_display_impl!(Mat5, 5);
|
||||||
|
|
||||||
/// Square matrix of dimension 6.
|
/// Square matrix of dimension 6.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -632,3 +638,4 @@ rand_impl!(Mat6,
|
||||||
m61, m62, m63, m64, m65, m66
|
m61, m62, m63, m64, m65, m66
|
||||||
);
|
);
|
||||||
mean_impl!(Mat6, Vec6, 6);
|
mean_impl!(Mat6, Vec6, 6);
|
||||||
|
mat_display_impl!(Mat6, 6);
|
||||||
|
|
|
@ -749,3 +749,56 @@ macro_rules! mean_impl(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
macro_rules! mat_display_impl(
|
||||||
|
($t: ident, $dim: expr) => (
|
||||||
|
impl<N: fmt::Display + BaseFloat> fmt::Display for $t<N> {
|
||||||
|
// XXX: will will not always work correctly due to rounding errors.
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
fn integral_length<N: BaseFloat>(val: &N) -> usize {
|
||||||
|
let mut res = 1;
|
||||||
|
let mut curr: N = ::cast(10.0f64);
|
||||||
|
|
||||||
|
while curr <= *val {
|
||||||
|
curr = curr * ::cast(10.0f64);
|
||||||
|
res = res + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if val.is_sign_negative() {
|
||||||
|
res + 1
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut max_decimal_length = 0;
|
||||||
|
let mut decimal_lengths: $t<usize> = ::zero();
|
||||||
|
for i in 0 .. $dim {
|
||||||
|
for j in 0 .. $dim {
|
||||||
|
decimal_lengths[(i, j)] = integral_length(&self[(i, j)].clone());
|
||||||
|
max_decimal_length = ::max(max_decimal_length, decimal_lengths[(i, j)]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let precision = f.precision().unwrap_or(3);
|
||||||
|
let max_number_length = max_decimal_length + precision + 1;
|
||||||
|
|
||||||
|
try!(writeln!(f, " ┌ {:>width$} ┐", "", width = max_number_length * $dim + $dim - 1));
|
||||||
|
|
||||||
|
for i in 0 .. $dim {
|
||||||
|
try!(write!(f, " │"));
|
||||||
|
for j in 0 .. $dim {
|
||||||
|
let number_length = decimal_lengths[(i, j)] + precision + 1;
|
||||||
|
let pad = max_number_length - number_length;
|
||||||
|
try!(write!(f, " {:>thepad$}", "", thepad = pad));
|
||||||
|
try!(write!(f, "{:.*}", precision, (*self)[(i, j)]));
|
||||||
|
}
|
||||||
|
try!(writeln!(f, " │"));
|
||||||
|
}
|
||||||
|
|
||||||
|
writeln!(f, " └ {:>width$} ┘", "", width = max_number_length * $dim + $dim - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
|
@ -41,11 +41,11 @@ impl<N: BaseFloat> Ortho3<N> {
|
||||||
|
|
||||||
/// Builds a 4D projection matrix (using homogeneous coordinates) for this projection.
|
/// Builds a 4D projection matrix (using homogeneous coordinates) for this projection.
|
||||||
pub fn to_mat(&self) -> Mat4<N> {
|
pub fn to_mat(&self) -> Mat4<N> {
|
||||||
self.to_persp_mat().mat
|
self.to_ortho_mat().mat
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build a `OrthoMat3` representing this projection.
|
/// Build a `OrthoMat3` representing this projection.
|
||||||
pub fn to_persp_mat(&self) -> OrthoMat3<N> {
|
pub fn to_ortho_mat(&self) -> OrthoMat3<N> {
|
||||||
OrthoMat3::new(self.width, self.height, self.znear, self.zfar)
|
OrthoMat3::new(self.width, self.height, self.znear, self.zfar)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,14 +114,14 @@ impl<N: BaseFloat + Clone> Ortho3<N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn project_pnt(&self, p: &Pnt3<N>) -> Pnt3<N> {
|
pub fn project_pnt(&self, p: &Pnt3<N>) -> Pnt3<N> {
|
||||||
// FIXME: optimize that
|
// FIXME: optimize that
|
||||||
self.to_persp_mat().project_pnt(p)
|
self.to_ortho_mat().project_pnt(p)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Projects a vector.
|
/// Projects a vector.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn project_vec(&self, p: &Vec3<N>) -> Vec3<N> {
|
pub fn project_vec(&self, p: &Vec3<N>) -> Vec3<N> {
|
||||||
// FIXME: optimize that
|
// FIXME: optimize that
|
||||||
self.to_persp_mat().project_vec(p)
|
self.to_ortho_mat().project_vec(p)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,7 +251,7 @@ impl<N: BaseFloat + Clone> OrthoMat3<N> {
|
||||||
impl<N: Arbitrary + BaseFloat> Arbitrary for OrthoMat3<N> {
|
impl<N: Arbitrary + BaseFloat> Arbitrary for OrthoMat3<N> {
|
||||||
fn arbitrary<G: Gen>(g: &mut G) -> OrthoMat3<N> {
|
fn arbitrary<G: Gen>(g: &mut G) -> OrthoMat3<N> {
|
||||||
let x: Ortho3<N> = Arbitrary::arbitrary(g);
|
let x: Ortho3<N> = Arbitrary::arbitrary(g);
|
||||||
x.to_persp_mat()
|
x.to_ortho_mat()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
//! Points with dimension known at compile-time.
|
//! Points with dimension known at compile-time.
|
||||||
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::fmt;
|
||||||
use std::slice::{Iter, IterMut};
|
use std::slice::{Iter, IterMut};
|
||||||
use std::iter::{Iterator, FromIterator, IntoIterator};
|
use std::iter::{Iterator, FromIterator, IntoIterator};
|
||||||
use std::ops::{Add, Sub, Mul, Div, Neg, Index, IndexMut};
|
use std::ops::{Add, Sub, Mul, Div, Neg, Index, IndexMut};
|
||||||
|
@ -57,6 +58,7 @@ pnt_from_homogeneous_impl!(Pnt1, Pnt2, y, x);
|
||||||
num_float_pnt_impl!(Pnt1, Vec1);
|
num_float_pnt_impl!(Pnt1, Vec1);
|
||||||
arbitrary_pnt_impl!(Pnt1, x);
|
arbitrary_pnt_impl!(Pnt1, x);
|
||||||
rand_impl!(Pnt1, x);
|
rand_impl!(Pnt1, x);
|
||||||
|
pnt_display_impl!(Pnt1);
|
||||||
|
|
||||||
/// Point of dimension 2.
|
/// Point of dimension 2.
|
||||||
///
|
///
|
||||||
|
@ -102,6 +104,7 @@ pnt_from_homogeneous_impl!(Pnt2, Pnt3, z, x, y);
|
||||||
num_float_pnt_impl!(Pnt2, Vec2);
|
num_float_pnt_impl!(Pnt2, Vec2);
|
||||||
arbitrary_pnt_impl!(Pnt2, x, y);
|
arbitrary_pnt_impl!(Pnt2, x, y);
|
||||||
rand_impl!(Pnt2, x, y);
|
rand_impl!(Pnt2, x, y);
|
||||||
|
pnt_display_impl!(Pnt2);
|
||||||
|
|
||||||
/// Point of dimension 3.
|
/// Point of dimension 3.
|
||||||
///
|
///
|
||||||
|
@ -149,6 +152,7 @@ pnt_from_homogeneous_impl!(Pnt3, Pnt4, w, x, y, z);
|
||||||
num_float_pnt_impl!(Pnt3, Vec3);
|
num_float_pnt_impl!(Pnt3, Vec3);
|
||||||
arbitrary_pnt_impl!(Pnt3, x, y, z);
|
arbitrary_pnt_impl!(Pnt3, x, y, z);
|
||||||
rand_impl!(Pnt3, x, y, z);
|
rand_impl!(Pnt3, x, y, z);
|
||||||
|
pnt_display_impl!(Pnt3);
|
||||||
|
|
||||||
/// Point of dimension 4.
|
/// Point of dimension 4.
|
||||||
///
|
///
|
||||||
|
@ -198,6 +202,7 @@ pnt_from_homogeneous_impl!(Pnt4, Pnt5, a, x, y, z, w);
|
||||||
num_float_pnt_impl!(Pnt4, Vec4);
|
num_float_pnt_impl!(Pnt4, Vec4);
|
||||||
arbitrary_pnt_impl!(Pnt4, x, y, z, w);
|
arbitrary_pnt_impl!(Pnt4, x, y, z, w);
|
||||||
rand_impl!(Pnt4, x, y, z, w);
|
rand_impl!(Pnt4, x, y, z, w);
|
||||||
|
pnt_display_impl!(Pnt4);
|
||||||
|
|
||||||
/// Point of dimension 5.
|
/// Point of dimension 5.
|
||||||
///
|
///
|
||||||
|
@ -249,6 +254,7 @@ pnt_from_homogeneous_impl!(Pnt5, Pnt6, b, x, y, z, w, a);
|
||||||
num_float_pnt_impl!(Pnt5, Vec5);
|
num_float_pnt_impl!(Pnt5, Vec5);
|
||||||
arbitrary_pnt_impl!(Pnt5, x, y, z, w, a);
|
arbitrary_pnt_impl!(Pnt5, x, y, z, w, a);
|
||||||
rand_impl!(Pnt5, x, y, z, w, a);
|
rand_impl!(Pnt5, x, y, z, w, a);
|
||||||
|
pnt_display_impl!(Pnt5);
|
||||||
|
|
||||||
/// Point of dimension 6.
|
/// Point of dimension 6.
|
||||||
///
|
///
|
||||||
|
@ -300,3 +306,4 @@ iterable_mut_impl!(Pnt6, 6);
|
||||||
num_float_pnt_impl!(Pnt6, Vec6);
|
num_float_pnt_impl!(Pnt6, Vec6);
|
||||||
arbitrary_pnt_impl!(Pnt6, x, y, z, w, a, b);
|
arbitrary_pnt_impl!(Pnt6, x, y, z, w, a, b);
|
||||||
rand_impl!(Pnt6, x, y, z, w, a, b);
|
rand_impl!(Pnt6, x, y, z, w, a, b);
|
||||||
|
pnt_display_impl!(Pnt6);
|
||||||
|
|
|
@ -155,3 +155,24 @@ macro_rules! arbitrary_pnt_impl(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
macro_rules! pnt_display_impl(
|
||||||
|
($t: ident) => (
|
||||||
|
impl<N: fmt::Display> fmt::Display for $t<N> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
// FIXME: differenciate them from vectors ?
|
||||||
|
try!(write!(f, "("));
|
||||||
|
|
||||||
|
let mut it = self.iter();
|
||||||
|
|
||||||
|
try!(write!(f, "{}", *it.next().unwrap()));
|
||||||
|
|
||||||
|
for comp in it {
|
||||||
|
try!(write!(f, ", {}", *comp));
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, ")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//! Quaternion definition.
|
//! Quaternion definition.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::slice::{Iter, IterMut};
|
use std::slice::{Iter, IterMut};
|
||||||
use std::ops::{Add, Sub, Mul, Div, Neg, Index, IndexMut};
|
use std::ops::{Add, Sub, Mul, Div, Neg, Index, IndexMut};
|
||||||
|
@ -154,6 +155,12 @@ impl<N: ApproxEq<N> + BaseFloat> Div<Quat<N>> for Quat<N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<N: fmt::Display> fmt::Display for Quat<N> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "Quaternion {} − ({}, {}, {})", self.w, self.i, self.j, self.k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rand_impl!(Quat, w, i, j, k);
|
rand_impl!(Quat, w, i, j, k);
|
||||||
|
|
||||||
|
|
||||||
|
@ -505,6 +512,12 @@ impl<N: BaseNum + Neg<Output = N>> Transform<Pnt3<N>> for UnitQuat<N> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<N: fmt::Display> fmt::Display for UnitQuat<N> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "Unit quaternion {} − ({}, {}, {})", self.q.w, self.q.i, self.q.j, self.q.k)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature="arbitrary")]
|
#[cfg(feature="arbitrary")]
|
||||||
impl<N: Arbitrary + BaseFloat> Arbitrary for UnitQuat<N> {
|
impl<N: Arbitrary + BaseFloat> Arbitrary for UnitQuat<N> {
|
||||||
fn arbitrary<G: Gen>(g: &mut G) -> UnitQuat<N> {
|
fn arbitrary<G: Gen>(g: &mut G) -> UnitQuat<N> {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//! Rotations matrices.
|
//! Rotations matrices.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
use std::ops::{Mul, Neg, Index};
|
use std::ops::{Mul, Neg, Index};
|
||||||
use rand::{Rand, Rng};
|
use rand::{Rand, Rng};
|
||||||
use num::{Zero, One};
|
use num::{Zero, One};
|
||||||
|
@ -193,47 +194,42 @@ impl<N: Clone + BaseFloat> Rot3<N> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Clone + BaseFloat> Rot3<N> {
|
impl<N: Clone + BaseFloat> Rot3<N> {
|
||||||
/// Create a new matrix and orient it such that its local `x` axis points to a given point.
|
/// Creates a rotation that corresponds to the local frame of an observer standing at the
|
||||||
/// Note that the usually known `look_at` function does the same thing but with the `z` axis.
|
/// origin and looking toward `dir`.
|
||||||
/// See `look_at_z` for that.
|
///
|
||||||
|
/// It maps the view direction `dir` to the positive `z` axis.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * at - The point to look at. It is also the direction the matrix `x` axis will be aligned
|
/// * dir - The look direction, that is, direction the matrix `z` axis will be aligned with.
|
||||||
/// with
|
/// * up - The vertical direction. The only requirement of this parameter is to not be
|
||||||
/// * up - Vector pointing `up`. The only requirement of this parameter is to not be colinear
|
/// collinear
|
||||||
/// with `at`. Non-colinearity is not checked.
|
/// to `dir`. Non-collinearity is not checked.
|
||||||
pub fn look_at(at: &Vec3<N>, up: &Vec3<N>) -> Rot3<N> {
|
#[inline]
|
||||||
let xaxis = Norm::normalize(at);
|
pub fn new_observer_frame(dir: &Vec3<N>, up: &Vec3<N>) -> Rot3<N> {
|
||||||
let zaxis = Norm::normalize(&Cross::cross(up, &xaxis));
|
let zaxis = Norm::normalize(dir);
|
||||||
let yaxis = Cross::cross(&zaxis, &xaxis);
|
let xaxis = Norm::normalize(&Cross::cross(up, &zaxis));
|
||||||
|
let yaxis = Norm::normalize(&Cross::cross(&zaxis, &xaxis));
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
Rot3::new_with_mat(Mat3::new(
|
Rot3::new_with_mat(Mat3::new(
|
||||||
xaxis.x.clone(), yaxis.x.clone(), zaxis.x.clone(),
|
xaxis.x.clone(), yaxis.x.clone(), zaxis.x.clone(),
|
||||||
xaxis.y.clone(), yaxis.y.clone(), zaxis.y.clone(),
|
xaxis.y.clone(), yaxis.y.clone(), zaxis.y.clone(),
|
||||||
xaxis.z , yaxis.z , zaxis.z)
|
xaxis.z , yaxis.z , zaxis.z))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new matrix and orient it such that its local `z` axis points to a given point.
|
/// Builds a look-at view matrix with no translational component.
|
||||||
|
///
|
||||||
|
/// This conforms to the common notion of "look-at" matrix from the computer graphics community.
|
||||||
|
/// Its maps the view direction `dir` to the **negative** `z` axis.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
/// * at - The look direction, that is, direction the matrix `y` axis will be aligned with
|
/// * dir - The view direction.
|
||||||
/// * up - Vector pointing `up`. The only requirement of this parameter is to not be colinear
|
/// * up - The vertical direction. The only requirement of this parameter is to not be
|
||||||
/// with `at`. Non-colinearity is not checked.
|
/// collinear to `dir`.
|
||||||
pub fn look_at_z(at: &Vec3<N>, up: &Vec3<N>) -> Rot3<N> {
|
#[inline]
|
||||||
let zaxis = Norm::normalize(at);
|
pub fn new_look_at(dir: &Vec3<N>, up: &Vec3<N>) -> Rot3<N> {
|
||||||
let xaxis = Norm::normalize(&Cross::cross(up, &zaxis));
|
Rot3::new_observer_frame(&(-*dir), up).inv().unwrap()
|
||||||
let yaxis = Cross::cross(&zaxis, &xaxis);
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
Rot3::new_with_mat(Mat3::new(
|
|
||||||
xaxis.x.clone(), yaxis.x.clone(), zaxis.x.clone(),
|
|
||||||
xaxis.y.clone(), yaxis.y.clone(), zaxis.y.clone(),
|
|
||||||
xaxis.z , yaxis.z , zaxis.z)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,6 +364,7 @@ inv_impl!(Rot2);
|
||||||
transpose_impl!(Rot2);
|
transpose_impl!(Rot2);
|
||||||
approx_eq_impl!(Rot2);
|
approx_eq_impl!(Rot2);
|
||||||
diag_impl!(Rot2, Vec2);
|
diag_impl!(Rot2, Vec2);
|
||||||
|
rot_display_impl!(Rot2);
|
||||||
|
|
||||||
submat_impl!(Rot3, Mat3);
|
submat_impl!(Rot3, Mat3);
|
||||||
rotate_impl!(Rot3, Vec3, Pnt3);
|
rotate_impl!(Rot3, Vec3, Pnt3);
|
||||||
|
@ -390,3 +387,4 @@ inv_impl!(Rot3);
|
||||||
transpose_impl!(Rot3);
|
transpose_impl!(Rot3);
|
||||||
approx_eq_impl!(Rot3);
|
approx_eq_impl!(Rot3);
|
||||||
diag_impl!(Rot3, Vec3);
|
diag_impl!(Rot3, Vec3);
|
||||||
|
rot_display_impl!(Rot3);
|
||||||
|
|
|
@ -326,3 +326,17 @@ macro_rules! absolute_impl(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
macro_rules! rot_display_impl(
|
||||||
|
($t: ident) => (
|
||||||
|
impl<N: fmt::Display + BaseFloat> fmt::Display for $t<N> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
let precision = f.precision().unwrap_or(3);
|
||||||
|
|
||||||
|
try!(writeln!(f, "Rotation matrix {{"));
|
||||||
|
try!(write!(f, "{:.*}", precision, self.submat));
|
||||||
|
writeln!(f, "}}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
use std::fmt;
|
||||||
use std::ops::{Mul, Neg};
|
use std::ops::{Mul, Neg};
|
||||||
|
|
||||||
use rand::{Rand, Rng};
|
use rand::{Rand, Rng};
|
||||||
|
@ -64,6 +65,7 @@ sim_to_homogeneous_impl!(Sim2, Mat3);
|
||||||
sim_approx_eq_impl!(Sim2);
|
sim_approx_eq_impl!(Sim2);
|
||||||
sim_rand_impl!(Sim2);
|
sim_rand_impl!(Sim2);
|
||||||
sim_arbitrary_impl!(Sim2);
|
sim_arbitrary_impl!(Sim2);
|
||||||
|
sim_display_impl!(Sim2);
|
||||||
|
|
||||||
sim_impl!(Sim3, Iso3, Rot3, Vec3, Vec3);
|
sim_impl!(Sim3, Iso3, Rot3, Vec3, Vec3);
|
||||||
dim_impl!(Sim3, 3);
|
dim_impl!(Sim3, 3);
|
||||||
|
@ -81,3 +83,4 @@ sim_to_homogeneous_impl!(Sim3, Mat4);
|
||||||
sim_approx_eq_impl!(Sim3);
|
sim_approx_eq_impl!(Sim3);
|
||||||
sim_rand_impl!(Sim3);
|
sim_rand_impl!(Sim3);
|
||||||
sim_arbitrary_impl!(Sim3);
|
sim_arbitrary_impl!(Sim3);
|
||||||
|
sim_display_impl!(Sim3);
|
||||||
|
|
|
@ -118,7 +118,7 @@ macro_rules! sim_mul_sim_impl(
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mul(self, right: $t<N>) -> $t<N> {
|
fn mul(self, right: $t<N>) -> $t<N> {
|
||||||
$t::new_with_rotmat(
|
$t::new_with_rotmat(
|
||||||
self.isometry.translation + self.isometry.rotation * (right.isometry.translation * right.scale),
|
self.isometry.translation + self.isometry.rotation * (right.isometry.translation * self.scale),
|
||||||
self.isometry.rotation * right.isometry.rotation,
|
self.isometry.rotation * right.isometry.rotation,
|
||||||
self.scale * right.scale)
|
self.scale * right.scale)
|
||||||
}
|
}
|
||||||
|
@ -174,10 +174,11 @@ macro_rules! sim_inv_impl(
|
||||||
fn inv_mut(&mut self) -> bool {
|
fn inv_mut(&mut self) -> bool {
|
||||||
self.scale = ::one::<N>() / self.scale;
|
self.scale = ::one::<N>() / self.scale;
|
||||||
self.isometry.inv_mut();
|
self.isometry.inv_mut();
|
||||||
// We multiply by self.scale because the scale has been inverted on the previous line.
|
// We multiply (instead of dividing) by self.scale because it has already been
|
||||||
|
// inverted.
|
||||||
self.isometry.translation = self.isometry.translation * self.scale;
|
self.isometry.translation = self.isometry.translation * self.scale;
|
||||||
|
|
||||||
// always succeed
|
// Always succeed.
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +187,7 @@ macro_rules! sim_inv_impl(
|
||||||
let mut res = *self;
|
let mut res = *self;
|
||||||
res.inv_mut();
|
res.inv_mut();
|
||||||
|
|
||||||
// always succeed
|
// Always succeed.
|
||||||
Some(res)
|
Some(res)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,7 +244,12 @@ macro_rules! sim_rand_impl(
|
||||||
impl<N: Rand + BaseFloat> Rand for $t<N> {
|
impl<N: Rand + BaseFloat> Rand for $t<N> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn rand<R: Rng>(rng: &mut R) -> $t<N> {
|
fn rand<R: Rng>(rng: &mut R) -> $t<N> {
|
||||||
$t::new_with_iso(rng.gen(), rng.gen())
|
let mut scale: N = rng.gen();
|
||||||
|
while scale.is_zero() {
|
||||||
|
scale = rng.gen();
|
||||||
|
}
|
||||||
|
|
||||||
|
$t::new_with_iso(rng.gen(), scale)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -262,3 +268,28 @@ macro_rules! sim_arbitrary_impl(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
macro_rules! sim_display_impl(
|
||||||
|
($t: ident) => (
|
||||||
|
impl<N: fmt::Display + BaseFloat> fmt::Display for $t<N> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
try!(writeln!(f, "Similarity transformation {{"));
|
||||||
|
|
||||||
|
if let Some(precision) = f.precision() {
|
||||||
|
try!(writeln!(f, "... scale factor: {:.*}", precision, self.scale));
|
||||||
|
try!(writeln!(f, "... translation: {:.*}", precision, self.isometry.translation));
|
||||||
|
try!(writeln!(f, "... rotation matrix:"));
|
||||||
|
try!(write!(f, "{:.*}", precision, *self.isometry.rotation.submat()));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
try!(writeln!(f, "... scale factor: {}", self.scale));
|
||||||
|
try!(writeln!(f, "... translation: {}", self.isometry.translation));
|
||||||
|
try!(writeln!(f, "... rotation matrix:"));
|
||||||
|
try!(write!(f, "{}", *self.isometry.rotation.submat()));
|
||||||
|
}
|
||||||
|
|
||||||
|
writeln!(f, "}}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
|
@ -4,6 +4,7 @@ use std::ops::{Add, Sub, Mul, Div, Neg, Index, IndexMut};
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::slice::{Iter, IterMut};
|
use std::slice::{Iter, IterMut};
|
||||||
use std::iter::{Iterator, FromIterator, IntoIterator};
|
use std::iter::{Iterator, FromIterator, IntoIterator};
|
||||||
|
use std::fmt;
|
||||||
use rand::{Rand, Rng};
|
use rand::{Rand, Rng};
|
||||||
use num::{Zero, One};
|
use num::{Zero, One};
|
||||||
use traits::operations::{ApproxEq, POrd, POrdering, Axpy, Absolute, Mean};
|
use traits::operations::{ApproxEq, POrd, POrdering, Axpy, Absolute, Mean};
|
||||||
|
@ -71,6 +72,7 @@ absolute_vec_impl!(Vec1, x);
|
||||||
arbitrary_impl!(Vec1, x);
|
arbitrary_impl!(Vec1, x);
|
||||||
rand_impl!(Vec1, x);
|
rand_impl!(Vec1, x);
|
||||||
mean_impl!(Vec1);
|
mean_impl!(Vec1);
|
||||||
|
vec_display_impl!(Vec1);
|
||||||
|
|
||||||
/// Vector of dimension 2.
|
/// Vector of dimension 2.
|
||||||
///
|
///
|
||||||
|
@ -128,6 +130,7 @@ absolute_vec_impl!(Vec2, x, y);
|
||||||
arbitrary_impl!(Vec2, x, y);
|
arbitrary_impl!(Vec2, x, y);
|
||||||
rand_impl!(Vec2, x, y);
|
rand_impl!(Vec2, x, y);
|
||||||
mean_impl!(Vec2);
|
mean_impl!(Vec2);
|
||||||
|
vec_display_impl!(Vec2);
|
||||||
|
|
||||||
/// Vector of dimension 3.
|
/// Vector of dimension 3.
|
||||||
///
|
///
|
||||||
|
@ -187,6 +190,7 @@ absolute_vec_impl!(Vec3, x, y, z);
|
||||||
arbitrary_impl!(Vec3, x, y, z);
|
arbitrary_impl!(Vec3, x, y, z);
|
||||||
rand_impl!(Vec3, x, y, z);
|
rand_impl!(Vec3, x, y, z);
|
||||||
mean_impl!(Vec3);
|
mean_impl!(Vec3);
|
||||||
|
vec_display_impl!(Vec3);
|
||||||
|
|
||||||
|
|
||||||
/// Vector of dimension 4.
|
/// Vector of dimension 4.
|
||||||
|
@ -249,6 +253,7 @@ absolute_vec_impl!(Vec4, x, y, z, w);
|
||||||
arbitrary_impl!(Vec4, x, y, z, w);
|
arbitrary_impl!(Vec4, x, y, z, w);
|
||||||
rand_impl!(Vec4, x, y, z, w);
|
rand_impl!(Vec4, x, y, z, w);
|
||||||
mean_impl!(Vec4);
|
mean_impl!(Vec4);
|
||||||
|
vec_display_impl!(Vec4);
|
||||||
|
|
||||||
/// Vector of dimension 5.
|
/// Vector of dimension 5.
|
||||||
///
|
///
|
||||||
|
@ -312,6 +317,7 @@ absolute_vec_impl!(Vec5, x, y, z, w, a);
|
||||||
arbitrary_impl!(Vec5, x, y, z, w, a);
|
arbitrary_impl!(Vec5, x, y, z, w, a);
|
||||||
rand_impl!(Vec5, x, y, z, w, a);
|
rand_impl!(Vec5, x, y, z, w, a);
|
||||||
mean_impl!(Vec5);
|
mean_impl!(Vec5);
|
||||||
|
vec_display_impl!(Vec5);
|
||||||
|
|
||||||
/// Vector of dimension 6.
|
/// Vector of dimension 6.
|
||||||
///
|
///
|
||||||
|
@ -375,3 +381,4 @@ absolute_vec_impl!(Vec6, x, y, z, w, a, b);
|
||||||
arbitrary_impl!(Vec6, x, y, z, w, a, b);
|
arbitrary_impl!(Vec6, x, y, z, w, a, b);
|
||||||
rand_impl!(Vec6, x, y, z, w, a, b);
|
rand_impl!(Vec6, x, y, z, w, a, b);
|
||||||
mean_impl!(Vec6);
|
mean_impl!(Vec6);
|
||||||
|
vec_display_impl!(Vec6);
|
||||||
|
|
|
@ -820,3 +820,25 @@ macro_rules! mean_impl(
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
macro_rules! vec_display_impl(
|
||||||
|
($t: ident) => (
|
||||||
|
impl<N: fmt::Display> fmt::Display for $t<N> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
try!(write!(f, "("));
|
||||||
|
|
||||||
|
let mut it = self.iter();
|
||||||
|
|
||||||
|
let precision = f.precision().unwrap_or(8);
|
||||||
|
|
||||||
|
try!(write!(f, "{:.*}", precision, *it.next().unwrap()));
|
||||||
|
|
||||||
|
for comp in it {
|
||||||
|
try!(write!(f, ", {:.*}", precision, *comp));
|
||||||
|
}
|
||||||
|
|
||||||
|
write!(f, ")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
173
tests/mat.rs
173
tests/mat.rs
|
@ -2,8 +2,8 @@ extern crate nalgebra as na;
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
|
|
||||||
use rand::random;
|
use rand::random;
|
||||||
use na::{Vec1, Vec3, Mat1, Mat2, Mat3, Mat4, Mat5, Mat6, Rot2, Rot3, Persp3, PerspMat3, Ortho3,
|
use na::{Rot2, Rot3, Iso2, Iso3, Sim2, Sim3, Vec3, Mat1, Mat2, Mat3, Mat4, Mat5, Mat6, DMat, DVec,
|
||||||
OrthoMat3, DMat, DVec, Row, Col, BaseFloat, Diag, Transpose, RowSlice, ColSlice, Shape};
|
Row, Col, Diag, Transpose, RowSlice, ColSlice, Shape};
|
||||||
|
|
||||||
macro_rules! test_inv_mat_impl(
|
macro_rules! test_inv_mat_impl(
|
||||||
($t: ty) => (
|
($t: ty) => (
|
||||||
|
@ -12,7 +12,9 @@ macro_rules! test_inv_mat_impl(
|
||||||
|
|
||||||
match na::inv(&randmat) {
|
match na::inv(&randmat) {
|
||||||
None => { },
|
None => { },
|
||||||
Some(i) => assert!(na::approx_eq(&(i * randmat), &na::one()))
|
Some(i) => {
|
||||||
|
assert!(na::approx_eq(&(i * randmat), &na::one()))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -183,13 +185,33 @@ fn test_inv_mat6() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_rotation2() {
|
fn test_inv_rot2() {
|
||||||
for _ in 0usize .. 10000 {
|
test_inv_mat_impl!(Rot2<f64>);
|
||||||
let randmat: na::Rot2<f64> = na::one();
|
}
|
||||||
let ang = Vec1::new(na::abs(&random::<f64>()) % <f64 as BaseFloat>::pi());
|
|
||||||
|
|
||||||
assert!(na::approx_eq(&na::rotation(&na::append_rotation(&randmat, &ang)), &ang));
|
#[test]
|
||||||
}
|
fn test_inv_rot3() {
|
||||||
|
test_inv_mat_impl!(Rot3<f64>);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_inv_iso2() {
|
||||||
|
test_inv_mat_impl!(Iso2<f64>);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_inv_iso3() {
|
||||||
|
test_inv_mat_impl!(Iso3<f64>);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_inv_sim2() {
|
||||||
|
test_inv_mat_impl!(Sim2<f64>);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_inv_sim3() {
|
||||||
|
test_inv_mat_impl!(Sim3<f64>);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -199,59 +221,6 @@ fn test_index_mat2() {
|
||||||
assert!(mat[(0, 1)] == na::transpose(&mat)[(1, 0)]);
|
assert!(mat[(0, 1)] == na::transpose(&mat)[(1, 0)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_inv_rotation3() {
|
|
||||||
for _ in 0usize .. 10000 {
|
|
||||||
let randmat: Rot3<f64> = na::one();
|
|
||||||
let dir: Vec3<f64> = random();
|
|
||||||
let ang = na::normalize(&dir) * (na::abs(&random::<f64>()) % <f64 as BaseFloat>::pi());
|
|
||||||
let rot = na::append_rotation(&randmat, &ang);
|
|
||||||
|
|
||||||
assert!(na::approx_eq(&(na::transpose(&rot) * rot), &na::one()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rot3_rotation_between() {
|
|
||||||
let r1: Rot3<f64> = random();
|
|
||||||
let r2: Rot3<f64> = random();
|
|
||||||
|
|
||||||
let delta = na::rotation_between(&r1, &r2);
|
|
||||||
|
|
||||||
assert!(na::approx_eq(&(delta * r1), &r2))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rot3_angle_between() {
|
|
||||||
let r1: Rot3<f64> = random();
|
|
||||||
let r2: Rot3<f64> = random();
|
|
||||||
|
|
||||||
let delta = na::rotation_between(&r1, &r2);
|
|
||||||
let delta_angle = na::angle_between(&r1, &r2);
|
|
||||||
|
|
||||||
assert!(na::approx_eq(&na::norm(&na::rotation(&delta)), &delta_angle))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rot2_rotation_between() {
|
|
||||||
let r1: Rot2<f64> = random();
|
|
||||||
let r2: Rot2<f64> = random();
|
|
||||||
|
|
||||||
let delta = na::rotation_between(&r1, &r2);
|
|
||||||
|
|
||||||
assert!(na::approx_eq(&(delta * r1), &r2))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_rot2_angle_between() {
|
|
||||||
let r1: Rot2<f64> = random();
|
|
||||||
let r2: Rot2<f64> = random();
|
|
||||||
|
|
||||||
let delta = na::rotation_between(&r1, &r2);
|
|
||||||
let delta_angle = na::angle_between(&r1, &r2);
|
|
||||||
|
|
||||||
assert!(na::approx_eq(&na::norm(&na::rotation(&delta)), &delta_angle))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_mean_dmat() {
|
fn test_mean_dmat() {
|
||||||
|
@ -755,86 +724,6 @@ fn test_row_3() {
|
||||||
assert!(second_col == Vec3::new(1.0, 4.0, 7.0));
|
assert!(second_col == Vec3::new(1.0, 4.0, 7.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_persp() {
|
|
||||||
let mut p = Persp3::new(42.0f64, 0.5, 1.5, 10.0);
|
|
||||||
let mut pm = PerspMat3::new(42.0f64, 0.5, 1.5, 10.0);
|
|
||||||
assert!(p.to_mat() == pm.to_mat());
|
|
||||||
assert!(p.aspect() == 42.0);
|
|
||||||
assert!(p.fov() == 0.5);
|
|
||||||
assert!(p.znear() == 1.5);
|
|
||||||
assert!(p.zfar() == 10.0);
|
|
||||||
assert!(na::approx_eq(&pm.aspect(), &42.0));
|
|
||||||
assert!(na::approx_eq(&pm.fov(), &0.5));
|
|
||||||
assert!(na::approx_eq(&pm.znear(), &1.5));
|
|
||||||
assert!(na::approx_eq(&pm.zfar(), &10.0));
|
|
||||||
|
|
||||||
p.set_fov(0.1);
|
|
||||||
pm.set_fov(0.1);
|
|
||||||
assert!(na::approx_eq(&p.to_mat(), pm.as_mat()));
|
|
||||||
|
|
||||||
p.set_znear(24.0);
|
|
||||||
pm.set_znear(24.0);
|
|
||||||
assert!(na::approx_eq(&p.to_mat(), pm.as_mat()));
|
|
||||||
|
|
||||||
p.set_zfar(61.0);
|
|
||||||
pm.set_zfar(61.0);
|
|
||||||
assert!(na::approx_eq(&p.to_mat(), pm.as_mat()));
|
|
||||||
|
|
||||||
p.set_aspect(23.0);
|
|
||||||
pm.set_aspect(23.0);
|
|
||||||
assert!(na::approx_eq(&p.to_mat(), pm.as_mat()));
|
|
||||||
|
|
||||||
assert!(p.aspect() == 23.0);
|
|
||||||
assert!(p.fov() == 0.1);
|
|
||||||
assert!(p.znear() == 24.0);
|
|
||||||
assert!(p.zfar() == 61.0);
|
|
||||||
assert!(na::approx_eq(&pm.aspect(), &23.0));
|
|
||||||
assert!(na::approx_eq(&pm.fov(), &0.1));
|
|
||||||
assert!(na::approx_eq(&pm.znear(), &24.0));
|
|
||||||
assert!(na::approx_eq(&pm.zfar(), &61.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_ortho() {
|
|
||||||
let mut p = Ortho3::new(42.0f64, 0.5, 1.5, 10.0);
|
|
||||||
let mut pm = OrthoMat3::new(42.0f64, 0.5, 1.5, 10.0);
|
|
||||||
assert!(p.to_mat() == pm.to_mat());
|
|
||||||
assert!(p.width() == 42.0);
|
|
||||||
assert!(p.height() == 0.5);
|
|
||||||
assert!(p.znear() == 1.5);
|
|
||||||
assert!(p.zfar() == 10.0);
|
|
||||||
assert!(na::approx_eq(&pm.width(), &42.0));
|
|
||||||
assert!(na::approx_eq(&pm.height(), &0.5));
|
|
||||||
assert!(na::approx_eq(&pm.znear(), &1.5));
|
|
||||||
assert!(na::approx_eq(&pm.zfar(), &10.0));
|
|
||||||
|
|
||||||
p.set_width(0.1);
|
|
||||||
pm.set_width(0.1);
|
|
||||||
assert!(na::approx_eq(&p.to_mat(), pm.as_mat()));
|
|
||||||
|
|
||||||
p.set_znear(24.0);
|
|
||||||
pm.set_znear(24.0);
|
|
||||||
assert!(na::approx_eq(&p.to_mat(), pm.as_mat()));
|
|
||||||
|
|
||||||
p.set_zfar(61.0);
|
|
||||||
pm.set_zfar(61.0);
|
|
||||||
assert!(na::approx_eq(&p.to_mat(), pm.as_mat()));
|
|
||||||
|
|
||||||
p.set_height(23.0);
|
|
||||||
pm.set_height(23.0);
|
|
||||||
assert!(na::approx_eq(&p.to_mat(), pm.as_mat()));
|
|
||||||
|
|
||||||
assert!(p.height() == 23.0);
|
|
||||||
assert!(p.width() == 0.1);
|
|
||||||
assert!(p.znear() == 24.0);
|
|
||||||
assert!(p.zfar() == 61.0);
|
|
||||||
assert!(na::approx_eq(&pm.height(), &23.0));
|
|
||||||
assert!(na::approx_eq(&pm.width(), &0.1));
|
|
||||||
assert!(na::approx_eq(&pm.znear(), &24.0));
|
|
||||||
assert!(na::approx_eq(&pm.zfar(), &61.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_cholesky_const() {
|
fn test_cholesky_const() {
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,220 @@
|
||||||
|
extern crate nalgebra as na;
|
||||||
|
extern crate rand;
|
||||||
|
|
||||||
|
use rand::random;
|
||||||
|
use na::{Pnt3, Vec3, Vec1, Rot2, Rot3, Persp3, PerspMat3, Ortho3, OrthoMat3, Iso2, Iso3, BaseFloat,
|
||||||
|
Sim2, Sim3};
|
||||||
|
|
||||||
|
macro_rules! test_transform_inv_transform_impl(
|
||||||
|
($t: ty, $p: ty) => (
|
||||||
|
for _ in 0usize .. 10000 {
|
||||||
|
let randmat: $t = random();
|
||||||
|
let randvec: $p = random();
|
||||||
|
|
||||||
|
let tvec = randmat.transform(&randvec);
|
||||||
|
let original = randmat.inv_transform(&randvec);
|
||||||
|
|
||||||
|
assert!(na::approx_eq(&randvec, &original));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
);
|
||||||
|
|
||||||
|
test_transform_inv_transform_impl!(Rot2, Pnt2);
|
||||||
|
test_transform_inv_transform_impl!(Rot3, Pnt3);
|
||||||
|
test_transform_inv_transform_impl!(Iso2, Pnt2);
|
||||||
|
test_transform_inv_transform_impl!(Iso3, Pnt3);
|
||||||
|
test_transform_inv_transform_impl!(Sim2, Pnt2);
|
||||||
|
test_transform_inv_transform_impl!(Sim3, Pnt3);
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rotation2() {
|
||||||
|
for _ in 0usize .. 10000 {
|
||||||
|
let randmat: na::Rot2<f64> = na::one();
|
||||||
|
let ang = Vec1::new(na::abs(&random::<f64>()) % <f64 as BaseFloat>::pi());
|
||||||
|
|
||||||
|
assert!(na::approx_eq(&na::rotation(&na::append_rotation(&randmat, &ang)), &ang));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_inv_rotation3() {
|
||||||
|
for _ in 0usize .. 10000 {
|
||||||
|
let randmat: Rot3<f64> = na::one();
|
||||||
|
let dir: Vec3<f64> = random();
|
||||||
|
let ang = na::normalize(&dir) * (na::abs(&random::<f64>()) % <f64 as BaseFloat>::pi());
|
||||||
|
let rot = na::append_rotation(&randmat, &ang);
|
||||||
|
|
||||||
|
assert!(na::approx_eq(&(na::transpose(&rot) * rot), &na::one()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rot3_rotation_between() {
|
||||||
|
let r1: Rot3<f64> = random();
|
||||||
|
let r2: Rot3<f64> = random();
|
||||||
|
|
||||||
|
let delta = na::rotation_between(&r1, &r2);
|
||||||
|
|
||||||
|
assert!(na::approx_eq(&(delta * r1), &r2))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rot3_angle_between() {
|
||||||
|
let r1: Rot3<f64> = random();
|
||||||
|
let r2: Rot3<f64> = random();
|
||||||
|
|
||||||
|
let delta = na::rotation_between(&r1, &r2);
|
||||||
|
let delta_angle = na::angle_between(&r1, &r2);
|
||||||
|
|
||||||
|
assert!(na::approx_eq(&na::norm(&na::rotation(&delta)), &delta_angle))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rot2_rotation_between() {
|
||||||
|
let r1: Rot2<f64> = random();
|
||||||
|
let r2: Rot2<f64> = random();
|
||||||
|
|
||||||
|
let delta = na::rotation_between(&r1, &r2);
|
||||||
|
|
||||||
|
assert!(na::approx_eq(&(delta * r1), &r2))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rot2_angle_between() {
|
||||||
|
let r1: Rot2<f64> = random();
|
||||||
|
let r2: Rot2<f64> = random();
|
||||||
|
|
||||||
|
let delta = na::rotation_between(&r1, &r2);
|
||||||
|
let delta_angle = na::angle_between(&r1, &r2);
|
||||||
|
|
||||||
|
assert!(na::approx_eq(&na::norm(&na::rotation(&delta)), &delta_angle))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_look_at_iso3() {
|
||||||
|
for _ in 0usize .. 10000 {
|
||||||
|
let eye = random::<Pnt3<f64>>();
|
||||||
|
let target = random::<Pnt3<f64>>();
|
||||||
|
let up = random::<Vec3<f64>>();
|
||||||
|
let viewmat = Iso3::new_look_at(&eye, &target, &up);
|
||||||
|
|
||||||
|
assert_eq!(&(viewmat * eye), &na::orig());
|
||||||
|
assert!(na::approx_eq(&na::normalize(&(viewmat * (target - eye))), &-Vec3::z()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_look_at_rot3() {
|
||||||
|
for _ in 0usize .. 10000 {
|
||||||
|
let dir = random::<Vec3<f64>>();
|
||||||
|
let up = random::<Vec3<f64>>();
|
||||||
|
let viewmat = Rot3::new_look_at(&dir, &up);
|
||||||
|
|
||||||
|
assert!(na::approx_eq(&na::normalize(&(viewmat * dir)), &-Vec3::z()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_observer_frame_iso3() {
|
||||||
|
for _ in 0usize .. 10000 {
|
||||||
|
let eye = random::<Pnt3<f64>>();
|
||||||
|
let target = random::<Pnt3<f64>>();
|
||||||
|
let up = random::<Vec3<f64>>();
|
||||||
|
let observer = Iso3::new_observer_frame(&eye, &target, &up);
|
||||||
|
|
||||||
|
assert_eq!(&(observer * na::orig::<Pnt3<f64>>()), &eye);
|
||||||
|
assert!(na::approx_eq(&(observer * Vec3::z()), &na::normalize(&(target - eye))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_observer_frame_rot3() {
|
||||||
|
for _ in 0usize .. 10000 {
|
||||||
|
let dir = random::<Vec3<f64>>();
|
||||||
|
let up = random::<Vec3<f64>>();
|
||||||
|
let observer = Rot3::new_observer_frame(&dir, &up);
|
||||||
|
|
||||||
|
assert!(na::approx_eq(&(observer * Vec3::z()), &na::normalize(&dir)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_persp() {
|
||||||
|
let mut p = Persp3::new(42.0f64, 0.5, 1.5, 10.0);
|
||||||
|
let mut pm = PerspMat3::new(42.0f64, 0.5, 1.5, 10.0);
|
||||||
|
assert!(p.to_mat() == pm.to_mat());
|
||||||
|
assert!(p.aspect() == 42.0);
|
||||||
|
assert!(p.fov() == 0.5);
|
||||||
|
assert!(p.znear() == 1.5);
|
||||||
|
assert!(p.zfar() == 10.0);
|
||||||
|
assert!(na::approx_eq(&pm.aspect(), &42.0));
|
||||||
|
assert!(na::approx_eq(&pm.fov(), &0.5));
|
||||||
|
assert!(na::approx_eq(&pm.znear(), &1.5));
|
||||||
|
assert!(na::approx_eq(&pm.zfar(), &10.0));
|
||||||
|
|
||||||
|
p.set_fov(0.1);
|
||||||
|
pm.set_fov(0.1);
|
||||||
|
assert!(na::approx_eq(&p.to_mat(), pm.as_mat()));
|
||||||
|
|
||||||
|
p.set_znear(24.0);
|
||||||
|
pm.set_znear(24.0);
|
||||||
|
assert!(na::approx_eq(&p.to_mat(), pm.as_mat()));
|
||||||
|
|
||||||
|
p.set_zfar(61.0);
|
||||||
|
pm.set_zfar(61.0);
|
||||||
|
assert!(na::approx_eq(&p.to_mat(), pm.as_mat()));
|
||||||
|
|
||||||
|
p.set_aspect(23.0);
|
||||||
|
pm.set_aspect(23.0);
|
||||||
|
assert!(na::approx_eq(&p.to_mat(), pm.as_mat()));
|
||||||
|
|
||||||
|
assert!(p.aspect() == 23.0);
|
||||||
|
assert!(p.fov() == 0.1);
|
||||||
|
assert!(p.znear() == 24.0);
|
||||||
|
assert!(p.zfar() == 61.0);
|
||||||
|
assert!(na::approx_eq(&pm.aspect(), &23.0));
|
||||||
|
assert!(na::approx_eq(&pm.fov(), &0.1));
|
||||||
|
assert!(na::approx_eq(&pm.znear(), &24.0));
|
||||||
|
assert!(na::approx_eq(&pm.zfar(), &61.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_ortho() {
|
||||||
|
let mut p = Ortho3::new(42.0f64, 0.5, 1.5, 10.0);
|
||||||
|
let mut pm = OrthoMat3::new(42.0f64, 0.5, 1.5, 10.0);
|
||||||
|
assert!(p.to_mat() == pm.to_mat());
|
||||||
|
assert!(p.width() == 42.0);
|
||||||
|
assert!(p.height() == 0.5);
|
||||||
|
assert!(p.znear() == 1.5);
|
||||||
|
assert!(p.zfar() == 10.0);
|
||||||
|
assert!(na::approx_eq(&pm.width(), &42.0));
|
||||||
|
assert!(na::approx_eq(&pm.height(), &0.5));
|
||||||
|
assert!(na::approx_eq(&pm.znear(), &1.5));
|
||||||
|
assert!(na::approx_eq(&pm.zfar(), &10.0));
|
||||||
|
|
||||||
|
p.set_width(0.1);
|
||||||
|
pm.set_width(0.1);
|
||||||
|
assert!(na::approx_eq(&p.to_mat(), pm.as_mat()));
|
||||||
|
|
||||||
|
p.set_znear(24.0);
|
||||||
|
pm.set_znear(24.0);
|
||||||
|
assert!(na::approx_eq(&p.to_mat(), pm.as_mat()));
|
||||||
|
|
||||||
|
p.set_zfar(61.0);
|
||||||
|
pm.set_zfar(61.0);
|
||||||
|
assert!(na::approx_eq(&p.to_mat(), pm.as_mat()));
|
||||||
|
|
||||||
|
p.set_height(23.0);
|
||||||
|
pm.set_height(23.0);
|
||||||
|
assert!(na::approx_eq(&p.to_mat(), pm.as_mat()));
|
||||||
|
|
||||||
|
assert!(p.height() == 23.0);
|
||||||
|
assert!(p.width() == 0.1);
|
||||||
|
assert!(p.znear() == 24.0);
|
||||||
|
assert!(p.zfar() == 61.0);
|
||||||
|
assert!(na::approx_eq(&pm.height(), &23.0));
|
||||||
|
assert!(na::approx_eq(&pm.width(), &0.1));
|
||||||
|
assert!(na::approx_eq(&pm.znear(), &24.0));
|
||||||
|
assert!(na::approx_eq(&pm.zfar(), &61.0));
|
||||||
|
}
|
|
@ -1,10 +1,16 @@
|
||||||
extern crate rand;
|
extern crate rand;
|
||||||
|
#[cfg(feature="generic_sizes")]
|
||||||
extern crate typenum;
|
extern crate typenum;
|
||||||
extern crate nalgebra as na;
|
extern crate nalgebra as na;
|
||||||
|
|
||||||
use rand::random;
|
use rand::random;
|
||||||
|
use na::{Vec1, Vec2, Vec3, Vec4, Vec5, Vec6, Mat3, Rot2, Rot3, Iterable, IterableMut};
|
||||||
|
|
||||||
|
#[cfg(feature="generic_sizes")]
|
||||||
use typenum::U10;
|
use typenum::U10;
|
||||||
use na::{VecN, Vec1, Vec2, Vec3, Vec4, Vec5, Vec6, Mat3, Rot2, Rot3, Iterable, IterableMut};
|
#[cfg(feature="generic_sizes")]
|
||||||
|
use na::VecN;
|
||||||
|
|
||||||
|
|
||||||
macro_rules! test_iterator_impl(
|
macro_rules! test_iterator_impl(
|
||||||
($t: ty, $n: ty) => (
|
($t: ty, $n: ty) => (
|
||||||
|
@ -295,6 +301,7 @@ fn test_outer_vec3() {
|
||||||
12.0, 15.0, 18.0));
|
12.0, 15.0, 18.0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature="generic_sizes")]
|
||||||
#[test]
|
#[test]
|
||||||
fn test_vecn10_add_mul() {
|
fn test_vecn10_add_mul() {
|
||||||
for _ in 0usize .. 10000 {
|
for _ in 0usize .. 10000 {
|
||||||
|
|
Loading…
Reference in New Issue