From 831142d618b3d263907d2499509957f291ecfc04 Mon Sep 17 00:00:00 2001 From: Owen Brooks Date: Wed, 15 Jun 2022 13:42:14 +1000 Subject: [PATCH 01/16] Make matrix Debug output semicolon-delimited rows --- src/base/matrix.rs | 44 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 41 insertions(+), 3 deletions(-) diff --git a/src/base/matrix.rs b/src/base/matrix.rs index 8f8786c13..9afd8a148 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -195,9 +195,47 @@ pub struct Matrix { _phantoms: PhantomData<(T, R, C)>, } -impl fmt::Debug for Matrix { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - self.data.fmt(formatter) +impl + fmt::Debug> fmt::Debug + for Matrix +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + write!(f, "Matrix {{ ")?; + if f.alternate() { + write!(f, "\n ")?; + } + write!(f, "data: [")?; + let nrows = self.nrows(); + let ncols = self.ncols(); + for i in 0..nrows { + for j in 0..ncols { + if j != 0 { + write!(f, ", ")?; + } + // Safety: the indices are within range + unsafe { + (*self.data.get_unchecked(i, j)).fmt(f)?; + } + } + if i != nrows - 1 { + write!(f, "; ")?; + } + if f.alternate() && i != nrows - 1 { + write!(f, "\n ")?; + } + } + write!(f, "], ")?; + if f.alternate() { + write!(f, "\n ")?; + } + write!(f, "nrows: {:?}, ", nrows)?; + if f.alternate() { + write!(f, "\n ")?; + } + write!(f, "ncols: {:?} ", ncols)?; + if f.alternate() { + writeln!(f, "")?; + } + write!(f, "}}") } } From f77f5564818661542fd2963e1ad922e46e8f6073 Mon Sep 17 00:00:00 2001 From: Owen Brooks Date: Wed, 15 Jun 2022 13:44:20 +1000 Subject: [PATCH 02/16] Derive ArrayStorage Debug formatting --- src/base/array_storage.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/base/array_storage.rs b/src/base/array_storage.rs index 3bc71e1a3..ae7a2e3bc 100644 --- a/src/base/array_storage.rs +++ b/src/base/array_storage.rs @@ -1,4 +1,4 @@ -use std::fmt::{self, Debug, Formatter}; +use std::fmt::Debug; // use std::hash::{Hash, Hasher}; use std::ops::Mul; @@ -26,7 +26,7 @@ use std::mem; */ /// A array-based statically sized matrix data storage. #[repr(transparent)] -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] #[cfg_attr( feature = "rkyv-serialize-no-std", @@ -62,13 +62,6 @@ where } } -impl Debug for ArrayStorage { - #[inline] - fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - self.0.fmt(fmt) - } -} - unsafe impl RawStorage, Const> for ArrayStorage { From 807e4c153aacf973d9d5b68d943e6bea72d1f431 Mon Sep 17 00:00:00 2001 From: Owen Brooks Date: Wed, 15 Jun 2022 13:47:55 +1000 Subject: [PATCH 03/16] Simplify and standardise formatting of geometry types --- src/base/matrix.rs | 15 +++++++++++ src/geometry/dual_quaternion.rs | 25 +++++------------ src/geometry/isometry.rs | 12 ++++----- src/geometry/point.rs | 33 +++++++++-------------- src/geometry/quaternion.rs | 48 ++++++++++++++++++++------------- src/geometry/scale.rs | 18 +++++-------- src/geometry/similarity.rs | 14 +++++----- src/geometry/translation.rs | 18 +++++-------- 8 files changed, 89 insertions(+), 94 deletions(-) diff --git a/src/base/matrix.rs b/src/base/matrix.rs index 9afd8a148..fc3ff8571 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -1968,6 +1968,21 @@ impl_fmt!(fmt::UpperHex, "{:X}", "{:1$X}"); impl_fmt!(fmt::Binary, "{:b}", "{:.1$b}"); impl_fmt!(fmt::Pointer, "{:p}", "{:.1$p}"); +/// Displays a vector using commas as the delimiter +pub fn display_column_vec_as_row(vector: &OVector, f: &mut fmt::Formatter<'_>) -> fmt::Result +where + DefaultAllocator: Allocator, +{ + write!(f, "[")?; + let mut it = vector.iter(); + std::fmt::Display::fmt(it.next().unwrap(), f)?; + for comp in it { + write!(f, ", ")?; + std::fmt::Display::fmt(comp, f)?; + } + write!(f, "]") +} + #[cfg(test)] mod tests { #[test] diff --git a/src/geometry/dual_quaternion.rs b/src/geometry/dual_quaternion.rs index 6f1b70536..466668637 100644 --- a/src/geometry/dual_quaternion.rs +++ b/src/geometry/dual_quaternion.rs @@ -951,25 +951,12 @@ impl Default for UnitDualQuaternion { impl fmt::Display for UnitDualQuaternion { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(axis) = self.rotation().axis() { - let axis = axis.into_inner(); - write!( - f, - "UnitDualQuaternion translation: {} − angle: {} − axis: ({}, {}, {})", - self.translation().vector, - self.rotation().angle(), - axis[0], - axis[1], - axis[2] - ) - } else { - write!( - f, - "UnitDualQuaternion translation: {} − angle: {} − axis: (undefined)", - self.translation().vector, - self.rotation().angle() - ) - } + write!(f, "{{ translation: ")?; + crate::display_column_vec_as_row(&self.translation().vector, f)?; + write!(f, ", ")?; + write!(f, "rotation: ")?; + std::fmt::Display::fmt(&self.rotation(), f)?; + write!(f, " }}") } } diff --git a/src/geometry/isometry.rs b/src/geometry/isometry.rs index 921697427..6f375d45b 100755 --- a/src/geometry/isometry.rs +++ b/src/geometry/isometry.rs @@ -548,11 +548,11 @@ where R: fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let precision = f.precision().unwrap_or(3); - - writeln!(f, "Isometry {{")?; - write!(f, "{:.*}", precision, self.translation)?; - write!(f, "{:.*}", precision, self.rotation)?; - writeln!(f, "}}") + write!(f, "{{ translation: ")?; + crate::display_column_vec_as_row(&self.translation.vector, f)?; + write!(f, ", ")?; + write!(f, "rotation: ")?; + std::fmt::Display::fmt(&self.rotation, f)?; + write!(f, " }}") } } diff --git a/src/geometry/point.rs b/src/geometry/point.rs index 306c18e5e..d639a04af 100644 --- a/src/geometry/point.rs +++ b/src/geometry/point.rs @@ -35,7 +35,7 @@ use std::mem::MaybeUninit; /// may have some other methods, e.g., `isometry.inverse_transform_point(&point)`. See the documentation /// of said transformations for details. #[repr(C)] -#[derive(Clone)] +#[derive(Clone, Debug)] #[cfg_attr( feature = "rkyv-serialize-no-std", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) @@ -49,15 +49,6 @@ where pub coords: OVector, } -impl fmt::Debug for OPoint -where - DefaultAllocator: Allocator, -{ - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - self.coords.as_slice().fmt(formatter) - } -} - impl hash::Hash for OPoint where DefaultAllocator: Allocator, @@ -457,17 +448,19 @@ impl fmt::Display for OPoint where DefaultAllocator: Allocator, { + /// ```rust + /// # use nalgebra::Point3; + /// let point = Point3::new(1.12345678, 2.12345678, 3.12345678); + /// let rounded = format!("{:#.4}", point); // print point in compact representation + /// assert_eq!(rounded, "[1.1235, 2.1235, 3.1235]"); + /// let vertical = format!("{}", point); // print point as a column + /// assert_eq!(vertical, "\n ┌ ┐\n │ 1.12345678 │\n │ 2.12345678 │\n │ 3.12345678 │\n └ ┘"); + /// ``` fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{{")?; - - let mut it = self.coords.iter(); - - write!(f, "{}", *it.next().unwrap())?; - - for comp in it { - write!(f, ", {}", *comp)?; + if f.alternate() { + crate::display_column_vec_as_row(&self.coords, f) + } else { + std::fmt::Display::fmt(&self.coords, f) // pretty-prints vector } - - write!(f, "}}") } } diff --git a/src/geometry/quaternion.rs b/src/geometry/quaternion.rs index f38dca6f7..5d02988a2 100755 --- a/src/geometry/quaternion.rs +++ b/src/geometry/quaternion.rs @@ -36,7 +36,13 @@ pub struct Quaternion { impl fmt::Debug for Quaternion { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - self.coords.as_slice().fmt(formatter) + formatter + .debug_struct("Quaternion") + .field("x", &self.coords[0]) + .field("y", &self.coords[1]) + .field("z", &self.coords[2]) + .field("w", &self.coords[3]) + .finish() } } @@ -995,11 +1001,16 @@ impl> UlpsEq for Quaternion { impl fmt::Display for Quaternion { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "Quaternion {} − ({}, {}, {})", - self[3], self[0], self[1], self[2] - ) + // Formatting of each item is forwarded to standard fmt display so that formatting + // flags are followed correctly. + std::fmt::Display::fmt(&self[0], f)?; + write!(f, " + ")?; + std::fmt::Display::fmt(&self[1], f)?; + write!(f, "i + ")?; + std::fmt::Display::fmt(&self[2], f)?; + write!(f, "j + ")?; + std::fmt::Display::fmt(&self[3], f)?; + write!(f, "k") } } @@ -1636,23 +1647,22 @@ impl Default for UnitQuaternion { impl fmt::Display for UnitQuaternion { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Formatting of each item is forwarded to standard fmt Display so that formatting + // flags are followed correctly. + write!(f, "{{ angle: ")?; + std::fmt::Display::fmt(&self.angle(), f)?; + write!(f, ", axis: (")?; if let Some(axis) = self.axis() { let axis = axis.into_inner(); - write!( - f, - "UnitQuaternion angle: {} − axis: ({}, {}, {})", - self.angle(), - axis[0], - axis[1], - axis[2] - ) + std::fmt::Display::fmt(&axis[0], f)?; + write!(f, ", ")?; + std::fmt::Display::fmt(&axis[1], f)?; + write!(f, ", ")?; + std::fmt::Display::fmt(&axis[2], f)?; } else { - write!( - f, - "UnitQuaternion angle: {} − axis: (undefined)", - self.angle() - ) + write!(f, "undefined")?; } + write!(f, ") }}") } } diff --git a/src/geometry/scale.rs b/src/geometry/scale.rs index 37da1ef04..ad09cca57 100755 --- a/src/geometry/scale.rs +++ b/src/geometry/scale.rs @@ -23,19 +23,13 @@ use crate::geometry::Point; derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) )] #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct Scale { /// The scale coordinates, i.e., how much is multiplied to a point's coordinates when it is /// scaled. pub vector: SVector, } -impl fmt::Debug for Scale { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - self.vector.as_slice().fmt(formatter) - } -} - impl hash::Hash for Scale where Owned>: hash::Hash, @@ -369,10 +363,10 @@ where */ impl fmt::Display for Scale { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let precision = f.precision().unwrap_or(3); - - writeln!(f, "Scale {{")?; - write!(f, "{:.*}", precision, self.vector)?; - writeln!(f, "}}") + if f.alternate() { + crate::display_column_vec_as_row(&self.vector, f) + } else { + std::fmt::Display::fmt(&self.vector, f) // pretty-prints vector + } } } diff --git a/src/geometry/similarity.rs b/src/geometry/similarity.rs index 8c38ff1e6..0a6060acc 100755 --- a/src/geometry/similarity.rs +++ b/src/geometry/similarity.rs @@ -397,11 +397,13 @@ where R: AbstractRotation + fmt::Display, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let precision = f.precision().unwrap_or(3); - - writeln!(f, "Similarity {{")?; - write!(f, "{:.*}", precision, self.isometry)?; - write!(f, "Scaling: {:.*}", precision, self.scaling)?; - writeln!(f, "}}") + write!(f, "{{ translation: ")?; + crate::display_column_vec_as_row(&self.isometry.translation.vector, f)?; + write!(f, ", ")?; + write!(f, "rotation: ")?; + std::fmt::Display::fmt(&self.isometry.rotation, f)?; + write!(f, ", scaling: ")?; + std::fmt::Display::fmt(&self.scaling, f)?; + write!(f, " }}") } } diff --git a/src/geometry/translation.rs b/src/geometry/translation.rs index bef66f686..b910d88b0 100755 --- a/src/geometry/translation.rs +++ b/src/geometry/translation.rs @@ -23,19 +23,13 @@ use crate::geometry::Point; derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) )] #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct Translation { /// The translation coordinates, i.e., how much is added to a point's coordinates when it is /// translated. pub vector: SVector, } -impl fmt::Debug for Translation { - fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - self.vector.as_slice().fmt(formatter) - } -} - impl hash::Hash for Translation where Owned>: hash::Hash, @@ -284,10 +278,10 @@ where */ impl fmt::Display for Translation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let precision = f.precision().unwrap_or(3); - - writeln!(f, "Translation {{")?; - write!(f, "{:.*}", precision, self.vector)?; - writeln!(f, "}}") + if f.alternate() { + crate::display_column_vec_as_row(&self.vector, f) + } else { + std::fmt::Display::fmt(&self.vector, f) // pretty-prints vector + } } } From 49e3633c1c935d53368a0fbd1943397682a027a8 Mon Sep 17 00:00:00 2001 From: Owen Brooks Date: Wed, 15 Jun 2022 13:48:46 +1000 Subject: [PATCH 04/16] Add alternate Display for concise matrix printing Add format option for concise printing of matrices as semicolon-delimited rows. e.g. println!("{:#}", matrix); --- src/base/matrix.rs | 124 +++++++++++++++++++++++++++------------------ 1 file changed, 74 insertions(+), 50 deletions(-) diff --git a/src/base/matrix.rs b/src/base/matrix.rs index fc3ff8571..0d0f9f268 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -1893,68 +1893,92 @@ macro_rules! impl_fmt { S: RawStorage, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - #[cfg(feature = "std")] - fn val_width(val: &T, f: &mut fmt::Formatter<'_>) -> usize { - match f.precision() { - Some(precision) => format!($fmt_str_with_precision, val, precision) - .chars() - .count(), - None => format!($fmt_str_without_precision, val).chars().count(), + if !f.alternate() { // pretty print in 2D layout + #[cfg(feature = "std")] + fn val_width(val: &T, f: &mut fmt::Formatter<'_>) -> usize { + match f.precision() { + Some(precision) => format!($fmt_str_with_precision, val, precision) + .chars() + .count(), + None => format!($fmt_str_without_precision, val).chars().count(), + } } - } - #[cfg(not(feature = "std"))] - fn val_width(_: &T, _: &mut fmt::Formatter<'_>) -> usize { - 4 - } + #[cfg(not(feature = "std"))] + fn val_width(_: &T, _: &mut fmt::Formatter<'_>) -> usize { + 4 + } - let (nrows, ncols) = self.shape(); + let (nrows, ncols) = self.shape(); - if nrows == 0 || ncols == 0 { - return write!(f, "[ ]"); - } + if nrows == 0 || ncols == 0 { + return write!(f, "[ ]"); + } - let mut max_length = 0; + let mut max_length = 0; - for i in 0..nrows { - for j in 0..ncols { - max_length = crate::max(max_length, val_width(&self[(i, j)], f)); + for i in 0..nrows { + for j in 0..ncols { + max_length = crate::max(max_length, val_width(&self[(i, j)], f)); + } } - } - let max_length_with_space = max_length + 1; - - writeln!(f)?; - writeln!( - f, - " ┌ {:>width$} ┐", - "", - width = max_length_with_space * ncols - 1 - )?; - - for i in 0..nrows { - write!(f, " │")?; - for j in 0..ncols { - let number_length = val_width(&self[(i, j)], f) + 1; - let pad = max_length_with_space - number_length; - write!(f, " {:>thepad$}", "", thepad = pad)?; - match f.precision() { - Some(precision) => { - write!(f, $fmt_str_with_precision, (*self)[(i, j)], precision)? + let max_length_with_space = max_length + 1; + + writeln!(f)?; // leading newline to ensure no offset from previous prints + writeln!( + f, + " ┌ {:>width$} ┐", + "", + width = max_length_with_space * ncols - 1 + )?; + + for i in 0..nrows { + write!(f, " │")?; + for j in 0..ncols { + let number_length = val_width(&self[(i, j)], f) + 1; + let pad = max_length_with_space - number_length; + write!(f, " {:>thepad$}", "", thepad = pad)?; + match f.precision() { + Some(precision) => { + write!(f, $fmt_str_with_precision, (*self)[(i, j)], precision)? + } + None => write!(f, $fmt_str_without_precision, (*self)[(i, j)])?, } - None => write!(f, $fmt_str_without_precision, (*self)[(i, j)])?, } + writeln!(f, " │")?; } - writeln!(f, " │")?; - } - writeln!( - f, - " └ {:>width$} ┘", - "", - width = max_length_with_space * ncols - 1 - )?; - writeln!(f) + write!( + f, + " └ {:>width$} ┘", + "", + width = max_length_with_space * ncols - 1 + ) + } else { // print on single line with semicolon-delimited rows and comma-delimited columns + let (nrows, ncols) = self.shape(); + write!(f, "[")?; + for row in 0..nrows { + for col in 0..ncols { + if col != 0 { + write!(f, ", ")?; + } + match f.precision() { + Some(precision) => write!( + f, + $fmt_str_with_precision, + (*self)[(row, col)], + precision + )?, + None => write!(f, $fmt_str_without_precision, (*self)[(row, col)])?, + } + } + if row != nrows - 1 { + write!(f, "; ")?; + } + } + write!(f, "]") + } } } }; From 65e90d53a9c9b3e69a65233fae9e589640c23432 Mon Sep 17 00:00:00 2001 From: Owen Brooks Date: Wed, 15 Jun 2022 20:13:48 +1000 Subject: [PATCH 05/16] Simplify Point, Translation and Scale Debug output --- src/base/matrix.rs | 5 ++++- src/geometry/dual_quaternion.rs | 2 +- src/geometry/isometry.rs | 2 +- src/geometry/point.rs | 13 +++++++++++-- src/geometry/scale.rs | 10 ++++++++-- src/geometry/similarity.rs | 2 +- src/geometry/translation.rs | 10 ++++++++-- 7 files changed, 34 insertions(+), 10 deletions(-) diff --git a/src/base/matrix.rs b/src/base/matrix.rs index 0d0f9f268..f1417d391 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -1993,7 +1993,10 @@ impl_fmt!(fmt::Binary, "{:b}", "{:.1$b}"); impl_fmt!(fmt::Pointer, "{:p}", "{:.1$p}"); /// Displays a vector using commas as the delimiter -pub fn display_column_vec_as_row(vector: &OVector, f: &mut fmt::Formatter<'_>) -> fmt::Result +pub fn format_column_vec_as_row( + vector: &OVector, + f: &mut fmt::Formatter<'_>, +) -> fmt::Result where DefaultAllocator: Allocator, { diff --git a/src/geometry/dual_quaternion.rs b/src/geometry/dual_quaternion.rs index 466668637..adb6d9eaa 100644 --- a/src/geometry/dual_quaternion.rs +++ b/src/geometry/dual_quaternion.rs @@ -952,7 +952,7 @@ impl Default for UnitDualQuaternion { impl fmt::Display for UnitDualQuaternion { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{{ translation: ")?; - crate::display_column_vec_as_row(&self.translation().vector, f)?; + crate::format_column_vec_as_row(&self.translation().vector, f)?; write!(f, ", ")?; write!(f, "rotation: ")?; std::fmt::Display::fmt(&self.rotation(), f)?; diff --git a/src/geometry/isometry.rs b/src/geometry/isometry.rs index 6f375d45b..5db33bc3b 100755 --- a/src/geometry/isometry.rs +++ b/src/geometry/isometry.rs @@ -549,7 +549,7 @@ where { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{{ translation: ")?; - crate::display_column_vec_as_row(&self.translation.vector, f)?; + crate::format_column_vec_as_row(&self.translation.vector, f)?; write!(f, ", ")?; write!(f, "rotation: ")?; std::fmt::Display::fmt(&self.rotation, f)?; diff --git a/src/geometry/point.rs b/src/geometry/point.rs index d639a04af..dce84ed46 100644 --- a/src/geometry/point.rs +++ b/src/geometry/point.rs @@ -35,7 +35,7 @@ use std::mem::MaybeUninit; /// may have some other methods, e.g., `isometry.inverse_transform_point(&point)`. See the documentation /// of said transformations for details. #[repr(C)] -#[derive(Clone, Debug)] +#[derive(Clone)] #[cfg_attr( feature = "rkyv-serialize-no-std", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) @@ -49,6 +49,15 @@ where pub coords: OVector, } +impl fmt::Debug for OPoint +where + DefaultAllocator: Allocator, +{ + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + self.coords.as_slice().fmt(formatter) + } +} + impl hash::Hash for OPoint where DefaultAllocator: Allocator, @@ -458,7 +467,7 @@ where /// ``` fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if f.alternate() { - crate::display_column_vec_as_row(&self.coords, f) + crate::format_column_vec_as_row(&self.coords, f) } else { std::fmt::Display::fmt(&self.coords, f) // pretty-prints vector } diff --git a/src/geometry/scale.rs b/src/geometry/scale.rs index ad09cca57..4a06ac6c7 100755 --- a/src/geometry/scale.rs +++ b/src/geometry/scale.rs @@ -23,13 +23,19 @@ use crate::geometry::Point; derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) )] #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone)] pub struct Scale { /// The scale coordinates, i.e., how much is multiplied to a point's coordinates when it is /// scaled. pub vector: SVector, } +impl fmt::Debug for Scale { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + self.vector.as_slice().fmt(formatter) + } +} + impl hash::Hash for Scale where Owned>: hash::Hash, @@ -364,7 +370,7 @@ where impl fmt::Display for Scale { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if f.alternate() { - crate::display_column_vec_as_row(&self.vector, f) + crate::format_column_vec_as_row(&self.vector, f) } else { std::fmt::Display::fmt(&self.vector, f) // pretty-prints vector } diff --git a/src/geometry/similarity.rs b/src/geometry/similarity.rs index 0a6060acc..cb5e32f09 100755 --- a/src/geometry/similarity.rs +++ b/src/geometry/similarity.rs @@ -398,7 +398,7 @@ where { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{{ translation: ")?; - crate::display_column_vec_as_row(&self.isometry.translation.vector, f)?; + crate::format_column_vec_as_row(&self.isometry.translation.vector, f)?; write!(f, ", ")?; write!(f, "rotation: ")?; std::fmt::Display::fmt(&self.isometry.rotation, f)?; diff --git a/src/geometry/translation.rs b/src/geometry/translation.rs index b910d88b0..2cbff1a06 100755 --- a/src/geometry/translation.rs +++ b/src/geometry/translation.rs @@ -23,13 +23,19 @@ use crate::geometry::Point; derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) )] #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone)] pub struct Translation { /// The translation coordinates, i.e., how much is added to a point's coordinates when it is /// translated. pub vector: SVector, } +impl fmt::Debug for Translation { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + self.vector.as_slice().fmt(formatter) + } +} + impl hash::Hash for Translation where Owned>: hash::Hash, @@ -279,7 +285,7 @@ where impl fmt::Display for Translation { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if f.alternate() { - crate::display_column_vec_as_row(&self.vector, f) + crate::format_column_vec_as_row(&self.vector, f) } else { std::fmt::Display::fmt(&self.vector, f) // pretty-prints vector } From 97e2a8ff44468fc0b129ab88a86313a93470e5b9 Mon Sep 17 00:00:00 2001 From: Owen Brooks Date: Wed, 15 Jun 2022 20:14:37 +1000 Subject: [PATCH 06/16] Simplify Matrix Debug output --- src/base/matrix.rs | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/src/base/matrix.rs b/src/base/matrix.rs index f1417d391..37fc8b14e 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -199,11 +199,10 @@ impl + fmt::Debug> fmt::De for Matrix { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - write!(f, "Matrix {{ ")?; if f.alternate() { - write!(f, "\n ")?; + writeln!(f, "")?; } - write!(f, "data: [")?; + write!(f, "[")?; let nrows = self.nrows(); let ncols = self.ncols(); for i in 0..nrows { @@ -220,22 +219,10 @@ impl + fmt::Debug> fmt::De write!(f, "; ")?; } if f.alternate() && i != nrows - 1 { - write!(f, "\n ")?; + write!(f, "\n ")?; } } - write!(f, "], ")?; - if f.alternate() { - write!(f, "\n ")?; - } - write!(f, "nrows: {:?}, ", nrows)?; - if f.alternate() { - write!(f, "\n ")?; - } - write!(f, "ncols: {:?} ", ncols)?; - if f.alternate() { - writeln!(f, "")?; - } - write!(f, "}}") + write!(f, "]") } } @@ -2028,9 +2015,7 @@ mod tests { ┌ ┐ │ 1e6 2e5 │ │ 2e-5 1e0 │ - └ ┘ - -" + └ ┘" ) } } From 9dffc5bdea6be248b8234c920f3eae5f6610d642 Mon Sep 17 00:00:00 2001 From: Owen Brooks Date: Wed, 15 Jun 2022 20:15:00 +1000 Subject: [PATCH 07/16] Fix Matrix Debug test to match new format --- tests/core/matrix.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/core/matrix.rs b/tests/core/matrix.rs index 8a545e973..5aec8302b 100644 --- a/tests/core/matrix.rs +++ b/tests/core/matrix.rs @@ -78,16 +78,14 @@ fn iter() { } #[test] -fn debug_output_corresponds_to_data_container() { +fn debug_output_semicolon_delimited_rowwise() { let m = Matrix2::new(1.0, 2.0, 3.0, 4.0); - let output_stable = "[[1, 3], [2, 4]]"; // Current output on the stable channel. - let output_nightly = "[[1.0, 3.0], [2.0, 4.0]]"; // Current output on the nightly channel. + let expected_output = "[1.0, 2.0; 3.0, 4.0]"; // Current output on the nightly channel. let current_output = format!("{:?}", m); - dbg!(output_stable); - dbg!(output_nightly); + dbg!(expected_output); dbg!(¤t_output); - assert!(current_output == output_stable || current_output == output_nightly); + assert!(current_output == expected_output); } #[test] From 004091a0bc58ca03dc63c40c22219ffba877e162 Mon Sep 17 00:00:00 2001 From: Owen Brooks Date: Wed, 15 Jun 2022 20:37:37 +1000 Subject: [PATCH 08/16] Fix formatting --- src/base/matrix.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/base/matrix.rs b/src/base/matrix.rs index 37fc8b14e..11c500cd8 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -1880,7 +1880,8 @@ macro_rules! impl_fmt { S: RawStorage, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if !f.alternate() { // pretty print in 2D layout + if !f.alternate() { + // pretty print in 2D layout #[cfg(feature = "std")] fn val_width(val: &T, f: &mut fmt::Formatter<'_>) -> usize { match f.precision() { @@ -1942,7 +1943,8 @@ macro_rules! impl_fmt { "", width = max_length_with_space * ncols - 1 ) - } else { // print on single line with semicolon-delimited rows and comma-delimited columns + } else { + // print on single line with semicolon-delimited rows and comma-delimited columns let (nrows, ncols) = self.shape(); write!(f, "[")?; for row in 0..nrows { From b16a3edbbe5ba68c2178300eaea858775f804e79 Mon Sep 17 00:00:00 2001 From: Owen Brooks Date: Wed, 15 Jun 2022 20:39:03 +1000 Subject: [PATCH 09/16] Fix missing use --- src/base/array_storage.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/base/array_storage.rs b/src/base/array_storage.rs index ae7a2e3bc..bbcf69c99 100644 --- a/src/base/array_storage.rs +++ b/src/base/array_storage.rs @@ -10,6 +10,8 @@ use serde::ser::SerializeSeq; use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde-serialize-no-std")] use std::marker::PhantomData; +#[cfg(feature = "serde-serialize-no-std")] +use std::fmt::{self, Formatter}; use crate::base::allocator::Allocator; use crate::base::default_allocator::DefaultAllocator; From 2dd76fd86e76bb897b7326c5a9972e76396f2fe7 Mon Sep 17 00:00:00 2001 From: Owen Brooks Date: Fri, 17 Jun 2022 17:38:03 +1000 Subject: [PATCH 10/16] Change quaternion debug format back to list form --- src/geometry/quaternion.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/geometry/quaternion.rs b/src/geometry/quaternion.rs index 5d02988a2..03a1312aa 100755 --- a/src/geometry/quaternion.rs +++ b/src/geometry/quaternion.rs @@ -37,11 +37,8 @@ pub struct Quaternion { impl fmt::Debug for Quaternion { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { formatter - .debug_struct("Quaternion") - .field("x", &self.coords[0]) - .field("y", &self.coords[1]) - .field("z", &self.coords[2]) - .field("w", &self.coords[3]) + .debug_list() + .entries(self.coords.iter()) .finish() } } From 699d57d9ddec32823f60b28874d141b98fc23f15 Mon Sep 17 00:00:00 2001 From: Owen Brooks Date: Fri, 17 Jun 2022 17:43:38 +1000 Subject: [PATCH 11/16] Safely get data in matrix Debug formatting --- src/base/matrix.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/base/matrix.rs b/src/base/matrix.rs index 11c500cd8..77e269256 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -210,10 +210,7 @@ impl + fmt::Debug> fmt::De if j != 0 { write!(f, ", ")?; } - // Safety: the indices are within range - unsafe { - (*self.data.get_unchecked(i, j)).fmt(f)?; - } + self[(i, j)].fmt(f)?; } if i != nrows - 1 { write!(f, "; ")?; From 7bc91d3c6822c149ccc84bd0eef22f76830c273d Mon Sep 17 00:00:00 2001 From: Owen Brooks Date: Fri, 17 Jun 2022 17:43:50 +1000 Subject: [PATCH 12/16] Check for empty vector in vector Debug --- src/base/matrix.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/base/matrix.rs b/src/base/matrix.rs index 77e269256..fcdfa2d6d 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -1986,6 +1986,10 @@ pub fn format_column_vec_as_row( where DefaultAllocator: Allocator, { + if vector.is_empty() { + return write!(f, "[ ]"); + } + write!(f, "[")?; let mut it = vector.iter(); std::fmt::Display::fmt(it.next().unwrap(), f)?; From 6df81c2292ee105c8ccfcaca2fdea4232512ccaa Mon Sep 17 00:00:00 2001 From: Owen Brooks Date: Fri, 17 Jun 2022 18:23:59 +1000 Subject: [PATCH 13/16] Add test for formatting of empty matrix --- tests/core/matrix.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/core/matrix.rs b/tests/core/matrix.rs index 5aec8302b..c1278e7e5 100644 --- a/tests/core/matrix.rs +++ b/tests/core/matrix.rs @@ -80,7 +80,7 @@ fn iter() { #[test] fn debug_output_semicolon_delimited_rowwise() { let m = Matrix2::new(1.0, 2.0, 3.0, 4.0); - let expected_output = "[1.0, 2.0; 3.0, 4.0]"; // Current output on the nightly channel. + let expected_output = "[1.0, 2.0; 3.0, 4.0]"; let current_output = format!("{:?}", m); dbg!(expected_output); dbg!(¤t_output); @@ -88,6 +88,18 @@ fn debug_output_semicolon_delimited_rowwise() { assert!(current_output == expected_output); } +#[test] +fn format_empty_matrix() { + let empty_row: [f32; 0] = []; + let m = na::DMatrix::from_row_slice(0, 0, &empty_row); + let expected_output = "[ ]"; + let current_output = format!("{}", m); + dbg!(expected_output); + dbg!(¤t_output); + + assert!(current_output == expected_output); +} + #[test] fn is_column_major() { let a = Matrix2x3::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0); From 76bc230a309405d082d8da352d620d23a091318d Mon Sep 17 00:00:00 2001 From: Owen Brooks Date: Fri, 17 Jun 2022 18:25:50 +1000 Subject: [PATCH 14/16] Fix formatting --- src/base/array_storage.rs | 4 ++-- src/geometry/quaternion.rs | 5 +---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/base/array_storage.rs b/src/base/array_storage.rs index bbcf69c99..53f8efbe7 100644 --- a/src/base/array_storage.rs +++ b/src/base/array_storage.rs @@ -9,9 +9,9 @@ use serde::ser::SerializeSeq; #[cfg(feature = "serde-serialize-no-std")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "serde-serialize-no-std")] -use std::marker::PhantomData; -#[cfg(feature = "serde-serialize-no-std")] use std::fmt::{self, Formatter}; +#[cfg(feature = "serde-serialize-no-std")] +use std::marker::PhantomData; use crate::base::allocator::Allocator; use crate::base::default_allocator::DefaultAllocator; diff --git a/src/geometry/quaternion.rs b/src/geometry/quaternion.rs index 03a1312aa..0898cfc29 100755 --- a/src/geometry/quaternion.rs +++ b/src/geometry/quaternion.rs @@ -36,10 +36,7 @@ pub struct Quaternion { impl fmt::Debug for Quaternion { fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - formatter - .debug_list() - .entries(self.coords.iter()) - .finish() + formatter.debug_list().entries(self.coords.iter()).finish() } } From 364302d072fec7548a266e470c9e6d4a5c28b8a6 Mon Sep 17 00:00:00 2001 From: Owen Brooks Date: Fri, 17 Jun 2022 18:41:26 +1000 Subject: [PATCH 15/16] Add debug format to matrix format test --- tests/core/matrix.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/tests/core/matrix.rs b/tests/core/matrix.rs index c1278e7e5..8030b47ea 100644 --- a/tests/core/matrix.rs +++ b/tests/core/matrix.rs @@ -92,12 +92,19 @@ fn debug_output_semicolon_delimited_rowwise() { fn format_empty_matrix() { let empty_row: [f32; 0] = []; let m = na::DMatrix::from_row_slice(0, 0, &empty_row); - let expected_output = "[ ]"; - let current_output = format!("{}", m); - dbg!(expected_output); - dbg!(¤t_output); - - assert!(current_output == expected_output); + let expected_output_display = "[ ]"; + let expected_output_debug = "[]"; + let current_output_display = format!("{}", m); + let current_output_debug = format!("{:?}", m); + dbg!(expected_output_display); + dbg!(expected_output_debug); + dbg!(¤t_output_debug); + dbg!(¤t_output_display); + + assert!( + current_output_display == expected_output_display + && current_output_debug == expected_output_debug + ); } #[test] From e70bcdbe22cfcf90473818fdd49e8c7634a52fca Mon Sep 17 00:00:00 2001 From: Owen Brooks Date: Fri, 17 Jun 2022 18:41:53 +1000 Subject: [PATCH 16/16] Fix possible overflow in matrix debug formatting --- src/base/matrix.rs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/base/matrix.rs b/src/base/matrix.rs index fcdfa2d6d..7998ff22c 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -203,20 +203,21 @@ impl + fmt::Debug> fmt::De writeln!(f, "")?; } write!(f, "[")?; - let nrows = self.nrows(); - let ncols = self.ncols(); - for i in 0..nrows { - for j in 0..ncols { - if j != 0 { + + let row_separator = match f.alternate() { + true => ";\n ", + false => "; ", + }; + + for (i, row) in self.row_iter().enumerate() { + if i > 0 { + write!(f, "{row_separator}")?; + } + for (j, element) in row.iter().enumerate() { + if j > 0 { write!(f, ", ")?; } - self[(i, j)].fmt(f)?; - } - if i != nrows - 1 { - write!(f, "; ")?; - } - if f.alternate() && i != nrows - 1 { - write!(f, "\n ")?; + element.fmt(f)?; } } write!(f, "]")