parent
03eda09084
commit
0cf725f5f2
39
README.md
39
README.md
|
@ -1,31 +1,30 @@
|
|||
# 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 physics.
|
||||
|
||||
An on-line version of this documentation is available [here](http://nalgebra.org).
|
||||
|
||||
## 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
|
||||
out-of-place modifications.
|
||||
|
||||
* You can import the whole prelude using:
|
||||
|
||||
```
|
||||
use nalgebra::na::*;
|
||||
```.ignore
|
||||
use nalgebra::*;
|
||||
```
|
||||
|
||||
The preferred way to use **nalgebra** is to import types and traits explicitly, and call
|
||||
free-functions using the `na::` prefix:
|
||||
|
||||
```.rust
|
||||
extern crate nalgebra;
|
||||
use nalgebra::na::{Vec3, Rot3, Rotation};
|
||||
use nalgebra::na;
|
||||
extern crate "nalgebra" as na;
|
||||
use na::{Vec3, Rot3, Rotation};
|
||||
|
||||
fn main() {
|
||||
let a = Vec3::new(1.0f64, 1.0, 1.0);
|
||||
|
@ -38,26 +37,27 @@ fn main() {
|
|||
```
|
||||
|
||||
## Features
|
||||
**nalgebra** is meant to be a general-purpose linear algebra library (but is very far from that…),
|
||||
and keeps an optimized set of tools for computational graphics and physics. Those features include:
|
||||
**nalgebra** is meant to be a general-purpose, low-dimensional, linear algebra
|
||||
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`.
|
||||
* Points with static sizes: `Pnt0`, `Pnt1`, `Pnt2`, `Pnt3`, `Pnt4`, `Pnt5`, `Pnt6`.
|
||||
* Square matrices with static sizes: `Mat1`, `Mat2`, `Mat3`, `Mat4`, `Mat5`, `Mat6 `.
|
||||
* Rotation matrices: `Rot2`, `Rot3`, `Rot4`.
|
||||
* Isometries: `Iso2`, `Iso3`, `Iso4`.
|
||||
* 3D projections for computer graphics: `Persp3`, `PerspMat3`, `Ortho3`, `OrthoMat3`.
|
||||
* Dynamically sized vector: `DVec`.
|
||||
* Dynamically sized (square or rectangular) matrix: `DMat`.
|
||||
* A few methods for data analysis: `Cov`, `Mean`.
|
||||
* Some matrix factorization algorithms: QR decomposition, ...
|
||||
* Almost one trait per functionality: useful for generic programming.
|
||||
* Operator overloading using the double trait dispatch
|
||||
[trick](http://smallcultfollowing.com/babysteps/blog/2012/10/04/refining-traits-slash-impls/).
|
||||
For example, the following works:
|
||||
|
||||
```rust
|
||||
extern crate nalgebra;
|
||||
use nalgebra::na::{Vec3, Mat3};
|
||||
use nalgebra::na;
|
||||
extern crate "nalgebra" as na;
|
||||
use na::{Vec3, Mat3};
|
||||
|
||||
fn main() {
|
||||
let v: Vec3<f64> = na::zero();
|
||||
|
@ -66,7 +66,7 @@ fn main() {
|
|||
let _ = m * v; // matrix-vector multiplication.
|
||||
let _ = v * m; // vector-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:
|
||||
|
||||
```
|
||||
```.ignore
|
||||
[dependencies.nalgebra]
|
||||
git = "https://github.com/sebcrozet/nalgebra"
|
||||
```
|
||||
|
@ -86,6 +86,7 @@ git = "https://github.com/sebcrozet/nalgebra"
|
|||
Here are some projects using **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.
|
||||
* [ncollide](http://ncollide.org): a collision detection library.
|
||||
* [kiss3d](http://kiss3d.org): a minimalistic graphics engine.
|
||||
* [nphysics](https://github.com/sebcrozet/nphysics): a real-time physics engine.
|
||||
* [ncollide](https://github.com/sebcrozet/ncollide): a collision detection library.
|
||||
* [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** 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…).
|
||||
* real time computer graphics.
|
||||
|
@ -38,14 +38,15 @@ fn main() {
|
|||
```
|
||||
|
||||
## Features
|
||||
**nalgebra** is meant to be a general-purpose linear algebra library (but is very far from that…),
|
||||
and keeps an optimized set of tools for computational graphics and physics. Those features include:
|
||||
**nalgebra** is meant to be a general-purpose, low-dimensional, linear algebra 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`.
|
||||
* Points with static sizes: `Pnt0`, `Pnt1`, `Pnt2`, `Pnt3`, `Pnt4`, `Pnt5`, `Pnt6`.
|
||||
* Square matrices with static sizes: `Mat1`, `Mat2`, `Mat3`, `Mat4`, `Mat5`, `Mat6 `.
|
||||
* Rotation matrices: `Rot2`, `Rot3`, `Rot4`.
|
||||
* Isometries: `Iso2`, `Iso3`, `Iso4`.
|
||||
* 3D projections for computer graphics: `Persp3`, `PerspMat3`, `Ortho3`, `OrthoMat3`.
|
||||
* Dynamically sized vector: `DVec`.
|
||||
* Dynamically sized (square or rectangular) matrix: `DMat`.
|
||||
* A few methods for data analysis: `Cov`, `Mean`.
|
||||
|
@ -150,7 +151,6 @@ pub use traits::{
|
|||
PartialOrdering,
|
||||
PntAsVec,
|
||||
PntExt,
|
||||
Projector,
|
||||
RMul,
|
||||
Rotate, Rotation, RotationMatrix, RotationWithTranslation,
|
||||
Row,
|
||||
|
@ -174,7 +174,9 @@ pub use structs::{
|
|||
Mat5, Mat6,
|
||||
Rot2, Rot3, Rot4,
|
||||
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::{
|
||||
|
@ -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
|
||||
/// 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> {
|
||||
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::rot::{Rot2, Rot3, Rot4};
|
||||
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,
|
||||
Vec1DivRhs, Vec2DivRhs, Vec3DivRhs, Vec4DivRhs, Vec5DivRhs, Vec6DivRhs,
|
||||
|
@ -35,6 +37,8 @@ mod rot_macros;
|
|||
mod rot;
|
||||
mod iso_macros;
|
||||
mod iso;
|
||||
mod persp;
|
||||
mod ortho;
|
||||
|
||||
// specialization for some 1d, 2d and 3d operations
|
||||
#[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.
|
||||
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.
|
||||
|
||||
pub use self::geometry::{AbsoluteRotate, Cross, CrossMatrix, Dot, FromHomogeneous, Norm, Orig,
|
||||
Projector, Rotate, Rotation, RotationMatrix, RotationWithTranslation,
|
||||
ToHomogeneous, Transform, Transformation, Translate, Translation,
|
||||
UniformSphereSample};
|
||||
Rotate, Rotation, RotationMatrix, RotationWithTranslation, ToHomogeneous,
|
||||
Transform, Transformation, Translate, Translation, UniformSphereSample};
|
||||
|
||||
pub use self::structure::{FloatVec, FloatVecExt, FloatPnt, FloatPntExt, Basis, Cast, Col, Dim,
|
||||
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::rand::random;
|
||||
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(
|
||||
($t: ty) => (
|
||||
|
@ -296,7 +297,7 @@ fn test_qr_mat6() {
|
|||
test_qr_impl!(Mat6<f64>);
|
||||
}
|
||||
|
||||
// NOTE: deactivated untile we get a better convergence rate.
|
||||
// NOTE: deactivated until we get a better convergence rate.
|
||||
// #[test]
|
||||
// fn test_eigen_qr_mat1() {
|
||||
// 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_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