From 6d2469707d623c1abc56a4fcb8464fb55cb47d49 Mon Sep 17 00:00:00 2001 From: adamnemecek Date: Sun, 31 Mar 2019 14:14:07 -0700 Subject: [PATCH 01/30] added quaternionic divisions to changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb2c09e2..36aea56e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ as matrix decomposition. This excludes geometric type (like `Isometry`, `Rotatio #### Quaternion and geometric operations * Add trigonometric functions for quaternions: `.cos, .sin, .tan, .acos, .asin, .atan, .cosh, .sinh, .tanh, .acosh, .asinh, .atanh`. * Add geometric algebra operations for quaternions: `.inner, .outer, .project, .rejection` + * Add `.left_div, .right_div` for quaternions. * Add `.renormalize` to `Unit<...>` and `Rotation3` to correct potential drift due to repeated operations. Those drifts could cause them not to be pure rotations anymore. From 4e81830775bac43385878f3da63190fc708ecd9e Mon Sep 17 00:00:00 2001 From: sebcrozet Date: Sat, 6 Apr 2019 09:37:58 +0200 Subject: [PATCH 02/30] Add tests for serialization of 2D transformations. Fix #320. --- tests/core/serde.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/core/serde.rs b/tests/core/serde.rs index a65ca8b3..c209e35c 100644 --- a/tests/core/serde.rs +++ b/tests/core/serde.rs @@ -2,7 +2,8 @@ use na::{ DMatrix, Isometry3, IsometryMatrix3, Matrix3x4, Point3, Quaternion, Rotation3, Similarity3, - SimilarityMatrix3, Translation3, Unit, + SimilarityMatrix3, Translation3, Unit, Point2, Translation2, Rotation2, Isometry2, IsometryMatrix2, + Similarity2, SimilarityMatrix2, }; use rand; use serde_json; @@ -35,6 +36,13 @@ test_serde!( serde_similarity3, Similarity3; serde_similarity_matrix3, SimilarityMatrix3; serde_quaternion, Quaternion; + serde_point2, Point2; + serde_translation2, Translation2; + serde_rotation2, Rotation2; + serde_isometry2, Isometry2; + serde_isometry_matrix2, IsometryMatrix2; + serde_similarity2, Similarity2; + serde_similarity_matrix2, SimilarityMatrix2; ); #[test] From 5392b936d179fdfca10494b63a2661668bf9e76e Mon Sep 17 00:00:00 2001 From: Stefan Mesken Date: Mon, 8 Apr 2019 17:29:32 +0200 Subject: [PATCH 03/30] Allow the removal of multiple rows/columns given an array of indices. #530 --- src/base/edition.rs | 143 ++++++++++++++++++++++++++++++++---------- tests/core/edition.rs | 108 +++++++++++++++++++++++++++++++ 2 files changed, 219 insertions(+), 32 deletions(-) diff --git a/src/base/edition.rs b/src/base/edition.rs index 5b1c16c4..1200f958 100644 --- a/src/base/edition.rs +++ b/src/base/edition.rs @@ -1,18 +1,18 @@ use num::{One, Zero}; use std::cmp; -use std::ptr; #[cfg(any(feature = "std", feature = "alloc"))] use std::iter::ExactSizeIterator; #[cfg(any(feature = "std", feature = "alloc"))] use std::mem; +use std::ptr; use crate::base::allocator::{Allocator, Reallocator}; use crate::base::constraint::{DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint}; +#[cfg(any(feature = "std", feature = "alloc"))] +use crate::base::dimension::Dynamic; use crate::base::dimension::{ Dim, DimAdd, DimDiff, DimMin, DimMinimum, DimName, DimSub, DimSum, U1, }; -#[cfg(any(feature = "std", feature = "alloc"))] -use crate::base::dimension::Dynamic; use crate::base::storage::{Storage, StorageMut}; #[cfg(any(feature = "std", feature = "alloc"))] use crate::base::DMatrix; @@ -42,12 +42,15 @@ impl> Matrix { /// Creates a new matrix by extracting the given set of rows from `self`. #[cfg(any(feature = "std", feature = "alloc"))] pub fn select_rows<'a, I>(&self, irows: I) -> MatrixMN - where I: IntoIterator, - I::IntoIter: ExactSizeIterator + Clone, - DefaultAllocator: Allocator { + where + I: IntoIterator, + I::IntoIter: ExactSizeIterator + Clone, + DefaultAllocator: Allocator, + { let irows = irows.into_iter(); let ncols = self.data.shape().1; - let mut res = unsafe { MatrixMN::new_uninitialized_generic(Dynamic::new(irows.len()), ncols) }; + let mut res = + unsafe { MatrixMN::new_uninitialized_generic(Dynamic::new(irows.len()), ncols) }; // First, check that all the indices from irows are valid. // This will allow us to use unchecked access in the inner loop. @@ -61,9 +64,7 @@ impl> Matrix { let src = self.column(j); for (destination, source) in irows.clone().enumerate() { - unsafe { - *res.vget_unchecked_mut(destination) = *src.vget_unchecked(*source) - } + unsafe { *res.vget_unchecked_mut(destination) = *src.vget_unchecked(*source) } } } @@ -73,12 +74,15 @@ impl> Matrix { /// Creates a new matrix by extracting the given set of columns from `self`. #[cfg(any(feature = "std", feature = "alloc"))] pub fn select_columns<'a, I>(&self, icols: I) -> MatrixMN - where I: IntoIterator, - I::IntoIter: ExactSizeIterator, - DefaultAllocator: Allocator { + where + I: IntoIterator, + I::IntoIter: ExactSizeIterator, + DefaultAllocator: Allocator, + { let icols = icols.into_iter(); let nrows = self.data.shape().0; - let mut res = unsafe { MatrixMN::new_uninitialized_generic(nrows, Dynamic::new(icols.len())) }; + let mut res = + unsafe { MatrixMN::new_uninitialized_generic(nrows, Dynamic::new(icols.len())) }; for (destination, source) in icols.enumerate() { res.column_mut(destination).copy_from(&self.column(*source)) @@ -137,10 +141,10 @@ impl> Matrix { /// Fills the diagonal of this matrix with the content of the given vector. #[inline] pub fn set_diagonal(&mut self, diag: &Vector) - where - R: DimMin, - S2: Storage, - ShapeConstraint: DimEq, R2>, + where + R: DimMin, + S2: Storage, + ShapeConstraint: DimEq, R2>, { let (nrows, ncols) = self.shape(); let min_nrows_ncols = cmp::min(nrows, ncols); @@ -303,6 +307,79 @@ impl> Matrix { self.remove_fixed_columns::(i) } + /// Removes all columns in `indices` + #[inline] + pub fn remove_columns_at(self, indices: &[usize]) -> MatrixMN + where + C: DimSub, + DefaultAllocator: Reallocator, + { + let mut m = self.into_owned(); + let mut v: Vec = indices.to_vec(); + let (nrows, ncols) = m.data.shape(); + let mut offset: usize = 0; + let mut target: usize = 0; + while offset + target < ncols.value() { + if v.contains(&(target + offset)) { + offset += 1; + } else { + unsafe { + let ptr_source = m + .data + .ptr() + .offset(((target + offset) * nrows.value()) as isize); + let ptr_target = m.data.ptr_mut().offset((target * nrows.value()) as isize); + + ptr::copy(ptr_source, ptr_target, nrows.value()); + target += 1; + } + } + } + + unsafe { + Matrix::from_data(DefaultAllocator::reallocate_copy( + nrows, + ncols.sub(Dynamic::from_usize(v.len())), + m.data, + )) + } + } + + /// Removes all columns in `indices` + #[inline] + pub fn remove_rows_at(self, indices: &[usize]) -> MatrixMN + where + R: DimSub, + DefaultAllocator: Reallocator, + { + let mut m = self.into_owned(); + let mut v: Vec = indices.to_vec(); + let (nrows, ncols) = m.data.shape(); + let mut offset: usize = 0; + let mut target: usize = 0; + while offset + target < nrows.value() * ncols.value() { + if v.contains(&((target + offset) % nrows.value())) { + offset += 1; + } else { + unsafe { + let ptr_source = m.data.ptr().offset((target + offset) as isize); + let ptr_target = m.data.ptr_mut().offset(target as isize); + + ptr::copy(ptr_source, ptr_target, 1); + target += 1; + } + } + } + + unsafe { + Matrix::from_data(DefaultAllocator::reallocate_copy( + nrows.sub(Dynamic::from_usize(v.len())), + ncols, + m.data, + )) + } + } + /// Removes `D::dim()` consecutive columns from this matrix, starting with the `i`-th /// (included). #[inline] @@ -628,7 +705,7 @@ impl> Matrix { /// rows than `self`, then the extra rows are filled with `val`. #[cfg(any(feature = "std", feature = "alloc"))] pub fn resize_vertically(self, new_nrows: usize, val: N) -> MatrixMN - where DefaultAllocator: Reallocator { + where DefaultAllocator: Reallocator { let ncols = self.data.shape().1; self.resize_generic(Dynamic::new(new_nrows), ncols, val) } @@ -639,12 +716,11 @@ impl> Matrix { /// columns than `self`, then the extra columns are filled with `val`. #[cfg(any(feature = "std", feature = "alloc"))] pub fn resize_horizontally(self, new_ncols: usize, val: N) -> MatrixMN - where DefaultAllocator: Reallocator { + where DefaultAllocator: Reallocator { let nrows = self.data.shape().0; self.resize_generic(nrows, Dynamic::new(new_ncols), val) } - /// Resizes this matrix so that it contains `R2::value()` rows and `C2::value()` columns. /// /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more @@ -731,7 +807,7 @@ impl DMatrix { /// /// Defined only for owned fully-dynamic matrices, i.e., `DMatrix`. pub fn resize_mut(&mut self, new_nrows: usize, new_ncols: usize, val: N) - where DefaultAllocator: Reallocator { + where DefaultAllocator: Reallocator { let placeholder = unsafe { Self::new_uninitialized(0, 0) }; let old = mem::replace(self, placeholder); let new = old.resize(new_nrows, new_ncols, val); @@ -741,7 +817,8 @@ impl DMatrix { #[cfg(any(feature = "std", feature = "alloc"))] impl MatrixMN - where DefaultAllocator: Allocator { +where DefaultAllocator: Allocator +{ /// Changes the number of rows of this matrix in-place. /// /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more @@ -750,8 +827,9 @@ impl MatrixMN /// Defined only for owned matrices with a dynamic number of rows (for example, `DVector`). #[cfg(any(feature = "std", feature = "alloc"))] pub fn resize_vertically_mut(&mut self, new_nrows: usize, val: N) - where DefaultAllocator: Reallocator { - let placeholder = unsafe { Self::new_uninitialized_generic(Dynamic::new(0), self.data.shape().1) }; + where DefaultAllocator: Reallocator { + let placeholder = + unsafe { Self::new_uninitialized_generic(Dynamic::new(0), self.data.shape().1) }; let old = mem::replace(self, placeholder); let new = old.resize_vertically(new_nrows, val); let _ = mem::replace(self, new); @@ -760,7 +838,8 @@ impl MatrixMN #[cfg(any(feature = "std", feature = "alloc"))] impl MatrixMN - where DefaultAllocator: Allocator { +where DefaultAllocator: Allocator +{ /// Changes the number of column of this matrix in-place. /// /// The values are copied such that `self[(i, j)] == result[(i, j)]`. If the result has more @@ -769,8 +848,9 @@ impl MatrixMN /// Defined only for owned matrices with a dynamic number of columns (for example, `DVector`). #[cfg(any(feature = "std", feature = "alloc"))] pub fn resize_horizontally_mut(&mut self, new_ncols: usize, val: N) - where DefaultAllocator: Reallocator { - let placeholder = unsafe { Self::new_uninitialized_generic(self.data.shape().0, Dynamic::new(0)) }; + where DefaultAllocator: Reallocator { + let placeholder = + unsafe { Self::new_uninitialized_generic(self.data.shape().0, Dynamic::new(0)) }; let old = mem::replace(self, placeholder); let new = old.resize_horizontally(new_ncols, val); let _ = mem::replace(self, new); @@ -898,7 +978,7 @@ where /// // The following panics because the vec length is not a multiple of 3. /// matrix.extend(vec![6, 7, 8, 9]); /// ``` - fn extend>(&mut self, iter: I) { + fn extend>(&mut self, iter: I) { self.data.extend(iter); } } @@ -921,7 +1001,7 @@ where /// vector.extend(vec![3, 4, 5]); /// assert!(vector.eq(&DVector::from_vec(vec![0, 1, 2, 3, 4, 5]))); /// ``` - fn extend>(&mut self, iter: I) { + fn extend>(&mut self, iter: I) { self.data.extend(iter); } } @@ -985,8 +1065,7 @@ where /// matrix.extend( /// vec![Vector4::new(6, 7, 8, 9)]); // too few dimensions! /// ``` - fn extend>>(&mut self, iter: I) - { + fn extend>>(&mut self, iter: I) { self.data.extend(iter); } } diff --git a/tests/core/edition.rs b/tests/core/edition.rs index 37452a2d..7c2dee0f 100644 --- a/tests/core/edition.rs +++ b/tests/core/edition.rs @@ -260,6 +260,63 @@ fn remove_columns() { assert!(computed.eq(&expected2)); } +#[test] +fn remove_columns_at() { + let m = DMatrix::from_row_slice(5, 5, &[ + 11, 12, 13, 14, 15, + 21, 22, 23, 24, 25, + 31, 32, 33, 34, 35, + 41, 42, 43, 44, 45, + 51, 52, 53, 54, 55 + ]); + + let expected1 = DMatrix::from_row_slice(5, 4, &[ + 12, 13, 14, 15, + 22, 23, 24, 25, + 32, 33, 34, 35, + 42, 43, 44, 45, + 52, 53, 54, 55 + ]); + + assert_eq!(m.remove_columns_at(&[0]), expected1); + + let m = DMatrix::from_row_slice(5, 5, &[ + 11, 12, 13, 14, 15, + 21, 22, 23, 24, 25, + 31, 32, 33, 34, 35, + 41, 42, 43, 44, 45, + 51, 52, 53, 54, 55 + ]); + + let expected2 = DMatrix::from_row_slice(5, 3, &[ + 11, 13, 15, + 21, 23, 25, + 31, 33, 35, + 41, 43, 45, + 51, 53, 55 + ]); + + assert_eq!(m.remove_columns_at(&[1,3]), expected2); + + let m = DMatrix::from_row_slice(5, 5, &[ + 11, 12, 13, 14, 15, + 21, 22, 23, 24, 25, + 31, 32, 33, 34, 35, + 41, 42, 43, 44, 45, + 51, 52, 53, 54, 55 + ]); + + let expected3 = DMatrix::from_row_slice(5, 2, &[ + 12, 13, + 22, 23, + 32, 33, + 42, 43, + 52, 53, + ]); + + assert_eq!(m.remove_columns_at(&[0,3,4]), expected3); +} + #[test] fn remove_rows() { @@ -316,6 +373,57 @@ fn remove_rows() { assert!(computed.eq(&expected2)); } +#[test] +fn remove_rows_at() { + let m = DMatrix::from_row_slice(5, 5, &[ + 11, 12, 13, 14, 15, + 21, 22, 23, 24, 25, + 31, 32, 33, 34, 35, + 41, 42, 43, 44, 45, + 51, 52, 53, 54, 55 + ]); + + let expected1 = DMatrix::from_row_slice(4, 5, &[ + 21, 22, 23, 24, 25, + 31, 32, 33, 34, 35, + 41, 42, 43, 44, 45, + 51, 52, 53, 54, 55 + ]); + + assert_eq!(m.remove_rows_at(&[0]), expected1); + + let m = DMatrix::from_row_slice(5, 5, &[ + 11, 12, 13, 14, 15, + 21, 22, 23, 24, 25, + 31, 32, 33, 34, 35, + 41, 42, 43, 44, 45, + 51, 52, 53, 54, 55 + ]); + + let expected2 = DMatrix::from_row_slice(3, 5, &[ + 11, 12, 13, 14, 15, + 31, 32, 33, 34, 35, + 51, 52, 53, 54, 55 + ]); + + assert_eq!(m.remove_rows_at(&[1,3]), expected2); + + let m = DMatrix::from_row_slice(5, 5, &[ + 11, 12, 13, 14, 15, + 21, 22, 23, 24, 25, + 31, 32, 33, 34, 35, + 41, 42, 43, 44, 45, + 51, 52, 53, 54, 55 + ]); + + let expected3 = DMatrix::from_row_slice(2, 5, &[ + 21, 22, 23, 24, 25, + 31, 32, 33, 34, 35 + ]); + + assert_eq!(m.remove_rows_at(&[0,3,4]), expected3); +} + #[test] fn insert_columns() { From cb459d4493641fc914aabf2300aeb912cc8784f9 Mon Sep 17 00:00:00 2001 From: Stefan Mesken Date: Mon, 8 Apr 2019 22:32:26 +0200 Subject: [PATCH 04/30] addressed Trevis CI error --- src/base/edition.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/base/edition.rs b/src/base/edition.rs index 1200f958..1c51479f 100644 --- a/src/base/edition.rs +++ b/src/base/edition.rs @@ -308,7 +308,7 @@ impl> Matrix { } /// Removes all columns in `indices` - #[inline] + #[cfg(any(feature = "std", feature = "alloc"))] pub fn remove_columns_at(self, indices: &[usize]) -> MatrixMN where C: DimSub, @@ -346,7 +346,7 @@ impl> Matrix { } /// Removes all columns in `indices` - #[inline] + #[cfg(any(feature = "std", feature = "alloc"))] pub fn remove_rows_at(self, indices: &[usize]) -> MatrixMN where R: DimSub, From ff9027f47342b3940083496f0c5bc63c7e83fe43 Mon Sep 17 00:00:00 2001 From: Stefan Mesken Date: Mon, 8 Apr 2019 23:10:27 +0200 Subject: [PATCH 05/30] removed depedency on Vec --- src/base/edition.rs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/src/base/edition.rs b/src/base/edition.rs index 1c51479f..e473246f 100644 --- a/src/base/edition.rs +++ b/src/base/edition.rs @@ -315,12 +315,11 @@ impl> Matrix { DefaultAllocator: Reallocator, { let mut m = self.into_owned(); - let mut v: Vec = indices.to_vec(); let (nrows, ncols) = m.data.shape(); let mut offset: usize = 0; let mut target: usize = 0; while offset + target < ncols.value() { - if v.contains(&(target + offset)) { + if indices.contains(&(target + offset)) { offset += 1; } else { unsafe { @@ -339,26 +338,25 @@ impl> Matrix { unsafe { Matrix::from_data(DefaultAllocator::reallocate_copy( nrows, - ncols.sub(Dynamic::from_usize(v.len())), + ncols.sub(Dynamic::from_usize(offset)), m.data, )) } } - /// Removes all columns in `indices` + /// Removes all rows in `indices` #[cfg(any(feature = "std", feature = "alloc"))] pub fn remove_rows_at(self, indices: &[usize]) -> MatrixMN where R: DimSub, DefaultAllocator: Reallocator, - { + { let mut m = self.into_owned(); - let mut v: Vec = indices.to_vec(); let (nrows, ncols) = m.data.shape(); let mut offset: usize = 0; let mut target: usize = 0; while offset + target < nrows.value() * ncols.value() { - if v.contains(&((target + offset) % nrows.value())) { + if indices.contains(&((target + offset) % nrows.value())) { offset += 1; } else { unsafe { @@ -373,7 +371,7 @@ impl> Matrix { unsafe { Matrix::from_data(DefaultAllocator::reallocate_copy( - nrows.sub(Dynamic::from_usize(v.len())), + nrows.sub(Dynamic::from_usize(offset / ncols.value ())), ncols, m.data, )) From 1df1c4226bae1d43ed11da59d35d38bd0cd46a90 Mon Sep 17 00:00:00 2001 From: sebcrozet Date: Tue, 2 Apr 2019 19:51:43 +0200 Subject: [PATCH 06/30] Add some infinite and reversed perspectives. This adds: infinite_perspective_rh_no infinite_perspective_rh_zo reversed_perspective_rh_no reversed_perspective_rh_zo reversed_infinite_perspective_rh_zo reversed_infinite_perspective_rh_zo Fix #573 --- nalgebra-glm/src/ext/matrix_clip_space.rs | 170 +++++++++++++++++++++- 1 file changed, 164 insertions(+), 6 deletions(-) diff --git a/nalgebra-glm/src/ext/matrix_clip_space.rs b/nalgebra-glm/src/ext/matrix_clip_space.rs index 6ef1404b..ec4f3b95 100644 --- a/nalgebra-glm/src/ext/matrix_clip_space.rs +++ b/nalgebra-glm/src/ext/matrix_clip_space.rs @@ -43,11 +43,7 @@ use na::{RealField}; // //pub fn infinite_perspective_lh(fovy: N, aspect: N, near: N) -> TMat4 { // unimplemented!() -//} -// -//pub fn infinite_perspective_rh(fovy: N, aspect: N, near: N) -> TMat4 { -// unimplemented!() -//} +//}ç // //pub fn infinite_ortho(left: N, right: N, bottom: N, top: N) -> TMat4 { // unimplemented!() @@ -691,10 +687,172 @@ pub fn perspective_zo(aspect: N, fovy: N, near: N, far: N) -> TMat perspective_rh_zo(aspect, fovy, near, far) } +/// Build infinite right-handed perspective projection matrix with [-1,1] depth range. +/// +/// # Parameters +/// +/// * `fovy` - Field of view, in radians +/// * `aspect` - Ratio of viewport width to height (width/height) +/// * `near` - Distance from the viewer to the near clipping plane. +/// +/// # Important note +/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. +pub fn infinite_perspective_rh_no(aspect: N, fovy: N, near: N) -> TMat4 { + let f = N::one() / (fovy * na::convert(0.5)).tan(); + let mut mat = TMat4::zeros(); + + mat[(0, 0)] = f / aspect; + mat[(1, 1)] = f; + mat[(2, 2)] = -N::one(); + mat[(2, 3)] = -near * na::convert(2.0); + mat[(3, 2)] = -N::one(); + + mat +} + +/// Build infinite right-handed perspective projection matrix with [0,1] depth range. +/// +/// # Parameters +/// +/// * `fovy` - Field of view, in radians +/// * `aspect` - Ratio of viewport width to height (width/height) +/// * `near` - Distance from the viewer to the near clipping plane. +/// +/// # Important note +/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. +pub fn infinite_perspective_rh_zo(aspect: N, fovy: N, near: N) -> TMat4 { + let f = N::one() / (fovy * na::convert(0.5)).tan(); + let mut mat = TMat4::zeros(); + + mat[(0, 0)] = f / aspect; + mat[(1, 1)] = f; + mat[(2, 2)] = -N::one(); + mat[(2, 3)] = -near; + mat[(3, 2)] = -N::one(); + + mat +} + +/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1 +/// +/// # Parameters +/// +/// * `fovy` - Field of view, in radians +/// * `aspect` - Ratio of viewport width to height (width/height) +/// * `near` - Distance from the viewer to the near clipping plane +/// * `far` - Distance from the viewer to the far clipping plane +/// +/// # Important note +/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. +pub fn reversed_perspective_rh_no(aspect: N, fovy: N, near: N, far: N) -> TMat4 { + assert!( + !relative_eq!(far - near, N::zero()), + "The near-plane and far-plane must not be superimposed." + ); + assert!( + !relative_eq!(aspect, N::zero()), + "The apsect ratio must not be zero." + ); + + let one = N::one(); + let two: N = crate::convert(2.0); + let mut mat = TMat4::zeros(); + + let tan_half_fovy = (fovy / two).tan(); + + mat[(0, 0)] = one / (aspect * tan_half_fovy); + mat[(1, 1)] = one / tan_half_fovy; + mat[(2, 2)] = (far + near) / (far - near) - one; + mat[(2, 3)] = (two * far * near) / (far - near); + mat[(3, 2)] = -one; + + mat +} + +/// Creates a matrix for a right hand perspective-view frustum with a reversed depth range of 0 to 1 +/// +/// # Parameters +/// +/// * `fovy` - Field of view, in radians +/// * `aspect` - Ratio of viewport width to height (width/height) +/// * `near` - Distance from the viewer to the near clipping plane +/// * `far` - Distance from the viewer to the far clipping plane +/// +/// # Important note +/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. +pub fn reversed_perspective_rh_zo(aspect: N, fovy: N, near: N, far: N) -> TMat4 { + assert!( + !relative_eq!(far - near, N::zero()), + "The near-plane and far-plane must not be superimposed." + ); + assert!( + !relative_eq!(aspect, N::zero()), + "The apsect ratio must not be zero." + ); + + let one = N::one(); + let two = crate::convert(2.0); + let mut mat = TMat4::zeros(); + + let tan_half_fovy = (fovy / two).tan(); + + mat[(0, 0)] = one / (aspect * tan_half_fovy); + mat[(1, 1)] = one / tan_half_fovy; + mat[(2, 2)] = -far / (near - far) - one; + mat[(2, 3)] = (far * near) / (far - near); + mat[(3, 2)] = -one; + + mat +} + +/// Build reverted infinite perspective projection matrix with [-1, 1] depth range. +/// +/// # Parameters +/// +/// * `fovy` - Field of view, in radians +/// * `aspect` - Ratio of viewport width to height (width/height) +/// * `near` - Distance from the viewer to the near clipping plane +/// +/// # Important note +/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. +pub fn reversed_infinite_perspective_rh_no(aspect: N, fovy: N, near: N) -> TMat4 { + let f = N::one() / (fovy * na::convert(0.5)).tan(); + let mut mat = TMat4::zeros(); + + mat[(0, 0)] = f / aspect; + mat[(1, 1)] = f; + mat[(2, 3)] = two * near; + mat[(3, 2)] = -N::one(); + + mat +} + +/// Build reverted infinite perspective projection matrix with [0, 1] depth range. +/// +/// # Parameters +/// +/// * `fovy` - Field of view, in radians +/// * `aspect` - Ratio of viewport width to height (width/height) +/// * `near` - Distance from the viewer to the near clipping plane. +/// +/// # Important note +/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. +pub fn reversed_infinite_perspective_rh_zo(aspect: N, fovy: N, near: N) -> TMat4 { + let f = N::one() / (fovy * na::convert(0.5)).tan(); + let mut mat = TMat4::zeros(); + + mat[(0, 0)] = f / aspect; + mat[(1, 1)] = f; + mat[(2, 3)] = near; + mat[(3, 2)] = -N::one(); + + mat +} + //pub fn tweaked_infinite_perspective(fovy: N, aspect: N, near: N) -> TMat4 { // unimplemented!() //} // //pub fn tweaked_infinite_perspective_ep(fovy: N, aspect: N, near: N, ep: N) -> TMat4 { // unimplemented!() -//} +//} \ No newline at end of file From 9c3cea1d32ad8249c168edb91a9fc6987fe66ee4 Mon Sep 17 00:00:00 2001 From: sebcrozet Date: Tue, 2 Apr 2019 19:56:56 +0200 Subject: [PATCH 07/30] Add more comments. --- nalgebra-glm/src/ext/matrix_clip_space.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/nalgebra-glm/src/ext/matrix_clip_space.rs b/nalgebra-glm/src/ext/matrix_clip_space.rs index ec4f3b95..74f32e07 100644 --- a/nalgebra-glm/src/ext/matrix_clip_space.rs +++ b/nalgebra-glm/src/ext/matrix_clip_space.rs @@ -720,6 +720,8 @@ pub fn infinite_perspective_rh_no(aspect: N, fovy: N, near: N) -> /// /// # Important note /// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. +/// +// https://discourse.nphysics.org/t/reversed-z-and-infinite-zfar-in-projections/341/2 pub fn infinite_perspective_rh_zo(aspect: N, fovy: N, near: N) -> TMat4 { let f = N::one() / (fovy * na::convert(0.5)).tan(); let mut mat = TMat4::zeros(); @@ -733,7 +735,9 @@ pub fn infinite_perspective_rh_zo(aspect: N, fovy: N, near: N) -> mat } -/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1 +/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1. +/// +/// Note that when using reversed perspective, it is best to use a depth buffer based on floating points. /// /// # Parameters /// @@ -769,7 +773,9 @@ pub fn reversed_perspective_rh_no(aspect: N, fovy: N, near: N, far mat } -/// Creates a matrix for a right hand perspective-view frustum with a reversed depth range of 0 to 1 +/// Creates a matrix for a right hand perspective-view frustum with a reversed depth range of 0 to 1. +/// +/// Note that when using reversed perspective, it is best to use a depth buffer based on floating points. /// /// # Parameters /// @@ -807,6 +813,8 @@ pub fn reversed_perspective_rh_zo(aspect: N, fovy: N, near: N, far /// Build reverted infinite perspective projection matrix with [-1, 1] depth range. /// +/// Note that when using reversed perspective, it is best to use a depth buffer based on floating points. +/// /// # Parameters /// /// * `fovy` - Field of view, in radians @@ -829,6 +837,8 @@ pub fn reversed_infinite_perspective_rh_no(aspect: N, fovy: N, nea /// Build reverted infinite perspective projection matrix with [0, 1] depth range. /// +/// Note that when using reversed perspective, it is best to use a depth buffer based on floating points. +/// /// # Parameters /// /// * `fovy` - Field of view, in radians @@ -837,6 +847,7 @@ pub fn reversed_infinite_perspective_rh_no(aspect: N, fovy: N, nea /// /// # Important note /// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. +// Credit: https://discourse.nphysics.org/t/reversed-z-and-infinite-zfar-in-projections/341/2 pub fn reversed_infinite_perspective_rh_zo(aspect: N, fovy: N, near: N) -> TMat4 { let f = N::one() / (fovy * na::convert(0.5)).tan(); let mut mat = TMat4::zeros(); From 68d8331c2a94f34cd7fec65e43900e0e82ec5f5f Mon Sep 17 00:00:00 2001 From: sebcrozet Date: Tue, 2 Apr 2019 19:59:22 +0200 Subject: [PATCH 08/30] Fix typos. --- nalgebra-glm/src/ext/matrix_clip_space.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nalgebra-glm/src/ext/matrix_clip_space.rs b/nalgebra-glm/src/ext/matrix_clip_space.rs index 74f32e07..97c199ed 100644 --- a/nalgebra-glm/src/ext/matrix_clip_space.rs +++ b/nalgebra-glm/src/ext/matrix_clip_space.rs @@ -43,7 +43,7 @@ use na::{RealField}; // //pub fn infinite_perspective_lh(fovy: N, aspect: N, near: N) -> TMat4 { // unimplemented!() -//}ç +//} // //pub fn infinite_ortho(left: N, right: N, bottom: N, top: N) -> TMat4 { // unimplemented!() @@ -735,7 +735,7 @@ pub fn infinite_perspective_rh_zo(aspect: N, fovy: N, near: N) -> mat } -/// Creates a matrix for a right hand perspective-view frustum with a depth range of -1 to 1. +/// Creates a matrix for a right hand perspective-view frustum with a reversed depth range of -1 to 1. /// /// Note that when using reversed perspective, it is best to use a depth buffer based on floating points. /// @@ -811,7 +811,7 @@ pub fn reversed_perspective_rh_zo(aspect: N, fovy: N, near: N, far mat } -/// Build reverted infinite perspective projection matrix with [-1, 1] depth range. +/// Build an infinite perspective projection matrix with a reversed [-1, 1] depth range. /// /// Note that when using reversed perspective, it is best to use a depth buffer based on floating points. /// @@ -835,7 +835,7 @@ pub fn reversed_infinite_perspective_rh_no(aspect: N, fovy: N, nea mat } -/// Build reverted infinite perspective projection matrix with [0, 1] depth range. +/// Build an infinite perspective projection matrix with a reversed [0, 1] depth range. /// /// Note that when using reversed perspective, it is best to use a depth buffer based on floating points. /// From 94908cf2ad451e797e0e73e0a50fa6d14b771306 Mon Sep 17 00:00:00 2001 From: sebcrozet Date: Tue, 2 Apr 2019 20:01:16 +0200 Subject: [PATCH 09/30] Remove some assertions. --- nalgebra-glm/src/ext/matrix_clip_space.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/nalgebra-glm/src/ext/matrix_clip_space.rs b/nalgebra-glm/src/ext/matrix_clip_space.rs index 97c199ed..17b95b6f 100644 --- a/nalgebra-glm/src/ext/matrix_clip_space.rs +++ b/nalgebra-glm/src/ext/matrix_clip_space.rs @@ -749,15 +749,6 @@ pub fn infinite_perspective_rh_zo(aspect: N, fovy: N, near: N) -> /// # Important note /// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. pub fn reversed_perspective_rh_no(aspect: N, fovy: N, near: N, far: N) -> TMat4 { - assert!( - !relative_eq!(far - near, N::zero()), - "The near-plane and far-plane must not be superimposed." - ); - assert!( - !relative_eq!(aspect, N::zero()), - "The apsect ratio must not be zero." - ); - let one = N::one(); let two: N = crate::convert(2.0); let mut mat = TMat4::zeros(); @@ -787,15 +778,6 @@ pub fn reversed_perspective_rh_no(aspect: N, fovy: N, near: N, far /// # Important note /// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. pub fn reversed_perspective_rh_zo(aspect: N, fovy: N, near: N, far: N) -> TMat4 { - assert!( - !relative_eq!(far - near, N::zero()), - "The near-plane and far-plane must not be superimposed." - ); - assert!( - !relative_eq!(aspect, N::zero()), - "The apsect ratio must not be zero." - ); - let one = N::one(); let two = crate::convert(2.0); let mut mat = TMat4::zeros(); From ba93e0a7740d5103989ef4c1bdcbe8a29a90aba7 Mon Sep 17 00:00:00 2001 From: sebcrozet Date: Tue, 2 Apr 2019 20:04:44 +0200 Subject: [PATCH 10/30] Fix missing identifier. --- nalgebra-glm/src/ext/matrix_clip_space.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nalgebra-glm/src/ext/matrix_clip_space.rs b/nalgebra-glm/src/ext/matrix_clip_space.rs index 17b95b6f..d7ab44db 100644 --- a/nalgebra-glm/src/ext/matrix_clip_space.rs +++ b/nalgebra-glm/src/ext/matrix_clip_space.rs @@ -811,7 +811,7 @@ pub fn reversed_infinite_perspective_rh_no(aspect: N, fovy: N, nea mat[(0, 0)] = f / aspect; mat[(1, 1)] = f; - mat[(2, 3)] = two * near; + mat[(2, 3)] = near * crate::convert(2.0); mat[(3, 2)] = -N::one(); mat From f03c785a60a3416f8218cd11ea16ff3b1e29584d Mon Sep 17 00:00:00 2001 From: sebcrozet Date: Sat, 6 Apr 2019 09:41:19 +0200 Subject: [PATCH 11/30] Remove comments about float depth buffer. --- nalgebra-glm/src/ext/matrix_clip_space.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/nalgebra-glm/src/ext/matrix_clip_space.rs b/nalgebra-glm/src/ext/matrix_clip_space.rs index d7ab44db..68a1b1e4 100644 --- a/nalgebra-glm/src/ext/matrix_clip_space.rs +++ b/nalgebra-glm/src/ext/matrix_clip_space.rs @@ -737,8 +737,6 @@ pub fn infinite_perspective_rh_zo(aspect: N, fovy: N, near: N) -> /// Creates a matrix for a right hand perspective-view frustum with a reversed depth range of -1 to 1. /// -/// Note that when using reversed perspective, it is best to use a depth buffer based on floating points. -/// /// # Parameters /// /// * `fovy` - Field of view, in radians @@ -766,8 +764,6 @@ pub fn reversed_perspective_rh_no(aspect: N, fovy: N, near: N, far /// Creates a matrix for a right hand perspective-view frustum with a reversed depth range of 0 to 1. /// -/// Note that when using reversed perspective, it is best to use a depth buffer based on floating points. -/// /// # Parameters /// /// * `fovy` - Field of view, in radians @@ -795,8 +791,6 @@ pub fn reversed_perspective_rh_zo(aspect: N, fovy: N, near: N, far /// Build an infinite perspective projection matrix with a reversed [-1, 1] depth range. /// -/// Note that when using reversed perspective, it is best to use a depth buffer based on floating points. -/// /// # Parameters /// /// * `fovy` - Field of view, in radians @@ -819,8 +813,6 @@ pub fn reversed_infinite_perspective_rh_no(aspect: N, fovy: N, nea /// Build an infinite perspective projection matrix with a reversed [0, 1] depth range. /// -/// Note that when using reversed perspective, it is best to use a depth buffer based on floating points. -/// /// # Parameters /// /// * `fovy` - Field of view, in radians From 6b67687e1c1f37fc2dbe1a10f2e46698f273538f Mon Sep 17 00:00:00 2001 From: sebcrozet Date: Sat, 6 Apr 2019 09:43:07 +0200 Subject: [PATCH 12/30] Remove the _no variants of reversed perspective. --- nalgebra-glm/src/ext/matrix_clip_space.rs | 51 +---------------------- 1 file changed, 2 insertions(+), 49 deletions(-) diff --git a/nalgebra-glm/src/ext/matrix_clip_space.rs b/nalgebra-glm/src/ext/matrix_clip_space.rs index 68a1b1e4..93558206 100644 --- a/nalgebra-glm/src/ext/matrix_clip_space.rs +++ b/nalgebra-glm/src/ext/matrix_clip_space.rs @@ -735,33 +735,6 @@ pub fn infinite_perspective_rh_zo(aspect: N, fovy: N, near: N) -> mat } -/// Creates a matrix for a right hand perspective-view frustum with a reversed depth range of -1 to 1. -/// -/// # Parameters -/// -/// * `fovy` - Field of view, in radians -/// * `aspect` - Ratio of viewport width to height (width/height) -/// * `near` - Distance from the viewer to the near clipping plane -/// * `far` - Distance from the viewer to the far clipping plane -/// -/// # Important note -/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. -pub fn reversed_perspective_rh_no(aspect: N, fovy: N, near: N, far: N) -> TMat4 { - let one = N::one(); - let two: N = crate::convert(2.0); - let mut mat = TMat4::zeros(); - - let tan_half_fovy = (fovy / two).tan(); - - mat[(0, 0)] = one / (aspect * tan_half_fovy); - mat[(1, 1)] = one / tan_half_fovy; - mat[(2, 2)] = (far + near) / (far - near) - one; - mat[(2, 3)] = (two * far * near) / (far - near); - mat[(3, 2)] = -one; - - mat -} - /// Creates a matrix for a right hand perspective-view frustum with a reversed depth range of 0 to 1. /// /// # Parameters @@ -773,6 +746,7 @@ pub fn reversed_perspective_rh_no(aspect: N, fovy: N, near: N, far /// /// # Important note /// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. +// NOTE: The variants `_no` of reversed perspective are not useful. pub fn reversed_perspective_rh_zo(aspect: N, fovy: N, near: N, far: N) -> TMat4 { let one = N::one(); let two = crate::convert(2.0); @@ -789,28 +763,6 @@ pub fn reversed_perspective_rh_zo(aspect: N, fovy: N, near: N, far mat } -/// Build an infinite perspective projection matrix with a reversed [-1, 1] depth range. -/// -/// # Parameters -/// -/// * `fovy` - Field of view, in radians -/// * `aspect` - Ratio of viewport width to height (width/height) -/// * `near` - Distance from the viewer to the near clipping plane -/// -/// # Important note -/// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. -pub fn reversed_infinite_perspective_rh_no(aspect: N, fovy: N, near: N) -> TMat4 { - let f = N::one() / (fovy * na::convert(0.5)).tan(); - let mut mat = TMat4::zeros(); - - mat[(0, 0)] = f / aspect; - mat[(1, 1)] = f; - mat[(2, 3)] = near * crate::convert(2.0); - mat[(3, 2)] = -N::one(); - - mat -} - /// Build an infinite perspective projection matrix with a reversed [0, 1] depth range. /// /// # Parameters @@ -822,6 +774,7 @@ pub fn reversed_infinite_perspective_rh_no(aspect: N, fovy: N, nea /// # Important note /// The `aspect` and `fovy` argument are interchanged compared to the original GLM API. // Credit: https://discourse.nphysics.org/t/reversed-z-and-infinite-zfar-in-projections/341/2 +// NOTE: The variants `_no` of reversed perspective are not useful. pub fn reversed_infinite_perspective_rh_zo(aspect: N, fovy: N, near: N) -> TMat4 { let f = N::one() / (fovy * na::convert(0.5)).tan(); let mut mat = TMat4::zeros(); From 049957ff554d3365242542bf35438477930e9672 Mon Sep 17 00:00:00 2001 From: sebcrozet Date: Tue, 9 Apr 2019 20:25:42 +0200 Subject: [PATCH 13/30] Reorder comments about parameters of projection so they match the order of the function parameter. --- nalgebra-glm/src/ext/matrix_clip_space.rs | 26 +++++++++++------------ 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/nalgebra-glm/src/ext/matrix_clip_space.rs b/nalgebra-glm/src/ext/matrix_clip_space.rs index 93558206..6b279024 100644 --- a/nalgebra-glm/src/ext/matrix_clip_space.rs +++ b/nalgebra-glm/src/ext/matrix_clip_space.rs @@ -456,8 +456,8 @@ pub fn perspective_fov_zo(fov: N, width: N, height: N, near: N, fa /// /// # Parameters /// -/// * `fovy` - Field of view, in radians /// * `aspect` - Ratio of viewport width to height (width/height) +/// * `fovy` - Field of view, in radians /// * `near` - Distance from the viewer to the near clipping plane /// * `far` - Distance from the viewer to the far clipping plane /// @@ -485,8 +485,8 @@ pub fn perspective(aspect: N, fovy: N, near: N, far: N) -> TMat4(aspect: N, fovy: N, near: N, far: N) -> TMat /// /// # Parameters /// -/// * `fovy` - Field of view, in radians /// * `aspect` - Ratio of viewport width to height (width/height) +/// * `fovy` - Field of view, in radians /// * `near` - Distance from the viewer to the near clipping plane /// * `far` - Distance from the viewer to the far clipping plane /// @@ -536,8 +536,8 @@ pub fn perspective_lh_no(aspect: N, fovy: N, near: N, far: N) -> T /// /// # Parameters /// -/// * `fovy` - Field of view, in radians /// * `aspect` - Ratio of viewport width to height (width/height) +/// * `fovy` - Field of view, in radians /// * `near` - Distance from the viewer to the near clipping plane /// * `far` - Distance from the viewer to the far clipping plane /// @@ -572,8 +572,8 @@ pub fn perspective_lh_zo(aspect: N, fovy: N, near: N, far: N) -> T /// /// # Parameters /// -/// * `fovy` - Field of view, in radians /// * `aspect` - Ratio of viewport width to height (width/height) +/// * `fovy` - Field of view, in radians /// * `near` - Distance from the viewer to the near clipping plane /// * `far` - Distance from the viewer to the far clipping plane /// @@ -587,8 +587,8 @@ pub fn perspective_no(aspect: N, fovy: N, near: N, far: N) -> TMat /// /// # Parameters /// -/// * `fovy` - Field of view, in radians /// * `aspect` - Ratio of viewport width to height (width/height) +/// * `fovy` - Field of view, in radians /// * `near` - Distance from the viewer to the near clipping plane /// * `far` - Distance from the viewer to the far clipping plane /// @@ -602,8 +602,8 @@ pub fn perspective_rh(aspect: N, fovy: N, near: N, far: N) -> TMat /// /// # Parameters /// -/// * `fovy` - Field of view, in radians /// * `aspect` - Ratio of viewport width to height (width/height) +/// * `fovy` - Field of view, in radians /// * `near` - Distance from the viewer to the near clipping plane /// * `far` - Distance from the viewer to the far clipping plane /// @@ -639,8 +639,8 @@ pub fn perspective_rh_no(aspect: N, fovy: N, near: N, far: N) -> T /// /// # Parameters /// -/// * `fovy` - Field of view, in radians /// * `aspect` - Ratio of viewport width to height (width/height) +/// * `fovy` - Field of view, in radians /// * `near` - Distance from the viewer to the near clipping plane /// * `far` - Distance from the viewer to the far clipping plane /// @@ -676,8 +676,8 @@ pub fn perspective_rh_zo(aspect: N, fovy: N, near: N, far: N) -> T /// /// # Parameters /// -/// * `fovy` - Field of view, in radians /// * `aspect` - Ratio of viewport width to height (width/height) +/// * `fovy` - Field of view, in radians /// * `near` - Distance from the viewer to the near clipping plane /// * `far` - Distance from the viewer to the far clipping plane /// @@ -691,8 +691,8 @@ pub fn perspective_zo(aspect: N, fovy: N, near: N, far: N) -> TMat /// /// # Parameters /// -/// * `fovy` - Field of view, in radians /// * `aspect` - Ratio of viewport width to height (width/height) +/// * `fovy` - Field of view, in radians /// * `near` - Distance from the viewer to the near clipping plane. /// /// # Important note @@ -714,8 +714,8 @@ pub fn infinite_perspective_rh_no(aspect: N, fovy: N, near: N) -> /// /// # Parameters /// -/// * `fovy` - Field of view, in radians /// * `aspect` - Ratio of viewport width to height (width/height) +/// * `fovy` - Field of view, in radians /// * `near` - Distance from the viewer to the near clipping plane. /// /// # Important note @@ -739,8 +739,8 @@ pub fn infinite_perspective_rh_zo(aspect: N, fovy: N, near: N) -> /// /// # Parameters /// -/// * `fovy` - Field of view, in radians /// * `aspect` - Ratio of viewport width to height (width/height) +/// * `fovy` - Field of view, in radians /// * `near` - Distance from the viewer to the near clipping plane /// * `far` - Distance from the viewer to the far clipping plane /// @@ -767,8 +767,8 @@ pub fn reversed_perspective_rh_zo(aspect: N, fovy: N, near: N, far /// /// # Parameters /// -/// * `fovy` - Field of view, in radians /// * `aspect` - Ratio of viewport width to height (width/height) +/// * `fovy` - Field of view, in radians /// * `near` - Distance from the viewer to the near clipping plane. /// /// # Important note From 306f096c64caf1a6ba6439311367c96c92934d42 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Tue, 9 Apr 2019 14:39:36 -0400 Subject: [PATCH 14/30] prevent constructing `MatrixSliceMutMN` for which disjoint indices may alias the same linear index Fixes #486. --- Cargo.toml | 1 + src/base/construction_slice.rs | 32 ++++++++++++++++++++++++++++++++ src/lib.rs | 1 + 3 files changed, 34 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 120d2916..4371df05 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,7 @@ generic-array = "0.12" rand = { version = "0.6", default-features = false } num-traits = { version = "0.2", default-features = false } num-complex = { version = "0.2", default-features = false } +num-rational = { version = "0.2", default-features = false } approx = { version = "0.3", default-features = false } alga = { version = "0.9", default-features = false } matrixmultiply = { version = "0.2", optional = true } diff --git a/src/base/construction_slice.rs b/src/base/construction_slice.rs index 0946653a..e5f311f8 100644 --- a/src/base/construction_slice.rs +++ b/src/base/construction_slice.rs @@ -2,6 +2,7 @@ use crate::base::dimension::{Dim, DimName, Dynamic, U1}; use crate::base::matrix_slice::{SliceStorage, SliceStorageMut}; use crate::base::{MatrixSliceMN, MatrixSliceMutMN, Scalar}; +use num_rational::Ratio; /* * * Slice constructors. @@ -107,6 +108,37 @@ impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> "Matrix slice: input data buffer to small." ); + assert!({ + let nrows = nrows.value(); + let ncols = ncols.value(); + let rstride = rstride.value(); + let cstride = cstride.value(); + + // `Storage::linear_index` + let index = |i, j| (i * rstride) + (j * cstride); + + // The final condition of each arm is an expression in the form: + // index(i₀, j₀) != index(i₁, j₁) + // If this expression is `false`, then the values (i₀, j₀) + // and (i₁, j₁) are concrete examples of indices that would + // collide if the matrix was actually constructed. + nrows * ncols <= 1 || + match (rstride, cstride) { + (0, 0) => index(0, 0) != index(nrows - 1, ncols - 1), + (0, _) => nrows <= 1 || index(0, 0) != index(nrows - 1, 0), + (_, 0) => ncols <= 1 || index(0, 0) != index(0, ncols - 1), + (_, _) => { + let ratio = Ratio::new(rstride, cstride); + let numer = *ratio.numer(); + let denom = *ratio.denom(); + + nrows <= denom || ncols <= numer + || index(0, numer) != index(denom, 0) + } + } + }, + "Matrix slice: dimensions and strides result in aliased indices."); + unsafe { Self::from_slice_with_strides_generic_unchecked(data, 0, nrows, ncols, rstride, cstride) } diff --git a/src/lib.rs b/src/lib.rs index 1cab3da8..2c649f63 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -112,6 +112,7 @@ extern crate generic_array; extern crate matrixmultiply; extern crate num_complex; extern crate num_traits as num; +extern crate num_rational; extern crate rand; extern crate typenum; From 05eb9ac2ba4bb6bbc7429f0602ea9b41f4f80385 Mon Sep 17 00:00:00 2001 From: Jack Wrenn Date: Mon, 15 Apr 2019 17:54:10 -0400 Subject: [PATCH 15/30] simplify anti-aliasing assertion --- src/base/construction_slice.rs | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/src/base/construction_slice.rs b/src/base/construction_slice.rs index e5f311f8..4f745a65 100644 --- a/src/base/construction_slice.rs +++ b/src/base/construction_slice.rs @@ -114,26 +114,14 @@ impl<'a, N: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> let rstride = rstride.value(); let cstride = cstride.value(); - // `Storage::linear_index` - let index = |i, j| (i * rstride) + (j * cstride); - - // The final condition of each arm is an expression in the form: - // index(i₀, j₀) != index(i₁, j₁) - // If this expression is `false`, then the values (i₀, j₀) - // and (i₁, j₁) are concrete examples of indices that would - // collide if the matrix was actually constructed. nrows * ncols <= 1 || match (rstride, cstride) { - (0, 0) => index(0, 0) != index(nrows - 1, ncols - 1), - (0, _) => nrows <= 1 || index(0, 0) != index(nrows - 1, 0), - (_, 0) => ncols <= 1 || index(0, 0) != index(0, ncols - 1), - (_, _) => { + (0, 0) => false, // otherwise: matrix[(0, 0)] == index[(nrows - 1, ncols - 1)], + (0, _) => nrows <= 1, // otherwise: matrix[(0, 0)] == index[(nrows - 1, 0)], + (_, 0) => ncols <= 1, // otherwise: matrix[(0, 0)] == index[(0, ncols - 1)], + (_, _) => { // otherwise: matrix[(0, numer)] == index[(denom, 0)] let ratio = Ratio::new(rstride, cstride); - let numer = *ratio.numer(); - let denom = *ratio.denom(); - - nrows <= denom || ncols <= numer - || index(0, numer) != index(denom, 0) + nrows <= *ratio.denom() || ncols <= *ratio.numer() } } }, From 65e4c591521d7e49f4ba2a7e13d9accfcfe2aab7 Mon Sep 17 00:00:00 2001 From: Las Date: Wed, 17 Apr 2019 18:31:13 +0200 Subject: [PATCH 16/30] Fix incorrect documentation from `s/Real/&Field` --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2c649f63..21792c97 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,8 +4,8 @@ **nalgebra** is a linear algebra library written for Rust targeting: * General-purpose linear algebra (still lacks a lot of features…) -* RealField time computer graphics. -* RealField time computer physics. +* 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) From fb95634d8c4693732e525efe79a1fe1ab004d19f Mon Sep 17 00:00:00 2001 From: Felipe Jorge Date: Fri, 26 Apr 2019 14:38:03 -0300 Subject: [PATCH 17/30] Fix for nostd builds (#589) --- nalgebra-glm/src/common.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nalgebra-glm/src/common.rs b/nalgebra-glm/src/common.rs index c9f9c265..eda9f295 100644 --- a/nalgebra-glm/src/common.rs +++ b/nalgebra-glm/src/common.rs @@ -1,6 +1,6 @@ use na::{self, DefaultAllocator, RealField}; use num::FromPrimitive; -use std::mem; +use core::mem; use crate::aliases::{TMat, TVec}; use crate::traits::{Alloc, Dimension, Number}; From cce690f3a96e5d136d701541b18f35f65f266c05 Mon Sep 17 00:00:00 2001 From: Bruce Mitchener Date: Fri, 7 Jun 2019 23:54:56 +0700 Subject: [PATCH 18/30] Fix typo. (#600) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4371df05..08e14057 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,7 +56,7 @@ pest_derive = { version = "2.0", optional = true } serde_json = "1.0" rand_xorshift = "0.1" ### Uncomment this line before running benchmarks. -### We can't just let this uncommented because that would breack +### We can't just let this uncommented because that would break ### compilation for #[no-std] because of the terrible Cargo bug ### https://github.com/rust-lang/cargo/issues/4866 #criterion = "0.2.10" From 0384268bd4c757b5b0125d63bb0599695b961c48 Mon Sep 17 00:00:00 2001 From: Jake Shadle Date: Tue, 11 Jun 2019 20:56:50 +0200 Subject: [PATCH 19/30] HTTPS All The Things (#608) * Use https for all links where it is valid * Fix random links to external sites --- CHANGELOG.md | 12 ++++++------ Cargo.toml | 4 ++-- README.md | 6 +++--- nalgebra-glm/src/lib.rs | 4 ++-- nalgebra-lapack/Cargo.toml | 4 ++-- nalgebra-lapack/README.md | 2 +- nalgebra-lapack/src/lib.rs | 6 +++--- src/base/blas.rs | 2 +- src/geometry/quaternion_construction.rs | 2 +- src/geometry/rotation_specialization.rs | 2 +- src/lib.rs | 6 +++--- 11 files changed, 25 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 36aea56e..9e22820c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ All notable changes to `nalgebra`, starting with the version 0.6.0 will be documented here. -This project adheres to [Semantic Versioning](http://semver.org/). +This project adheres to [Semantic Versioning](https://semver.org/). ## [0.18.0] This release adds full complex number support to nalgebra. This includes all common vector/matrix operations as well @@ -111,7 +111,7 @@ All dependencies have been updated to their latest versions. ## [0.15.0] The most notable change of this release is the support for using part of the library without the rust standard -library (i.e. it supports `#![no_std]`). See the corresponding [documentation](http://nalgebra.org/wasm_and_embedded_programming/). +library (i.e. it supports `#![no_std]`). See the corresponding [documentation](https://nalgebra.org/wasm_and_embedded_programming/). ### Modified * Rename the `core` module to `base` to avoid conflicts with the `core` crate implicitly imported when `#![no_std]` is enabled. @@ -276,7 +276,7 @@ The main change of this release is the update of the dependency serde to 1.0. elements.) ## [0.11.0] -The [website](http://nalgebra.org) has been fully rewritten and gives a good +The [website](https://nalgebra.org) has been fully rewritten and gives a good overview of all the added/modified features. This version is a major rewrite of the library. Major changes are: @@ -298,9 +298,9 @@ This version is a major rewrite of the library. Major changes are: ### Added Lots of features including rectangular matrices, slices, and Serde -serialization. Refer to the brand new [website](http://nalgebra.org) for more +serialization. Refer to the brand new [website](https://nalgebra.org) for more details. The following free-functions have been added as well: - * `::id()` that returns the universal [identity element](http://nalgebra.org/performance_tricks/#the-id-type) + * `::id()` that returns the universal [identity element](https://nalgebra.org/performance_tricks/#the-id-type) of type `Id`. * `::inf_sup()` that returns both the infimum and supremum of a value at the same time. @@ -459,7 +459,7 @@ crate for vectors, rotations and points. To enable them, activate the ## [0.6.0] **Announcement:** a users forum has been created for `nalgebra`, `ncollide`, and `nphysics`. See -you [there](http://users.nphysics.org)! +you [there](https://users.nphysics.org)! ### Added * Added a dependency to [generic-array](https://crates.io/crates/generic-array). Feature-gated: diff --git a/Cargo.toml b/Cargo.toml index 08e14057..fd9ad6e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,8 +4,8 @@ version = "0.18.0" authors = [ "Sébastien Crozet " ] description = "Linear algebra library with transformations and statically-sized or dynamically-sized matrices." -documentation = "http://nalgebra.org/rustdoc/nalgebra/index.html" -homepage = "http://nalgebra.org" +documentation = "https://nalgebra.org/rustdoc/nalgebra/index.html" +homepage = "https://nalgebra.org" repository = "https://github.com/rustsim/nalgebra" readme = "README.md" categories = [ "science" ] diff --git a/README.md b/README.md index 17a312be..df3a82f3 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@

- crates.io + crates.io

@@ -9,7 +9,7 @@ Build status - crates.io + crates.io @@ -17,7 +17,7 @@

- Users guide | Documentation | Forum + Users guide | Documentation | Forum

diff --git a/nalgebra-glm/src/lib.rs b/nalgebra-glm/src/lib.rs index 66502e73..1414bf6a 100644 --- a/nalgebra-glm/src/lib.rs +++ b/nalgebra-glm/src/lib.rs @@ -7,7 +7,7 @@ seamless inter-operability between both. ## Getting started - First of all, you should start by taking a look at the official [GLM API documentation](http://glm.g-truc.net/0.9.9/api/index.html) + First of all, you should start by taking a look at the official [GLM API documentation](https://glm.g-truc.net/0.9.9/api/index.html) since **nalgebra-glm** implements a large subset of it. To use **nalgebra-glm** to your project, you should add it as a dependency to your `Crates.toml`: @@ -110,7 +110,7 @@ and keep in mind it is possible to convert, e.g., an `Isometry3` to a `Mat4` and vice-versa (see the [conversions section](#conversions)). */ -#![doc(html_favicon_url = "http://nalgebra.org/img/favicon.ico")] +#![doc(html_favicon_url = "https://nalgebra.org/img/favicon.ico")] #![cfg_attr(not(feature = "std"), no_std)] extern crate num_traits as num; diff --git a/nalgebra-lapack/Cargo.toml b/nalgebra-lapack/Cargo.toml index 759cef7e..9d392712 100644 --- a/nalgebra-lapack/Cargo.toml +++ b/nalgebra-lapack/Cargo.toml @@ -4,8 +4,8 @@ version = "0.10.0" authors = [ "Sébastien Crozet ", "Andrew Straw " ] description = "Linear algebra library with transformations and satically-sized or dynamically-sized matrices." -documentation = "http://nalgebra.org/doc/nalgebra/index.html" -homepage = "http://nalgebra.org" +documentation = "https://nalgebra.org/doc/nalgebra/index.html" +homepage = "https://nalgebra.org" repository = "https://github.com/rustsim/nalgebra" readme = "README.md" keywords = [ "linear", "algebra", "matrix", "vector" ] diff --git a/nalgebra-lapack/README.md b/nalgebra-lapack/README.md index 9f474f75..d6762758 100644 --- a/nalgebra-lapack/README.md +++ b/nalgebra-lapack/README.md @@ -14,7 +14,7 @@ MIT Like the [lapack crate](https://crates.io/crates/lapack) from which this behavior is inherited, nalgebra-lapack uses [cargo -features](http://doc.crates.io/manifest.html#the-[features]-section) to select +features](https://doc.crates.io/manifest.html#the-[features]-section) to select which lapack provider (or implementation) is used. Command line arguments to cargo are the easiest way to do this, and the best provider depends on your particular system. In some cases, the providers can be further tuned with diff --git a/nalgebra-lapack/src/lib.rs b/nalgebra-lapack/src/lib.rs index a1a7b7b7..d58aba0b 100644 --- a/nalgebra-lapack/src/lib.rs +++ b/nalgebra-lapack/src/lib.rs @@ -14,7 +14,7 @@ //! //! Like the [lapack crate](https://crates.io/crates/lapack) from which this //! behavior is inherited, nalgebra-lapack uses [cargo -//! features](http://doc.crates.io/manifest.html#the-[features]-section) to select +//! features](https://doc.crates.io/manifest.html#the-[features]-section) to select //! which lapack provider (or implementation) is used. Command line arguments to //! cargo are the easiest way to do this, and the best provider depends on your //! particular system. In some cases, the providers can be further tuned with @@ -69,8 +69,8 @@ #![deny(unused_results)] #![deny(missing_docs)] #![doc( - html_favicon_url = "http://nalgebra.org/img/favicon.ico", - html_root_url = "http://nalgebra.org/rustdoc" + html_favicon_url = "https://nalgebra.org/img/favicon.ico", + html_root_url = "https://nalgebra.org/rustdoc" )] extern crate alga; diff --git a/src/base/blas.rs b/src/base/blas.rs index 6e1b6c81..beb83c4b 100644 --- a/src/base/blas.rs +++ b/src/base/blas.rs @@ -311,7 +311,7 @@ where N: Scalar + Zero + ClosedAdd + ClosedMul } // All this is inspired from the "unrolled version" discussed in: - // http://blog.theincredibleholk.org/blog/2012/12/10/optimizing-dot-product/ + // https://blog.theincredibleholk.org/blog/2012/12/10/optimizing-dot-product/ // // And this comment from bluss: // https://users.rust-lang.org/t/how-to-zip-two-slices-efficiently/2048/12 diff --git a/src/geometry/quaternion_construction.rs b/src/geometry/quaternion_construction.rs index 7758b4c9..893fdb6a 100644 --- a/src/geometry/quaternion_construction.rs +++ b/src/geometry/quaternion_construction.rs @@ -256,7 +256,7 @@ impl UnitQuaternion { #[inline] pub fn from_rotation_matrix(rotmat: &Rotation3) -> Self { // Robust matrix to quaternion transformation. - // See http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion + // See https://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion let tr = rotmat[(0, 0)] + rotmat[(1, 1)] + rotmat[(2, 2)]; let res; diff --git a/src/geometry/rotation_specialization.rs b/src/geometry/rotation_specialization.rs index 973190a6..4baec27c 100644 --- a/src/geometry/rotation_specialization.rs +++ b/src/geometry/rotation_specialization.rs @@ -464,7 +464,7 @@ impl Rotation3 { /// ``` pub fn euler_angles(&self) -> (N, N, N) { // Implementation informed by "Computing Euler angles from a rotation matrix", by Gregory G. Slabaugh - // http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.371.6578 + // https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.371.6578 if self[(2, 0)].abs() < N::one() { let yaw = -self[(2, 0)].asin(); let roll = (self[(2, 1)] / yaw.cos()).atan2(self[(2, 2)] / yaw.cos()); diff --git a/src/lib.rs b/src/lib.rs index 21792c97..a92e2250 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ * Real-time computer physics. ## Using **nalgebra** -You will need the last stable build of the [rust compiler](http://www.rust-lang.org) +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: @@ -84,8 +84,8 @@ an optimized set of tools for computer graphics and physics. Those features incl #![deny(missing_docs)] #![warn(incoherent_fundamental_impls)] #![doc( - html_favicon_url = "http://nalgebra.org/img/favicon.ico", - html_root_url = "http://nalgebra.org/rustdoc" + html_favicon_url = "https://nalgebra.org/img/favicon.ico", + html_root_url = "https://nalgebra.org/rustdoc" )] #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(alloc))] From bedb5dc9637e09d04db97f2d10bc52544f3e2c7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Crozet?= Date: Tue, 13 Aug 2019 10:05:39 +0200 Subject: [PATCH 20/30] Fix CI (#634) --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3f6c3bcf..29de4010 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,8 +15,8 @@ addons: apt: packages: - gfortran - - libblas3gf - - liblapack3gf + - libblas-dev + - liblapack-dev script: - rustc --version - cargo --version From 0f0b9bcca113c8fc253676280c4cd85e8a4b0579 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20L=C3=B6schner?= Date: Sat, 10 Aug 2019 16:18:33 +0200 Subject: [PATCH 21/30] Fix for [a,ca]min/max methods. Panic on empty matrices, propagate NaN, fix of wrong results, added doc tests --- src/base/ops.rs | 136 +++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 118 insertions(+), 18 deletions(-) diff --git a/src/base/ops.rs b/src/base/ops.rs index cf921c33..30f6194e 100644 --- a/src/base/ops.rs +++ b/src/base/ops.rs @@ -1,5 +1,5 @@ use num::{One, Signed, Zero}; -use std::cmp::PartialOrd; +use std::cmp::{PartialOrd, Ordering}; use std::iter; use std::ops::{ Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign, @@ -868,60 +868,160 @@ where impl> Matrix { #[inline(always)] - fn xcmp(&self, abs: impl Fn(N) -> N2, cmp: impl Fn(N2, N2) -> bool) -> N2 + fn xcmp(&self, abs: impl Fn(N) -> N2, ordering: Ordering) -> N2 where N2: Scalar + PartialOrd + Zero { - let mut max = N2::zero(); + assert!(self.len() > 0, "Empty matrix supplied to min/max function."); + let mut iter = self.iter(); + let mut max = abs(iter.next().cloned().unwrap()); - for e in self.iter() { + for e in iter { let ae = abs(*e); - if cmp(ae, max) { - max = ae; + if let Some(ae_ordering) = ae.partial_cmp(&max) { + if ae_ordering == ordering { + max = ae; + } + } else { + return ae; } } max } - /// Returns the absolute value of the component with the largest absolute value. + /// Returns the absolute value of the component with the largest absolute value. Propagates NaN. + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// assert_eq!(Vector3::new(-1.0, 2.0, 3.0).amax(), 3.0); + /// assert_eq!(Vector3::new(-1.0, -2.0, -3.0).amax(), 3.0); + /// assert!(Vector3::new(1.0, std::f64::NAN, 3.0).amax().is_nan()); + /// ``` + /// + /// # Panics + /// Panics if the matrix is empty: + /// ```should_panic + /// # use nalgebra::DMatrix; + /// let min = DMatrix::::zeros(0,1).amax(); // panics! + /// ``` #[inline] pub fn amax(&self) -> N where N: PartialOrd + Signed { - self.xcmp(|e| e.abs(), |a, b| a > b) + self.xcmp(|e| e.abs(), Ordering::Greater) } - /// Returns the the 1-norm of the complex component with the largest 1-norm. + /// Returns the the 1-norm of the complex component with the largest 1-norm. Propagates NaN. + /// # Example + /// ``` + /// # use nalgebra::{Vector3, Complex}; + /// assert_eq!(Vector3::new( + /// Complex::new(-3.0, -2.0), + /// Complex::new(1.0, 2.0), + /// Complex::new(1.0, 3.0)).camax(), 5.0); + /// assert!(Vector3::new( + /// Complex::new(-3.0, -2.0), + /// Complex::new(1.0, std::f64::NAN), + /// Complex::new(1.0, 3.0)).camax().is_nan()); + /// ``` + /// + /// # Panics + /// Panics if the matrix is empty: + /// ```should_panic + /// # use nalgebra::{DMatrix, Complex}; + /// let min = DMatrix::>::zeros(0,1).camax(); // panics! + /// ``` #[inline] pub fn camax(&self) -> N::RealField where N: ComplexField { - self.xcmp(|e| e.norm1(), |a, b| a > b) + self.xcmp(|e| e.norm1(), Ordering::Greater) } - /// Returns the component with the largest value. + /// Returns the component with the largest value. Propagates NaN. + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// assert_eq!(Vector3::new(-1.0, 2.0, 3.0).max(), 3.0); + /// assert_eq!(Vector3::new(-1.0, -2.0, -3.0).max(), -1.0); + /// assert!(Vector3::new(1.0, std::f64::NAN, 3.0).max().is_nan()); + /// ``` + /// + /// # Panics + /// Panics if the matrix is empty: + /// ```should_panic + /// # use nalgebra::DMatrix; + /// let min = DMatrix::::zeros(0,1).max(); // panics! + /// ``` #[inline] pub fn max(&self) -> N where N: PartialOrd + Signed { - self.xcmp(|e| e, |a, b| a > b) + self.xcmp(|e| e, Ordering::Greater) } - /// Returns the absolute value of the component with the smallest absolute value. + /// Returns the absolute value of the component with the smallest absolute value. Propagates NaN. + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// assert_eq!(Vector3::new(-1.0, 2.0, -3.0).amin(), 1.0); + /// assert_eq!(Vector3::new(10.0, 2.0, 30.0).amin(), 2.0); + /// assert!(Vector3::new(-1.0, std::f64::NAN, 3.0).amin().is_nan()); + /// ``` + /// + /// # Panics + /// Panics if the matrix is empty: + /// ```should_panic + /// # use nalgebra::DMatrix; + /// let min = DMatrix::::zeros(0,1).amin(); // panics! + /// ``` #[inline] pub fn amin(&self) -> N where N: PartialOrd + Signed { - self.xcmp(|e| e.abs(), |a, b| a < b) + self.xcmp(|e| e.abs(), Ordering::Less) } - /// Returns the the 1-norm of the complex component with the smallest 1-norm. + /// Returns the the 1-norm of the complex component with the smallest 1-norm. Propagates NaN. + /// # Example + /// ``` + /// # use nalgebra::{Vector3, Complex}; + /// assert_eq!(Vector3::new( + /// Complex::new(-3.0, -2.0), + /// Complex::new(1.0, 2.0), + /// Complex::new(1.0, 3.0)).camin(), 3.0); + /// assert!(Vector3::new( + /// Complex::new(-3.0, -2.0), + /// Complex::new(1.0, std::f64::NAN), + /// Complex::new(1.0, 3.0)).camin().is_nan()); + /// ``` + /// + /// # Panics + /// Panics if the matrix is empty: + /// ```should_panic + /// # use nalgebra::{DMatrix, Complex}; + /// let min = DMatrix::>::zeros(0,1).camin(); // panics! + /// ``` #[inline] pub fn camin(&self) -> N::RealField where N: ComplexField { - self.xcmp(|e| e.norm1(), |a, b| a < b) + self.xcmp(|e| e.norm1(), Ordering::Less) } - /// Returns the component with the smallest value. + /// Returns the component with the smallest value. Propagates NaN. + /// # Example + /// ``` + /// # use nalgebra::Vector3; + /// assert_eq!(Vector3::new(-1.0, 2.0, 3.0).min(), -1.0); + /// assert_eq!(Vector3::new(1.0, 2.0, 3.0).min(), 1.0); + /// assert!(Vector3::new(1.0, std::f64::NAN, 3.0).min().is_nan()); + /// ``` + /// + /// # Panics + /// Panics if the matrix is empty: + /// ```should_panic + /// # use nalgebra::DMatrix; + /// let min = DMatrix::::zeros(0,1).min(); // panics! + /// ``` #[inline] pub fn min(&self) -> N where N: PartialOrd + Signed { - self.xcmp(|e| e, |a, b| a < b) + self.xcmp(|e| e, Ordering::Less) } } \ No newline at end of file From 206242e5e4cf1909c2d0fdb454429c42f002aea4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20L=C3=B6schner?= Date: Sat, 10 Aug 2019 16:25:19 +0200 Subject: [PATCH 22/30] Clarified documentation of min/max behaviour --- src/base/ops.rs | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/base/ops.rs b/src/base/ops.rs index 30f6194e..15325e63 100644 --- a/src/base/ops.rs +++ b/src/base/ops.rs @@ -889,7 +889,10 @@ impl> Matrix { max } - /// Returns the absolute value of the component with the largest absolute value. Propagates NaN. + /// Returns the absolute value of the component with the largest absolute value. + /// If the matrix contains any value for which `PartialOrd::partial_cmp` returns + /// `None`, the first encountered value that causes this is returned instead + /// (e.g. a `NaN` value). /// # Example /// ``` /// # use nalgebra::Vector3; @@ -910,7 +913,10 @@ impl> Matrix { self.xcmp(|e| e.abs(), Ordering::Greater) } - /// Returns the the 1-norm of the complex component with the largest 1-norm. Propagates NaN. + /// Returns the the 1-norm of the complex component with the largest 1-norm. + /// If the matrix contains any value for which `PartialOrd::partial_cmp` returns + /// `None`, the first encountered value that causes this is returned instead + /// (e.g. a `NaN` value). /// # Example /// ``` /// # use nalgebra::{Vector3, Complex}; @@ -936,7 +942,10 @@ impl> Matrix { self.xcmp(|e| e.norm1(), Ordering::Greater) } - /// Returns the component with the largest value. Propagates NaN. + /// Returns the component with the largest value. + /// If the matrix contains any value for which `PartialOrd::partial_cmp` returns + /// `None`, the first encountered value that causes this is returned instead + /// (e.g. a `NaN` value). /// # Example /// ``` /// # use nalgebra::Vector3; @@ -957,7 +966,10 @@ impl> Matrix { self.xcmp(|e| e, Ordering::Greater) } - /// Returns the absolute value of the component with the smallest absolute value. Propagates NaN. + /// Returns the absolute value of the component with the smallest absolute value. + /// If the matrix contains any value for which `PartialOrd::partial_cmp` returns + /// `None`, the first encountered value that causes this is returned instead + /// (e.g. a `NaN` value). /// # Example /// ``` /// # use nalgebra::Vector3; @@ -978,7 +990,10 @@ impl> Matrix { self.xcmp(|e| e.abs(), Ordering::Less) } - /// Returns the the 1-norm of the complex component with the smallest 1-norm. Propagates NaN. + /// Returns the the 1-norm of the complex component with the smallest 1-norm. + /// If the matrix contains any value for which `PartialOrd::partial_cmp` returns + /// `None`, the first encountered value that causes this is returned instead + /// (e.g. a `NaN` value). /// # Example /// ``` /// # use nalgebra::{Vector3, Complex}; @@ -1004,7 +1019,10 @@ impl> Matrix { self.xcmp(|e| e.norm1(), Ordering::Less) } - /// Returns the component with the smallest value. Propagates NaN. + /// Returns the component with the smallest value. + /// If the matrix contains any value for which `PartialOrd::partial_cmp` returns + /// `None`, the first encountered value that causes this is returned instead + /// (e.g. a `NaN` value). /// # Example /// ``` /// # use nalgebra::Vector3; From 8916e907f242489fc0134a8c71841022f6d40086 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20L=C3=B6schner?= Date: Tue, 13 Aug 2019 09:00:54 +0200 Subject: [PATCH 23/30] Undo breaking changes --- src/base/ops.rs | 80 +++---------------------------------------------- 1 file changed, 4 insertions(+), 76 deletions(-) diff --git a/src/base/ops.rs b/src/base/ops.rs index 15325e63..758c1464 100644 --- a/src/base/ops.rs +++ b/src/base/ops.rs @@ -870,9 +870,11 @@ impl> Matrix { #[inline(always)] fn xcmp(&self, abs: impl Fn(N) -> N2, ordering: Ordering) -> N2 where N2: Scalar + PartialOrd + Zero { - assert!(self.len() > 0, "Empty matrix supplied to min/max function."); let mut iter = self.iter(); - let mut max = abs(iter.next().cloned().unwrap()); + let mut max = match iter.next() { + Some(first) => abs(*first), + None => { return N2::zero(); } + }; for e in iter { let ae = abs(*e); @@ -881,8 +883,6 @@ impl> Matrix { if ae_ordering == ordering { max = ae; } - } else { - return ae; } } @@ -890,22 +890,11 @@ impl> Matrix { } /// Returns the absolute value of the component with the largest absolute value. - /// If the matrix contains any value for which `PartialOrd::partial_cmp` returns - /// `None`, the first encountered value that causes this is returned instead - /// (e.g. a `NaN` value). /// # Example /// ``` /// # use nalgebra::Vector3; /// assert_eq!(Vector3::new(-1.0, 2.0, 3.0).amax(), 3.0); /// assert_eq!(Vector3::new(-1.0, -2.0, -3.0).amax(), 3.0); - /// assert!(Vector3::new(1.0, std::f64::NAN, 3.0).amax().is_nan()); - /// ``` - /// - /// # Panics - /// Panics if the matrix is empty: - /// ```should_panic - /// # use nalgebra::DMatrix; - /// let min = DMatrix::::zeros(0,1).amax(); // panics! /// ``` #[inline] pub fn amax(&self) -> N @@ -914,9 +903,6 @@ impl> Matrix { } /// Returns the the 1-norm of the complex component with the largest 1-norm. - /// If the matrix contains any value for which `PartialOrd::partial_cmp` returns - /// `None`, the first encountered value that causes this is returned instead - /// (e.g. a `NaN` value). /// # Example /// ``` /// # use nalgebra::{Vector3, Complex}; @@ -924,17 +910,6 @@ impl> Matrix { /// Complex::new(-3.0, -2.0), /// Complex::new(1.0, 2.0), /// Complex::new(1.0, 3.0)).camax(), 5.0); - /// assert!(Vector3::new( - /// Complex::new(-3.0, -2.0), - /// Complex::new(1.0, std::f64::NAN), - /// Complex::new(1.0, 3.0)).camax().is_nan()); - /// ``` - /// - /// # Panics - /// Panics if the matrix is empty: - /// ```should_panic - /// # use nalgebra::{DMatrix, Complex}; - /// let min = DMatrix::>::zeros(0,1).camax(); // panics! /// ``` #[inline] pub fn camax(&self) -> N::RealField @@ -943,22 +918,11 @@ impl> Matrix { } /// Returns the component with the largest value. - /// If the matrix contains any value for which `PartialOrd::partial_cmp` returns - /// `None`, the first encountered value that causes this is returned instead - /// (e.g. a `NaN` value). /// # Example /// ``` /// # use nalgebra::Vector3; /// assert_eq!(Vector3::new(-1.0, 2.0, 3.0).max(), 3.0); /// assert_eq!(Vector3::new(-1.0, -2.0, -3.0).max(), -1.0); - /// assert!(Vector3::new(1.0, std::f64::NAN, 3.0).max().is_nan()); - /// ``` - /// - /// # Panics - /// Panics if the matrix is empty: - /// ```should_panic - /// # use nalgebra::DMatrix; - /// let min = DMatrix::::zeros(0,1).max(); // panics! /// ``` #[inline] pub fn max(&self) -> N @@ -967,22 +931,11 @@ impl> Matrix { } /// Returns the absolute value of the component with the smallest absolute value. - /// If the matrix contains any value for which `PartialOrd::partial_cmp` returns - /// `None`, the first encountered value that causes this is returned instead - /// (e.g. a `NaN` value). /// # Example /// ``` /// # use nalgebra::Vector3; /// assert_eq!(Vector3::new(-1.0, 2.0, -3.0).amin(), 1.0); /// assert_eq!(Vector3::new(10.0, 2.0, 30.0).amin(), 2.0); - /// assert!(Vector3::new(-1.0, std::f64::NAN, 3.0).amin().is_nan()); - /// ``` - /// - /// # Panics - /// Panics if the matrix is empty: - /// ```should_panic - /// # use nalgebra::DMatrix; - /// let min = DMatrix::::zeros(0,1).amin(); // panics! /// ``` #[inline] pub fn amin(&self) -> N @@ -991,9 +944,6 @@ impl> Matrix { } /// Returns the the 1-norm of the complex component with the smallest 1-norm. - /// If the matrix contains any value for which `PartialOrd::partial_cmp` returns - /// `None`, the first encountered value that causes this is returned instead - /// (e.g. a `NaN` value). /// # Example /// ``` /// # use nalgebra::{Vector3, Complex}; @@ -1001,17 +951,6 @@ impl> Matrix { /// Complex::new(-3.0, -2.0), /// Complex::new(1.0, 2.0), /// Complex::new(1.0, 3.0)).camin(), 3.0); - /// assert!(Vector3::new( - /// Complex::new(-3.0, -2.0), - /// Complex::new(1.0, std::f64::NAN), - /// Complex::new(1.0, 3.0)).camin().is_nan()); - /// ``` - /// - /// # Panics - /// Panics if the matrix is empty: - /// ```should_panic - /// # use nalgebra::{DMatrix, Complex}; - /// let min = DMatrix::>::zeros(0,1).camin(); // panics! /// ``` #[inline] pub fn camin(&self) -> N::RealField @@ -1020,22 +959,11 @@ impl> Matrix { } /// Returns the component with the smallest value. - /// If the matrix contains any value for which `PartialOrd::partial_cmp` returns - /// `None`, the first encountered value that causes this is returned instead - /// (e.g. a `NaN` value). /// # Example /// ``` /// # use nalgebra::Vector3; /// assert_eq!(Vector3::new(-1.0, 2.0, 3.0).min(), -1.0); /// assert_eq!(Vector3::new(1.0, 2.0, 3.0).min(), 1.0); - /// assert!(Vector3::new(1.0, std::f64::NAN, 3.0).min().is_nan()); - /// ``` - /// - /// # Panics - /// Panics if the matrix is empty: - /// ```should_panic - /// # use nalgebra::DMatrix; - /// let min = DMatrix::::zeros(0,1).min(); // panics! /// ``` #[inline] pub fn min(&self) -> N From 3ef76ab9e4c484185875da7739b0796cb7b37f6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20L=C3=B6schner?= Date: Tue, 13 Aug 2019 09:04:41 +0200 Subject: [PATCH 24/30] More elegant initial value for xcmp --- src/base/ops.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/base/ops.rs b/src/base/ops.rs index 758c1464..3566a2b5 100644 --- a/src/base/ops.rs +++ b/src/base/ops.rs @@ -871,10 +871,7 @@ impl> Matrix { fn xcmp(&self, abs: impl Fn(N) -> N2, ordering: Ordering) -> N2 where N2: Scalar + PartialOrd + Zero { let mut iter = self.iter(); - let mut max = match iter.next() { - Some(first) => abs(*first), - None => { return N2::zero(); } - }; + let mut max = iter.next().cloned().map_or(N2::zero(), &abs); for e in iter { let ae = abs(*e); From a74702bb5af6d5fad292b06540bb66908f0708f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fabian=20L=C3=B6schner?= Date: Tue, 13 Aug 2019 09:27:24 +0200 Subject: [PATCH 25/30] Simplified ordering check --- src/base/ops.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/base/ops.rs b/src/base/ops.rs index 3566a2b5..f389eae5 100644 --- a/src/base/ops.rs +++ b/src/base/ops.rs @@ -876,10 +876,8 @@ impl> Matrix { for e in iter { let ae = abs(*e); - if let Some(ae_ordering) = ae.partial_cmp(&max) { - if ae_ordering == ordering { + if ae.partial_cmp(&max) == Some(ordering) { max = ae; - } } } From 7a4daba91c7c927ee1faac1b3f5bb979187e85c7 Mon Sep 17 00:00:00 2001 From: sebcrozet Date: Tue, 27 Aug 2019 14:30:20 +0200 Subject: [PATCH 26/30] Matrix::transform_point: correctly take the normalization term into account. Fix #640 --- src/base/cg.rs | 6 +++--- tests/geometry/projection.rs | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/base/cg.rs b/src/base/cg.rs index d23d5cd3..0822ea27 100644 --- a/src/base/cg.rs +++ b/src/base/cg.rs @@ -358,10 +358,10 @@ where DefaultAllocator: Allocator + unsafe { *self.get_unchecked((D::dim() - 1, D::dim() - 1)) }; if !n.is_zero() { - return transform * (pt / n) + translation; + (transform * pt + translation) / n + } else { + transform * pt + translation } - - transform * pt + translation } } diff --git a/tests/geometry/projection.rs b/tests/geometry/projection.rs index 0f38bc37..03c6d4df 100644 --- a/tests/geometry/projection.rs +++ b/tests/geometry/projection.rs @@ -1,4 +1,4 @@ -use na::{Orthographic3, Perspective3}; +use na::{Orthographic3, Perspective3, Point3}; #[test] fn perspective_inverse() { @@ -20,6 +20,19 @@ fn orthographic_inverse() { assert!(id.is_identity(1.0e-7)); } +#[test] +fn perspective_matrix_point_transformation() { + // https://github.com/rustsim/nalgebra/issues/640 + let proj = Perspective3::new(4.0 / 3.0, 90.0, 0.1, 100.0); + let perspective_inv = proj.as_matrix().try_inverse().unwrap(); + let some_point = Point3::new(1.0, 2.0, 0.0); + + assert_eq!( + perspective_inv.transform_point(&some_point), + Point3::from_homogeneous(perspective_inv * some_point.coords.push(1.0)).unwrap() + ); +} + #[cfg(feature = "arbitrary")] mod quickcheck_tests { use na::{Orthographic3, Perspective3, Point3}; From 14430d4f74966a7b6e874b19fec5bc51c8a6a91c Mon Sep 17 00:00:00 2001 From: sebcrozet Date: Tue, 27 Aug 2019 20:53:54 +0200 Subject: [PATCH 27/30] Update changelog. --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e22820c..8be48e79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ documented here. This project adheres to [Semantic Versioning](https://semver.org/). +## [0.19.0] - WIP +### Added + * `.remove_rows_at` and `remove_columns_at` which removes a set of rows or columns (specified by indices) from a matrix. + ## [0.18.0] This release adds full complex number support to nalgebra. This includes all common vector/matrix operations as well as matrix decomposition. This excludes geometric type (like `Isometry`, `Rotation`, `Translation`, etc.) from the From d60aa68609eeb3e6ab1fd1c04661f27e64e25de7 Mon Sep 17 00:00:00 2001 From: sebcrozet Date: Tue, 27 Aug 2019 20:55:25 +0200 Subject: [PATCH 28/30] Release v0.18.1 --- Cargo.toml | 2 +- nalgebra-glm/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fd9ad6e0..c61c1e71 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra" -version = "0.18.0" +version = "0.18.1" authors = [ "Sébastien Crozet " ] description = "Linear algebra library with transformations and statically-sized or dynamically-sized matrices." diff --git a/nalgebra-glm/Cargo.toml b/nalgebra-glm/Cargo.toml index 6eda9a46..40e62e4a 100644 --- a/nalgebra-glm/Cargo.toml +++ b/nalgebra-glm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra-glm" -version = "0.4.0" +version = "0.4.1" authors = ["sebcrozet "] description = "A computer-graphics oriented API for nalgebra, inspired by the C++ GLM library." From f1576953dd33b38f4e3a1d190cf03c9c8442a1fe Mon Sep 17 00:00:00 2001 From: sebcrozet Date: Tue, 27 Aug 2019 22:41:09 +0200 Subject: [PATCH 29/30] nalgebra-glm: reexport infinite and reversed perspectives. --- nalgebra-glm/src/ext/mod.rs | 4 ++++ nalgebra-glm/src/lib.rs | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/nalgebra-glm/src/ext/mod.rs b/nalgebra-glm/src/ext/mod.rs index 0f9879ef..52aa9dc3 100644 --- a/nalgebra-glm/src/ext/mod.rs +++ b/nalgebra-glm/src/ext/mod.rs @@ -10,6 +10,10 @@ pub use self::matrix_clip_space::{ perspective_fov, perspective_fov_lh,perspective_fov_lh_no, perspective_fov_lh_zo, perspective_fov_no, perspective_fov_rh, perspective_fov_rh_no, perspective_fov_rh_zo, perspective_fov_zo, + + infinite_perspective_rh_no, infinite_perspective_rh_zo, + + reversed_perspective_rh_zo, reversed_infinite_perspective_rh_zo, }; pub use self::matrix_projection::{ pick_matrix, project, project_no, project_zo, unproject, unproject_no, unproject_zo, diff --git a/nalgebra-glm/src/lib.rs b/nalgebra-glm/src/lib.rs index 1414bf6a..c8f266a4 100644 --- a/nalgebra-glm/src/lib.rs +++ b/nalgebra-glm/src/lib.rs @@ -155,7 +155,8 @@ pub use ext::{ quat_equal, quat_equal_eps, quat_exp, quat_inverse, quat_length, quat_lerp, quat_log, quat_magnitude, quat_normalize, quat_not_equal, quat_not_equal_eps, quat_pow, quat_rotate, quat_slerp, rotate, rotate_x, rotate_y, rotate_z, scale, translate, unproject, unproject_no, - unproject_zo, + unproject_zo, infinite_perspective_rh_no, infinite_perspective_rh_zo, + reversed_perspective_rh_zo, reversed_infinite_perspective_rh_zo, }; pub use gtc::{ affine_inverse, column, e, euler, four_over_pi, golden_ratio, half_pi, inverse_transpose, From e48ee26d4570a59f1660e400e6881927f9df18a9 Mon Sep 17 00:00:00 2001 From: sebcrozet Date: Tue, 27 Aug 2019 22:45:20 +0200 Subject: [PATCH 30/30] Release nalgebra-glm v0.4.2 --- nalgebra-glm/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nalgebra-glm/Cargo.toml b/nalgebra-glm/Cargo.toml index 40e62e4a..bb54e205 100644 --- a/nalgebra-glm/Cargo.toml +++ b/nalgebra-glm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra-glm" -version = "0.4.1" +version = "0.4.2" authors = ["sebcrozet "] description = "A computer-graphics oriented API for nalgebra, inspired by the C++ GLM library."