From 4ce6555b965660b75528b6ba8111eec6e705b10f Mon Sep 17 00:00:00 2001 From: sebcrozet Date: Sat, 27 Oct 2018 11:00:11 +0200 Subject: [PATCH] Add more point and quaternion documentation. --- src/geometry/point.rs | 48 +++++ src/geometry/point_construction.rs | 13 +- src/geometry/quaternion.rs | 324 ++++++++++++++++++++++++++--- 3 files changed, 358 insertions(+), 27 deletions(-) diff --git a/src/geometry/point.rs b/src/geometry/point.rs index 6c9cd904..8499fddc 100644 --- a/src/geometry/point.rs +++ b/src/geometry/point.rs @@ -106,12 +106,26 @@ where DefaultAllocator: Allocator { /// Clones this point into one that owns its data. #[inline] + #[deprecated(note = "This will be removed. Use the `.clone()` method from the `Clone` trait instead.")] pub fn clone(&self) -> Point { Point::from(self.coords.clone_owned()) } /// Converts this point into a vector in homogeneous coordinates, i.e., appends a `1` at the /// end of it. + /// + /// This is the same as `.into()`. + /// + /// # Example + /// ``` + /// # use nalgebra::{Point2, Point3, Vector3, Vector4}; + /// let p = Point2::new(10.0, 20.0); + /// assert_eq!(p.to_homogeneous(), Vector3::new(10.0, 20.0, 1.0)); + /// + /// // This works in any dimension. + /// let p = Point3::new(10.0, 20.0, 30.0); + /// assert_eq!(p.to_homogeneous(), Vector4::new(10.0, 20.0, 30.0, 1.0)); + /// ``` #[inline] pub fn to_homogeneous(&self) -> VectorN> where @@ -134,6 +148,17 @@ where DefaultAllocator: Allocator } /// The dimension of this point. + /// + /// # Example + /// ``` + /// # use nalgebra::{Point2, Point3}; + /// let p = Point2::new(1.0, 2.0); + /// assert_eq!(p.len(), 2); + /// + /// // This works in any dimension. + /// let p = Point3::new(10.0, 20.0, 30.0); + /// assert_eq!(p.len(), 3); + /// ``` #[inline] pub fn len(&self) -> usize { self.coords.len() @@ -142,11 +167,23 @@ where DefaultAllocator: Allocator /// The stride of this point. This is the number of buffer element separating each component of /// this point. #[inline] + #[deprecated(note = "This methods is no longer significant and will always return 1.")] pub fn stride(&self) -> usize { self.coords.strides().0 } /// Iterates through this point coordinates. + /// + /// # Example + /// ``` + /// # use nalgebra::Point3; + /// let p = Point3::new(1.0, 2.0, 3.0); + /// let mut it = p.iter().cloned(); + /// + /// assert_eq!(it.next(), Some(1.0)); + /// assert_eq!(it.next(), Some(2.0)); + /// assert_eq!(it.next(), Some(3.0)); + /// assert_eq!(it.next(), None); #[inline] pub fn iter(&self) -> MatrixIter>::Buffer> { self.coords.iter() @@ -159,6 +196,17 @@ where DefaultAllocator: Allocator } /// Mutably iterates through this point coordinates. + /// + /// # Example + /// ``` + /// # use nalgebra::Point3; + /// let mut p = Point3::new(1.0, 2.0, 3.0); + /// + /// for e in p.iter_mut() { + /// *e *= 10.0; + /// } + /// + /// assert_eq!(p, Point3::new(10.0, 20.0, 30.0)); #[inline] pub fn iter_mut( &mut self, diff --git a/src/geometry/point_construction.rs b/src/geometry/point_construction.rs index 5a16b7a3..9f380912 100644 --- a/src/geometry/point_construction.rs +++ b/src/geometry/point_construction.rs @@ -155,10 +155,13 @@ where * */ macro_rules! componentwise_constructors_impl( - ($($D: ty, $($args: ident:$irow: expr),*);* $(;)*) => {$( + ($($doc: expr; $D: ty, $($args: ident:$irow: expr),*);* $(;)*) => {$( impl Point where DefaultAllocator: Allocator { - /// Initializes this matrix from its components. + #[doc = "Initializes this matrix from its components."] + #[doc = "# Example\n```"] + #[doc = $doc] + #[doc = "```"] #[inline] pub fn new($($args: N),*) -> Point { unsafe { @@ -173,11 +176,17 @@ macro_rules! componentwise_constructors_impl( ); componentwise_constructors_impl!( + "# use nalgebra::Point1;\nlet p = Point1::new(1.0);\nassert!(p.x == 1.0);"; U1, x:0; + "# use nalgebra::Point2;\nlet p = Point2::new(1.0, 2.0);\nassert!(p.x == 1.0 && p.y == 2.0);"; U2, x:0, y:1; + "# use nalgebra::Point3;\nlet p = Point3::new(1.0, 2.0, 3.0);\nassert!(p.x == 1.0 && p.y == 2.0 && p.z == 3.0);"; U3, x:0, y:1, z:2; + "# use nalgebra::Point4;\nlet p = Point4::new(1.0, 2.0, 3.0, 4.0);\nassert!(p.x == 1.0 && p.y == 2.0 && p.z == 3.0 && p.w == 4.0);"; U4, x:0, y:1, z:2, w:3; + "# use nalgebra::Point5;\nlet p = Point5::new(1.0, 2.0, 3.0, 4.0, 5.0);\nassert!(p.x == 1.0 && p.y == 2.0 && p.z == 3.0 && p.w == 4.0 && p.a == 5.0);"; U5, x:0, y:1, z:2, w:3, a:4; + "# use nalgebra::Point6;\nlet p = Point6::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);\nassert!(p.x == 1.0 && p.y == 2.0 && p.z == 3.0 && p.w == 4.0 && p.a == 5.0 && p.b == 6.0);"; U6, x:0, y:1, z:2, w:3, a:4, b:5; ); diff --git a/src/geometry/quaternion.rs b/src/geometry/quaternion.rs index 6fb70d2b..cb5c87ab 100644 --- a/src/geometry/quaternion.rs +++ b/src/geometry/quaternion.rs @@ -110,12 +110,30 @@ impl Quaternion { } /// Normalizes this quaternion. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # extern crate nalgebra; + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let q_normalized = q.normalize(); + /// relative_eq!(q_normalized.norm(), 1.0); + /// ``` #[inline] pub fn normalize(&self) -> Quaternion { Quaternion::from_vector(self.coords.normalize()) } - /// Compute the conjugate of this quaternion. + /// The conjugate of this quaternion. + /// + /// # Example + /// ``` + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let conj = q.conjugate(); + /// assert!(conj.i == -2.0 && conj.j == -3.0 && conj.k == -4.0 && conj.w == 1.0); + /// ``` #[inline] pub fn conjugate(&self) -> Quaternion { let v = Vector4::new( @@ -128,6 +146,24 @@ impl Quaternion { } /// Inverts this quaternion if it is not zero. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # extern crate nalgebra; + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let inv_q = q.try_inverse(); + /// + /// assert!(inv_q.is_some()); + /// assert_relative_eq!(inv_q.unwrap() * q, Quaternion::identity()); + /// + /// //Non-invertible case + /// let q = Quaternion::new(0.0, 0.0, 0.0, 0.0); + /// let inv_q = q.try_inverse(); + /// + /// assert!(inv_q.is_none()); + /// ``` #[inline] pub fn try_inverse(&self) -> Option> { let mut res = Quaternion::from_vector(self.coords.clone_owned()); @@ -140,30 +176,75 @@ impl Quaternion { } /// Linear interpolation between two quaternion. + /// + /// Computes `self * (1 - t) + other * t`. + /// + /// # Example + /// ``` + /// # use nalgebra::Quaternion; + /// let q1 = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let q2 = Quaternion::new(10.0, 20.0, 30.0, 40.0); + /// + /// assert_eq!(q1.lerp(&q2, 0.1), Quaternion::new(1.9, 3.8, 5.7, 7.6)); + /// ``` #[inline] pub fn lerp(&self, other: &Quaternion, t: N) -> Quaternion { self * (N::one() - t) + other * t } /// The vector part `(i, j, k)` of this quaternion. + /// + /// # Example + /// ``` + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// assert_eq!(q.vector()[0], 2.0); + /// assert_eq!(q.vector()[1], 3.0); + /// assert_eq!(q.vector()[2], 4.0); + /// ``` #[inline] pub fn vector(&self) -> MatrixSlice, CStride> { self.coords.fixed_rows::(0) } /// The scalar part `w` of this quaternion. + /// + /// # Example + /// ``` + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// assert_eq!(q.scalar(), 1.0); + /// ``` #[inline] pub fn scalar(&self) -> N { self.coords[3] } /// Reinterprets this quaternion as a 4D vector. + /// + /// # Example + /// ``` + /// # use nalgebra::{Vector4, Quaternion}; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// // Recall that the quaternion is stored internally as (i, j, k, w) + /// // while the ::new constructor takes the arguments as (w, i, j, k). + /// assert_eq!(*q.as_vector(), Vector4::new(2.0, 3.0, 4.0, 1.0)); + /// ``` #[inline] pub fn as_vector(&self) -> &Vector4 { &self.coords } /// The norm of this quaternion. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # extern crate nalgebra; + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// assert_relative_eq!(q.norm(), 5.47722557, epsilon = 1.0e-6); + /// ``` #[inline] pub fn norm(&self) -> N { self.coords.norm() @@ -172,30 +253,59 @@ impl Quaternion { /// A synonym for the norm of this quaternion. /// /// Aka the length. + /// This is the same as `.norm()` /// - /// This function is simply implemented as a call to `norm()` + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # extern crate nalgebra; + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// assert_relative_eq!(q.magnitude(), 5.47722557, epsilon = 1.0e-6); + /// ``` #[inline] pub fn magnitude(&self) -> N { self.norm() } - /// A synonym for the squared norm of this quaternion. - /// - /// Aka the squared length. - /// - /// This function is simply implemented as a call to `norm_squared()` - #[inline] - pub fn magnitude_squared(&self) -> N { - self.norm_squared() - } - /// The squared norm of this quaternion. + /// + /// # Example + /// ``` + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// assert_eq!(q.magnitude_squared(), 30.0); + /// ``` #[inline] pub fn norm_squared(&self) -> N { self.coords.norm_squared() } + /// A synonym for the squared norm of this quaternion. + /// + /// Aka the squared length. + /// This is the same as `.norm_squared()` + /// + /// # Example + /// ``` + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// assert_eq!(q.magnitude_squared(), 30.0); + /// ``` + #[inline] + pub fn magnitude_squared(&self) -> N { + self.norm_squared() + } + /// The dot product of two quaternions. + /// + /// # Example + /// ``` + /// # use nalgebra::Quaternion; + /// let q1 = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// let q2 = Quaternion::new(5.0, 6.0, 7.0, 8.0); + /// assert_eq!(q1.dot(&q2), 70.0); + /// ``` #[inline] pub fn dot(&self, rhs: &Self) -> N { self.coords.dot(&rhs.coords) @@ -205,6 +315,17 @@ impl Quaternion { /// /// Returns, from left to right: the quaternion norm, the half rotation angle, the rotation /// axis. If the rotation angle is zero, the rotation axis is set to `None`. + /// + /// # Example + /// ``` + /// # use std::f32; + /// # use nalgebra::{Vector3, Quaternion}; + /// let q = Quaternion::new(0.0, 5.0, 0.0, 0.0); + /// let (norm, half_ang, axis) = q.polar_decomposition(); + /// assert_eq!(norm, 5.0); + /// assert_eq!(half_ang, f32::consts::FRAC_PI_2); + /// assert_eq!(axis, Some(Vector3::x_axis())); + /// ``` pub fn polar_decomposition(&self) -> (N, N, Option>>) { if let Some((q, n)) = Unit::try_new_and_get(*self, N::zero()) { if let Some(axis) = Unit::try_new(self.vector().clone_owned(), N::zero()) { @@ -219,13 +340,55 @@ impl Quaternion { } } + /// Compute the natural logarithm of a quaternion. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # extern crate nalgebra; + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(2.0, 5.0, 0.0, 0.0); + /// assert_relative_eq!(q.ln(), Quaternion::new(1.683647, 1.190289, 0.0, 0.0), epsilon = 1.0e-6) + /// ``` + #[inline] + pub fn ln(&self) -> Quaternion { + let n = self.norm(); + let v = self.vector(); + let s = self.scalar(); + + Quaternion::from_parts(n.ln(), v.normalize() * (s / n).acos()) + } + /// Compute the exponential of a quaternion. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # extern crate nalgebra; + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.683647, 1.190289, 0.0, 0.0); + /// assert_relative_eq!(q.exp(), Quaternion::new(2.0, 5.0, 0.0, 0.0), epsilon = 1.0e-5) + /// ``` #[inline] pub fn exp(&self) -> Quaternion { self.exp_eps(N::default_epsilon()) } - /// Compute the exponential of a quaternion. + /// Compute the exponential of a quaternion. Returns the identity if the vector part of this quaternion + /// has a norm smaller than `eps`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # extern crate nalgebra; + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.683647, 1.190289, 0.0, 0.0); + /// assert_relative_eq!(q.exp_eps(1.0e-6), Quaternion::new(2.0, 5.0, 0.0, 0.0), epsilon = 1.0e-5); + /// + /// // Singular case. + /// let q = Quaternion::new(0.0000001, 0.0, 0.0, 0.0); + /// assert_eq!(q.exp_eps(1.0e-6), Quaternion::identity()); + /// ``` #[inline] pub fn exp_eps(&self, eps: N) -> Quaternion { let v = self.vector(); @@ -238,33 +401,54 @@ impl Quaternion { let n = nn.sqrt(); let nv = v * (w_exp * n.sin() / n); - Quaternion::from_parts(n.cos(), nv) + Quaternion::from_parts(w_exp * n.cos(), nv) } } - /// Compute the natural logarithm of a quaternion. - #[inline] - pub fn ln(&self) -> Quaternion { - let n = self.norm(); - let v = self.vector(); - let s = self.scalar(); - - Quaternion::from_parts(n.ln(), v.normalize() * (s / n).acos()) - } /// Raise the quaternion to a given floating power. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # extern crate nalgebra; + /// # use nalgebra::Quaternion; + /// let q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// assert_relative_eq!(q.powf(1.5), Quaternion::new( -6.2576659, 4.1549037, 6.2323556, 8.3098075), epsilon = 1.0e-6); + /// ``` #[inline] pub fn powf(&self, n: N) -> Quaternion { (self.ln() * n).exp() } /// Transforms this quaternion into its 4D vector form (Vector part, Scalar part). + /// + /// # Example + /// ``` + /// # use nalgebra::{Quaternion, Vector4}; + /// let mut q = Quaternion::identity(); + /// *q.as_vector_mut() = Vector4::new(1.0, 2.0, 3.0, 4.0); + /// assert!(q.i == 1.0 && q.j == 2.0 && q.k == 3.0 && q.w == 4.0); + /// ``` #[inline] pub fn as_vector_mut(&mut self) -> &mut Vector4 { &mut self.coords } /// The mutable vector part `(i, j, k)` of this quaternion. + /// + /// # Example + /// ``` + /// # use nalgebra::{Quaternion, Vector4}; + /// let mut q = Quaternion::identity(); + /// { + /// let mut v = q.vector_mut(); + /// v[0] = 2.0; + /// v[1] = 3.0; + /// v[2] = 4.0; + /// } + /// assert!(q.i == 2.0 && q.j == 3.0 && q.k == 4.0 && q.w == 1.0); + /// ``` #[inline] pub fn vector_mut( &mut self, @@ -273,6 +457,14 @@ impl Quaternion { } /// Replaces this quaternion by its conjugate. + /// + /// # Example + /// ``` + /// # use nalgebra::Quaternion; + /// let mut q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// q.conjugate_mut(); + /// assert!(q.i == -2.0 && q.j == -3.0 && q.k == -4.0 && q.w == 1.0); + /// ``` #[inline] pub fn conjugate_mut(&mut self) { self.coords[0] = -self.coords[0]; @@ -281,6 +473,21 @@ impl Quaternion { } /// Inverts this quaternion in-place if it is not zero. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # extern crate nalgebra; + /// # use nalgebra::Quaternion; + /// let mut q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// + /// assert!(q.try_inverse_mut()); + /// assert_relative_eq!(q * Quaternion::new(1.0, 2.0, 3.0, 4.0), Quaternion::identity()); + /// + /// //Non-invertible case + /// let mut q = Quaternion::new(0.0, 0.0, 0.0, 0.0); + /// assert!(!q.try_inverse_mut()); + /// ``` #[inline] pub fn try_inverse_mut(&mut self) -> bool { let norm_squared = self.norm_squared(); @@ -296,6 +503,16 @@ impl Quaternion { } /// Normalizes this quaternion. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # extern crate nalgebra; + /// # use nalgebra::Quaternion; + /// let mut q = Quaternion::new(1.0, 2.0, 3.0, 4.0); + /// q.normalize_mut(); + /// assert_relative_eq!(q.norm(), 1.0); + /// ``` #[inline] pub fn normalize_mut(&mut self) -> N { self.coords.normalize_mut() @@ -368,19 +585,27 @@ pub type UnitQuaternion = Unit>; impl UnitQuaternion { /// Moves this unit quaternion into one that owns its data. #[inline] - #[deprecated(note = "This method is a no-op and will be removed in a future release.")] + #[deprecated(note = "This method is unnecessary and will be removed in a future release. Use `.clone()` instead.")] pub fn into_owned(self) -> UnitQuaternion { self } /// Clones this unit quaternion into one that owns its data. #[inline] - #[deprecated(note = "This method is a no-op and will be removed in a future release.")] + #[deprecated(note = "This method is unnecessary and will be removed in a future release. Use `.clone()` instead.")] pub fn clone_owned(&self) -> UnitQuaternion { *self } /// The rotation angle in [0; pi] of this unit quaternion. + /// + /// # Example + /// ``` + /// # use nalgebra::{Unit, UnitQuaternion, Vector3}; + /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); + /// let rot = UnitQuaternion::from_axis_angle(&axis, 1.78); + /// assert_eq!(rot.angle(), 1.78); + /// ``` #[inline] pub fn angle(&self) -> N { let w = self.quaternion().scalar().abs(); @@ -396,24 +621,60 @@ impl UnitQuaternion { /// The underlying quaternion. /// /// Same as `self.as_ref()`. + /// + /// # Example + /// ``` + /// # use nalgebra::{UnitQuaternion, Quaternion}; + /// let axis = UnitQuaternion::identity(); + /// assert_eq!(*axis.quaternion(), Quaternion::new(1.0, 0.0, 0.0, 0.0)); + /// ``` #[inline] pub fn quaternion(&self) -> &Quaternion { self.as_ref() } /// Compute the conjugate of this unit quaternion. + /// + /// # Example + /// ``` + /// # use nalgebra::{Unit, UnitQuaternion, Vector3}; + /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); + /// let rot = UnitQuaternion::from_axis_angle(&axis, 1.78); + /// let conj = rot.conjugate(); + /// assert_eq!(conj, UnitQuaternion::from_axis_angle(&-axis, 1.78)); + /// ``` #[inline] pub fn conjugate(&self) -> UnitQuaternion { UnitQuaternion::new_unchecked(self.as_ref().conjugate()) } /// Inverts this quaternion if it is not zero. + /// + /// # Example + /// ``` + /// # use nalgebra::{Unit, UnitQuaternion, Vector3}; + /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0)); + /// let rot = UnitQuaternion::from_axis_angle(&axis, 1.78); + /// let inv = rot.inverse(); + /// assert_eq!(rot * inv, UnitQuaternion::identity()); + /// assert_eq!(inv * rot, UnitQuaternion::identity()); + /// ``` #[inline] pub fn inverse(&self) -> UnitQuaternion { self.conjugate() } /// The rotation angle needed to make `self` and `other` coincide. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # extern crate nalgebra; + /// # use nalgebra::{UnitQuaternion, Vector3}; + /// let rot1 = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 1.0); + /// let rot2 = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 0.1); + /// assert_relative_eq!(rot1.angle_to(&rot2), 1.0045657, epsilon = 1.0e-6); + /// ``` #[inline] pub fn angle_to(&self, other: &UnitQuaternion) -> N { let delta = self.rotation_to(other); @@ -423,6 +684,17 @@ impl UnitQuaternion { /// The unit quaternion needed to make `self` and `other` coincide. /// /// The result is such that: `self.rotation_to(other) * self == other`. + /// + /// # Example + /// ``` + /// # #[macro_use] extern crate approx; + /// # extern crate nalgebra; + /// # use nalgebra::{UnitQuaternion, Vector3}; + /// let rot1 = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), 1.0); + /// let rot2 = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), 0.1); + /// let rot_to = rot1.rotation_to(&rot2); + /// assert_relative_eq!(rot_to * rot1, rot2, epsilon = 1.0e-6); + /// ``` #[inline] pub fn rotation_to(&self, other: &UnitQuaternion) -> UnitQuaternion { other / self @@ -437,6 +709,8 @@ impl UnitQuaternion { } /// Normalized linear interpolation between two unit quaternions. + /// + /// This is the same as `self.lerp` except that the result is normalized. #[inline] pub fn nlerp(&self, other: &UnitQuaternion, t: N) -> UnitQuaternion { let mut res = self.lerp(other, t);