Merge pull request #175 from sebcrozet/sim_and_vecn

Release v0.6.0: similarity transformations, VecN, and computer-graphics fixes.
This commit is contained in:
Sébastien Crozet 2016-03-31 21:54:00 +02:00
commit b910ce914f
34 changed files with 2068 additions and 1349 deletions

32
CHANGELOG Normal file
View File

@ -0,0 +1,32 @@
# Change Log
All notable changes to `nalgebra`, starting with the version 0.6.0 will be
documented here.
This project adheres to [Semantic Versioning](http://semver.org/).
## [0.6.0]
**Announcement:** a users forum has been created for `nalgebra`, `ncollide`, and `nphysics`. See
you [there](http://users.nphysics.org)!
### Added
* Added a dependency to [generic-array](https://crates.io/crates/generic-array). Feature-gated:
requires `features="generic_sizes"`.
* Added statically sized vectors with user-defined sizes: `VecN`. Feature-gated: requires
`features="generic_sizes"`.
* Added similarity transformations (an uniform scale followed by a rotation followed by a
translation): `Sim2`, `Sim3`.
### Removed
* Removed zero-sized elements `Vec0`, `Pnt0`.
* Removed 4-dimensional transformations `Rot4` and `Iso4` (which had an implementation to incomplete to be useful).
### Modified
* Vectors are now multipliable with isometries. This will result into a pure rotation (this is how
vectors differ from point semantically: they design directions so they are not translatable).
* `{Iso3, Rot3}::look_at` reimplemented and renamed to `::look_at_rh` and `::look_at_lh` to agree
with the computer graphics community (in particular, the GLM library). Use the `::look_at_rh`
variant to build a view matrix that
may be successfully used with `Persp` and `Ortho`.
* The old `{Iso3, Rot3}::look_at` implementations are now called `::new_observer_frame`.
* Rename every `fov` on `Persp` to `fovy`.
* Fixed the perspective and orthographic projection matrices.

View File

@ -1,6 +1,6 @@
[package] [package]
name = "nalgebra" name = "nalgebra"
version = "0.5.1" version = "0.6.0"
authors = [ "Sébastien Crozet <developer@crozet.re>" ] # FIXME: add the contributors. authors = [ "Sébastien Crozet <developer@crozet.re>" ] # FIXME: add the contributors.
description = "Linear algebra library for computer physics, computer graphics and general low-dimensional linear algebra for Rust." description = "Linear algebra library for computer physics, computer graphics and general low-dimensional linear algebra for Rust."
@ -17,13 +17,22 @@ path = "src/lib.rs"
[features] [features]
# Generate arbitrary instances of nalgebra types for testing with quickcheck # Generate arbitrary instances of nalgebra types for testing with quickcheck
arbitrary = ["quickcheck"] arbitrary = [ "quickcheck" ]
generic_sizes = [ "generic-array", "typenum" ]
[dependencies] [dependencies]
rustc-serialize = "0.3.*" rustc-serialize = "0.3.*"
rand = "0.3.*" rand = "0.3.*"
num = "0.1.*" num = "0.1.*"
[dependencies.generic-array]
optional = true
version = "0.2.*"
[dependencies.typenum]
optional = true
version = "1.3.*"
[dependencies.quickcheck] [dependencies.quickcheck]
optional = true optional = true
version = "0.2.*" version = "0.2.*"

View File

@ -1,7 +1,7 @@
tmp=_git_distcheck tmp=_git_distcheck
all: all:
cargo build --release cargo build --release --features arbitrary
test: test:
cargo test cargo test

View File

@ -9,12 +9,12 @@ nalgebra
* real time computer graphics. * real time computer graphics.
* real time computer physics. * real time computer physics.
An on-line version of this documentation is available [here](http://nalgebra.org). An on-line version of this documentation is available [here](http://nalgebra.org/doc/nalgebra).
## Using **nalgebra** ## Using **nalgebra**
All the functionality of **nalgebra** is grouped in one place: the root module `nalgebra::`. All the functionality of **nalgebra** is grouped in one place: the root module `nalgebra::`. This
This module re-exports everything and includes free functions for all traits methods doing module re-exports everything and includes free functions for all traits methods performing
out-of-place modifications. out-of-place operations.
* You can import the whole prelude using: * You can import the whole prelude using:
@ -44,15 +44,17 @@ fn main() {
**nalgebra** is meant to be a general-purpose, low-dimensional, linear algebra library, with **nalgebra** is meant to be a general-purpose, low-dimensional, linear algebra library, with
an optimized set of tools for computer graphics and physics. Those features include: an optimized set of tools for computer graphics and physics. Those features include:
* Vectors with static sizes: `Vec0`, `Vec1`, `Vec2`, `Vec3`, `Vec4`, `Vec5`, `Vec6`. * Vectors with predefined static sizes: `Vec1`, `Vec2`, `Vec3`, `Vec4`, `Vec5`, `Vec6`.
* Points with static sizes: `Pnt0`, `Pnt1`, `Pnt2`, `Pnt3`, `Pnt4`, `Pnt5`, `Pnt6`. * Vector with a user-defined static size: `VecN` (available only with the `generic_sizes` feature).
* Points with static sizes: `Pnt1`, `Pnt2`, `Pnt3`, `Pnt4`, `Pnt5`, `Pnt6`.
* Square matrices with static sizes: `Mat1`, `Mat2`, `Mat3`, `Mat4`, `Mat5`, `Mat6 `. * Square matrices with static sizes: `Mat1`, `Mat2`, `Mat3`, `Mat4`, `Mat5`, `Mat6 `.
* Rotation matrices: `Rot2`, `Rot3`, `Rot4`. * Rotation matrices: `Rot2`, `Rot3`
* Quaternions: `Quat`, `UnitQuat`. * Quaternions: `Quat`, `UnitQuat`.
* Isometries: `Iso2`, `Iso3`, `Iso4`. * Isometries (translation rotation): `Iso2`, `Iso3`
* Similarity transformations (translation rotation uniform scale): `Sim2`, `Sim3`.
* 3D projections for computer graphics: `Persp3`, `PerspMat3`, `Ortho3`, `OrthoMat3`. * 3D projections for computer graphics: `Persp3`, `PerspMat3`, `Ortho3`, `OrthoMat3`.
* Dynamically sized vector: `DVec`. * Dynamically sized heap-allocated vector: `DVec`.
* Dynamically sized (square or rectangular) matrix: `DMat`. * Dynamically sized stack-allocated vectors with a maximum size: `DVec1` to `DVec6`.
* A few methods for data analysis: `Cov`, `Mean`. * Dynamically sized heap-allocated (square or rectangular) matrix: `DMat`.
* Linear algebra and data analysis operators: `Cov`, `Mean`, `qr`, `cholesky`.
* Almost one trait per functionality: useful for generic programming. * Almost one trait per functionality: useful for generic programming.
* Operator overloading using multidispatch.

View File

@ -1,5 +1,8 @@
#![feature(test)] #![feature(test)]
#[cfg(feature = "generic_sizes")]
extern crate typenum;
extern crate test; extern crate test;
extern crate rand; extern crate rand;
extern crate nalgebra as na; extern crate nalgebra as na;
@ -57,3 +60,53 @@ bench_unop!(_bench_vec4_norm, Vec4<f32>, norm);
bench_unop!(_bench_vec2_normalize, Vec2<f32>, normalize); bench_unop!(_bench_vec2_normalize, Vec2<f32>, normalize);
bench_unop!(_bench_vec3_normalize, Vec3<f32>, normalize); bench_unop!(_bench_vec3_normalize, Vec3<f32>, normalize);
bench_unop!(_bench_vec4_normalize, Vec4<f32>, normalize); bench_unop!(_bench_vec4_normalize, Vec4<f32>, normalize);
#[cfg(feature = "generic_sizes")]
mod bench_vecn {
use typenum::{U2, U3, U4};
use na::VecN;
bench_binop!(_bench_vecn2_add_v, VecN<f32, U2>, VecN<f32, U2>, add);
bench_binop!(_bench_vecn3_add_v, VecN<f32, U3>, VecN<f32, U3>, add);
bench_binop!(_bench_vecn4_add_v, VecN<f32, U4>, VecN<f32, U4>, add);
bench_binop!(_bench_vecn2_sub_v, VecN<f32, U2>, VecN<f32, U2>, sub);
bench_binop!(_bench_vecn3_sub_v, VecN<f32, U3>, VecN<f32, U3>, sub);
bench_binop!(_bench_vecn4_sub_v, VecN<f32, U4>, VecN<f32, U4>, sub);
bench_binop!(_bench_vecn2_mul_v, VecN<f32, U2>, VecN<f32, U2>, mul);
bench_binop!(_bench_vecn3_mul_v, VecN<f32, U3>, VecN<f32, U3>, mul);
bench_binop!(_bench_vecn4_mul_v, VecN<f32, U4>, VecN<f32, U4>, mul);
bench_binop!(_bench_vecn2_div_v, VecN<f32, U2>, VecN<f32, U2>, div);
bench_binop!(_bench_vecn3_div_v, VecN<f32, U3>, VecN<f32, U3>, div);
bench_binop!(_bench_vecn4_div_v, VecN<f32, U4>, VecN<f32, U4>, div);
bench_binop!(_bench_vecn2_add_s, VecN<f32, U2>, f32, add);
bench_binop!(_bench_vecn3_add_s, VecN<f32, U3>, f32, add);
bench_binop!(_bench_vecn4_add_s, VecN<f32, U4>, f32, add);
bench_binop!(_bench_vecn2_sub_s, VecN<f32, U2>, f32, sub);
bench_binop!(_bench_vecn3_sub_s, VecN<f32, U3>, f32, sub);
bench_binop!(_bench_vecn4_sub_s, VecN<f32, U4>, f32, sub);
bench_binop!(_bench_vecn2_mul_s, VecN<f32, U2>, f32, mul);
bench_binop!(_bench_vecn3_mul_s, VecN<f32, U3>, f32, mul);
bench_binop!(_bench_vecn4_mul_s, VecN<f32, U4>, f32, mul);
bench_binop!(_bench_vecn2_div_s, VecN<f32, U2>, f32, div);
bench_binop!(_bench_vecn3_div_s, VecN<f32, U3>, f32, div);
bench_binop!(_bench_vecn4_div_s, VecN<f32, U4>, f32, div);
bench_binop_na!(_bench_vecn2_dot, VecN<f32, U2>, VecN<f32, U2>, dot);
bench_binop_na!(_bench_vecn3_dot, VecN<f32, U3>, VecN<f32, U3>, dot);
bench_binop_na!(_bench_vecn4_dot, VecN<f32, U4>, VecN<f32, U4>, dot);
bench_unop!(_bench_vecn2_norm, VecN<f32, U2>, norm);
bench_unop!(_bench_vecn3_norm, VecN<f32, U3>, norm);
bench_unop!(_bench_vecn4_norm, VecN<f32, U4>, norm);
bench_unop!(_bench_vecn2_normalize, VecN<f32, U2>, normalize);
bench_unop!(_bench_vecn3_normalize, VecN<f32, U3>, normalize);
bench_unop!(_bench_vecn4_normalize, VecN<f32, U4>, normalize);
}

View File

@ -3,16 +3,16 @@
**nalgebra** is a low-dimensional linear algebra library written for Rust targeting: **nalgebra** is a low-dimensional linear algebra library written for Rust targeting:
* general-purpose linear algebra (still lacks a lot of features). * low-dimensional general-purpose linear algebra (still lacks a lot of features).
* real time computer graphics. * real time computer graphics.
* real time computer physics. * real time computer physics.
An on-line version of this documentation is available [here](http://nalgebra.org). An on-line version of this documentation is available [here](http://nalgebra.org/doc/nalgebra).
## Using **nalgebra** ## Using **nalgebra**
All the functionality of **nalgebra** is grouped in one place: the root module `nalgebra::`. All the functionality of **nalgebra** is grouped in one place: the root module `nalgebra::`. This
This module re-exports everything and includes free functions for all traits methods doing module re-exports everything and includes free functions for all traits methods performing
out-of-place modifications. out-of-place operations.
* You can import the whole prelude using: * You can import the whole prelude using:
@ -41,18 +41,20 @@ fn main() {
**nalgebra** is meant to be a general-purpose, low-dimensional, linear algebra library, with **nalgebra** is meant to be a general-purpose, low-dimensional, linear algebra library, with
an optimized set of tools for computer graphics and physics. Those features include: an optimized set of tools for computer graphics and physics. Those features include:
* Vectors with static sizes: `Vec0`, `Vec1`, `Vec2`, `Vec3`, `Vec4`, `Vec5`, `Vec6`. * Vectors with predefined static sizes: `Vec1`, `Vec2`, `Vec3`, `Vec4`, `Vec5`, `Vec6`.
* Points with static sizes: `Pnt0`, `Pnt1`, `Pnt2`, `Pnt3`, `Pnt4`, `Pnt5`, `Pnt6`. * Vector with a user-defined static size: `VecN` (available only with the `generic_sizes` feature).
* Points with static sizes: `Pnt1`, `Pnt2`, `Pnt3`, `Pnt4`, `Pnt5`, `Pnt6`.
* Square matrices with static sizes: `Mat1`, `Mat2`, `Mat3`, `Mat4`, `Mat5`, `Mat6 `. * Square matrices with static sizes: `Mat1`, `Mat2`, `Mat3`, `Mat4`, `Mat5`, `Mat6 `.
* Rotation matrices: `Rot2`, `Rot3`, `Rot4`. * Rotation matrices: `Rot2`, `Rot3`
* Quaternions: `Quat`, `UnitQuat`. * Quaternions: `Quat`, `UnitQuat`.
* Isometries: `Iso2`, `Iso3`, `Iso4`. * Isometries (translation rotation): `Iso2`, `Iso3`
* Similarity transformations (translation rotation uniform scale): `Sim2`, `Sim3`.
* 3D projections for computer graphics: `Persp3`, `PerspMat3`, `Ortho3`, `OrthoMat3`. * 3D projections for computer graphics: `Persp3`, `PerspMat3`, `Ortho3`, `OrthoMat3`.
* Dynamically sized vector: `DVec`. * Dynamically sized heap-allocated vector: `DVec`.
* Dynamically sized (square or rectangular) matrix: `DMat`. * Dynamically sized stack-allocated vectors with a maximum size: `DVec1` to `DVec6`.
* A few methods for data analysis: `Cov`, `Mean`. * Dynamically sized heap-allocated (square or rectangular) matrix: `DMat`.
* Linear algebra and data analysis operators: `Cov`, `Mean`, `qr`, `cholesky`.
* Almost one trait per functionality: useful for generic programming. * Almost one trait per functionality: useful for generic programming.
* Operator overloading using multidispatch.
## **nalgebra** in use ## **nalgebra** in use
@ -77,6 +79,9 @@ extern crate rustc_serialize;
extern crate rand; extern crate rand;
extern crate num; extern crate num;
#[cfg(feature="generic_sizes")]
extern crate generic_array;
#[cfg(feature="arbitrary")] #[cfg(feature="arbitrary")]
extern crate quickcheck; extern crate quickcheck;
@ -133,16 +138,20 @@ pub use traits::{
UniformSphereSample UniformSphereSample
}; };
#[cfg(feature="generic_sizes")]
pub use structs::VecN;
pub use structs::{ pub use structs::{
Identity, Identity,
DMat, DMat1, DMat2, DMat3, DMat4, DMat5, DMat6, DMat, DMat1, DMat2, DMat3, DMat4, DMat5, DMat6,
DVec, DVec1, DVec2, DVec3, DVec4, DVec5, DVec6, DVec, DVec1, DVec2, DVec3, DVec4, DVec5, DVec6,
Iso2, Iso3, Iso4, Iso2, Iso3,
Sim2, Sim3,
Mat1, Mat2, Mat3, Mat4, Mat1, Mat2, Mat3, Mat4,
Mat5, Mat6, Mat5, Mat6,
Rot2, Rot3, Rot4, Rot2, Rot3,
Vec0, Vec1, Vec2, Vec3, Vec4, Vec5, Vec6, Vec1, Vec2, Vec3, Vec4, Vec5, Vec6,
Pnt0, Pnt1, Pnt2, Pnt3, Pnt4, Pnt5, Pnt6, Pnt1, Pnt2, Pnt3, Pnt4, Pnt5, Pnt6,
Persp3, PerspMat3, Persp3, PerspMat3,
Ortho3, OrthoMat3, Ortho3, OrthoMat3,
Quat, UnitQuat Quat, UnitQuat

View File

@ -1,7 +1,5 @@
//! Matrix with dimensions unknown at compile-time. //! Matrix with dimensions unknown at compile-time.
#![allow(missing_docs)] // we hide doc to not have to document the $trhs double dispatch trait.
use std::cmp; use std::cmp;
use std::mem; use std::mem;
use std::iter::repeat; use std::iter::repeat;
@ -110,7 +108,7 @@ impl<N: Clone + Copy> DMat<N> {
} }
impl<N> DMat<N> { impl<N> DMat<N> {
/// Builds a matrix using an initialization function. /// Builds a matrix filled with the results of a function applied to each of its component coordinates.
#[inline(always)] #[inline(always)]
pub fn from_fn<F: FnMut(usize, usize) -> N>(nrows: usize, ncols: usize, mut f: F) -> DMat<N> { pub fn from_fn<F: FnMut(usize, usize) -> N>(nrows: usize, ncols: usize, mut f: F) -> DMat<N> {
DMat { DMat {
@ -131,6 +129,7 @@ impl<N> DMat<N> {
dmat_impl!(DMat, DVec); dmat_impl!(DMat, DVec);
/// A stack-allocated dynamically sized matrix with at most one row and column.
pub struct DMat1<N> { pub struct DMat1<N> {
nrows: usize, nrows: usize,
ncols: usize, ncols: usize,
@ -141,6 +140,7 @@ small_dmat_impl!(DMat1, DVec1, 1, 0);
small_dmat_from_impl!(DMat1, 1, ::zero()); small_dmat_from_impl!(DMat1, 1, ::zero());
/// A stack-allocated dynamically sized square or rectangular matrix with at most 2 rows and columns.
pub struct DMat2<N> { pub struct DMat2<N> {
nrows: usize, nrows: usize,
ncols: usize, ncols: usize,
@ -153,6 +153,7 @@ small_dmat_from_impl!(DMat2, 2, ::zero(), ::zero(),
::zero(), ::zero()); ::zero(), ::zero());
/// A stack-allocated dynamically sized square or rectangular matrix with at most 3 rows and columns.
pub struct DMat3<N> { pub struct DMat3<N> {
nrows: usize, nrows: usize,
ncols: usize, ncols: usize,
@ -167,6 +168,7 @@ small_dmat_from_impl!(DMat3, 3, ::zero(), ::zero(), ::zero(),
::zero(), ::zero(), ::zero()); ::zero(), ::zero(), ::zero());
/// A stack-allocated dynamically sized square or rectangular matrix with at most 4 rows and columns.
pub struct DMat4<N> { pub struct DMat4<N> {
nrows: usize, nrows: usize,
ncols: usize, ncols: usize,
@ -183,6 +185,7 @@ small_dmat_from_impl!(DMat4, 4, ::zero(), ::zero(), ::zero(), ::zero(),
::zero(), ::zero(), ::zero(), ::zero()); ::zero(), ::zero(), ::zero(), ::zero());
/// A stack-allocated dynamically sized square or rectangular matrix with at most 5 rows and columns.
pub struct DMat5<N> { pub struct DMat5<N> {
nrows: usize, nrows: usize,
ncols: usize, ncols: usize,
@ -201,6 +204,7 @@ small_dmat_from_impl!(DMat5, 5, ::zero(), ::zero(), ::zero(), ::zero(), ::zero()
::zero(), ::zero(), ::zero(), ::zero(), ::zero()); ::zero(), ::zero(), ::zero(), ::zero(), ::zero());
/// A stack-allocated dynamically sized square or rectangular matrix with at most 6 rows and columns.
pub struct DMat6<N> { pub struct DMat6<N> {
nrows: usize, nrows: usize,
ncols: usize, ncols: usize,

View File

@ -19,6 +19,7 @@ macro_rules! dmat_impl(
self.mij.iter().all(|e| e.is_zero()) self.mij.iter().all(|e| e.is_zero())
} }
/// Set this matrix components to zero.
#[inline] #[inline]
pub fn reset(&mut self) { pub fn reset(&mut self) {
for mij in self.mij.iter_mut() { for mij in self.mij.iter_mut() {
@ -881,7 +882,8 @@ macro_rules! small_dmat_from_impl(
} }
} }
impl<N> $dmat<N> { impl<N: Copy> $dmat<N> {
/// Creates a new matrix with uninitialized components (with `mem::uninitialized()`).
#[inline] #[inline]
pub unsafe fn new_uninitialized(nrows: usize, ncols: usize) -> $dmat<N> { pub unsafe fn new_uninitialized(nrows: usize, ncols: usize) -> $dmat<N> {
assert!(nrows <= $dim); assert!(nrows <= $dim);

View File

@ -1,7 +1,5 @@
//! Vector with dimensions unknown at compile-time. //! Vector with dimensions unknown at compile-time.
#![allow(missing_docs)] // we hide doc to not have to document the $trhs double dispatch trait.
use std::slice::{Iter, IterMut}; use std::slice::{Iter, IterMut};
use std::iter::{FromIterator, IntoIterator}; use std::iter::{FromIterator, IntoIterator};
use std::iter::repeat; use std::iter::repeat;
@ -56,12 +54,13 @@ impl<N: Clone> DVec<N> {
} }
impl<N> DVec<N> { impl<N> DVec<N> {
/// Builds a vector filled with the result of a function. /// Builds a vector filled with the results of a function applied to each of its component coordinates.
#[inline(always)] #[inline(always)]
pub fn from_fn<F: FnMut(usize) -> N>(dim: usize, mut f: F) -> DVec<N> { pub fn from_fn<F: FnMut(usize) -> N>(dim: usize, mut f: F) -> DVec<N> {
DVec { at: (0..dim).map(|i| f(i)).collect() } DVec { at: (0..dim).map(|i| f(i)).collect() }
} }
/// The vector length.
#[inline] #[inline]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.at.len() self.at.len()

View File

@ -2,6 +2,8 @@
macro_rules! dvec_impl( macro_rules! dvec_impl(
($dvec: ident) => ( ($dvec: ident) => (
vecn_dvec_common_impl!($dvec);
impl<N: Zero + Copy + Clone> $dvec<N> { impl<N: Zero + Copy + Clone> $dvec<N> {
/// Builds a vector filled with zeros. /// Builds a vector filled with zeros.
/// ///
@ -11,68 +13,6 @@ macro_rules! dvec_impl(
pub fn new_zeros(dim: usize) -> $dvec<N> { pub fn new_zeros(dim: usize) -> $dvec<N> {
$dvec::from_elem(dim, ::zero()) $dvec::from_elem(dim, ::zero())
} }
/// Tests if all components of the vector are zeroes.
#[inline]
pub fn is_zero(&self) -> bool {
self.as_ref().iter().all(|e| e.is_zero())
}
}
impl<N> $dvec<N> {
/// Slices this vector.
#[inline]
pub fn as_ref<'a>(&'a self) -> &'a [N] {
&self.at[.. self.len()]
}
/// Mutably slices this vector.
#[inline]
pub fn as_mut<'a>(&'a mut self) -> &'a mut [N] {
let len = self.len();
&mut self.at[.. len]
}
}
impl<N> Shape<usize> for $dvec<N> {
#[inline]
fn shape(&self) -> usize {
self.len()
}
}
impl<N: Copy> Indexable<usize, N> for $dvec<N> {
#[inline]
fn swap(&mut self, i: usize, j: usize) {
assert!(i < self.len());
assert!(j < self.len());
self.as_mut().swap(i, j);
}
#[inline]
unsafe fn unsafe_at(&self, i: usize) -> N {
*self.at[..].get_unchecked(i)
}
#[inline]
unsafe fn unsafe_set(&mut self, i: usize, val: N) {
*self.at[..].get_unchecked_mut(i) = val
}
}
impl<N, T> Index<T> for $dvec<N> where [N]: Index<T> {
type Output = <[N] as Index<T>>::Output;
fn index(&self, i: T) -> &<[N] as Index<T>>::Output {
&self.as_ref()[i]
}
}
impl<N, T> IndexMut<T> for $dvec<N> where [N]: IndexMut<T> {
fn index_mut(&mut self, i: T) -> &mut <[N] as Index<T>>::Output {
&mut self.as_mut()[i]
}
} }
impl<N: One + Zero + Copy + Clone> $dvec<N> { impl<N: One + Zero + Copy + Clone> $dvec<N> {
@ -94,33 +34,6 @@ macro_rules! dvec_impl(
} }
} }
impl<N> Iterable<N> for $dvec<N> {
#[inline]
fn iter<'l>(&'l self) -> Iter<'l, N> {
self.as_ref().iter()
}
}
impl<N> IterableMut<N> for $dvec<N> {
#[inline]
fn iter_mut<'l>(&'l mut self) -> IterMut<'l, N> {
self.as_mut().iter_mut()
}
}
impl<N: Copy + Add<N, Output = N> + Mul<N, Output = N>> Axpy<N> for $dvec<N> {
fn axpy(&mut self, a: &N, x: &$dvec<N>) {
assert!(self.len() == x.len());
for i in 0..x.len() {
unsafe {
let self_i = self.unsafe_at(i);
self.unsafe_set(i, self_i + *a * x.unsafe_at(i))
}
}
}
}
impl<N: BaseFloat + ApproxEq<N>> $dvec<N> { impl<N: BaseFloat + ApproxEq<N>> $dvec<N> {
/// Computes the canonical basis for the given dimension. A canonical basis is a set of /// Computes the canonical basis for the given dimension. A canonical basis is a set of
/// vectors, mutually orthogonal, with all its component equal to 0.0 except one which is equal /// vectors, mutually orthogonal, with all its component equal to 0.0 except one which is equal
@ -128,7 +41,7 @@ macro_rules! dvec_impl(
pub fn canonical_basis_with_dim(dim: usize) -> Vec<$dvec<N>> { pub fn canonical_basis_with_dim(dim: usize) -> Vec<$dvec<N>> {
let mut res : Vec<$dvec<N>> = Vec::new(); let mut res : Vec<$dvec<N>> = Vec::new();
for i in 0..dim { for i in 0 .. dim {
let mut basis_element : $dvec<N> = $dvec::new_zeros(dim); let mut basis_element : $dvec<N> = $dvec::new_zeros(dim);
basis_element[i] = ::one(); basis_element[i] = ::one();
@ -147,7 +60,7 @@ macro_rules! dvec_impl(
let dim = self.len(); let dim = self.len();
let mut res : Vec<$dvec<N>> = Vec::new(); let mut res : Vec<$dvec<N>> = Vec::new();
for i in 0..dim { for i in 0 .. dim {
let mut basis_element : $dvec<N> = $dvec::new_zeros(self.len()); let mut basis_element : $dvec<N> = $dvec::new_zeros(self.len());
basis_element[i] = ::one(); basis_element[i] = ::one();
@ -175,217 +88,13 @@ macro_rules! dvec_impl(
res res
} }
} }
impl<N: Copy + Mul<N, Output = N> + Zero> Mul<$dvec<N>> for $dvec<N> {
type Output = $dvec<N>;
#[inline]
fn mul(self, right: $dvec<N>) -> $dvec<N> {
assert!(self.len() == right.len());
let mut res = self;
for (left, right) in res.as_mut().iter_mut().zip(right.as_ref().iter()) {
*left = *left * *right
}
res
}
}
impl<N: Copy + Div<N, Output = N> + Zero> Div<$dvec<N>> for $dvec<N> {
type Output = $dvec<N>;
#[inline]
fn div(self, right: $dvec<N>) -> $dvec<N> {
assert!(self.len() == right.len());
let mut res = self;
for (left, right) in res.as_mut().iter_mut().zip(right.as_ref().iter()) {
*left = *left / *right
}
res
}
}
impl<N: Copy + Add<N, Output = N> + Zero> Add<$dvec<N>> for $dvec<N> {
type Output = $dvec<N>;
#[inline]
fn add(self, right: $dvec<N>) -> $dvec<N> {
assert!(self.len() == right.len());
let mut res = self;
for (left, right) in res.as_mut().iter_mut().zip(right.as_ref().iter()) {
*left = *left + *right
}
res
}
}
impl<N: Copy + Sub<N, Output = N> + Zero> Sub<$dvec<N>> for $dvec<N> {
type Output = $dvec<N>;
#[inline]
fn sub(self, right: $dvec<N>) -> $dvec<N> {
assert!(self.len() == right.len());
let mut res = self;
for (left, right) in res.as_mut().iter_mut().zip(right.as_ref().iter()) {
*left = *left - *right
}
res
}
}
impl<N: Neg<Output = N> + Zero + Copy> Neg for $dvec<N> {
type Output = $dvec<N>;
#[inline]
fn neg(self) -> $dvec<N> {
FromIterator::from_iter(self.as_ref().iter().map(|a| -*a))
}
}
impl<N: BaseNum> Dot<N> for $dvec<N> {
#[inline]
fn dot(&self, other: &$dvec<N>) -> N {
assert!(self.len() == other.len());
let mut res: N = ::zero();
for i in 0..self.len() {
res = res + unsafe { self.unsafe_at(i) * other.unsafe_at(i) };
}
res
}
}
impl<N: BaseFloat> Norm<N> for $dvec<N> {
#[inline]
fn sqnorm(&self) -> N {
Dot::dot(self, self)
}
#[inline]
fn normalize(&self) -> $dvec<N> {
let mut res : $dvec<N> = self.clone();
let _ = res.normalize_mut();
res
}
#[inline]
fn normalize_mut(&mut self) -> N {
let l = Norm::norm(self);
for n in self.as_mut().iter_mut() {
*n = *n / l;
}
l
}
}
impl<N: BaseFloat + Cast<f64>> Mean<N> for $dvec<N> {
#[inline]
fn mean(&self) -> N {
let normalizer = ::cast(1.0f64 / self.len() as f64);
self.iter().fold(::zero(), |acc, x| acc + *x * normalizer)
}
}
impl<N: ApproxEq<N>> ApproxEq<N> for $dvec<N> {
#[inline]
fn approx_epsilon(_: Option<$dvec<N>>) -> N {
ApproxEq::approx_epsilon(None::<N>)
}
#[inline]
fn approx_ulps(_: Option<$dvec<N>>) -> u32 {
ApproxEq::approx_ulps(None::<N>)
}
#[inline]
fn approx_eq_eps(&self, other: &$dvec<N>, epsilon: &N) -> bool {
let mut zip = self.as_ref().iter().zip(other.as_ref().iter());
zip.all(|(a, b)| ApproxEq::approx_eq_eps(a, b, epsilon))
}
#[inline]
fn approx_eq_ulps(&self, other: &$dvec<N>, ulps: u32) -> bool {
let mut zip = self.as_ref().iter().zip(other.as_ref().iter());
zip.all(|(a, b)| ApproxEq::approx_eq_ulps(a, b, ulps))
}
}
impl<N: Copy + Mul<N, Output = N> + Zero> Mul<N> for $dvec<N> {
type Output = $dvec<N>;
#[inline]
fn mul(self, right: N) -> $dvec<N> {
let mut res = self;
for e in res.as_mut().iter_mut() {
*e = *e * right
}
res
}
}
impl<N: Copy + Div<N, Output = N> + Zero> Div<N> for $dvec<N> {
type Output = $dvec<N>;
#[inline]
fn div(self, right: N) -> $dvec<N> {
let mut res = self;
for e in res.as_mut().iter_mut() {
*e = *e / right
}
res
}
}
impl<N: Copy + Add<N, Output = N> + Zero> Add<N> for $dvec<N> {
type Output = $dvec<N>;
#[inline]
fn add(self, right: N) -> $dvec<N> {
let mut res = self;
for e in res.as_mut().iter_mut() {
*e = *e + right
}
res
}
}
impl<N: Copy + Sub<N, Output = N> + Zero> Sub<N> for $dvec<N> {
type Output = $dvec<N>;
#[inline]
fn sub(self, right: N) -> $dvec<N> {
let mut res = self;
for e in res.as_mut().iter_mut() {
*e = *e - right
}
res
}
}
) )
); );
macro_rules! small_dvec_impl ( macro_rules! small_dvec_impl (
($dvec: ident, $dim: expr, $($idx: expr),*) => ( ($dvec: ident, $dim: expr, $($idx: expr),*) => (
dvec_impl!($dvec);
impl<N> $dvec<N> { impl<N> $dvec<N> {
/// The number of elements of this vector. /// The number of elements of this vector.
#[inline] #[inline]
@ -434,8 +143,6 @@ macro_rules! small_dvec_impl (
} }
} }
} }
dvec_impl!($dvec);
) )
); );
@ -490,7 +197,7 @@ macro_rules! small_dvec_from_impl (
let mut at: [N; $dim] = [ $( $zeros, )* ]; let mut at: [N; $dim] = [ $( $zeros, )* ];
for i in 0..dim { for i in 0 .. dim {
at[i] = f(i); at[i] = f(i);
} }

View File

@ -1,28 +1,25 @@
//! Isometric transformations. use std::fmt;
#![allow(missing_docs)]
use std::ops::{Add, Sub, Mul, Neg}; use std::ops::{Add, Sub, Mul, Neg};
use rand::{Rand, Rng}; use rand::{Rand, Rng};
use num::One; use num::One;
use structs::mat::{Mat3, Mat4, Mat5}; use structs::mat::{Mat3, Mat4};
use traits::structure::{Cast, Dim, Col, BaseFloat, BaseNum}; use traits::structure::{Cast, Dim, Col, BaseFloat, BaseNum};
use traits::operations::{Inv, ApproxEq}; use traits::operations::{Inv, ApproxEq};
use traits::geometry::{RotationMatrix, Rotation, Rotate, AbsoluteRotate, Transform, Transformation, use traits::geometry::{RotationMatrix, Rotation, Rotate, AbsoluteRotate, Transform, Transformation,
Translate, Translation, ToHomogeneous}; Translate, Translation, ToHomogeneous};
use structs::vec::{Vec1, Vec2, Vec3};
use structs::vec::{Vec1, Vec2, Vec3, Vec4}; use structs::pnt::{Pnt2, Pnt3};
use structs::pnt::{Pnt2, Pnt3, Pnt4}; use structs::rot::{Rot2, Rot3};
use structs::rot::{Rot2, Rot3, Rot4};
#[cfg(feature="arbitrary")] #[cfg(feature="arbitrary")]
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
/// Two dimensional isometry. /// Two dimensional **direct** isometry.
/// ///
/// This is the composition of a rotation followed by a translation. /// This is the composition of a rotation followed by a translation. Vectors `Vec2` are not
/// affected by the translational component of this transformation while points `Pnt2` are.
/// Isometries conserve angles and distances, hence do not allow shearing nor scaling. /// Isometries conserve angles and distances, hence do not allow shearing nor scaling.
#[repr(C)] #[repr(C)]
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)] #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)]
@ -33,9 +30,10 @@ pub struct Iso2<N> {
pub translation: Vec2<N> pub translation: Vec2<N>
} }
/// Three dimensional isometry. /// Three dimensional **direct** isometry.
/// ///
/// This is the composition of a rotation followed by a translation. /// This is the composition of a rotation followed by a translation. Vectors `Vec3` are not
/// affected by the translational component of this transformation while points `Pnt3` are.
/// Isometries conserve angles and distances, hence do not allow shearing nor scaling. /// Isometries conserve angles and distances, hence do not allow shearing nor scaling.
#[repr(C)] #[repr(C)]
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)] #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)]
@ -46,56 +44,58 @@ pub struct Iso3<N> {
pub translation: Vec3<N> pub translation: Vec3<N>
} }
/// Four dimensional isometry.
///
/// Isometries conserve angles and distances, hence do not allow shearing nor scaling.
#[repr(C)]
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)]
pub struct Iso4<N> {
/// The rotation applicable by this isometry.
pub rotation: Rot4<N>,
/// The translation applicable by this isometry.
pub translation: Vec4<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.
pub fn look_at(eye: &Pnt3<N>, at: &Pnt3<N>, up: &Vec3<N>) -> Iso3<N> {
Iso3::new_with_rotmat(eye.as_vec().clone(), Rot3::look_at(&(*at - *eye), up))
}
/// Reorient and translate this transformation such that its local `z` axis points to a given
/// direction.
///
/// # Arguments
/// * eye - The new translation of the transformation.
/// * at - The point to look at. `at - eye` is the direction the matrix `x` axis will be
/// aligned with
/// * up - Vector pointing `up`. The only requirement of this parameter is to not be colinear
/// with `at`. Non-colinearity is not checked.
pub fn look_at_z(eye: &Pnt3<N>, at: &Pnt3<N>, up: &Vec3<N>) -> Iso3<N> {
Iso3::new_with_rotmat(eye.as_vec().clone(), Rot3::look_at_z(&(*at - *eye), up))
}
}
impl<N> Iso4<N> {
// XXX remove that when iso_impl works for Iso4
/// Creates a new isometry from a rotation matrix and a vector.
#[inline] #[inline]
pub fn new_with_rotmat(translation: Vec4<N>, rotation: Rot4<N>) -> Iso4<N> { pub fn new_observer_frame(eye: &Pnt3<N>, target: &Pnt3<N>, up: &Vec3<N>) -> Iso3<N> {
Iso4 { let new_rotmat = Rot3::new_observer_frame(&(*target - *eye), up);
rotation: rotation, Iso3::new_with_rotmat(eye.as_vec().clone(), new_rotmat)
translation: translation }
}
/// Builds a right-handed look-at view matrix.
///
/// This conforms to the common notion of right handed look-at matrix from the computer
/// graphics community.
///
/// # Arguments
/// * eye - The eye position.
/// * target - The target position.
/// * up - A vector approximately aligned with required the vertical axis. The only
/// requirement of this parameter is to not be collinear to `target - eye`.
#[inline]
pub fn look_at_rh(eye: &Pnt3<N>, target: &Pnt3<N>, up: &Vec3<N>) -> Iso3<N> {
let rot = Rot3::look_at_rh(&(*target - *eye), up);
let trans = rot * (-*eye);
Iso3::new_with_rotmat(trans.to_vec(), rot)
}
/// Builds a left-handed look-at view matrix.
///
/// This conforms to the common notion of left handed look-at matrix from the computer
/// graphics community.
///
/// # Arguments
/// * eye - The eye position.
/// * target - The target position.
/// * up - A vector approximately aligned with required the vertical axis. The only
/// requirement of this parameter is to not be collinear to `target - eye`.
#[inline]
pub fn look_at_lh(eye: &Pnt3<N>, target: &Pnt3<N>, up: &Vec3<N>) -> Iso3<N> {
let rot = Rot3::look_at_lh(&(*target - *eye), up);
let trans = rot * (-*eye);
Iso3::new_with_rotmat(trans.to_vec(), rot)
} }
} }
@ -115,9 +115,11 @@ rotate_impl!(Iso2, Vec2);
translation_impl!(Iso2, Vec2); translation_impl!(Iso2, Vec2);
translate_impl!(Iso2, Pnt2); translate_impl!(Iso2, Pnt2);
iso_mul_iso_impl!(Iso2); iso_mul_iso_impl!(Iso2);
iso_mul_rot_impl!(Iso2, Rot2);
iso_mul_pnt_impl!(Iso2, Pnt2); iso_mul_pnt_impl!(Iso2, Pnt2);
pnt_mul_iso_impl!(Iso2, Pnt2); iso_mul_vec_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);
@ -135,27 +137,8 @@ rotate_impl!(Iso3, Vec3);
translation_impl!(Iso3, Vec3); translation_impl!(Iso3, Vec3);
translate_impl!(Iso3, Pnt3); translate_impl!(Iso3, Pnt3);
iso_mul_iso_impl!(Iso3); iso_mul_iso_impl!(Iso3);
iso_mul_rot_impl!(Iso3, Rot3);
iso_mul_pnt_impl!(Iso3, Pnt3); iso_mul_pnt_impl!(Iso3, Pnt3);
pnt_mul_iso_impl!(Iso3, Pnt3); iso_mul_vec_impl!(Iso3, Vec3);
arbitrary_iso_impl!(Iso3); arbitrary_iso_impl!(Iso3);
iso_display_impl!(Iso3);
// iso_impl!(Iso4, Rot4, Vec4, Vec4);
// rotation_matrix_impl!(Iso4, Rot4, Vec4, Vec4);
// rotation_impl!(Iso4, Rot4, Vec4);
dim_impl!(Iso4, 4);
one_impl!(Iso4);
absolute_rotate_impl!(Iso4, Vec4);
// rand_impl!(Iso4);
approx_eq_impl!(Iso4);
to_homogeneous_impl!(Iso4, Mat5);
inv_impl!(Iso4);
transform_impl!(Iso4, Pnt4);
transformation_impl!(Iso4);
rotate_impl!(Iso4, Vec4);
translation_impl!(Iso4, Vec4);
translate_impl!(Iso4, Pnt4);
iso_mul_iso_impl!(Iso4);
iso_mul_pnt_impl!(Iso4, Pnt4);
pnt_mul_iso_impl!(Iso4, Pnt4);
// FIXME: as soon as Rot4<N>: Arbitrary
// arbitrary_iso_impl!(Iso4);

View File

@ -3,7 +3,7 @@
macro_rules! iso_impl( macro_rules! iso_impl(
($t: ident, $submat: ident, $subvec: ident, $subrotvec: ident) => ( ($t: ident, $submat: ident, $subvec: ident, $subrotvec: ident) => (
impl<N: BaseFloat> $t<N> { impl<N: BaseFloat> $t<N> {
/// Creates a new isometry from a rotation matrix and a vector. /// Creates a new isometry from an axis-angle rotation, and a vector.
#[inline] #[inline]
pub fn new(translation: $subvec<N>, rotation: $subrotvec<N>) -> $t<N> { pub fn new(translation: $subvec<N>, rotation: $subrotvec<N>) -> $t<N> {
$t { $t {
@ -76,6 +76,30 @@ macro_rules! iso_mul_iso_impl(
) )
); );
macro_rules! iso_mul_rot_impl(
($t: ident, $tr: ident) => (
impl<N: BaseFloat> Mul<$tr<N>> for $t<N> {
type Output = $t<N>;
#[inline]
fn mul(self, right: $tr<N>) -> $t<N> {
$t::new_with_rotmat(self.translation, self.rotation * right)
}
}
impl<N: BaseFloat> Mul<$t<N>> for $tr<N> {
type Output = $t<N>;
#[inline]
fn mul(self, right: $t<N>) -> $t<N> {
$t::new_with_rotmat(
self * right.translation,
self * right.rotation)
}
}
)
);
macro_rules! iso_mul_pnt_impl( macro_rules! iso_mul_pnt_impl(
($t: ident, $tv: ident) => ( ($t: ident, $tv: ident) => (
impl<N: BaseNum> Mul<$tv<N>> for $t<N> { impl<N: BaseNum> Mul<$tv<N>> for $t<N> {
@ -86,16 +110,20 @@ macro_rules! iso_mul_pnt_impl(
self.rotation * right + self.translation self.rotation * right + self.translation
} }
} }
// NOTE: there is no viable pre-multiplication definition because of the translation
// component.
) )
); );
macro_rules! pnt_mul_iso_impl( macro_rules! iso_mul_vec_impl(
($t: ident, $tv: ident) => ( ($t: ident, $tv: ident) => (
impl<N: BaseNum> Mul<$t<N>> for $tv<N> { impl<N: BaseNum> Mul<$tv<N>> for $t<N> {
type Output = $tv<N>; type Output = $tv<N>;
#[inline] #[inline]
fn mul(self, right: $t<N>) -> $tv<N> { fn mul(self, right: $tv<N>) -> $tv<N> {
(self + right.translation) * right.rotation self.rotation * right
} }
} }
) )
@ -378,3 +406,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, "}}")
}
}
)
);

View File

@ -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);

View File

@ -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)
}
}
)
);

View File

@ -2,17 +2,24 @@
pub use self::dmat::{DMat, DMat1, DMat2, DMat3, DMat4, DMat5, DMat6}; pub use self::dmat::{DMat, DMat1, DMat2, DMat3, DMat4, DMat5, DMat6};
pub use self::dvec::{DVec, DVec1, DVec2, DVec3, DVec4, DVec5, DVec6}; pub use self::dvec::{DVec, DVec1, DVec2, DVec3, DVec4, DVec5, DVec6};
pub use self::vec::{Vec0, Vec1, Vec2, Vec3, Vec4, Vec5, Vec6}; pub use self::vec::{Vec1, Vec2, Vec3, Vec4, Vec5, Vec6};
pub use self::pnt::{Pnt0, Pnt1, Pnt2, Pnt3, Pnt4, Pnt5, Pnt6}; pub use self::pnt::{Pnt1, Pnt2, Pnt3, Pnt4, Pnt5, Pnt6};
pub use self::mat::{Identity, Mat1, Mat2, Mat3, Mat4, Mat5, Mat6}; pub use self::mat::{Identity, Mat1, Mat2, Mat3, Mat4, Mat5, Mat6};
pub use self::rot::{Rot2, Rot3, Rot4}; pub use self::rot::{Rot2, Rot3};
pub use self::iso::{Iso2, Iso3, Iso4}; pub use self::iso::{Iso2, Iso3};
pub use self::sim::{Sim2, Sim3};
pub use self::persp::{Persp3, PerspMat3}; pub use self::persp::{Persp3, PerspMat3};
pub use self::ortho::{Ortho3, OrthoMat3}; pub use self::ortho::{Ortho3, OrthoMat3};
pub use self::quat::{Quat, UnitQuat}; pub use self::quat::{Quat, UnitQuat};
#[cfg(feature="generic_sizes")]
pub use self::vecn::VecN;
mod dmat_macros; mod dmat_macros;
mod dmat; mod dmat;
mod vecn_macros;
#[cfg(feature="generic_sizes")]
mod vecn;
mod dvec_macros; mod dvec_macros;
mod dvec; mod dvec;
mod vec_macros; mod vec_macros;
@ -26,15 +33,16 @@ mod rot_macros;
mod rot; mod rot;
mod iso_macros; mod iso_macros;
mod iso; mod iso;
mod sim_macros;
mod sim;
mod persp; mod persp;
mod ortho; mod ortho;
// specialization for some 1d, 2d and 3d operations // Specialization for some 1d, 2d and 3d operations.
#[doc(hidden)] #[doc(hidden)]
mod spec { mod spec {
mod identity; mod identity;
mod mat; mod mat;
mod vec0;
mod vec; mod vec;
mod primitives; mod primitives;
// mod complex; // mod complex;

View File

@ -7,18 +7,24 @@ use quickcheck::{Arbitrary, Gen};
/// A 3D orthographic projection stored without any matrix. /// A 3D orthographic projection stored without any matrix.
/// ///
/// Reading or modifying its individual properties is cheap but applying the transformation is costly. /// This flips the `z` axis and maps a axis-aligned cube to the unit cube with corners varying from
/// `(-1, -1, -1)` to `(1, 1, 1)`. Reading or modifying its individual properties is cheap but
/// applying the transformation is costly.
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)] #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)]
pub struct Ortho3<N> { pub struct Ortho3<N> {
width: N, left: N,
height: N, right: N,
bottom: N,
top: N,
znear: N, znear: N,
zfar: N zfar: N
} }
/// A 3D orthographic projection stored as a 4D matrix. /// A 3D orthographic projection stored as a 4D matrix.
/// ///
/// Reading or modifying its individual properties is costly but applying the transformation is cheap. /// This flips the `z` axis and maps a axis-aligned cube to the unit cube with corners varying from
/// `(-1, -1, -1)` to `(1, 1, 1)`. Reading or modifying its individual properties is costly but
/// applying the transformation is cheap.
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)] #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)]
pub struct OrthoMat3<N> { pub struct OrthoMat3<N> {
mat: Mat4<N> mat: Mat4<N>
@ -26,14 +32,16 @@ pub struct OrthoMat3<N> {
impl<N: BaseFloat> Ortho3<N> { impl<N: BaseFloat> Ortho3<N> {
/// Creates a new 3D orthographic projection. /// Creates a new 3D orthographic projection.
pub fn new(width: N, height: N, znear: N, zfar: N) -> Ortho3<N> { pub fn new(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> Ortho3<N> {
assert!(!::is_zero(&(zfar - znear))); assert!(!::is_zero(&(zfar - znear)));
assert!(!::is_zero(&width)); assert!(!::is_zero(&(left - right)));
assert!(!::is_zero(&height)); assert!(!::is_zero(&(top - bottom)));
Ortho3 { Ortho3 {
width: width, left: left,
height: height, right: right,
bottom: bottom,
top: top,
znear: znear, znear: znear,
zfar: zfar zfar: zfar
} }
@ -46,32 +54,46 @@ impl<N: BaseFloat> Ortho3<N> {
/// Build a `OrthoMat3` representing this projection. /// Build a `OrthoMat3` representing this projection.
pub fn to_persp_mat(&self) -> OrthoMat3<N> { pub fn to_persp_mat(&self) -> OrthoMat3<N> {
OrthoMat3::new(self.width, self.height, self.znear, self.zfar) OrthoMat3::new(self.left, self.right, self.bottom, self.top, self.znear, self.zfar)
} }
} }
#[cfg(feature="arbitrary")] #[cfg(feature="arbitrary")]
impl<N: Arbitrary + BaseFloat> Arbitrary for Ortho3<N> { impl<N: Arbitrary + BaseFloat> Arbitrary for Ortho3<N> {
fn arbitrary<G: Gen>(g: &mut G) -> Ortho3<N> { fn arbitrary<G: Gen>(g: &mut G) -> Ortho3<N> {
let width = reject(g, |x| !::is_zero(x)); let left = Arbitrary::arbitrary(g);
let height = reject(g, |x| !::is_zero(x)); let right = reject(g, |x: &N| *x > left);
let znear = Arbitrary::arbitrary(g); let bottom = Arbitrary::arbitrary(g);
let zfar = reject(g, |&x: &N| !::is_zero(&(x - znear))); let top = reject(g, |x: &N| *x > bottom);
Ortho3::new(width, height, znear, zfar) let znear = Arbitrary::arbitrary(g);
let zfar = reject(g, |x: &N| *x > znear);
Ortho3::new(left, right, bottom, top, znear, zfar)
} }
} }
impl<N: BaseFloat + Clone> Ortho3<N> { impl<N: BaseFloat + Clone> Ortho3<N> {
/// The width of the view cuboid. /// The smallest x-coordinate of the view cuboid.
#[inline] #[inline]
pub fn width(&self) -> N { pub fn left(&self) -> N {
self.width.clone() self.left.clone()
} }
/// The height of the view cuboid. /// The largest x-coordinate of the view cuboid.
#[inline] #[inline]
pub fn height(&self) -> N { pub fn right(&self) -> N {
self.height.clone() self.right.clone()
}
/// The smallest y-coordinate of the view cuboid.
#[inline]
pub fn bottom(&self) -> N {
self.bottom.clone()
}
/// The largest y-coordinate of the view cuboid.
#[inline]
pub fn top(&self) -> N {
self.top.clone()
} }
/// The near plane offset of the view cuboid. /// The near plane offset of the view cuboid.
@ -86,27 +108,45 @@ impl<N: BaseFloat + Clone> Ortho3<N> {
self.zfar.clone() self.zfar.clone()
} }
/// Sets the width of the view cuboid. /// Sets the smallest x-coordinate of the view cuboid.
#[inline] #[inline]
pub fn set_width(&mut self, width: N) { pub fn set_left(&mut self, left: N) {
self.width = width assert!(left < self.right, "The left corner must be farther than the right corner.");
self.left = left
} }
/// Sets the height of the view cuboid. /// Sets the largest x-coordinate of the view cuboid.
#[inline] #[inline]
pub fn set_height(&mut self, height: N) { pub fn set_right(&mut self, right: N) {
self.height = height assert!(right > self.left, "The left corner must be farther than the right corner.");
self.right = right
}
/// Sets the smallest y-coordinate of the view cuboid.
#[inline]
pub fn set_bottom(&mut self, bottom: N) {
assert!(bottom < self.top, "The top corner must be higher than the bottom corner.");
self.bottom = bottom
}
/// Sets the largest y-coordinate of the view cuboid.
#[inline]
pub fn set_top(&mut self, top: N) {
assert!(top > self.bottom, "The top corner must be higher than the left corner.");
self.top = top
} }
/// Sets the near plane offset of the view cuboid. /// Sets the near plane offset of the view cuboid.
#[inline] #[inline]
pub fn set_znear(&mut self, znear: N) { pub fn set_znear(&mut self, znear: N) {
assert!(znear < self.zfar, "The far plane must be farther than the near plane.");
self.znear = znear self.znear = znear
} }
/// Sets the far plane offset of the view cuboid. /// Sets the far plane offset of the view cuboid.
#[inline] #[inline]
pub fn set_zfar(&mut self, zfar: N) { pub fn set_zfar(&mut self, zfar: N) {
assert!(zfar > self.znear, "The far plane must be farther than the near plane.");
self.zfar = zfar self.zfar = zfar
} }
@ -126,22 +166,35 @@ impl<N: BaseFloat + Clone> Ortho3<N> {
} }
impl<N: BaseFloat> OrthoMat3<N> { impl<N: BaseFloat> OrthoMat3<N> {
/// Creates a new orthographic projection matrix from the width, heihgt, znear and zfar planes of the view cuboid. /// Creates a new orthographic projection matrix.
pub fn new(width: N, height: N, znear: N, zfar: N) -> OrthoMat3<N> { pub fn new(left: N, right: N, bottom: N, top: N, znear: N, zfar: N) -> OrthoMat3<N> {
assert!(!::is_zero(&(zfar - znear))); assert!(left < right, "The left corner must be farther than the right corner.");
assert!(!::is_zero(&width)); assert!(bottom < top, "The top corner must be higher than the bottom corner.");
assert!(!::is_zero(&height)); assert!(znear < zfar, "The far plane must be farther than the near plane.");
let mat: Mat4<N> = ::one(); let mat: Mat4<N> = ::one();
let mut res = OrthoMat3 { mat: mat }; let mut res = OrthoMat3 { mat: mat };
res.set_width(width); res.set_left_and_right(left, right);
res.set_height(height); res.set_bottom_and_top(bottom, top);
res.set_znear_and_zfar(znear, zfar); res.set_znear_and_zfar(znear, zfar);
res res
} }
/// Creates a new orthographic projection matrix from an aspect ratio and the vertical field of view.
pub fn new_with_fov(aspect: N, vfov: N, znear: N, zfar: N) -> OrthoMat3<N> {
assert!(znear < zfar, "The far plane must be farther than the near plane.");
assert!(!::is_zero(&aspect));
let _1: N = ::one();
let _2 = _1 + _1;
let width = zfar * (vfov / _2).tan();
let height = width / aspect;
OrthoMat3::new(-width / _2, width / _2, -height / _2, height / _2, znear, zfar)
}
/// Creates a new orthographic matrix from a 4D matrix. /// Creates a new orthographic matrix from a 4D matrix.
/// ///
/// This is unsafe because the input matrix is not checked to be a orthographic projection. /// This is unsafe because the input matrix is not checked to be a orthographic projection.
@ -158,42 +211,68 @@ impl<N: BaseFloat> OrthoMat3<N> {
&self.mat &self.mat
} }
/// The width of the view cuboid. /// The smallest x-coordinate of the view cuboid.
#[inline] #[inline]
pub fn width(&self) -> N { pub fn left(&self) -> N {
<N as Cast<f64>>::from(2.0) / self.mat.m11 (-::one::<N>() - self.mat.m14) / self.mat.m11
} }
/// The height of the view cuboid. /// The largest x-coordinate of the view cuboid.
#[inline] #[inline]
pub fn height(&self) -> N { pub fn right(&self) -> N {
<N as Cast<f64>>::from(2.0) / self.mat.m22 (::one::<N>() - self.mat.m14) / self.mat.m11
}
/// The smallest y-coordinate of the view cuboid.
#[inline]
pub fn bottom(&self) -> N {
(-::one::<N>() - self.mat.m24) / self.mat.m22
}
/// The largest y-coordinate of the view cuboid.
#[inline]
pub fn top(&self) -> N {
(::one::<N>() - self.mat.m24) / self.mat.m22
} }
/// The near plane offset of the view cuboid. /// The near plane offset of the view cuboid.
#[inline] #[inline]
pub fn znear(&self) -> N { pub fn znear(&self) -> N {
(self.mat.m34 + ::one()) / self.mat.m33 (::one::<N>() + self.mat.m34) / self.mat.m33
} }
/// The far plane offset of the view cuboid. /// The far plane offset of the view cuboid.
#[inline] #[inline]
pub fn zfar(&self) -> N { pub fn zfar(&self) -> N {
(self.mat.m34 - ::one()) / self.mat.m33 (-::one::<N>() + self.mat.m34) / self.mat.m33
} }
/// Sets the width of the view cuboid. /// Sets the smallest x-coordinate of the view cuboid.
#[inline] #[inline]
pub fn set_width(&mut self, width: N) { pub fn set_left(&mut self, left: N) {
assert!(!::is_zero(&width)); let right = self.right();
self.mat.m11 = <N as Cast<f64>>::from(2.0) / width; self.set_left_and_right(left, right);
} }
/// Sets the height of the view cuboid. /// Sets the largest x-coordinate of the view cuboid.
#[inline] #[inline]
pub fn set_height(&mut self, height: N) { pub fn set_right(&mut self, right: N) {
assert!(!::is_zero(&height)); let left = self.left();
self.mat.m22 = <N as Cast<f64>>::from(2.0) / height; self.set_left_and_right(left, right);
}
/// Sets the smallest y-coordinate of the view cuboid.
#[inline]
pub fn set_bottom(&mut self, bottom: N) {
let top = self.top();
self.set_bottom_and_top(bottom, top);
}
/// Sets the largest y-coordinate of the view cuboid.
#[inline]
pub fn set_top(&mut self, top: N) {
let bottom = self.bottom();
self.set_bottom_and_top(bottom, top);
} }
/// Sets the near plane offset of the view cuboid. /// Sets the near plane offset of the view cuboid.
@ -210,6 +289,22 @@ impl<N: BaseFloat> OrthoMat3<N> {
self.set_znear_and_zfar(znear, zfar); self.set_znear_and_zfar(znear, zfar);
} }
/// Sets the view cuboid coordinates along the `x` axis.
#[inline]
pub fn set_left_and_right(&mut self, left: N, right: N) {
assert!(left < right, "The left corner must be farther than the right corner.");
self.mat.m11 = <N as Cast<f64>>::from(2.0) / (right - left);
self.mat.m14 = -(right + left) / (right - left);
}
/// Sets the view cuboid coordinates along the `y` axis.
#[inline]
pub fn set_bottom_and_top(&mut self, bottom: N, top: N) {
assert!(bottom < top, "The top corner must be higher than the bottom corner.");
self.mat.m22 = <N as Cast<f64>>::from(2.0) / (top - bottom);
self.mat.m24 = -(top + bottom) / (top - bottom);
}
/// Sets the near and far plane offsets of the view cuboid. /// Sets the near and far plane offsets of the view cuboid.
#[inline] #[inline]
pub fn set_znear_and_zfar(&mut self, znear: N, zfar: N) { pub fn set_znear_and_zfar(&mut self, znear: N, zfar: N) {
@ -222,8 +317,8 @@ impl<N: BaseFloat> OrthoMat3<N> {
#[inline] #[inline]
pub fn project_pnt(&self, p: &Pnt3<N>) -> Pnt3<N> { pub fn project_pnt(&self, p: &Pnt3<N>) -> Pnt3<N> {
Pnt3::new( Pnt3::new(
self.mat.m11 * p.x, self.mat.m11 * p.x + self.mat.m14,
self.mat.m22 * p.y, self.mat.m22 * p.y + self.mat.m24,
self.mat.m33 * p.z + self.mat.m34 self.mat.m33 * p.z + self.mat.m34
) )
} }

View File

@ -7,18 +7,22 @@ use quickcheck::{Arbitrary, Gen};
/// A 3D perspective projection stored without any matrix. /// A 3D perspective projection stored without any matrix.
/// ///
/// Reading or modifying its individual properties is cheap but applying the transformation is costly. /// This maps a frustrum cube to the unit cube with corners varying from `(-1, -1, -1)` to
/// `(1, 1, 1)`. Reading or modifying its individual properties is cheap but applying the
/// transformation is costly.
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)] #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)]
pub struct Persp3<N> { pub struct Persp3<N> {
aspect: N, aspect: N,
fov: N, fovy: N,
znear: N, znear: N,
zfar: N zfar: N
} }
/// A 3D perspective projection stored as a 4D matrix. /// A 3D perspective projection stored as a 4D matrix.
/// ///
/// Reading or modifying its individual properties is costly but applying the transformation is cheap. /// This maps a frustrum to the unit cube with corners varying from `(-1, -1, -1)` to
/// `(1, 1, 1)`. Reading or modifying its individual properties is costly but applying the
/// transformation is cheap.
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)] #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)]
pub struct PerspMat3<N> { pub struct PerspMat3<N> {
mat: Mat4<N> mat: Mat4<N>
@ -26,13 +30,13 @@ pub struct PerspMat3<N> {
impl<N: BaseFloat> Persp3<N> { impl<N: BaseFloat> Persp3<N> {
/// Creates a new 3D perspective projection. /// Creates a new 3D perspective projection.
pub fn new(aspect: N, fov: N, znear: N, zfar: N) -> Persp3<N> { pub fn new(aspect: N, fovy: N, znear: N, zfar: N) -> Persp3<N> {
assert!(!::is_zero(&(zfar - znear))); assert!(!::is_zero(&(zfar - znear)));
assert!(!::is_zero(&aspect)); assert!(!::is_zero(&aspect));
Persp3 { Persp3 {
aspect: aspect, aspect: aspect,
fov: fov, fovy: fovy,
znear: znear, znear: znear,
zfar: zfar zfar: zfar
} }
@ -45,7 +49,7 @@ impl<N: BaseFloat> Persp3<N> {
/// Build a `PerspMat3` representing this projection. /// Build a `PerspMat3` representing this projection.
pub fn to_persp_mat(&self) -> PerspMat3<N> { pub fn to_persp_mat(&self) -> PerspMat3<N> {
PerspMat3::new(self.aspect, self.fov, self.znear, self.zfar) PerspMat3::new(self.aspect, self.fovy, self.znear, self.zfar)
} }
} }
@ -66,10 +70,10 @@ impl<N: BaseFloat + Clone> Persp3<N> {
self.aspect.clone() self.aspect.clone()
} }
/// Gets the field of view of the view frustrum. /// Gets the y field of view of the view frustrum.
#[inline] #[inline]
pub fn fov(&self) -> N { pub fn fovy(&self) -> N {
self.fov.clone() self.fovy.clone()
} }
/// Gets the near plane offset of the view frustrum. /// Gets the near plane offset of the view frustrum.
@ -92,12 +96,12 @@ impl<N: BaseFloat + Clone> Persp3<N> {
self.aspect = aspect; self.aspect = aspect;
} }
/// Sets the field of view of the view frustrum. /// Sets the y field of view of the view frustrum.
/// ///
/// This method does not build any matrix. /// This method does not build any matrix.
#[inline] #[inline]
pub fn set_fov(&mut self, fov: N) { pub fn set_fovy(&mut self, fovy: N) {
self.fov = fov; self.fovy = fovy;
} }
/// Sets the near plane offset of the view frustrum. /// Sets the near plane offset of the view frustrum.
@ -132,19 +136,19 @@ impl<N: BaseFloat + Clone> Persp3<N> {
} }
impl<N: BaseFloat> PerspMat3<N> { impl<N: BaseFloat> PerspMat3<N> {
/// Creates a new persepctive matrix from the aspect ratio, field of view, and near/far planes. /// Creates a new perspective matrix from the aspect ratio, y field of view, and near/far planes.
pub fn new(aspect: N, fov: N, znear: N, zfar: N) -> PerspMat3<N> { pub fn new(aspect: N, fovy: N, znear: N, zfar: N) -> PerspMat3<N> {
assert!(!::is_zero(&(znear - zfar))); assert!(!::is_zero(&(znear - zfar)));
assert!(!::is_zero(&aspect)); assert!(!::is_zero(&aspect));
let mat: Mat4<N> = ::one(); let mat: Mat4<N> = ::one();
let mut res = PerspMat3 { mat: mat }; let mut res = PerspMat3 { mat: mat };
res.set_fov(fov); res.set_fovy(fovy);
res.set_aspect(aspect); res.set_aspect(aspect);
res.set_znear_and_zfar(znear, zfar); res.set_znear_and_zfar(znear, zfar);
res.mat.m44 = ::zero(); res.mat.m44 = ::zero();
res.mat.m43 = ::one(); res.mat.m43 = -::one::<N>();
res res
} }
@ -168,12 +172,12 @@ impl<N: BaseFloat> PerspMat3<N> {
/// Gets the `width / height` aspect ratio of the view frustrum. /// Gets the `width / height` aspect ratio of the view frustrum.
#[inline] #[inline]
pub fn aspect(&self) -> N { pub fn aspect(&self) -> N {
-self.mat.m22 / self.mat.m11 self.mat.m22 / self.mat.m11
} }
/// Gets the field of view of the view frustrum. /// Gets the y field of view of the view frustrum.
#[inline] #[inline]
pub fn fov(&self) -> N { pub fn fovy(&self) -> N {
let _1: N = ::one(); let _1: N = ::one();
let _2 = _1 + _1; let _2 = _1 + _1;
@ -185,7 +189,7 @@ impl<N: BaseFloat> PerspMat3<N> {
pub fn znear(&self) -> N { pub fn znear(&self) -> N {
let _1: N = ::one(); let _1: N = ::one();
let _2 = _1 + _1; let _2 = _1 + _1;
let ratio = (self.mat.m33 + _1) / (self.mat.m33 - _1); let ratio = (-self.mat.m33 + _1) / (-self.mat.m33 - _1);
self.mat.m34 / (_2 * ratio) - self.mat.m34 / _2 self.mat.m34 / (_2 * ratio) - self.mat.m34 / _2
} }
@ -195,29 +199,29 @@ impl<N: BaseFloat> PerspMat3<N> {
pub fn zfar(&self) -> N { pub fn zfar(&self) -> N {
let _1: N = ::one(); let _1: N = ::one();
let _2 = _1 + _1; let _2 = _1 + _1;
let ratio = (self.mat.m33 + _1) / (self.mat.m33 - _1); let ratio = (-self.mat.m33 + _1) / (-self.mat.m33 - _1);
(self.mat.m34 - ratio * self.mat.m34) / _2 (self.mat.m34 - ratio * self.mat.m34) / _2
} }
// FIXME: add a method to retriev znear and zfar at once ? // FIXME: add a method to retrieve znear and zfar simultaneously?
/// Updates this projection matrix with a new `width / height` aspect ratio of the view /// Updates this projection matrix with a new `width / height` aspect ratio of the view
/// frustrum. /// frustrum.
#[inline] #[inline]
pub fn set_aspect(&mut self, aspect: N) { pub fn set_aspect(&mut self, aspect: N) {
assert!(!::is_zero(&aspect)); assert!(!::is_zero(&aspect));
self.mat.m11 = -self.mat.m22 / aspect; self.mat.m11 = self.mat.m22 / aspect;
} }
/// Updates this projection with a new field of view of the view frustrum. /// Updates this projection with a new y field of view of the view frustrum.
#[inline] #[inline]
pub fn set_fov(&mut self, fov: N) { pub fn set_fovy(&mut self, fovy: N) {
let _1: N = ::one(); let _1: N = ::one();
let _2 = _1 + _1; let _2 = _1 + _1;
let old_m22 = self.mat.m22.clone(); let old_m22 = self.mat.m22.clone();
self.mat.m22 = _1 / (fov / _2).tan(); self.mat.m22 = _1 / (fovy / _2).tan();
self.mat.m11 = self.mat.m11 * (self.mat.m22 / old_m22); self.mat.m11 = self.mat.m11 * (self.mat.m22 / old_m22);
} }
@ -241,7 +245,7 @@ impl<N: BaseFloat> PerspMat3<N> {
let _1: N = ::one(); let _1: N = ::one();
let _2 = _1 + _1; let _2 = _1 + _1;
self.mat.m33 = -(zfar + znear) / (znear - zfar); self.mat.m33 = (zfar + znear) / (znear - zfar);
self.mat.m34 = zfar * znear * _2 / (znear - zfar); self.mat.m34 = zfar * znear * _2 / (znear - zfar);
} }
@ -249,7 +253,7 @@ impl<N: BaseFloat> PerspMat3<N> {
#[inline] #[inline]
pub fn project_pnt(&self, p: &Pnt3<N>) -> Pnt3<N> { pub fn project_pnt(&self, p: &Pnt3<N>) -> Pnt3<N> {
let _1: N = ::one(); let _1: N = ::one();
let inv_denom = _1 / p.z; let inv_denom = -_1 / p.z;
Pnt3::new( Pnt3::new(
self.mat.m11 * p.x * inv_denom, self.mat.m11 * p.x * inv_denom,
self.mat.m22 * p.y * inv_denom, self.mat.m22 * p.y * inv_denom,
@ -261,7 +265,7 @@ impl<N: BaseFloat> PerspMat3<N> {
#[inline] #[inline]
pub fn project_vec(&self, p: &Vec3<N>) -> Vec3<N> { pub fn project_vec(&self, p: &Vec3<N>) -> Vec3<N> {
let _1: N = ::one(); let _1: N = ::one();
let inv_denom = _1 / p.z; let inv_denom = -_1 / p.z;
Vec3::new( Vec3::new(
self.mat.m11 * p.x * inv_denom, self.mat.m11 * p.x * inv_denom,
self.mat.m22 * p.y * inv_denom, self.mat.m22 * p.y * inv_denom,

View File

@ -1,9 +1,7 @@
//! Points with dimensions known at compile-time. //! Points with dimension known at compile-time.
#![allow(missing_docs)] // we allow missing to avoid having to document the point components.
use std::marker::PhantomData;
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};
@ -18,27 +16,10 @@ use structs::vec::{Vec1, Vec2, Vec3, Vec4, Vec5, Vec6};
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
/// Point of dimension 0.
#[repr(C)]
#[derive(Eq, PartialEq, Clone, Debug, Copy)]
pub struct Pnt0<N>(pub PhantomData<N>);
impl<N> Pnt0<N> {
/// Creates a new point.
#[inline]
pub fn new() -> Pnt0<N> {
Pnt0(PhantomData)
}
}
impl<N> Repeat<N> for Pnt0<N> {
#[inline]
fn repeat(_: N) -> Pnt0<N> {
Pnt0(PhantomData)
}
}
/// Point of dimension 1. /// Point of dimension 1.
///
/// The main differance between a point and a vector is that a vector is not affected by
/// translations.
#[repr(C)] #[repr(C)]
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)] #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)]
pub struct Pnt1<N> { pub struct Pnt1<N> {
@ -48,7 +29,7 @@ pub struct Pnt1<N> {
new_impl!(Pnt1, x); new_impl!(Pnt1, x);
orig_impl!(Pnt1, x); orig_impl!(Pnt1, x);
ord_impl!(Pnt1, x,); pord_impl!(Pnt1, x,);
scalar_mul_impl!(Pnt1, x); scalar_mul_impl!(Pnt1, x);
scalar_div_impl!(Pnt1, x); scalar_div_impl!(Pnt1, x);
scalar_add_impl!(Pnt1, x); scalar_add_impl!(Pnt1, x);
@ -77,8 +58,12 @@ 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.
///
/// The main differance between a point and a vector is that a vector is not affected by
/// translations.
#[repr(C)] #[repr(C)]
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)] #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)]
pub struct Pnt2<N> { pub struct Pnt2<N> {
@ -90,7 +75,7 @@ pub struct Pnt2<N> {
new_impl!(Pnt2, x, y); new_impl!(Pnt2, x, y);
orig_impl!(Pnt2, x, y); orig_impl!(Pnt2, x, y);
ord_impl!(Pnt2, x, y); pord_impl!(Pnt2, x, y);
scalar_mul_impl!(Pnt2, x, y); scalar_mul_impl!(Pnt2, x, y);
scalar_div_impl!(Pnt2, x, y); scalar_div_impl!(Pnt2, x, y);
scalar_add_impl!(Pnt2, x, y); scalar_add_impl!(Pnt2, x, y);
@ -119,8 +104,12 @@ 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.
///
/// The main differance between a point and a vector is that a vector is not affected by
/// translations.
#[repr(C)] #[repr(C)]
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)] #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)]
pub struct Pnt3<N> { pub struct Pnt3<N> {
@ -134,7 +123,7 @@ pub struct Pnt3<N> {
new_impl!(Pnt3, x, y, z); new_impl!(Pnt3, x, y, z);
orig_impl!(Pnt3, x, y, z); orig_impl!(Pnt3, x, y, z);
ord_impl!(Pnt3, x, y, z); pord_impl!(Pnt3, x, y, z);
scalar_mul_impl!(Pnt3, x, y, z); scalar_mul_impl!(Pnt3, x, y, z);
scalar_div_impl!(Pnt3, x, y, z); scalar_div_impl!(Pnt3, x, y, z);
scalar_add_impl!(Pnt3, x, y, z); scalar_add_impl!(Pnt3, x, y, z);
@ -163,8 +152,12 @@ 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.
///
/// The main differance between a point and a vector is that a vector is not affected by
/// translations.
#[repr(C)] #[repr(C)]
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)] #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)]
pub struct Pnt4<N> { pub struct Pnt4<N> {
@ -180,7 +173,7 @@ pub struct Pnt4<N> {
new_impl!(Pnt4, x, y, z, w); new_impl!(Pnt4, x, y, z, w);
orig_impl!(Pnt4, x, y, z, w); orig_impl!(Pnt4, x, y, z, w);
ord_impl!(Pnt4, x, y, z, w); pord_impl!(Pnt4, x, y, z, w);
scalar_mul_impl!(Pnt4, x, y, z, w); scalar_mul_impl!(Pnt4, x, y, z, w);
scalar_div_impl!(Pnt4, x, y, z, w); scalar_div_impl!(Pnt4, x, y, z, w);
scalar_add_impl!(Pnt4, x, y, z, w); scalar_add_impl!(Pnt4, x, y, z, w);
@ -209,8 +202,12 @@ 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.
///
/// The main differance between a point and a vector is that a vector is not affected by
/// translations.
#[repr(C)] #[repr(C)]
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)] #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)]
pub struct Pnt5<N> { pub struct Pnt5<N> {
@ -228,7 +225,7 @@ pub struct Pnt5<N> {
new_impl!(Pnt5, x, y, z, w, a); new_impl!(Pnt5, x, y, z, w, a);
orig_impl!(Pnt5, x, y, z, w, a); orig_impl!(Pnt5, x, y, z, w, a);
ord_impl!(Pnt5, x, y, z, w, a); pord_impl!(Pnt5, x, y, z, w, a);
scalar_mul_impl!(Pnt5, x, y, z, w, a); scalar_mul_impl!(Pnt5, x, y, z, w, a);
scalar_div_impl!(Pnt5, x, y, z, w, a); scalar_div_impl!(Pnt5, x, y, z, w, a);
scalar_add_impl!(Pnt5, x, y, z, w, a); scalar_add_impl!(Pnt5, x, y, z, w, a);
@ -257,8 +254,12 @@ 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.
///
/// The main differance between a point and a vector is that a vector is not affected by
/// translations.
#[repr(C)] #[repr(C)]
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)] #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)]
pub struct Pnt6<N> { pub struct Pnt6<N> {
@ -278,7 +279,7 @@ pub struct Pnt6<N> {
new_impl!(Pnt6, x, y, z, w, a, b); new_impl!(Pnt6, x, y, z, w, a, b);
orig_impl!(Pnt6, x, y, z, w, a, b); orig_impl!(Pnt6, x, y, z, w, a, b);
ord_impl!(Pnt6, x, y, z, w, a, b); pord_impl!(Pnt6, x, y, z, w, a, b);
scalar_mul_impl!(Pnt6, x, y, z, w, a, b); scalar_mul_impl!(Pnt6, x, y, z, w, a, b);
scalar_div_impl!(Pnt6, x, y, z, w, a, b); scalar_div_impl!(Pnt6, x, y, z, w, a, b);
scalar_add_impl!(Pnt6, x, y, z, w, a, b); scalar_add_impl!(Pnt6, x, y, z, w, a, b);
@ -305,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);

View File

@ -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, ")")
}
}
)
);

View File

@ -1,7 +1,6 @@
//! Quaternion definition. //! Quaternion definition.
#![allow(missing_docs)] // we allow missing to avoid having to document the dispatch trait. 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};
@ -156,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);
@ -507,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> {
@ -515,7 +526,7 @@ impl<N: Arbitrary + BaseFloat> Arbitrary for UnitQuat<N> {
} }
ord_impl!(Quat, w, i, j, k); pord_impl!(Quat, w, i, j, k);
vec_axis_impl!(Quat, w, i, j, k); vec_axis_impl!(Quat, w, i, j, k);
vec_cast_impl!(Quat, w, i, j, k); vec_cast_impl!(Quat, w, i, j, k);
conversion_impl!(Quat, 4); conversion_impl!(Quat, 4);

View File

@ -1,7 +1,6 @@
//! Rotations matrices. //! Rotations matrices.
#![allow(missing_docs)] 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};
@ -9,9 +8,9 @@ use traits::geometry::{Rotate, Rotation, AbsoluteRotate, RotationMatrix, Rotatio
ToHomogeneous, Norm, Cross}; ToHomogeneous, Norm, Cross};
use traits::structure::{Cast, Dim, Row, Col, BaseFloat, BaseNum, Eye, Diag}; use traits::structure::{Cast, Dim, Row, Col, BaseFloat, BaseNum, Eye, Diag};
use traits::operations::{Absolute, Inv, Transpose, ApproxEq}; use traits::operations::{Absolute, Inv, Transpose, ApproxEq};
use structs::vec::{Vec1, Vec2, Vec3, Vec4}; use structs::vec::{Vec1, Vec2, Vec3};
use structs::pnt::{Pnt2, Pnt3, Pnt4}; use structs::pnt::{Pnt2, Pnt3};
use structs::mat::{Mat2, Mat3, Mat4, Mat5}; use structs::mat::{Mat2, Mat3, Mat4};
#[cfg(feature="arbitrary")] #[cfg(feature="arbitrary")]
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
@ -195,47 +194,59 @@ 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 right-handed look-at view matrix without translation.
///
/// This conforms to the common notion of right handed look-at matrix from the computer
/// graphics community.
/// ///
/// # Arguments /// # Arguments
/// * at - The look direction, that is, direction the matrix `y` axis will be aligned with /// * eye - The eye position.
/// * up - Vector pointing `up`. The only requirement of this parameter is to not be colinear /// * target - The target position.
/// with `at`. Non-colinearity is not checked. /// * up - A vector approximately aligned with required the vertical axis. The only
pub fn look_at_z(at: &Vec3<N>, up: &Vec3<N>) -> Rot3<N> { /// requirement of this parameter is to not be collinear to `target - eye`.
let zaxis = Norm::normalize(at); #[inline]
let xaxis = Norm::normalize(&Cross::cross(up, &zaxis)); pub fn look_at_rh(dir: &Vec3<N>, up: &Vec3<N>) -> Rot3<N> {
let yaxis = Cross::cross(&zaxis, &xaxis); Rot3::new_observer_frame(&(-*dir), up).inv().unwrap()
}
unsafe { /// Builds a left-handed look-at view matrix without translation.
Rot3::new_with_mat(Mat3::new( ///
xaxis.x.clone(), yaxis.x.clone(), zaxis.x.clone(), /// This conforms to the common notion of left handed look-at matrix from the computer
xaxis.y.clone(), yaxis.y.clone(), zaxis.y.clone(), /// graphics community.
xaxis.z , yaxis.z , zaxis.z) ///
) /// # Arguments
} /// * eye - The eye position.
/// * target - The target position.
/// * up - A vector approximately aligned with required the vertical axis. The only
/// requirement of this parameter is to not be collinear to `target - eye`.
#[inline]
pub fn look_at_lh(dir: &Vec3<N>, up: &Vec3<N>) -> Rot3<N> {
Rot3::new_observer_frame(&(*dir), up).inv().unwrap()
} }
} }
@ -345,92 +356,6 @@ impl<N: Arbitrary + Clone + BaseFloat> Arbitrary for Rot3<N> {
} }
/// Four dimensional rotation matrix.
#[repr(C)]
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Hash, Copy)]
pub struct Rot4<N> {
submat: Mat4<N>
}
// impl<N> Rot4<N> {
// pub fn new(left_iso: Quat<N>, right_iso: Quat<N>) -> Rot4<N> {
// assert!(left_iso.is_unit());
// assert!(right_iso.is_unright);
//
// let mat_left_iso = Mat4::new(
// left_iso.x, -left_iso.y, -left_iso.z, -left_iso.w,
// left_iso.y, left_iso.x, -left_iso.w, left_iso.z,
// left_iso.z, left_iso.w, left_iso.x, -left_iso.y,
// left_iso.w, -left_iso.z, left_iso.y, left_iso.x);
// let mat_right_iso = Mat4::new(
// right_iso.x, -right_iso.y, -right_iso.z, -right_iso.w,
// right_iso.y, right_iso.x, right_iso.w, -right_iso.z,
// right_iso.z, -right_iso.w, right_iso.x, right_iso.y,
// right_iso.w, right_iso.z, -right_iso.y, right_iso.x);
//
// Rot4 {
// submat: mat_left_iso * mat_right_iso
// }
// }
// }
impl<N: BaseFloat> AbsoluteRotate<Vec4<N>> for Rot4<N> {
#[inline]
fn absolute_rotate(&self, v: &Vec4<N>) -> Vec4<N> {
Vec4::new(
::abs(&self.submat.m11) * v.x + ::abs(&self.submat.m12) * v.y +
::abs(&self.submat.m13) * v.z + ::abs(&self.submat.m14) * v.w,
::abs(&self.submat.m21) * v.x + ::abs(&self.submat.m22) * v.y +
::abs(&self.submat.m23) * v.z + ::abs(&self.submat.m24) * v.w,
::abs(&self.submat.m31) * v.x + ::abs(&self.submat.m32) * v.y +
::abs(&self.submat.m33) * v.z + ::abs(&self.submat.m34) * v.w,
::abs(&self.submat.m41) * v.x + ::abs(&self.submat.m42) * v.y +
::abs(&self.submat.m43) * v.z + ::abs(&self.submat.m44) * v.w)
}
}
impl<N: BaseFloat + Clone>
Rotation<Vec4<N>> for Rot4<N> {
#[inline]
fn rotation(&self) -> Vec4<N> {
panic!("Not yet implemented")
}
#[inline]
fn inv_rotation(&self) -> Vec4<N> {
panic!("Not yet implemented")
}
#[inline]
fn append_rotation_mut(&mut self, _: &Vec4<N>) {
panic!("Not yet implemented")
}
#[inline]
fn append_rotation(&self, _: &Vec4<N>) -> Rot4<N> {
panic!("Not yet implemented")
}
#[inline]
fn prepend_rotation_mut(&mut self, _: &Vec4<N>) {
panic!("Not yet implemented")
}
#[inline]
fn prepend_rotation(&self, _: &Vec4<N>) -> Rot4<N> {
panic!("Not yet implemented")
}
#[inline]
fn set_rotation(&mut self, _: Vec4<N>) {
panic!("Not yet implemented")
}
}
/* /*
* Common implementations. * Common implementations.
*/ */
@ -456,6 +381,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);
@ -478,25 +404,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);
submat_impl!(Rot4, Mat4);
rotate_impl!(Rot4, Vec4, Pnt4);
transform_impl!(Rot4, Vec4, Pnt4);
dim_impl!(Rot4, 4);
rot_mul_rot_impl!(Rot4);
rot_mul_vec_impl!(Rot4, Vec4);
vec_mul_rot_impl!(Rot4, Vec4);
rot_mul_pnt_impl!(Rot4, Pnt4);
pnt_mul_rot_impl!(Rot4, Pnt4);
one_impl!(Rot4);
eye_impl!(Rot4);
rotation_matrix_impl!(Rot4, Vec4, Vec4);
col_impl!(Rot4, Vec4);
row_impl!(Rot4, Vec4);
index_impl!(Rot4);
absolute_impl!(Rot4, Mat4);
to_homogeneous_impl!(Rot4, Mat5);
inv_impl!(Rot4);
transpose_impl!(Rot4);
approx_eq_impl!(Rot4);
diag_impl!(Rot4, Vec4);

View File

@ -3,6 +3,7 @@
macro_rules! submat_impl( macro_rules! submat_impl(
($t: ident, $submat: ident) => ( ($t: ident, $submat: ident) => (
impl<N> $t<N> { impl<N> $t<N> {
/// This rotation's underlying matrix.
#[inline] #[inline]
pub fn submat<'r>(&'r self) -> &'r $submat<N> { pub fn submat<'r>(&'r self) -> &'r $submat<N> {
&self.submat &self.submat
@ -325,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, "}}")
}
}
)
);

86
src/structs/sim.rs Normal file
View File

@ -0,0 +1,86 @@
use std::fmt;
use std::ops::{Mul, Neg};
use rand::{Rand, Rng};
use num::One;
use structs::mat::{Mat3, Mat4};
use traits::structure::{Dim, Col, BaseFloat, BaseNum};
use traits::operations::{Inv, ApproxEq};
use traits::geometry::{Rotation, Transform, Transformation, Translation, ToHomogeneous};
use structs::vec::{Vec1, Vec2, Vec3};
use structs::pnt::{Pnt2, Pnt3};
use structs::rot::{Rot2, Rot3};
use structs::iso::{Iso2, Iso3};
#[cfg(feature="arbitrary")]
use quickcheck::{Arbitrary, Gen};
// FIXME: the name is not explicit at all but coherent with the other tree-letters names…
/// A two-dimensional similarity transformation.
///
/// This is a composition of a uniform scale, followed by a rotation, followed by a translation.
/// Vectors `Vec2` are not affected by the translational component of this transformation while
/// points `Pnt2` are.
/// Similarity transformations conserve angles. Distances are multiplied by some constant (the
/// scale factor). The scale factor cannot be zero.
#[repr(C)]
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)]
pub struct Sim2<N> {
/// The uniform scale applicable by this similarity transformation.
scale: N,
/// The isometry applicable by this similarity transformation.
pub isometry: Iso2<N>
}
/// A three-dimensional similarity transformation.
///
/// This is a composition of a scale, followed by a rotation, followed by a translation.
/// Vectors `Vec3` are not affected by the translational component of this transformation while
/// points `Pnt3` are.
/// Similarity transformations conserve angles. Distances are multiplied by some constant (the
/// scale factor). The scale factor cannot be zero.
#[repr(C)]
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Debug, Copy)]
pub struct Sim3<N> {
/// The uniform scale applicable by this similarity transformation.
scale: N,
/// The isometry applicable by this similarity transformation.
pub isometry: Iso3<N>
}
sim_impl!(Sim2, Iso2, Rot2, Vec2, Vec1);
dim_impl!(Sim2, 2);
sim_scale_impl!(Sim2);
sim_one_impl!(Sim2);
sim_mul_sim_impl!(Sim2);
sim_mul_iso_impl!(Sim2, Iso2);
sim_mul_rot_impl!(Sim2, Rot2);
sim_mul_pnt_vec_impl!(Sim2, Pnt2);
sim_mul_pnt_vec_impl!(Sim2, Vec2);
transformation_impl!(Sim2);
sim_transform_impl!(Sim2, Pnt2);
sim_inv_impl!(Sim2);
sim_to_homogeneous_impl!(Sim2, Mat3);
sim_approx_eq_impl!(Sim2);
sim_rand_impl!(Sim2);
sim_arbitrary_impl!(Sim2);
sim_display_impl!(Sim2);
sim_impl!(Sim3, Iso3, Rot3, Vec3, Vec3);
dim_impl!(Sim3, 3);
sim_scale_impl!(Sim3);
sim_one_impl!(Sim3);
sim_mul_sim_impl!(Sim3);
sim_mul_iso_impl!(Sim3, Iso3);
sim_mul_rot_impl!(Sim3, Rot3);
sim_mul_pnt_vec_impl!(Sim3, Pnt3);
sim_mul_pnt_vec_impl!(Sim3, Vec3);
transformation_impl!(Sim3);
sim_transform_impl!(Sim3, Pnt3);
sim_inv_impl!(Sim3);
sim_to_homogeneous_impl!(Sim3, Mat4);
sim_approx_eq_impl!(Sim3);
sim_rand_impl!(Sim3);
sim_arbitrary_impl!(Sim3);
sim_display_impl!(Sim3);

343
src/structs/sim_macros.rs Normal file
View File

@ -0,0 +1,343 @@
#![macro_use]
macro_rules! sim_impl(
($t: ident, $iso: ident, $rotmat: ident, $subvec: ident, $subrotvec: ident) => (
impl<N: BaseFloat> $t<N> {
/// Creates a new similarity transformation from a vector, an axis-angle rotation, and a scale factor.
///
/// The scale factor may be negative but not zero.
#[inline]
pub fn new(translation: $subvec<N>, rotation: $subrotvec<N>, scale: N) -> $t<N> {
assert!(!scale.is_zero(), "A similarity transformation scale factor cannot be zero.");
$t {
scale: scale,
isometry: $iso::new(translation, rotation)
}
}
/// Creates a new similarity transformation from a rotation matrix, a vector, and a scale factor.
///
/// The scale factor may be negative but not zero.
#[inline]
pub fn new_with_rotmat(translation: $subvec<N>, rotation: $rotmat<N>, scale: N) -> $t<N> {
assert!(!scale.is_zero(), "A similarity transformation scale factor cannot be zero.");
$t {
scale: scale,
isometry: $iso::new_with_rotmat(translation, rotation)
}
}
/// Creates a new similarity transformation from an isometry and a scale factor.
///
/// The scale factor may be negative but not zero.
#[inline]
pub fn new_with_iso(isometry: $iso<N>, scale: N) -> $t<N> {
assert!(!scale.is_zero(), "A similarity transformation scale factor cannot be zero.");
$t {
scale: scale,
isometry: isometry
}
}
}
)
);
macro_rules! sim_scale_impl(
($t: ident) => (
impl<N: BaseFloat> $t<N> {
/// The scale factor of this similarity transformation.
#[inline]
pub fn scale(&self) -> N {
self.scale
}
/// The inverse scale factor of this similarity transformation.
#[inline]
pub fn inv_scale(&self) -> N {
::one::<N>() / self.scale
}
/// Appends in-place a scale to this similarity transformation.
#[inline]
pub fn append_scale_mut(&mut self, s: &N) {
assert!(!s.is_zero(), "Cannot append a zero scale to a similarity transformation.");
self.scale = *s * self.scale;
self.isometry.translation = self.isometry.translation * *s;
}
/// Appends a scale to this similarity transformation.
#[inline]
pub fn append_scale(&self, s: &N) -> $t<N> {
assert!(!s.is_zero(), "Cannot append a zero scale to a similarity transformation.");
$t::new_with_rotmat(self.isometry.translation * *s, self.isometry.rotation, self.scale * *s)
}
/// Prepends in-place a scale to this similarity transformation.
#[inline]
pub fn prepend_scale_mut(&mut self, s: &N) {
assert!(!s.is_zero(), "Cannot prepend a zero scale to a similarity transformation.");
self.scale = self.scale * *s;
}
/// Prepends a scale to this similarity transformation.
#[inline]
pub fn prepend_scale(&self, s: &N) -> $t<N> {
assert!(!s.is_zero(), "A similarity transformation scale must not be zero.");
$t::new_with_iso(self.isometry, self.scale * *s)
}
/// Sets the scale of this similarity transformation.
#[inline]
pub fn set_scale(&mut self, s: N) {
assert!(!s.is_zero(), "A similarity transformation scale must not be zero.");
self.scale = s
}
}
)
);
macro_rules! sim_one_impl(
($t: ident) => (
impl<N: BaseFloat> One for $t<N> {
#[inline]
fn one() -> $t<N> {
$t::new_with_iso(::one(), ::one())
}
}
)
);
macro_rules! sim_mul_sim_impl(
($t: ident) => (
impl<N: BaseFloat> Mul<$t<N>> for $t<N> {
type Output = $t<N>;
#[inline]
fn mul(self, right: $t<N>) -> $t<N> {
$t::new_with_rotmat(
self.isometry.translation + self.isometry.rotation * (right.isometry.translation * self.scale),
self.isometry.rotation * right.isometry.rotation,
self.scale * right.scale)
}
}
)
);
macro_rules! sim_mul_iso_impl(
($t: ident, $ti: ident) => (
impl<N: BaseFloat> Mul<$ti<N>> for $t<N> {
type Output = $t<N>;
#[inline]
fn mul(self, right: $ti<N>) -> $t<N> {
$t::new_with_rotmat(
self.isometry.translation + self.isometry.rotation * (right.translation * self.scale),
self.isometry.rotation * right.rotation,
self.scale)
}
}
impl<N: BaseFloat> Mul<$t<N>> for $ti<N> {
type Output = $t<N>;
#[inline]
fn mul(self, right: $t<N>) -> $t<N> {
$t::new_with_rotmat(
self.translation + self.rotation * right.isometry.translation,
self.rotation * right.isometry.rotation,
right.scale)
}
}
)
);
macro_rules! sim_mul_rot_impl(
($t: ident, $tr: ident) => (
impl<N: BaseFloat> Mul<$tr<N>> for $t<N> {
type Output = $t<N>;
#[inline]
fn mul(self, right: $tr<N>) -> $t<N> {
$t::new_with_rotmat(
self.isometry.translation,
self.isometry.rotation * right,
self.scale)
}
}
impl<N: BaseFloat> Mul<$t<N>> for $tr<N> {
type Output = $t<N>;
#[inline]
fn mul(self, right: $t<N>) -> $t<N> {
$t::new_with_rotmat(
self * right.isometry.translation,
self * right.isometry.rotation,
right.scale)
}
}
)
);
macro_rules! sim_mul_pnt_vec_impl(
($t: ident, $tv: ident) => (
impl<N: BaseNum> Mul<$tv<N>> for $t<N> {
type Output = $tv<N>;
#[inline]
fn mul(self, right: $tv<N>) -> $tv<N> {
self.isometry * (right * self.scale)
}
}
// NOTE: there is no viable pre-multiplication definition because of the translation
// component.
)
);
macro_rules! sim_transform_impl(
($t: ident, $tp: ident) => (
impl<N: BaseNum> Transform<$tp<N>> for $t<N> {
#[inline]
fn transform(&self, p: &$tp<N>) -> $tp<N> {
self.isometry.transform(&(*p * self.scale))
}
#[inline]
fn inv_transform(&self, p: &$tp<N>) -> $tp<N> {
self.isometry.inv_transform(p) / self.scale
}
}
)
);
macro_rules! sim_inv_impl(
($t: ident) => (
impl<N: BaseNum + Neg<Output = N>> Inv for $t<N> {
#[inline]
fn inv_mut(&mut self) -> bool {
self.scale = ::one::<N>() / self.scale;
self.isometry.inv_mut();
// We multiply (instead of dividing) by self.scale because it has already been
// inverted.
self.isometry.translation = self.isometry.translation * self.scale;
// Always succeed.
true
}
#[inline]
fn inv(&self) -> Option<$t<N>> {
let mut res = *self;
res.inv_mut();
// Always succeed.
Some(res)
}
}
)
);
macro_rules! sim_to_homogeneous_impl(
($t: ident, $th: ident) => (
impl<N: BaseNum> ToHomogeneous<$th<N>> for $t<N> {
fn to_homogeneous(&self) -> $th<N> {
let mut res = (*self.isometry.rotation.submat() * self.scale).to_homogeneous();
// copy the translation
let dim = Dim::dim(None::<$th<N>>);
res.set_col(dim - 1, self.isometry.translation.as_pnt().to_homogeneous().to_vec());
res
}
}
)
);
macro_rules! sim_approx_eq_impl(
($t: ident) => (
impl<N: ApproxEq<N>> ApproxEq<N> for $t<N> {
#[inline]
fn approx_epsilon(_: Option<$t<N>>) -> N {
ApproxEq::approx_epsilon(None::<N>)
}
#[inline]
fn approx_ulps(_: Option<$t<N>>) -> u32 {
ApproxEq::approx_ulps(None::<N>)
}
#[inline]
fn approx_eq_eps(&self, other: &$t<N>, epsilon: &N) -> bool {
ApproxEq::approx_eq_eps(&self.scale, &other.scale, epsilon) &&
ApproxEq::approx_eq_eps(&self.isometry, &other.isometry, epsilon)
}
#[inline]
fn approx_eq_ulps(&self, other: &$t<N>, ulps: u32) -> bool {
ApproxEq::approx_eq_ulps(&self.scale, &other.scale, ulps) &&
ApproxEq::approx_eq_ulps(&self.isometry, &other.isometry, ulps)
}
}
)
);
macro_rules! sim_rand_impl(
($t: ident) => (
impl<N: Rand + BaseFloat> Rand for $t<N> {
#[inline]
fn rand<R: Rng>(rng: &mut R) -> $t<N> {
let mut scale: N = rng.gen();
while scale.is_zero() {
scale = rng.gen();
}
$t::new_with_iso(rng.gen(), scale)
}
}
)
);
macro_rules! sim_arbitrary_impl(
($t: ident) => (
#[cfg(feature="arbitrary")]
impl<N: Arbitrary + BaseFloat> Arbitrary for $t<N> {
fn arbitrary<G: Gen>(g: &mut G) -> $t<N> {
$t::new_with_iso(
Arbitrary::arbitrary(g),
Arbitrary::arbitrary(g)
)
}
}
)
);
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, "}}")
}
}
)
);

View File

@ -1,219 +1,170 @@
//! nalgebra trait implementation for primitive types. //! nalgebra trait implementation for primitive types.
#![allow(missing_docs)]
#![allow(non_camel_case_types)]
use traits::structure::Cast; use traits::structure::Cast;
// Double dispatch traits to drive the Cast method for primitive types. macro_rules! primitive_cast_impl(
macro_rules! primitive_double_dispatch_cast_decl_trait( ($from: ty, $to: ty) => (
($t: ident, $tcast: ident) => ( impl Cast<$from> for $to {
pub trait $tcast {
fn to(Self) -> $t;
}
)
);
macro_rules! primitive_double_dispatch_cast_impl(
($ttarget: ident, $tself: ident, $tcast: ident) => (
impl $tcast for $tself{
#[inline(always)] #[inline(always)]
fn to(v: $tself) -> $ttarget { fn from(t: $from) -> $to {
v as $ttarget t as $to
} }
} }
) )
); );
macro_rules! primitive_cast_redispatch_impl( primitive_cast_impl!(f64, f64);
($t:ident, $tcast: ident) => ( primitive_cast_impl!(f64, f32);
impl<T: $tcast> Cast<T> for $t { primitive_cast_impl!(f64, i64);
#[inline(always)] primitive_cast_impl!(f64, i32);
fn from(t: T) -> $t { primitive_cast_impl!(f64, i16);
$tcast::to(t) primitive_cast_impl!(f64, i8);
} primitive_cast_impl!(f64, u64);
} primitive_cast_impl!(f64, u32);
) primitive_cast_impl!(f64, u16);
); primitive_cast_impl!(f64, u8);
primitive_cast_impl!(f64, isize);
primitive_cast_impl!(f64, usize);
primitive_double_dispatch_cast_decl_trait!(f64, f64Cast); primitive_cast_impl!(f32, f64);
primitive_double_dispatch_cast_decl_trait!(f32, f32Cast); primitive_cast_impl!(f32, f32);
primitive_double_dispatch_cast_decl_trait!(i64, i64Cast); primitive_cast_impl!(f32, i64);
primitive_double_dispatch_cast_decl_trait!(i32, i32Cast); primitive_cast_impl!(f32, i32);
primitive_double_dispatch_cast_decl_trait!(i16, i16Cast); primitive_cast_impl!(f32, i16);
primitive_double_dispatch_cast_decl_trait!(i8, i8Cast); primitive_cast_impl!(f32, i8);
primitive_double_dispatch_cast_decl_trait!(u64, u64Cast); primitive_cast_impl!(f32, u64);
primitive_double_dispatch_cast_decl_trait!(u32, u32Cast); primitive_cast_impl!(f32, u32);
primitive_double_dispatch_cast_decl_trait!(u16, u16Cast); primitive_cast_impl!(f32, u16);
primitive_double_dispatch_cast_decl_trait!(u8, u8Cast); primitive_cast_impl!(f32, u8);
primitive_double_dispatch_cast_decl_trait!(isize, isizeCast); primitive_cast_impl!(f32, isize);
primitive_double_dispatch_cast_decl_trait!(usize, usizeCast); primitive_cast_impl!(f32, usize);
primitive_cast_redispatch_impl!(f64, f64Cast); primitive_cast_impl!(i64, f64);
primitive_cast_redispatch_impl!(f32, f32Cast); primitive_cast_impl!(i64, f32);
primitive_cast_redispatch_impl!(i64, i64Cast); primitive_cast_impl!(i64, i64);
primitive_cast_redispatch_impl!(i32, i32Cast); primitive_cast_impl!(i64, i32);
primitive_cast_redispatch_impl!(i16, i16Cast); primitive_cast_impl!(i64, i16);
primitive_cast_redispatch_impl!(i8, i8Cast); primitive_cast_impl!(i64, i8);
primitive_cast_redispatch_impl!(u64, u64Cast); primitive_cast_impl!(i64, u64);
primitive_cast_redispatch_impl!(u32, u32Cast); primitive_cast_impl!(i64, u32);
primitive_cast_redispatch_impl!(u16, u16Cast); primitive_cast_impl!(i64, u16);
primitive_cast_redispatch_impl!(u8, u8Cast); primitive_cast_impl!(i64, u8);
primitive_cast_redispatch_impl!(isize, isizeCast); primitive_cast_impl!(i64, isize);
primitive_cast_redispatch_impl!(usize, usizeCast); primitive_cast_impl!(i64, usize);
primitive_double_dispatch_cast_impl!(f64, f64, f64Cast); primitive_cast_impl!(i32, f64);
primitive_double_dispatch_cast_impl!(f64, f32, f64Cast); primitive_cast_impl!(i32, f32);
primitive_double_dispatch_cast_impl!(f64, i64, f64Cast); primitive_cast_impl!(i32, i64);
primitive_double_dispatch_cast_impl!(f64, i32, f64Cast); primitive_cast_impl!(i32, i32);
primitive_double_dispatch_cast_impl!(f64, i16, f64Cast); primitive_cast_impl!(i32, i16);
primitive_double_dispatch_cast_impl!(f64, i8, f64Cast); primitive_cast_impl!(i32, i8);
primitive_double_dispatch_cast_impl!(f64, u64, f64Cast); primitive_cast_impl!(i32, u64);
primitive_double_dispatch_cast_impl!(f64, u32, f64Cast); primitive_cast_impl!(i32, u32);
primitive_double_dispatch_cast_impl!(f64, u16, f64Cast); primitive_cast_impl!(i32, u16);
primitive_double_dispatch_cast_impl!(f64, u8, f64Cast); primitive_cast_impl!(i32, u8);
primitive_double_dispatch_cast_impl!(f64, isize, f64Cast); primitive_cast_impl!(i32, isize);
primitive_double_dispatch_cast_impl!(f64, usize, f64Cast); primitive_cast_impl!(i32, usize);
primitive_double_dispatch_cast_impl!(f32, f64, f32Cast); primitive_cast_impl!(i16, f64);
primitive_double_dispatch_cast_impl!(f32, f32, f32Cast); primitive_cast_impl!(i16, f32);
primitive_double_dispatch_cast_impl!(f32, i64, f32Cast); primitive_cast_impl!(i16, i64);
primitive_double_dispatch_cast_impl!(f32, i32, f32Cast); primitive_cast_impl!(i16, i32);
primitive_double_dispatch_cast_impl!(f32, i16, f32Cast); primitive_cast_impl!(i16, i16);
primitive_double_dispatch_cast_impl!(f32, i8, f32Cast); primitive_cast_impl!(i16, i8);
primitive_double_dispatch_cast_impl!(f32, u64, f32Cast); primitive_cast_impl!(i16, u64);
primitive_double_dispatch_cast_impl!(f32, u32, f32Cast); primitive_cast_impl!(i16, u32);
primitive_double_dispatch_cast_impl!(f32, u16, f32Cast); primitive_cast_impl!(i16, u16);
primitive_double_dispatch_cast_impl!(f32, u8, f32Cast); primitive_cast_impl!(i16, u8);
primitive_double_dispatch_cast_impl!(f32, isize, f32Cast); primitive_cast_impl!(i16, isize);
primitive_double_dispatch_cast_impl!(f32, usize, f32Cast); primitive_cast_impl!(i16, usize);
primitive_double_dispatch_cast_impl!(i64, f64, i64Cast); primitive_cast_impl!(i8, f64);
primitive_double_dispatch_cast_impl!(i64, f32, i64Cast); primitive_cast_impl!(i8, f32);
primitive_double_dispatch_cast_impl!(i64, i64, i64Cast); primitive_cast_impl!(i8, i64);
primitive_double_dispatch_cast_impl!(i64, i32, i64Cast); primitive_cast_impl!(i8, i32);
primitive_double_dispatch_cast_impl!(i64, i16, i64Cast); primitive_cast_impl!(i8, i16);
primitive_double_dispatch_cast_impl!(i64, i8, i64Cast); primitive_cast_impl!(i8, i8);
primitive_double_dispatch_cast_impl!(i64, u64, i64Cast); primitive_cast_impl!(i8, u64);
primitive_double_dispatch_cast_impl!(i64, u32, i64Cast); primitive_cast_impl!(i8, u32);
primitive_double_dispatch_cast_impl!(i64, u16, i64Cast); primitive_cast_impl!(i8, u16);
primitive_double_dispatch_cast_impl!(i64, u8, i64Cast); primitive_cast_impl!(i8, u8);
primitive_double_dispatch_cast_impl!(i64, isize, i64Cast); primitive_cast_impl!(i8, isize);
primitive_double_dispatch_cast_impl!(i64, usize, i64Cast); primitive_cast_impl!(i8, usize);
primitive_double_dispatch_cast_impl!(i32, f64, i32Cast); primitive_cast_impl!(u64, f64);
primitive_double_dispatch_cast_impl!(i32, f32, i32Cast); primitive_cast_impl!(u64, f32);
primitive_double_dispatch_cast_impl!(i32, i64, i32Cast); primitive_cast_impl!(u64, i64);
primitive_double_dispatch_cast_impl!(i32, i32, i32Cast); primitive_cast_impl!(u64, i32);
primitive_double_dispatch_cast_impl!(i32, i16, i32Cast); primitive_cast_impl!(u64, i16);
primitive_double_dispatch_cast_impl!(i32, i8, i32Cast); primitive_cast_impl!(u64, i8);
primitive_double_dispatch_cast_impl!(i32, u64, i32Cast); primitive_cast_impl!(u64, u64);
primitive_double_dispatch_cast_impl!(i32, u32, i32Cast); primitive_cast_impl!(u64, u32);
primitive_double_dispatch_cast_impl!(i32, u16, i32Cast); primitive_cast_impl!(u64, u16);
primitive_double_dispatch_cast_impl!(i32, u8, i32Cast); primitive_cast_impl!(u64, u8);
primitive_double_dispatch_cast_impl!(i32, isize, i32Cast); primitive_cast_impl!(u64, isize);
primitive_double_dispatch_cast_impl!(i32, usize, i32Cast); primitive_cast_impl!(u64, usize);
primitive_double_dispatch_cast_impl!(i16, f64, i16Cast); primitive_cast_impl!(u32, f64);
primitive_double_dispatch_cast_impl!(i16, f32, i16Cast); primitive_cast_impl!(u32, f32);
primitive_double_dispatch_cast_impl!(i16, i64, i16Cast); primitive_cast_impl!(u32, i64);
primitive_double_dispatch_cast_impl!(i16, i32, i16Cast); primitive_cast_impl!(u32, i32);
primitive_double_dispatch_cast_impl!(i16, i16, i16Cast); primitive_cast_impl!(u32, i16);
primitive_double_dispatch_cast_impl!(i16, i8, i16Cast); primitive_cast_impl!(u32, i8);
primitive_double_dispatch_cast_impl!(i16, u64, i16Cast); primitive_cast_impl!(u32, u64);
primitive_double_dispatch_cast_impl!(i16, u32, i16Cast); primitive_cast_impl!(u32, u32);
primitive_double_dispatch_cast_impl!(i16, u16, i16Cast); primitive_cast_impl!(u32, u16);
primitive_double_dispatch_cast_impl!(i16, u8, i16Cast); primitive_cast_impl!(u32, u8);
primitive_double_dispatch_cast_impl!(i16, isize, i16Cast); primitive_cast_impl!(u32, isize);
primitive_double_dispatch_cast_impl!(i16, usize, i16Cast); primitive_cast_impl!(u32, usize);
primitive_double_dispatch_cast_impl!(i8, f64, i8Cast); primitive_cast_impl!(u16, f64);
primitive_double_dispatch_cast_impl!(i8, f32, i8Cast); primitive_cast_impl!(u16, f32);
primitive_double_dispatch_cast_impl!(i8, i64, i8Cast); primitive_cast_impl!(u16, i64);
primitive_double_dispatch_cast_impl!(i8, i32, i8Cast); primitive_cast_impl!(u16, i32);
primitive_double_dispatch_cast_impl!(i8, i16, i8Cast); primitive_cast_impl!(u16, i16);
primitive_double_dispatch_cast_impl!(i8, i8, i8Cast); primitive_cast_impl!(u16, i8);
primitive_double_dispatch_cast_impl!(i8, u64, i8Cast); primitive_cast_impl!(u16, u64);
primitive_double_dispatch_cast_impl!(i8, u32, i8Cast); primitive_cast_impl!(u16, u32);
primitive_double_dispatch_cast_impl!(i8, u16, i8Cast); primitive_cast_impl!(u16, u16);
primitive_double_dispatch_cast_impl!(i8, u8, i8Cast); primitive_cast_impl!(u16, u8);
primitive_double_dispatch_cast_impl!(i8, isize, i8Cast); primitive_cast_impl!(u16, isize);
primitive_double_dispatch_cast_impl!(i8, usize, i8Cast); primitive_cast_impl!(u16, usize);
primitive_double_dispatch_cast_impl!(u64, f64, u64Cast); primitive_cast_impl!(u8, f64);
primitive_double_dispatch_cast_impl!(u64, f32, u64Cast); primitive_cast_impl!(u8, f32);
primitive_double_dispatch_cast_impl!(u64, i64, u64Cast); primitive_cast_impl!(u8, i64);
primitive_double_dispatch_cast_impl!(u64, i32, u64Cast); primitive_cast_impl!(u8, i32);
primitive_double_dispatch_cast_impl!(u64, i16, u64Cast); primitive_cast_impl!(u8, i16);
primitive_double_dispatch_cast_impl!(u64, i8, u64Cast); primitive_cast_impl!(u8, i8);
primitive_double_dispatch_cast_impl!(u64, u64, u64Cast); primitive_cast_impl!(u8, u64);
primitive_double_dispatch_cast_impl!(u64, u32, u64Cast); primitive_cast_impl!(u8, u32);
primitive_double_dispatch_cast_impl!(u64, u16, u64Cast); primitive_cast_impl!(u8, u16);
primitive_double_dispatch_cast_impl!(u64, u8, u64Cast); primitive_cast_impl!(u8, u8);
primitive_double_dispatch_cast_impl!(u64, isize, u64Cast); primitive_cast_impl!(u8, isize);
primitive_double_dispatch_cast_impl!(u64, usize, u64Cast); primitive_cast_impl!(u8, usize);
primitive_double_dispatch_cast_impl!(u32, f64, u32Cast); primitive_cast_impl!(usize, f64);
primitive_double_dispatch_cast_impl!(u32, f32, u32Cast); primitive_cast_impl!(usize, f32);
primitive_double_dispatch_cast_impl!(u32, i64, u32Cast); primitive_cast_impl!(usize, i64);
primitive_double_dispatch_cast_impl!(u32, i32, u32Cast); primitive_cast_impl!(usize, i32);
primitive_double_dispatch_cast_impl!(u32, i16, u32Cast); primitive_cast_impl!(usize, i16);
primitive_double_dispatch_cast_impl!(u32, i8, u32Cast); primitive_cast_impl!(usize, i8);
primitive_double_dispatch_cast_impl!(u32, u64, u32Cast); primitive_cast_impl!(usize, u64);
primitive_double_dispatch_cast_impl!(u32, u32, u32Cast); primitive_cast_impl!(usize, u32);
primitive_double_dispatch_cast_impl!(u32, u16, u32Cast); primitive_cast_impl!(usize, u16);
primitive_double_dispatch_cast_impl!(u32, u8, u32Cast); primitive_cast_impl!(usize, u8);
primitive_double_dispatch_cast_impl!(u32, isize, u32Cast); primitive_cast_impl!(usize, isize);
primitive_double_dispatch_cast_impl!(u32, usize, u32Cast); primitive_cast_impl!(usize, usize);
primitive_double_dispatch_cast_impl!(u16, f64, u16Cast); primitive_cast_impl!(isize, f64);
primitive_double_dispatch_cast_impl!(u16, f32, u16Cast); primitive_cast_impl!(isize, f32);
primitive_double_dispatch_cast_impl!(u16, i64, u16Cast); primitive_cast_impl!(isize, i64);
primitive_double_dispatch_cast_impl!(u16, i32, u16Cast); primitive_cast_impl!(isize, i32);
primitive_double_dispatch_cast_impl!(u16, i16, u16Cast); primitive_cast_impl!(isize, i16);
primitive_double_dispatch_cast_impl!(u16, i8, u16Cast); primitive_cast_impl!(isize, i8);
primitive_double_dispatch_cast_impl!(u16, u64, u16Cast); primitive_cast_impl!(isize, u64);
primitive_double_dispatch_cast_impl!(u16, u32, u16Cast); primitive_cast_impl!(isize, u32);
primitive_double_dispatch_cast_impl!(u16, u16, u16Cast); primitive_cast_impl!(isize, u16);
primitive_double_dispatch_cast_impl!(u16, u8, u16Cast); primitive_cast_impl!(isize, u8);
primitive_double_dispatch_cast_impl!(u16, isize, u16Cast); primitive_cast_impl!(isize, isize);
primitive_double_dispatch_cast_impl!(u16, usize, u16Cast); primitive_cast_impl!(isize, usize);
primitive_double_dispatch_cast_impl!(u8, f64, u8Cast);
primitive_double_dispatch_cast_impl!(u8, f32, u8Cast);
primitive_double_dispatch_cast_impl!(u8, i64, u8Cast);
primitive_double_dispatch_cast_impl!(u8, i32, u8Cast);
primitive_double_dispatch_cast_impl!(u8, i16, u8Cast);
primitive_double_dispatch_cast_impl!(u8, i8, u8Cast);
primitive_double_dispatch_cast_impl!(u8, u64, u8Cast);
primitive_double_dispatch_cast_impl!(u8, u32, u8Cast);
primitive_double_dispatch_cast_impl!(u8, u16, u8Cast);
primitive_double_dispatch_cast_impl!(u8, u8, u8Cast);
primitive_double_dispatch_cast_impl!(u8, isize, u8Cast);
primitive_double_dispatch_cast_impl!(u8, usize, u8Cast);
primitive_double_dispatch_cast_impl!(usize, f64, usizeCast);
primitive_double_dispatch_cast_impl!(usize, f32, usizeCast);
primitive_double_dispatch_cast_impl!(usize, i64, usizeCast);
primitive_double_dispatch_cast_impl!(usize, i32, usizeCast);
primitive_double_dispatch_cast_impl!(usize, i16, usizeCast);
primitive_double_dispatch_cast_impl!(usize, i8, usizeCast);
primitive_double_dispatch_cast_impl!(usize, u64, usizeCast);
primitive_double_dispatch_cast_impl!(usize, u32, usizeCast);
primitive_double_dispatch_cast_impl!(usize, u16, usizeCast);
primitive_double_dispatch_cast_impl!(usize, u8, usizeCast);
primitive_double_dispatch_cast_impl!(usize, isize, usizeCast);
primitive_double_dispatch_cast_impl!(usize, usize, usizeCast);
primitive_double_dispatch_cast_impl!(isize, f64, isizeCast);
primitive_double_dispatch_cast_impl!(isize, f32, isizeCast);
primitive_double_dispatch_cast_impl!(isize, i64, isizeCast);
primitive_double_dispatch_cast_impl!(isize, i32, isizeCast);
primitive_double_dispatch_cast_impl!(isize, i16, isizeCast);
primitive_double_dispatch_cast_impl!(isize, i8, isizeCast);
primitive_double_dispatch_cast_impl!(isize, u64, isizeCast);
primitive_double_dispatch_cast_impl!(isize, u32, isizeCast);
primitive_double_dispatch_cast_impl!(isize, u16, isizeCast);
primitive_double_dispatch_cast_impl!(isize, u8, isizeCast);
primitive_double_dispatch_cast_impl!(isize, isize, isizeCast);
primitive_double_dispatch_cast_impl!(isize, usize, isizeCast);

View File

@ -1,257 +0,0 @@
use std::ops::{Add, Sub, Mul, Div, Neg, Index, IndexMut};
use std::marker::PhantomData;
use std::mem;
use std::slice::{Iter, IterMut};
use std::iter::{FromIterator, IntoIterator};
use rand::{Rand, Rng};
use num::{Zero, One};
use traits::operations::ApproxEq;
use traits::structure::{Iterable, IterableMut, Indexable, Basis, Dim, Shape, BaseFloat, BaseNum, Bounded};
use traits::geometry::{Translation, Dot, Norm};
use structs::vec;
impl<N> Zero for vec::Vec0<N> {
#[inline]
fn zero() -> vec::Vec0<N> {
vec::Vec0(PhantomData)
}
#[inline]
fn is_zero(&self) -> bool {
true
}
}
impl<N> Index<usize> for vec::Vec0<N> {
type Output = N;
#[inline]
fn index(&self, _: usize) -> &N {
panic!("Canot index a Vec0.")
}
}
impl<N> IndexMut<usize> for vec::Vec0<N> {
#[inline]
fn index_mut(&mut self, _: usize) -> &mut N {
panic!("Canot index a Vec0.")
}
}
impl<N> Shape<usize> for vec::Vec0<N> {
#[inline]
fn shape(&self) -> usize {
0
}
}
impl<N> Indexable<usize, N> for vec::Vec0<N> {
#[inline]
fn swap(&mut self, _: usize, _: usize) {
}
#[inline]
unsafe fn unsafe_at(&self, _: usize) -> N {
panic!("Cannot index a Vec0.")
}
#[inline]
unsafe fn unsafe_set(&mut self, _: usize, _: N) {
}
}
impl<N: 'static> Iterable<N> for vec::Vec0<N> {
#[inline]
fn iter<'l>(&'l self) -> Iter<'l, N> {
unsafe { mem::transmute::<&'l vec::Vec0<N>, &'l [N; 0]>(self).iter() }
}
}
impl<N: 'static> IterableMut<N> for vec::Vec0<N> {
#[inline]
fn iter_mut<'l>(&'l mut self) -> IterMut<'l, N> {
unsafe { mem::transmute::<&'l mut vec::Vec0<N>, &'l mut [N; 0]>(self).iter_mut() }
}
}
impl<N> Dim for vec::Vec0<N> {
#[inline]
fn dim(_: Option<vec::Vec0<N>>) -> usize {
0
}
}
impl<N> Basis for vec::Vec0<N> {
#[inline(always)]
fn canonical_basis<F: FnMut(vec::Vec0<N>) -> bool>(_: F) { }
#[inline(always)]
fn orthonormal_subspace_basis<F: FnMut(vec::Vec0<N>) -> bool>(_: &vec::Vec0<N>, _: F) { }
#[inline(always)]
fn canonical_basis_element(_: usize) -> Option<vec::Vec0<N>> {
None
}
}
impl<N, T> Add<T> for vec::Vec0<N> {
type Output = vec::Vec0<N>;
#[inline]
fn add(self, _: T) -> vec::Vec0<N> {
vec::Vec0(PhantomData)
}
}
impl<N, T> Sub<T> for vec::Vec0<N> {
type Output = vec::Vec0<N>;
#[inline]
fn sub(self, _: T) -> vec::Vec0<N> {
vec::Vec0(PhantomData)
}
}
impl<N: Neg<Output = N> + Copy> Neg for vec::Vec0<N> {
type Output = vec::Vec0<N>;
#[inline]
fn neg(self) -> vec::Vec0<N> {
vec::Vec0(PhantomData)
}
}
impl<N: BaseNum> Dot<N> for vec::Vec0<N> {
#[inline]
fn dot(&self, _: &vec::Vec0<N>) -> N {
::zero()
}
}
impl<N, T> Mul<T> for vec::Vec0<N> {
type Output = vec::Vec0<N>;
#[inline]
fn mul(self, _: T) -> vec::Vec0<N> {
vec::Vec0(PhantomData)
}
}
impl<N, T> Div<T> for vec::Vec0<N> {
type Output = vec::Vec0<N>;
#[inline]
fn div(self, _: T) -> vec::Vec0<N> {
vec::Vec0(PhantomData)
}
}
impl<N: Copy + Add<N, Output = N> + Neg<Output = N>> Translation<vec::Vec0<N>> for vec::Vec0<N> {
#[inline]
fn translation(&self) -> vec::Vec0<N> {
*self
}
#[inline]
fn inv_translation(&self) -> vec::Vec0<N> {
-*self
}
#[inline]
fn append_translation_mut(&mut self, t: &vec::Vec0<N>) {
*self = *t + *self;
}
#[inline]
fn append_translation(&self, t: &vec::Vec0<N>) -> vec::Vec0<N> {
*t + self
}
#[inline]
fn prepend_translation_mut(&mut self, t: &vec::Vec0<N>) {
*self = *self + *t;
}
#[inline]
fn prepend_translation(&self, t: &vec::Vec0<N>) -> vec::Vec0<N> {
*self + *t
}
#[inline]
fn set_translation(&mut self, _: vec::Vec0<N>) {
}
}
impl<N: BaseFloat> Norm<N> for vec::Vec0<N> {
#[inline]
fn sqnorm(&self) -> N {
::zero()
}
#[inline]
fn norm(&self) -> N {
::zero()
}
#[inline]
fn normalize(&self) -> vec::Vec0<N> {
::zero()
}
#[inline]
fn normalize_mut(&mut self) -> N {
::zero()
}
}
impl<N: ApproxEq<N>> ApproxEq<N> for vec::Vec0<N> {
#[inline]
fn approx_epsilon(_: Option<vec::Vec0<N>>) -> N {
ApproxEq::approx_epsilon(None::<N>)
}
fn approx_ulps(_: Option<vec::Vec0<N>>) -> u32 {
ApproxEq::approx_ulps(None::<N>)
}
#[inline]
fn approx_eq_eps(&self, _: &vec::Vec0<N>, _: &N) -> bool {
true
}
#[inline]
fn approx_eq_ulps(&self, _: &vec::Vec0<N>, _: u32) -> bool {
true
}
}
impl<N: One> One for vec::Vec0<N> {
#[inline]
fn one() -> vec::Vec0<N> {
vec::Vec0(PhantomData)
}
}
impl<N> FromIterator<N> for vec::Vec0<N> {
#[inline]
fn from_iter<I: IntoIterator<Item = N>>(_: I) -> vec::Vec0<N> {
vec::Vec0(PhantomData)
}
}
impl<N: Bounded> Bounded for vec::Vec0<N> {
#[inline]
fn max_value() -> vec::Vec0<N> {
vec::Vec0(PhantomData)
}
#[inline]
fn min_value() -> vec::Vec0<N> {
vec::Vec0(PhantomData)
}
}
impl<N> Rand for vec::Vec0<N> {
#[inline]
fn rand<R: Rng>(_: &mut R) -> vec::Vec0<N> { vec::Vec0(PhantomData) }
}

View File

@ -1,12 +1,10 @@
//! Vectors with dimensions known at compile-time. //! Vectors with dimension known at compile-time.
#![allow(missing_docs)] // we allow missing to avoid having to document the dispatch traits.
use std::ops::{Add, Sub, Mul, Div, Neg, Index, IndexMut}; use std::ops::{Add, Sub, Mul, Div, Neg, Index, IndexMut};
use std::marker::PhantomData;
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};
@ -20,27 +18,10 @@ use structs::pnt::{Pnt1, Pnt2, Pnt3, Pnt4, Pnt5, Pnt6};
use quickcheck::{Arbitrary, Gen}; use quickcheck::{Arbitrary, Gen};
/// Vector of dimension 0.
#[repr(C)]
#[derive(Eq, PartialEq, Clone, Debug, Copy)]
pub struct Vec0<N>(pub PhantomData<N>);
impl<N> Vec0<N> {
/// Creates a new vector.
#[inline]
pub fn new() -> Vec0<N> {
Vec0(PhantomData)
}
}
impl<N> Repeat<N> for Vec0<N> {
#[inline]
fn repeat(_: N) -> Vec0<N> {
Vec0(PhantomData)
}
}
/// Vector of dimension 1. /// Vector of dimension 1.
///
/// The main differance between a point and a vector is that a vector is not affected by
/// translations.
#[repr(C)] #[repr(C)]
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)] #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)]
pub struct Vec1<N> { pub struct Vec1<N> {
@ -49,7 +30,7 @@ pub struct Vec1<N> {
} }
new_impl!(Vec1, x); new_impl!(Vec1, x);
ord_impl!(Vec1, x,); pord_impl!(Vec1, x,);
vec_axis_impl!(Vec1, x); vec_axis_impl!(Vec1, x);
vec_cast_impl!(Vec1, x); vec_cast_impl!(Vec1, x);
conversion_impl!(Vec1, 1); conversion_impl!(Vec1, 1);
@ -91,8 +72,12 @@ 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.
///
/// The main differance between a point and a vector is that a vector is not affected by
/// translations.
#[repr(C)] #[repr(C)]
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)] #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)]
pub struct Vec2<N> { pub struct Vec2<N> {
@ -103,7 +88,7 @@ pub struct Vec2<N> {
} }
new_impl!(Vec2, x, y); new_impl!(Vec2, x, y);
ord_impl!(Vec2, x, y); pord_impl!(Vec2, x, y);
vec_axis_impl!(Vec2, x, y); vec_axis_impl!(Vec2, x, y);
vec_cast_impl!(Vec2, x, y); vec_cast_impl!(Vec2, x, y);
conversion_impl!(Vec2, 2); conversion_impl!(Vec2, 2);
@ -145,8 +130,12 @@ 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.
///
/// The main differance between a point and a vector is that a vector is not affected by
/// translations.
#[repr(C)] #[repr(C)]
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)] #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)]
pub struct Vec3<N> { pub struct Vec3<N> {
@ -159,7 +148,7 @@ pub struct Vec3<N> {
} }
new_impl!(Vec3, x, y, z); new_impl!(Vec3, x, y, z);
ord_impl!(Vec3, x, y, z); pord_impl!(Vec3, x, y, z);
vec_axis_impl!(Vec3, x, y, z); vec_axis_impl!(Vec3, x, y, z);
vec_cast_impl!(Vec3, x, y, z); vec_cast_impl!(Vec3, x, y, z);
conversion_impl!(Vec3, 3); conversion_impl!(Vec3, 3);
@ -201,9 +190,13 @@ 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.
///
/// The main differance between a point and a vector is that a vector is not affected by
/// translations.
#[repr(C)] #[repr(C)]
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)] #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)]
pub struct Vec4<N> { pub struct Vec4<N> {
@ -218,7 +211,7 @@ pub struct Vec4<N> {
} }
new_impl!(Vec4, x, y, z, w); new_impl!(Vec4, x, y, z, w);
ord_impl!(Vec4, x, y, z, w); pord_impl!(Vec4, x, y, z, w);
vec_axis_impl!(Vec4, x, y, z, w); vec_axis_impl!(Vec4, x, y, z, w);
vec_cast_impl!(Vec4, x, y, z, w); vec_cast_impl!(Vec4, x, y, z, w);
conversion_impl!(Vec4, 4); conversion_impl!(Vec4, 4);
@ -260,8 +253,12 @@ 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.
///
/// The main differance between a point and a vector is that a vector is not affected by
/// translations.
#[repr(C)] #[repr(C)]
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)] #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)]
pub struct Vec5<N> { pub struct Vec5<N> {
@ -278,7 +275,7 @@ pub struct Vec5<N> {
} }
new_impl!(Vec5, x, y, z, w, a); new_impl!(Vec5, x, y, z, w, a);
ord_impl!(Vec5, x, y, z, w, a); pord_impl!(Vec5, x, y, z, w, a);
vec_axis_impl!(Vec5, x, y, z, w, a); vec_axis_impl!(Vec5, x, y, z, w, a);
vec_cast_impl!(Vec5, x, y, z, w, a); vec_cast_impl!(Vec5, x, y, z, w, a);
conversion_impl!(Vec5, 5); conversion_impl!(Vec5, 5);
@ -320,8 +317,12 @@ 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.
///
/// The main differance between a point and a vector is that a vector is not affected by
/// translations.
#[repr(C)] #[repr(C)]
#[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)] #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)]
pub struct Vec6<N> { pub struct Vec6<N> {
@ -340,7 +341,7 @@ pub struct Vec6<N> {
} }
new_impl!(Vec6, x, y, z, w, a, b); new_impl!(Vec6, x, y, z, w, a, b);
ord_impl!(Vec6, x, y, z, w, a, b); pord_impl!(Vec6, x, y, z, w, a, b);
vec_axis_impl!(Vec6, x, y, z, w, a, b); vec_axis_impl!(Vec6, x, y, z, w, a, b);
vec_cast_impl!(Vec6, x, y, z, w, a, b); vec_cast_impl!(Vec6, x, y, z, w, a, b);
conversion_impl!(Vec6, 6); conversion_impl!(Vec6, 6);
@ -380,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);

View File

@ -74,7 +74,7 @@ macro_rules! at_fast_impl(
// FIXME: N should be bounded by Ord instead of BaseFloat… // FIXME: N should be bounded by Ord instead of BaseFloat…
// However, f32/f64 does not implement Ord… // However, f32/f64 does not implement Ord…
macro_rules! ord_impl( macro_rules! pord_impl(
($t: ident, $comp0: ident, $($compN: ident),*) => ( ($t: ident, $comp0: ident, $($compN: ident),*) => (
impl<N: BaseFloat> POrd for $t<N> { impl<N: BaseFloat> POrd for $t<N> {
#[inline] #[inline]
@ -278,6 +278,7 @@ macro_rules! dim_impl(
macro_rules! container_impl( macro_rules! container_impl(
($t: ident) => ( ($t: ident) => (
impl<N> $t<N> { impl<N> $t<N> {
/// The dimension of this entity.
#[inline] #[inline]
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
Dim::dim(None::<$t<N>>) Dim::dim(None::<$t<N>>)
@ -291,18 +292,18 @@ macro_rules! basis_impl(
impl<N: BaseFloat + ApproxEq<N>> Basis for $t<N> { impl<N: BaseFloat + ApproxEq<N>> Basis for $t<N> {
#[inline] #[inline]
fn canonical_basis<F: FnMut($t<N>) -> bool>(mut f: F) { fn canonical_basis<F: FnMut($t<N>) -> bool>(mut f: F) {
for i in 0..$dim { for i in 0 .. $dim {
if !f(Basis::canonical_basis_element(i).unwrap()) { return } if !f(Basis::canonical_basis_element(i).unwrap()) { return }
} }
} }
#[inline] #[inline]
fn orthonormal_subspace_basis<F: FnMut($t<N>) -> bool>(n: &$t<N>, mut f: F) { fn orthonormal_subspace_basis<F: FnMut($t<N>) -> bool>(n: &$t<N>, mut f: F) {
// compute the basis of the orthogonal subspace using Gram-Schmidt // Compute the basis of the orthogonal subspace using Gram-Schmidt
// orthogonalization algorithm // orthogonalization algorithm.
let mut basis: Vec<$t<N>> = Vec::new(); let mut basis: Vec<$t<N>> = Vec::new();
for i in 0..$dim { for i in 0 .. $dim {
let mut basis_element : $t<N> = ::zero(); let mut basis_element : $t<N> = ::zero();
unsafe { unsafe {
@ -743,6 +744,7 @@ macro_rules! transform_impl(
macro_rules! vec_as_pnt_impl( macro_rules! vec_as_pnt_impl(
($tv: ident, $t: ident, $($compN: ident),+) => ( ($tv: ident, $t: ident, $($compN: ident),+) => (
impl<N> $tv<N> { impl<N> $tv<N> {
/// Converts this vector to a point.
#[inline] #[inline]
pub fn to_pnt(self) -> $t<N> { pub fn to_pnt(self) -> $t<N> {
$t::new( $t::new(
@ -750,6 +752,7 @@ macro_rules! vec_as_pnt_impl(
) )
} }
/// Reinterprets this vector as a point.
#[inline] #[inline]
pub fn as_pnt(&self) -> &$t<N> { pub fn as_pnt(&self) -> &$t<N> {
unsafe { unsafe {
@ -817,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, ")")
}
}
)
);

123
src/structs/vecn.rs Normal file
View File

@ -0,0 +1,123 @@
use std::slice::{Iter, IterMut};
use std::iter::{FromIterator, IntoIterator};
use std::ops::{Add, Sub, Mul, Div, Neg, Index, IndexMut};
use std::mem;
use rand::{Rand, Rng};
use num::{Zero, One};
use generic_array::{GenericArray, ArrayLength};
use traits::operations::{ApproxEq, Axpy, Mean};
use traits::geometry::{Dot, Norm};
use traits::structure::{Iterable, IterableMut, Indexable, Shape, BaseFloat, BaseNum, Cast, Dim};
#[cfg(feature="arbitrary")]
use quickcheck::{Arbitrary, Gen};
/// A static array of arbitrary dimension.
#[repr(C)]
#[derive(Eq, PartialEq, Debug)] // FIXME: Hash, RustcEncodable, RustcDecodable
pub struct VecN<N, D: ArrayLength<N>> {
/// The underlying data of the vector.
pub at: GenericArray<N, D>
}
unsafe impl<N: Send, D: ArrayLength<N>> Send for VecN<N, D> {
}
impl<N: Clone, D: ArrayLength<N>> Clone for VecN<N, D> {
fn clone(&self) -> VecN<N, D> {
VecN::new(self.at.clone())
}
}
impl<N: Copy, D: ArrayLength<N>> Copy for VecN<N, D>
where D::ArrayType: Copy { }
impl<N, D: ArrayLength<N>> VecN<N, D> {
/// Creates a new vector from a given arbirtarily-sized array.
#[inline]
pub fn new(components: GenericArray<N, D>) -> VecN<N, D> {
VecN {
at: components
}
}
/// The vector length.
#[inline]
pub fn len(&self) -> usize {
self.at.len()
}
}
impl<N, D: ArrayLength<N>> Dim for VecN<N, D> {
fn dim(_unused: Option<Self>) -> usize {
D::to_usize()
}
}
impl<N: Copy, D: ArrayLength<N>> FromIterator<N> for VecN<N, D> {
#[inline]
fn from_iter<I: IntoIterator<Item = N>>(param: I) -> VecN<N, D> {
let mut res: VecN<N, D> = unsafe { mem::uninitialized() };
let mut it = param.into_iter();
for e in res.iter_mut() {
*e = it.next().expect("Not enough data into the provided iterator to initialize this `VecN`.");
}
res
}
}
impl<N: Rand + Zero, D: ArrayLength<N>> Rand for VecN<N, D> {
#[inline]
fn rand<R: Rng>(rng: &mut R) -> VecN<N, D> {
let mut res: VecN<N, D> = unsafe { mem::uninitialized() };
for e in res.iter_mut() {
*e = Rand::rand(rng)
}
res
}
}
impl<N: Copy + One + Zero, D: ArrayLength<N>> One for VecN<N, D> {
#[inline]
fn one() -> VecN<N, D> {
let mut res: VecN<N, D> = unsafe { mem::uninitialized() };
for e in res.iter_mut() {
*e = ::one()
}
res
}
}
impl<N: Copy + Zero, D: ArrayLength<N>> Zero for VecN<N, D> {
#[inline]
fn zero() -> VecN<N, D> {
let mut res: VecN<N, D> = unsafe { mem::uninitialized() };
for e in res.iter_mut() {
*e = ::zero()
}
res
}
#[inline]
fn is_zero(&self) -> bool {
self.iter().all(|e| e.is_zero())
}
}
#[cfg(feature="arbitrary")]
impl<N: Arbitrary + Zero + Copy, D: 'static + ArrayLength<N>> Arbitrary for VecN<N, D> {
#[inline]
fn arbitrary<G: Gen>(g: &mut G) -> VecN<N, D> {
(0 .. D::to_usize()).map(|_| Arbitrary::arbitrary(g)).collect()
}
}
vecn_dvec_common_impl!(VecN, D);

312
src/structs/vecn_macros.rs Normal file
View File

@ -0,0 +1,312 @@
#![macro_use]
macro_rules! vecn_dvec_common_impl(
($vecn: ident $(, $param: ident)*) => (
impl<N: Zero + Copy + Clone $(, $param: ArrayLength<N>)*> $vecn<N $(, $param)*> {
/// Tests if all components of the vector are zeroes.
#[inline]
pub fn is_zero(&self) -> bool {
self.as_ref().iter().all(|e| e.is_zero())
}
}
impl<N $(, $param: ArrayLength<N>)*> AsRef<[N]> for $vecn<N $(, $param)*> {
#[inline]
fn as_ref(&self) -> &[N] {
&self.at[.. self.len()]
}
}
impl<N $(, $param: ArrayLength<N>)*> AsMut<[N]> for $vecn<N $(, $param)*> {
#[inline]
fn as_mut(&mut self) -> &mut [N] {
let len = self.len();
&mut self.at[.. len]
}
}
impl<N $(, $param: ArrayLength<N>)*> Shape<usize> for $vecn<N $(, $param)*> {
#[inline]
fn shape(&self) -> usize {
self.len()
}
}
impl<N: Copy $(, $param : ArrayLength<N>)*> Indexable<usize, N> for $vecn<N $(, $param)*> {
#[inline]
fn swap(&mut self, i: usize, j: usize) {
assert!(i < self.len());
assert!(j < self.len());
self.as_mut().swap(i, j);
}
#[inline]
unsafe fn unsafe_at(&self, i: usize) -> N {
*self[..].get_unchecked(i)
}
#[inline]
unsafe fn unsafe_set(&mut self, i: usize, val: N) {
*self[..].get_unchecked_mut(i) = val
}
}
impl<N, T $(, $param: ArrayLength<N>)*> Index<T> for $vecn<N $(, $param)*> where [N]: Index<T> {
type Output = <[N] as Index<T>>::Output;
fn index(&self, i: T) -> &<[N] as Index<T>>::Output {
&self.as_ref()[i]
}
}
impl<N, T $(, $param: ArrayLength<N>)*> IndexMut<T> for $vecn<N $(, $param)*> where [N]: IndexMut<T> {
fn index_mut(&mut self, i: T) -> &mut <[N] as Index<T>>::Output {
&mut self.as_mut()[i]
}
}
impl<N $(, $param : ArrayLength<N>)*> Iterable<N> for $vecn<N $(, $param)*> {
#[inline]
fn iter<'l>(&'l self) -> Iter<'l, N> {
self.as_ref().iter()
}
}
impl<N $(, $param : ArrayLength<N>)*> IterableMut<N> for $vecn<N $(, $param)*> {
#[inline]
fn iter_mut<'l>(&'l mut self) -> IterMut<'l, N> {
self.as_mut().iter_mut()
}
}
impl<N: Copy + Add<N, Output = N> + Mul<N, Output = N> $(, $param : ArrayLength<N>)*>
Axpy<N> for $vecn<N $(, $param)*> {
fn axpy(&mut self, a: &N, x: &$vecn<N $(, $param)*>) {
assert!(self.len() == x.len());
for i in 0 .. x.len() {
unsafe {
let self_i = self.unsafe_at(i);
self.unsafe_set(i, self_i + *a * x.unsafe_at(i))
}
}
}
}
impl<N: Copy + Mul<N, Output = N> + Zero $(, $param : ArrayLength<N>)*>
Mul<$vecn<N $(, $param)*>> for $vecn<N $(, $param)*> {
type Output = $vecn<N $(, $param)*>;
#[inline]
fn mul(self, right: $vecn<N $(, $param)*>) -> $vecn<N $(, $param)*> {
assert!(self.len() == right.len());
let mut res = self;
for (left, right) in res.as_mut().iter_mut().zip(right.as_ref().iter()) {
*left = *left * *right
}
res
}
}
impl<N: Copy + Div<N, Output = N> + Zero $(, $param : ArrayLength<N>)*>
Div<$vecn<N $(, $param)*>> for $vecn<N $(, $param)*> {
type Output = $vecn<N $(, $param)*>;
#[inline]
fn div(self, right: $vecn<N $(, $param)*>) -> $vecn<N $(, $param)*> {
assert!(self.len() == right.len());
let mut res = self;
for (left, right) in res.as_mut().iter_mut().zip(right.as_ref().iter()) {
*left = *left / *right
}
res
}
}
impl<N: Copy + Add<N, Output = N> + Zero $(, $param : ArrayLength<N>)*>
Add<$vecn<N $(, $param)*>> for $vecn<N $(, $param)*> {
type Output = $vecn<N $(, $param)*>;
#[inline]
fn add(self, right: $vecn<N $(, $param)*>) -> $vecn<N $(, $param)*> {
assert!(self.len() == right.len());
let mut res = self;
for (left, right) in res.as_mut().iter_mut().zip(right.as_ref().iter()) {
*left = *left + *right
}
res
}
}
impl<N: Copy + Sub<N, Output = N> + Zero $(, $param : ArrayLength<N>)*>
Sub<$vecn<N $(, $param)*>> for $vecn<N $(, $param)*> {
type Output = $vecn<N $(, $param)*>;
#[inline]
fn sub(self, right: $vecn<N $(, $param)*>) -> $vecn<N $(, $param)*> {
assert!(self.len() == right.len());
let mut res = self;
for (left, right) in res.as_mut().iter_mut().zip(right.as_ref().iter()) {
*left = *left - *right
}
res
}
}
impl<N: Neg<Output = N> + Zero + Copy $(, $param : ArrayLength<N>)*> Neg for $vecn<N $(, $param)*> {
type Output = $vecn<N $(, $param)*>;
#[inline]
fn neg(mut self) -> $vecn<N $(, $param)*> {
for e in self.as_mut().iter_mut() {
*e = -*e;
}
self
}
}
impl<N: BaseNum $(, $param : ArrayLength<N>)*> Dot<N> for $vecn<N $(, $param)*> {
#[inline]
fn dot(&self, other: &$vecn<N $(, $param)*>) -> N {
assert!(self.len() == other.len());
let mut res: N = ::zero();
for i in 0 .. self.len() {
res = res + unsafe { self.unsafe_at(i) * other.unsafe_at(i) };
}
res
}
}
impl<N: BaseFloat $(, $param : ArrayLength<N>)*> Norm<N> for $vecn<N $(, $param)*> {
#[inline]
fn sqnorm(&self) -> N {
Dot::dot(self, self)
}
#[inline]
fn normalize(&self) -> $vecn<N $(, $param)*> {
let mut res : $vecn<N $(, $param)*> = self.clone();
let _ = res.normalize_mut();
res
}
#[inline]
fn normalize_mut(&mut self) -> N {
let l = Norm::norm(self);
for n in self.as_mut().iter_mut() {
*n = *n / l;
}
l
}
}
impl<N: BaseFloat + Cast<f64> $(, $param : ArrayLength<N>)*> Mean<N> for $vecn<N $(, $param)*> {
#[inline]
fn mean(&self) -> N {
let normalizer = ::cast(1.0f64 / self.len() as f64);
self.iter().fold(::zero(), |acc, x| acc + *x * normalizer)
}
}
impl<N: ApproxEq<N> $(, $param : ArrayLength<N>)*> ApproxEq<N> for $vecn<N $(, $param)*> {
#[inline]
fn approx_epsilon(_: Option<$vecn<N $(, $param)*>>) -> N {
ApproxEq::approx_epsilon(None::<N>)
}
#[inline]
fn approx_ulps(_: Option<$vecn<N $(, $param)*>>) -> u32 {
ApproxEq::approx_ulps(None::<N>)
}
#[inline]
fn approx_eq_eps(&self, other: &$vecn<N $(, $param)*>, epsilon: &N) -> bool {
let mut zip = self.as_ref().iter().zip(other.as_ref().iter());
zip.all(|(a, b)| ApproxEq::approx_eq_eps(a, b, epsilon))
}
#[inline]
fn approx_eq_ulps(&self, other: &$vecn<N $(, $param)*>, ulps: u32) -> bool {
let mut zip = self.as_ref().iter().zip(other.as_ref().iter());
zip.all(|(a, b)| ApproxEq::approx_eq_ulps(a, b, ulps))
}
}
impl<N: Copy + Mul<N, Output = N> + Zero $(, $param : ArrayLength<N>)*>
Mul<N> for $vecn<N $(, $param)*> {
type Output = $vecn<N $(, $param)*>;
#[inline]
fn mul(self, right: N) -> $vecn<N $(, $param)*> {
let mut res = self;
for e in res.as_mut().iter_mut() {
*e = *e * right
}
res
}
}
impl<N: Copy + Div<N, Output = N> + Zero $(, $param : ArrayLength<N>)*> Div<N> for $vecn<N $(, $param)*> {
type Output = $vecn<N $(, $param)*>;
#[inline]
fn div(self, right: N) -> $vecn<N $(, $param)*> {
let mut res = self;
for e in res.as_mut().iter_mut() {
*e = *e / right
}
res
}
}
impl<N: Copy + Add<N, Output = N> + Zero $(, $param : ArrayLength<N>)*> Add<N> for $vecn<N $(, $param)*> {
type Output = $vecn<N $(, $param)*>;
#[inline]
fn add(self, right: N) -> $vecn<N $(, $param)*> {
let mut res = self;
for e in res.as_mut().iter_mut() {
*e = *e + right
}
res
}
}
impl<N: Copy + Sub<N, Output = N> + Zero $(, $param : ArrayLength<N>)*> Sub<N> for $vecn<N $(, $param)*> {
type Output = $vecn<N $(, $param)*>;
#[inline]
fn sub(self, right: N) -> $vecn<N $(, $param)*> {
let mut res = self;
for e in res.as_mut().iter_mut() {
*e = *e - right
}
res
}
}
)
);

View File

@ -158,7 +158,7 @@ pub trait RowSlice<R> {
/// Trait of objects having a spacial dimension known at compile time. /// Trait of objects having a spacial dimension known at compile time.
pub trait Dim: Sized { pub trait Dim: Sized {
/// The dimension of the object. /// The dimension of the object.
fn dim(unused_mut: Option<Self>) -> usize; fn dim(_unused: Option<Self>) -> usize;
} }
/// Trait to get the diagonal of square matrices. /// Trait to get the diagonal of square matrices.

View File

@ -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() {

280
tests/transforms.rs Normal file
View File

@ -0,0 +1,280 @@
extern crate nalgebra as na;
extern crate rand;
use rand::random;
use na::{Pnt2, Pnt3, Vec2, Vec3, Vec1, Rot2, Rot3, Persp3, PerspMat3, Ortho3, OrthoMat3,
Iso2, Iso3, Sim2, Sim3, BaseFloat, Transform};
#[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_rh_iso3() {
for _ in 0usize .. 10000 {
let eye = random::<Pnt3<f64>>();
let target = random::<Pnt3<f64>>();
let up = random::<Vec3<f64>>();
let viewmat = Iso3::look_at_rh(&eye, &target, &up);
let origin: Pnt3<f64> = na::orig();
assert_eq!(&(viewmat * eye), &origin);
assert!(na::approx_eq(&na::normalize(&(viewmat * (target - eye))), &-Vec3::z()));
}
}
#[test]
fn test_look_at_rh_rot3() {
for _ in 0usize .. 10000 {
let dir = random::<Vec3<f64>>();
let up = random::<Vec3<f64>>();
let viewmat = Rot3::look_at_rh(&dir, &up);
println!("found: {}", viewmat * dir);
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.fovy() == 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.fovy(), &0.5));
assert!(na::approx_eq(&pm.znear(), &1.5));
assert!(na::approx_eq(&pm.zfar(), &10.0));
p.set_fovy(0.1);
pm.set_fovy(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.fovy() == 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.fovy(), &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(-0.3, 5.2, -3.9, -1.0, 1.5, 10.0);
let mut pm = OrthoMat3::new(-0.3, 5.2, -3.9, -1.0, 1.5, 10.0);
assert!(p.to_mat() == pm.to_mat());
assert!(p.left() == -0.3);
assert!(p.right() == 5.2);
assert!(p.bottom() == -3.9);
assert!(p.top() == -1.0);
assert!(p.znear() == 1.5);
assert!(p.zfar() == 10.0);
assert!(na::approx_eq(&pm.left(), &-0.3));
assert!(na::approx_eq(&pm.right(), &5.2));
assert!(na::approx_eq(&pm.bottom(), &-3.9));
assert!(na::approx_eq(&pm.top(), &-1.0));
assert!(na::approx_eq(&pm.znear(), &1.5));
assert!(na::approx_eq(&pm.zfar(), &10.0));
p.set_left(0.1);
pm.set_left(0.1);
assert!(na::approx_eq(&p.to_mat(), pm.as_mat()));
p.set_right(10.1);
pm.set_right(10.1);
assert!(na::approx_eq(&p.to_mat(), pm.as_mat()));
p.set_top(24.0);
pm.set_top(24.0);
assert!(na::approx_eq(&p.to_mat(), pm.as_mat()));
p.set_bottom(-23.0);
pm.set_bottom(-23.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_znear(21.0);
pm.set_znear(21.0);
assert!(na::approx_eq(&p.to_mat(), pm.as_mat()));
assert!(p.znear() == 21.0);
assert!(p.zfar() == 61.0);
assert!(na::approx_eq(&pm.znear(), &21.0));
assert!(na::approx_eq(&pm.zfar(), &61.0));
}
macro_rules! test_transform_inv_transform_impl(
($fnname: ident, $t: ty, $p: ty) => (
#[test]
fn $fnname() {
for _ in 0usize .. 10000 {
let randmat: $t = random();
let expected: $p = random();
let computed = randmat.inv_transform(&randmat.transform(&expected));
println!("computed: {}, expected: {}", computed, expected);
assert!(na::approx_eq(&computed, &expected));
}
}
);
);
test_transform_inv_transform_impl!(test_transform_inv_transform_rot2, Rot2<f64>, Pnt2<f64>);
test_transform_inv_transform_impl!(test_transform_inv_transform_rot3, Rot3<f64>, Pnt3<f64>);
test_transform_inv_transform_impl!(test_transform_inv_transform_iso2, Iso2<f64>, Pnt2<f64>);
test_transform_inv_transform_impl!(test_transform_inv_transform_iso3, Iso3<f64>, Pnt3<f64>);
test_transform_inv_transform_impl!(test_transform_inv_transform_sim2, Sim2<f64>, Pnt2<f64>);
test_transform_inv_transform_impl!(test_transform_inv_transform_sim3, Sim3<f64>, Pnt3<f64>);
macro_rules! test_transform_mul_assoc(
($fnname: ident, $t1: ty, $t2: ty, $p: ty) => (
#[test]
fn $fnname() {
for _ in 0usize .. 10000 {
let t1: $t1 = random();
let t2: $t2 = random();
let p: $p = random();
let t1p = t1 * p;
let t2p = t2 * p;
let t1t2 = t1 * t2;
let t2t1 = t2 * t1;
assert!(na::approx_eq(&(t1t2 * p), &(t1 * t2p)));
assert!(na::approx_eq(&(t2t1 * p), &(t2 * t1p)));
}
}
);
);
test_transform_mul_assoc!(test_transform_inv_transform_sim3_sim3_pnt3, Sim3<f64>, Sim3<f64>, Pnt3<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_sim3_iso3_pnt3, Sim3<f64>, Iso3<f64>, Pnt3<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_sim3_rot3_pnt3, Sim3<f64>, Rot3<f64>, Pnt3<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_iso3_iso3_pnt3, Iso3<f64>, Iso3<f64>, Pnt3<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_iso3_rot3_pnt3, Iso3<f64>, Rot3<f64>, Pnt3<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_rot3_rot3_pnt3, Rot3<f64>, Rot3<f64>, Pnt3<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_sim3_sim3_vec3, Sim3<f64>, Sim3<f64>, Vec3<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_sim3_iso3_vec3, Sim3<f64>, Iso3<f64>, Vec3<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_sim3_rot3_vec3, Sim3<f64>, Rot3<f64>, Vec3<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_iso3_iso3_vec3, Iso3<f64>, Iso3<f64>, Vec3<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_iso3_rot3_vec3, Iso3<f64>, Rot3<f64>, Vec3<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_rot3_rot3_vec3, Rot3<f64>, Rot3<f64>, Vec3<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_sim2_sim2_pnt2, Sim2<f64>, Sim2<f64>, Pnt2<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_sim2_iso2_pnt2, Sim2<f64>, Iso2<f64>, Pnt2<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_sim2_rot2_pnt2, Sim2<f64>, Rot2<f64>, Pnt2<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_iso2_iso2_pnt2, Iso2<f64>, Iso2<f64>, Pnt2<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_iso2_rot2_pnt2, Iso2<f64>, Rot2<f64>, Pnt2<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_rot2_rot2_pnt2, Rot2<f64>, Rot2<f64>, Pnt2<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_sim2_sim2_vec2, Sim2<f64>, Sim2<f64>, Vec2<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_sim2_iso2_vec2, Sim2<f64>, Iso2<f64>, Vec2<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_sim2_rot2_vec2, Sim2<f64>, Rot2<f64>, Vec2<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_iso2_iso2_vec2, Iso2<f64>, Iso2<f64>, Vec2<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_iso2_rot2_vec2, Iso2<f64>, Rot2<f64>, Vec2<f64>);
test_transform_mul_assoc!(test_transform_inv_transform_rot2_rot2_vec2, Rot2<f64>, Rot2<f64>, Vec2<f64>);

View File

@ -1,8 +1,16 @@
extern crate nalgebra as na;
extern crate rand; extern crate rand;
#[cfg(feature="generic_sizes")]
extern crate typenum;
extern crate nalgebra as na;
use rand::random; use rand::random;
use na::{Vec0, Vec1, Vec2, Vec3, Vec4, Vec5, Vec6, Mat3, Rot2, Rot3, Iterable, IterableMut}; use na::{Vec1, Vec2, Vec3, Vec4, Vec5, Vec6, Mat3, Rot2, Rot3, Iterable, IterableMut};
#[cfg(feature="generic_sizes")]
use typenum::U10;
#[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) => (
@ -110,11 +118,6 @@ fn test_cross_vec3() {
} }
} }
#[test]
fn test_commut_dot_vec0() {
test_commut_dot_impl!(Vec0<f64>);
}
#[test] #[test]
fn test_commut_dot_vec1() { fn test_commut_dot_vec1() {
test_commut_dot_impl!(Vec1<f64>); test_commut_dot_impl!(Vec1<f64>);
@ -145,11 +148,6 @@ fn test_commut_dot_vec6() {
test_commut_dot_impl!(Vec6<f64>); test_commut_dot_impl!(Vec6<f64>);
} }
#[test]
fn test_basis_vec0() {
test_basis_impl!(Vec0<f64>);
}
#[test] #[test]
fn test_basis_vec1() { fn test_basis_vec1() {
test_basis_impl!(Vec1<f64>); test_basis_impl!(Vec1<f64>);
@ -180,11 +178,6 @@ fn test_basis_vec6() {
test_basis_impl!(Vec6<f64>); test_basis_impl!(Vec6<f64>);
} }
#[test]
fn test_subspace_basis_vec0() {
test_subspace_basis_impl!(Vec0<f64>);
}
#[test] #[test]
fn test_subspace_basis_vec1() { fn test_subspace_basis_vec1() {
test_subspace_basis_impl!(Vec1<f64>); test_subspace_basis_impl!(Vec1<f64>);
@ -215,11 +208,6 @@ fn test_subspace_basis_vec6() {
test_subspace_basis_impl!(Vec6<f64>); test_subspace_basis_impl!(Vec6<f64>);
} }
#[test]
fn test_scalar_op_vec0() {
test_scalar_op_impl!(Vec0<f64>, f64);
}
#[test] #[test]
fn test_scalar_op_vec1() { fn test_scalar_op_vec1() {
test_scalar_op_impl!(Vec1<f64>, f64); test_scalar_op_impl!(Vec1<f64>, f64);
@ -250,11 +238,6 @@ fn test_scalar_op_vec6() {
test_scalar_op_impl!(Vec6<f64>, f64); test_scalar_op_impl!(Vec6<f64>, f64);
} }
#[test]
fn test_iterator_vec0() {
test_iterator_impl!(Vec0<f64>, f64);
}
#[test] #[test]
fn test_iterator_vec1() { fn test_iterator_vec1() {
test_iterator_impl!(Vec1<f64>, f64); test_iterator_impl!(Vec1<f64>, f64);
@ -318,6 +301,16 @@ fn test_outer_vec3() {
12.0, 15.0, 18.0)); 12.0, 15.0, 18.0));
} }
#[cfg(feature="generic_sizes")]
#[test]
fn test_vecn10_add_mul() {
for _ in 0usize .. 10000 {
let v1: VecN<f64, U10> = random();
assert!(na::approx_eq(&(v1 + v1), &(v1 * 2.0)))
}
}
#[test] #[test]
fn test_vec3_rotation_between() { fn test_vec3_rotation_between() {