/*! # nalgebra **nalgebra** is a 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](https://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] // TODO: replace the * by the latest version. nalgebra = "*" ``` Most useful functionalities of **nalgebra** are grouped in the root module `nalgebra::`. However, the recommended way to use **nalgebra** is to import types and traits explicitly, and call free-functions using the `na::` prefix: ``` #[macro_use] extern crate approx; // For the macro assert_relative_eq! extern crate nalgebra as na; use na::{Vector3, Rotation3}; fn main() { let axis = Vector3::x_axis(); let angle = 1.57; let b = Rotation3::from_axis_angle(&axis, angle); assert_relative_eq!(b.axis().unwrap(), axis); assert_relative_eq!(b.angle(), angle); } ``` ## 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: * A single parametrizable type [`Matrix`](Matrix) for vectors, (square or rectangular) matrices, and slices with dimensions known either at compile-time (using type-level integers) or at runtime. * Matrices and vectors with compile-time sizes are statically allocated while dynamic ones are allocated on the heap. * Convenient aliases for low-dimensional matrices and vectors: [`Vector1`](Vector1) to [`Vector6`](Vector6) and [`Matrix1x1`](Matrix1) to [`Matrix6x6`](Matrix6), including rectangular matrices like [`Matrix2x5`](Matrix2x5). * Points sizes known at compile time, and convenience aliases: [`Point1`](Point1) to [`Point6`](Point6). * Translation (seen as a transformation that composes by multiplication): [`Translation2`](Translation2), [`Translation3`](Translation3). * Rotation matrices: [`Rotation2`](Rotation2), [`Rotation3`](Rotation3). * Quaternions: [`Quaternion`](Quaternion), [`UnitQuaternion`](UnitQuaternion) (for 3D rotation). * Unit complex numbers can be used for 2D rotation: [`UnitComplex`](UnitComplex). * Algebraic entities with a norm equal to one: [`Unit`](Unit), e.g., `Unit>`. * Isometries (translation ⨯ rotation): [`Isometry2`](Isometry2), [`Isometry3`](Isometry3) * Similarity transformations (translation ⨯ rotation ⨯ uniform scale): [`Similarity2`](Similarity2), [`Similarity3`](Similarity3). * Affine transformations stored as a homogeneous matrix: [`Affine2`](Affine2), [`Affine3`](Affine3). * Projective (i.e. invertible) transformations stored as a homogeneous matrix: [`Projective2`](Projective2), [`Projective3`](Projective3). * General transformations that does not have to be invertible, stored as a homogeneous matrix: [`Transform2`](Transform2), [`Transform3`](Transform3). * 3D projections for computer graphics: [`Perspective3`](Perspective3), [`Orthographic3`](Orthographic3). * Matrix factorizations: [`Cholesky`](Cholesky), [`QR`](QR), [`LU`](LU), [`FullPivLU`](FullPivLU), [`SVD`](SVD), [`Schur`](Schur), [`Hessenberg`](Hessenberg), [`SymmetricEigen`](SymmetricEigen). * Insertion and removal of rows of columns of a matrix. */ #![deny( missing_docs, nonstandard_style, unused_variables, unused_mut, unused_parens, rust_2018_idioms, rust_2018_compatibility, future_incompatible, missing_copy_implementations )] #![cfg_attr(not(feature = "rkyv-serialize-no-std"), deny(unused_results))] // TODO: deny this globally once bytecheck stops generating unused results. #![doc( html_favicon_url = "https://nalgebra.org/img/favicon.ico", html_root_url = "https://docs.rs/nalgebra/0.25.0" )] #![cfg_attr(not(feature = "std"), no_std)] /// Generates an appropriate deprecation note with a suggestion for replacement. /// /// Used for deprecating slice types in various locations throughout the library. /// See #1076 for more information. macro_rules! slice_deprecation_note { ($replacement:ident) => { concat!("Use ", stringify!($replacement), r###" instead. See [issue #1076](https://github.com/dimforge/nalgebra/issues/1076) for more information."###) } } pub(crate) use slice_deprecation_note; #[cfg(feature = "rand-no-std")] extern crate rand_package as rand; #[cfg(feature = "serde-serialize-no-std")] #[macro_use] extern crate serde; #[macro_use] extern crate approx; extern crate num_traits as num; #[cfg(all(feature = "alloc", not(feature = "std")))] #[cfg_attr(test, macro_use)] extern crate alloc; #[cfg(not(feature = "std"))] extern crate core as std; #[macro_use] #[cfg(feature = "io")] extern crate pest_derive; pub mod base; #[cfg(feature = "debug")] pub mod debug; pub mod geometry; #[cfg(feature = "io")] pub mod io; pub mod linalg; #[cfg(feature = "proptest-support")] pub mod proptest; #[cfg(feature = "sparse")] pub mod sparse; mod third_party; pub use crate::base::*; pub use crate::geometry::*; pub use crate::linalg::*; #[cfg(feature = "sparse")] pub use crate::sparse::*; #[cfg(feature = "std")] #[deprecated( note = "The 'core' module is being renamed to 'base' to avoid conflicts with the 'core' crate." )] pub use base as core; #[cfg(feature = "macros")] pub use nalgebra_macros::{dmatrix, dvector, matrix, point, vector}; use simba::scalar::SupersetOf; use std::cmp::{self, Ordering, PartialOrd}; use num::{One, Signed, Zero}; use base::allocator::Allocator; pub use num_complex::Complex; pub use simba::scalar::{ ClosedAdd, ClosedDiv, ClosedMul, ClosedSub, ComplexField, Field, RealField, }; pub use simba::simd::{SimdBool, SimdComplexField, SimdPartialOrd, SimdRealField, SimdValue}; /// Gets the multiplicative identity element. /// /// # See also: /// /// * [`origin`](../nalgebra/fn.origin.html) /// * [`zero`](fn.zero.html) #[inline] pub fn one() -> T { T::one() } /// Gets the additive identity element. /// /// # See also: /// /// * [`one`](fn.one.html) /// * [`origin`](../nalgebra/fn.origin.html) #[inline] pub fn zero() -> T { T::zero() } /* * * Ordering * */ // XXX: this is very naive and could probably be optimized for specific types. // XXX: also, we might just want to use divisions, but assuming `val` is usually not far from `min` // or `max`, would it still be more efficient? /// Wraps `val` into the range `[min, max]` using modular arithmetics. /// /// The range must not be empty. #[must_use] #[inline] pub fn wrap(mut val: T, min: T, max: T) -> T where T: Copy + PartialOrd + ClosedAdd + ClosedSub, { assert!(min < max, "Invalid wrapping bounds."); let width = max - min; if val < min { val += width; while val < min { val += width } } else if val > max { val -= width; while val > max { val -= width } } val } /// Returns a reference to the input value clamped to the interval `[min, max]`. /// /// In particular: /// * If `min < val < max`, this returns `val`. /// * If `val <= min`, this returns `min`. /// * If `val >= max`, this returns `max`. #[must_use] #[inline] pub fn clamp(val: T, min: T, max: T) -> T { if val > min { if val < max { val } else { max } } else { min } } /// Same as `cmp::max`. #[inline] pub fn max(a: T, b: T) -> T { cmp::max(a, b) } /// Same as `cmp::min`. #[inline] pub fn min(a: T, b: T) -> T { cmp::min(a, b) } /// The absolute value of `a`. /// /// Deprecated: Use [`Matrix::abs`] or [`ComplexField::abs`] instead. #[deprecated(note = "use the inherent method `Matrix::abs` or `ComplexField::abs` instead")] #[inline] pub fn abs(a: &T) -> T { a.abs() } /// Returns the infimum of `a` and `b`. #[deprecated(note = "use the inherent method `Matrix::inf` instead")] #[inline] pub fn inf(a: &OMatrix, b: &OMatrix) -> OMatrix where T: Scalar + SimdPartialOrd, DefaultAllocator: Allocator, { a.inf(b) } /// Returns the supremum of `a` and `b`. #[deprecated(note = "use the inherent method `Matrix::sup` instead")] #[inline] pub fn sup(a: &OMatrix, b: &OMatrix) -> OMatrix where T: Scalar + SimdPartialOrd, DefaultAllocator: Allocator, { a.sup(b) } /// Returns simultaneously the infimum and supremum of `a` and `b`. #[deprecated(note = "use the inherent method `Matrix::inf_sup` instead")] #[inline] pub fn inf_sup( a: &OMatrix, b: &OMatrix, ) -> (OMatrix, OMatrix) where T: Scalar + SimdPartialOrd, DefaultAllocator: Allocator, { a.inf_sup(b) } /// Compare `a` and `b` using a partial ordering relation. #[inline] pub fn partial_cmp(a: &T, b: &T) -> Option { a.partial_cmp(b) } /// Returns `true` iff `a` and `b` are comparable and `a < b`. #[inline] pub fn partial_lt(a: &T, b: &T) -> bool { a.lt(b) } /// Returns `true` iff `a` and `b` are comparable and `a <= b`. #[inline] pub fn partial_le(a: &T, b: &T) -> bool { a.le(b) } /// Returns `true` iff `a` and `b` are comparable and `a > b`. #[inline] pub fn partial_gt(a: &T, b: &T) -> bool { a.gt(b) } /// Returns `true` iff `a` and `b` are comparable and `a >= b`. #[inline] pub fn partial_ge(a: &T, b: &T) -> bool { a.ge(b) } /// Return the minimum of `a` and `b` if they are comparable. #[inline] pub fn partial_min<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> Option<&'a T> { if let Some(ord) = a.partial_cmp(b) { match ord { Ordering::Greater => Some(b), _ => Some(a), } } else { None } } /// Return the maximum of `a` and `b` if they are comparable. #[inline] pub fn partial_max<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> Option<&'a T> { if let Some(ord) = a.partial_cmp(b) { match ord { Ordering::Less => Some(b), _ => Some(a), } } else { None } } /// Clamp `value` between `min` and `max`. Returns `None` if `value` is not comparable to /// `min` or `max`. #[inline] pub fn partial_clamp<'a, T: PartialOrd>(value: &'a T, min: &'a T, max: &'a T) -> Option<&'a T> { if let (Some(cmp_min), Some(cmp_max)) = (value.partial_cmp(min), value.partial_cmp(max)) { if cmp_min == Ordering::Less { Some(min) } else if cmp_max == Ordering::Greater { Some(max) } else { Some(value) } } else { None } } /// Sorts two values in increasing order using a partial ordering. #[inline] pub fn partial_sort2<'a, T: PartialOrd>(a: &'a T, b: &'a T) -> Option<(&'a T, &'a T)> { if let Some(ord) = a.partial_cmp(b) { match ord { Ordering::Less => Some((a, b)), _ => Some((b, a)), } } else { None } } /* * * Point operations. * */ /// The center of two points. /// /// # See also: /// /// * [distance](fn.distance.html) /// * [`distance_squared`](fn.distance_squared.html) #[inline] pub fn center( p1: &Point, p2: &Point, ) -> Point { ((&p1.coords + &p2.coords) * convert::<_, T>(0.5)).into() } /// The distance between two points. /// /// # See also: /// /// * [center](fn.center.html) /// * [`distance_squared`](fn.distance_squared.html) #[inline] pub fn distance( p1: &Point, p2: &Point, ) -> T::SimdRealField { (&p2.coords - &p1.coords).norm() } /// The squared distance between two points. /// /// # See also: /// /// * [center](fn.center.html) /// * [distance](fn.distance.html) #[inline] pub fn distance_squared( p1: &Point, p2: &Point, ) -> T::SimdRealField { (&p2.coords - &p1.coords).norm_squared() } /* * Cast */ /// Converts an object from one type to an equivalent or more general one. /// /// See also [`try_convert`](fn.try_convert.html) for conversion to more specific types. /// /// # See also: /// /// * [`convert_ref`](fn.convert_ref.html) /// * [`convert_ref_unchecked`](fn.convert_ref_unchecked.html) /// * [`is_convertible`](../nalgebra/fn.is_convertible.html) /// * [`try_convert`](fn.try_convert.html) /// * [`try_convert_ref`](fn.try_convert_ref.html) #[inline] pub fn convert>(t: From) -> To { To::from_subset(&t) } /// Attempts to convert an object to a more specific one. /// /// See also [`convert`](fn.convert.html) for conversion to more general types. /// /// # See also: /// /// * [convert](fn.convert.html) /// * [`convert_ref`](fn.convert_ref.html) /// * [`convert_ref_unchecked`](fn.convert_ref_unchecked.html) /// * [`is_convertible`](../nalgebra/fn.is_convertible.html) /// * [`try_convert_ref`](fn.try_convert_ref.html) #[inline] pub fn try_convert, To>(t: From) -> Option { t.to_subset() } /// Indicates if [`try_convert`](fn.try_convert.html) will succeed without /// actually performing the conversion. /// /// # See also: /// /// * [convert](fn.convert.html) /// * [`convert_ref`](fn.convert_ref.html) /// * [`convert_ref_unchecked`](fn.convert_ref_unchecked.html) /// * [`try_convert`](fn.try_convert.html) /// * [`try_convert_ref`](fn.try_convert_ref.html) #[inline] pub fn is_convertible, To>(t: &From) -> bool { t.is_in_subset() } /// Use with care! Same as [`try_convert`](fn.try_convert.html) but /// without any property checks. /// /// # See also: /// /// * [convert](fn.convert.html) /// * [`convert_ref`](fn.convert_ref.html) /// * [`convert_ref_unchecked`](fn.convert_ref_unchecked.html) /// * [`is_convertible`](../nalgebra/fn.is_convertible.html) /// * [`try_convert`](fn.try_convert.html) /// * [`try_convert_ref`](fn.try_convert_ref.html) #[inline] pub fn convert_unchecked, To>(t: From) -> To { t.to_subset_unchecked() } /// Converts an object from one type to an equivalent or more general one. /// /// # See also: /// /// * [convert](fn.convert.html) /// * [`convert_ref_unchecked`](fn.convert_ref_unchecked.html) /// * [`is_convertible`](../nalgebra/fn.is_convertible.html) /// * [`try_convert`](fn.try_convert.html) /// * [`try_convert_ref`](fn.try_convert_ref.html) #[inline] pub fn convert_ref>(t: &From) -> To { To::from_subset(t) } /// Attempts to convert an object to a more specific one. /// /// # See also: /// /// * [convert](fn.convert.html) /// * [`convert_ref`](fn.convert_ref.html) /// * [`convert_ref_unchecked`](fn.convert_ref_unchecked.html) /// * [`is_convertible`](../nalgebra/fn.is_convertible.html) /// * [`try_convert`](fn.try_convert.html) #[inline] pub fn try_convert_ref, To>(t: &From) -> Option { t.to_subset() } /// Use with care! Same as [`try_convert`](fn.try_convert.html) but /// without any property checks. /// /// # See also: /// /// * [convert](fn.convert.html) /// * [`convert_ref`](fn.convert_ref.html) /// * [`is_convertible`](../nalgebra/fn.is_convertible.html) /// * [`try_convert`](fn.try_convert.html) /// * [`try_convert_ref`](fn.try_convert_ref.html) #[inline] pub fn convert_ref_unchecked, To>(t: &From) -> To { t.to_subset_unchecked() }