Skip to main content

geo_nd/
traits.rs

1//a Imports
2use crate::{matrix, quat, vector};
3
4//a IsSquared
5//tp IsSquared
6/// This trait, with `D2 = D^2`, should be implemented for [();D] to
7/// indicate that `D2` is indeed `D*D`
8///
9/// This permits the `SqMatrix` trait to only be implemented for actually square matrices
10pub trait IsSquared<const D: usize, const D2: usize> {}
11impl IsSquared<2, 4> for [(); 2] {}
12impl IsSquared<3, 9> for [(); 3] {}
13impl IsSquared<4, 16> for [(); 4] {}
14
15//a Num and Float traits
16//tp Num
17/// The [Num] trait is required for matrix or vector elements; it is
18/// not a float, and so some of the matrix and vector operations can
19/// operate on integer types such as i32, i64 and isize; it can also
20/// operate on rational numbers (such as num::Rational64)
21///
22/// The fundamental difference between this and Float is the lack of support
23/// for functions such as sqrt(), cos(), abs() (!), powi(_), etc
24///
25/// The trait requires basic numeric operations, plus specifically [std::fmt::Display].
26///
27/// v0.7 added PartialOrd, FromPrimitve
28pub trait Num:
29    Copy
30    + PartialEq
31    + PartialOrd
32    + std::fmt::Display
33    + std::fmt::Debug
34    + std::ops::Neg<Output = Self>
35    + num_traits::Num
36    + num_traits::ConstOne
37    + num_traits::ConstZero
38    + num_traits::FromPrimitive
39{
40}
41
42//ip Num
43/// Num is implemented for all types that support the traits
44impl<T> Num for T where
45    T: Copy
46        + PartialEq
47        + PartialOrd
48        + std::fmt::Display
49        + std::fmt::Debug
50        + std::ops::Neg<Output = Self>
51        + num_traits::Num
52        + num_traits::ConstOne
53        + num_traits::ConstZero
54        + num_traits::FromPrimitive
55{
56}
57
58//tp Float
59/// The [Float] trait is required for matrix or vector elements which
60/// have a float aspect, such as `sqrt`.
61///
62/// The trait is essentially `num_traits::Float`, but it supplies
63/// implicit methods for construction of a [Float] from an `isize`
64/// value, or as a rational from a pair of `isize` values.
65pub trait Float: Num + num_traits::Float {
66    /// Generate a value that is the fraction of a signed integer numerator and an unsigned integer denominator
67    fn frac(n: i32, d: u32) -> Self {
68        Self::from_i32(n).unwrap() / Self::from_u32(d).unwrap()
69    }
70}
71
72impl<T> Float for T where T: Num + num_traits::Float {}
73
74//a Array and Quat traits
75//tp ArrayBasic
76pub trait ArrayBasic:
77    Clone + Copy + std::fmt::Debug + std::fmt::Display + std::default::Default + PartialEq<Self>
78{
79}
80
81//ip ArrayBasic
82impl<T> ArrayBasic for T where
83    T: Clone + Copy + std::fmt::Debug + std::fmt::Display + std::default::Default + PartialEq<Self>
84{
85}
86
87//tp ArrayRef
88pub trait ArrayRef<F, const D:usize>:
89    std::convert::AsRef<[F; D]> // Note, [F;D] implements AsRef only for [F] which is an issue
90    + std::convert::AsMut<[F; D]> // Note, [F;D] implements AsRef only for [F] which is an issue
91    + std::ops::Deref<Target = [F;D]>
92    + std::ops::DerefMut
93{
94}
95
96//ip ArrayRef
97impl<T, F, const D: usize> ArrayRef<F, D> for T where
98    T: std::convert::AsRef<[F; D]> // Note, [F;D] implements AsRef only for [F] which is an issue
99        + std::convert::AsMut<[F; D]>
100        // Note, [F;D] implements AsRef only for [F] which is an issue
101        + std::ops::Deref<Target = [F; D]>
102        + std::ops::DerefMut
103{
104}
105
106//tp ArrayIndex
107pub trait ArrayIndex<F>: std::ops::Index<usize, Output = F> + std::ops::IndexMut<usize> {}
108
109//ip ArrayIndex
110impl<T, F> ArrayIndex<F> for T where
111    T: std::ops::Index<usize, Output = F> + std::ops::IndexMut<usize>
112{
113}
114
115//ip ArrayConvert
116pub trait ArrayConvert<F, const D: usize>:
117    std::convert::From<[F; D]>
118    + for<'a> std::convert::From<&'a [F; D]>
119    + for<'a> std::convert::TryFrom<&'a [F]>
120    + for<'a> std::convert::TryFrom<Vec<F>>
121    + std::convert::Into<[F; D]>
122{
123}
124
125//ip ArrayConvert
126impl<T, F, const D: usize> ArrayConvert<F, D> for T where
127    T: std::convert::From<[F; D]>
128        + for<'a> std::convert::From<&'a [F; D]>
129        + for<'a> std::convert::TryFrom<&'a [F]>
130        + for<'a> std::convert::TryFrom<Vec<F>>
131        + std::convert::Into<[F; D]>
132{
133}
134
135//tt ArrayAddSubNeg
136pub trait ArrayAddSubNeg<F, const D: usize>:
137    Sized
138    + std::ops::Neg<Output = Self>
139    + std::ops::Add<Self, Output = Self>
140    + for<'a> std::ops::Add<&'a [F; D], Output = Self>
141    + for<'a> std::ops::Add<&'a Self, Output = Self>
142    + std::ops::AddAssign<Self>
143    + for<'a> std::ops::AddAssign<&'a [F; D]>
144    + std::ops::Sub<Self, Output = Self>
145    + for<'a> std::ops::Sub<&'a [F; D], Output = Self>
146    + for<'a> std::ops::Sub<&'a Self, Output = Self>
147    + std::ops::SubAssign<Self>
148    + for<'a> std::ops::SubAssign<&'a [F; D]>
149{
150}
151//tt ArrayAddSubNeg
152impl<T, F, const D: usize> ArrayAddSubNeg<F, D> for T where
153    T: Sized
154        + std::ops::Neg<Output = Self>
155        + std::ops::Add<Self, Output = Self>
156        + for<'a> std::ops::Add<&'a [F; D], Output = Self>
157        + for<'a> std::ops::Add<&'a Self, Output = Self>
158        + std::ops::AddAssign<Self>
159        + for<'a> std::ops::AddAssign<&'a [F; D]>
160        + std::ops::Sub<Self, Output = Self>
161        + for<'a> std::ops::Sub<&'a [F; D], Output = Self>
162        + for<'a> std::ops::Sub<&'a Self, Output = Self>
163        + std::ops::SubAssign<Self>
164        + for<'a> std::ops::SubAssign<&'a [F; D]>
165{
166}
167
168//tp ArrayScale
169pub trait ArrayScale<F>:
170    std::ops::Mul<F, Output = Self>
171    + std::ops::MulAssign<F>
172    + std::ops::Div<F, Output = Self>
173    + std::ops::DivAssign<F>
174{
175}
176
177//ip ArrayScale
178impl<T, F> ArrayScale<F> for T where
179    T: std::ops::Mul<F, Output = Self>
180        + std::ops::MulAssign<F>
181        + std::ops::Div<F, Output = Self>
182        + std::ops::DivAssign<F>
183{
184}
185
186//tp ArrayMulDiv - not used yet
187#[allow(dead_code)]
188pub trait ArrayMulDiv<F, const D: usize>:
189    Sized
190    + std::ops::Mul<Self, Output = Self>
191    + for<'a> std::ops::Mul<&'a [F; 4], Output = Self>
192    + for<'a> std::ops::Mul<&'a Self, Output = Self>
193    + std::ops::MulAssign<Self>
194    + for<'a> std::ops::MulAssign<&'a [F; 4]>
195    + std::ops::Div<Self, Output = Self>
196    + for<'a> std::ops::Div<&'a [F; 4], Output = Self>
197    + for<'a> std::ops::Div<&'a Self, Output = Self>
198    + std::ops::DivAssign<Self>
199    + for<'a> std::ops::DivAssign<&'a [F; 4]>
200{
201}
202
203//ip ArrayMulDiv
204impl<T, F, const D: usize> ArrayMulDiv<F, D> for T where
205    T: Sized
206        + std::ops::Mul<Self, Output = Self>
207        + for<'a> std::ops::Mul<&'a [F; 4], Output = Self>
208        + for<'a> std::ops::Mul<&'a Self, Output = Self>
209        + std::ops::MulAssign<Self>
210        + for<'a> std::ops::MulAssign<&'a [F; 4]>
211        + std::ops::Div<Self, Output = Self>
212        + for<'a> std::ops::Div<&'a [F; 4], Output = Self>
213        + for<'a> std::ops::Div<&'a Self, Output = Self>
214        + std::ops::DivAssign<Self>
215        + for<'a> std::ops::DivAssign<&'a [F; 4]>
216{
217}
218
219//tp QuatMulDiv
220// Neat trick
221//
222// pub trait RefCanBeMultipliedBy<T> {}
223// impl<X, T> RefCanBeMultipliedBy<T> for X where for<'a> &'a X: std::ops::Mul<T, Output = X> {}
224pub trait QuatMulDiv<F, const D: usize>:
225    Sized
226    + std::ops::Mul<Self, Output = Self>
227    + for<'a> std::ops::Mul<&'a Self, Output = Self>
228    + std::ops::MulAssign<Self>
229    + std::ops::Div<Self, Output = Self>
230    + for<'a> std::ops::Div<&'a Self, Output = Self>
231    + std::ops::DivAssign<Self>
232{
233}
234
235//ip QuatMulDiv
236impl<T, F, const D: usize> QuatMulDiv<F, D> for T where
237    T: Sized
238        + std::ops::Mul<Self, Output = Self>
239        + for<'a> std::ops::Mul<&'a Self, Output = Self>
240        + std::ops::MulAssign<Self>
241        + std::ops::Div<Self, Output = Self>
242        + for<'a> std::ops::Div<&'a Self, Output = Self>
243        + std::ops::DivAssign<Self>
244{
245}
246
247//a Vector, Vector2, Vector3, Vector4
248//tt Vector
249/// The [Vector] trait describes an N-dimensional vector of [Float] type.
250///
251/// Such [Vector]s support basic vector arithmetic using addition and
252/// subtraction, and they provide component-wise multiplication and
253/// division, using the standard operators on two [Vector]s.
254///
255/// They also support basic arithmetic to all components of the
256/// [Vector] for addition, subtraction, multiplication and division by
257/// a scalar [Float] value type that they are comprised of. Hence a
258/// `v:Vector<F>` may be scaled by a `s:F` using `v * s`.
259///
260/// The [Vector] can be indexed only by a `usize`; that is individual
261/// components of the vector can be accessed, but ranges may not.
262///
263pub trait Vector<F: Float, const D: usize>:
264    ArrayBasic
265    + ArrayRef<F, D> // Can we move this to specifically Vector3 and Vector4? Maybe just the asref?
266    + ArrayIndex<F>
267    + ArrayConvert<F, D>
268    + ArrayAddSubNeg<F, D>
269    + ArrayScale<F>
270{
271    //mp is_zero
272    /// Return true if the vector is all zeros
273    fn is_zero(&self) -> bool {
274        !self.deref().iter().any(|f| !f.is_zero())
275    }
276
277    //mp mix
278    /// Create a linear combination of this [Vector] and another using parameter `t` from zero to one
279    #[must_use]
280    fn mix<A>(self, other: A, t: F) -> Self
281    where
282        A: std::ops::Deref<Target = [F; D]>,
283    {
284        vector::mix(self.deref(), other.deref(), t).into()
285    }
286
287    //mp dot
288    /// Return the dot product of two vectors
289    fn dot(&self, other: &[F; D]) -> F {
290        vector::dot(self.deref(), other)
291    }
292
293    /// Return the dot product of two vectors
294    fn reduce_sum(&self) -> F {
295        let mut r = F::zero();
296        for d in self.deref() {
297            r = r + *d
298        }
299        r
300    }
301
302    //mp length_sq
303    /// Return the square of the length of the vector
304    #[inline]
305    fn length_sq(&self) -> F {
306        self.dot(self)
307    }
308
309    //mp length
310    /// Return the length of the vector
311    #[inline]
312    fn length(&self) -> F {
313        self.length_sq().sqrt()
314    }
315
316    //mp distance_sq
317    /// Return the square of the distance between this vector and another
318    #[inline]
319    fn distance_sq(&self, other: &[F; D]) -> F {
320        (*self - other).length_sq()
321    }
322
323    //mp distance
324    /// Return the distance between this vector and another
325    #[inline]
326    fn distance(&self, other: &[F; D]) -> F {
327        self.distance_sq(other).sqrt()
328    }
329
330    //mp normalize
331    /// Normalize the vector; if its length is close to zero, then set it to be zero
332    #[inline]
333    #[must_use]
334    fn normalize(mut self) -> Self {
335        let l = self.length();
336        if l < F::epsilon() {
337            self = Self::default()
338        } else {
339            self /= l
340        }
341        self
342    }
343
344    //cp rotate_around
345    /// Rotate a vector within a plane around a
346    /// *pivot* point by the specified angle
347    ///
348    /// The plane of rotation is specified by providing two vector indices for the elements to adjust. For a 2D rotation then the values of c0 and c1 should be 0 and 1.
349    ///
350    /// For a 3D rotation about the Z axis, they should be 0 and 1; for
351    /// rotation about the Y axis they should be 2 and 0; and for rotation
352    /// about the X axis they should be 1 and 2.
353    ///
354    fn rotate_around(mut self, pivot: &Self, angle: F, c0: usize, c1: usize) -> Self {
355        let (s, c) = angle.sin_cos();
356        let dx = self[c0] - pivot[c0];
357        let dy = self[c1] - pivot[c1];
358        let x1 = c * dx - s * dy;
359        let y1 = c * dy + s * dx;
360        self[c0] = x1 + pivot[c0];
361        self[c1] = y1 + pivot[c1];
362        self
363    }
364
365    //cp cross_product - where D = 3
366    /// Cross product of two 3-element vectors
367    #[must_use]
368    fn cross_product(&self, other: &[F; 3]) -> Self
369    where
370        Self: From<[F; 3]>,
371        Self: AsRef<[F; 3]>, // so that it knows as_ref() returns &[F;3], i.e. D is 3
372    {
373        vector::cross_product3(self.as_ref(), other).into()
374    }
375
376    //fp apply_q3
377    /// Apply a quaternion to a V3
378    ///
379    /// This can either take other as &\[F;3\] and produce \[F; 3\], or
380    ///  &D where D:Deref<Target = \[F; 3\]> and D:From<\[F; 3\]
381    ///
382    /// If it takes the former then it can operate on \[F;3\] and
383    /// anything that is Deref<Target = \[F;3\]>, but it needs its result
384    /// cast into the correct vector
385    ///
386    /// If it tkes the latter then it cannot operate on \[F;3\], but its
387    /// result need not be cast
388    #[must_use]
389    fn apply_q3<Q>(&self, q: &Q) -> Self
390    where
391        Q: Quaternion<F>,
392        Self: From<[F; 3]>,  // Enforce D = 3
393        Self: AsRef<[F; 3]>, // so that it knows as_ref() returns &[F;3], i.e. D is 3
394    {
395        quat::apply3(q.deref(), self.as_ref()).into()
396    }
397
398    //fp apply_q4
399    /// Apply a quaternion to a V4
400    ///
401    /// This can either take other as &\[F;3\] and produce \[F; 3\], or
402    ///  &D where D:Deref<Target =\[F; 3\]> and D:From<\[F; 3\]
403    ///
404    /// If it takes the former then it can operate on \[F;3\] and
405    /// anything that is Deref<Target = \[F;3\]>, but it needs its result
406    /// cast into the correct vector
407    ///
408    /// If it tkes the latter then it cannot operate on \[F;3\], but its
409    /// result need not be cast
410    #[must_use]
411    fn apply_q4<Q>(&self, q: &Q) -> Self
412    where
413        Q: Quaternion<F>,
414        Self: From<[F; 4]>,
415        Self: AsRef<[F; 4]>, // so that it knows as_ref() returns &[F;3], i.e. D is 3
416    {
417        quat::apply4(q.deref(), self.as_ref()).into()
418    }
419
420    //mp transformed_by_m
421    /// Multiply the vector by the matrix to transform it
422    fn transformed_by_m<const D2: usize>(&mut self, m: &[F; D2]) -> &mut Self
423    where
424        [(); D]: IsSquared<D, D2>,
425    {
426        *self = matrix::multiply::<F, D2, D, D, D, D, 1>(m, self.deref()).into();
427        self
428    }
429
430    //cp uniform_dist_sphere3
431    /// Get a point on a sphere uniformly distributed for a point
432    /// where x in [0,1) and y in [0,1)
433    #[must_use]
434    fn uniform_dist_sphere3(x: [F; 2], map: bool) -> Self
435    where
436        Self: From<[F; 3]>,
437    {
438        (vector::uniform_dist_sphere3(x, map)).into()
439    }
440}
441
442//tt Vector2
443/// The [Vector2] trait describes a 3-dimensional vector of [Float]
444///
445pub trait Vector2<F: Float>: Vector<F, 2> {}
446impl<F, V> Vector2<F> for V
447where
448    F: Float,
449    V: Vector<F, 2>,
450{
451}
452
453//tt Vector3
454/// The [Vector3] trait describes a 3-dimensional vector of [Float]
455///
456pub trait Vector3<F: Float>: Vector<F, 3> {}
457impl<F, V> Vector3<F> for V
458where
459    F: Float,
460    V: Vector<F, 3>,
461{
462}
463
464//tt Vector4
465/// The [Vector4] trait describes a 3-dimensional vector of [Float]
466///
467pub trait Vector4<F: Float>: Vector<F, 4> {}
468impl<F, V> Vector4<F> for V
469where
470    F: Float,
471    V: Vector<F, 4>,
472{
473}
474
475//a SqMatrix
476//tt SqMatrix
477/// The [SqMatrix] trait describes an N-dimensional square matrix of [Float] type that operates on a [Vector].
478///
479/// This trait is not stable.
480///
481/// Such [SqMatrix] support basic arithmetic using addition and
482/// subtraction, and they provide component-wise multiplication and
483/// division, using the standard operators on two [SqMatrix]s.
484///
485/// They also support basic arithmetic to all components of the
486/// [SqMatrix] for addition, subtraction, multiplication and division by
487/// a scalar [Float] value type that they are comprised of. Hence a
488/// `m:SqMatrix<F>` may be scaled by a `s:F` using `m * s`.
489pub trait SqMatrix<F: Float, const D: usize, const D2: usize>:
490    ArrayBasic
491    + ArrayRef<F, D2>
492    + ArrayIndex<F>
493    + ArrayConvert<F, D2>
494    + ArrayAddSubNeg<F, D2>
495    + ArrayScale<F>
496    + std::ops::Mul<Output = Self>
497    + std::ops::MulAssign
498{
499    /// Create an identity matrix
500    fn identity() -> Self {
501        matrix::identity::<F, D2, D>().into()
502    }
503
504    /// Return true if the matrix is zero
505    fn is_zero(&self) -> bool {
506        vector::is_zero(self.deref())
507    }
508
509    /// Set the matrix to zero
510    fn set_zero(&mut self) -> &mut Self {
511        vector::set_zero(self.deref_mut());
512        self
513    }
514
515    //mp transpose
516    /// Return a transpose matrix
517    fn transpose(&self) -> Self;
518
519    //mp determinant
520    /// Calculate the determinant of the matrix
521    fn determinant(&self) -> F;
522
523    //mp inverse
524    /// Create an inverse matrix
525    fn inverse(&self) -> Self;
526
527    //mp transform
528    /// Apply the matrix to a vector to transform it
529    fn transform<T>(&self, v: &T) -> T
530    where
531        T: std::ops::Deref<Target = [F; D]>,
532        T: From<[F; D]>;
533}
534
535//tt SqMatrix2
536/// The [SqMatrix2] trait describes a 2-dimensional vector of [Float]
537///
538pub trait SqMatrix2<F: Float>: SqMatrix<F, 2, 4> {}
539impl<F, M> SqMatrix2<F> for M
540where
541    F: Float,
542    M: SqMatrix<F, 2, 4>,
543{
544}
545
546//tt SqMatrix3
547/// The [SqMatrix3] trait describes a 2-dimensional vector of [Float]
548///
549pub trait SqMatrix3<F: Float>: SqMatrix<F, 3, 9> {}
550impl<F, M> SqMatrix3<F> for M
551where
552    F: Float,
553    M: SqMatrix<F, 3, 9>,
554{
555}
556
557//tt SqMatrix4
558/// The [SqMatrix4] trait describes a 2-dimensional vector of [Float]
559///
560pub trait SqMatrix4<F: Float>: SqMatrix<F, 4, 16> {
561    /// Generate a perspective matrix
562    fn perspective(fov: F, aspect: F, near: F, far: F) -> Self {
563        matrix::perspective4(fov, aspect, near, far).into()
564    }
565
566    /// Generate a matrix that represents a 'look at a vector'
567    fn look_at(eye: &[F; 3], center: &[F; 3], up: &[F; 3]) -> Self {
568        matrix::look_at4(eye, center, up).into()
569    }
570
571    /// Translate the matrix by a Vec3
572    fn translate3(&mut self, by: &[F; 3]) {
573        self[3] = self[3] + by[0];
574        self[7] = self[7] + by[1];
575        self[11] = self[11] + by[2];
576    }
577
578    /// Translate the matrix by a Vec4
579    fn translate4(&mut self, by: &[F; 4]) {
580        self[3] = self[3] + by[0];
581        self[7] = self[7] + by[1];
582        self[11] = self[11] + by[2];
583    }
584}
585impl<F, M> SqMatrix4<F> for M
586where
587    F: Float,
588    M: SqMatrix<F, 4, 16>,
589{
590}
591
592//a Quaternion
593//tt Quaternion
594/// The [Quaternion] trait describes a 4-dimensional vector of [Float] type.
595///
596/// Such [Quaternion]s support basic arithmetic using addition and
597/// subtraction, and they provide quaternion multiplication and division.
598///
599/// They also support basic arithmetic to all components of the
600/// [Quaternion] for addition, subtraction, multiplication and division by
601/// a scalar [Float] value type that they are comprised of. Hence a
602/// `q:Quaternion<F>` may be scaled by a `s:F` using `q * s`.
603///
604/// The [Quaternion] can be indexed only by a `usize`; that is individual
605/// components of the vector can be accessed, but ranges may not.
606pub trait Quaternion<F: Float>:
607    ArrayBasic
608    + ArrayRef<F, 4>
609    + ArrayIndex<F>
610    + ArrayConvert<F, 4>
611    + ArrayAddSubNeg<F, 4>
612    + QuatMulDiv<F, 4>
613    + ArrayScale<F>
614{
615    //cp of_rijk
616    /// Create from r, i, j, k
617    #[must_use]
618    fn of_rijk(r: F, i: F, j: F, k: F) -> Self;
619
620    //cp conjugate
621    /// Create the conjugate of a quaternion
622    #[must_use]
623    #[inline]
624    fn conjugate(self) -> Self {
625        let (r, i, j, k) = self.as_rijk();
626        Self::of_rijk(r, -i, -j, -k)
627    }
628
629    //cp of_axis_angle
630    /// Create a unit quaternion for a rotation of an angle about an axis
631    #[must_use]
632    fn of_axis_angle(axis: &[F; 3], angle: F) -> Self {
633        quat::of_axis_angle(axis, angle).into()
634    }
635
636    //cp rotate_x
637    /// Apply a rotation about the X-axis to this quaternion
638    #[inline]
639    #[must_use]
640    fn rotate_x(self, angle: F) -> Self {
641        quat::rotate_x(self.as_ref(), angle).into()
642    }
643
644    //cp rotate_y
645    /// Apply a rotation about the Y-axis to this quaternion
646    #[inline]
647    #[must_use]
648    fn rotate_y(self, angle: F) -> Self {
649        quat::rotate_y(self.as_ref(), angle).into()
650    }
651
652    //cp rotate_z
653    /// Apply a rotation about the Z-axis to this quaternion
654    #[inline]
655    #[must_use]
656    fn rotate_z(self, angle: F) -> Self {
657        quat::rotate_z(self.as_ref(), angle).into()
658    }
659
660    //cp look_at
661    /// Create a quaternion that maps a unit V3 of dirn to (0,0,-1) and a unit V3 of up (if perpendicular to dirn) to (0,1,0)
662    #[must_use]
663    fn look_at(dirn: &[F; 3], up: &[F; 3]) -> Self {
664        quat::look_at(dirn, up).into()
665    }
666
667    //cp rotation_of_vec_to_vec
668    /// Get a quaternion that is a rotation of one vector to another
669    ///
670    /// The vectors must be unit vectors
671    #[must_use]
672    fn rotation_of_vec_to_vec(a: &[F; 3], b: &[F; 3]) -> Self {
673        quat::rotation_of_vec_to_vec(a, b).into()
674    }
675
676    //cp mapping_vector_pair_to_vector_pair
677    /// Create a quaternion that maps (v0, v1) to (w0, w1)
678    ///
679    /// This will map v0 to the Z axis, and the Z axis to w0. Applying
680    /// both of these quaternions in succession maps v0 to w0.
681    ///
682    /// It maps v1 to v1' and w1 *backwards* to w1', where the
683    /// difference between v1' and w1' should be *just* a rotation
684    /// around the Z axis. Creating a rotation to do this is a third quaternion
685    ///
686    /// Then the three quaternions can be applied appropriately to map
687    /// v0 to w0 (for sure), and v1 to w1 (if the intermediate
688    /// rotation were just a Z-rotation)
689    fn mapping_vector_pair_to_vector_pair(
690        (di_m, dj_m): (&[F; 3], &[F; 3]),
691        (di_c, dj_c): (&[F; 3], &[F; 3]),
692    ) -> Self {
693        let z_axis: [F; 3] = [F::zero(), F::zero(), F::one()];
694        let qi_c = Self::rotation_of_vec_to_vec(di_c, &z_axis);
695        let qi_m = Self::rotation_of_vec_to_vec(di_m, &z_axis);
696
697        let dj_c_rotated = quat::apply3(&qi_c, dj_c);
698        let dj_m_rotated = quat::apply3(&qi_m, dj_m);
699
700        let theta_dj_m = dj_m_rotated[0].atan2(dj_m_rotated[1]);
701        let theta_dj_c = dj_c_rotated[0].atan2(dj_c_rotated[1]);
702        let theta = theta_dj_m - theta_dj_c;
703        let theta_div_2 = theta / (F::one() + F::one());
704        let cos_2theta = theta_div_2.cos();
705        let sin_2theta = theta_div_2.sin();
706        let q_z = Self::of_rijk(cos_2theta, F::zero(), F::zero(), sin_2theta);
707        qi_c.conjugate() * q_z * qi_m
708    }
709
710    //cp weighted_average_pair
711    /// Calculate the weighted average of two unit quaternions
712    ///
713    /// w_a + w_b must be 1.
714    ///
715    /// See <http://www.acsu.buffalo.edu/~johnc/ave_quat07.pdf>
716    /// Averaging Quaternions by F. Landis Markley
717    #[must_use]
718    fn weighted_average_pair(&self, w_a: F, qb: &Self, w_b: F) -> Self {
719        quat::weighted_average_pair(self.as_ref(), w_a, qb.as_ref(), w_b).into()
720    }
721
722    //cp weighted_average_many
723    /// Calculate the weighted average of many unit quaternions
724    ///
725    /// weights need not add up to 1
726    ///
727    /// This is an approximation compared to the Landis Markley paper
728    #[must_use]
729    fn weighted_average_many<A: Into<[F; 4]>, I: Iterator<Item = (F, A)>>(value_iter: I) -> Self {
730        let value_iter = value_iter.map(|(w, v)| (w, v.into()));
731        quat::weighted_average_many(value_iter).into()
732    }
733
734    //fp as_rijk
735    /// Break out into r, i, j, k
736    fn as_rijk(&self) -> (F, F, F, F);
737
738    //fp as_axis_angle
739    /// Find the axis and angle of rotation for a (non-unit) quaternion
740    fn as_axis_angle<V: From<[F; 3]>>(&self) -> (V, F) {
741        let (axis, angle) = quat::as_axis_angle(self.as_ref());
742        (axis.into(), angle)
743    }
744
745    //mp set_zero
746    /// Set the quaternion to be all zeros
747    fn set_zero(&mut self) {
748        *self = [F::zero(); 4].into();
749    }
750
751    //mp mix
752    /// Create a linear combination of this [Quaternion] and another using parameter `t` from zero to one
753    #[must_use]
754    fn mix(self, other: &[F; 4], t: F) -> Self {
755        vector::mix(self.deref(), other, t).into()
756    }
757
758    //mp dot
759    /// Return the dot product of two quaternions; basically used for length
760    fn dot(self, other: &Self) -> F {
761        vector::dot(self.deref(), other.deref())
762    }
763
764    //mp length_sq
765    /// Return the square of the length of the quaternion
766    fn length_sq(&self) -> F {
767        self.dot(self)
768    }
769
770    //mp length
771    /// Return the length of the quaternion
772    fn length(&self) -> F {
773        self.length_sq().sqrt()
774    }
775
776    //mp distance_sq
777    /// Return the square of the distance between this quaternion and another
778    fn distance_sq(&self, other: &Self) -> F {
779        quat::distance_sq(self, other)
780    }
781
782    //mp distance
783    /// Return the distance between this quaternion and another
784    fn distance(&self, other: &Self) -> F {
785        self.distance_sq(other).sqrt()
786    }
787
788    //mp normalize
789    /// Normalize the quaternion; if its length is close to zero, then set it to be zero
790    #[must_use]
791    fn normalize(mut self) -> Self {
792        let l = self.length();
793        if l < F::epsilon() {
794            self.set_zero()
795        } else {
796            self /= l
797        }
798        self
799    }
800
801    //cp of_rotation3
802    /// Find the unit quaternion of a Matrix3 assuming it is purely a rotation
803    #[must_use]
804    fn of_rotation3<M>(rotation: &M) -> Self
805    where
806        M: SqMatrix3<F>;
807
808    //fp set_rotation3
809    /// Set a Matrix3 to be the rotation matrix corresponding to the unit quaternion
810    fn set_rotation3<M>(&self, m: &mut M)
811    where
812        M: SqMatrix3<F>;
813
814    //fp set_rotation4
815    /// Set a Matrix4 to be the rotation matrix corresponding to the unit quaternion
816    fn set_rotation4<M>(&self, m: &mut M)
817    where
818        M: SqMatrix4<F>;
819
820    //fp apply3
821    /// Apply the quaternion to a V3
822    ///
823    /// This can either take other as &\[F;3\] and produce \[F; 3\], or
824    ///  &D where D:Deref<Target =\[F; 3\]> and D:From<\[F; 3\]>
825    ///
826    /// If it takes the former then it can operate on \[F;3\] and
827    /// anything that is Deref<Target=\[F;3\]>, but it needs its result
828    /// cast into the correct vector
829    ///
830    /// If it tkes the latter then it cannot operate on \[F;3\], but its
831    /// result need not be cast
832    #[must_use]
833    fn apply3<T>(&self, other: &T) -> T
834    where
835        T: std::ops::Deref<Target = [F; 3]>,
836        T: From<[F; 3]>,
837    {
838        quat::apply3(self.deref(), other.deref()).into()
839    }
840
841    /// Apply the quaternion to a [F; 3]
842    ///
843    /// See apply3 for why this is provided
844    ///
845    #[must_use]
846    fn apply3_arr(&self, other: &[F; 3]) -> [F; 3] {
847        quat::apply3(self.deref(), other)
848    }
849
850    //fp apply4
851    /// Apply the quaternion to a V4
852    #[must_use]
853    fn apply4<T>(&self, other: &T) -> T
854    where
855        T: std::ops::Deref<Target = [F; 4]>,
856        T: From<[F; 4]>,
857    {
858        quat::apply4(self.deref(), other.deref()).into()
859    }
860
861    /// Apply the quaternion to a [F; 3]
862    ///
863    /// See apply3 for why this is provided
864    ///
865    #[must_use]
866    fn apply4_arr(&self, other: &[F; 4]) -> [F; 4] {
867        quat::apply4(self.deref(), other)
868    }
869
870    //zz All done
871}
872
873//a Transform
874//tt Transform
875/// The [Transform] trait describes a translation, rotation and
876/// scaling for 3D, represented eventually as a Mat4
877///
878/// A transformation that is a translation . scaling . rotation
879/// (i.e. it applies the rotation to an object, then scales it, then
880/// translates it)
881pub trait Transform<F, V3, Q>:
882    Clone + Copy + std::fmt::Debug + std::fmt::Display + std::default::Default
883// + std::ops::Neg<Output = Self>
884// apply to self - this is possible
885// + std::ops::Mul<Self, Output = Self>
886// + std::ops::MulAssign<Self>
887// + std::ops::Div<Self, Output = Self>
888// + std::ops::DivAssign<Self>
889// translation of self - can only choose one of V3 or V4
890// + std::ops::Add<V3, Output = Self>
891// + std::ops::AddAssign<V3>
892// + std::ops::Sub<V3, Output = Self>
893// + std::ops::SubAssign<V3>
894// + std::ops::Add<V4, Output = Self>
895// + std::ops::AddAssign<V4>
896// + std::ops::Sub<V4, Output = Self>
897// + std::ops::SubAssign<V4>
898// scaling
899// + std::ops::Mul<F, Output = Self>
900// + std::ops::MulAssign<F>
901// + std::ops::Div<F, Output = Self>
902// + std::ops::DivAssign<F>
903// rotation
904// + std::ops::Mul<Q, Output = Self>
905// + std::ops::MulAssign<Q>
906// + std::ops::Div<Q, Output = Self>
907// + std::ops::DivAssign<Q>
908// and probably where Q:std::ops::Mul<Self, Output=Self> etc
909where
910    F: Float,
911    V3: Vector<F, 3>,
912    Q: Quaternion<F>,
913{
914    /// Create a transformation that is a translation, rotation and scaling
915    fn of_trs(t: V3, r: Q, s: F) -> Self;
916    /// Get the scale of the transform
917    fn scale(&self) -> F;
918    /// Get a translation by a vector
919    fn translation(&self) -> V3;
920    /// Get the rotation of the transfirnatuib
921    fn rotation(&self) -> Q;
922    /// Get the inverse transformation
923    #[must_use]
924    fn inverse(&self) -> Self;
925    /// Invert the transformation
926    fn invert(&mut self);
927    /// Convert it to a 4-by-4 matrix
928    fn as_mat<M: SqMatrix4<F>>(&self) -> M;
929}
930
931//a Vector3D, Geometry3D
932//tt Vector3D
933/// This is probably a temporary trait used until SIMD supports Geometry3D and Geometry2D
934///
935/// The [Vector3D] trait describes vectors that may be used for
936/// 3D geometry
937pub trait Vector3D<Scalar: Float> {
938    /// The type of a 2D vector
939    type Vec2: Vector<Scalar, 2>;
940    /// The type of a 3D vector
941    type Vec3: Vector<Scalar, 3>;
942    /// The type of a 3D vector with an additional '1' expected in its extra element
943    type Vec4: Vector<Scalar, 4>;
944}
945
946//tt Geometry3D
947/// The [Geometry3D] trait supplies a framework for implementing 3D
948/// vector and matrix operations, and should also include the
949/// quaternion type.
950///
951/// An implementation of [Geometry3D] can be used for OpenGL and Vulkan graphics, for example.
952pub trait Geometry3D<Scalar: Float> {
953    /// The type of a 3D vector
954    type Vec3: Vector<Scalar, 3>;
955    /// The type of a 3D vector with an additional '1' expected in its extra element if it is a position
956    type Vec4: Vector<Scalar, 4>;
957    /// The type of a 3D matrix that can transform Vec3
958    type Mat3: SqMatrix3<Scalar>;
959    /// The type of a 3D matrix which allows for translations, that can transform Vec4
960    type Mat4: SqMatrix4<Scalar>;
961    /// The quaternion type that provides for rotations in 3D
962    type Quat: Quaternion<Scalar>;
963    /// The transform type
964    type Trans: Transform<Scalar, Self::Vec3, Self::Quat>;
965    // fn of_transform3/4?
966    // cross_product3
967    // axis_of_rotation3/4
968    // clamp
969}
970
971//tt Geometry2D
972/// This is an experimental trait - it bundles together a Vec2 and a Mat2.
973///
974/// The [Geometry2D] trait supplies a framework for implementing 2D
975/// vector and matrix operations.
976pub trait Geometry2D<Scalar: Float> {
977    /// The type of a 2D vector
978    type Vec2: Vector<Scalar, 2>;
979    /// The type of a 2D matrix that can transform a Vec2
980    type Mat2: SqMatrix<Scalar, 2, 4>;
981}