math_utils/types/
mod.rs

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