Simplify and standardise formatting of geometry types

This commit is contained in:
Owen Brooks 2022-06-15 13:47:55 +10:00
parent f77f556481
commit 807e4c153a
8 changed files with 89 additions and 94 deletions

View File

@ -1968,6 +1968,21 @@ impl_fmt!(fmt::UpperHex, "{:X}", "{:1$X}");
impl_fmt!(fmt::Binary, "{:b}", "{:.1$b}"); impl_fmt!(fmt::Binary, "{:b}", "{:.1$b}");
impl_fmt!(fmt::Pointer, "{:p}", "{:.1$p}"); impl_fmt!(fmt::Pointer, "{:p}", "{:.1$p}");
/// Displays a vector using commas as the delimiter
pub fn display_column_vec_as_row<T: Scalar + fmt::Display, D: crate::DimName>(vector: &OVector<T, D>, f: &mut fmt::Formatter<'_>) -> fmt::Result
where
DefaultAllocator: Allocator<T, D>,
{
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)] #[cfg(test)]
mod tests { mod tests {
#[test] #[test]

View File

@ -951,25 +951,12 @@ impl<T: RealField> Default for UnitDualQuaternion<T> {
impl<T: RealField + fmt::Display> fmt::Display for UnitDualQuaternion<T> { impl<T: RealField + fmt::Display> fmt::Display for UnitDualQuaternion<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if let Some(axis) = self.rotation().axis() { write!(f, "{{ translation: ")?;
let axis = axis.into_inner(); crate::display_column_vec_as_row(&self.translation().vector, f)?;
write!( write!(f, ", ")?;
f, write!(f, "rotation: ")?;
"UnitDualQuaternion translation: {} angle: {} axis: ({}, {}, {})", std::fmt::Display::fmt(&self.rotation(), f)?;
self.translation().vector, write!(f, " }}")
self.rotation().angle(),
axis[0],
axis[1],
axis[2]
)
} else {
write!(
f,
"UnitDualQuaternion translation: {} angle: {} axis: (undefined)",
self.translation().vector,
self.rotation().angle()
)
}
} }
} }

View File

@ -548,11 +548,11 @@ where
R: fmt::Display, R: fmt::Display,
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let precision = f.precision().unwrap_or(3); write!(f, "{{ translation: ")?;
crate::display_column_vec_as_row(&self.translation.vector, f)?;
writeln!(f, "Isometry {{")?; write!(f, ", ")?;
write!(f, "{:.*}", precision, self.translation)?; write!(f, "rotation: ")?;
write!(f, "{:.*}", precision, self.rotation)?; std::fmt::Display::fmt(&self.rotation, f)?;
writeln!(f, "}}") write!(f, " }}")
} }
} }

View File

@ -35,7 +35,7 @@ use std::mem::MaybeUninit;
/// may have some other methods, e.g., `isometry.inverse_transform_point(&point)`. See the documentation /// may have some other methods, e.g., `isometry.inverse_transform_point(&point)`. See the documentation
/// of said transformations for details. /// of said transformations for details.
#[repr(C)] #[repr(C)]
#[derive(Clone)] #[derive(Clone, Debug)]
#[cfg_attr( #[cfg_attr(
feature = "rkyv-serialize-no-std", feature = "rkyv-serialize-no-std",
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
@ -49,15 +49,6 @@ where
pub coords: OVector<T, D>, pub coords: OVector<T, D>,
} }
impl<T: Scalar + fmt::Debug, D: DimName> fmt::Debug for OPoint<T, D>
where
DefaultAllocator: Allocator<T, D>,
{
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
self.coords.as_slice().fmt(formatter)
}
}
impl<T: Scalar + hash::Hash, D: DimName> hash::Hash for OPoint<T, D> impl<T: Scalar + hash::Hash, D: DimName> hash::Hash for OPoint<T, D>
where where
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
@ -457,17 +448,19 @@ impl<T: Scalar + fmt::Display, D: DimName> fmt::Display for OPoint<T, D>
where where
DefaultAllocator: Allocator<T, D>, DefaultAllocator: Allocator<T, D>,
{ {
/// ```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 { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{{")?; if f.alternate() {
crate::display_column_vec_as_row(&self.coords, f)
let mut it = self.coords.iter(); } else {
std::fmt::Display::fmt(&self.coords, f) // pretty-prints vector
write!(f, "{}", *it.next().unwrap())?; }
for comp in it {
write!(f, ", {}", *comp)?;
}
write!(f, "}}")
} }
} }

View File

@ -36,7 +36,13 @@ pub struct Quaternion<T> {
impl<T: fmt::Debug> fmt::Debug for Quaternion<T> { impl<T: fmt::Debug> fmt::Debug for Quaternion<T> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { 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<T: RealField + UlpsEq<Epsilon = T>> UlpsEq for Quaternion<T> {
impl<T: RealField + fmt::Display> fmt::Display for Quaternion<T> { impl<T: RealField + fmt::Display> fmt::Display for Quaternion<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!( // Formatting of each item is forwarded to standard fmt display so that formatting
f, // flags are followed correctly.
"Quaternion {} ({}, {}, {})", std::fmt::Display::fmt(&self[0], f)?;
self[3], self[0], self[1], self[2] 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<T: RealField> Default for UnitQuaternion<T> {
impl<T: RealField + fmt::Display> fmt::Display for UnitQuaternion<T> { impl<T: RealField + fmt::Display> fmt::Display for UnitQuaternion<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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() { if let Some(axis) = self.axis() {
let axis = axis.into_inner(); let axis = axis.into_inner();
write!( std::fmt::Display::fmt(&axis[0], f)?;
f, write!(f, ", ")?;
"UnitQuaternion angle: {} axis: ({}, {}, {})", std::fmt::Display::fmt(&axis[1], f)?;
self.angle(), write!(f, ", ")?;
axis[0], std::fmt::Display::fmt(&axis[2], f)?;
axis[1],
axis[2]
)
} else { } else {
write!( write!(f, "undefined")?;
f,
"UnitQuaternion angle: {} axis: (undefined)",
self.angle()
)
} }
write!(f, ") }}")
} }
} }

View File

@ -23,19 +23,13 @@ use crate::geometry::Point;
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)] )]
#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))]
#[derive(Copy, Clone)] #[derive(Copy, Clone, Debug)]
pub struct Scale<T, const D: usize> { pub struct Scale<T, const D: usize> {
/// The scale coordinates, i.e., how much is multiplied to a point's coordinates when it is /// The scale coordinates, i.e., how much is multiplied to a point's coordinates when it is
/// scaled. /// scaled.
pub vector: SVector<T, D>, pub vector: SVector<T, D>,
} }
impl<T: fmt::Debug, const D: usize> fmt::Debug for Scale<T, D> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
self.vector.as_slice().fmt(formatter)
}
}
impl<T: Scalar + hash::Hash, const D: usize> hash::Hash for Scale<T, D> impl<T: Scalar + hash::Hash, const D: usize> hash::Hash for Scale<T, D>
where where
Owned<T, Const<D>>: hash::Hash, Owned<T, Const<D>>: hash::Hash,
@ -369,10 +363,10 @@ where
*/ */
impl<T: Scalar + fmt::Display, const D: usize> fmt::Display for Scale<T, D> { impl<T: Scalar + fmt::Display, const D: usize> fmt::Display for Scale<T, D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let precision = f.precision().unwrap_or(3); if f.alternate() {
crate::display_column_vec_as_row(&self.vector, f)
writeln!(f, "Scale {{")?; } else {
write!(f, "{:.*}", precision, self.vector)?; std::fmt::Display::fmt(&self.vector, f) // pretty-prints vector
writeln!(f, "}}") }
} }
} }

View File

@ -397,11 +397,13 @@ where
R: AbstractRotation<T, D> + fmt::Display, R: AbstractRotation<T, D> + fmt::Display,
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let precision = f.precision().unwrap_or(3); write!(f, "{{ translation: ")?;
crate::display_column_vec_as_row(&self.isometry.translation.vector, f)?;
writeln!(f, "Similarity {{")?; write!(f, ", ")?;
write!(f, "{:.*}", precision, self.isometry)?; write!(f, "rotation: ")?;
write!(f, "Scaling: {:.*}", precision, self.scaling)?; std::fmt::Display::fmt(&self.isometry.rotation, f)?;
writeln!(f, "}}") write!(f, ", scaling: ")?;
std::fmt::Display::fmt(&self.scaling, f)?;
write!(f, " }}")
} }
} }

View File

@ -23,19 +23,13 @@ use crate::geometry::Point;
derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize)
)] )]
#[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))]
#[derive(Copy, Clone)] #[derive(Copy, Clone, Debug)]
pub struct Translation<T, const D: usize> { pub struct Translation<T, const D: usize> {
/// The translation coordinates, i.e., how much is added to a point's coordinates when it is /// The translation coordinates, i.e., how much is added to a point's coordinates when it is
/// translated. /// translated.
pub vector: SVector<T, D>, pub vector: SVector<T, D>,
} }
impl<T: fmt::Debug, const D: usize> fmt::Debug for Translation<T, D> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
self.vector.as_slice().fmt(formatter)
}
}
impl<T: Scalar + hash::Hash, const D: usize> hash::Hash for Translation<T, D> impl<T: Scalar + hash::Hash, const D: usize> hash::Hash for Translation<T, D>
where where
Owned<T, Const<D>>: hash::Hash, Owned<T, Const<D>>: hash::Hash,
@ -284,10 +278,10 @@ where
*/ */
impl<T: Scalar + fmt::Display, const D: usize> fmt::Display for Translation<T, D> { impl<T: Scalar + fmt::Display, const D: usize> fmt::Display for Translation<T, D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let precision = f.precision().unwrap_or(3); if f.alternate() {
crate::display_column_vec_as_row(&self.vector, f)
writeln!(f, "Translation {{")?; } else {
write!(f, "{:.*}", precision, self.vector)?; std::fmt::Display::fmt(&self.vector, f) // pretty-prints vector
writeln!(f, "}}") }
} }
} }