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}