parent
03eda09084
commit
0cf725f5f2
39
README.md
39
README.md
|
@ -1,31 +1,30 @@
|
||||||
# nalgebra
|
# nalgebra
|
||||||
|
|
||||||
**nalgebra** is a linear algebra library written for Rust targeting:
|
**nalgebra** is a low-dimensional linear algebra library written for Rust targeting:
|
||||||
|
|
||||||
* general-purpose linear algebra (still misses a lot of features…).
|
* 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).
|
||||||
|
|
||||||
## Using **nalgebra**
|
## Using **nalgebra**
|
||||||
All the functionalities of **nalgebra** are grouped in one place: the `na` module.
|
All the functionalities of **nalgebra** are grouped in one place: the root `nalgebra::` module.
|
||||||
This module re-exports everything and includes free functions for all traits methods doing
|
This module re-exports everything and includes free functions for all traits methods doing
|
||||||
out-of-place modifications.
|
out-of-place modifications.
|
||||||
|
|
||||||
* You can import the whole prelude using:
|
* You can import the whole prelude using:
|
||||||
|
|
||||||
```
|
```.ignore
|
||||||
use nalgebra::na::*;
|
use nalgebra::*;
|
||||||
```
|
```
|
||||||
|
|
||||||
The preferred way to use **nalgebra** is to import types and traits explicitly, and call
|
The preferred way to use **nalgebra** is to import types and traits explicitly, and call
|
||||||
free-functions using the `na::` prefix:
|
free-functions using the `na::` prefix:
|
||||||
|
|
||||||
```.rust
|
```.rust
|
||||||
extern crate nalgebra;
|
extern crate "nalgebra" as na;
|
||||||
use nalgebra::na::{Vec3, Rot3, Rotation};
|
use na::{Vec3, Rot3, Rotation};
|
||||||
use nalgebra::na;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let a = Vec3::new(1.0f64, 1.0, 1.0);
|
let a = Vec3::new(1.0f64, 1.0, 1.0);
|
||||||
|
@ -38,26 +37,27 @@ fn main() {
|
||||||
```
|
```
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
**nalgebra** is meant to be a general-purpose linear algebra library (but is very far from that…),
|
**nalgebra** is meant to be a general-purpose, low-dimensional, linear algebra
|
||||||
and keeps an optimized set of tools for computational graphics and physics. Those features include:
|
library, and keeps an optimized set of tools for computational graphics and
|
||||||
|
physics. Those features include:
|
||||||
|
|
||||||
* Vectors with static sizes: `Vec0`, `Vec1`, `Vec2`, `Vec3`, `Vec4`, `Vec5`, `Vec6`.
|
* Vectors with static sizes: `Vec0`, `Vec1`, `Vec2`, `Vec3`, `Vec4`, `Vec5`, `Vec6`.
|
||||||
|
* Points with static sizes: `Pnt0`, `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`, `Rot4`.
|
||||||
* Isometries: `Iso2`, `Iso3`, `Iso4`.
|
* Isometries: `Iso2`, `Iso3`, `Iso4`.
|
||||||
|
* 3D projections for computer graphics: `Persp3`, `PerspMat3`, `Ortho3`, `OrthoMat3`.
|
||||||
* Dynamically sized vector: `DVec`.
|
* Dynamically sized vector: `DVec`.
|
||||||
* Dynamically sized (square or rectangular) matrix: `DMat`.
|
* Dynamically sized (square or rectangular) matrix: `DMat`.
|
||||||
* A few methods for data analysis: `Cov`, `Mean`.
|
* A few methods for data analysis: `Cov`, `Mean`.
|
||||||
* Some matrix factorization algorithms: QR decomposition, ...
|
|
||||||
* Almost one trait per functionality: useful for generic programming.
|
* Almost one trait per functionality: useful for generic programming.
|
||||||
* Operator overloading using the double trait dispatch
|
* Operator overloading using the double trait dispatch
|
||||||
[trick](http://smallcultfollowing.com/babysteps/blog/2012/10/04/refining-traits-slash-impls/).
|
[trick](http://smallcultfollowing.com/babysteps/blog/2012/10/04/refining-traits-slash-impls/).
|
||||||
For example, the following works:
|
For example, the following works:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
extern crate nalgebra;
|
extern crate "nalgebra" as na;
|
||||||
use nalgebra::na::{Vec3, Mat3};
|
use na::{Vec3, Mat3};
|
||||||
use nalgebra::na;
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let v: Vec3<f64> = na::zero();
|
let v: Vec3<f64> = na::zero();
|
||||||
|
@ -66,7 +66,7 @@ fn main() {
|
||||||
let _ = m * v; // matrix-vector multiplication.
|
let _ = m * v; // matrix-vector multiplication.
|
||||||
let _ = v * m; // vector-matrix multiplication.
|
let _ = v * m; // vector-matrix multiplication.
|
||||||
let _ = m * m; // matrix-matrix multiplication.
|
let _ = m * m; // matrix-matrix multiplication.
|
||||||
let _ = v * 2.0; // vector-scalar multiplication.
|
let _ = v * 2.0f64; // vector-scalar multiplication.
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ and the official package manager: [cargo](https://github.com/rust-lang/cargo).
|
||||||
|
|
||||||
Simply add the following to your `Cargo.toml` file:
|
Simply add the following to your `Cargo.toml` file:
|
||||||
|
|
||||||
```
|
```.ignore
|
||||||
[dependencies.nalgebra]
|
[dependencies.nalgebra]
|
||||||
git = "https://github.com/sebcrozet/nalgebra"
|
git = "https://github.com/sebcrozet/nalgebra"
|
||||||
```
|
```
|
||||||
|
@ -86,6 +86,7 @@ git = "https://github.com/sebcrozet/nalgebra"
|
||||||
Here are some projects using **nalgebra**.
|
Here are some projects using **nalgebra**.
|
||||||
Feel free to add your project to this list if you happen to use **nalgebra**!
|
Feel free to add your project to this list if you happen to use **nalgebra**!
|
||||||
|
|
||||||
* [nphysics](http://nphysics-dev.org): a real-time physics engine.
|
* [nphysics](https://github.com/sebcrozet/nphysics): a real-time physics engine.
|
||||||
* [ncollide](http://ncollide.org): a collision detection library.
|
* [ncollide](https://github.com/sebcrozet/ncollide): a collision detection library.
|
||||||
* [kiss3d](http://kiss3d.org): a minimalistic graphics engine.
|
* [kiss3d](https://github.com/sebcrozet/kiss3d): a minimalistic graphics engine.
|
||||||
|
* [nrays](https://github.com/sebcrozet/nrays): a ray tracer.
|
||||||
|
|
13
src/lib.rs
13
src/lib.rs
|
@ -1,7 +1,7 @@
|
||||||
/*!
|
/*!
|
||||||
# nalgebra
|
# nalgebra
|
||||||
|
|
||||||
**nalgebra** is a 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…).
|
* general-purpose linear algebra (still lacks a lot of features…).
|
||||||
* real time computer graphics.
|
* real time computer graphics.
|
||||||
|
@ -38,14 +38,15 @@ fn main() {
|
||||||
```
|
```
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
**nalgebra** is meant to be a general-purpose linear algebra library (but is very far from that…),
|
**nalgebra** is meant to be a general-purpose, low-dimensional, linear algebra library, and keeps
|
||||||
and keeps an optimized set of tools for computational graphics and physics. Those features include:
|
an optimized set of tools for computational graphics and physics. Those features include:
|
||||||
|
|
||||||
* Vectors with static sizes: `Vec0`, `Vec1`, `Vec2`, `Vec3`, `Vec4`, `Vec5`, `Vec6`.
|
* Vectors with static sizes: `Vec0`, `Vec1`, `Vec2`, `Vec3`, `Vec4`, `Vec5`, `Vec6`.
|
||||||
* Points with static sizes: `Pnt0`, `Pnt1`, `Pnt2`, `Pnt3`, `Pnt4`, `Pnt5`, `Pnt6`.
|
* Points with static sizes: `Pnt0`, `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`, `Rot4`.
|
||||||
* Isometries: `Iso2`, `Iso3`, `Iso4`.
|
* Isometries: `Iso2`, `Iso3`, `Iso4`.
|
||||||
|
* 3D projections for computer graphics: `Persp3`, `PerspMat3`, `Ortho3`, `OrthoMat3`.
|
||||||
* Dynamically sized vector: `DVec`.
|
* Dynamically sized vector: `DVec`.
|
||||||
* Dynamically sized (square or rectangular) matrix: `DMat`.
|
* Dynamically sized (square or rectangular) matrix: `DMat`.
|
||||||
* A few methods for data analysis: `Cov`, `Mean`.
|
* A few methods for data analysis: `Cov`, `Mean`.
|
||||||
|
@ -150,7 +151,6 @@ pub use traits::{
|
||||||
PartialOrdering,
|
PartialOrdering,
|
||||||
PntAsVec,
|
PntAsVec,
|
||||||
PntExt,
|
PntExt,
|
||||||
Projector,
|
|
||||||
RMul,
|
RMul,
|
||||||
Rotate, Rotation, RotationMatrix, RotationWithTranslation,
|
Rotate, Rotation, RotationMatrix, RotationWithTranslation,
|
||||||
Row,
|
Row,
|
||||||
|
@ -174,7 +174,9 @@ pub use structs::{
|
||||||
Mat5, Mat6,
|
Mat5, Mat6,
|
||||||
Rot2, Rot3, Rot4,
|
Rot2, Rot3, Rot4,
|
||||||
Vec0, Vec1, Vec2, Vec3, Vec4, Vec5, Vec6,
|
Vec0, Vec1, Vec2, Vec3, Vec4, Vec5, Vec6,
|
||||||
Pnt0, Pnt1, Pnt2, Pnt3, Pnt4, Pnt5, Pnt6
|
Pnt0, Pnt1, Pnt2, Pnt3, Pnt4, Pnt5, Pnt6,
|
||||||
|
Persp3, PerspMat3,
|
||||||
|
Ortho3, OrthoMat3
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use linalg::{
|
pub use linalg::{
|
||||||
|
@ -383,6 +385,7 @@ pub fn sqdist<N: Float, P: FloatPnt<N, V>, V: Norm<N>>(a: &P, b: &P) -> N {
|
||||||
*/
|
*/
|
||||||
/// Computes a projection matrix given the frustrum near plane width, height, the field of
|
/// Computes a projection matrix given the frustrum near plane width, height, the field of
|
||||||
/// view, and the distance to the clipping planes (`znear` and `zfar`).
|
/// view, and the distance to the clipping planes (`znear` and `zfar`).
|
||||||
|
#[deprecated = "Use `Persp3::new(width / height, fov, znear, zfar).as_mat()` instead"]
|
||||||
pub fn perspective3d<N: FloatMath + Cast<f32> + Zero + One>(width: N, height: N, fov: N, znear: N, zfar: N) -> Mat4<N> {
|
pub fn perspective3d<N: FloatMath + Cast<f32> + Zero + One>(width: N, height: N, fov: N, znear: N, zfar: N) -> Mat4<N> {
|
||||||
let aspect = width / height;
|
let aspect = width / height;
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,8 @@ pub use self::pnt::{Pnt0, 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, Rot4};
|
||||||
pub use self::iso::{Iso2, Iso3, Iso4};
|
pub use self::iso::{Iso2, Iso3, Iso4};
|
||||||
|
pub use self::persp::{Persp3, PerspMat3};
|
||||||
|
pub use self::ortho::{Ortho3, OrthoMat3};
|
||||||
|
|
||||||
pub use self::vec::{Vec1MulRhs, Vec2MulRhs, Vec3MulRhs, Vec4MulRhs, Vec5MulRhs, Vec6MulRhs,
|
pub use self::vec::{Vec1MulRhs, Vec2MulRhs, Vec3MulRhs, Vec4MulRhs, Vec5MulRhs, Vec6MulRhs,
|
||||||
Vec1DivRhs, Vec2DivRhs, Vec3DivRhs, Vec4DivRhs, Vec5DivRhs, Vec6DivRhs,
|
Vec1DivRhs, Vec2DivRhs, Vec3DivRhs, Vec4DivRhs, Vec5DivRhs, Vec6DivRhs,
|
||||||
|
@ -35,6 +37,8 @@ mod rot_macros;
|
||||||
mod rot;
|
mod rot;
|
||||||
mod iso_macros;
|
mod iso_macros;
|
||||||
mod iso;
|
mod iso;
|
||||||
|
mod persp;
|
||||||
|
mod ortho;
|
||||||
|
|
||||||
// specialization for some 1d, 2d and 3d operations
|
// specialization for some 1d, 2d and 3d operations
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
|
|
@ -0,0 +1,234 @@
|
||||||
|
use std::num::{Zero, One};
|
||||||
|
use std::num;
|
||||||
|
use structs::{Pnt3, Vec3, Mat4};
|
||||||
|
|
||||||
|
/// A 3D orthographic projection stored without any matrix.
|
||||||
|
///
|
||||||
|
/// Reading or modifying its individual properties is cheap but applying the transformation is costly.
|
||||||
|
#[deriving(Eq, PartialEq, Encodable, Decodable, Clone, Show)]
|
||||||
|
pub struct Ortho3<N> {
|
||||||
|
width: N,
|
||||||
|
height: N,
|
||||||
|
znear: N,
|
||||||
|
zfar: N
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A 3D orthographic projection stored as a 4D matrix.
|
||||||
|
///
|
||||||
|
/// Reading or modifying its individual properties is costly but applying the transformation is cheap.
|
||||||
|
#[deriving(Eq, PartialEq, Encodable, Decodable, Clone, Show)]
|
||||||
|
pub struct OrthoMat3<N> {
|
||||||
|
mat: Mat4<N>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: FloatMath> Ortho3<N> {
|
||||||
|
/// Creates a new 3D orthographic projection.
|
||||||
|
pub fn new(width: N, height: N, znear: N, zfar: N) -> Ortho3<N> {
|
||||||
|
assert!(!(zfar - znear).is_zero());
|
||||||
|
assert!(!width.is_zero());
|
||||||
|
assert!(!height.is_zero());
|
||||||
|
|
||||||
|
Ortho3 {
|
||||||
|
width: width,
|
||||||
|
height: height,
|
||||||
|
znear: znear,
|
||||||
|
zfar: zfar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds a 4D projection matrix (using homogeneous coordinates) for this projection.
|
||||||
|
pub fn to_mat(&self) -> Mat4<N> {
|
||||||
|
self.to_persp_mat().mat
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build a `OrthoMat3` representing this projection.
|
||||||
|
pub fn to_persp_mat(&self) -> OrthoMat3<N> {
|
||||||
|
OrthoMat3::new(self.width, self.height, self.znear, self.zfar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: FloatMath + Clone> Ortho3<N> {
|
||||||
|
/// The width of the view cuboid.
|
||||||
|
#[inline]
|
||||||
|
pub fn width(&self) -> N {
|
||||||
|
self.width.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The height of the view cuboid.
|
||||||
|
#[inline]
|
||||||
|
pub fn height(&self) -> N {
|
||||||
|
self.height.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The near plane offset of the view cuboid.
|
||||||
|
#[inline]
|
||||||
|
pub fn znear(&self) -> N {
|
||||||
|
self.znear.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The far plane offset of the view cuboid.
|
||||||
|
#[inline]
|
||||||
|
pub fn zfar(&self) -> N {
|
||||||
|
self.zfar.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the width of the view cuboid.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_width(&mut self, width: N) {
|
||||||
|
self.width = width
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the height of the view cuboid.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_height(&mut self, height: N) {
|
||||||
|
self.height = height
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the near plane offset of the view cuboid.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_znear(&mut self, znear: N) {
|
||||||
|
self.znear = znear
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the far plane offset of the view cuboid.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_zfar(&mut self, zfar: N) {
|
||||||
|
self.zfar = zfar
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Projects a point.
|
||||||
|
#[inline]
|
||||||
|
pub fn project_pnt(&self, p: &Pnt3<N>) -> Pnt3<N> {
|
||||||
|
// FIXME: optimize that
|
||||||
|
self.to_persp_mat().project_pnt(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Projects a vector.
|
||||||
|
#[inline]
|
||||||
|
pub fn project_vec(&self, p: &Vec3<N>) -> Vec3<N> {
|
||||||
|
// FIXME: optimize that
|
||||||
|
self.to_persp_mat().project_vec(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: FloatMath> OrthoMat3<N> {
|
||||||
|
/// Creates a new orthographic projection matrix from the width, heihgt, znear and zfar planes of the view cuboid.
|
||||||
|
pub fn new(width: N, height: N, znear: N, zfar: N) -> OrthoMat3<N> {
|
||||||
|
assert!(!(zfar - znear).is_zero());
|
||||||
|
assert!(!width.is_zero());
|
||||||
|
assert!(!height.is_zero());
|
||||||
|
|
||||||
|
let mat: Mat4<N> = One::one();
|
||||||
|
|
||||||
|
let mut res = OrthoMat3 { mat: mat };
|
||||||
|
res.set_width(width);
|
||||||
|
res.set_height(height);
|
||||||
|
res.set_znear_and_zfar(znear, zfar);
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new orthographic matrix from a 4D matrix.
|
||||||
|
///
|
||||||
|
/// This is unsafe because the input matrix is not checked to be a orthographic projection.
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn new_with_mat(mat: Mat4<N>) -> OrthoMat3<N> {
|
||||||
|
OrthoMat3 {
|
||||||
|
mat: mat
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reference to the 4D matrix (using homogeneous coordinates) of this projection.
|
||||||
|
#[inline]
|
||||||
|
pub fn as_mat<'a>(&'a self) -> &'a Mat4<N> {
|
||||||
|
&self.mat
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The width of the view cuboid.
|
||||||
|
#[inline]
|
||||||
|
pub fn width(&self) -> N {
|
||||||
|
num::cast::<f64, N>(2.0).unwrap() / self.mat.m11
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The height of the view cuboid.
|
||||||
|
#[inline]
|
||||||
|
pub fn height(&self) -> N {
|
||||||
|
num::cast::<f64, N>(2.0).unwrap() / self.mat.m22
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The near plane offset of the view cuboid.
|
||||||
|
#[inline]
|
||||||
|
pub fn znear(&self) -> N {
|
||||||
|
(self.mat.m34 + One::one()) / self.mat.m33
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The far plane offset of the view cuboid.
|
||||||
|
#[inline]
|
||||||
|
pub fn zfar(&self) -> N {
|
||||||
|
(self.mat.m34 - One::one()) / self.mat.m33
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the width of the view cuboid.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_width(&mut self, width: N) {
|
||||||
|
assert!(!width.is_zero());
|
||||||
|
self.mat.m11 = num::cast::<f64, N>(2.0).unwrap() / width;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the height of the view cuboid.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_height(&mut self, height: N) {
|
||||||
|
assert!(!height.is_zero());
|
||||||
|
self.mat.m22 = num::cast::<f64, N>(2.0).unwrap() / height;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the near plane offset of the view cuboid.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_znear(&mut self, znear: N) {
|
||||||
|
let zfar = self.zfar();
|
||||||
|
self.set_znear_and_zfar(znear, zfar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the far plane offset of the view cuboid.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_zfar(&mut self, zfar: N) {
|
||||||
|
let znear = self.znear();
|
||||||
|
self.set_znear_and_zfar(znear, zfar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the near and far plane offsets of the view cuboid.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_znear_and_zfar(&mut self, znear: N, zfar: N) {
|
||||||
|
assert!(!(zfar - znear).is_zero());
|
||||||
|
self.mat.m33 = -num::cast::<f64, N>(2.0).unwrap() / (zfar - znear);
|
||||||
|
self.mat.m34 = -(zfar + znear) / (zfar - znear);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Projects a point.
|
||||||
|
#[inline]
|
||||||
|
pub fn project_pnt(&self, p: &Pnt3<N>) -> Pnt3<N> {
|
||||||
|
Pnt3::new(
|
||||||
|
self.mat.m11 * p.x,
|
||||||
|
self.mat.m22 * p.y,
|
||||||
|
self.mat.m33 * p.z + self.mat.m34
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Projects a vector.
|
||||||
|
#[inline]
|
||||||
|
pub fn project_vec(&self, p: &Vec3<N>) -> Vec3<N> {
|
||||||
|
Vec3::new(
|
||||||
|
self.mat.m11 * p.x,
|
||||||
|
self.mat.m22 * p.y,
|
||||||
|
self.mat.m33 * p.z
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: FloatMath + Clone> OrthoMat3<N> {
|
||||||
|
/// Returns the 4D matrix (using homogeneous coordinates) of this projection.
|
||||||
|
#[inline]
|
||||||
|
pub fn to_mat<'a>(&'a self) -> Mat4<N> {
|
||||||
|
self.mat.clone()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,265 @@
|
||||||
|
use std::num::{Zero, One};
|
||||||
|
use structs::{Pnt3, Vec3, Mat4};
|
||||||
|
|
||||||
|
/// A 3D perspective projection stored without any matrix.
|
||||||
|
///
|
||||||
|
/// Reading or modifying its individual properties is cheap but applying the transformation is costly.
|
||||||
|
#[deriving(Eq, PartialEq, Encodable, Decodable, Clone, Show)]
|
||||||
|
pub struct Persp3<N> {
|
||||||
|
aspect: N,
|
||||||
|
fov: N,
|
||||||
|
znear: N,
|
||||||
|
zfar: N
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A 3D perspective projection stored as a 4D matrix.
|
||||||
|
///
|
||||||
|
/// Reading or modifying its individual properties is costly but applying the transformation is cheap.
|
||||||
|
#[deriving(Eq, PartialEq, Encodable, Decodable, Clone, Show)]
|
||||||
|
pub struct PerspMat3<N> {
|
||||||
|
mat: Mat4<N>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: FloatMath> Persp3<N> {
|
||||||
|
/// Creates a new 3D perspective projection.
|
||||||
|
pub fn new(aspect: N, fov: N, znear: N, zfar: N) -> Persp3<N> {
|
||||||
|
assert!(!(zfar - znear).is_zero());
|
||||||
|
assert!(!aspect.is_zero());
|
||||||
|
|
||||||
|
Persp3 {
|
||||||
|
aspect: aspect,
|
||||||
|
fov: fov,
|
||||||
|
znear: znear,
|
||||||
|
zfar: zfar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Builds a 4D projection matrix (using homogeneous coordinates) for this projection.
|
||||||
|
pub fn to_mat(&self) -> Mat4<N> {
|
||||||
|
self.to_persp_mat().mat
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Build a `PerspMat3` representing this projection.
|
||||||
|
pub fn to_persp_mat(&self) -> PerspMat3<N> {
|
||||||
|
PerspMat3::new(self.aspect, self.fov, self.znear, self.zfar)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: FloatMath + Clone> Persp3<N> {
|
||||||
|
/// Gets the `width / height` aspect ratio.
|
||||||
|
#[inline]
|
||||||
|
pub fn aspect(&self) -> N {
|
||||||
|
self.aspect.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the field of view of the view frustrum.
|
||||||
|
#[inline]
|
||||||
|
pub fn fov(&self) -> N {
|
||||||
|
self.fov.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the near plane offset of the view frustrum.
|
||||||
|
#[inline]
|
||||||
|
pub fn znear(&self) -> N {
|
||||||
|
self.znear.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the far plane offset of the view frustrum.
|
||||||
|
#[inline]
|
||||||
|
pub fn zfar(&self) -> N {
|
||||||
|
self.zfar.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the `width / height` aspect ratio of the view frustrum.
|
||||||
|
///
|
||||||
|
/// This method does not build any matrix.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_aspect(&mut self, aspect: N) {
|
||||||
|
self.aspect = aspect;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the field of view of the view frustrum.
|
||||||
|
///
|
||||||
|
/// This method does not build any matrix.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_fov(&mut self, fov: N) {
|
||||||
|
self.fov = fov;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the near plane offset of the view frustrum.
|
||||||
|
///
|
||||||
|
/// This method does not build any matrix.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_znear(&mut self, znear: N) {
|
||||||
|
self.znear = znear;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the far plane offset of the view frustrum.
|
||||||
|
///
|
||||||
|
/// This method does not build any matrix.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_zfar(&mut self, zfar: N) {
|
||||||
|
self.zfar = zfar;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Projects a point.
|
||||||
|
#[inline]
|
||||||
|
pub fn project_pnt(&self, p: &Pnt3<N>) -> Pnt3<N> {
|
||||||
|
// FIXME: optimize that
|
||||||
|
self.to_persp_mat().project_pnt(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Projects a vector.
|
||||||
|
#[inline]
|
||||||
|
pub fn project_vec(&self, p: &Vec3<N>) -> Vec3<N> {
|
||||||
|
// FIXME: optimize that
|
||||||
|
self.to_persp_mat().project_vec(p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: FloatMath> PerspMat3<N> {
|
||||||
|
/// Creates a new persepctive matrix from the aspect ratio, field of view, and near/far planes.
|
||||||
|
pub fn new(aspect: N, fov: N, znear: N, zfar: N) -> PerspMat3<N> {
|
||||||
|
assert!(!(znear - zfar).is_zero());
|
||||||
|
assert!(!aspect.is_zero());
|
||||||
|
|
||||||
|
let mat: Mat4<N> = One::one();
|
||||||
|
|
||||||
|
let mut res = PerspMat3 { mat: mat };
|
||||||
|
res.set_fov(fov);
|
||||||
|
res.set_aspect(aspect);
|
||||||
|
res.set_znear_and_zfar(znear, zfar);
|
||||||
|
res.mat.m44 = Zero::zero();
|
||||||
|
res.mat.m43 = One::one();
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new perspective projection matrix from a 4D matrix.
|
||||||
|
///
|
||||||
|
/// This is unsafe because the input matrix is not checked to be a perspective projection.
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn new_with_mat(mat: Mat4<N>) -> PerspMat3<N> {
|
||||||
|
PerspMat3 {
|
||||||
|
mat: mat
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reference to the 4D matrix (using homogeneous coordinates) of this projection.
|
||||||
|
#[inline]
|
||||||
|
pub fn as_mat<'a>(&'a self) -> &'a Mat4<N> {
|
||||||
|
&self.mat
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the `width / height` aspect ratio of the view frustrum.
|
||||||
|
#[inline]
|
||||||
|
pub fn aspect(&self) -> N {
|
||||||
|
-self.mat.m22 / self.mat.m11
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the field of view of the view frustrum.
|
||||||
|
#[inline]
|
||||||
|
pub fn fov(&self) -> N {
|
||||||
|
let _1: N = One::one();
|
||||||
|
let _2 = _1 + _1;
|
||||||
|
|
||||||
|
(_1 / self.mat.m22).atan() * _2
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the near plane offset of the view frustrum.
|
||||||
|
#[inline]
|
||||||
|
pub fn znear(&self) -> N {
|
||||||
|
let _1: N = One::one();
|
||||||
|
let _2 = _1 + _1;
|
||||||
|
let ratio = (self.mat.m33 + _1) / (self.mat.m33 - _1);
|
||||||
|
|
||||||
|
self.mat.m34 / (_2 * ratio) - self.mat.m34 / _2
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets the far plane offset of the view frustrum.
|
||||||
|
#[inline]
|
||||||
|
pub fn zfar(&self) -> N {
|
||||||
|
let _1: N = One::one();
|
||||||
|
let _2 = _1 + _1;
|
||||||
|
let ratio = (self.mat.m33 + _1) / (self.mat.m33 - _1);
|
||||||
|
|
||||||
|
(self.mat.m34 - ratio * self.mat.m34) / _2
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: add a method to retriev znear and zfar at once ?
|
||||||
|
|
||||||
|
/// Updates this projection matrix with a new `width / height` aspect ratio of the view
|
||||||
|
/// frustrum.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_aspect(&mut self, aspect: N) {
|
||||||
|
assert!(!aspect.is_zero());
|
||||||
|
self.mat.m11 = -self.mat.m22 / aspect;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates this projection with a new field of view of the view frustrum.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_fov(&mut self, fov: N) {
|
||||||
|
let _1: N = One::one();
|
||||||
|
let _2 = _1 + _1;
|
||||||
|
|
||||||
|
let old_m22 = self.mat.m22.clone();
|
||||||
|
self.mat.m22 = _1 / (fov / _2).tan();
|
||||||
|
self.mat.m11 = self.mat.m11 * (self.mat.m22 / old_m22);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates this projection matrix with a new near plane offset of the view frustrum.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_znear(&mut self, znear: N) {
|
||||||
|
let zfar = self.zfar();
|
||||||
|
self.set_znear_and_zfar(znear, zfar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates this projection matrix with a new far plane offset of the view frustrum.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_zfar(&mut self, zfar: N) {
|
||||||
|
let znear = self.znear();
|
||||||
|
self.set_znear_and_zfar(znear, zfar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates this projection matrix with new near and far plane offsets of the view frustrum.
|
||||||
|
#[inline]
|
||||||
|
pub fn set_znear_and_zfar(&mut self, znear: N, zfar: N) {
|
||||||
|
let _1: N = One::one();
|
||||||
|
let _2 = _1 + _1;
|
||||||
|
|
||||||
|
self.mat.m33 = -(zfar + znear) / (znear - zfar);
|
||||||
|
self.mat.m34 = zfar * znear * _2 / (znear - zfar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Projects a point.
|
||||||
|
#[inline]
|
||||||
|
pub fn project_pnt(&self, p: &Pnt3<N>) -> Pnt3<N> {
|
||||||
|
let _1: N = One::one();
|
||||||
|
let inv_denom = _1 / p.z;
|
||||||
|
Pnt3::new(
|
||||||
|
self.mat.m11 * p.x * inv_denom,
|
||||||
|
self.mat.m22 * p.y * inv_denom,
|
||||||
|
(self.mat.m33 * p.z + self.mat.m34) * inv_denom
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Projects a vector.
|
||||||
|
#[inline]
|
||||||
|
pub fn project_vec(&self, p: &Vec3<N>) -> Vec3<N> {
|
||||||
|
let _1: N = One::one();
|
||||||
|
let inv_denom = _1 / p.z;
|
||||||
|
Vec3::new(
|
||||||
|
self.mat.m11 * p.x * inv_denom,
|
||||||
|
self.mat.m22 * p.y * inv_denom,
|
||||||
|
self.mat.m33
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<N: FloatMath + Clone> PerspMat3<N> {
|
||||||
|
/// Returns the 4D matrix (using homogeneous coordinates) of this projection.
|
||||||
|
#[inline]
|
||||||
|
pub fn to_mat<'a>(&'a self) -> Mat4<N> {
|
||||||
|
self.mat.clone()
|
||||||
|
}
|
||||||
|
}
|
|
@ -276,12 +276,3 @@ pub trait Orig {
|
||||||
/// Returns true if this points is exactly the trivial origin.
|
/// Returns true if this points is exactly the trivial origin.
|
||||||
fn is_orig(&self) -> bool;
|
fn is_orig(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait implemented by projectors.
|
|
||||||
// XXX: Vout should be an associated type instead of a type parameter.
|
|
||||||
pub trait Projector<Vin, Vout> {
|
|
||||||
/// Projects an element of a vector or affine space to a subspace.
|
|
||||||
///
|
|
||||||
/// This must be an indempotent operaton.
|
|
||||||
fn project(&self, &Vin) -> Vout;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,9 +1,8 @@
|
||||||
//! Mathematical traits.
|
//! Mathematical traits.
|
||||||
|
|
||||||
pub use self::geometry::{AbsoluteRotate, Cross, CrossMatrix, Dot, FromHomogeneous, Norm, Orig,
|
pub use self::geometry::{AbsoluteRotate, Cross, CrossMatrix, Dot, FromHomogeneous, Norm, Orig,
|
||||||
Projector, Rotate, Rotation, RotationMatrix, RotationWithTranslation,
|
Rotate, Rotation, RotationMatrix, RotationWithTranslation, ToHomogeneous,
|
||||||
ToHomogeneous, Transform, Transformation, Translate, Translation,
|
Transform, Transformation, Translate, Translation, UniformSphereSample};
|
||||||
UniformSphereSample};
|
|
||||||
|
|
||||||
pub use self::structure::{FloatVec, FloatVecExt, FloatPnt, FloatPntExt, Basis, Cast, Col, Dim,
|
pub use self::structure::{FloatVec, FloatVecExt, FloatPnt, FloatPntExt, Basis, Cast, Col, Dim,
|
||||||
Indexable, Iterable, IterableMut, Mat, Row, AnyVec, VecExt, AnyPnt,
|
Indexable, Iterable, IterableMut, Mat, Row, AnyVec, VecExt, AnyPnt,
|
||||||
|
|
85
tests/mat.rs
85
tests/mat.rs
|
@ -6,7 +6,8 @@ extern crate "nalgebra" as na;
|
||||||
use std::num::{Float, abs};
|
use std::num::{Float, abs};
|
||||||
use std::rand::random;
|
use std::rand::random;
|
||||||
use std::cmp::{min, max};
|
use std::cmp::{min, max};
|
||||||
use na::{Vec1, Vec3, Mat1, Mat2, Mat3, Mat4, Mat5, Mat6, Rot3, DMat, DVec, Indexable, Row, Col};
|
use na::{Vec1, Vec3, Mat1, Mat2, Mat3, Mat4, Mat5, Mat6, Rot3, Persp3, PerspMat3, Ortho3, OrthoMat3,
|
||||||
|
DMat, DVec, Indexable, Row, Col};
|
||||||
|
|
||||||
macro_rules! test_inv_mat_impl(
|
macro_rules! test_inv_mat_impl(
|
||||||
($t: ty) => (
|
($t: ty) => (
|
||||||
|
@ -296,7 +297,7 @@ fn test_qr_mat6() {
|
||||||
test_qr_impl!(Mat6<f64>);
|
test_qr_impl!(Mat6<f64>);
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: deactivated untile we get a better convergence rate.
|
// NOTE: deactivated until we get a better convergence rate.
|
||||||
// #[test]
|
// #[test]
|
||||||
// fn test_eigen_qr_mat1() {
|
// fn test_eigen_qr_mat1() {
|
||||||
// test_eigen_qr_impl!(Mat1<f64>);
|
// test_eigen_qr_impl!(Mat1<f64>);
|
||||||
|
@ -349,3 +350,83 @@ fn test_row_3() {
|
||||||
assert!(second_row == Vec3::new(3.0, 4.0, 5.0));
|
assert!(second_row == Vec3::new(3.0, 4.0, 5.0));
|
||||||
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));
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue