math_utils/types/
mod.rs

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