nalgebra/geometry/
rotation_specialization.rs

1#[cfg(feature = "arbitrary")]
2use crate::base::storage::Owned;
3#[cfg(feature = "arbitrary")]
4use quickcheck::{Arbitrary, Gen};
5
6use num::Zero;
7
8#[cfg(feature = "rand-no-std")]
9use rand::{
10    Rng,
11    distr::{Distribution, OpenClosed01, StandardUniform, Uniform, uniform::SampleUniform},
12};
13
14use simba::scalar::RealField;
15use simba::simd::{SimdBool, SimdRealField};
16use std::ops::Neg;
17
18use crate::base::dimension::{U1, U2, U3};
19use crate::base::storage::Storage;
20use crate::base::{
21    Matrix2, Matrix3, SMatrix, SVector, Unit, UnitVector3, Vector, Vector1, Vector2, Vector3,
22};
23
24use crate::geometry::{Rotation2, Rotation3, UnitComplex, UnitQuaternion};
25
26/*
27 *
28 * 2D Rotation matrix.
29 *
30 */
31/// # Construction from a 2D rotation angle
32impl<T: SimdRealField> Rotation2<T> {
33    /// Builds a 2 dimensional rotation matrix from an angle in radian.
34    ///
35    /// # Example
36    ///
37    /// ```
38    /// # #[macro_use] extern crate approx;
39    /// # use std::f32;
40    /// # use nalgebra::{Rotation2, Point2};
41    /// let rot = Rotation2::new(f32::consts::FRAC_PI_2);
42    ///
43    /// assert_relative_eq!(rot * Point2::new(3.0, 4.0), Point2::new(-4.0, 3.0));
44    /// ```
45    pub fn new(angle: T) -> Self {
46        let (sia, coa) = angle.simd_sin_cos();
47        Self::from_matrix_unchecked(Matrix2::new(coa.clone(), -sia.clone(), sia, coa))
48    }
49
50    /// Builds a 2 dimensional rotation matrix from an angle in radian wrapped in a 1-dimensional vector.
51    ///
52    ///
53    /// This is generally used in the context of generic programming. Using
54    /// the `::new(angle)` method instead is more common.
55    #[inline]
56    pub fn from_scaled_axis<SB: Storage<T, U1>>(axisangle: Vector<T, U1, SB>) -> Self {
57        Self::new(axisangle[0].clone())
58    }
59}
60
61/// # Construction from an existing 2D matrix or rotations
62impl<T: SimdRealField> Rotation2<T> {
63    /// Builds a rotation from a basis assumed to be orthonormal.
64    ///
65    /// In order to get a valid rotation matrix, the input must be an
66    /// orthonormal basis, i.e., all vectors are normalized, and the are
67    /// all orthogonal to each other. These invariants are not checked
68    /// by this method.
69    pub fn from_basis_unchecked(basis: &[Vector2<T>; 2]) -> Self {
70        let mat = Matrix2::from_columns(&basis[..]);
71        Self::from_matrix_unchecked(mat)
72    }
73
74    /// Builds a rotation matrix by extracting the rotation part of the given transformation `m`.
75    ///
76    /// This is an iterative method. See `.from_matrix_eps` to provide mover
77    /// convergence parameters and starting solution.
78    /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al.
79    pub fn from_matrix(m: &Matrix2<T>) -> Self
80    where
81        T: RealField,
82    {
83        Self::from_matrix_eps(m, T::default_epsilon(), 0, Self::identity())
84    }
85
86    /// Builds a rotation matrix by extracting the rotation part of the given transformation `m`.
87    ///
88    /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al.
89    ///
90    /// # Parameters
91    ///
92    /// * `m`: the matrix from which the rotational part is to be extracted.
93    /// * `eps`: the angular errors tolerated between the current rotation and the optimal one.
94    /// * `max_iter`: the maximum number of iterations. Loops indefinitely until convergence if set to `0`.
95    /// * `guess`: an estimate of the solution. Convergence will be significantly faster if an initial solution close
96    ///   to the actual solution is provided. Can be set to `Rotation2::identity()` if no other
97    ///   guesses come to mind.
98    pub fn from_matrix_eps(m: &Matrix2<T>, eps: T, mut max_iter: usize, guess: Self) -> Self
99    where
100        T: RealField,
101    {
102        if max_iter == 0 {
103            max_iter = usize::MAX;
104        }
105
106        let mut rot = guess.into_inner();
107
108        for _ in 0..max_iter {
109            let axis = rot.column(0).perp(&m.column(0)) + rot.column(1).perp(&m.column(1));
110            let denom = rot.column(0).dot(&m.column(0)) + rot.column(1).dot(&m.column(1));
111
112            let angle = axis / (denom.abs() + T::default_epsilon());
113            if angle.clone().abs() > eps {
114                rot = Self::new(angle) * rot;
115            } else {
116                break;
117            }
118        }
119
120        Self::from_matrix_unchecked(rot)
121    }
122
123    /// The rotation matrix required to align `a` and `b` but with its angle.
124    ///
125    /// This is the rotation `R` such that `(R * a).angle(b) == 0 && (R * a).dot(b).is_positive()`.
126    ///
127    /// # Example
128    /// ```
129    /// # #[macro_use] extern crate approx;
130    /// # use nalgebra::{Vector2, Rotation2};
131    /// let a = Vector2::new(1.0, 2.0);
132    /// let b = Vector2::new(2.0, 1.0);
133    /// let rot = Rotation2::rotation_between(&a, &b);
134    /// assert_relative_eq!(rot * a, b);
135    /// assert_relative_eq!(rot.inverse() * b, a);
136    /// ```
137    #[inline]
138    pub fn rotation_between<SB, SC>(a: &Vector<T, U2, SB>, b: &Vector<T, U2, SC>) -> Self
139    where
140        T: RealField,
141        SB: Storage<T, U2>,
142        SC: Storage<T, U2>,
143    {
144        crate::convert(UnitComplex::rotation_between(a, b).to_rotation_matrix())
145    }
146
147    /// The smallest rotation needed to make `a` and `b` collinear and point toward the same
148    /// direction, raised to the power `s`.
149    ///
150    /// # Example
151    /// ```
152    /// # #[macro_use] extern crate approx;
153    /// # use nalgebra::{Vector2, Rotation2};
154    /// let a = Vector2::new(1.0, 2.0);
155    /// let b = Vector2::new(2.0, 1.0);
156    /// let rot2 = Rotation2::scaled_rotation_between(&a, &b, 0.2);
157    /// let rot5 = Rotation2::scaled_rotation_between(&a, &b, 0.5);
158    /// assert_relative_eq!(rot2 * rot2 * rot2 * rot2 * rot2 * a, b, epsilon = 1.0e-6);
159    /// assert_relative_eq!(rot5 * rot5 * a, b, epsilon = 1.0e-6);
160    /// ```
161    #[inline]
162    pub fn scaled_rotation_between<SB, SC>(
163        a: &Vector<T, U2, SB>,
164        b: &Vector<T, U2, SC>,
165        s: T,
166    ) -> Self
167    where
168        T: RealField,
169        SB: Storage<T, U2>,
170        SC: Storage<T, U2>,
171    {
172        crate::convert(UnitComplex::scaled_rotation_between(a, b, s).to_rotation_matrix())
173    }
174
175    /// The rotation matrix needed to make `self` and `other` coincide.
176    ///
177    /// The result is such that: `self.rotation_to(other) * self == other`.
178    ///
179    /// # Example
180    /// ```
181    /// # #[macro_use] extern crate approx;
182    /// # use nalgebra::Rotation2;
183    /// let rot1 = Rotation2::new(0.1);
184    /// let rot2 = Rotation2::new(1.7);
185    /// let rot_to = rot1.rotation_to(&rot2);
186    ///
187    /// assert_relative_eq!(rot_to * rot1, rot2);
188    /// assert_relative_eq!(rot_to.inverse() * rot2, rot1);
189    /// ```
190    #[inline]
191    #[must_use]
192    pub fn rotation_to(&self, other: &Self) -> Self {
193        other * self.inverse()
194    }
195
196    /// Ensure this rotation is an orthonormal rotation matrix. This is useful when repeated
197    /// computations might cause the matrix from progressively not being orthonormal anymore.
198    #[inline]
199    pub fn renormalize(&mut self)
200    where
201        T: RealField,
202    {
203        let mut c = UnitComplex::from(self.clone());
204        let _ = c.renormalize();
205
206        *self = Self::from_matrix_eps(self.matrix(), T::default_epsilon(), 0, c.into())
207    }
208
209    /// Raise the rotation to a given floating power, i.e., returns the rotation with the angle
210    /// of `self` multiplied by `n`.
211    ///
212    /// # Example
213    /// ```
214    /// # #[macro_use] extern crate approx;
215    /// # use nalgebra::Rotation2;
216    /// let rot = Rotation2::new(0.78);
217    /// let pow = rot.powf(2.0);
218    /// assert_relative_eq!(pow.angle(), 2.0 * 0.78);
219    /// ```
220    #[inline]
221    #[must_use]
222    pub fn powf(&self, n: T) -> Self {
223        Self::new(self.angle() * n)
224    }
225}
226
227/// # 2D angle extraction
228impl<T: SimdRealField> Rotation2<T> {
229    /// The rotation angle.
230    ///
231    /// # Example
232    /// ```
233    /// # #[macro_use] extern crate approx;
234    /// # use nalgebra::Rotation2;
235    /// let rot = Rotation2::new(1.78);
236    /// assert_relative_eq!(rot.angle(), 1.78);
237    /// ```
238    #[inline]
239    #[must_use]
240    pub fn angle(&self) -> T {
241        self.matrix()[(1, 0)]
242            .clone()
243            .simd_atan2(self.matrix()[(0, 0)].clone())
244    }
245
246    /// The rotation angle needed to make `self` and `other` coincide.
247    ///
248    /// # Example
249    /// ```
250    /// # #[macro_use] extern crate approx;
251    /// # use nalgebra::Rotation2;
252    /// let rot1 = Rotation2::new(0.1);
253    /// let rot2 = Rotation2::new(1.7);
254    /// assert_relative_eq!(rot1.angle_to(&rot2), 1.6);
255    /// ```
256    #[inline]
257    #[must_use]
258    pub fn angle_to(&self, other: &Self) -> T {
259        self.rotation_to(other).angle()
260    }
261
262    /// The rotation angle returned as a 1-dimensional vector.
263    ///
264    /// This is generally used in the context of generic programming. Using
265    /// the `.angle()` method instead is more common.
266    #[inline]
267    #[must_use]
268    pub fn scaled_axis(&self) -> SVector<T, 1> {
269        Vector1::new(self.angle())
270    }
271}
272
273#[cfg(feature = "rand-no-std")]
274impl<T: SimdRealField> Distribution<Rotation2<T>> for StandardUniform
275where
276    T::Element: SimdRealField,
277    T: SampleUniform,
278{
279    /// Generate a uniformly distributed random rotation.
280    #[inline]
281    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Rotation2<T> {
282        let twopi = Uniform::new(T::zero(), T::simd_two_pi())
283            .expect("Failed to construct `Uniform`, should be unreachable");
284
285        Rotation2::new(rng.sample(twopi))
286    }
287}
288
289#[cfg(feature = "arbitrary")]
290impl<T: SimdRealField + Arbitrary> Arbitrary for Rotation2<T>
291where
292    T::Element: SimdRealField,
293    Owned<T, U2, U2>: Send,
294{
295    #[inline]
296    fn arbitrary(g: &mut Gen) -> Self {
297        Self::new(T::arbitrary(g))
298    }
299}
300
301/*
302 *
303 * 3D Rotation matrix.
304 *
305 */
306/// # Construction from a 3D axis and/or angles
307impl<T: SimdRealField> Rotation3<T>
308where
309    T::Element: SimdRealField,
310{
311    /// Builds a 3 dimensional rotation matrix from an axis and an angle.
312    ///
313    /// # Arguments
314    ///   * `axisangle` - A vector representing the rotation. Its magnitude is the amount of rotation
315    ///     in radian. Its direction is the axis of rotation.
316    ///
317    /// # Example
318    /// ```
319    /// # #[macro_use] extern crate approx;
320    /// # use std::f32;
321    /// # use nalgebra::{Rotation3, Point3, Vector3};
322    /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
323    /// // Point and vector being transformed in the tests.
324    /// let pt = Point3::new(4.0, 5.0, 6.0);
325    /// let vec = Vector3::new(4.0, 5.0, 6.0);
326    /// let rot = Rotation3::new(axisangle);
327    ///
328    /// assert_relative_eq!(rot * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
329    /// assert_relative_eq!(rot * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
330    ///
331    /// // A zero vector yields an identity.
332    /// assert_eq!(Rotation3::new(Vector3::<f32>::zeros()), Rotation3::identity());
333    /// ```
334    pub fn new<SB: Storage<T, U3>>(axisangle: Vector<T, U3, SB>) -> Self {
335        let axisangle = axisangle.into_owned();
336        let (axis, angle) = Unit::new_and_get(axisangle);
337        Self::from_axis_angle(&axis, angle)
338    }
339
340    /// Builds a 3D rotation matrix from an axis scaled by the rotation angle.
341    ///
342    /// This is the same as `Self::new(axisangle)`.
343    ///
344    /// # Example
345    /// ```
346    /// # #[macro_use] extern crate approx;
347    /// # use std::f32;
348    /// # use nalgebra::{Rotation3, Point3, Vector3};
349    /// let axisangle = Vector3::y() * f32::consts::FRAC_PI_2;
350    /// // Point and vector being transformed in the tests.
351    /// let pt = Point3::new(4.0, 5.0, 6.0);
352    /// let vec = Vector3::new(4.0, 5.0, 6.0);
353    /// let rot = Rotation3::new(axisangle);
354    ///
355    /// assert_relative_eq!(rot * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
356    /// assert_relative_eq!(rot * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
357    ///
358    /// // A zero vector yields an identity.
359    /// assert_eq!(Rotation3::from_scaled_axis(Vector3::<f32>::zeros()), Rotation3::identity());
360    /// ```
361    pub fn from_scaled_axis<SB: Storage<T, U3>>(axisangle: Vector<T, U3, SB>) -> Self {
362        Self::new(axisangle)
363    }
364
365    /// Builds a 3D rotation matrix from an axis and a rotation angle.
366    ///
367    /// # Example
368    /// ```
369    /// # #[macro_use] extern crate approx;
370    /// # use std::f32;
371    /// # use nalgebra::{Rotation3, Point3, Vector3};
372    /// let axis = Vector3::y_axis();
373    /// let angle = f32::consts::FRAC_PI_2;
374    /// // Point and vector being transformed in the tests.
375    /// let pt = Point3::new(4.0, 5.0, 6.0);
376    /// let vec = Vector3::new(4.0, 5.0, 6.0);
377    /// let rot = Rotation3::from_axis_angle(&axis, angle);
378    ///
379    /// assert_eq!(rot.axis().unwrap(), axis);
380    /// assert_eq!(rot.angle(), angle);
381    /// assert_relative_eq!(rot * pt, Point3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
382    /// assert_relative_eq!(rot * vec, Vector3::new(6.0, 5.0, -4.0), epsilon = 1.0e-6);
383    ///
384    /// // A zero vector yields an identity.
385    /// assert_eq!(Rotation3::from_scaled_axis(Vector3::<f32>::zeros()), Rotation3::identity());
386    /// ```
387    pub fn from_axis_angle<SB>(axis: &Unit<Vector<T, U3, SB>>, angle: T) -> Self
388    where
389        SB: Storage<T, U3>,
390    {
391        angle.clone().simd_ne(T::zero()).if_else(
392            || {
393                let ux = axis.as_ref()[0].clone();
394                let uy = axis.as_ref()[1].clone();
395                let uz = axis.as_ref()[2].clone();
396                let sqx = ux.clone() * ux.clone();
397                let sqy = uy.clone() * uy.clone();
398                let sqz = uz.clone() * uz.clone();
399                let (sin, cos) = angle.simd_sin_cos();
400                let one_m_cos = T::one() - cos.clone();
401
402                Self::from_matrix_unchecked(SMatrix::<T, 3, 3>::new(
403                    sqx.clone() + (T::one() - sqx) * cos.clone(),
404                    ux.clone() * uy.clone() * one_m_cos.clone() - uz.clone() * sin.clone(),
405                    ux.clone() * uz.clone() * one_m_cos.clone() + uy.clone() * sin.clone(),
406                    ux.clone() * uy.clone() * one_m_cos.clone() + uz.clone() * sin.clone(),
407                    sqy.clone() + (T::one() - sqy) * cos.clone(),
408                    uy.clone() * uz.clone() * one_m_cos.clone() - ux.clone() * sin.clone(),
409                    ux.clone() * uz.clone() * one_m_cos.clone() - uy.clone() * sin.clone(),
410                    uy * uz * one_m_cos + ux * sin,
411                    sqz.clone() + (T::one() - sqz) * cos,
412                ))
413            },
414            Self::identity,
415        )
416    }
417
418    /// Creates a new rotation from Euler angles.
419    ///
420    /// The primitive rotations are applied in order: 1 roll − 2 pitch − 3 yaw.
421    ///
422    /// # Example
423    /// ```
424    /// # #[macro_use] extern crate approx;
425    /// # use nalgebra::Rotation3;
426    /// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3);
427    /// let euler = rot.euler_angles();
428    /// assert_relative_eq!(euler.0, 0.1, epsilon = 1.0e-6);
429    /// assert_relative_eq!(euler.1, 0.2, epsilon = 1.0e-6);
430    /// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6);
431    /// ```
432    pub fn from_euler_angles(roll: T, pitch: T, yaw: T) -> Self {
433        let (sr, cr) = roll.simd_sin_cos();
434        let (sp, cp) = pitch.simd_sin_cos();
435        let (sy, cy) = yaw.simd_sin_cos();
436
437        Self::from_matrix_unchecked(SMatrix::<T, 3, 3>::new(
438            cy.clone() * cp.clone(),
439            cy.clone() * sp.clone() * sr.clone() - sy.clone() * cr.clone(),
440            cy.clone() * sp.clone() * cr.clone() + sy.clone() * sr.clone(),
441            sy.clone() * cp.clone(),
442            sy.clone() * sp.clone() * sr.clone() + cy.clone() * cr.clone(),
443            sy * sp.clone() * cr.clone() - cy * sr.clone(),
444            -sp,
445            cp.clone() * sr,
446            cp * cr,
447        ))
448    }
449}
450
451/// # Construction from a 3D eye position and target point
452impl<T: SimdRealField> Rotation3<T>
453where
454    T::Element: SimdRealField,
455{
456    /// Creates a rotation that corresponds to the local frame of an observer standing at the
457    /// origin and looking toward `dir`.
458    ///
459    /// It maps the `z` axis to the direction `dir`.
460    ///
461    /// # Arguments
462    ///   * dir - The look direction, that is, direction the matrix `z` axis will be aligned with.
463    ///   * up - The vertical direction. The only requirement of this parameter is to not be
464    ///     collinear to `dir`. Non-collinearity is not checked.
465    ///
466    /// # Example
467    /// ```
468    /// # #[macro_use] extern crate approx;
469    /// # use std::f32;
470    /// # use nalgebra::{Rotation3, Vector3};
471    /// let dir = Vector3::new(1.0, 2.0, 3.0);
472    /// let up = Vector3::y();
473    ///
474    /// let rot = Rotation3::face_towards(&dir, &up);
475    /// assert_relative_eq!(rot * Vector3::z(), dir.normalize());
476    /// ```
477    #[inline]
478    pub fn face_towards<SB, SC>(dir: &Vector<T, U3, SB>, up: &Vector<T, U3, SC>) -> Self
479    where
480        SB: Storage<T, U3>,
481        SC: Storage<T, U3>,
482    {
483        // Gram–Schmidt process
484        let zaxis = dir.normalize();
485        let xaxis = up.cross(&zaxis).normalize();
486        let yaxis = zaxis.cross(&xaxis);
487
488        Self::from_matrix_unchecked(SMatrix::<T, 3, 3>::new(
489            xaxis.x.clone(),
490            yaxis.x.clone(),
491            zaxis.x.clone(),
492            xaxis.y.clone(),
493            yaxis.y.clone(),
494            zaxis.y.clone(),
495            xaxis.z.clone(),
496            yaxis.z.clone(),
497            zaxis.z.clone(),
498        ))
499    }
500
501    /// Deprecated: Use [`Rotation3::face_towards`] instead.
502    #[deprecated(note = "renamed to `face_towards`")]
503    pub fn new_observer_frames<SB, SC>(dir: &Vector<T, U3, SB>, up: &Vector<T, U3, SC>) -> Self
504    where
505        SB: Storage<T, U3>,
506        SC: Storage<T, U3>,
507    {
508        Self::face_towards(dir, up)
509    }
510
511    /// Builds a right-handed look-at view matrix without translation.
512    ///
513    /// It maps the view direction `dir` to the **negative** `z` axis.
514    /// This conforms to the common notion of right handed look-at matrix from the computer
515    /// graphics community.
516    ///
517    /// # Arguments
518    ///   * dir - The direction toward which the camera looks.
519    ///   * up - A vector approximately aligned with required the vertical axis. The only
520    ///     requirement of this parameter is to not be collinear to `dir`.
521    ///
522    /// # Example
523    /// ```
524    /// # #[macro_use] extern crate approx;
525    /// # use std::f32;
526    /// # use nalgebra::{Rotation3, Vector3};
527    /// let dir = Vector3::new(1.0, 2.0, 3.0);
528    /// let up = Vector3::y();
529    ///
530    /// let rot = Rotation3::look_at_rh(&dir, &up);
531    /// assert_relative_eq!(rot * dir.normalize(), -Vector3::z());
532    /// ```
533    #[inline]
534    pub fn look_at_rh<SB, SC>(dir: &Vector<T, U3, SB>, up: &Vector<T, U3, SC>) -> Self
535    where
536        SB: Storage<T, U3>,
537        SC: Storage<T, U3>,
538    {
539        Self::face_towards(&dir.neg(), up).inverse()
540    }
541
542    /// Builds a left-handed look-at view matrix without translation.
543    ///
544    /// It maps the view direction `dir` to the **positive** `z` axis.
545    /// This conforms to the common notion of left handed look-at matrix from the computer
546    /// graphics community.
547    ///
548    /// # Arguments
549    ///   * dir - The direction toward which the camera looks.
550    ///   * up - A vector approximately aligned with required the vertical axis. The only
551    ///     requirement of this parameter is to not be collinear to `dir`.
552    ///
553    /// # Example
554    /// ```
555    /// # #[macro_use] extern crate approx;
556    /// # use std::f32;
557    /// # use nalgebra::{Rotation3, Vector3};
558    /// let dir = Vector3::new(1.0, 2.0, 3.0);
559    /// let up = Vector3::y();
560    ///
561    /// let rot = Rotation3::look_at_lh(&dir, &up);
562    /// assert_relative_eq!(rot * dir.normalize(), Vector3::z());
563    /// ```
564    #[inline]
565    pub fn look_at_lh<SB, SC>(dir: &Vector<T, U3, SB>, up: &Vector<T, U3, SC>) -> Self
566    where
567        SB: Storage<T, U3>,
568        SC: Storage<T, U3>,
569    {
570        Self::face_towards(dir, up).inverse()
571    }
572}
573
574/// # Construction from an existing 3D matrix or rotations
575impl<T: SimdRealField> Rotation3<T>
576where
577    T::Element: SimdRealField,
578{
579    /// The rotation matrix required to align `a` and `b` but with its angle.
580    ///
581    /// This is the rotation `R` such that `(R * a).angle(b) == 0 && (R * a).dot(b).is_positive()`.
582    ///
583    /// # Example
584    /// ```
585    /// # #[macro_use] extern crate approx;
586    /// # use nalgebra::{Vector3, Rotation3};
587    /// let a = Vector3::new(1.0, 2.0, 3.0);
588    /// let b = Vector3::new(3.0, 1.0, 2.0);
589    /// let rot = Rotation3::rotation_between(&a, &b).unwrap();
590    /// assert_relative_eq!(rot * a, b, epsilon = 1.0e-6);
591    /// assert_relative_eq!(rot.inverse() * b, a, epsilon = 1.0e-6);
592    /// ```
593    #[inline]
594    pub fn rotation_between<SB, SC>(a: &Vector<T, U3, SB>, b: &Vector<T, U3, SC>) -> Option<Self>
595    where
596        T: RealField,
597        SB: Storage<T, U3>,
598        SC: Storage<T, U3>,
599    {
600        Self::scaled_rotation_between(a, b, T::one())
601    }
602
603    /// The smallest rotation needed to make `a` and `b` collinear and point toward the same
604    /// direction, raised to the power `s`.
605    ///
606    /// # Example
607    /// ```
608    /// # #[macro_use] extern crate approx;
609    /// # use nalgebra::{Vector3, Rotation3};
610    /// let a = Vector3::new(1.0, 2.0, 3.0);
611    /// let b = Vector3::new(3.0, 1.0, 2.0);
612    /// let rot2 = Rotation3::scaled_rotation_between(&a, &b, 0.2).unwrap();
613    /// let rot5 = Rotation3::scaled_rotation_between(&a, &b, 0.5).unwrap();
614    /// assert_relative_eq!(rot2 * rot2 * rot2 * rot2 * rot2 * a, b, epsilon = 1.0e-6);
615    /// assert_relative_eq!(rot5 * rot5 * a, b, epsilon = 1.0e-6);
616    /// ```
617    #[inline]
618    pub fn scaled_rotation_between<SB, SC>(
619        a: &Vector<T, U3, SB>,
620        b: &Vector<T, U3, SC>,
621        n: T,
622    ) -> Option<Self>
623    where
624        T: RealField,
625        SB: Storage<T, U3>,
626        SC: Storage<T, U3>,
627    {
628        // TODO: code duplication with Rotation.
629        if let (Some(na), Some(nb)) = (a.try_normalize(T::zero()), b.try_normalize(T::zero())) {
630            let c = na.cross(&nb);
631
632            if let Some(axis) = Unit::try_new(c, T::default_epsilon()) {
633                return Some(Self::from_axis_angle(&axis, na.dot(&nb).acos() * n));
634            }
635
636            // Zero or PI.
637            if na.dot(&nb) < T::zero() {
638                // PI
639                //
640                // The rotation axis is undefined but the angle not zero. This is not a
641                // simple rotation.
642                return None;
643            }
644        }
645
646        Some(Self::identity())
647    }
648
649    /// The rotation matrix needed to make `self` and `other` coincide.
650    ///
651    /// The result is such that: `self.rotation_to(other) * self == other`.
652    ///
653    /// # Example
654    /// ```
655    /// # #[macro_use] extern crate approx;
656    /// # use nalgebra::{Rotation3, Vector3};
657    /// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0);
658    /// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1);
659    /// let rot_to = rot1.rotation_to(&rot2);
660    /// assert_relative_eq!(rot_to * rot1, rot2, epsilon = 1.0e-6);
661    /// ```
662    #[inline]
663    #[must_use]
664    pub fn rotation_to(&self, other: &Self) -> Self {
665        other * self.inverse()
666    }
667
668    /// Raise the rotation to a given floating power, i.e., returns the rotation with the same
669    /// axis as `self` and an angle equal to `self.angle()` multiplied by `n`.
670    ///
671    /// # Example
672    /// ```
673    /// # #[macro_use] extern crate approx;
674    /// # use nalgebra::{Rotation3, Vector3, Unit};
675    /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
676    /// let angle = 1.2;
677    /// let rot = Rotation3::from_axis_angle(&axis, angle);
678    /// let pow = rot.powf(2.0);
679    /// assert_relative_eq!(pow.axis().unwrap(), axis, epsilon = 1.0e-6);
680    /// assert_eq!(pow.angle(), 2.4);
681    /// ```
682    #[inline]
683    #[must_use]
684    pub fn powf(&self, n: T) -> Self
685    where
686        T: RealField,
687    {
688        match self.axis() {
689            Some(axis) => Self::from_axis_angle(&axis, self.angle() * n),
690            None => {
691                if self.matrix()[(0, 0)] < T::zero() {
692                    let minus_id = SMatrix::<T, 3, 3>::from_diagonal_element(-T::one());
693                    Self::from_matrix_unchecked(minus_id)
694                } else {
695                    Self::identity()
696                }
697            }
698        }
699    }
700
701    /// Builds a rotation from a basis assumed to be orthonormal.
702    ///
703    /// In order to get a valid rotation matrix, the input must be an
704    /// orthonormal basis, i.e., all vectors are normalized, and the are
705    /// all orthogonal to each other. These invariants are not checked
706    /// by this method.
707    pub fn from_basis_unchecked(basis: &[Vector3<T>; 3]) -> Self {
708        let mat = Matrix3::from_columns(&basis[..]);
709        Self::from_matrix_unchecked(mat)
710    }
711
712    /// Builds a rotation matrix by extracting the rotation part of the given transformation `m`.
713    ///
714    /// This is an iterative method. See `.from_matrix_eps` to provide mover
715    /// convergence parameters and starting solution.
716    /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al.
717    pub fn from_matrix(m: &Matrix3<T>) -> Self
718    where
719        T: RealField,
720    {
721        Self::from_matrix_eps(m, T::default_epsilon(), 0, Self::identity())
722    }
723
724    /// Builds a rotation matrix by extracting the rotation part of the given transformation `m`.
725    ///
726    /// This implements "A Robust Method to Extract the Rotational Part of Deformations" by Müller et al.
727    ///
728    /// # Parameters
729    ///
730    /// * `m`: the matrix from which the rotational part is to be extracted.
731    /// * `eps`: the angular errors tolerated between the current rotation and the optimal one.
732    /// * `max_iter`: the maximum number of iterations. Loops indefinitely until convergence if set to `0`.
733    /// * `guess`: a guess of the solution. Convergence will be significantly faster if an initial solution close
734    ///   to the actual solution is provided. Can be set to `Rotation3::identity()` if no other
735    ///   guesses come to mind.
736    pub fn from_matrix_eps(m: &Matrix3<T>, eps: T, mut max_iter: usize, guess: Self) -> Self
737    where
738        T: RealField,
739    {
740        if max_iter == 0 {
741            max_iter = usize::MAX;
742        }
743
744        // Using sqrt(eps) ensures we perturb with something larger than eps; clamp to eps to handle the case of eps > 1.0
745        let eps_disturbance = eps.clone().sqrt().max(eps.clone() * eps.clone());
746        let mut perturbation_axes = Vector3::x_axis();
747        let mut rot = guess.into_inner();
748
749        for _ in 0..max_iter {
750            let axis = rot.column(0).cross(&m.column(0))
751                + rot.column(1).cross(&m.column(1))
752                + rot.column(2).cross(&m.column(2));
753            let denom = rot.column(0).dot(&m.column(0))
754                + rot.column(1).dot(&m.column(1))
755                + rot.column(2).dot(&m.column(2));
756
757            let axisangle = axis / (denom.abs() + T::default_epsilon());
758
759            match Unit::try_new_and_get(axisangle, eps.clone()) {
760                Some((axis, angle)) => {
761                    rot = Rotation3::from_axis_angle(&axis, angle) * rot;
762                }
763                None => {
764                    // Check if stuck in a maximum w.r.t. the norm (m - rot).norm()
765                    let mut perturbed = rot.clone();
766                    let norm_squared = (m - &rot).norm_squared();
767                    let mut new_norm_squared: T;
768
769                    // Perturb until the new norm is significantly different
770                    loop {
771                        perturbed *=
772                            Rotation3::from_axis_angle(&perturbation_axes, eps_disturbance.clone());
773                        new_norm_squared = (m - &perturbed).norm_squared();
774                        if abs_diff_ne!(
775                            norm_squared,
776                            new_norm_squared,
777                            epsilon = T::default_epsilon()
778                        ) {
779                            break;
780                        }
781                    }
782
783                    // If new norm is larger, it's a minimum
784                    if norm_squared < new_norm_squared {
785                        break;
786                    }
787
788                    // If not, continue from perturbed rotation, but use a different axes for the next perturbation
789                    perturbation_axes = UnitVector3::new_unchecked(perturbation_axes.yzx());
790                    rot = perturbed;
791                }
792            }
793        }
794
795        Self::from_matrix_unchecked(rot)
796    }
797
798    /// Ensure this rotation is an orthonormal rotation matrix. This is useful when repeated
799    /// computations might cause the matrix from progressively not being orthonormal anymore.
800    #[inline]
801    pub fn renormalize(&mut self)
802    where
803        T: RealField,
804    {
805        let mut c = UnitQuaternion::from(self.clone());
806        let _ = c.renormalize();
807
808        *self = Self::from_matrix_eps(self.matrix(), T::default_epsilon(), 0, c.into())
809    }
810}
811
812/// # 3D axis and angle extraction
813impl<T: SimdRealField> Rotation3<T> {
814    /// The rotation angle in [0; pi].
815    ///
816    /// # Example
817    /// ```
818    /// # #[macro_use] extern crate approx;
819    /// # use nalgebra::{Unit, Rotation3, Vector3};
820    /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
821    /// let rot = Rotation3::from_axis_angle(&axis, 1.78);
822    /// assert_relative_eq!(rot.angle(), 1.78);
823    /// ```
824    #[inline]
825    #[must_use]
826    pub fn angle(&self) -> T {
827        ((self.matrix()[(0, 0)].clone()
828            + self.matrix()[(1, 1)].clone()
829            + self.matrix()[(2, 2)].clone()
830            - T::one())
831            / crate::convert(2.0))
832        .simd_acos()
833    }
834
835    /// The rotation axis. Returns `None` if the rotation angle is zero or PI.
836    ///
837    /// # Example
838    /// ```
839    /// # #[macro_use] extern crate approx;
840    /// # use nalgebra::{Rotation3, Vector3, Unit};
841    /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
842    /// let angle = 1.2;
843    /// let rot = Rotation3::from_axis_angle(&axis, angle);
844    /// assert_relative_eq!(rot.axis().unwrap(), axis);
845    ///
846    /// // Case with a zero angle.
847    /// let rot = Rotation3::from_axis_angle(&axis, 0.0);
848    /// assert!(rot.axis().is_none());
849    /// ```
850    #[inline]
851    #[must_use]
852    pub fn axis(&self) -> Option<Unit<Vector3<T>>>
853    where
854        T: RealField,
855    {
856        let rotmat = self.matrix();
857        let axis = SVector::<T, 3>::new(
858            rotmat[(2, 1)].clone() - rotmat[(1, 2)].clone(),
859            rotmat[(0, 2)].clone() - rotmat[(2, 0)].clone(),
860            rotmat[(1, 0)].clone() - rotmat[(0, 1)].clone(),
861        );
862
863        Unit::try_new(axis, T::default_epsilon())
864    }
865
866    /// The rotation axis multiplied by the rotation angle.
867    ///
868    /// # Example
869    /// ```
870    /// # #[macro_use] extern crate approx;
871    /// # use nalgebra::{Rotation3, Vector3, Unit};
872    /// let axisangle = Vector3::new(0.1, 0.2, 0.3);
873    /// let rot = Rotation3::new(axisangle);
874    /// assert_relative_eq!(rot.scaled_axis(), axisangle, epsilon = 1.0e-6);
875    /// ```
876    #[inline]
877    #[must_use]
878    pub fn scaled_axis(&self) -> Vector3<T>
879    where
880        T: RealField,
881    {
882        match self.axis() {
883            Some(axis) => axis.into_inner() * self.angle(),
884            None => Vector::zero(),
885        }
886    }
887
888    /// The rotation axis and angle in (0, pi] of this rotation matrix.
889    ///
890    /// Returns `None` if the angle is zero.
891    ///
892    /// # Example
893    /// ```
894    /// # #[macro_use] extern crate approx;
895    /// # use nalgebra::{Rotation3, Vector3, Unit};
896    /// let axis = Unit::new_normalize(Vector3::new(1.0, 2.0, 3.0));
897    /// let angle = 1.2;
898    /// let rot = Rotation3::from_axis_angle(&axis, angle);
899    /// let axis_angle = rot.axis_angle().unwrap();
900    /// assert_relative_eq!(axis_angle.0, axis);
901    /// assert_relative_eq!(axis_angle.1, angle);
902    ///
903    /// // Case with a zero angle.
904    /// let rot = Rotation3::from_axis_angle(&axis, 0.0);
905    /// assert!(rot.axis_angle().is_none());
906    /// ```
907    #[inline]
908    #[must_use]
909    pub fn axis_angle(&self) -> Option<(Unit<Vector3<T>>, T)>
910    where
911        T: RealField,
912    {
913        self.axis().map(|axis| (axis, self.angle()))
914    }
915
916    /// The rotation angle needed to make `self` and `other` coincide.
917    ///
918    /// # Example
919    /// ```
920    /// # #[macro_use] extern crate approx;
921    /// # use nalgebra::{Rotation3, Vector3};
922    /// let rot1 = Rotation3::from_axis_angle(&Vector3::y_axis(), 1.0);
923    /// let rot2 = Rotation3::from_axis_angle(&Vector3::x_axis(), 0.1);
924    /// assert_relative_eq!(rot1.angle_to(&rot2), 1.0045657, epsilon = 1.0e-6);
925    /// ```
926    #[inline]
927    #[must_use]
928    pub fn angle_to(&self, other: &Self) -> T
929    where
930        T::Element: SimdRealField,
931    {
932        self.rotation_to(other).angle()
933    }
934
935    /// Creates Euler angles from a rotation.
936    ///
937    /// The angles are produced in the form (roll, pitch, yaw).
938    #[deprecated(note = "This is renamed to use `.euler_angles()`.")]
939    pub fn to_euler_angles(self) -> (T, T, T)
940    where
941        T: RealField,
942    {
943        self.euler_angles()
944    }
945
946    /// Euler angles corresponding to this rotation from a rotation.
947    ///
948    /// The angles are produced in the form (roll, pitch, yaw).
949    ///
950    /// # Example
951    /// ```
952    /// # #[macro_use] extern crate approx;
953    /// # use nalgebra::Rotation3;
954    /// let rot = Rotation3::from_euler_angles(0.1, 0.2, 0.3);
955    /// let euler = rot.euler_angles();
956    /// assert_relative_eq!(euler.0, 0.1, epsilon = 1.0e-6);
957    /// assert_relative_eq!(euler.1, 0.2, epsilon = 1.0e-6);
958    /// assert_relative_eq!(euler.2, 0.3, epsilon = 1.0e-6);
959    /// ```
960    #[must_use]
961    pub fn euler_angles(&self) -> (T, T, T)
962    where
963        T: RealField,
964    {
965        // Implementation informed by "Computing Euler angles from a rotation matrix", by Gregory G. Slabaugh
966        //  https://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.371.6578
967        //  where roll, pitch, yaw angles are referred to as ψ, θ, ϕ,
968        if self[(2, 0)].clone().abs() < T::one() {
969            let pitch = -self[(2, 0)].clone().asin();
970            let theta_cos = pitch.clone().cos();
971            let roll = (self[(2, 1)].clone() / theta_cos.clone())
972                .atan2(self[(2, 2)].clone() / theta_cos.clone());
973            let yaw =
974                (self[(1, 0)].clone() / theta_cos.clone()).atan2(self[(0, 0)].clone() / theta_cos);
975            (roll, pitch, yaw)
976        } else if self[(2, 0)].clone() <= -T::one() {
977            (
978                self[(0, 1)].clone().atan2(self[(0, 2)].clone()),
979                T::frac_pi_2(),
980                T::zero(),
981            )
982        } else {
983            (
984                -self[(0, 1)].clone().atan2(-self[(0, 2)].clone()),
985                -T::frac_pi_2(),
986                T::zero(),
987            )
988        }
989    }
990
991    /// Represent this rotation as Euler angles.
992    ///
993    /// Returns the angles produced in the order provided by seq parameter, along with the
994    /// observability flag. The Euler axes passed to seq must form an orthonormal basis. If the
995    /// rotation is gimbal locked, then the observability flag is false.
996    ///
997    /// # Panics
998    ///
999    /// Panics if the Euler axes in `seq` are not orthonormal.
1000    ///
1001    /// # Example 1:
1002    /// ```
1003    /// use std::f64::consts::PI;
1004    /// use approx::assert_relative_eq;
1005    /// use nalgebra::{Matrix3, Rotation3, Unit, Vector3};
1006    ///
1007    /// // 3-1-2
1008    /// let n = [
1009    ///     Unit::new_unchecked(Vector3::new(0.0, 0.0, 1.0)),
1010    ///     Unit::new_unchecked(Vector3::new(1.0, 0.0, 0.0)),
1011    ///     Unit::new_unchecked(Vector3::new(0.0, 1.0, 0.0)),
1012    /// ];
1013    ///
1014    /// let r1 = Rotation3::from_axis_angle(&n[2], 20.0 * PI / 180.0);
1015    /// let r2 = Rotation3::from_axis_angle(&n[1], 30.0 * PI / 180.0);
1016    /// let r3 = Rotation3::from_axis_angle(&n[0], 45.0 * PI / 180.0);
1017    ///
1018    /// let d = r3 * r2 * r1;
1019    ///
1020    /// let (angles, observable) = d.euler_angles_ordered(n, false);
1021    /// assert!(observable);
1022    /// assert_relative_eq!(angles[0] * 180.0 / PI, 45.0, epsilon = 1e-12);
1023    /// assert_relative_eq!(angles[1] * 180.0 / PI, 30.0, epsilon = 1e-12);
1024    /// assert_relative_eq!(angles[2] * 180.0 / PI, 20.0, epsilon = 1e-12);
1025    /// ```
1026    ///
1027    /// # Example 2:
1028    /// ```
1029    /// use std::f64::consts::PI;
1030    /// use approx::assert_relative_eq;
1031    /// use nalgebra::{Matrix3, Rotation3, Unit, Vector3};
1032    ///
1033    /// let sqrt_2 = 2.0_f64.sqrt();
1034    /// let n = [
1035    ///     Unit::new_unchecked(Vector3::new(1.0 / sqrt_2, 1.0 / sqrt_2, 0.0)),
1036    ///     Unit::new_unchecked(Vector3::new(1.0 / sqrt_2, -1.0 / sqrt_2, 0.0)),
1037    ///     Unit::new_unchecked(Vector3::new(0.0, 0.0, 1.0)),
1038    /// ];
1039    ///
1040    /// let r1 = Rotation3::from_axis_angle(&n[2], 20.0 * PI / 180.0);
1041    /// let r2 = Rotation3::from_axis_angle(&n[1], 30.0 * PI / 180.0);
1042    /// let r3 = Rotation3::from_axis_angle(&n[0], 45.0 * PI / 180.0);
1043    ///
1044    /// let d = r3 * r2 * r1;
1045    ///
1046    /// let (angles, observable) = d.euler_angles_ordered(n, false);
1047    /// assert!(observable);
1048    /// assert_relative_eq!(angles[0] * 180.0 / PI, 45.0, epsilon = 1e-12);
1049    /// assert_relative_eq!(angles[1] * 180.0 / PI, 30.0, epsilon = 1e-12);
1050    /// assert_relative_eq!(angles[2] * 180.0 / PI, 20.0, epsilon = 1e-12);
1051    /// ```
1052    ///
1053    /// Algorithm based on:
1054    /// Malcolm D. Shuster, F. Landis Markley, “General formula for extraction the Euler
1055    /// angles”, Journal of guidance, control, and dynamics, vol. 29.1, pp. 215-221. 2006,
1056    /// and modified to be able to produce extrinsic rotations.
1057    #[must_use]
1058    pub fn euler_angles_ordered(
1059        &self,
1060        mut seq: [Unit<Vector3<T>>; 3],
1061        extrinsic: bool,
1062    ) -> ([T; 3], bool)
1063    where
1064        T: RealField + Copy,
1065    {
1066        let mut angles = [T::zero(); 3];
1067        let eps = T::from_subset(&1e-6);
1068        let two = T::from_subset(&2.0);
1069
1070        if extrinsic {
1071            seq.reverse();
1072        }
1073
1074        let [n1, n2, n3] = &seq;
1075        assert_relative_eq!(n1.dot(n2), T::zero(), epsilon = eps);
1076        assert_relative_eq!(n3.dot(n1), T::zero(), epsilon = eps);
1077
1078        let n1_c_n2 = n1.cross(n2);
1079        let s1 = n1_c_n2.dot(n3);
1080        let c1 = n1.dot(n3);
1081        let lambda = s1.atan2(c1);
1082
1083        let mut c = Matrix3::zeros();
1084        c.column_mut(0).copy_from(n2);
1085        c.column_mut(1).copy_from(&n1_c_n2);
1086        c.column_mut(2).copy_from(n1);
1087        c.transpose_mut();
1088
1089        let r1l = Matrix3::new(
1090            T::one(),
1091            T::zero(),
1092            T::zero(),
1093            T::zero(),
1094            c1,
1095            s1,
1096            T::zero(),
1097            -s1,
1098            c1,
1099        );
1100        let o_t = c * self.matrix() * (c.transpose() * r1l);
1101        angles[1] = o_t.m33.acos();
1102
1103        let safe1 = angles[1].abs() >= eps;
1104        let safe2 = (angles[1] - T::pi()).abs() >= eps;
1105        let observable = safe1 && safe2;
1106        angles[1] += lambda;
1107
1108        if observable {
1109            angles[0] = o_t.m13.atan2(-o_t.m23);
1110            angles[2] = o_t.m31.atan2(o_t.m32);
1111        } else {
1112            // gimbal lock detected
1113            if extrinsic {
1114                // angle1 is initialized to zero
1115                if !safe1 {
1116                    angles[2] = (o_t.m12 - o_t.m21).atan2(o_t.m11 + o_t.m22);
1117                } else {
1118                    angles[2] = -(o_t.m12 + o_t.m21).atan2(o_t.m11 - o_t.m22);
1119                };
1120            } else {
1121                // angle3 is initialized to zero
1122                if !safe1 {
1123                    angles[0] = (o_t.m12 - o_t.m21).atan2(o_t.m11 + o_t.m22);
1124                } else {
1125                    angles[0] = (o_t.m12 + o_t.m21).atan2(o_t.m11 - o_t.m22);
1126                };
1127            };
1128        };
1129
1130        let adjust = if seq[0] == seq[2] {
1131            // lambda = 0, so ensure angle2 -> [0, pi]
1132            angles[1] < T::zero() || angles[1] > T::pi()
1133        } else {
1134            // lambda = + or - pi/2, so ensure angle2 -> [-pi/2, pi/2]
1135            angles[1] < -T::frac_pi_2() || angles[1] > T::frac_pi_2()
1136        };
1137
1138        // dont adjust gimbal locked rotation
1139        if adjust && observable {
1140            angles[0] += T::pi();
1141            angles[1] = two * lambda - angles[1];
1142            angles[2] -= T::pi();
1143        }
1144
1145        // ensure all angles are within [-pi, pi]
1146        for angle in angles.as_mut_slice().iter_mut() {
1147            if *angle < -T::pi() {
1148                *angle += T::two_pi();
1149            } else if *angle > T::pi() {
1150                *angle -= T::two_pi();
1151            }
1152        }
1153
1154        if extrinsic {
1155            angles.reverse();
1156        }
1157
1158        (angles, observable)
1159    }
1160}
1161
1162#[cfg(feature = "rand-no-std")]
1163impl<T: SimdRealField> Distribution<Rotation3<T>> for StandardUniform
1164where
1165    T::Element: SimdRealField,
1166    OpenClosed01: Distribution<T>,
1167    T: SampleUniform,
1168{
1169    /// Generate a uniformly distributed random rotation.
1170    #[inline]
1171    fn sample<'a, R: Rng + ?Sized>(&self, rng: &mut R) -> Rotation3<T> {
1172        // James Arvo.
1173        // Fast random rotation matrices.
1174        // In D. Kirk, editor, Graphics Gems III, pages 117-120. Academic, New York, 1992.
1175
1176        // Compute a random rotation around Z
1177        let twopi = Uniform::new(T::zero(), T::simd_two_pi())
1178            .expect("Failed to construct `Uniform`, should be unreachable");
1179        let theta = rng.sample(&twopi);
1180        let (ts, tc) = theta.simd_sin_cos();
1181        let a = SMatrix::<T, 3, 3>::new(
1182            tc.clone(),
1183            ts.clone(),
1184            T::zero(),
1185            -ts,
1186            tc,
1187            T::zero(),
1188            T::zero(),
1189            T::zero(),
1190            T::one(),
1191        );
1192
1193        // Compute a random rotation *of* Z
1194        let phi = rng.sample(&twopi);
1195        let z = rng.sample(OpenClosed01);
1196        let (ps, pc) = phi.simd_sin_cos();
1197        let sqrt_z = z.clone().simd_sqrt();
1198        let v = Vector3::new(pc * sqrt_z.clone(), ps * sqrt_z, (T::one() - z).simd_sqrt());
1199        let mut b = v.clone() * v.transpose();
1200        b += b.clone();
1201        b -= SMatrix::<T, 3, 3>::identity();
1202
1203        Rotation3::from_matrix_unchecked(b * a)
1204    }
1205}
1206
1207#[cfg(feature = "arbitrary")]
1208impl<T: SimdRealField + Arbitrary> Arbitrary for Rotation3<T>
1209where
1210    T::Element: SimdRealField,
1211    Owned<T, U3, U3>: Send,
1212    Owned<T, U3>: Send,
1213{
1214    #[inline]
1215    fn arbitrary(g: &mut Gen) -> Self {
1216        Self::new(SVector::arbitrary(g))
1217    }
1218}