diff --git a/Cargo.toml b/Cargo.toml
index 37a43717..398f0db9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -19,7 +19,6 @@ path = "src/lib.rs"
arbitrary = [ "quickcheck" ]
[dependencies]
-rustc-serialize = "0.3"
typenum = "1.4"
generic-array = "0.2"
rand = "0.3"
@@ -27,8 +26,13 @@ num-traits = "0.1"
num-complex = "0.1"
approx = "0.1"
alga = "0.4"
+serde = "0.9"
+serde_derive = "0.9"
# clippy = "*"
[dependencies.quickcheck]
optional = true
version = "0.3"
+
+[dev-dependencies]
+serde_json = "0.9"
diff --git a/Makefile b/Makefile
index f9586c02..00457c11 100644
--- a/Makefile
+++ b/Makefile
@@ -1,11 +1,11 @@
all:
- cargo build --features "arbitrary"
+ CARGO_INCREMENTAL=1 cargo build --features "arbitrary"
doc:
- cargo doc
+ CARGO_INCREMENTAL=1 cargo doc
bench:
cargo bench
test:
- cargo test --features "arbitrary"
+ CARGO_INCREMENTAL=1 cargo test --features "arbitrary"
diff --git a/README.md b/README.md
index c860659c..7d6a99fa 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,6 @@
+
+
+
@@ -8,75 +11,6 @@
- Documentation | Forum
+ Users guide | Documentation | Forum
-
-nalgebra
-========
-
-**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.
-* Real time computer physics.
-
-## Using **nalgebra**
-You will need the last stable build of the [rust compiler](http://www.rust-lang.org)
-and the official package manager: [cargo](https://github.com/rust-lang/cargo).
-
-Simply add the following to your `Cargo.toml` file:
-
-```.ignore
-[dependencies]
-nalgebra = "0.10.*"
-```
-
-
-All the functionality of **nalgebra** is grouped in one place: the root module `nalgebra::`. This
-module re-exports everything and includes free functions for all traits methods performing
-out-of-place operations.
-
-Thus, you can import the whole prelude using:
-
-```.ignore
-use nalgebra::*;
-```
-
-However, the recommended way to use **nalgebra** is to import types and traits
-explicitly, and call free-functions using the `na::` prefix:
-
-```.rust
-extern crate nalgebra as na;
-use na::{Vector3, Rotation3, Rotation};
-
-fn main() {
- let a = Vector3::new(1.0f64, 1.0, 1.0);
- let mut b = Rotation3::new(na::zero());
-
- b.append_rotation_mut(&a);
-
- assert!(na::approx_eq(&na::rotation(&b), &a));
-}
-```
-
-
-## Features
-**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:
-
-* Vectors with predefined static sizes: `Vector1`, `Vector2`, `Vector3`, `Vector4`, `Vector5`, `Vector6`.
-* Vector with a user-defined static size: `VectorN` (available only with the `generic_sizes` feature).
-* Points with static sizes: `Point1`, `Point2`, `Point3`, `Point4`, `Point5`, `Point6`.
-* Square matrices with static sizes: `Matrix1`, `Matrix2`, `Matrix3`, `Matrix4`, `Matrix5`, `Matrix6 `.
-* Rotation matrices: `Rotation2`, `Rotation3`
-* Quaternions: `Quaternion`, `Unit`.
-* Unit-sized values (unit vectors, unit quaternions, etc.): `Unit`, e.g., `Unit>`.
-* Isometries (translation ⨯ rotation): `Isometry2`, `Isometry3`
-* Similarity transformations (translation ⨯ rotation ⨯ uniform scale): `Similarity2`, `Similarity3`.
-* 3D projections for computer graphics: `Persp3`, `PerspMatrix3`, `Ortho3`, `OrthoMatrix3`.
-* Dynamically sized heap-allocated vector: `DVector`.
-* Dynamically sized stack-allocated vectors with a maximum size: `DVector1` to `DVector6`.
-* Dynamically sized heap-allocated (square or rectangular) matrix: `DMatrix`.
-* Linear algebra and data analysis operators: `Covariance`, `Mean`, `qr`, `cholesky`.
-* Almost one trait per functionality: useful for generic programming.
diff --git a/examples/dimensional_genericity.rs b/examples/dimensional_genericity.rs
new file mode 100644
index 00000000..df22b945
--- /dev/null
+++ b/examples/dimensional_genericity.rs
@@ -0,0 +1,66 @@
+extern crate alga;
+extern crate nalgebra as na;
+
+use alga::general::Real;
+use alga::linear::FiniteDimInnerSpace;
+use na::{Unit, ColumnVector, OwnedColumnVector, Vector2, Vector3};
+use na::storage::Storage;
+use na::dimension::{DimName, U1};
+
+/// Reflects a vector wrt. the hyperplane with normal `plane_normal`.
+fn reflect_wrt_hyperplane_with_algebraic_genericity(plane_normal: &Unit, vector: &V) -> V
+ where V: FiniteDimInnerSpace + Copy {
+ let n = plane_normal.as_ref(); // Get the underlying vector of type `V`.
+ *vector - *n * (n.dot(vector) * na::convert(2.0))
+}
+
+
+/// Reflects a vector wrt. the hyperplane with normal `plane_normal`.
+fn reflect_wrt_hyperplane_with_structural_genericity(plane_normal: &Unit>,
+ vector: &ColumnVector)
+ -> OwnedColumnVector
+ where N: Real,
+ D: DimName,
+ S: Storage {
+ let n = plane_normal.as_ref(); // Get the underlying V.
+ vector - n * (n.dot(vector) * na::convert(2.0))
+}
+
+/// Reflects a 2D vector wrt. the 2D line with normal `plane_normal`.
+fn reflect_wrt_hyperplane2(plane_normal: &Unit>,
+ vector: &Vector2)
+ -> Vector2
+ where N: Real {
+ let n = plane_normal.as_ref(); // Get the underlying Vector2
+ vector - n * (n.dot(vector) * na::convert(2.0))
+}
+
+/// Reflects a 3D vector wrt. the 3D plane with normal `plane_normal`.
+/// /!\ This is an exact replicate of `reflect_wrt_hyperplane2, but for 3D.
+fn reflect_wrt_hyperplane3(plane_normal: &Unit>,
+ vector: &Vector3)
+ -> Vector3
+ where N: Real {
+ let n = plane_normal.as_ref(); // Get the underlying Vector3
+ vector - n * (n.dot(vector) * na::convert(2.0))
+}
+
+
+fn main() {
+ let plane2 = Vector2::y_axis(); // 2D plane normal.
+ let plane3 = Vector3::y_axis(); // 3D plane normal.
+
+ let v2 = Vector2::new(1.0, 2.0); // 2D vector to be reflected.
+ let v3 = Vector3::new(1.0, 2.0, 3.0); // 3D vector to be reflected.
+
+ // We can call the same function for 2D and 3D.
+ assert_eq!(reflect_wrt_hyperplane_with_algebraic_genericity(&plane2, &v2).y, -2.0);
+ assert_eq!(reflect_wrt_hyperplane_with_algebraic_genericity(&plane3, &v3).y, -2.0);
+
+ assert_eq!(reflect_wrt_hyperplane_with_structural_genericity(&plane2, &v2).y, -2.0);
+ assert_eq!(reflect_wrt_hyperplane_with_structural_genericity(&plane3, &v3).y, -2.0);
+
+ // Call each specific implementation depending on the dimension.
+ assert_eq!(reflect_wrt_hyperplane2(&plane2, &v2).y, -2.0);
+ assert_eq!(reflect_wrt_hyperplane3(&plane3, &v3).y, -2.0);
+}
diff --git a/examples/homogeneous_coordinates.rs b/examples/homogeneous_coordinates.rs
new file mode 100644
index 00000000..a18b5a72
--- /dev/null
+++ b/examples/homogeneous_coordinates.rs
@@ -0,0 +1,45 @@
+#[macro_use]
+extern crate approx;
+extern crate nalgebra as na;
+
+use std::f32;
+use na::{Vector2, Point2, Isometry2};
+
+
+fn use_dedicated_types() {
+ let iso = Isometry2::new(Vector2::new(1.0, 1.0), f32::consts::PI);
+ let pt = Point2::new(1.0, 0.0);
+ let vec = Vector2::x();
+
+ let transformed_pt = iso * pt;
+ let transformed_vec = iso * vec;
+
+ assert_relative_eq!(transformed_pt, Point2::new(0.0, 1.0));
+ assert_relative_eq!(transformed_vec, Vector2::new(-1.0, 0.0));
+}
+
+fn use_homogeneous_coordinates() {
+ let iso = Isometry2::new(Vector2::new(1.0, 1.0), f32::consts::PI);
+ let pt = Point2::new(1.0, 0.0);
+ let vec = Vector2::x();
+
+ // Compute using homogeneous coordinates.
+ let hom_iso = iso.to_homogeneous();
+ let hom_pt = pt.to_homogeneous();
+ let hom_vec = vec.to_homogeneous();
+
+ let hom_transformed_pt = hom_iso * hom_pt;
+ let hom_transformed_vec = hom_iso * hom_vec;
+
+ // Convert back to the cartesian coordinates.
+ let transformed_pt = Point2::from_homogeneous(hom_transformed_pt).unwrap();
+ let transformed_vec = Vector2::from_homogeneous(hom_transformed_vec).unwrap();
+
+ assert_relative_eq!(transformed_pt, Point2::new(0.0, 1.0));
+ assert_relative_eq!(transformed_vec, Vector2::new(-1.0, 0.0));
+}
+
+fn main() {
+ use_dedicated_types();
+ use_homogeneous_coordinates();
+}
diff --git a/examples/identity.rs b/examples/identity.rs
new file mode 100644
index 00000000..1805bf1e
--- /dev/null
+++ b/examples/identity.rs
@@ -0,0 +1,42 @@
+extern crate alga;
+extern crate nalgebra as na;
+
+
+use alga::linear::Transformation;
+use na::{Id, Vector3, Point3, Isometry3};
+
+/*
+ * Applies `n` times the transformation `t` to the vector `v` and sum each
+ * intermediate value.
+ */
+fn complicated_algorithm(v: &Vector3, t: &T, n: usize) -> Vector3
+ where T: Transformation> {
+
+ let mut result = *v;
+
+ // Do lots of operations involving t.
+ for _ in 0 .. n {
+ result = v + t.transform_vector(&result);
+ }
+
+ result
+}
+
+
+/*
+ * The two following calls are equivalent in term of result.
+ */
+fn main() {
+ let v = Vector3::new(1.0, 2.0, 3.0);
+
+ // The specialization generated by the compiler will do vector additions only.
+ let result1 = complicated_algorithm(&v, &Id::new(), 100000);
+
+ // The specialization generated by the compiler will also include matrix multiplications.
+ let iso = Isometry3::identity();
+ let result2 = complicated_algorithm(&v, &iso, 100000);
+
+ // They both return the same result.
+ assert!(result1 == Vector3::new(100001.0, 200002.0, 300003.0));
+ assert!(result2 == Vector3::new(100001.0, 200002.0, 300003.0));
+}
diff --git a/examples/matrix_construction.rs b/examples/matrix_construction.rs
new file mode 100644
index 00000000..4eb4ad06
--- /dev/null
+++ b/examples/matrix_construction.rs
@@ -0,0 +1,62 @@
+extern crate nalgebra as na;
+
+use na::{Vector2, RowVector3, Matrix2x3, DMatrix};
+
+
+fn main() {
+ // All the following matrices are equal but constructed in different ways.
+ let m = Matrix2x3::new(1.1, 1.2, 1.3,
+ 2.1, 2.2, 2.3);
+
+ let m1 = Matrix2x3::from_rows(&[
+ RowVector3::new(1.1, 1.2, 1.3),
+ RowVector3::new(2.1, 2.2, 2.3)
+ ]);
+
+ let m2 = Matrix2x3::from_columns(&[
+ Vector2::new(1.1, 2.1),
+ Vector2::new(1.2, 2.2),
+ Vector2::new(1.3, 2.3)
+ ]);
+
+ let m3 = Matrix2x3::from_row_slice(&[
+ 1.1, 1.2, 1.3,
+ 2.1, 2.2, 2.3
+ ]);
+
+ let m4 = Matrix2x3::from_column_slice(&[
+ 1.1, 2.1,
+ 1.2, 2.2,
+ 1.3, 2.3
+ ]);
+
+ let m5 = Matrix2x3::from_fn(|r, c| (r + 1) as f32 + (c + 1) as f32 / 10.0);
+
+ let m6 = Matrix2x3::from_iterator([ 1.1f32, 2.1, 1.2, 2.2, 1.3, 2.3 ].iter().cloned());
+
+ assert_eq!(m, m1); assert_eq!(m, m2); assert_eq!(m, m3);
+ assert_eq!(m, m4); assert_eq!(m, m5); assert_eq!(m, m6);
+
+ // All the following matrices are equal but constructed in different ways.
+ // This time, we used a dynamically-sized matrix to show the extra arguments
+ // for the matrix shape.
+ let dm = DMatrix::from_row_slice(4, 3, &[
+ 1.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0,
+ 0.0, 0.0, 1.0,
+ 0.0, 0.0, 0.0
+ ]);
+
+ let dm1 = DMatrix::from_diagonal_element(4, 3, 1.0);
+ let dm2 = DMatrix::identity(4, 3);
+ let dm3 = DMatrix::from_fn(4, 3, |r, c| if r == c { 1.0 } else { 0.0 });
+ let dm4 = DMatrix::from_iterator(4, 3, [
+ // Components listed column-by-column.
+ 1.0, 0.0, 0.0, 0.0,
+ 0.0, 1.0, 0.0, 0.0,
+ 0.0, 0.0, 1.0, 0.0
+ ].iter().cloned());
+
+ assert_eq!(dm, dm1); assert_eq!(dm, dm2);
+ assert_eq!(dm, dm3); assert_eq!(dm, dm4);
+}
diff --git a/examples/mvp.rs b/examples/mvp.rs
new file mode 100644
index 00000000..7a38c671
--- /dev/null
+++ b/examples/mvp.rs
@@ -0,0 +1,28 @@
+#![allow(unused_variables)]
+
+extern crate nalgebra as na;
+
+use na::{Vector3, Point3, Isometry3, Perspective3};
+
+fn main() {
+ // Our object is translated along the x axis.
+ let model = Isometry3::new(Vector3::x(), na::zero());
+
+ // Our camera looks toward the point (1.0, 0.0, 0.0).
+ // It is located at (0.0, 0.0, 1.0).
+ let eye = Point3::new(0.0, 0.0, 1.0);
+ let target = Point3::new(1.0, 0.0, 0.0);
+ let view = Isometry3::look_at_rh(&eye, &target, &Vector3::y());
+
+ // A perspective projection.
+ let projection = Perspective3::new(16.0 / 9.0, 3.14 / 2.0, 1.0, 1000.0);
+
+ // The combination of the model with the view is still an isometry.
+ let model_view = model * view;
+
+ // Convert everything to a `Matrix4` so that they can be combined.
+ let mat_model_view = model_view.to_homogeneous();
+
+ // Combine everything.
+ let model_view_projection = projection.as_matrix() * mat_model_view;
+}
diff --git a/examples/raw_pointer.rs b/examples/raw_pointer.rs
new file mode 100644
index 00000000..ec960da4
--- /dev/null
+++ b/examples/raw_pointer.rs
@@ -0,0 +1,35 @@
+extern crate nalgebra as na;
+
+use na::{Vector3, Point3, Matrix3};
+
+fn main() {
+ let v = Vector3::new(1.0f32, 0.0, 1.0);
+ let p = Point3::new(1.0f32, 0.0, 1.0);
+ let m = na::one::>();
+
+ // Convert to arrays.
+ let v_array = v.as_slice();
+ let p_array = p.coords.as_slice();
+ let m_array = m.as_slice();
+
+ // Get data pointers.
+ let v_pointer = v_array.as_ptr();
+ let p_pointer = p_array.as_ptr();
+ let m_pointer = m_array.as_ptr();
+
+ /* Then pass the raw pointers to some graphics API. */
+
+ unsafe {
+ assert_eq!(*v_pointer, 1.0);
+ assert_eq!(*v_pointer.offset(1), 0.0);
+ assert_eq!(*v_pointer.offset(2), 1.0);
+
+ assert_eq!(*p_pointer, 1.0);
+ assert_eq!(*p_pointer.offset(1), 0.0);
+ assert_eq!(*p_pointer.offset(2), 1.0);
+
+ assert_eq!(*m_pointer, 1.0);
+ assert_eq!(*m_pointer.offset(4), 1.0);
+ assert_eq!(*m_pointer.offset(8), 1.0);
+ }
+}
diff --git a/examples/scalar_genericity.rs b/examples/scalar_genericity.rs
new file mode 100644
index 00000000..156d93ab
--- /dev/null
+++ b/examples/scalar_genericity.rs
@@ -0,0 +1,34 @@
+extern crate alga;
+extern crate nalgebra as na;
+
+use alga::general::{RingCommutative, Real};
+use na::{Vector3, Scalar};
+
+fn print_vector(m: &Vector3) {
+ println!("{:?}", m)
+}
+
+fn print_squared_norm(v: &Vector3) {
+ // NOTE: alternatively, nalgebra already defines `v.squared_norm()`.
+ let sqnorm = v.dot(v);
+
+ println!("{:?}", sqnorm);
+}
+
+fn print_norm(v: &Vector3) {
+ // NOTE: alternatively, nalgebra already defines `v.norm()`.
+ let norm = v.dot(v).sqrt();
+
+ // The Real bound implies that N is Display so we can
+ // use "{}" instead of "{:?}" for the format string.
+ println!("{}", norm)
+}
+
+fn main() {
+ let v1 = Vector3::new(1, 2, 3);
+ let v2 = Vector3::new(1.0, 2.0, 3.0);
+
+ print_vector(&v1);
+ print_squared_norm(&v1);
+ print_norm(&v2);
+}
diff --git a/examples/screen_to_view_coords.rs b/examples/screen_to_view_coords.rs
new file mode 100644
index 00000000..4d6bc351
--- /dev/null
+++ b/examples/screen_to_view_coords.rs
@@ -0,0 +1,24 @@
+#![allow(unused_variables)]
+
+extern crate nalgebra as na;
+
+use na::{Point2, Point3, Perspective3, Unit};
+
+
+fn main() {
+ let projection = Perspective3::new(800.0 / 600.0, 3.14 / 2.0, 1.0, 1000.0);
+ let screen_point = Point2::new(10.0f32, 20.0);
+
+ // Compute two points in clip-space.
+ // "ndc" = normalized device coordinates.
+ let near_ndc_point = Point3::new(screen_point.x / 800.0, screen_point.y / 600.0, -1.0);
+ let far_ndc_point = Point3::new(screen_point.x / 800.0, screen_point.y / 600.0, 1.0);
+
+ // Unproject them to view-space.
+ let near_view_point = projection.unproject_point(&near_ndc_point);
+ let far_view_point = projection.unproject_point(&far_ndc_point);
+
+ // Compute the view-space line parameters.
+ let line_location = near_view_point;
+ let line_direction = Unit::new_normalize(far_view_point - near_view_point);
+}
diff --git a/examples/transform_conversion.rs b/examples/transform_conversion.rs
new file mode 100644
index 00000000..37b266c4
--- /dev/null
+++ b/examples/transform_conversion.rs
@@ -0,0 +1,23 @@
+extern crate nalgebra as na;
+
+use na::{Vector2, Isometry2, Similarity2};
+
+fn main() {
+ // Isometry -> Similarity conversion always succeeds.
+ let iso = Isometry2::new(Vector2::new(1.0f32, 2.0), na::zero());
+ let _: Similarity2 = na::convert(iso);
+
+ // Similarity -> Isometry conversion fails if the scaling factor is not 1.0.
+ let sim_without_scaling = Similarity2::new(Vector2::new(1.0f32, 2.0), 3.14, 1.0);
+ let sim_with_scaling = Similarity2::new(Vector2::new(1.0f32, 2.0), 3.14, 2.0);
+
+ let iso_success: Option> = na::try_convert(sim_without_scaling);
+ let iso_fail: Option> = na::try_convert(sim_with_scaling);
+
+ assert!(iso_success.is_some());
+ assert!(iso_fail.is_none());
+
+ // Similarity -> Isometry conversion can be forced at your own risks.
+ let iso_forced: Isometry2 = unsafe { na::convert_unchecked(sim_with_scaling) };
+ assert_eq!(iso_success.unwrap(), iso_forced);
+}
diff --git a/examples/transform_matrix4.rs b/examples/transform_matrix4.rs
new file mode 100644
index 00000000..7d473b6b
--- /dev/null
+++ b/examples/transform_matrix4.rs
@@ -0,0 +1,39 @@
+#[macro_use]
+extern crate approx;
+extern crate alga;
+extern crate nalgebra as na;
+
+use alga::linear::Transformation;
+use na::{Vector3, Point3, Matrix4};
+
+
+fn main() {
+ // Create a uniform scaling matrix with scaling factor 2.
+ let mut m = Matrix4::new_scaling(2.0);
+
+ assert_eq!(m.transform_vector(&Vector3::x()), Vector3::x() * 2.0);
+ assert_eq!(m.transform_vector(&Vector3::y()), Vector3::y() * 2.0);
+ assert_eq!(m.transform_vector(&Vector3::z()), Vector3::z() * 2.0);
+
+ // Append a nonuniform scaling in-place.
+ m.append_nonuniform_scaling_mut(&Vector3::new(1.0, 2.0, 3.0));
+
+ assert_eq!(m.transform_vector(&Vector3::x()), Vector3::x() * 2.0);
+ assert_eq!(m.transform_vector(&Vector3::y()), Vector3::y() * 4.0);
+ assert_eq!(m.transform_vector(&Vector3::z()), Vector3::z() * 6.0);
+
+ // Append a translation out-of-place.
+ let m2 = m.append_translation(&Vector3::new(42.0, 0.0, 0.0));
+
+ assert_eq!(m2.transform_point(&Point3::new(1.0, 1.0, 1.0)), Point3::new(42.0 + 2.0, 4.0, 6.0));
+
+ // Create rotation.
+ let rot = Matrix4::from_scaled_axis(&Vector3::x() * 3.14);
+ let rot_then_m = m * rot; // Right-multiplication is equivalent to prepending `rot` to `m`.
+ let m_then_rot = rot * m; // Left-multiplication is equivalent to appending `rot` to `m`.
+
+ let pt = Point3::new(1.0, 2.0, 3.0);
+
+ assert_relative_eq!(m.transform_point(&rot.transform_point(&pt)), rot_then_m.transform_point(&pt));
+ assert_relative_eq!(rot.transform_point(&m.transform_point(&pt)), m_then_rot.transform_point(&pt));
+}
diff --git a/examples/transform_vector_point.rs b/examples/transform_vector_point.rs
new file mode 100644
index 00000000..f94b88e3
--- /dev/null
+++ b/examples/transform_vector_point.rs
@@ -0,0 +1,20 @@
+#[macro_use]
+extern crate approx;
+extern crate nalgebra as na;
+
+use std::f32;
+use na::{Vector2, Point2, Isometry2};
+
+fn main() {
+ let t = Isometry2::new(Vector2::new(1.0, 1.0), f32::consts::PI);
+ let p = Point2::new(1.0, 0.0); // Will be affected by te rotation and the translation.
+ let v = Vector2::x(); // Will *not* be affected by the translation.
+
+ assert_relative_eq!(t * p, Point2::new(-1.0 + 1.0, 1.0));
+ // ^^^^ │ ^^^^^^^^
+ // rotated │ translated
+
+ assert_relative_eq!(t * v, Vector2::new(-1.0, 0.0));
+ // ^^^^^
+ // rotated only
+}
diff --git a/examples/transform_vector_point3.rs b/examples/transform_vector_point3.rs
new file mode 100644
index 00000000..f1a010bf
--- /dev/null
+++ b/examples/transform_vector_point3.rs
@@ -0,0 +1,27 @@
+extern crate alga;
+extern crate nalgebra as na;
+
+use alga::linear::Transformation;
+use na::{Vector3, Vector4, Point3, Matrix4};
+
+
+fn main() {
+ let mut m = Matrix4::new_rotation_wrt_point(Vector3::x() * 1.57, Point3::new(1.0, 2.0, 1.0));
+ m.append_scaling_mut(2.0);
+
+ let point1 = Point3::new(2.0, 3.0, 4.0);
+ let homogeneous_point2 = Vector4::new(2.0, 3.0, 4.0, 1.0);
+
+ // First option: use the dedicated `.transform_point(...)` method.
+ let transformed_point1 = m.transform_point(&point1);
+ // Second option: use the homogeneous coordinates of the point.
+ let transformed_homogeneous_point2 = m * homogeneous_point2;
+
+ // Recover the 3D point from its 4D homogeneous coordinates.
+ let transformed_point2 = Point3::from_homogeneous(transformed_homogeneous_point2);
+
+ // Check that transforming the 3D point with the `.transform_point` method is
+ // indeed equivalent to multiplying its 4D homogeneous coordinates by the 4x4
+ // matrix.
+ assert_eq!(transformed_point1, transformed_point2.unwrap());
+}
diff --git a/examples/transformation_pointer.rs b/examples/transformation_pointer.rs
new file mode 100644
index 00000000..68d35e09
--- /dev/null
+++ b/examples/transformation_pointer.rs
@@ -0,0 +1,25 @@
+extern crate nalgebra as na;
+
+use na::{Vector3, Isometry3};
+
+fn main() {
+ let iso = Isometry3::new(Vector3::new(1.0f32, 0.0, 1.0), na::zero());
+
+ // Compute the homogeneous coordinates first.
+ let iso_matrix = iso.to_homogeneous();
+ let iso_array = iso_matrix.as_slice();
+ let iso_pointer = iso_array.as_ptr();
+
+ /* Then pass the raw pointer to some graphics API. */
+
+ unsafe {
+ assert_eq!(*iso_pointer, 1.0);
+ assert_eq!(*iso_pointer.offset(5), 1.0);
+ assert_eq!(*iso_pointer.offset(10), 1.0);
+ assert_eq!(*iso_pointer.offset(15), 1.0);
+
+ assert_eq!(*iso_pointer.offset(12), 1.0);
+ assert_eq!(*iso_pointer.offset(13), 0.0);
+ assert_eq!(*iso_pointer.offset(14), 1.0);
+ }
+}
diff --git a/examples/unit_wrapper.rs b/examples/unit_wrapper.rs
new file mode 100644
index 00000000..dc898c50
--- /dev/null
+++ b/examples/unit_wrapper.rs
@@ -0,0 +1,30 @@
+extern crate nalgebra as na;
+
+use na::{Unit, Vector3};
+
+fn length_on_direction_with_unit(v: &Vector3, dir: &Unit>) -> f32 {
+ // No need to normalize `dir`: we know that it is non-zero and normalized.
+ v.dot(dir.as_ref())
+}
+
+
+
+fn length_on_direction_without_unit(v: &Vector3, dir: &Vector3) -> f32 {
+ // Obligatory normalization of the direction vector (and test, for robustness).
+ if let Some(unit_dir) = dir.try_normalize(1.0e-6) {
+ v.dot(&unit_dir)
+ }
+ else {
+ // Normalization failed because the norm was too small.
+ panic!("Invalid input direction.")
+ }
+}
+
+fn main() {
+ let v = Vector3::new(1.0, 2.0, 3.0);
+
+ let l1 = length_on_direction_with_unit(&v, &Vector3::y_axis());
+ let l2 = length_on_direction_without_unit(&v, &Vector3::y());
+
+ assert_eq!(l1, l2)
+}
diff --git a/src/core/alias.rs b/src/core/alias.rs
index e4395dcd..df296257 100644
--- a/src/core/alias.rs
+++ b/src/core/alias.rs
@@ -19,52 +19,88 @@ pub type MatrixNM = Matrix>;
/// A staticaly sized column-major square matrix with `D` rows and columns.
pub type MatrixN = MatrixNM;
+/// A stack-allocated, column-major, 1x1 square matrix.
pub type Matrix1 = MatrixN;
+/// A stack-allocated, column-major, 2x2 square matrix.
pub type Matrix2 = MatrixN;
+/// A stack-allocated, column-major, 3x3 square matrix.
pub type Matrix3 = MatrixN;
+/// A stack-allocated, column-major, 4x4 square matrix.
pub type Matrix4 = MatrixN;
+/// A stack-allocated, column-major, 5x5 square matrix.
pub type Matrix5 = MatrixN;
+/// A stack-allocated, column-major, 6x6 square matrix.
pub type Matrix6 = MatrixN;
+/// A stack-allocated, column-major, 1x2 square matrix.
pub type Matrix1x2 = MatrixNM;
+/// A stack-allocated, column-major, 1x3 square matrix.
pub type Matrix1x3 = MatrixNM;
+/// A stack-allocated, column-major, 1x4 square matrix.
pub type Matrix1x4 = MatrixNM;
+/// A stack-allocated, column-major, 1x5 square matrix.
pub type Matrix1x5 = MatrixNM;
+/// A stack-allocated, column-major, 1x6 square matrix.
pub type Matrix1x6 = MatrixNM;
+/// A stack-allocated, column-major, 2x3 square matrix.
pub type Matrix2x3 = MatrixNM;
+/// A stack-allocated, column-major, 2x4 square matrix.
pub type Matrix2x4 = MatrixNM;
+/// A stack-allocated, column-major, 2x5 square matrix.
pub type Matrix2x5 = MatrixNM;
+/// A stack-allocated, column-major, 2x6 square matrix.
pub type Matrix2x6 = MatrixNM;
+/// A stack-allocated, column-major, 3x4 square matrix.
pub type Matrix3x4 = MatrixNM;
+/// A stack-allocated, column-major, 3x5 square matrix.
pub type Matrix3x5 = MatrixNM;
+/// A stack-allocated, column-major, 3x6 square matrix.
pub type Matrix3x6 = MatrixNM;
+/// A stack-allocated, column-major, 4x5 square matrix.
pub type Matrix4x5 = MatrixNM;
+/// A stack-allocated, column-major, 4x6 square matrix.
pub type Matrix4x6 = MatrixNM;
+/// A stack-allocated, column-major, 5x6 square matrix.
pub type Matrix5x6 = MatrixNM;
+/// A stack-allocated, column-major, 2x1 square matrix.
pub type Matrix2x1 = MatrixNM;
+/// A stack-allocated, column-major, 3x1 square matrix.
pub type Matrix3x1 = MatrixNM;
+/// A stack-allocated, column-major, 4x1 square matrix.
pub type Matrix4x1 = MatrixNM;
+/// A stack-allocated, column-major, 5x1 square matrix.
pub type Matrix5x1 = MatrixNM;
+/// A stack-allocated, column-major, 6x1 square matrix.
pub type Matrix6x1 = MatrixNM;
+/// A stack-allocated, column-major, 3x2 square matrix.
pub type Matrix3x2 = MatrixNM;
+/// A stack-allocated, column-major, 4x2 square matrix.
pub type Matrix4x2 = MatrixNM;
+/// A stack-allocated, column-major, 5x2 square matrix.
pub type Matrix5x2 = MatrixNM;
+/// A stack-allocated, column-major, 6x2 square matrix.
pub type Matrix6x2 = MatrixNM;
+/// A stack-allocated, column-major, 4x3 square matrix.
pub type Matrix4x3 = MatrixNM;
+/// A stack-allocated, column-major, 5x3 square matrix.
pub type Matrix5x3 = MatrixNM;
+/// A stack-allocated, column-major, 6x3 square matrix.
pub type Matrix6x3 = MatrixNM;
+/// A stack-allocated, column-major, 5x4 square matrix.
pub type Matrix5x4 = MatrixNM;
+/// A stack-allocated, column-major, 6x4 square matrix.
pub type Matrix6x4 = MatrixNM;
+/// A stack-allocated, column-major, 6x5 square matrix.
pub type Matrix6x5 = MatrixNM;
@@ -81,11 +117,17 @@ pub type DVector = Matrix>;
/// A statically sized D-dimensional column vector.
pub type VectorN = MatrixNM;
+/// A stack-allocated, 1-dimensional column vector.
pub type Vector1 = VectorN;
+/// A stack-allocated, 2-dimensional column vector.
pub type Vector2 = VectorN;
+/// A stack-allocated, 3-dimensional column vector.
pub type Vector3 = VectorN;
+/// A stack-allocated, 4-dimensional column vector.
pub type Vector4 = VectorN;
+/// A stack-allocated, 5-dimensional column vector.
pub type Vector5 = VectorN;
+/// A stack-allocated, 6-dimensional column vector.
pub type Vector6 = VectorN;
@@ -102,9 +144,15 @@ pub type RowDVector = Matrix>;
/// A statically sized D-dimensional row vector.
pub type RowVectorN = MatrixNM;
+/// A stack-allocated, 1-dimensional row vector.
pub type RowVector1 = RowVectorN;
+/// A stack-allocated, 2-dimensional row vector.
pub type RowVector2 = RowVectorN;
+/// A stack-allocated, 3-dimensional row vector.
pub type RowVector3 = RowVectorN;
+/// A stack-allocated, 4-dimensional row vector.
pub type RowVector4 = RowVectorN;
+/// A stack-allocated, 5-dimensional row vector.
pub type RowVector5 = RowVectorN;
+/// A stack-allocated, 6-dimensional row vector.
pub type RowVector6 = RowVectorN;
diff --git a/src/core/allocator.rs b/src/core/allocator.rs
index 23bfd356..d0c0a416 100644
--- a/src/core/allocator.rs
+++ b/src/core/allocator.rs
@@ -1,3 +1,5 @@
+//! Abstract definition of a matrix data storage allocator.
+
use std::any::Any;
use core::Scalar;
@@ -15,6 +17,7 @@ use core::storage::{Storage, OwnedStorage};
/// Every allocator must be both static and dynamic. Though not all implementations may share the
/// same `Buffer` type.
pub trait Allocator: Any + Sized {
+ /// The type of buffer this allocator can instanciate.
type Buffer: OwnedStorage;
/// Allocates a buffer with the given number of rows and columns without initializing its content.
diff --git a/src/core/cg.rs b/src/core/cg.rs
index cfd40ac3..e409d006 100644
--- a/src/core/cg.rs
+++ b/src/core/cg.rs
@@ -25,7 +25,7 @@ impl SquareMatrix
#[inline]
pub fn new_scaling(scaling: N) -> Self {
let mut res = Self::from_diagonal_element(scaling);
- res[(D::dim(), D::dim())] = N::one();
+ res[(D::dim() - 1, D::dim() - 1)] = N::one();
res
}
@@ -50,7 +50,7 @@ impl SquareMatrix
SB: Storage, U1>,
S::Alloc: Allocator, U1> {
let mut res = Self::one();
- res.fixed_slice_mut::, U1>(0, D::dim()).copy_from(translation);
+ res.fixed_slice_mut::, U1>(0, D::dim() - 1).copy_from(translation);
res
}
@@ -311,7 +311,7 @@ impl SquareMatrix
S::Alloc: Allocator, U1> {
for i in 0 .. D::dim() {
for j in 0 .. D::dim() - 1 {
- self[(j, i)] += shift[i] * self[(D::dim(), j)];
+ self[(j, i)] += shift[j] * self[(D::dim() - 1, i)];
}
}
}
@@ -324,12 +324,12 @@ impl SquareMatrix
S::Alloc: Allocator, U1> +
Allocator, DimNameDiff> +
Allocator> {
- let scale = self.fixed_slice::>(D::dim(), 0).tr_dot(&shift);
+ let scale = self.fixed_slice::>(D::dim() - 1, 0).tr_dot(&shift);
let post_translation = self.fixed_slice::, DimNameDiff>(0, 0) * shift;
- self[(D::dim(), D::dim())] += scale;
+ self[(D::dim() - 1, D::dim() - 1)] += scale;
- let mut translation = self.fixed_slice_mut::, U1>(0, D::dim());
+ let mut translation = self.fixed_slice_mut::, U1>(0, D::dim() - 1);
translation += post_translation;
}
}
@@ -349,7 +349,7 @@ impl Transformation, SB>> for Squa
fn transform_vector(&self, v: &ColumnVector, SB>)
-> ColumnVector, SB> {
let transform = self.fixed_slice::, DimNameDiff>(0, 0);
- let normalizer = self.fixed_slice::>(D::dim(), 0);
+ let normalizer = self.fixed_slice::>(D::dim() - 1, 0);
let n = normalizer.tr_dot(&v);
if !n.is_zero() {
@@ -363,9 +363,9 @@ impl Transformation, SB>> for Squa
fn transform_point(&self, pt: &PointBase, SB>)
-> PointBase, SB> {
let transform = self.fixed_slice::, DimNameDiff>(0, 0);
- let translation = self.fixed_slice::, U1>(0, D::dim());
- let normalizer = self.fixed_slice::>(D::dim(), 0);
- let n = normalizer.tr_dot(&pt.coords) + unsafe { *self.get_unchecked(D::dim(), D::dim()) };
+ let translation = self.fixed_slice::, U1>(0, D::dim() - 1);
+ let normalizer = self.fixed_slice::>(D::dim() - 1, 0);
+ let n = normalizer.tr_dot(&pt.coords) + unsafe { *self.get_unchecked(D::dim() - 1, D::dim() - 1) };
if !n.is_zero() {
return transform * (pt / n) + translation;
diff --git a/src/core/constraint.rs b/src/core/constraint.rs
index 182bf2ae..0f017e5b 100644
--- a/src/core/constraint.rs
+++ b/src/core/constraint.rs
@@ -1,6 +1,8 @@
+//! Compatibility constraints between matrix shapes, e.g., for addition or multiplication.
+
use core::dimension::{Dim, DimName, Dynamic};
-/// A type for enforcing constraints.
+/// A type used in `where` clauses for enforcing constraints.
pub struct ShapeConstraint;
/// Constraints `C1` and `R2` to be equivalent.
@@ -14,9 +16,12 @@ where ShapeConstraint: DimEq {
}
macro_rules! equality_trait_decl(
- ($($Trait: ident),* $(,)*) => {$(
+ ($($doc: expr, $Trait: ident),* $(,)*) => {$(
// XXX: we can't do something like `DimEq for D2` because we would require a blancket impl…
+ #[doc = $doc]
pub trait $Trait {
+ /// This is either equal to `D1` or `D2`, always choosing the one (if any) which is a type-level
+ /// constant.
type Representative: Dim;
}
@@ -34,11 +39,26 @@ macro_rules! equality_trait_decl(
)*}
);
-equality_trait_decl!(DimEq, SameNumberOfRows, SameNumberOfColumns);
+equality_trait_decl!(
+ "Constraints `D1` and `D2` to be equivalent.",
+ DimEq,
-/// Constraints D1 and D2 to be equivalent, where the both designates dimensions of algebraic
+ "Constraints `D1` and `D2` to be equivalent. \
+ They are both assumed to be the number of \
+ rows of a matrix.",
+ SameNumberOfRows,
+
+ "Constraints `D1` and `D2` to be equivalent. \
+ They are both assumed to be the number of \
+ columns of a matrix.",
+ SameNumberOfColumns
+);
+
+/// Constraints D1 and D2 to be equivalent, where they both designate dimensions of algebraic
/// entities (e.g. square matrices).
pub trait SameDimension: SameNumberOfRows + SameNumberOfColumns {
+ /// This is either equal to `D1` or `D2`, always choosing the one (if any) which is a type-level
+ /// constant.
type Representative: Dim;
}
diff --git a/src/core/construction.rs b/src/core/construction.rs
index db586a6c..606f0a2f 100644
--- a/src/core/construction.rs
+++ b/src/core/construction.rs
@@ -116,6 +116,10 @@ impl> Matrix
res
}
+ /// Builds a new matrix from its rows.
+ ///
+ /// Panics if not enough rows are provided (for statically-sized matrices), or if all rows do
+ /// not have the same dimensions.
#[inline]
pub fn from_rows(rows: &[Matrix]) -> Matrix
where SB: Storage {
@@ -127,13 +131,18 @@ impl> Matrix
if C::try_to_usize().is_none() {
assert!(rows.iter().all(|r| r.len() == ncols),
- "The rows provided must all have the same dimension.");
+ "The provided rows must all have the same dimension.");
}
// FIXME: optimize that.
Self::from_fn_generic(R::from_usize(nrows), C::from_usize(ncols), |i, j| rows[i][(0, j)])
}
+
+ /// Builds a new matrix from its columns.
+ ///
+ /// Panics if not enough columns are provided (for statically-sized matrices), or if all
+ /// columns do not have the same dimensions.
#[inline]
pub fn from_columns(columns: &[ColumnVector]) -> Matrix
where SB: Storage {
@@ -239,12 +248,17 @@ macro_rules! impl_constructors(
Self::from_fn_generic($($gargs, )* f)
}
+ /// Creates an identity matrix. If the matrix is not square, the largest square
+ /// submatrix (starting at the first row and column) is set to the identity while all
+ /// other entries are set to zero.
#[inline]
pub fn identity($($args: usize,)*) -> Matrix
where N: Zero + One {
Self::identity_generic($($gargs),* )
}
+ /// Creates a matrix filled with its diagonal filled with `elt` and all other
+ /// components set to zero.
#[inline]
pub fn from_diagonal_element($($args: usize,)* elt: N) -> Matrix
where N: Zero + One {
diff --git a/src/core/coordinates.rs b/src/core/coordinates.rs
index 6fff9193..3a8f371f 100644
--- a/src/core/coordinates.rs
+++ b/src/core/coordinates.rs
@@ -1,3 +1,9 @@
+#![allow(missing_docs)]
+
+//! Structures to which matrices and vector can be auto-dereferenced (through `Deref`) to access
+//! components using their names. For example, if `v` is a 3D vector, one can write `v.z` instead
+//! of `v[2]`.
+
use std::mem;
use std::ops::{Deref, DerefMut};
@@ -14,8 +20,10 @@ use core::allocator::OwnedAllocator;
macro_rules! coords_impl(
($T: ident; $($comps: ident),*) => {
+ /// Data structure used to provide access to matrix and vector coordinates with the dot
+ /// notation, e.g., `v.x` is the same as `v[0]` for a vector.
#[repr(C)]
- #[derive(Eq, PartialEq, RustcEncodable, RustcDecodable, Clone, Hash, Debug, Copy)]
+ #[derive(Eq, PartialEq, Clone, Hash, Debug, Copy, Serialize, Deserialize)]
pub struct $T {
$(pub $comps: N),*
}
diff --git a/src/core/decompositions.rs b/src/core/decompositions.rs
index 7c19bd21..41183fcb 100644
--- a/src/core/decompositions.rs
+++ b/src/core/decompositions.rs
@@ -272,14 +272,7 @@ impl> SquareMatrix {
///
/// Matrix symmetricness is not checked. Returns `None` if `self` is not definite positive.
#[inline]
- pub fn cholesky(&self) -> Option> {
- let out = self.transpose();
- self.do_cholesky(out).ok()
- }
-
- /// Cholesky decomposition G of a square symmetric positive definite matrix A, such that A = G * G^T
- #[inline]
- pub fn cholesky_unchecked(&self) -> Result, &'static str> {
+ pub fn cholesky(&self) -> Result, &'static str> {
let out = self.transpose();
if !out.relative_eq(self, N::default_epsilon(), N::default_max_relative()) {
@@ -289,6 +282,13 @@ impl> SquareMatrix {
self.do_cholesky(out)
}
+ /// Cholesky decomposition G of a square symmetric positive definite matrix A, such that A = G * G^T
+ #[inline]
+ pub fn cholesky_unchecked(&self) -> Result, &'static str> {
+ let out = self.transpose();
+ self.do_cholesky(out)
+ }
+
#[inline(always)]
fn do_cholesky(&self, mut out: OwnedSquareMatrix)
-> Result, &'static str> {
diff --git a/src/core/default_allocator.rs b/src/core/default_allocator.rs
index 41cdf50d..acfbe97c 100644
--- a/src/core/default_allocator.rs
+++ b/src/core/default_allocator.rs
@@ -1,3 +1,8 @@
+//! The default matrix data storage allocator.
+//!
+//! This will use stack-allocated buffers for matrices with dimensions known at compile-time, and
+//! heap-allocated buffers for matrices with at least one dimension unknown at compile-time.
+
use std::mem;
use std::ops::Mul;
diff --git a/src/core/dimension.rs b/src/core/dimension.rs
index 1f723ad4..20819b68 100644
--- a/src/core/dimension.rs
+++ b/src/core/dimension.rs
@@ -1,10 +1,14 @@
+#![allow(missing_docs)]
+
+//! Traits and tags for identifying the dimension of all algebraic entities.
+
use std::fmt::Debug;
use std::any::Any;
use std::ops::{Add, Sub, Mul, Div};
use typenum::{self, Unsigned, UInt, B1, Bit, UTerm, Sum, Prod, Diff, Quot};
/// Dim of dynamically-sized algebraic entities.
-#[derive(Clone, Copy, Eq, PartialEq, Debug)]
+#[derive(Clone, Copy, Eq, PartialEq, Debug, Serialize, Deserialize)]
pub struct Dynamic {
value: usize
}
@@ -19,17 +23,27 @@ impl Dynamic {
}
}
-/// Trait implemented by dynamic dimensions.
+/// Trait implemented by `Dynamic`.
pub trait IsDynamic { }
-/// Trait implemented by dimensions that are not equal to U1.
+/// Trait implemented by `Dynamic` and type-level integers different from `U1`.
pub trait IsNotStaticOne { }
impl IsDynamic for Dynamic { }
impl IsNotStaticOne for Dynamic { }
+/// Trait implemented by any type that can be used as a dimension. This includes type-level
+/// integers and `Dynamic` (for dimensions not known at compile-time).
pub trait Dim: Any + Debug + Copy + PartialEq + Send {
+ /// Gets the compile-time value of `Self`. Returns `None` if it is not known, i.e., if `Self =
+ /// Dynamic`.
fn try_to_usize() -> Option;
+
+ /// Gets the run-time value of `self`. For type-level integers, this is the same as
+ /// `Self::try_to_usize().unwrap()`.
fn value(&self) -> usize;
+
+ /// Builds an instance of `Self` from a run-time value. Panics if `Self` is a type-level
+ /// integer and `dim != Self::try_to_usize().unwrap()`.
fn from_usize(dim: usize) -> Self;
}
@@ -127,6 +141,7 @@ dim_ops!(
);
+/// Trait implemented exclusively by type-level integers.
pub trait DimName: Dim {
type Value: NamedDim;
@@ -146,7 +161,7 @@ pub trait NamedDim: Sized + Any + Unsigned {
type Name: DimName;
}
-#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
pub struct U1;
impl Dim for U1 {
@@ -182,7 +197,7 @@ impl NamedDim for typenum::U1{
macro_rules! named_dimension(
($($D: ident),* $(,)*) => {$(
- #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
+ #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
pub struct $D;
impl Dim for $D {
diff --git a/src/core/iter.rs b/src/core/iter.rs
index 50af9da5..3c99a4ae 100644
--- a/src/core/iter.rs
+++ b/src/core/iter.rs
@@ -1,3 +1,5 @@
+//! Matrix iterators.
+
use std::marker::PhantomData;
use std::mem;
diff --git a/src/core/matrix.rs b/src/core/matrix.rs
index cde94f38..c92b76a8 100644
--- a/src/core/matrix.rs
+++ b/src/core/matrix.rs
@@ -7,9 +7,9 @@ use std::any::TypeId;
use std::mem;
use approx::ApproxEq;
-use alga::general::{Field, Real};
+use alga::general::{Ring, Real};
-use core::Scalar;
+use core::{Scalar, Unit};
use core::dimension::{Dim, DimAdd, DimSum, U1, U2};
use core::constraint::{ShapeConstraint, SameNumberOfRows, SameNumberOfColumns};
use core::iter::{MatrixIter, MatrixIterMut};
@@ -55,10 +55,37 @@ pub type MatrixTrMul = Matrix =
Matrix>::Alloc as Allocator>::Buffer>;
+/// The most generic column-major matrix (and vector) type.
+///
+/// It combines four type parameters:
+/// - `N`: for the matrix components scalar type.
+/// - `R`: for the matrix number of rows.
+/// - `C`: for the matrix number of columns.
+/// - `S`: for the matrix data storage, i.e., the buffer that actually contains the matrix
+/// components.
+///
+/// The matrix dimensions parameters `R` and `C` can either be:
+/// - type-level unsigned integer contants (e.g. `U1`, `U124`) from the `nalgebra::` root module.
+/// All numbers from 0 to 127 are defined that way.
+/// - type-level unsigned integer constants (e.g. `U1024`, `U10000`) from the `typenum::` crate.
+/// Using those, you will not get error messages as nice as for numbers smaller than 128 defined on
+/// the `nalgebra::` module.
+/// - the special value `Dynamic` from the `nalgebra::` root module. This indicates that the
+/// specified dimension is not known at compile-time. Note that this will generally imply that the
+/// matrix data storage `S` performs a dynamic allocation and contains extra metadata for the
+/// matrix shape.
+///
+/// Note that mixing `Dynamic` with type-level unsigned integers is allowed. Actually, a
+/// dynamically-sized column vector should be represented as a `Matrix` (given
+/// some concrete types for `N` and a compatible data storage type `S`).
#[repr(C)]
-#[derive(RustcEncodable, RustcDecodable, Hash, Debug, Clone, Copy)]
+#[derive(Serialize, Deserialize, Hash, Debug, Clone, Copy)]
pub struct Matrix {
+ /// The data storage that contains all the matrix components and informations about its number
+ /// of rows and column (if needed).
pub data: S,
+
+ #[serde(skip_serializing, skip_deserializing)]
_phantoms: PhantomData<(N, R, C)>
}
@@ -149,7 +176,7 @@ impl> Matrix {
nrows * ncols
}
- /// The shape (number of rows, number of columns) of this matrix.
+ /// The shape of this matrix returned as the tuple (number of rows, number of columns).
#[inline]
pub fn shape(&self) -> (usize, usize) {
let (nrows, ncols) = self.data.shape();
@@ -405,6 +432,20 @@ impl ColumnVector
res
}
+
+ /// Constructs a vector from coordinates in projective space, i.e., removes a `0` at the end of
+ /// `self`. Returns `None` if this last component is not zero.
+ #[inline]
+ pub fn from_homogeneous(v: ColumnVector, SB>) -> Option>
+ where SB: Storage, U1, Alloc = S::Alloc> {
+ if v[v.len() - 1].is_zero() {
+ let nrows = D::from_usize(v.len() - 1);
+ Some(v.generic_slice((0, 0), (nrows, U1)).into_owned())
+ }
+ else {
+ None
+ }
+ }
}
@@ -677,7 +718,7 @@ impl PartialOrd for Matrix
if let Some(mut first_ord) = first_ord {
let mut it = self.iter().zip(other.iter());
- it.next(); // Drop the first elements (we already tested it).
+ let _ = it.next(); // Drop the first elements (we already tested it).
for (left, right) in it {
if let Some(ord) = left.partial_cmp(right) {
@@ -806,7 +847,7 @@ impl fmt::Display for Matrix
impl Matrix
- where N: Scalar + Field,
+ where N: Scalar + Ring,
S: Storage {
/// The dot product between two matrices (seen as vectors).
#[inline]
@@ -1011,3 +1052,35 @@ impl Matrix
}
}
}
+
+impl ApproxEq for Unit>
+ where N: Scalar + ApproxEq,
+ S: Storage,
+ N::Epsilon: Copy {
+ type Epsilon = N::Epsilon;
+
+ #[inline]
+ fn default_epsilon() -> Self::Epsilon {
+ N::default_epsilon()
+ }
+
+ #[inline]
+ fn default_max_relative() -> Self::Epsilon {
+ N::default_max_relative()
+ }
+
+ #[inline]
+ fn default_max_ulps() -> u32 {
+ N::default_max_ulps()
+ }
+
+ #[inline]
+ fn relative_eq(&self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon) -> bool {
+ self.as_ref().relative_eq(other.as_ref(), epsilon, max_relative)
+ }
+
+ #[inline]
+ fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
+ self.as_ref().ulps_eq(other.as_ref(), epsilon, max_ulps)
+ }
+}
diff --git a/src/core/matrix_alga.rs b/src/core/matrix_alga.rs
index 0c4ae645..ed0bad14 100644
--- a/src/core/matrix_alga.rs
+++ b/src/core/matrix_alga.rs
@@ -263,7 +263,7 @@ impl FiniteDimInnerSpace for Matrix
a = Self::from_column_slice(&[N::zero(), -v[2], v[1]]);
};
- a.normalize_mut();
+ let _ = a.normalize_mut();
if f(&a.cross(v)) {
f(&a);
diff --git a/src/core/matrix_array.rs b/src/core/matrix_array.rs
index 6d2e7154..5ef36198 100644
--- a/src/core/matrix_array.rs
+++ b/src/core/matrix_array.rs
@@ -1,6 +1,11 @@
+use std::mem;
+use std::marker::PhantomData;
use std::ops::{Deref, DerefMut, Mul};
-use std::fmt::{Debug, Formatter, Result};
+use std::fmt::{self, Debug, Formatter};
use std::hash::{Hash, Hasher};
+use serde::{Serialize, Serializer, Deserialize, Deserializer};
+use serde::ser::SerializeSeq;
+use serde::de::{SeqVisitor, Visitor};
use typenum::Prod;
use generic_array::{ArrayLength, GenericArray};
@@ -28,6 +33,7 @@ where R: DimName,
data: GenericArray>
}
+
impl Hash for MatrixArray
where N: Hash,
R: DimName,
@@ -70,7 +76,7 @@ where N: Debug,
R::Value: Mul