math_utils/types/
mod.rs

1use std::marker::PhantomData;
2use derive_more::{Deref, Display, From, Neg};
3use either::Either;
4
5use crate::approx;
6use crate::num_traits as num;
7
8#[cfg(feature = "derive_serdes")]
9use serde::{Deserialize, Serialize};
10
11use crate::traits::*;
12
13pub mod coordinate;
14
15pub use vek::Vec2 as Vector2;
16pub use vek::Mat2 as Matrix2;
17pub use vek::Vec3 as Vector3;
18pub use vek::Mat3 as Matrix3;
19pub use vek::Vec4 as Vector4;
20pub use vek::Mat4 as Matrix4;
21pub use vek::Quaternion as Quaternion;
22
23pub use self::enums::{Axis2, Axis3, Axis4, Octant, Quadrant, Sign, SignedAxis1,
24  SignedAxis2, SignedAxis3, SignedAxis4};
25
26////////////////////////////////////////////////////////////////////////////////////////
27//  enums
28////////////////////////////////////////////////////////////////////////////////////////
29
30// we define enums in a separate module so that the generated iterator types don't
31// pollute the namespace
32mod enums {
33  use strum::{EnumCount, EnumIter, FromRepr};
34  #[cfg(feature = "derive_serdes")]
35  use serde::{Deserialize, Serialize};
36
37  /// Negative, zero, or positive
38  #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
39  #[derive(Clone, Copy, Debug, Eq, PartialEq, EnumCount, EnumIter, FromRepr)]
40  #[repr(u8)]
41  pub enum Sign {
42    Negative,
43    Zero,
44    Positive
45  }
46
47  /// 2D quadrant
48  #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
49  #[derive(Clone, Copy, Debug, Eq, PartialEq, EnumCount, EnumIter, FromRepr)]
50  #[repr(u8)]
51  pub enum Quadrant {
52    /// +X, +Y
53    PosPos,
54    /// -X, +Y
55    NegPos,
56    /// +X, -Y
57    PosNeg,
58    /// -X, -Y
59    NegNeg
60  }
61
62  /// 3D octant
63  #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
64  #[derive(Clone, Copy, Debug, Eq, PartialEq, EnumCount, EnumIter, FromRepr)]
65  #[repr(u8)]
66  pub enum Octant {
67    /// +X, +Y, +Z
68    PosPosPos,
69    /// -X, +Y, +Z
70    NegPosPos,
71    /// +X, -Y, +Z
72    PosNegPos,
73    /// -X, -Y, +Z
74    NegNegPos,
75    /// +X, +Y, -Z
76    PosPosNeg,
77    /// -X, +Y, -Z
78    NegPosNeg,
79    /// +X, -Y, -Z
80    PosNegNeg,
81    /// -X, -Y, -Z
82    NegNegNeg
83  }
84
85  /// X or Y axis
86  #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
87  #[derive(Clone, Copy, Debug, Eq, PartialEq, EnumCount, EnumIter, FromRepr)]
88  #[repr(u8)]
89  pub enum Axis2 {
90    X=0,
91    Y
92  }
93
94  /// X, Y, or Z axis
95  #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
96  #[derive(Clone, Copy, Debug, Eq, PartialEq, EnumCount, EnumIter, FromRepr)]
97  #[repr(u8)]
98  pub enum Axis3 {
99    X=0,
100    Y,
101    Z
102  }
103
104  /// X, Y, Z, or W axis
105  #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
106  #[derive(Clone, Copy, Debug, Eq, PartialEq, EnumCount, EnumIter, FromRepr)]
107  #[repr(u8)]
108  pub enum Axis4 {
109    X=0,
110    Y,
111    Z,
112    W
113  }
114
115  /// Positive or negative X axis
116  #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
117  #[derive(Clone, Copy, Debug, Eq, PartialEq, EnumCount, EnumIter, FromRepr)]
118  #[repr(u8)]
119  pub enum SignedAxis1 {
120    NegX, PosX
121  }
122
123  /// Positive or negative X or Y axis
124  #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
125  #[derive(Clone, Copy, Debug, Eq, PartialEq, EnumCount, EnumIter, FromRepr)]
126  #[repr(u8)]
127  pub enum SignedAxis2 {
128    NegX, PosX,
129    NegY, PosY
130  }
131
132  /// Positive or negative X, Y, or Z axis
133  #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
134  #[derive(Clone, Copy, Debug, Eq, PartialEq, EnumCount, EnumIter, FromRepr)]
135  #[repr(u8)]
136  pub enum SignedAxis3 {
137    NegX, PosX,
138    NegY, PosY,
139    NegZ, PosZ
140  }
141
142  /// Positive or negative X, Y, Z, or W axis
143  #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
144  #[derive(Clone, Copy, Debug, Eq, PartialEq, EnumCount, EnumIter, FromRepr)]
145  #[repr(u8)]
146  pub enum SignedAxis4 {
147    NegX, PosX,
148    NegY, PosY,
149    NegZ, PosZ,
150    NegW, PosW
151  }
152}
153
154////////////////////////////////////////////////////////////////////////////////
155//  structs
156////////////////////////////////////////////////////////////////////////////////
157
158/// Strictly positive scalars (non-zero)
159#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
160#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, PartialOrd)]
161pub struct Positive <S> (S);
162
163/// Non-negative scalars (may be zero)
164#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
165#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, PartialOrd)]
166pub struct NonNegative <S> (S);
167
168/// Non-zero scalars
169#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
170#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
171pub struct NonZero <S> (S);
172
173/// Scalars in the closed unit interval [0, 1]
174#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
175#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
176pub struct Normalized <S> (S);
177
178/// Scalars in the closed interval [-1, 1]
179#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
180#[derive(Clone, Copy, Debug, Default, PartialEq, PartialOrd)]
181pub struct NormalSigned <S> (S);
182
183/// (Euler angles) representation of a 3D orientation. Internally the angles are wrapped
184/// to $[0, 2\pi)$.
185///
186/// Throughout this library this is usually interpreted as intrinsic ZX'Y'' Euler
187/// angles.
188#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
189#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
190pub struct Angles3 <S> {
191  pub yaw   : AngleWrapped <S>,
192  pub pitch : AngleWrapped <S>,
193  pub roll  : AngleWrapped <S>
194}
195
196/// Representation of a 3D position + orientation
197#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
198#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
199pub struct Pose3 <S> {
200  pub position : Point3  <S>,
201  pub angles   : Angles3 <S>
202}
203
204/// Invertible linear map
205#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Display)]
206#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
207#[display("{}", _0)]
208pub struct LinearIso <S, V, W, M> (M, PhantomData <(S, V, W)>);
209
210/// Invertible linear endomorphism
211#[derive(Clone, Copy, Debug, Default, PartialEq, Deref, Display, From)]
212#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
213#[display("{}", _0)]
214pub struct LinearAuto <S, V> (pub LinearIso <S, V, V, V::LinearEndo>) where
215  V : Module <S>,
216  V::LinearEndo : MaybeSerDes,
217  S : Ring;
218
219/// Orthogonal 2x2 matrix with determinant +1, i.e. a member of the circle group $SO(2)$
220/// of special orthogonal matrices
221#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
222#[cfg_attr(feature = "derive_serdes", serde(bound = "S : MaybeSerDes"))]
223#[derive(Clone, Copy, Debug, Default, PartialEq)]
224pub struct Rotation2 <S> (LinearAuto <S, Vector2 <S>>) where S : Ring + MaybeSerDes;
225
226/// Orthogonal 3x3 matrix with determinant +1, i.e. a member of the 3D rotation group
227/// $SO(3)$ of special orthogonal matrices
228#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
229#[cfg_attr(feature = "derive_serdes", serde(bound = "S : MaybeSerDes"))]
230#[derive(Clone, Copy, Debug, Default, PartialEq)]
231pub struct Rotation3 <S> (LinearAuto <S, Vector3 <S>>) where S : Ring + MaybeSerDes;
232
233/// Unit quaternion representing an orientation in $\mathbb{R}^3$
234#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
235#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
236pub struct Versor <S> (Quaternion <S>) where S : num::Zero + num::One;
237
238/// Homomorphism of an affine spaces: a combination of a linear map and a translation
239#[derive(Clone, Copy, Debug, Default, PartialEq, Display)]
240#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
241#[display("({}, {})", linear_map, translation)]
242pub struct AffineMap <S, A, B, M> where
243  B : AffineSpace <S>,
244  S : Field + std::fmt::Display,
245  B::Vector : std::fmt::Display
246{
247  pub linear_map  : M,
248  pub translation : B::Vector,
249  pub _phantom    : PhantomData <A>
250}
251
252/// Affine isomorphism
253#[derive(Clone, Copy, Debug, Default, PartialEq, Display)]
254#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
255#[display("({}, {})", linear_iso, translation)]
256pub struct Affinity <S, A, B, M> where
257  A : AffineSpace <S>,
258  B : AffineSpace <S>,
259  S : Field + std::fmt::Display,
260  B::Vector : std::fmt::Display
261{
262  pub linear_iso  : LinearIso <S, A::Vector, B::Vector, M>,
263  pub translation : B::Vector,
264  pub _phantom    : PhantomData <A>
265}
266
267/// Isomorphism of projective spaces (a.k.a. homography or projective collineation)
268#[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Display)]
269#[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
270#[display("{}", _0)]
271pub struct Projectivity <S, V, W, P, Q, M> (
272  pub LinearIso <S, P, Q, M>,
273  pub PhantomData <(V, W)>
274);
275
276////////////////////////////////////////////////////////////////////////////////
277//  impls
278////////////////////////////////////////////////////////////////////////////////
279
280//
281//  impl Deg
282//
283impl <S : Real> Angle <S> for Deg <S> {
284  fn full_turn() -> Self {
285    Deg (S::ten() * S::nine() * S::two() * S::two())
286  }
287  fn half_turn() -> Self {
288    Deg (S::ten() * S::nine() * S::two())
289  }
290}
291impl <S : Real> Trig for Deg <S> {
292  fn sin     (self) -> Self {
293    Rad::from (self).sin().into()
294  }
295  fn sin_cos (self) -> (Self, Self) {
296    let (sin, cos) = Rad::from (self).sin_cos();
297    (sin.into(), cos.into())
298  }
299  fn cos     (self) -> Self {
300    Rad::from (self).cos().into()
301  }
302  fn tan     (self) -> Self {
303    Rad::from (self).tan().into()
304  }
305  fn asin    (self) -> Self {
306    Rad::from (self).asin().into()
307  }
308  fn acos    (self) -> Self {
309    Rad::from (self).acos().into()
310  }
311  fn atan    (self) -> Self {
312    Rad::from (self).atan().into()
313  }
314  fn atan2   (self, other : Self) -> Self {
315    Rad::from (self).atan2 (Rad::from (other)).into()
316  }
317}
318impl <S : Real> From <Rad <S>> for Deg <S> {
319  fn from (radians : Rad <S>) -> Self {
320    let full_turns = radians / Rad::full_turn();
321    Deg::full_turn() * full_turns
322  }
323}
324impl <S : Real> From <Turn <S>> for Deg <S> {
325  fn from (turns : Turn <S>) -> Self {
326    Deg (turns.0 * Deg::full_turn().0)
327  }
328}
329
330//
331//  impl Rad
332//
333impl <S : Real> Angle <S> for Rad <S> {
334  fn full_turn() -> Self {
335    Rad (S::pi() * S::two())
336  }
337}
338impl <S : Real> Trig for Rad <S> {
339  fn sin     (self) -> Self {
340    Rad (self.0.sin())
341  }
342  fn sin_cos (self) -> (Self, Self) {
343    let (sin, cos) = self.0.sin_cos();
344    (Rad (sin), Rad (cos))
345  }
346  fn cos     (self) -> Self {
347    Rad (self.0.cos())
348  }
349  fn tan     (self) -> Self {
350    Rad (self.0.tan())
351  }
352  fn asin    (self) -> Self {
353    Rad (self.0.asin())
354  }
355  fn acos    (self) -> Self {
356    Rad (self.0.acos())
357  }
358  fn atan    (self) -> Self {
359    Rad (self.0.atan())
360  }
361  fn atan2   (self, other : Self) -> Self {
362    Rad (self.0.atan2 (other.0))
363  }
364}
365impl <S : Real> From <Deg <S>> for Rad <S> {
366  fn from (degrees : Deg <S>) -> Self {
367    let full_turns = degrees / Deg::full_turn();
368    Rad::full_turn() * full_turns
369  }
370}
371impl <S : Real> From <Turn <S>> for Rad <S> {
372  fn from (turns : Turn <S>) -> Self {
373    Rad (turns.0 * Rad::full_turn().0)
374  }
375}
376
377//
378//  impl Turn
379//
380impl <S : Real> Angle <S> for Turn <S> {
381  fn full_turn() -> Self {
382    Turn (S::one())
383  }
384  fn half_turn() -> Self {
385    Turn (S::half())
386  }
387}
388impl <S : Real> Trig for Turn <S> {
389  fn sin     (self) -> Self {
390    Rad::from (self).sin().into()
391  }
392  fn sin_cos (self) -> (Self, Self) {
393    let (sin, cos) = Rad::from (self).sin_cos();
394    (sin.into(), cos.into())
395  }
396  fn cos     (self) -> Self {
397    Rad::from (self).cos().into()
398  }
399  fn tan     (self) -> Self {
400    Rad::from (self).tan().into()
401  }
402  fn asin    (self) -> Self {
403    Rad::from (self).asin().into()
404  }
405  fn acos    (self) -> Self {
406    Rad::from (self).acos().into()
407  }
408  fn atan    (self) -> Self {
409    Rad::from (self).atan().into()
410  }
411  fn atan2   (self, other : Self) -> Self {
412    Rad::from (self).atan2 (Rad::from (other)).into()
413  }
414}
415impl <S : Real> From <Rad <S>> for Turn <S> {
416  fn from (radians : Rad <S>) -> Self {
417    Turn (radians.0 / Rad::full_turn().0)
418  }
419}
420impl <S : Real> From <Deg <S>> for Turn <S> {
421  fn from (degrees : Deg <S>) -> Self {
422    Turn (degrees.0 / Deg::full_turn().0)
423  }
424}
425
426//
427//  impl AngleWrapped
428//
429impl <S : Real> AngleWrapped <S> {
430  pub fn wrap (angle : Rad <S>) -> Self {
431    AngleWrapped (angle.wrap_unsigned())
432  }
433
434  pub fn map <F> (self, f : F) -> Self where
435    F : FnOnce (Rad <S>) -> Rad <S>
436  {
437    AngleWrapped (f (self.0).wrap_unsigned())
438  }
439}
440
441//
442//  impl AngleWrappedSigned
443//
444impl <S : Real> AngleWrappedSigned <S> {
445  pub fn wrap (angle : Rad <S>) -> Self {
446    AngleWrappedSigned (angle.wrap_signed())
447  }
448
449  pub fn map <F> (self, f : F) -> Self where
450    F : FnOnce (Rad <S>) -> Rad <S>
451  {
452    AngleWrappedSigned (f (self.0).wrap_signed())
453  }
454}
455
456//
457//  impl Angles3
458//
459
460impl <S : Real> Angles3 <S> {
461  pub const fn new (
462    yaw   : AngleWrapped <S>,
463    pitch : AngleWrapped <S>,
464    roll  : AngleWrapped <S>
465  ) -> Self {
466    Angles3 { yaw, pitch, roll }
467  }
468
469  pub fn zero() -> Self {
470    use num::Zero;
471    Angles3::new (
472      AngleWrapped::zero(),
473      AngleWrapped::zero(),
474      AngleWrapped::zero())
475  }
476
477  pub fn wrap (yaw : Rad <S>, pitch : Rad <S>, roll : Rad <S>) -> Self {
478    let yaw   = AngleWrapped::wrap (yaw);
479    let pitch = AngleWrapped::wrap (pitch);
480    let roll  = AngleWrapped::wrap (roll);
481    Angles3 { yaw, pitch, roll }
482  }
483}
484
485impl <S> From <Rotation3 <S>> for Angles3 <S> where S : Real + MaybeSerDes {
486  fn from (rotation : Rotation3 <S>) -> Self {
487    let (yaw, pitch, roll) = {
488      let (yaw, pitch, roll) = rotation.intrinsic_angles();
489      ( AngleWrapped::wrap (yaw),
490        AngleWrapped::wrap (pitch),
491        AngleWrapped::wrap (roll)
492      )
493    };
494    Angles3 { yaw, pitch, roll }
495  }
496}
497
498//
499//  impl Axis2
500//
501impl Axis2 {
502  #[inline]
503  pub const fn component (self) -> usize {
504    self as usize
505  }
506}
507
508//
509//  impl Axis3
510//
511impl Axis3 {
512  #[inline]
513  pub const fn component (self) -> usize {
514    self as usize
515  }
516}
517
518//
519//  impl SignedAxis3
520//
521impl SignedAxis3 {
522  pub fn try_from <S : Field> (vector : &Vector3 <S>) -> Option <Self> {
523    if *vector == [ S::one(),   S::zero(),  S::zero()].into() {
524      Some (SignedAxis3::PosX)
525    } else if *vector == [-S::one(),   S::zero(),  S::zero()].into() {
526      Some (SignedAxis3::NegX)
527    } else if *vector == [ S::zero(),  S::one(),   S::zero()].into() {
528      Some (SignedAxis3::PosY)
529    } else if *vector == [ S::zero(), -S::one(),   S::zero()].into() {
530      Some (SignedAxis3::NegY)
531    } else if *vector == [ S::zero(),  S::zero(),  S::one() ].into() {
532      Some (SignedAxis3::PosZ)
533    } else if *vector == [ S::zero(),  S::zero(), -S::one() ].into() {
534      Some (SignedAxis3::NegZ)
535    } else {
536      None
537    }
538  }
539
540  pub fn to_vec <S : Field> (self) -> Vector3 <S> {
541    match self {
542      SignedAxis3::NegX => [-S::one(),   S::zero(),  S::zero()].into(),
543      SignedAxis3::PosX => [ S::one(),   S::zero(),  S::zero()].into(),
544      SignedAxis3::NegY => [ S::zero(), -S::one(),   S::zero()].into(),
545      SignedAxis3::PosY => [ S::zero(),  S::one(),   S::zero()].into(),
546      SignedAxis3::NegZ => [ S::zero(),  S::zero(), -S::one() ].into(),
547      SignedAxis3::PosZ => [ S::zero(),  S::zero(),  S::one() ].into()
548    }
549  }
550  #[inline]
551  pub fn to_unit <S> (self) -> Unit3 <S> where S : Real + std::fmt::Debug {
552    Unit3::unchecked (self.to_vec())
553  }
554}
555
556//
557//  impl Quadrant
558//
559impl Quadrant {
560  /// Returns some 'Some (quadrant)' if the vector is strictly contained within a
561  /// quadrant and returns 'None' otherwise
562  pub fn from_vec_strict <S> (vector : &Vector2 <S>) -> Option <Quadrant> where
563    S : Ring + SignedExt
564  {
565    let sign_x = vector.x.sign();
566    let sign_y = vector.y.sign();
567    let quadrant = match (sign_x, sign_y) {
568      (Sign::Zero,          _) |
569      (         _, Sign::Zero) => return None,
570      (Sign::Positive, Sign::Positive) => Quadrant::PosPos,
571      (Sign::Negative, Sign::Positive) => Quadrant::NegPos,
572      (Sign::Positive, Sign::Negative) => Quadrant::PosNeg,
573      (Sign::Negative, Sign::Negative) => Quadrant::NegNeg
574    };
575    Some (quadrant)
576  }
577  /// Same as `from_vec_strict` for a point
578  #[inline]
579  pub fn from_point_strict <S> (point : &Point2 <S>) -> Option <Quadrant> where
580    S : Ring + SignedExt
581  {
582    Quadrant::from_vec_strict (&point.to_vector())
583  }
584}
585//  end impl Quadrant
586
587//
588//  impl Octant
589//
590impl Octant {
591  /// Returns some 'Some (octant)' if the vector is strictly contained within an octant
592  /// and returns 'None' otherwise
593  pub fn from_vec_strict <S> (vector : &Vector3 <S>) -> Option <Octant> where
594    S : Ring + SignedExt
595  {
596    let sign_x = vector.x.sign();
597    let sign_y = vector.y.sign();
598    let sign_z = vector.z.sign();
599    let octant = match (sign_x, sign_y, sign_z) {
600      (Sign::Zero,          _,          _) |
601      (         _, Sign::Zero,          _) |
602      (         _,          _, Sign::Zero) => return None,
603      (Sign::Positive, Sign::Positive, Sign::Positive) => Octant::PosPosPos,
604      (Sign::Negative, Sign::Positive, Sign::Positive) => Octant::NegPosPos,
605      (Sign::Positive, Sign::Negative, Sign::Positive) => Octant::PosNegPos,
606      (Sign::Negative, Sign::Negative, Sign::Positive) => Octant::NegNegPos,
607      (Sign::Positive, Sign::Positive, Sign::Negative) => Octant::PosPosNeg,
608      (Sign::Negative, Sign::Positive, Sign::Negative) => Octant::NegPosNeg,
609      (Sign::Positive, Sign::Negative, Sign::Negative) => Octant::PosNegNeg,
610      (Sign::Negative, Sign::Negative, Sign::Negative) => Octant::NegNegNeg
611    };
612    Some (octant)
613  }
614  /// Same as `from_vec_strict` for a point
615  #[inline]
616  pub fn from_point_strict <S> (point : &Point3 <S>) -> Option <Octant> where
617    S : Ring + SignedExt
618  {
619    Octant::from_vec_strict (&point.to_vector())
620  }
621}
622//  end impl Octant
623
624//
625//  impl Positive
626//
627impl <S : Ring> Positive <S> {
628  /// Returns 'None' when called with a negative or zero value.
629  ///
630  /// # Example
631  ///
632  /// ```
633  /// # use math_utils::Positive;
634  /// assert!(Positive::new (1.0).is_some());
635  /// assert!(Positive::new (0.0).is_none());
636  /// assert!(Positive::new (-1.0).is_none());
637  /// ```
638  pub fn new (value : S) -> Option <Self> {
639    if value > S::zero() {
640      Some (Positive (value))
641    } else {
642      None
643    }
644  }
645  /// Positive infinity
646  pub fn infinity() -> Self where S : num::float::FloatCore {
647    Positive (S::infinity())
648  }
649  /// Panics if negative or zero.
650  ///
651  /// # Panics
652  ///
653  /// ```should_panic
654  /// # use math_utils::Positive;
655  /// let x = Positive::noisy (0.0);  // panic!
656  /// ```
657  pub fn noisy (value : S) -> Self {
658    assert!(value > S::zero());
659    Positive (value)
660  }
661  /// Create a new positive number without checking the value.
662  ///
663  /// In debug builds this will fail with a debug assertion if the value is negative:
664  ///
665  /// ```should_panic
666  /// # use math_utils::Positive;
667  /// let negative = Positive::unchecked (-1.0);  // panic!
668  /// ```
669  pub fn unchecked (value : S) -> Self {
670    debug_assert!(value > S::zero());
671    Positive (value)
672  }
673  /// Map an operation on the underlying scalar, panicking if the result is zero or
674  /// negative.
675  ///
676  /// # Example
677  ///
678  /// ```
679  /// # use math_utils::Positive;
680  /// # use math_utils::num_traits::One;
681  /// assert_eq!(*Positive::<f64>::one().map_noisy (|x| 2.0 * x), 2.0);
682  /// ```
683  ///
684  /// # Panics
685  ///
686  /// Panics of the result is negative or zero:
687  ///
688  /// ```should_panic
689  /// # use math_utils::Positive;
690  /// # use math_utils::num_traits::One;
691  /// let v = Positive::<f64>::one().map_noisy (|_| 0.0);  // panic!
692  /// ```
693  pub fn map_noisy (self, fun : fn (S) -> S) -> Self {
694    Self::noisy (fun (self.0))
695  }
696}
697impl <S : Field> num::One for Positive <S> {
698  fn one() -> Self {
699    Positive (S::one())
700  }
701}
702impl <S : Ring> std::ops::Deref for Positive <S> {
703  type Target = S;
704  fn deref (&self) -> &S {
705    &self.0
706  }
707}
708impl <S : Ring> std::ops::Mul for Positive <S> {
709  type Output = Self;
710  fn mul (self, rhs : Self) -> Self::Output {
711    Positive (self.0 * rhs.0)
712  }
713}
714impl <S : Ring> std::ops::Mul <NonNegative <S>> for Positive <S> {
715  type Output = NonNegative <S>;
716  fn mul (self, rhs : NonNegative <S>) -> Self::Output {
717    NonNegative (self.0 * *rhs)
718  }
719}
720impl <S : Field> std::ops::Div for Positive <S> {
721  type Output = Self;
722  fn div (self, rhs : Self) -> Self::Output {
723    Positive (self.0 / rhs.0)
724  }
725}
726impl <S : Ring> std::ops::Add for Positive <S> {
727  type Output = Self;
728  fn add (self, rhs : Self) -> Self::Output {
729    Positive (self.0 + rhs.0)
730  }
731}
732impl <S : Ring> std::ops::Add <NonNegative <S>> for Positive <S> {
733  type Output = Self;
734  fn add (self, rhs : NonNegative <S>) -> Self::Output {
735    Positive (self.0 + rhs.0)
736  }
737}
738//  end impl Positive
739
740//
741//  impl NonNegative
742//
743impl <S : Ring> NonNegative <S> {
744  /// Returns 'None' when called with a negative value.
745  ///
746  /// # Example
747  ///
748  /// ```
749  /// # use math_utils::NonNegative;
750  /// assert!(NonNegative::new (1.0).is_some());
751  /// assert!(NonNegative::new (0.0).is_some());
752  /// assert!(NonNegative::new (-1.0).is_none());
753  /// ```
754  pub fn new (value : S) -> Option <Self> {
755    if value >= S::zero() {
756      Some (NonNegative (value))
757    } else {
758      None
759    }
760  }
761  /// Converts negative input to absolute value.
762  ///
763  /// # Example
764  ///
765  /// ```
766  /// # use math_utils::NonNegative;
767  /// assert_eq!(*NonNegative::abs (1.0), 1.0);
768  /// assert_eq!(*NonNegative::abs (-1.0), 1.0);
769  /// ```
770  pub fn abs (value : S) -> Self {
771    NonNegative (value.abs())
772  }
773  /// Panics if negative.
774  ///
775  /// # Panics
776  ///
777  /// ```should_panic
778  /// # use math_utils::NonNegative;
779  /// let x = NonNegative::noisy (-1.0);  // panic!
780  /// ```
781  pub fn noisy (value : S) -> Self {
782    assert!(S::zero() <= value);
783    NonNegative (value)
784  }
785  /// Create a new non-negative number without checking the value.
786  ///
787  /// This method is completely unchecked for release builds. Debug builds will panic if
788  /// the value is negative:
789  ///
790  /// ```should_panic
791  /// # use math_utils::NonNegative;
792  /// let negative = NonNegative::unchecked (-1.0);   // panic!
793  /// ```
794  pub fn unchecked (value : S) -> Self {
795    debug_assert!(value >= S::zero());
796    NonNegative (value)
797  }
798  /// Map an operation on the underlying scalar, converting negative result to an
799  /// absolute value.
800  ///
801  /// # Example
802  ///
803  /// ```
804  /// # use math_utils::NonNegative;
805  /// assert_eq!(*NonNegative::abs (1.0).map_abs (|x| -2.0 * x), 2.0);
806  /// ```
807  pub fn map_abs (self, fun : fn (S) -> S) -> Self {
808    Self::abs (fun (self.0))
809  }
810  /// Map an operation on the underlying scalar, panicking if the result is negative.
811  ///
812  /// # Example
813  ///
814  /// ```
815  /// # use math_utils::NonNegative;
816  /// assert_eq!(*NonNegative::abs (1.0).map_noisy (|x| 2.0 * x), 2.0);
817  /// ```
818  ///
819  /// # Panics
820  ///
821  /// Panics of the result is negative:
822  ///
823  /// ```should_panic
824  /// # use math_utils::NonNegative;
825  /// let v = NonNegative::abs (1.0).map_noisy (|x| -1.0 * x);  // panic!
826  /// ```
827  pub fn map_noisy (self, fun : fn (S) -> S) -> Self {
828    Self::noisy (fun (self.0))
829  }
830}
831impl <S : Ring> From <Positive <S>> for NonNegative <S> {
832  fn from (positive : Positive <S>) -> Self {
833    NonNegative (*positive)
834  }
835}
836impl <S : Ring> num::Zero for NonNegative <S> {
837  fn zero() -> Self {
838    NonNegative (S::zero())
839  }
840  fn is_zero (&self) -> bool {
841    self.0.is_zero()
842  }
843}
844impl <S : Field> num::One for NonNegative <S> {
845  fn one() -> Self {
846    NonNegative (S::one())
847  }
848}
849impl <S : Ring> std::ops::Deref for NonNegative <S> {
850  type Target = S;
851  fn deref (&self) -> &S {
852    &self.0
853  }
854}
855impl <S : Ring> std::ops::Mul for NonNegative <S> {
856  type Output = Self;
857  fn mul (self, rhs : Self) -> Self::Output {
858    NonNegative (self.0 * rhs.0)
859  }
860}
861impl <S : Ring> std::ops::Mul <Positive <S>> for NonNegative <S> {
862  type Output = Self;
863  fn mul (self, rhs : Positive <S>) -> Self::Output {
864    NonNegative (self.0 * rhs.0)
865  }
866}
867impl <S : Field> std::ops::Div for NonNegative <S> {
868  type Output = Self;
869  fn div (self, rhs : Self) -> Self::Output {
870    NonNegative (self.0 / rhs.0)
871  }
872}
873impl <S : Ring> std::ops::Add for NonNegative <S> {
874  type Output = Self;
875  fn add (self, rhs : Self) -> Self::Output {
876    NonNegative (self.0 + rhs.0)
877  }
878}
879//  end impl NonNegative
880
881//
882//  impl NonZero
883//
884impl <S : Field> NonZero <S> {
885  /// Returns 'None' when called with zero.
886  ///
887  /// # Example
888  ///
889  /// ```
890  /// # use math_utils::NonZero;
891  /// assert!(NonZero::new (2.0).is_some());
892  /// assert!(NonZero::new (0.0).is_none());
893  /// assert!(NonZero::new (-2.0).is_some());
894  /// ```
895  #[inline]
896  pub fn new (value : S) -> Option <Self> {
897    if S::zero() != value {
898      Some (NonZero (value))
899    } else {
900      None
901    }
902  }
903  /// Panics if called with zero.
904  ///
905  /// # Panics
906  ///
907  /// ```should_panic
908  /// # use math_utils::NonZero;
909  /// let x = NonZero::noisy (0.0);  // panic!
910  /// ```
911  #[inline]
912  pub fn noisy (value : S) -> Self {
913    assert!(S::zero() != value);
914    NonZero (value)
915  }
916  /// Map an operation on the underlying scalar, panicking if the result is zero.
917  ///
918  /// # Example
919  ///
920  /// ```
921  /// # use math_utils::NonZero;
922  /// # use math_utils::num_traits::One;
923  /// assert_eq!(*NonZero::<f64>::one().map_noisy (|x| 0.5 * x), 0.5);
924  /// ```
925  ///
926  /// # Panics
927  ///
928  /// Panics of the result is zero.
929  ///
930  /// ```should_panic
931  /// # use math_utils::NonZero;
932  /// # use math_utils::num_traits::One;
933  /// let v = NonZero::<f64>::one().map_noisy (|x| 0.0 * x);  // panic!
934  /// ```
935  #[inline]
936  pub fn map_noisy (self, fun : fn (S) -> S) -> Self {
937    Self::noisy (fun (self.0))
938  }
939}
940impl <S : Field> num::One for NonZero <S> {
941  fn one() -> Self {
942    NonZero (S::one())
943  }
944}
945impl <S : Field> std::ops::Deref for NonZero <S> {
946  type Target = S;
947  fn deref (&self) -> &S {
948    &self.0
949  }
950}
951impl <S : Field> std::ops::Mul for NonZero <S> {
952  type Output = Self;
953  fn mul (self, rhs : Self) -> Self::Output {
954    NonZero (self.0 * rhs.0)
955  }
956}
957impl <S : Field> Eq  for NonZero <S> { }
958//  end impl NonZero
959
960//
961//  impl Normalized
962//
963impl <S : Field> Normalized <S> {
964  // NOTE: num::Zero requires std::ops::Add which Normalized does not implement
965  #[inline]
966  pub fn zero() -> Self {
967    Normalized (S::zero())
968  }
969  #[inline]
970  pub fn is_zero (&self) -> bool {
971    self.0.is_zero()
972  }
973  /// Returns 'None' when called with a value outside of the closed unit interval
974  /// \[0,1\].
975  ///
976  /// # Example
977  ///
978  /// ```
979  /// # use math_utils::Normalized;
980  /// assert!(Normalized::new (2.0).is_none());
981  /// assert!(Normalized::new (1.0).is_some());
982  /// assert!(Normalized::new (0.5).is_some());
983  /// assert!(Normalized::new (0.0).is_some());
984  /// assert!(Normalized::new (-1.0).is_none());
985  /// ```
986  #[inline]
987  pub fn new (value : S) -> Option <Self> {
988    if S::zero() <= value && value <= S::one() {
989      Some (Normalized (value))
990    } else {
991      None
992    }
993  }
994  /// Clamps to the closed unit interval \[0,1\].
995  ///
996  /// # Example
997  ///
998  /// ```
999  /// # use math_utils::Normalized;
1000  /// assert_eq!(*Normalized::clamp (2.0), 1.0);
1001  /// assert_eq!(*Normalized::clamp (-1.0), 0.0);
1002  /// ```
1003  #[inline]
1004  #[expect(clippy::same_name_method)]
1005  pub fn clamp (value : S) -> Self {
1006    let value = S::max (S::zero(), S::min (value, S::one()));
1007    Normalized (value)
1008  }
1009  /// Panics if outside the closed unit interval \[0,1\].
1010  ///
1011  /// # Panics
1012  ///
1013  /// ```should_panic
1014  /// # use math_utils::Normalized;
1015  /// let x = Normalized::noisy (-1.0);  // panic!
1016  /// ```
1017  ///
1018  /// ```should_panic
1019  /// # use math_utils::Normalized;
1020  /// let x = Normalized::noisy (2.0);  // panic!
1021  /// ```
1022  #[inline]
1023  pub fn noisy (value : S) -> Self {
1024    assert!(value <= S::one());
1025    assert!(S::zero() <= value);
1026    Normalized (value)
1027  }
1028  /// Map an operation on the underlying scalar, clamping results to the closed unit
1029  /// interval \[0,1\].
1030  ///
1031  /// # Example
1032  ///
1033  /// ```
1034  /// # use math_utils::Normalized;
1035  /// # use math_utils::num_traits::One;
1036  /// assert_eq!(*Normalized::<f64>::one().map_clamp (|x|  2.0 * x), 1.0);
1037  /// assert_eq!(*Normalized::<f64>::one().map_clamp (|x| -2.0 * x), 0.0);
1038  /// ```
1039  #[inline]
1040  pub fn map_clamp (self, fun : fn (S) -> S) -> Self {
1041    Self::clamp (fun (self.0))
1042  }
1043  /// Map an operation on the underlying scalar, panicking if the result is outside the
1044  /// unit interval \[0,1\].
1045  ///
1046  /// # Example
1047  ///
1048  /// ```
1049  /// # use math_utils::Normalized;
1050  /// # use math_utils::num_traits::One;
1051  /// assert_eq!(*Normalized::<f64>::one().map_noisy (|x| 0.5 * x), 0.5);
1052  /// ```
1053  ///
1054  /// # Panics
1055  ///
1056  /// Panics of the result is outside \[0,1\]:
1057  ///
1058  /// ```should_panic
1059  /// # use math_utils::Normalized;
1060  /// # use math_utils::num_traits::One;
1061  /// let v = Normalized::<f64>::one().map_noisy (|x| -1.0 * x);  // panic!
1062  /// ```
1063  ///
1064  /// ```should_panic
1065  /// # use math_utils::Normalized;
1066  /// # use math_utils::num_traits::One;
1067  /// let v = Normalized::<f64>::one().map_noisy (|x|  2.0 * x);  // panic!
1068  /// ```
1069  #[inline]
1070  pub fn map_noisy (self, fun : fn (S) -> S) -> Self {
1071    Self::noisy (fun (self.0))
1072  }
1073}
1074impl <S : Field> num::One for Normalized <S> {
1075  fn one() -> Self {
1076    Normalized (S::one())
1077  }
1078}
1079impl <S : Field> std::ops::Deref for Normalized <S> {
1080  type Target = S;
1081  fn deref (&self) -> &S {
1082    &self.0
1083  }
1084}
1085impl <S : Field> std::ops::Mul for Normalized <S> {
1086  type Output = Self;
1087  fn mul (self, rhs : Self) -> Self::Output {
1088    Normalized (self.0 * rhs.0)
1089  }
1090}
1091impl <S : Field> Eq  for Normalized <S> { }
1092#[expect(clippy::derive_ord_xor_partial_ord)]
1093impl <S : Field> Ord for Normalized <S> {
1094  fn cmp (&self, other : &Self) -> std::cmp::Ordering {
1095    // safe to unwrap: normalized values are never NaN
1096    self.partial_cmp (other).unwrap()
1097  }
1098}
1099//  end impl Normalized
1100
1101//
1102//  impl NormalSigned
1103//
1104impl <S : Field> NormalSigned <S> {
1105  // NOTE: num::Zero requires std::ops::Add which Normalized does not implement
1106  #[inline]
1107  pub fn zero() -> Self {
1108    NormalSigned (S::zero())
1109  }
1110  #[inline]
1111  pub fn is_zero (&self) -> bool {
1112    self.0.is_zero()
1113  }
1114  /// Returns 'None' when called with a value outside of the closed interval \[-1,1\].
1115  ///
1116  /// # Example
1117  ///
1118  /// ```
1119  /// # use math_utils::NormalSigned;
1120  /// assert!(NormalSigned::new (2.0).is_none());
1121  /// assert!(NormalSigned::new (1.0).is_some());
1122  /// assert!(NormalSigned::new (0.5).is_some());
1123  /// assert!(NormalSigned::new (0.0).is_some());
1124  /// assert!(NormalSigned::new (-1.0).is_some());
1125  /// assert!(NormalSigned::new (-2.0).is_none());
1126  /// ```
1127  #[inline]
1128  pub fn new (value : S) -> Option <Self> {
1129    if -S::one() <= value && value <= S::one() {
1130      Some (NormalSigned (value))
1131    } else {
1132      None
1133    }
1134  }
1135  /// Clamps to the closed interval [-1,1].
1136  ///
1137  /// # Example
1138  ///
1139  /// ```
1140  /// # use math_utils::NormalSigned;
1141  /// assert_eq!(*NormalSigned::clamp (2.0), 1.0);
1142  /// assert_eq!(*NormalSigned::clamp (-2.0), -1.0);
1143  /// ```
1144  #[inline]
1145  #[expect(clippy::same_name_method)]
1146  pub fn clamp (value : S) -> Self {
1147    let value = S::max (-S::one(), S::min (value, S::one()));
1148    NormalSigned (value)
1149  }
1150  /// Panics if outside the closed interval [-1,1].
1151  ///
1152  /// # Panics
1153  ///
1154  /// ```should_panic
1155  /// # use math_utils::NormalSigned;
1156  /// let x = NormalSigned::noisy (-2.0);   // panic!
1157  /// ```
1158  ///
1159  /// ```should_panic
1160  /// # use math_utils::NormalSigned;
1161  /// let x = NormalSigned::noisy (2.0);    // panic!
1162  /// ```
1163  #[inline]
1164  pub fn noisy (value : S) -> Self {
1165    assert!(value <= S::one());
1166    assert!(-S::one() <= value);
1167    NormalSigned (value)
1168  }
1169  /// Map an operation on the underlying scalar, clamping results to the closed interval
1170  /// [-1,1].
1171  ///
1172  /// # Example
1173  ///
1174  /// ```
1175  /// # use math_utils::NormalSigned;
1176  /// # use math_utils::num_traits::One;
1177  /// assert_eq!(*NormalSigned::<f64>::one().map_clamp (|x|  2.0 * x),  1.0);
1178  /// assert_eq!(*NormalSigned::<f64>::one().map_clamp (|x| -2.0 * x), -1.0);
1179  /// ```
1180  #[inline]
1181  pub fn map_clamp (self, fun : fn (S) -> S) -> Self {
1182    Self::clamp (fun (self.0))
1183  }
1184  /// Map an operation on the underlying scalar, panicking if the result is outside the
1185  /// interval [-1, 1].
1186  ///
1187  /// # Example
1188  ///
1189  /// ```
1190  /// # use math_utils::NormalSigned;
1191  /// # use math_utils::num_traits::One;
1192  /// assert_eq!(*NormalSigned::<f64>::one().map_noisy (|x| 0.5 * x), 0.5);
1193  /// ```
1194  ///
1195  /// # Panics
1196  ///
1197  /// Panics of the result is outside [-1, 1]:
1198  ///
1199  /// ```should_panic
1200  /// # use math_utils::NormalSigned;
1201  /// # use math_utils::num_traits::One;
1202  /// let v = NormalSigned::<f64>::one().map_noisy (|x| -2.0 * x);  // panic!
1203  /// ```
1204  ///
1205  /// ```should_panic
1206  /// # use math_utils::NormalSigned;
1207  /// # use math_utils::num_traits::One;
1208  /// let v = NormalSigned::<f64>::one().map_noisy (|x|  2.0 * x);  // panic!
1209  /// ```
1210  #[inline]
1211  pub fn map_noisy (self, fun : fn (S) -> S) -> Self {
1212    Self::noisy (fun (self.0))
1213  }
1214}
1215impl <S : Field> From <Normalized <S>> for NormalSigned <S> {
1216  fn from (Normalized (value) : Normalized <S>) -> Self {
1217    debug_assert!(S::zero() <= value);
1218    debug_assert!(value <= S::one());
1219    NormalSigned (value)
1220  }
1221}
1222impl <S : Field> num::One for NormalSigned <S> {
1223  fn one() -> Self {
1224    NormalSigned (S::one())
1225  }
1226}
1227impl <S : Field> std::ops::Deref for NormalSigned <S> {
1228  type Target = S;
1229  fn deref (&self) -> &S {
1230    &self.0
1231  }
1232}
1233impl <S : Field> std::ops::Mul for NormalSigned <S> {
1234  type Output = Self;
1235  fn mul (self, rhs : Self) -> Self::Output {
1236    NormalSigned (self.0 * rhs.0)
1237  }
1238}
1239impl <S : Field> Eq  for NormalSigned <S> { }
1240#[expect(clippy::derive_ord_xor_partial_ord)]
1241impl <S : Field> Ord for NormalSigned <S> {
1242  fn cmp (&self, other : &Self) -> std::cmp::Ordering {
1243    // safe to unwrap: normalized values are never NaN
1244    self.partial_cmp (other).unwrap()
1245  }
1246}
1247impl <S : Field> std::ops::Neg for NormalSigned <S> {
1248  type Output = Self;
1249  fn neg (self) -> Self::Output {
1250    NormalSigned (-self.0)
1251  }
1252}
1253//  end impl NormalSigned
1254
1255//
1256//  impl Rotation2
1257//
1258impl <S> Rotation2 <S> where S : Ring + MaybeSerDes {
1259  /// Identity rotation
1260  pub fn identity() -> Self {
1261    use num::One;
1262    Self::one()
1263  }
1264  /// Returns `None` if called with a matrix that is not orthonormal with determinant
1265  /// +1.
1266  ///
1267  /// This method checks whether `mat * mat^T == I` and `mat.determinant() == 1`.
1268  pub fn new (mat : Matrix2 <S>) -> Option <Self> {
1269    let transform = LinearAuto (LinearIso::new (mat)?);
1270    if !transform.is_rotation() {
1271      None
1272    } else {
1273      Some (Rotation2 (transform))
1274    }
1275  }
1276  /// Returns `None` if called with a matrix that is not orthonormal with determinant
1277  /// +1.
1278  ///
1279  /// This method checks whether `mat * mat^T == I` and `mat.determinant() == 1`
1280  /// (approximately using relative equality).
1281  pub fn new_approx (mat : Matrix2 <S>) -> Option <Self> where
1282    S : approx::RelativeEq <Epsilon=S>
1283  {
1284    let four         = S::one() + S::one() + S::one() + S::one();
1285    let epsilon      = S::default_epsilon() * four;
1286    let max_relative = S::default_max_relative() * four;
1287    if approx::relative_ne!(mat * mat.transposed(), Matrix2::identity(),
1288      max_relative=max_relative, epsilon=epsilon
1289    ) || approx::relative_ne!(mat.determinant(), S::one(), max_relative=max_relative) {
1290      None
1291    } else {
1292      Some (Rotation2 (LinearAuto (LinearIso (mat, PhantomData))))
1293    }
1294  }
1295  /// Create a rotation for the given angle
1296  pub fn from_angle (angle : Rad <S>) -> Self where S : num::real::Real {
1297    Rotation2 (LinearAuto (LinearIso (Matrix2::rotation_z (angle.0), PhantomData)))
1298  }
1299  /// Panic if the given matrix is not orthogonal with determinant +1.
1300  ///
1301  /// This method checks whether `mat * mat^T == I` and `mat.determinant() == 1`.
1302  pub fn noisy (mat : Matrix2 <S>) -> Self where S : std::fmt::Debug {
1303    assert_eq!(mat * mat.transposed(), Matrix2::identity());
1304    assert_eq!(mat.determinant(), S::one());
1305    Rotation2 (LinearAuto (LinearIso (mat, PhantomData)))
1306  }
1307  /// Panic if the given matrix is not orthogonal with determinant +1.
1308  ///
1309  /// This method checks whether `mat * mat^T == I` and `mat.determinant() == 1`
1310  /// (approximately using relative equality).
1311  pub fn noisy_approx (mat : Matrix2 <S>) -> Self where
1312    S : approx::RelativeEq <Epsilon=S> + std::fmt::Debug
1313  {
1314    let four         = S::one() + S::one() + S::one() + S::one();
1315    let epsilon      = S::default_epsilon() * four;
1316    let max_relative = S::default_max_relative() * four;
1317    approx::assert_relative_eq!(mat * mat.transposed(), Matrix2::identity(),
1318      epsilon=epsilon, max_relative=max_relative);
1319    approx::assert_relative_eq!(mat.determinant(), S::one(), max_relative=max_relative);
1320    Rotation2 (LinearAuto (LinearIso (mat, PhantomData)))
1321  }
1322  /// It is a debug panic if the given matrix is not orthogonal with determinant +1.
1323  ///
1324  /// This method checks whether `mat * mat^T == I` and `mat.determinant() == 1`.
1325  pub fn unchecked (mat : Matrix2 <S>) -> Self where S : std::fmt::Debug {
1326    debug_assert!(mat * mat.transposed() == Matrix2::identity());
1327    debug_assert!(mat.determinant() == S::one());
1328    Rotation2 (LinearAuto (LinearIso (mat, PhantomData)))
1329  }
1330  /// It is a debug panic if the given matrix is not orthogonal with determinant +1.
1331  ///
1332  /// This method checks whether `mat * mat^T == I` and `mat.determinant() == 1`
1333  /// (approximately using relative equality).
1334  pub fn unchecked_approx (mat : Matrix2 <S>) -> Self where
1335    S : approx::RelativeEq <Epsilon=S> + std::fmt::Debug
1336  {
1337    if cfg!(debug_assertions) {
1338      let four         = S::one() + S::one() + S::one() + S::one();
1339      let epsilon      = S::default_epsilon() * four;
1340      let max_relative = S::default_max_relative() * four;
1341      approx::assert_relative_eq!(mat * mat.transposed(), Matrix2::identity(),
1342        max_relative=max_relative, epsilon=epsilon);
1343      approx::assert_relative_eq!(mat.determinant(), S::one(),
1344        max_relative=max_relative);
1345    }
1346    Rotation2 (LinearAuto (LinearIso (mat, PhantomData)))
1347  }
1348  /// Rotates a point around the origin
1349  pub fn rotate (self, point : Point2 <S>) -> Point2 <S> {
1350    Point2::from (self * point.0)
1351  }
1352}
1353impl <S> std::ops::Deref for Rotation2 <S> where S : Ring + MaybeSerDes {
1354  type Target = Matrix2 <S>;
1355  fn deref (&self) -> &Self::Target {
1356    &self.0
1357  }
1358}
1359impl <S> MultiplicativeGroup for Rotation2 <S> where S : Ring + MaybeSerDes { }
1360impl <S> MultiplicativeMonoid for Rotation2 <S> where S : Ring + MaybeSerDes { }
1361impl <S> num::Inv for Rotation2 <S> where S : Ring + MaybeSerDes {
1362  type Output = Self;
1363  fn inv (self) -> Self::Output {
1364    Rotation2 (LinearAuto (LinearIso (self.0.0.0.transpose(), PhantomData)))
1365  }
1366}
1367impl <S> std::ops::Mul <Vector2 <S>> for Rotation2 <S> where S : Ring + MaybeSerDes {
1368  type Output = Vector2 <S>;
1369  fn mul (self, rhs : Vector2 <S>) -> Self::Output {
1370    self.0 * rhs
1371  }
1372}
1373impl <S> std::ops::Mul <Rotation2 <S>> for Vector2 <S> where S : Ring + MaybeSerDes {
1374  type Output = Vector2 <S>;
1375  fn mul (self, rhs : Rotation2 <S>) -> Self::Output {
1376    self * rhs.0
1377  }
1378}
1379impl <S> std::ops::Mul for Rotation2 <S> where S : Ring + MaybeSerDes {
1380  type Output = Self;
1381  fn mul (self, rhs : Self) -> Self::Output {
1382    Rotation2 (self.0 * rhs.0)
1383  }
1384}
1385impl <S> std::ops::MulAssign <Self> for Rotation2 <S> where S : Ring + MaybeSerDes {
1386  fn mul_assign (&mut self, rhs : Self) {
1387    self.0 *= rhs.0
1388  }
1389}
1390impl <S> std::ops::Div for Rotation2 <S> where S : Ring + MaybeSerDes {
1391  type Output = Self;
1392  #[expect(clippy::suspicious_arithmetic_impl)]
1393  fn div (self, rhs : Self) -> Self::Output {
1394    use num::Inv;
1395    self * rhs.inv()
1396  }
1397}
1398impl <S> std::ops::DivAssign <Self> for Rotation2 <S> where S : Ring + MaybeSerDes {
1399  #[expect(clippy::suspicious_op_assign_impl)]
1400  fn div_assign (&mut self, rhs : Self) {
1401    use num::Inv;
1402    *self *= rhs.inv()
1403  }
1404}
1405impl <S> num::One for Rotation2 <S> where S : Ring + MaybeSerDes + num::Zero + num::One {
1406  fn one() -> Self {
1407    Rotation2 (LinearAuto (LinearIso (Matrix2::identity(), PhantomData)))
1408  }
1409}
1410
1411//
1412//  impl Rotation3
1413//
1414impl <S> Rotation3 <S> where S : Ring + MaybeSerDes {
1415  /// Identity rotation
1416  pub fn identity() -> Self {
1417    use num::One;
1418    Self::one()
1419  }
1420  /// Construct a rotation around the X axis.
1421  ///
1422  /// Positive angles are counter-clockwise.
1423  pub fn from_angle_x (angle : Rad <S>) -> Self where S : num::real::Real {
1424    Rotation3 (LinearAuto (LinearIso (Matrix3::rotation_x (angle.0), PhantomData)))
1425  }
1426  /// Construct a rotation around the Y axis
1427  ///
1428  /// Positive angles are counter-clockwise.
1429  pub fn from_angle_y (angle : Rad <S>) -> Self where S : num::real::Real {
1430    Rotation3 (LinearAuto (LinearIso (Matrix3::rotation_y (angle.0), PhantomData)))
1431  }
1432  /// Construct a rotation around the Z axis
1433  ///
1434  /// Positive angles are counter-clockwise.
1435  pub fn from_angle_z (angle : Rad <S>) -> Self where S : num::real::Real {
1436    Rotation3 (LinearAuto (LinearIso (Matrix3::rotation_z (angle.0), PhantomData)))
1437  }
1438  /// Construct a rotation from intrinsic ZX'Y'' Euler angles:
1439  ///
1440  /// - yaw: rotation around Z axis
1441  /// - pitch: rotation around X' axis
1442  /// - roll: rotation around Y'' axis
1443  pub fn from_angles_intrinsic (yaw : Rad <S>, pitch : Rad <S>, roll : Rad <S>)
1444    -> Self where S : num::real::Real
1445  {
1446    let rotation1 = Rotation3::from_angle_z (yaw);
1447    let rotation2 = Rotation3::from_axis_angle (rotation1.cols.x, pitch) * rotation1;
1448    Rotation3::from_axis_angle (rotation2.cols.y, roll) * rotation2
1449  }
1450  /// Construct a rotation around the given axis vector with the given angle
1451  pub fn from_axis_angle (axis : Vector3 <S>, angle : Rad <S>) -> Self where
1452    S : num::real::Real
1453  {
1454    Rotation3 (LinearAuto (LinearIso (
1455      Matrix3::rotation_3d (angle.0, axis), PhantomData)))
1456  }
1457  /// Construct an orthonormal matrix from a set of linearly-independent vectors using
1458  /// the Gram-Schmidt process
1459  pub fn orthonormalize (v1 : Vector3 <S>, v2 : Vector3 <S>, v3 : Vector3 <S>)
1460    -> Option <Self> where S : Field + Sqrt
1461  {
1462    if Matrix3::from_col_arrays ([v1, v2, v3].map (Vector3::into_array)).determinant()
1463      == S::zero()
1464    {
1465      None
1466    } else {
1467      let project = |u : Vector3 <S>, v : Vector3 <S>| u * (u.dot (v) / u.self_dot());
1468      let u1 = v1;
1469      let u2 = v2 - project (u1, v2);
1470      let u3 = v3 - project (u1, v3) - project (u2, v3);
1471      Some (Rotation3 (LinearAuto (LinearIso (Matrix3::from_col_arrays ([
1472        u1.normalize().into_array(),
1473        u2.normalize().into_array(),
1474        u3.normalize().into_array()
1475      ]), PhantomData))))
1476    }
1477  }
1478
1479  /// Returns a rotation with zero roll and oriented towards the target point.
1480  ///
1481  /// Returns the identity rotation if `point` is the origin.
1482  pub fn look_at (point : Point3 <S>) -> Self where
1483    S : num::Float + num::FloatConst + approx::RelativeEq <Epsilon=S> + std::fmt::Debug
1484  {
1485    if point == Point::origin() {
1486      Self::identity()
1487    } else {
1488      use num::Zero;
1489      let forward = point.0.normalized();
1490      let right = {
1491        let projected = forward.with_z (S::zero());
1492        if !projected.is_zero() {
1493          Self::from_angle_z (-Rad (S::FRAC_PI_2())) * projected.normalized()
1494        } else {
1495          Vector3::unit_x()
1496        }
1497      };
1498      let up = right.cross (forward);
1499      let mat =
1500        Matrix3::from_col_arrays ([right, forward, up].map (Vector3::into_array));
1501      Self::noisy_approx (mat)
1502    }
1503  }
1504
1505  /// Returns `None` if called with a matrix that is not orthonormal with determinant
1506  /// +1.
1507  ///
1508  /// This method checks whether `mat * mat^T == I` and `mat.determinant() == 1`.
1509  pub fn new (mat : Matrix3 <S>) -> Option <Self> {
1510    if mat * mat.transposed() != Matrix3::identity() || mat.determinant() != S::one() {
1511      None
1512    } else {
1513      Some (Rotation3 (LinearAuto (LinearIso (mat, PhantomData))))
1514    }
1515  }
1516  /// Returns `None` if called with a matrix that is not orthonormal with determinant
1517  /// +1.
1518  ///
1519  /// This method checks whether `mat * mat^T == I` and `mat.determinant() == 1`
1520  /// (approximately using relative equality).
1521  pub fn new_approx (mat : Matrix3 <S>) -> Option <Self> where
1522    S : approx::RelativeEq <Epsilon=S>
1523  {
1524    let four         = S::one() + S::one() + S::one() + S::one();
1525    let epsilon      = S::default_epsilon() * four;
1526    let max_relative = S::default_max_relative() * four;
1527    if approx::relative_ne!(mat * mat.transposed(), Matrix3::identity(),
1528      max_relative=max_relative, epsilon=epsilon
1529    ) || approx::relative_ne!(mat.determinant(), S::one(), max_relative=max_relative) {
1530      None
1531    } else {
1532      Some (Rotation3 (LinearAuto (LinearIso (mat, PhantomData))))
1533    }
1534  }
1535  /// Panic if the given matrix is not orthogonal with determinant +1.
1536  ///
1537  /// This method checks whether `mat * mat^T == I` and `mat.determinant() == 1`.
1538  pub fn noisy (mat : Matrix3 <S>) -> Self {
1539    assert!(mat * mat.transposed() == Matrix3::identity());
1540    assert!(mat.determinant() == S::one());
1541    Rotation3 (LinearAuto (LinearIso (mat, PhantomData)))
1542  }
1543  /// Panic if the given matrix is not orthogonal with determinant +1.
1544  ///
1545  /// This method checks whether `mat * mat^T == I` and `mat.determinant() == 1`
1546  /// (approximately using relative equality).
1547  pub fn noisy_approx (mat : Matrix3 <S>) -> Self where
1548    S : approx::RelativeEq <Epsilon=S> + std::fmt::Debug
1549  {
1550    let four         = S::one() + S::one() + S::one() + S::one();
1551    let eight        = four + S::one() + S::one() + S::one() + S::one();
1552    let epsilon      = S::default_epsilon() * four;
1553    let max_relative = S::default_max_relative() * eight;
1554    approx::assert_relative_eq!(mat * mat.transposed(), Matrix3::identity(),
1555      max_relative=max_relative, epsilon=epsilon);
1556    approx::assert_relative_eq!(mat.determinant(), S::one(), max_relative=max_relative);
1557    Rotation3 (LinearAuto (LinearIso (mat, PhantomData)))
1558  }
1559  /// It is a debug panic if the given matrix is not orthogonal with determinant +1.
1560  ///
1561  /// This method checks whether `mat * mat^T == I` and `mat.determinant() == 1`.
1562  pub fn unchecked (mat : Matrix3 <S>) -> Self where S : std::fmt::Debug {
1563    debug_assert!(mat * mat.transposed() == Matrix3::identity());
1564    debug_assert!(mat.determinant() == S::one());
1565    Rotation3 (LinearAuto (LinearIso (mat, PhantomData)))
1566  }
1567  /// It is a debug panic if the given matrix is not orthogonal with determinant +1.
1568  ///
1569  /// This method checks whether `mat * mat^T == I` and `mat.determinant() == 1`
1570  /// (approximately using relative equality).
1571  pub fn unchecked_approx (mat : Matrix3 <S>) -> Self where
1572    S : approx::RelativeEq <Epsilon=S> + std::fmt::Debug
1573  {
1574    if cfg!(debug_assertions) {
1575      let four         = S::one() + S::one() + S::one() + S::one();
1576      let epsilon      = S::default_epsilon() * four;
1577      let max_relative = S::default_max_relative() * four;
1578      approx::assert_relative_eq!(mat * mat.transposed(), Matrix3::identity(),
1579        max_relative=max_relative, epsilon=epsilon);
1580      approx::assert_relative_eq!(mat.determinant(), S::one(),
1581        max_relative=max_relative);
1582    }
1583    Rotation3 (LinearAuto (LinearIso (mat, PhantomData)))
1584  }
1585  /// Return intrinsic yaw (Z), pitch (X'), roll (Y'') angles.
1586  ///
1587  /// NOTE: this function returns the raw output of the `atan2` operations used to
1588  /// compute the angles. This function returns values in the range `[-\pi, \pi]`.
1589  pub fn intrinsic_angles (&self) -> (Rad <S>, Rad <S>, Rad <S>) where S : Real {
1590    let cols  = &self.cols;
1591    let yaw   = Rad (S::atan2 (-cols.y.x, cols.y.y));
1592    let pitch = Rad (S::atan2 (cols.y.z, S::sqrt (S::one() - cols.y.z * cols.y.z)));
1593    let roll  = Rad (S::atan2 (-cols.x.z, cols.z.z));
1594    (yaw, pitch, roll)
1595  }
1596
1597  /// Convert to versor (unit quaternion) representation.
1598  ///
1599  /// <https://stackoverflow.com/a/63745757>
1600  pub fn versor (self) -> Versor <S> where
1601    S : Real + MaybeSerDes + num::real::Real + approx::RelativeEq <Epsilon=S>
1602  {
1603    let diagonal = self.diagonal();
1604    let t     = diagonal.sum();
1605    let m     = MinMax::max (MinMax::max (MinMax::max (
1606      diagonal.x, diagonal.y), diagonal.z), t);
1607    let qmax  = S::half() * Sqrt::sqrt (S::one() - t + S::two() * m);
1608    let qmax4_recip = (S::four() * qmax).recip();
1609    let [qx, qy, qz, qw] : [S; 4];
1610    let cols = self.cols;
1611    if m == diagonal.x {
1612      qx = qmax;
1613      qy = qmax4_recip * (cols.x.y + cols.y.x);
1614      qz = qmax4_recip * (cols.x.z + cols.z.x);
1615      qw = -qmax4_recip * (cols.z.y - cols.y.z);
1616    } else if m == diagonal.y {
1617      qx = qmax4_recip * (cols.x.y + cols.y.x);
1618      qy = qmax;
1619      qz = qmax4_recip * (cols.y.z + cols.z.y);
1620      qw = -qmax4_recip * (cols.x.z - cols.z.x);
1621    } else if m == diagonal.z {
1622      qx = qmax4_recip * (cols.x.z + cols.z.x);
1623      qy = qmax4_recip * (cols.y.z + cols.z.y);
1624      qz = qmax;
1625      qw = -qmax4_recip * (cols.y.x - cols.x.y);
1626    } else {
1627      qx = -qmax4_recip * (cols.z.y - cols.y.z);
1628      qy = -qmax4_recip * (cols.x.z - cols.z.x);
1629      qz = -qmax4_recip * (cols.y.x - cols.x.y);
1630      qw = qmax;
1631    }
1632    let quat = Quaternion::from_xyzw (qx, qy, qz, qw);
1633    Versor::unchecked_approx (quat)
1634  }
1635  /// Rotates a point around the origin
1636  pub fn rotate (self, point : Point3 <S>) -> Point3 <S> {
1637    Point3::from (self * point.0)
1638  }
1639}
1640impl <S> std::ops::Deref for Rotation3 <S> where S : Ring + MaybeSerDes {
1641  type Target = Matrix3 <S>;
1642  fn deref (&self) -> &Self::Target {
1643    &self.0
1644  }
1645}
1646impl <S> MultiplicativeGroup  for Rotation3 <S> where S : Ring + MaybeSerDes { }
1647impl <S> MultiplicativeMonoid for Rotation3 <S> where S : Ring + MaybeSerDes { }
1648impl <S> num::Inv for Rotation3 <S> where S : Ring + MaybeSerDes {
1649  type Output = Self;
1650  fn inv (self) -> Self::Output {
1651    Rotation3 (LinearAuto (LinearIso (self.0.0.0.transpose(), PhantomData)))
1652  }
1653}
1654impl <S> std::ops::Mul <Vector3 <S>> for Rotation3 <S> where S : Ring + MaybeSerDes {
1655  type Output = Vector3 <S>;
1656  fn mul (self, rhs : Vector3 <S>) -> Self::Output {
1657    self.0 * rhs
1658  }
1659}
1660impl <S> std::ops::Mul <Rotation3 <S>> for Vector3 <S> where S : Ring + MaybeSerDes {
1661  type Output = Vector3 <S>;
1662  fn mul (self, rhs : Rotation3 <S>) -> Self::Output {
1663    self * rhs.0
1664  }
1665}
1666impl <S> std::ops::Mul for Rotation3 <S> where S : Ring + MaybeSerDes {
1667  type Output = Self;
1668  fn mul (self, rhs : Self) -> Self::Output {
1669    Rotation3 (self.0 * rhs.0)
1670  }
1671}
1672impl <S> std::ops::MulAssign <Self> for Rotation3 <S> where S : Ring + MaybeSerDes {
1673  fn mul_assign (&mut self, rhs : Self) {
1674    self.0 *= rhs.0
1675  }
1676}
1677impl <S> std::ops::Div for Rotation3 <S> where S : Ring + MaybeSerDes {
1678  type Output = Self;
1679  #[expect(clippy::suspicious_arithmetic_impl)]
1680  fn div (self, rhs : Self) -> Self::Output {
1681    use num::Inv;
1682    self * rhs.inv()
1683  }
1684}
1685impl <S> std::ops::DivAssign <Self> for Rotation3 <S> where S : Ring + MaybeSerDes {
1686  #[expect(clippy::suspicious_op_assign_impl)]
1687  fn div_assign (&mut self, rhs : Self) {
1688    use num::Inv;
1689    *self *= rhs.inv()
1690  }
1691}
1692impl <S> num::One for Rotation3 <S> where S : Ring + MaybeSerDes + num::Zero + num::One {
1693  fn one() -> Self {
1694    Rotation3 (LinearAuto (LinearIso (Matrix3::identity(), PhantomData)))
1695  }
1696}
1697impl <S> From <Angles3 <S>> for Rotation3 <S> where
1698  S : Real + MaybeSerDes + num::real::Real
1699{
1700  fn from (angles : Angles3 <S>) -> Self {
1701    Rotation3::from_angles_intrinsic (
1702      angles.yaw.angle(), angles.pitch.angle(), angles.roll.angle())
1703  }
1704}
1705
1706
1707//
1708//  impl Versor
1709//
1710impl <S : Real> Versor <S> {
1711  /// Normalizes the given quaternion.
1712  ///
1713  /// Panics if the zero quaternion is given.
1714  pub fn normalize (quaternion : Quaternion <S>) -> Self where S : std::fmt::Debug {
1715    assert_ne!(quaternion, Quaternion::zero());
1716    Versor (normalize_quaternion (quaternion))
1717  }
1718  /// Panic if the given quaternion is not a unit quaternion.
1719  ///
1720  /// This method checks whether `quaternion == quaternion.normalized()`.
1721  pub fn noisy (unit_quaternion : Quaternion <S>) -> Self where S : std::fmt::Debug {
1722    assert_eq!(unit_quaternion, normalize_quaternion (unit_quaternion));
1723    Versor (unit_quaternion)
1724  }
1725  /// Panic if the given quaternion is not a unit quaternion.
1726  ///
1727  /// Checks if the magnitude is approximately one.
1728  pub fn noisy_approx (unit_quaternion : Quaternion <S>) -> Self where
1729    S : num::real::Real + approx::RelativeEq <Epsilon=S>
1730  {
1731    assert!(unit_quaternion.into_vec4().is_normalized());
1732    Versor (unit_quaternion)
1733  }
1734  /// It is a debug panic if the given quaternion is not a unit quaternion.
1735  ///
1736  /// This method checks whether `quaternion == quaternion.normalized()`.
1737  pub fn unchecked (unit_quaternion : Quaternion <S>) -> Self where S : std::fmt::Debug {
1738    debug_assert_eq!(unit_quaternion, normalize_quaternion (unit_quaternion));
1739    Versor (unit_quaternion)
1740  }
1741  /// It is a debug panic if the given quaternion is not a unit quaternion.
1742  ///
1743  /// Checks if the magnitude is approximately one.
1744  pub fn unchecked_approx (unit_quaternion : Quaternion <S>) -> Self where
1745    S : num::real::Real + approx::RelativeEq <Epsilon=S>
1746  {
1747    debug_assert!(unit_quaternion.into_vec4().is_normalized());
1748    Versor (unit_quaternion)
1749  }
1750  /// Constructs the rotation using the direction and magnitude of the given vector
1751  // TODO: work around rotation_3d Float constraint
1752  pub fn from_scaled_axis (scaled_axis : &Vector3 <S>) -> Self where
1753    S : std::fmt::Debug + num::Float
1754  {
1755    if *scaled_axis == Vector3::zero() {
1756      let versor = Quaternion::rotation_3d (S::zero(), *scaled_axis);
1757      debug_assert_eq!(versor.magnitude(), S::one());
1758      Versor (versor)
1759    } else {
1760      let angle = scaled_axis.magnitude();
1761      debug_assert!(S::zero() < angle);
1762      let axis  = *scaled_axis / angle;
1763      Versor (Quaternion::rotation_3d (angle, axis))
1764    }
1765  }
1766}
1767impl <S> From <Rotation3 <S>> for Versor <S> where
1768  S : Real + MaybeSerDes + num::real::Real + approx::RelativeEq <Epsilon=S>
1769{
1770  fn from (rot : Rotation3 <S>) -> Self {
1771    rot.versor()
1772  }
1773}
1774impl <S : Real> std::ops::Deref for Versor <S> {
1775  type Target = Quaternion <S>;
1776  fn deref (&self) -> &Quaternion <S> {
1777    &self.0
1778  }
1779}
1780//  end impl Versor
1781
1782//
1783//  impl AffineMap
1784//
1785impl <S, A, B, M> AffineMap <S, A, B, M> where
1786  A : AffineSpace <S>,
1787  B : AffineSpace <S>,
1788  M : LinearMap <S, A::Vector, B::Vector>,
1789  S : Field + std::fmt::Display,
1790  B::Vector : std::fmt::Display
1791{
1792  pub const fn new (linear_map : M, translation : B::Vector) -> Self {
1793    AffineMap { linear_map, translation, _phantom: PhantomData }
1794  }
1795  pub fn transform (self, point : A::Point) -> B::Point {
1796    B::Point::from_vector (self.linear_map * point.to_vector() + self.translation)
1797  }
1798}
1799
1800//
1801//  impl LinearIso
1802//
1803impl <S, V, W, M> LinearIso <S, V, W, M> where
1804  M : LinearMap <S, V, W> + Copy,
1805  V : Module <S>,
1806  W : Module <S>,
1807  S : Ring
1808{
1809  /// Checks whether the determinant is non-zero
1810  pub fn is_invertible (linear_map : M) -> bool {
1811    linear_map.determinant() != S::zero()
1812  }
1813  /// Checks whether the determinant is non-zero with approximate equality
1814  pub fn is_invertible_approx (linear_map : M) -> bool where
1815    S : approx::RelativeEq <Epsilon=S>
1816  {
1817    let four         = S::one() + S::one() + S::one() + S::one();
1818    let epsilon      = S::default_epsilon() * four;
1819    let max_relative = S::default_max_relative() * four;
1820    approx::relative_ne!(linear_map.determinant(), S::zero(),
1821      max_relative=max_relative, epsilon=epsilon)
1822  }
1823  /// Checks if map is invertible
1824  pub fn new (linear_map : M) -> Option <Self> {
1825    if Self::is_invertible (linear_map) {
1826      Some (LinearIso (linear_map, PhantomData))
1827    } else {
1828      None
1829    }
1830  }
1831  /// Checks if map is invertible with approximate equality
1832  pub fn new_approx (linear_map : M) -> Option <Self> where
1833    S : approx::RelativeEq <Epsilon=S>
1834  {
1835    if Self::is_invertible_approx (linear_map) {
1836      Some (LinearIso (linear_map, PhantomData))
1837    } else {
1838      None
1839    }
1840  }
1841}
1842impl <S, V, W, M> std::ops::Deref for LinearIso <S, V, W, M> where
1843  M : LinearMap <S, V, W>,
1844  V : Module <S>,
1845  W : Module <S>,
1846  S : Ring
1847{
1848  type Target = M;
1849  fn deref (&self) -> &Self::Target {
1850    &self.0
1851  }
1852}
1853impl <S, V> num::One for LinearIso <S, V, V, V::LinearEndo> where
1854  V : Module <S>,
1855  S : Ring
1856{
1857  fn one () -> Self {
1858    LinearIso (V::LinearEndo::one(), PhantomData)
1859  }
1860}
1861impl <S, V, W, M> std::ops::Mul <V> for LinearIso <S, V, W, M> where
1862  M : LinearMap <S, V, W>,
1863  V : Module <S>,
1864  W : Module <S>,
1865  S : Ring
1866{
1867  type Output = W;
1868  fn mul (self, rhs : V) -> Self::Output {
1869    self.0 * rhs
1870  }
1871}
1872impl <S, V> std::ops::Mul for LinearIso <S, V, V, V::LinearEndo> where
1873  V : Module <S>,
1874  S : Ring
1875{
1876  type Output = Self;
1877  fn mul (self, rhs : Self) -> Self::Output {
1878    LinearIso (self.0 * rhs.0, PhantomData)
1879  }
1880}
1881impl <S, V> std::ops::MulAssign for LinearIso <S, V, V, V::LinearEndo> where
1882  V : Module <S>,
1883  S : Ring
1884{
1885  fn mul_assign (&mut self, rhs : Self) {
1886    self.0 *= rhs.0
1887  }
1888}
1889
1890//
1891//  impl LinearAuto
1892//
1893impl <S, V> LinearAuto <S, V> where
1894  V : Module <S>,
1895  V::LinearEndo : MaybeSerDes,
1896  S : Ring
1897{
1898  /// Returns false if called with a matrix that is not orthogonal with determinant
1899  /// +/-1.
1900  ///
1901  /// This method checks whether `mat * mat^T == I` and `mat.determinant() == +/-1`.
1902  pub fn is_orthonormal (&self) -> bool {
1903    use num::One;
1904    let determinant = self.0.0.determinant();
1905    self.0.0 * self.0.0.transpose() == V::LinearEndo::one() &&
1906    (determinant == S::one() || determinant == -S::one())
1907  }
1908  /// Returns `None` if called with a matrix that is not orthogonal with determinant
1909  /// +/-1.
1910  ///
1911  /// This method checks whether `mat * mat^T == I` and `mat.determinant() == +/-1`
1912  /// (approximately using relative equality).
1913  pub fn is_orthonormal_approx (&self) -> bool where
1914    S : approx::RelativeEq <Epsilon=S>,
1915    V::LinearEndo : approx::RelativeEq <Epsilon=S>
1916  {
1917    use num::One;
1918    let four         = S::one() + S::one() + S::one() + S::one();
1919    let epsilon      = S::default_epsilon() * four;
1920    let max_relative = S::default_max_relative() * four;
1921    let determinant  = self.0.0.determinant();
1922    approx::relative_eq!(self.0.0 * self.0.0.transpose(), V::LinearEndo::one(),
1923      max_relative=max_relative, epsilon=epsilon) &&
1924    ( approx::relative_eq!(determinant,  S::one(), max_relative=max_relative) ||
1925      approx::relative_eq!(determinant, -S::one(), max_relative=max_relative) )
1926  }
1927  /// Checks whether the transformation is a special orthogonal matrix.
1928  ///
1929  /// This method checks whether `mat * mat^T == I` and `mat.determinant() == 1`.
1930  pub fn is_rotation (&self) -> bool {
1931    use num::One;
1932    let determinant = self.0.0.determinant();
1933    self.0.0 * self.0.0.transpose() == V::LinearEndo::one() &&
1934    determinant == S::one()
1935  }
1936  /// Checks whether the transformation is a special orthogonal matrix.
1937  ///
1938  /// This method checks whether `mat * mat^T == I` and `mat.determinant() == 1`
1939  /// (approximately using relative equality).
1940  pub fn is_rotation_approx (&self) -> bool where
1941    S : approx::RelativeEq <Epsilon=S>,
1942    V::LinearEndo : approx::RelativeEq <Epsilon=S>
1943  {
1944    use num::One;
1945    let four         = S::one() + S::one() + S::one() + S::one();
1946    let epsilon      = S::default_epsilon() * four;
1947    let max_relative = S::default_max_relative() * four;
1948    let determinant  = self.0.0.determinant();
1949    approx::relative_eq!(self.0.0 * self.0.0.transpose(), V::LinearEndo::one(),
1950      max_relative=max_relative, epsilon=epsilon) &&
1951    approx::relative_eq!(determinant,  S::one(), max_relative=max_relative)
1952  }
1953}
1954impl <S, V> MultiplicativeMonoid for LinearAuto <S, V> where
1955  V : Module <S>,
1956  V::LinearEndo : MaybeSerDes + PartialEq,
1957  S : Ring
1958{ }
1959impl <S, V> std::ops::Mul <V> for LinearAuto <S, V> where
1960  V : Module <S>,
1961  V::LinearEndo : MaybeSerDes,
1962  S : Ring
1963{
1964  type Output = V;
1965  fn mul (self, rhs : V) -> Self::Output {
1966    self.0 * rhs
1967  }
1968}
1969impl <S, V> std::ops::Mul for LinearAuto <S, V> where
1970  V : Module <S>,
1971  V::LinearEndo : MaybeSerDes,
1972  S : Ring
1973{
1974  type Output = Self;
1975  fn mul (self, rhs : Self) -> Self::Output {
1976    LinearAuto (self.0 * rhs.0)
1977  }
1978}
1979impl <S, V> std::ops::MulAssign <Self> for LinearAuto <S, V> where
1980  V : Module <S>,
1981  V::LinearEndo : MaybeSerDes,
1982  S : Ring
1983{
1984  fn mul_assign (&mut self, rhs : Self) {
1985    self.0 *= rhs.0
1986  }
1987}
1988impl <S, V> num::One for LinearAuto <S, V> where
1989  V : Module <S>,
1990  V::LinearEndo : MaybeSerDes,
1991  S : Ring
1992{
1993  fn one() -> Self {
1994    LinearAuto (LinearIso::one())
1995  }
1996}
1997
1998//
1999//  impl Affinity
2000//
2001impl <S, A, B, M> Affinity <S, A, B, M> where
2002  M : LinearMap <S, A::Vector, B::Vector>,
2003  A : AffineSpace <S>,
2004  B : AffineSpace <S>,
2005  S : Field + std::fmt::Display,
2006  B::Vector : std::fmt::Display
2007{
2008  pub const fn new (
2009    linear_iso  : LinearIso <S, A::Vector, B::Vector, M>, translation : B::Vector
2010  ) -> Self {
2011    Affinity { linear_iso, translation, _phantom: PhantomData }
2012  }
2013}
2014
2015//
2016//  impl Projectivity
2017//
2018impl <S, V, W, P, Q, M> Projectivity <S, V, W, P, Q, M> where
2019  M : LinearMap <S, P, Q>,
2020  P : ProjectiveSpace <S, V>,
2021  Q : ProjectiveSpace <S, W>,
2022  V : VectorSpace <S> + std::fmt::Display,
2023  W : VectorSpace <S> + std::fmt::Display,
2024  S : Field + std::fmt::Display
2025{
2026  pub const fn new (linear_iso : LinearIso <S, P, Q, M>) -> Self {
2027    Projectivity (linear_iso, PhantomData)
2028  }
2029  pub fn transform (self, vector : P) -> Q {
2030    **self * vector
2031  }
2032}
2033impl <S, V, W, P, Q, M> std::ops::Deref for Projectivity <S, V, W, P, Q, M> where
2034  M : LinearMap <S, P, Q>,
2035  P : ProjectiveSpace <S, V>,
2036  Q : ProjectiveSpace <S, W>,
2037  V : VectorSpace <S> + std::fmt::Display,
2038  W : VectorSpace <S> + std::fmt::Display,
2039  S : Field + std::fmt::Display
2040{
2041  type Target = LinearIso <S, P, Q, M>;
2042  fn deref (&self) -> &Self::Target {
2043    &self.0
2044  }
2045}
2046
2047macro_rules! impl_angle {
2048  ( $angle:ident, $docname:expr ) => {
2049    #[doc = $docname]
2050    #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
2051    // TODO: derive From here causes a test failure in the intrinsic angles test
2052    #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, PartialOrd)]
2053    pub struct $angle <S> (pub S);
2054    impl_numcast_primitive!($angle);
2055    impl <S : Real> AdditiveGroup  for $angle <S> { }
2056    impl <S : Real> AdditiveMonoid for $angle <S> { }
2057    impl <S : Ring> std::ops::Neg for $angle <S> {
2058      type Output = Self;
2059      fn neg (self) -> Self::Output {
2060        $angle (-self.0)
2061      }
2062    }
2063    impl <S : Ring> std::ops::Add for $angle <S> {
2064      type Output = Self;
2065      fn add (self, other : Self) -> Self::Output {
2066        $angle (self.0 + other.0)
2067      }
2068    }
2069    impl <S : Ring> std::ops::AddAssign for $angle <S> {
2070      fn add_assign (&mut self, other : Self) {
2071        self.0 += other.0
2072      }
2073    }
2074    impl <S : Ring> std::ops::Sub for $angle <S> {
2075      type Output = Self;
2076      fn sub (self, other : Self) -> Self::Output {
2077        $angle (self.0 - other.0)
2078      }
2079    }
2080    impl <S : Ring> std::ops::SubAssign for $angle <S> {
2081      fn sub_assign (&mut self, other : Self) {
2082        self.0 -= other.0
2083      }
2084    }
2085    impl <S : Ring> std::ops::Mul <S> for $angle <S> {
2086      type Output = Self;
2087      fn mul (self, scalar : S) -> Self::Output {
2088        $angle (scalar * self.0)
2089      }
2090    }
2091    impl <S : Ring> std::ops::MulAssign <S> for $angle <S> {
2092      fn mul_assign (&mut self, scalar : S) {
2093        self.0 *= scalar
2094      }
2095    }
2096    impl <S : Ring> std::ops::Div for $angle <S> {
2097      type Output = S;
2098      fn div (self, other : Self) -> Self::Output {
2099        self.0 / other.0
2100      }
2101    }
2102    impl <S : Ring> std::ops::Div <S> for $angle <S> {
2103      type Output = Self;
2104      fn div (self, scalar : S) -> Self::Output {
2105        $angle (self.0 / scalar)
2106      }
2107    }
2108    impl <S : Field> std::ops::DivAssign <S> for $angle <S> {
2109      fn div_assign (&mut self, scalar : S) {
2110        self.0 /= scalar
2111      }
2112    }
2113    impl <S : Ring> std::ops::Rem for $angle <S> {
2114      type Output = Self;
2115      fn rem (self, other : Self) -> Self::Output {
2116        $angle (self.0 % other.0)
2117      }
2118    }
2119    impl <S : Ring> num::Zero for $angle <S> {
2120      fn zero() -> Self {
2121        $angle (S::zero())
2122      }
2123      fn is_zero (&self) -> bool {
2124        self.0.is_zero()
2125      }
2126    }
2127  }
2128}
2129
2130macro_rules! impl_angle_wrapped {
2131  ( $angle:ident, $comment:expr ) => {
2132    #[doc = $comment]
2133    #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
2134    #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, PartialOrd)]
2135    pub struct $angle <S> (Rad <S>);
2136
2137    impl_numcast!($angle);
2138    impl <S : Real> $angle <S> {
2139      pub const fn angle (&self) -> Rad <S> {
2140        self.0
2141      }
2142    }
2143    impl <S : Real> AdditiveGroup  for $angle <S> { }
2144    impl <S : Real> AdditiveMonoid for $angle <S> { }
2145    impl <S : Real> std::ops::Neg for $angle <S> {
2146      type Output = Self;
2147      fn neg (self) -> Self::Output {
2148        self.map (Rad::neg)
2149      }
2150    }
2151    impl <S : Real> std::ops::Add for $angle <S> {
2152      type Output = Self;
2153      fn add (self, other : Self) -> Self::Output {
2154        self.map (|angle| angle + other.0)
2155      }
2156    }
2157    impl <S : Real> std::ops::AddAssign for $angle <S> {
2158      fn add_assign (&mut self, other : Self) {
2159        *self = *self + other
2160      }
2161    }
2162    impl <S : Real> std::ops::Add <Rad <S>> for $angle <S> {
2163      type Output = Self;
2164      fn add (self, angle : Rad <S>) -> Self::Output {
2165        self.map (|a| a + angle)
2166      }
2167    }
2168    impl <S : Real> std::ops::AddAssign <Rad <S>> for $angle <S> {
2169      fn add_assign (&mut self, angle : Rad <S>) {
2170        *self = *self + angle
2171      }
2172    }
2173    impl <S : Real> std::ops::Sub for $angle <S> {
2174      type Output = Self;
2175      fn sub (self, other : Self) -> Self::Output {
2176        self.map (|angle| angle - other.0)
2177      }
2178    }
2179    impl <S : Real> std::ops::SubAssign for $angle <S> {
2180      fn sub_assign (&mut self, other : Self) {
2181        *self = *self - other
2182      }
2183    }
2184    impl <S : Real> std::ops::Sub <Rad <S>> for $angle <S> {
2185      type Output = Self;
2186      fn sub (self, angle : Rad <S>) -> Self::Output {
2187        self.map (|a| a - angle)
2188      }
2189    }
2190    impl <S : Real> std::ops::SubAssign <Rad <S>> for $angle <S> {
2191      fn sub_assign (&mut self, angle : Rad <S>) {
2192        *self = *self - angle
2193      }
2194    }
2195    impl <S : Real> std::ops::Mul <S> for $angle <S> {
2196      type Output = Self;
2197      fn mul (self, scalar : S) -> Self::Output {
2198        self.map (|angle| angle * scalar)
2199      }
2200    }
2201    impl <S : Real> std::ops::MulAssign <S> for $angle <S> {
2202      fn mul_assign (&mut self, scalar : S) {
2203        *self = *self * scalar
2204      }
2205    }
2206    impl <S : Real> std::ops::Div for $angle <S> {
2207      type Output = S;
2208      fn div (self, other : Self) -> Self::Output {
2209        self.0 / other.0
2210      }
2211    }
2212    impl <S : Real> std::ops::Div <S> for $angle <S> {
2213      type Output = Self;
2214      fn div (self, scalar : S) -> Self::Output {
2215        self.map (|angle| angle / scalar)
2216      }
2217    }
2218    impl <S : Real> std::ops::DivAssign <S> for $angle <S> {
2219      fn div_assign (&mut self, scalar : S) {
2220        *self = *self / scalar
2221      }
2222    }
2223    impl <S : Real> std::ops::Rem for $angle <S> {
2224      type Output = Self;
2225      fn rem (self, other : Self) -> Self::Output {
2226        self.map (|angle| angle % other.0)
2227      }
2228    }
2229    impl <S : Real> num::Zero for $angle <S> {
2230      fn zero() -> Self {
2231        $angle (Rad::zero())
2232      }
2233      fn is_zero (&self) -> bool {
2234        self.0.is_zero()
2235      }
2236    }
2237  }
2238}
2239
2240macro_rules! impl_dimension {
2241  ( $point:ident, $vector:ident, $nonzero:ident, $unit:ident,
2242    $point_fun:ident, $vector_fun:ident,
2243    [$($component:ident),+],
2244    [$(($axis_method:ident, $unit_method:ident)),+], [$($projective:ident)?],
2245    $matrix:ident, $affine:ident, $euclidean:ident, $ndims:expr, $dimension:expr
2246  ) => {
2247    #[doc = $dimension]
2248    #[doc = "position"]
2249    #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Display, From, Neg)]
2250    #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
2251    #[display("{}", _0)]
2252    #[repr(C)]
2253    pub struct $point <S> (pub $vector <S>);
2254
2255    #[doc = $dimension]
2256    #[doc = "affine space"]
2257    #[derive(Debug)]
2258    pub struct $affine <S> (PhantomData <S>);
2259    impl <S : Field> AffineSpace <S> for $affine <S> {
2260      type Point  = $point  <S>;
2261      type Vector = $vector <S>;
2262    }
2263
2264    #[doc = $dimension]
2265    #[doc = "euclidean space"]
2266    #[derive(Debug)]
2267    pub struct $euclidean <S> (PhantomData <S>);
2268    impl <S : Real> EuclideanSpace <S> for $euclidean <S> { }
2269    impl <S : Real> AffineSpace <S> for $euclidean <S> {
2270      type Point  = $point  <S>;
2271      type Vector = $vector <S>;
2272    }
2273
2274    #[doc = $dimension]
2275    #[doc = "non-zero vector"]
2276    #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
2277    #[derive(Clone, Copy, Debug, Eq, PartialEq, Display)]
2278    #[display("{}", _0)]
2279    #[repr(C)]
2280    pub struct $nonzero <S> ($vector <S>);
2281
2282    #[doc = $dimension]
2283    #[doc = "unit vector"]
2284    #[cfg_attr(feature = "derive_serdes", derive(Serialize, Deserialize))]
2285    #[derive(Clone, Copy, Debug, Eq, PartialEq, Display)]
2286    #[display("{}", _0)]
2287    #[repr(C)]
2288    pub struct $unit <S> ($vector <S>);
2289
2290    //
2291    //  impl PointN
2292    //
2293    #[doc = "Construct a"]
2294    #[doc = $dimension]
2295    #[doc = "point"]
2296    pub const fn $point_fun <S> ($($component : S),+) -> $point <S> {
2297      $point::new ($($component),+)
2298    }
2299    impl_numcast!($point);
2300    impl <S> $point <S> {
2301      pub const fn new ($($component : S),+) -> Self {
2302        $point ($vector::new ($($component),+))
2303      }
2304    }
2305    impl <S> Point <$vector <S>> for $point <S> where S : Ring {
2306      fn to_vector (self) -> $vector <S> {
2307        self.0
2308      }
2309      fn from_vector (vector : $vector <S>) -> Self {
2310        $point (vector)
2311      }
2312    }
2313    impl <S> From<[S; $ndims]> for $point <S> {
2314      fn from (array : [S; $ndims]) -> Self {
2315        $point (array.into())
2316      }
2317    }
2318    impl <S> std::cmp::PartialOrd for $point <S> where S : PartialOrd {
2319      fn partial_cmp (&self, other : &Self) -> Option <std::cmp::Ordering> {
2320        self.0.as_slice().partial_cmp (&other.0.as_slice())
2321      }
2322    }
2323    impl <S> std::ops::Add <$vector <S>> for $point <S> where S : AdditiveGroup {
2324      type Output = Self;
2325      fn add (self, displacement : $vector <S>) -> Self::Output {
2326        $point (self.0 + displacement)
2327      }
2328    }
2329    impl <S> std::ops::Add <&$vector <S>> for $point <S> where S : AdditiveGroup + Copy {
2330      type Output = Self;
2331      fn add (self, displacement : &$vector <S>) -> Self::Output {
2332        $point (self.0 + *displacement)
2333      }
2334    }
2335    impl <S> std::ops::Add <$vector <S>> for &$point <S> where S : AdditiveGroup + Copy {
2336      type Output = $point <S>;
2337      fn add (self, displacement : $vector <S>) -> Self::Output {
2338        $point (self.0 + displacement)
2339      }
2340    }
2341    impl <S> std::ops::Add <&$vector <S>> for &$point <S> where
2342      S : AdditiveGroup + Copy
2343    {
2344      type Output = $point <S>;
2345      fn add (self, displacement : &$vector <S>) -> Self::Output {
2346        $point (self.0 + *displacement)
2347      }
2348    }
2349    impl <S> std::ops::AddAssign <$vector <S>> for $point <S> where S : AdditiveGroup {
2350      fn add_assign (&mut self, displacement : $vector <S>) {
2351        self.0 += displacement
2352      }
2353    }
2354    impl <S> std::ops::AddAssign <&$vector <S>> for $point <S> where
2355      S : AdditiveGroup + Copy
2356    {
2357      fn add_assign (&mut self, displacement : &$vector <S>) {
2358        self.0 += *displacement
2359      }
2360    }
2361    impl <S> std::ops::Sub <$vector <S>> for $point <S> where S : AdditiveGroup {
2362      type Output = Self;
2363      fn sub (self, displacement : $vector <S>) -> Self::Output {
2364        $point (self.0 - displacement)
2365      }
2366    }
2367    impl <S> std::ops::Sub <&$vector <S>> for $point <S> where S : AdditiveGroup + Copy {
2368      type Output = Self;
2369      fn sub (self, displacement : &$vector <S>) -> Self::Output {
2370        $point (self.0 - *displacement)
2371      }
2372    }
2373    impl <S> std::ops::Sub <$point <S>> for $point <S> where S : AdditiveGroup {
2374      type Output = $vector <S>;
2375      fn sub (self, other : Self) -> Self::Output {
2376        self.0 - other.0
2377      }
2378    }
2379    impl <S> std::ops::Sub <&$point <S>> for $point <S> where S : AdditiveGroup + Copy {
2380      type Output = $vector <S>;
2381      fn sub (self, other : &Self) -> Self::Output {
2382        self.0 - other.0
2383      }
2384    }
2385    impl <S> std::ops::Sub <$vector <S>> for &$point <S> where S : AdditiveGroup + Copy {
2386      type Output = $point <S>;
2387      fn sub (self, displacement : $vector <S>) -> Self::Output {
2388        $point (self.0 - displacement)
2389      }
2390    }
2391    impl <S> std::ops::Sub <&$vector <S>> for &$point <S> where
2392      S : AdditiveGroup + Copy
2393    {
2394      type Output = $point <S>;
2395      fn sub (self, displacement : &$vector <S>) -> Self::Output {
2396        $point (self.0 - *displacement)
2397      }
2398    }
2399    impl <S> std::ops::Sub <$point <S>> for &$point <S> where S : AdditiveGroup + Copy {
2400      type Output = $vector <S>;
2401      fn sub (self, other : $point <S>) -> Self::Output {
2402        self.0 - other.0
2403      }
2404    }
2405    impl <S> std::ops::Sub <&$point <S>> for &$point <S> where S : AdditiveGroup + Copy {
2406      type Output = $vector <S>;
2407      fn sub (self, other : &$point <S>) -> Self::Output {
2408        self.0 - other.0
2409      }
2410    }
2411    impl <S> std::ops::SubAssign <$vector <S>> for $point <S> where
2412      S : AdditiveGroup
2413    {
2414      fn sub_assign (&mut self, displacement : $vector <S>) {
2415        self.0 -= displacement
2416      }
2417    }
2418    impl <S> std::ops::SubAssign <&$vector <S>> for $point <S> where
2419      S : AdditiveGroup + Copy
2420    {
2421      fn sub_assign (&mut self, displacement : &$vector <S>) {
2422        self.0 -= *displacement
2423      }
2424    }
2425    impl <S> approx::AbsDiffEq for $point <S> where
2426      S : approx::AbsDiffEq,
2427      S::Epsilon : Copy
2428    {
2429      type Epsilon = S::Epsilon;
2430      fn default_epsilon() -> Self::Epsilon {
2431        S::default_epsilon()
2432      }
2433      #[inline]
2434      fn abs_diff_eq (&self, other : &Self, epsilon : Self::Epsilon) -> bool {
2435        self.0.abs_diff_eq (&other.0, epsilon)
2436      }
2437    }
2438    impl <S> approx::RelativeEq for $point <S> where
2439      S : approx::RelativeEq,
2440      S::Epsilon : Copy
2441    {
2442      fn default_max_relative() -> Self::Epsilon {
2443        S::default_max_relative()
2444      }
2445      #[inline]
2446      fn relative_eq (&self,
2447        other : &Self, epsilon : Self::Epsilon, max_relative : Self::Epsilon
2448      ) -> bool {
2449        self.0.relative_eq (&other.0, epsilon, max_relative)
2450      }
2451    }
2452    impl <S> approx::UlpsEq for $point <S> where
2453      S : approx::UlpsEq,
2454      S::Epsilon : Copy
2455    {
2456      fn default_max_ulps() -> u32 {
2457        S::default_max_ulps()
2458      }
2459      #[inline]
2460      fn ulps_eq (&self, other : &Self, epsilon : Self::Epsilon, max_ulps : u32)
2461        -> bool
2462      {
2463        self.0.ulps_eq (&other.0, epsilon, max_ulps)
2464      }
2465    }
2466    //
2467    //  impl VectorN
2468    //
2469    #[doc = "Construct a"]
2470    #[doc = $dimension]
2471    #[doc = "vector"]
2472    pub const fn $vector_fun <S> ($($component : S),+) -> $vector <S> {
2473      $vector::new ($($component),+)
2474    }
2475    impl <S : Field> InnerProductSpace <S> for $vector <S> { }
2476    impl <S : Ring> Dot <S> for $vector <S> {
2477      fn dot (self, other : Self) -> S {
2478        self.dot (other)
2479      }
2480    }
2481    impl <S : Field> VectorSpace <S> for $vector <S> {
2482      fn map <F> (self, f : F) -> Self where F : FnMut (S) -> S {
2483        self.map (f)
2484      }
2485    }
2486    impl <S : Ring> Module <S> for $vector <S> {
2487      type LinearEndo = $matrix <S>;
2488    }
2489    impl <S : Ring> LinearMap <S, $vector <S>, $vector <S>> for $matrix <S> {
2490      fn determinant (self) -> S {
2491        self.determinant()
2492      }
2493      fn transpose (self) -> Self {
2494        self.transposed()
2495      }
2496    }
2497    impl <S : Ring> MultiplicativeMonoid for $matrix <S> { }
2498    impl <S> GroupAction <$point <S>> for $vector <S> where S : AdditiveGroup {
2499      fn action (self, point : $point <S>) -> $point <S> {
2500        point + self
2501      }
2502    }
2503    impl <S : Ring> AdditiveGroup  for $vector <S> { }
2504    impl <S : Ring> AdditiveMonoid for $vector <S> { }
2505    impl <S : AdditiveGroup> Group for $vector <S> {
2506      fn identity() -> Self {
2507        Self::zero()
2508      }
2509      fn operation (a : Self, b : Self) -> Self {
2510        a + b
2511      }
2512    }
2513    impl <S> Point <$vector <S>> for $vector <S> where S : Ring {
2514      fn to_vector (self) -> $vector <S> {
2515        self
2516      }
2517      fn from_vector (vector : $vector <S>) -> Self {
2518        vector
2519      }
2520    }
2521    impl <S> std::ops::Mul <LinearAuto <S, Self>> for $vector <S> where
2522      S : Ring + MaybeSerDes
2523    {
2524      type Output = Self;
2525      fn mul (self, rhs : LinearAuto <S, Self>) -> Self::Output {
2526        self * rhs.0
2527      }
2528    }
2529    impl <S> std::ops::Mul <LinearIso <S, Self, Self, $matrix <S>>> for $vector <S> where
2530      S : Ring + MaybeSerDes
2531    {
2532      type Output = Self;
2533      fn mul (self, rhs : LinearIso <S, Self, Self, $matrix <S>>) -> Self::Output {
2534        self * rhs.0
2535      }
2536    }
2537    impl <S> num::Inv for LinearAuto <S, $vector <S>> where
2538      S : Ring + num::Float + MaybeSerDes
2539    {
2540      type Output = Self;
2541      fn inv (self) -> Self::Output {
2542        LinearAuto (self.0.inv())
2543      }
2544    }
2545    impl <S> std::ops::Div for LinearAuto <S, $vector <S>> where
2546      S : Ring + num::Float + MaybeSerDes
2547    {
2548      type Output = Self;
2549      fn div (self, rhs : Self) -> Self::Output {
2550        LinearAuto (self.0 / rhs.0)
2551      }
2552    }
2553    impl <S> std::ops::DivAssign <Self> for LinearAuto <S, $vector <S>> where
2554      S : Ring + num::Float + MaybeSerDes
2555    {
2556      fn div_assign (&mut self, rhs : Self) {
2557        self.0 /= rhs.0
2558      }
2559    }
2560    impl <S> MultiplicativeGroup for LinearAuto <S, $vector <S>> where
2561      S : Ring + num::Float + MaybeSerDes
2562    { }
2563    // projective completion
2564    $(
2565      impl <S> ProjectiveSpace <S, $vector <S>> for $projective <S> where
2566        S : Field + std::fmt::Display
2567      {
2568        fn homography <A> (
2569          affinity : Affinity <S, A, A, <A::Vector as Module <S>>::LinearEndo>
2570        ) -> Projectivity <S, $vector <S>, $vector <S>, Self, Self, Self::LinearEndo>
2571          where A : AffineSpace <S, Vector=$vector <S>>
2572        {
2573          Projectivity::new (
2574            LinearIso::<S, Self, Self, Self::LinearEndo>::new (
2575              (*affinity.linear_iso).into()
2576            ).unwrap())
2577        }
2578        fn homogeneous <A> (point_or_vector : Either <A::Point, A::Vector>) -> Self where
2579          A : AffineSpace <S, Vector=$vector <S>>,
2580          $vector <S> : GroupAction <A::Point>
2581        {
2582          match point_or_vector {
2583            Either::Left  (point)  => (point.to_vector(), S::one()).into(),
2584            Either::Right (vector) => (vector, S::zero()).into(),
2585          }
2586        }
2587      }
2588    )?
2589    //
2590    //  impl MatrixN
2591    //
2592    impl <S, V, W> num::Inv for LinearIso <S, V, W, $matrix <S>> where
2593      V : Module <S>,
2594      W : Module <S>,
2595      S : Ring + num::Float
2596    {
2597      type Output = LinearIso <S, W, V, $matrix <S>>;
2598      fn inv (self) -> Self::Output {
2599        // TODO: currently the vek crate only implements invert for Mat4
2600        let mat4 = Matrix4::from (self.0);
2601        LinearIso (mat4.inverted().into(), PhantomData::default())
2602      }
2603    }
2604    impl <S, V> std::ops::Div for LinearIso <S, V, V, $matrix <S>> where
2605      V : Module <S, LinearEndo=$matrix <S>>,
2606      S : Ring + num::Float
2607    {
2608      type Output = Self;
2609      #[expect(clippy::suspicious_arithmetic_impl)]
2610      fn div (self, rhs : Self) -> Self::Output {
2611        use num::Inv;
2612        self * rhs.inv()
2613      }
2614    }
2615    impl <S, V> std::ops::DivAssign for LinearIso <S, V, V, $matrix <S>> where
2616      V : Module <S, LinearEndo=$matrix <S>>,
2617      S : Ring + num::Float
2618    {
2619      #[expect(clippy::suspicious_op_assign_impl)]
2620      fn div_assign (&mut self, rhs : Self) {
2621        use num::Inv;
2622        *self *= rhs.inv()
2623      }
2624    }
2625    //
2626    //  impl NonZeroN
2627    //
2628    impl_numcast!($nonzero);
2629    impl <S : Ring> $nonzero <S> {
2630      /// Returns 'None' if called with the zero vector
2631      // TODO: move broken doctests to unit tests
2632      // # Example
2633      //
2634      // ```
2635      // # use math_utils::$nonzero;
2636      // assert!($nonzero::new ([1.0, 0.0].into()).is_some());
2637      // assert!($nonzero::new ([0.0, 0.0].into()).is_none());
2638      // ```
2639      pub fn new (vector : $vector <S>) -> Option <Self> {
2640        use num::Zero;
2641        if !vector.is_zero() {
2642          Some ($nonzero (vector))
2643        } else {
2644          None
2645        }
2646      }
2647      /// Panics if zero vector is given.
2648      // TODO: move broken doctests to unit tests
2649      // # Panics
2650      //
2651      // ```should_panic
2652      // # use math_utils::$nonzero;
2653      // let x = $nonzero::noisy ([0.0, 0.0].into());  // panic!
2654      // ```
2655      pub fn noisy (vector : $vector <S>) -> Self {
2656        use num::Zero;
2657        assert!(!vector.is_zero());
2658        $nonzero (vector)
2659      }
2660      /// Map an operation on the underlying vector, panicking if the result is zero
2661      // TODO: move broken doctests to unit tests
2662      // # Panics
2663      //
2664      // Panics of the result is zero:
2665      //
2666      // ```should_panic
2667      // # use math_utils::$nonzero;
2668      // let v = $nonzero::noisy ([1.0, 1.0].into())
2669      //   .map_noisy (|x| 0.0 * x);  // panic!
2670      // ```
2671      pub fn map_noisy (self, fun : fn ($vector <S>) -> $vector <S>) -> Self {
2672        Self::noisy (fun (self.0))
2673      }
2674    }
2675    impl <S : Ring> std::ops::Deref for $nonzero <S> {
2676      type Target = $vector <S>;
2677      fn deref (&self) -> &$vector <S> {
2678        &self.0
2679      }
2680    }
2681    //
2682    //  impl UnitN
2683    //
2684    impl_numcast!($unit);
2685    impl <S : Real> $unit <S> {
2686      // TODO: move broken doc tests to unit tests
2687      // ```
2688      // # use math_utils::$unit;
2689      // assert_eq!($unit::axis_x(), $unit::new ([1.0, 0.0].into()).unwrap());
2690      // ```
2691      $(
2692      #[inline]
2693      pub fn $axis_method() -> Self {
2694        $unit ($vector::$unit_method())
2695      }
2696      )+
2697      /// Returns 'None' if called with a non-normalized vector.
2698      ///
2699      /// This method checks whether `vector == vector.normalize()`.
2700      pub fn new (vector : $vector <S>) -> Option <Self> {
2701        let normalized = vector.normalize();
2702        if vector == normalized {
2703          Some ($unit (vector))
2704        } else {
2705          None
2706        }
2707      }
2708      /// Returns 'None' if called with an non-normalized vector determined by checking
2709      /// if the magnitude is approximately one.
2710      ///
2711      /// Note the required `RelativeEq` trait is only implemented for floating-point
2712      /// types.
2713      pub fn new_approx (vector : $vector <S>) -> Option <Self> where
2714        S : num::real::Real + approx::RelativeEq <Epsilon=S>
2715      {
2716        if vector.is_normalized() {
2717          Some ($unit (vector))
2718        } else {
2719          None
2720        }
2721      }
2722      /// Normalizes a given non-zero vector.
2723      // TODO: move broken doc tests to unit tests
2724      // # Example
2725      //
2726      // ```
2727      // # use math_utils::$unit;
2728      // assert_eq!(
2729      //   *$unit::normalize ([2.0, 0.0].into()),
2730      //   [1.0, 0.0].into()
2731      // );
2732      // ```
2733      //
2734      // # Panics
2735      //
2736      // Panics if the zero vector is given:
2737      //
2738      // ```should_panic
2739      // # use math_utils::$unit;
2740      // let x = $unit::normalize ([0.0, 0.0].into());  // panic!
2741      // ```
2742      pub fn normalize (vector : $vector <S>) -> Self {
2743        use num::Zero;
2744        assert!(!vector.is_zero());
2745        $unit (vector.normalize())
2746      }
2747      /// Normalizes a given non-zero vector only if the vector is not already
2748      /// normalized.
2749      pub fn normalize_approx (vector : $vector <S>) -> Self where
2750        S : num::real::Real + approx::RelativeEq <Epsilon=S>
2751      {
2752        use num::Zero;
2753        assert!(!vector.is_zero());
2754        let vector = if vector.is_normalized() {
2755          vector
2756        } else {
2757          vector.normalize()
2758        };
2759        $unit (vector)
2760      }
2761      /// Panics if a non-normalized vector is given.
2762      ///
2763      /// This method checks whether `vector == vector.normalize()`.
2764      // TODO: move broken doc tests to unit tests
2765      // ```should_panic
2766      // # use math_utils::$unit;
2767      // let x = $unit::noisy ([2.0, 0.0].into());  // panic!
2768      // ```
2769      pub fn noisy (vector : $vector <S>) -> Self where S : std::fmt::Debug {
2770        assert_eq!(vector, vector.normalize());
2771        $unit (vector)
2772      }
2773      /// Panics if a non-normalized vector is given.
2774      ///
2775      /// Checks if the magnitude is approximately one.
2776      // TODO: move broken doc tests to unit tests
2777      // ```should_panic
2778      // # use math_utils::$unit;
2779      // let x = $unit::noisy ([2.0, 0.0].into());  // panic!
2780      // ```
2781      pub fn noisy_approx (vector : $vector <S>) -> Self where
2782        S : num::real::Real + approx::RelativeEq <Epsilon=S>
2783      {
2784        assert!(vector.is_normalized());
2785        $unit (vector)
2786      }
2787      /// It is a debug assertion if the given vector is not normalized.
2788      ///
2789      /// In debug builds, method checks that `vector == vector.normalize()`.
2790      #[inline]
2791      pub fn unchecked (vector : $vector <S>) -> Self where S : std::fmt::Debug {
2792        debug_assert_eq!(vector, vector.normalize());
2793        $unit (vector)
2794      }
2795      /// It is a debug assertion if the given vector is not normalized.
2796      ///
2797      /// In debug builds, checks if the magnitude is approximately one.
2798      // TODO: move broken doc tests to unit tests
2799      // ```should_panic
2800      // # use math_utils::$unit;
2801      // let n = $unit::unchecked ([2.0, 0.0].into());  // panic!
2802      // ```
2803      #[inline]
2804      pub fn unchecked_approx (vector : $vector <S>) -> Self where
2805        S : num::real::Real + approx::RelativeEq <Epsilon=S>
2806      {
2807        debug_assert!(vector.is_normalized());
2808        $unit (vector)
2809      }
2810      /// Generate a random unit vector. Uses naive algorithm.
2811      pub fn random_unit <R : rand::Rng> (rng : &mut R) -> Self where
2812        S : rand::distr::uniform::SampleUniform
2813      {
2814        let vector = $vector {
2815          $($component: rng.random_range (-S::one()..S::one())),+
2816        };
2817        $unit (vector.normalize())
2818      }
2819      /// Return the unit vector pointing in the opposite direction
2820      // TODO: implement num::Inv ?
2821      pub fn invert (mut self) -> Self {
2822        self.0 = -self.0;
2823        self
2824      }
2825      /// Map an operation on the underlying vector, panicking if the result is zero.
2826      ///
2827      /// # Panics
2828      ///
2829      /// Panics of the result is not normalized.
2830      // TODO: move broken doc tests to unit tests
2831      // ```should_panic
2832      // # use math_utils::$unit;
2833      // // panic!
2834      // let v = $unit::noisy ([1.0, 0.0].into()).map_noisy (|x| 2.0 * x);
2835      // ```
2836      pub fn map_noisy (self, fun : fn ($vector <S>) -> $vector <S>) -> Self where
2837        S : std::fmt::Debug
2838      {
2839        Self::noisy (fun (self.0))
2840      }
2841      /// Map an operation on the underlying vector, panicking if the result is zero.
2842      ///
2843      /// # Panics
2844      ///
2845      /// Panics of the result is not normalized.
2846      // TODO: move broken doc tests to unit tests
2847      // ```should_panic
2848      // # use math_utils::$unit;
2849      // // panic!
2850      // let v = $unit::noisy ([1.0, 0.0].into()).map_noisy (|x| 2.0 * x);
2851      // ```
2852      pub fn map_noisy_approx (self, fun : fn ($vector <S>) -> $vector <S>) -> Self where
2853        S : num::real::Real + approx::RelativeEq <Epsilon=S>
2854      {
2855        Self::noisy_approx (fun (self.0))
2856      }
2857    }
2858    impl <S : Real> std::ops::Deref for $unit <S> {
2859      type Target = $vector <S>;
2860      fn deref (&self) -> &$vector <S> {
2861        &self.0
2862      }
2863    }
2864    impl <S : Real> std::ops::Neg for $unit <S> {
2865      type Output = Self;
2866      fn neg (self) -> Self::Output {
2867        Self (-self.0)
2868      }
2869    }
2870    //  end UnitN
2871  }
2872}
2873
2874macro_rules! impl_numcast {
2875  ($type:ident) => {
2876    impl <S> $type <S> {
2877      #[inline]
2878      pub fn numcast <T> (self) -> Option <$type <T>> where
2879        S : num::NumCast,
2880        T : num::NumCast
2881      {
2882        self.0.numcast().map ($type)
2883      }
2884    }
2885  }
2886}
2887
2888macro_rules! impl_numcast_primitive {
2889  ($type:ident) => {
2890    impl <S> $type <S> {
2891      #[inline]
2892      pub fn numcast <T> (self) -> Option <$type <T>> where
2893        S : num::NumCast,
2894        T : num::NumCast
2895      {
2896        T::from (self.0).map ($type)
2897      }
2898    }
2899  }
2900}
2901
2902#[doc(hidden)]
2903#[macro_export]
2904macro_rules! impl_numcast_fields {
2905  ($type:ident, $($field:ident),+) => {
2906    impl <S> $type <S> {
2907      #[inline]
2908      pub fn numcast <T> (self) -> Option <$type <T>> where
2909        S : num::NumCast,
2910        T : num::NumCast
2911      {
2912        Some ($type {
2913          $($field: self.$field.numcast()?),+
2914        })
2915      }
2916    }
2917  }
2918}
2919
2920impl_angle!(Deg, "Degrees");
2921impl_angle!(Rad, "Radians");
2922impl_angle!(Turn, "Turns");
2923impl_angle_wrapped!(AngleWrapped,
2924  "Unsigned wrapped angle restricted to $[0, 2\\pi)$");
2925impl_angle_wrapped!(AngleWrappedSigned,
2926  "Signed wrapped angle restricted to $(-\\pi, \\pi]$");
2927
2928impl_dimension!(Point2, Vector2, NonZero2, Unit2,
2929  point2, vector2,
2930  [x, y],
2931  [(axis_x, unit_x), (axis_y, unit_y)], [Vector3], Matrix2, Affine2, Euclidean2,
2932  2, "2D");
2933impl_dimension!(Point3, Vector3, NonZero3, Unit3,
2934  point3, vector3,
2935  [x, y, z],
2936  [(axis_x, unit_x), (axis_y, unit_y), (axis_z, unit_z)],
2937  [Vector4], Matrix3, Affine3, Euclidean3, 3, "3D");
2938impl_dimension!(Point4, Vector4, NonZero4, Unit4,
2939  point4, vector4,
2940  [x, y, z, w],
2941  [(axis_x, unit_x), (axis_y, unit_y), (axis_z, unit_z), (axis_w, unit_w)],
2942  [], Matrix4, Affine4, Euclidean4, 4, "4D");
2943
2944impl_numcast_primitive!(Positive);
2945impl_numcast_primitive!(NonNegative);
2946impl_numcast_primitive!(NonZero);
2947impl_numcast_primitive!(Normalized);
2948impl_numcast_primitive!(NormalSigned);
2949impl_numcast_fields!(Angles3, yaw, pitch, roll);
2950
2951//
2952//  private
2953//
2954#[inline]
2955fn normalize_quaternion <S : Real> (quaternion : Quaternion <S>) -> Quaternion <S> {
2956  Quaternion::from_vec4 (quaternion.into_vec4().normalize())
2957}
2958
2959#[cfg(test)]
2960mod tests {
2961  use super::*;
2962  use crate::num_traits;
2963  use approx;
2964  use rand;
2965  use rand_xorshift;
2966
2967  #[test]
2968  fn defaults() {
2969    use num_traits::Zero;
2970
2971    assert_eq!(Positive::<f32>::default().0, 0.0);
2972    assert_eq!(NonNegative::<f32>::default().0, 0.0);
2973    assert_eq!(Normalized::<f32>::default().0, 0.0);
2974    assert_eq!(NormalSigned::<f32>::default().0, 0.0);
2975    assert_eq!(Deg::<f32>::default().0, 0.0);
2976    assert_eq!(Rad::<f32>::default().0, 0.0);
2977    assert_eq!(Turn::<f32>::default().0, 0.0);
2978    assert_eq!(
2979      Angles3::<f32>::default(),
2980      Angles3::new (AngleWrapped::zero(), AngleWrapped::zero(), AngleWrapped::zero()));
2981    assert_eq!(
2982      Pose3::<f32>::default(),
2983      Pose3 { position: Point3::origin(), angles: Angles3::default() });
2984    assert_eq!(
2985      LinearIso::<f32, Vector3 <f32>, Vector3 <f32>, Matrix3 <f32>>::default().0,
2986      Matrix3::identity());
2987    assert_eq!(LinearAuto::<f32, Vector3 <f32>>::default().0.0, Matrix3::identity());
2988    assert_eq!(Rotation2::<f32>::default().0.0.0, Matrix2::identity());
2989    assert_eq!(Rotation3::<f32>::default().0.0.0, Matrix3::identity());
2990    assert_eq!(Versor::<f32>::default().0, Quaternion::from_xyzw (0.0, 0.0, 0.0, 1.0));
2991    assert_eq!(
2992      AffineMap::<f32, Vector3 <f32>, Vector3 <f32>, Matrix3 <f32>>::default(),
2993      AffineMap::new (Matrix3::identity(), Vector3::zero()));
2994    assert_eq!(
2995      Affinity::<f32, Vector3 <f32>, Vector3 <f32>, Matrix3 <f32>>::default(),
2996      Affinity::new (LinearIso::new (Matrix3::identity()).unwrap(), Vector3::zero()));
2997    assert_eq!(
2998      Projectivity::<
2999        f32, Vector3 <f32>, Vector3 <f32>, Vector4 <f32>, Vector4 <f32>, Matrix4 <f32>
3000      >::default().0,
3001      LinearIso::new (Matrix4::identity()).unwrap());
3002  }
3003
3004  #[test]
3005  fn rotation3_noisy_approx() {
3006    use rand::{Rng, SeedableRng};
3007    // construct orthonormal matrices and verify they are orthonormal using noisy_approx
3008    // constructor
3009    let mut rng = rand_xorshift::XorShiftRng::seed_from_u64 (0);
3010    let up = Vector3::unit_z();
3011    for _ in 0..1000 {
3012      let forward = vector3 (
3013        rng.random_range (-1000.0f32..1000.0),
3014        rng.random_range (-1000.0f32..1000.0),
3015        0.0
3016      ).normalized();
3017      let right = forward.cross (up);
3018      let mat = Matrix3::from_col_arrays ([
3019        right.into_array(),
3020        forward.into_array(),
3021        up.into_array()
3022      ]);
3023      let _ = Rotation3::noisy_approx (mat);
3024    }
3025  }
3026
3027  #[test]
3028  fn rotation3_intrinsic_angles() {
3029    use std::f32::consts::PI;
3030    use num_traits::Zero;
3031    use rand::{Rng, SeedableRng};
3032    // yaw: CCW quarter turn around Z (world up) axis
3033    let rot = Rotation3::from_angles_intrinsic (
3034      Turn (0.25).into(), Rad::zero(), Rad::zero());
3035    approx::assert_relative_eq!(*rot,
3036      Matrix3::from_col_arrays ([
3037        [ 0.0, 1.0, 0.0],
3038        [-1.0, 0.0, 0.0],
3039        [ 0.0, 0.0, 1.0]
3040      ])
3041    );
3042    assert_eq!((Turn (0.25).into(), Rad::zero(), Rad::zero()), rot.intrinsic_angles());
3043    let rot = Rotation3::from_angles_intrinsic (
3044      Turn (0.5).into(), Rad::zero(), Rad::zero());
3045    approx::assert_relative_eq!(*rot,
3046      Matrix3::from_col_arrays ([
3047        [-1.0,  0.0, 0.0],
3048        [ 0.0, -1.0, 0.0],
3049        [ 0.0,  0.0, 1.0]
3050      ])
3051    );
3052    assert_eq!((Turn (0.5).into(), Rad::zero(), Rad::zero()), rot.intrinsic_angles());
3053    // pitch: CCW quarter turn around X (world right) axis
3054    let rot = Rotation3::from_angles_intrinsic (
3055      Rad::zero(), Turn (0.25).into(), Rad::zero());
3056    approx::assert_relative_eq!(*rot,
3057      Matrix3::from_col_arrays ([
3058        [1.0,  0.0, 0.0],
3059        [0.0,  0.0, 1.0],
3060        [0.0, -1.0, 0.0]
3061      ])
3062    );
3063    assert_eq!((Rad::zero(), Turn (0.25).into(), Rad::zero()), rot.intrinsic_angles());
3064    // roll: CCW quarter turn around Y (world forward) axis
3065    let rot = Rotation3::from_angles_intrinsic (
3066      Rad::zero(), Rad::zero(), Turn (0.25).into());
3067    approx::assert_relative_eq!(*rot,
3068      Matrix3::from_col_arrays ([
3069        [0.0, 0.0, -1.0],
3070        [0.0, 1.0,  0.0],
3071        [1.0, 0.0,  0.0]
3072      ])
3073    );
3074    assert_eq!((Rad::zero(), Rad::zero(), Turn (0.25).into()), rot.intrinsic_angles());
3075    // pitch after yaw
3076    let rot = Rotation3::from_angles_intrinsic (
3077      Turn (0.25).into(), Turn (0.25).into(), Rad::zero());
3078    approx::assert_relative_eq!(*rot,
3079      Matrix3::from_col_arrays ([
3080        [0.0, 1.0, 0.0],
3081        [0.0, 0.0, 1.0],
3082        [1.0, 0.0, 0.0]
3083      ])
3084    );
3085    let angles = rot.intrinsic_angles();
3086    approx::assert_relative_eq!(Rad::from (Turn (0.25)).0, angles.0.0);
3087    approx::assert_relative_eq!(Rad::from (Turn (0.25)).0, angles.1.0);
3088    approx::assert_relative_eq!(0.0, angles.2.0);
3089    // roll after pitch after yaw
3090    let rot = Rotation3::from_angles_intrinsic (
3091      Turn (0.25).into(), Turn (0.25).into(), Turn (0.25).into());
3092    approx::assert_relative_eq!(*rot,
3093      Matrix3::from_col_arrays ([
3094        [-1.0, 0.0, 0.0],
3095        [ 0.0, 0.0, 1.0],
3096        [ 0.0, 1.0, 0.0]
3097      ])
3098    );
3099    let angles = rot.intrinsic_angles();
3100    approx::assert_relative_eq!(Rad::from (Turn (0.25)).0, angles.0.0);
3101    approx::assert_relative_eq!(Rad::from (Turn (0.25)).0, angles.1.0);
3102    approx::assert_relative_eq!(Rad::from (Turn (0.25)).0, angles.2.0);
3103
3104    // construct random orthonormal matrices and verify the intrinsic angles are in the
3105    // range [-pi, pi]
3106    let mut rng = rand_xorshift::XorShiftRng::seed_from_u64 (0);
3107    let mut random_vector = || vector3 (
3108      rng.random_range (-100.0f32..100.0),
3109      rng.random_range (-100.0f32..100.0),
3110      rng.random_range (-100.0f32..100.0));
3111    for _ in 0..1000 {
3112      let rot = Rotation3::orthonormalize (
3113        random_vector(), random_vector(), random_vector()
3114      ).unwrap();
3115      let (yaw, pitch, roll) = rot.intrinsic_angles();
3116      assert!(yaw.0   <  PI);
3117      assert!(yaw.0   > -PI);
3118      assert!(pitch.0 <  PI);
3119      assert!(pitch.0 > -PI);
3120      assert!(roll.0  <  PI);
3121      assert!(roll.0  > -PI);
3122    }
3123  }
3124
3125  #[test]
3126  fn rotation3_into_versor() {
3127    use std::f32::consts::PI;
3128    let rot  = Rotation3::from_angle_x (Rad (0.01));
3129    let quat = rot.versor().0;
3130    approx::assert_relative_eq!(*rot, quat.into());
3131    let rot  = Rotation3::from_angle_x (Rad (-0.01));
3132    let quat = rot.versor().0;
3133    approx::assert_relative_eq!(*rot, quat.into());
3134
3135    let rot  = Rotation3::from_angle_y (Rad (0.01));
3136    let quat = rot.versor().0;
3137    approx::assert_relative_eq!(*rot, quat.into());
3138    let rot  = Rotation3::from_angle_y (Rad (-0.01));
3139    let quat = rot.versor().0;
3140    approx::assert_relative_eq!(*rot, quat.into());
3141
3142    let rot  = Rotation3::from_angle_z (Rad (0.01));
3143    let quat = rot.versor().0;
3144    approx::assert_relative_eq!(*rot, quat.into());
3145    let rot  = Rotation3::from_angle_z (Rad (-0.01));
3146    let quat = rot.versor().0;
3147    approx::assert_relative_eq!(*rot, quat.into());
3148
3149    let rot  = Rotation3::from_angle_x (Rad (PI / 2.0));
3150    let quat = rot.versor().0;
3151    approx::assert_relative_eq!(*rot, quat.into());
3152    let rot  = Rotation3::from_angle_x (Rad (-PI / 2.0));
3153    let quat = rot.versor().0;
3154    approx::assert_relative_eq!(*rot, quat.into());
3155
3156    let rot  = Rotation3::from_angle_y (Rad (PI / 2.0));
3157    let quat = rot.versor().0;
3158    approx::assert_relative_eq!(*rot, quat.into());
3159    let rot  = Rotation3::from_angle_y (Rad (-PI / 2.0));
3160    let quat = rot.versor().0;
3161    approx::assert_relative_eq!(*rot, quat.into());
3162
3163    let rot  = Rotation3::from_angle_z (Rad (PI / 2.0));
3164    let quat = rot.versor().0;
3165    approx::assert_relative_eq!(*rot, quat.into());
3166    let rot  = Rotation3::from_angle_z (Rad (-PI / 2.0));
3167    let quat = rot.versor().0;
3168    approx::assert_relative_eq!(*rot, quat.into());
3169  }
3170}