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    /// Return true if the vector is all zeros
272    fn set_zero(&mut self) {
273        *self = [F::ZERO;D].into();
274    }
275
276    /// Return true if the vector is all zeros
277    fn is_zero(&self) -> bool {
278        !self.deref().iter().any(|f| !f.is_zero())
279    }
280
281    /// Return the dot product of two vectors
282    #[inline]
283    fn dot<A: AsRef<[F;D]>>(&self, other: A) -> F {
284        vector::dot(self.deref(), other.as_ref())
285    }
286
287    /// Return the dot product of two vectors
288    #[inline]
289    fn dot_arr(&self, other: &[F; D]) -> F {
290        vector::dot(self.deref(), other)
291    }
292
293    /// Return the sum of the components
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    /// Return the square of the length of the vector
303    #[inline]
304    fn length_sq(&self) -> F {
305        self.dot(self)
306    }
307
308    /// Return the length of the vector
309    #[inline]
310    fn length(&self) -> F {
311        self.length_sq().sqrt()
312    }
313
314    /// Normalize the vector; if its length is close to zero, then set it to be zero
315    #[inline]
316    #[must_use]
317    fn normalize(mut self) -> Self {
318        let l = self.length();
319        if l < F::epsilon() {
320            self = Self::default()
321        } else {
322            self /= l
323        }
324        self
325    }
326
327    /// Return the square of the distance between this vector and another
328    #[inline]
329    fn distance_sq<A: AsRef<[F;D]>>(&self, other: A) -> F {
330        (*self - other.as_ref()).length_sq()
331    }
332
333    /// Return the square of the distance between this vector and another array
334    fn distance_sq_arr(&self, other: &[F; D]) -> F {
335        (*self - other).length_sq()
336    }
337
338    /// Return the distance between this vector and another
339    #[inline]
340    fn distance<A: AsRef<[F;D]>>(&self, other: A) -> F {
341        self.distance_sq(other).sqrt()
342    }
343    /// Return the distance between this vector and another array
344    fn distance_arr(&self, other: &[F; D]) -> F {
345        self.distance_sq_arr(other).sqrt()
346    }
347
348    /// Create a linear combination of this [Vector] and another using parameter `t` from zero to one
349    #[must_use]
350    fn mix<A>(self, other: A, t: F) -> Self
351    where
352        A: std::ops::Deref<Target = [F; D]>,
353    {
354        vector::mix(self.deref(), other.deref(), t).into()
355    }
356
357    /// Create a linear combination of a number of vectors given a scale for each
358    ///
359    /// If the lengths of the slices provided differ, then the entries in the
360    /// longer slice (without pairs to go with) are ignored
361    #[must_use]
362    fn sum_scaled<A>(v:&[A], scales:&[F]) -> Self
363    where
364        A: std::ops::Deref<Target = [F; D]>,
365    {
366        scales
367            .iter()
368            .zip(v.iter())
369            .fold([F::ZERO; D], |mut acc, (s, v)| {
370                for (a, v) in acc.iter_mut().zip(v.iter()) {
371                    *a = *a + *v * *s;
372                }
373                acc
374            }).into()
375    }
376
377    /// Rotate a vector within a plane around a
378    /// *pivot* point by the specified angle
379    ///
380    /// 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.
381    ///
382    /// For a 3D rotation about the Z axis, they should be 0 and 1; for
383    /// rotation about the Y axis they should be 2 and 0; and for rotation
384    /// about the X axis they should be 1 and 2.
385    ///
386    fn rotate_around(mut self, pivot: &Self, angle: F, c0: usize, c1: usize) -> Self {
387        let (s, c) = angle.sin_cos();
388        let dx = self[c0] - pivot[c0];
389        let dy = self[c1] - pivot[c1];
390        let x1 = c * dx - s * dy;
391        let y1 = c * dy + s * dx;
392        self[c0] = x1 + pivot[c0];
393        self[c1] = y1 + pivot[c1];
394        self
395    }
396
397    /// Cross product of two 3-element vectors
398    #[must_use]
399    fn cross_product<A: AsRef<[F;3]>>(&self, other: A) -> Self
400    where
401        Self: From<[F; 3]>,
402        Self: AsRef<[F; 3]>, // so that it knows as_ref() returns &[F;3], i.e. D is 3
403    {
404        vector::cross_product3(self.as_ref(), other.as_ref()).into()
405    }
406
407    /// Cross product of two 3-element vectors, one as an array reference
408    #[must_use]
409    fn cross_product_arr(&self, other: &[F; 3]) -> Self
410    where
411        Self: From<[F; 3]>,
412        Self: AsRef<[F; 3]>, // so that it knows as_ref() returns &[F;3], i.e. D is 3
413    {
414        vector::cross_product3(self.as_ref(), other).into()
415    }
416
417    //mp transformed_by_m
418    /// Multiply the vector by the matrix to transform it
419    fn transformed_by_m<const D2: usize>(&mut self, m: &[F; D2]) -> &mut Self
420    where
421        [(); D]: IsSquared<D, D2>,
422    {
423        *self = matrix::multiply::<F, D2, D, D, D, D, 1>(m, self.deref()).into();
424        self
425    }
426
427    //cp uniform_dist_sphere3
428    /// Get a point on a sphere uniformly distributed for a point
429    /// where x in [0,1) and y in [0,1)
430    #[must_use]
431    fn uniform_dist_sphere3(x: [F; 2], map: bool) -> Self
432    where
433        Self: From<[F; 3]>,
434    {
435        (vector::uniform_dist_sphere3(x, map)).into()
436    }
437}
438
439/// The [Vector2] trait describes a 3-dimensional vector of [Float]
440///
441pub trait Vector2<F: Float>: Vector<F, 2> {}
442impl<F, V> Vector2<F> for V
443where
444    F: Float,
445    V: Vector<F, 2>,
446{
447}
448
449/// The [Vector3] trait describes a 3-dimensional vector of [Float]
450///
451pub trait Vector3<F: Float>: Vector<F, 3> {
452    //fp apply_q3
453    /// Apply a quaternion to a V3
454    ///
455    /// This can either take other as &\[F;3\] and produce \[F; 3\], or
456    ///  &D where D:Deref<Target = \[F; 3\]> and D:From<\[F; 3\]
457    ///
458    /// If it takes the former then it can operate on \[F;3\] and
459    /// anything that is Deref<Target = \[F;3\]>, but it needs its result
460    /// cast into the correct vector
461    ///
462    /// If it tkes the latter then it cannot operate on \[F;3\], but its
463    /// result need not be cast
464    #[must_use]
465    fn apply_q<Q>(&self, q: &Q) -> Self
466    where
467        Q: Quaternion<F>,
468    {
469        quat::apply3(q.deref(), self.as_ref()).into()
470    }
471}
472impl<F, V> Vector3<F> for V
473where
474    F: Float,
475    V: Vector<F, 3>,
476{
477}
478
479/// The [Vector4] trait describes a 3-dimensional vector of [Float]
480///
481pub trait Vector4<F: Float>: Vector<F, 4> {
482    //fp apply_q
483    /// Apply a quaternion to a V4
484    ///
485    /// This can either take other as &\[F;3\] and produce \[F; 3\], or
486    ///  &D where D:Deref<Target =\[F; 3\]> and D:From<\[F; 3\]
487    ///
488    /// If it takes the former then it can operate on \[F;3\] and
489    /// anything that is Deref<Target = \[F;3\]>, but it needs its result
490    /// cast into the correct vector
491    ///
492    /// If it tkes the latter then it cannot operate on \[F;3\], but its
493    /// result need not be cast
494    #[must_use]
495    fn apply_q<Q>(&self, q: &Q) -> Self
496    where
497        Q: Quaternion<F>,
498    {
499        quat::apply4(q.deref(), self.as_ref()).into()
500    }
501}
502impl<F, V> Vector4<F> for V
503where
504    F: Float,
505    V: Vector<F, 4>,
506{
507}
508
509/// The [Matrix] trait describes an R-by-C matrix of [Float] type that operates on a [Vector].
510///
511/// Such [Matrix] support basic arithmetic using addition and
512/// subtraction, scaling, indexing (linearly, row major).
513///
514/// The 'transform vector' methods are tricky to put in here as type inference
515/// fails more frequently then it does for square matrices (whwre R*C is always
516/// D^2)
517pub trait Matrix<F: Float, const R: usize, const C: usize, const RC: usize>:
518    ArrayBasic
519    + ArrayRef<F, RC>
520    + ArrayIndex<F>
521    + ArrayConvert<F, RC>
522    + ArrayAddSubNeg<F, RC>
523    + ArrayScale<F>
524{
525    /// Return true if the matrix is zero
526    fn is_zero(&self) -> bool {
527        vector::is_zero(self.deref())
528    }
529
530    /// Set the matrix to zero
531    fn set_zero(&mut self) -> &mut Self {
532        vector::set_zero(self.deref_mut());
533        self
534    }
535
536    /// Return a transpose matrix
537    fn transpose<M: Matrix<F, C, R, RC>>(&self) -> M {
538        matrix::transpose::<F, RC, R, C>(self).into()
539    }
540}
541impl<F: Float, const R: usize, const C: usize, const RC: usize, M> Matrix<F, R, C, RC> for M where
542    M: ArrayBasic
543        + ArrayRef<F, RC>
544        + ArrayIndex<F>
545        + ArrayConvert<F, RC>
546        + ArrayAddSubNeg<F, RC>
547        + ArrayScale<F>
548{
549}
550
551/// The [SqMatrix] trait describes an N-dimensional square matrix of [Float] type that operates on a [Vector].
552///
553/// This trait is not stable.
554///
555/// Such [SqMatrix] support basic arithmetic using addition and
556/// subtraction, and they provide component-wise multiplication and
557/// division, using the standard operators on two [SqMatrix]s.
558///
559/// They also support basic arithmetic to all components of the
560/// [SqMatrix] for addition, subtraction, multiplication and division by
561/// a scalar [Float] value type that they are comprised of. Hence a
562/// `m:SqMatrix<F>` may be scaled by a `s:F` using `m * s`.
563pub trait SqMatrix<F: Float, const D: usize, const D2: usize>:
564    Matrix<F, D, D, D2> + std::ops::Mul<Output = Self> + std::ops::MulAssign
565{
566    /// Apply the matrix to a vector to transform it
567    ///
568    /// This is in SqMatrix rather than Matrix as type inference works for the
569    /// output of transfomrations as the type matches the input (which is not
570    /// the case for rectangular transformations)
571    fn mul_vec<T>(&self, v: &T) -> T
572    where
573        T: std::ops::Deref<Target = [F; D]>,
574        T: From<[F; D]>,
575    {
576        matrix::transform_vec::<F, D2, D, D>(self, v).into()
577    }
578
579    /// Apply the matrix to a vector to transform it
580    ///
581    /// This is in SqMatrix rather than Matrix as type inference works for the
582    /// output of transfomrations as the type matches the input (which is not
583    /// the case for rectangular transformations)
584    fn mul_vec_arr(&self, v: &[F; D]) -> [F; D] {
585        matrix::transform_vec::<F, D2, D, D>(self, v)
586    }
587
588    /// Create an identity matrix
589    fn identity() -> Self {
590        matrix::identity::<F, D2, D>().into()
591    }
592
593    /// Calculate the determinant of the matrix
594    fn determinant(&self) -> F;
595
596    /// Create an inverse matrix, and in indication the inverse could not be created
597    ///
598    /// If the matrix is not invertible, return anything
599    fn checked_inverse(&self) -> (Self, bool);
600
601    /// Create an inverse matrix
602    ///
603    /// If the matrix is not invertible, return anything
604    fn inverse(&self) -> Self {
605        self.checked_inverse().0
606    }
607
608    /// Create an inverse matrix
609    ///
610    /// If the matrix is not invertible, return None
611    fn opt_inverse(&self) -> Option<Self> {
612        let (inverse, ok) = self.checked_inverse();
613        ok.then_some(inverse)
614    }
615
616    /// Create a 2D rotation matrix by an angle in radians, anticlockwise about the origin
617    fn rotation2d(angle: F) -> Self
618    where
619        Self: From<[F; 4]>,
620    {
621        let c = angle.cos();
622        let s = angle.sin();
623        [c, s, -s, c].into()
624    }
625}
626
627//tt SqMatrix2
628/// The [SqMatrix2] trait describes a 2-dimensional vector of [Float]
629///
630pub trait SqMatrix2<F: Float>: SqMatrix<F, 2, 4> {}
631impl<F, M> SqMatrix2<F> for M
632where
633    F: Float,
634    M: SqMatrix<F, 2, 4>,
635{
636}
637
638//tt SqMatrix3
639/// The [SqMatrix3] trait describes a 2-dimensional vector of [Float]
640///
641pub trait SqMatrix3<F: Float>: SqMatrix<F, 3, 9> {
642    /// Create a 3-by-3 matrix of the rotation of a quaternion
643    // This is not in SqMatrix so that SqMatrix4 can have a different implementaion
644    fn of_quaternion<Q: Quaternion<F>>(q: Q) -> Self {
645        let mut s = Self::default();
646        q.set_rotation3(&mut s);
647        s
648    }
649}
650
651impl<F, M> SqMatrix3<F> for M
652where
653    F: Float,
654    M: SqMatrix<F, 3, 9>,
655{
656}
657
658//tt SqMatrix4
659/// The [SqMatrix4] trait describes a 2-dimensional vector of [Float]
660///
661pub trait SqMatrix4<F: Float>: SqMatrix<F, 4, 16> {
662    /// Generate a perspective matrix
663    fn perspective(fov: F, aspect: F, near: F, far: F) -> Self {
664        matrix::perspective4(fov, aspect, near, far).into()
665    }
666
667    /// Generate a matrix that represents a 'look at a vector'
668    fn look_at(eye: &[F; 3], center: &[F; 3], up: &[F; 3]) -> Self {
669        matrix::look_at4(eye, center, up).into()
670    }
671
672    /// Scale the matrix for a transformation - only update top *3* rows
673    fn scale3(&mut self, by: F) {
674        for d in self.iter_mut().take(12) {
675            *d = *d * by;
676        }
677    }
678    /// Translate the matrix by a Vec3
679    fn translate3(&mut self, by: &[F; 3]) {
680        self[3] = self[3] + by[0];
681        self[7] = self[7] + by[1];
682        self[11] = self[11] + by[2];
683    }
684
685    /// Translate the matrix by a Vec4
686    fn translate4(&mut self, by: &[F; 4]) {
687        self[3] = self[3] + by[0];
688        self[7] = self[7] + by[1];
689        self[11] = self[11] + by[2];
690    }
691}
692impl<F, M> SqMatrix4<F> for M
693where
694    F: Float,
695    M: SqMatrix<F, 4, 16>,
696{
697}
698
699//a Quaternion
700//tt Quaternion
701/// The [Quaternion] trait describes a 4-dimensional vector of [Float] type.
702///
703/// Such [Quaternion]s support basic arithmetic using addition and
704/// subtraction, and they provide quaternion multiplication and division.
705///
706/// They also support basic arithmetic to all components of the
707/// [Quaternion] for addition, subtraction, multiplication and division by
708/// a scalar [Float] value type that they are comprised of. Hence a
709/// `q:Quaternion<F>` may be scaled by a `s:F` using `q * s`.
710///
711/// The [Quaternion] can be indexed only by a `usize`; that is individual
712/// components of the vector can be accessed, but ranges may not.
713pub trait Quaternion<F: Float>:
714    ArrayBasic
715    + ArrayRef<F, 4>
716    + ArrayIndex<F>
717    + ArrayConvert<F, 4>
718    + ArrayAddSubNeg<F, 4>
719    + QuatMulDiv<F, 4>
720    + ArrayScale<F>
721{
722    /// Create from r, i, j, k
723    #[must_use]
724    fn of_rijk(r: F, i: F, j: F, k: F) -> Self;
725
726    /// Create the conjugate of a quaternion
727    #[must_use]
728    #[inline]
729    fn conjugate(self) -> Self {
730        let (r, i, j, k) = self.as_rijk();
731        Self::of_rijk(r, -i, -j, -k)
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    /// Set to an identity transformation
746    fn set_identity(&mut self) {
747        *self = Self::default();
748    }
749
750    /// Set the quaternion to be all zeros
751    fn set_zero(&mut self) {
752        *self = [F::ZERO; 4].into();
753    }
754
755    /// Create a linear combination of this [Quaternion] and another using parameter `t` from zero to one
756    #[must_use]
757    fn mix(self, other: &[F; 4], t: F) -> Self {
758        vector::mix(self.deref(), other, t).into()
759    }
760
761    /// Return the dot product of two quaternions; basically used for length
762    fn dot(self, other: &Self) -> F {
763        vector::dot(self.deref(), other.deref())
764    }
765
766    /// Return the square of the length of the quaternion
767    fn length_sq(&self) -> F {
768        self.dot(self)
769    }
770
771    /// Return the length of the quaternion
772    fn length(&self) -> F {
773        self.length_sq().sqrt()
774    }
775
776    /// Return the square of the distance between this quaternion and another
777    fn distance_sq(&self, other: &Self) -> F {
778        quat::distance_sq(self, other)
779    }
780
781    /// Return the distance between this quaternion and another
782    fn distance(&self, other: &Self) -> F {
783        self.distance_sq(other).sqrt()
784    }
785
786    /// Normalize the quaternion; if its length is close to zero, then set it to be zero
787    #[must_use]
788    fn normalize(mut self) -> Self {
789        let l = self.length();
790        if l < F::epsilon() {
791            self.set_zero()
792        } else {
793            self /= l
794        }
795        self
796    }
797
798    /// Create a unit quaternion for a rotation of an angle about an axis
799    ///
800    /// The axis need not be a unit vector
801    #[must_use]
802    fn of_axis_angle(axis: &[F; 3], angle: F) -> Self {
803        quat::of_axis_angle(axis, angle).into()
804    }
805
806    /// Multiply a rotation about the X-axis by this quaternion
807    ///
808    /// ie. result = rotate(x, angle) * self
809    #[inline]
810    #[must_use]
811    fn rotate_x(self, angle: F) -> Self {
812        quat::rotate_x(self.as_ref(), angle).into()
813    }
814
815    /// Multiply a rotation about the Y-axis by this quaternion
816    ///
817    /// ie. result = rotate(y, angle) * self
818    #[inline]
819    #[must_use]
820    fn rotate_y(self, angle: F) -> Self {
821        quat::rotate_y(self.as_ref(), angle).into()
822    }
823
824    /// Multiply a rotation about the Z-axis by this quaternion
825    ///
826    /// ie. result = rotate(z, angle) * self
827    #[inline]
828    #[must_use]
829    fn rotate_z(self, angle: F) -> Self {
830        quat::rotate_z(self.as_ref(), angle).into()
831    }
832
833    /// Multiply a rotation about the X-axis by this quaternion
834    ///
835    /// ie. result = self * rotate(x, angle)
836    #[inline]
837    #[must_use]
838    fn premul_rotate_x(self, angle: F) -> Self {
839        quat::multiply(
840            &self,
841            &quat::rotate_x(&[F::ZERO, F::ZERO, F::ZERO, F::ONE], angle),
842        )
843        .into()
844    }
845
846    /// Multiply a rotation about the Y-axis by this quaternion
847    ///
848    /// ie. result = self * rotate(y, angle)
849    #[inline]
850    #[must_use]
851    fn premul_rotate_y(self, angle: F) -> Self {
852        quat::multiply(
853            &self,
854            &quat::rotate_y(&[F::ZERO, F::ZERO, F::ZERO, F::ONE], angle),
855        )
856        .into()
857    }
858
859    /// Multiply a rotation about the Z-axis by this quaternion
860    ///
861    /// ie. result = self * rotate(z, angle)
862    #[inline]
863    #[must_use]
864    fn premul_rotate_z(self, angle: F) -> Self {
865        quat::multiply(
866            &self,
867            &quat::rotate_z(&[F::ZERO, F::ZERO, F::ZERO, F::ONE], angle),
868        )
869        .into()
870    }
871
872    /// Create a quaternion that maps a unit V3 of dirn to (0,0,-1) and a unit
873    /// V3 of up (if perpendicular to dirn) to (0,1,0)
874    #[must_use]
875    fn look_at(dirn: &[F; 3], up: &[F; 3]) -> Self {
876        quat::look_at(dirn, up).into()
877    }
878
879    //cp rotation_of_vec_to_vec
880    /// Get a quaternion that is a rotation of one vector to another
881    ///
882    /// The vectors must be unit vectors
883    #[must_use]
884    fn rotation_of_vec_to_vec(a: &[F; 3], b: &[F; 3]) -> Self {
885        quat::rotation_of_vec_to_vec(a, b).into()
886    }
887
888    //cp mapping_vector_pair_to_vector_pair
889    /// Create a quaternion that maps (v0, v1) to (w0, w1)
890    ///
891    /// This will map v0 to the Z axis, and the Z axis to w0. Applying
892    /// both of these quaternions in succession maps v0 to w0.
893    ///
894    /// It maps v1 to v1' and w1 *backwards* to w1', where the
895    /// difference between v1' and w1' should be *just* a rotation
896    /// around the Z axis. Creating a rotation to do this is a third quaternion
897    ///
898    /// Then the three quaternions can be applied appropriately to map
899    /// v0 to w0 (for sure), and v1 to w1 (if the intermediate
900    /// rotation were just a Z-rotation)
901    fn mapping_vector_pair_to_vector_pair(
902        (di_m, dj_m): (&[F; 3], &[F; 3]),
903        (di_c, dj_c): (&[F; 3], &[F; 3]),
904    ) -> Self {
905        let z_axis: [F; 3] = [F::zero(), F::zero(), F::one()];
906        let qi_c = Self::rotation_of_vec_to_vec(di_c, &z_axis);
907        let qi_m = Self::rotation_of_vec_to_vec(di_m, &z_axis);
908
909        let dj_c_rotated = quat::apply3(&qi_c, dj_c);
910        let dj_m_rotated = quat::apply3(&qi_m, dj_m);
911
912        let theta_dj_m = dj_m_rotated[0].atan2(dj_m_rotated[1]);
913        let theta_dj_c = dj_c_rotated[0].atan2(dj_c_rotated[1]);
914        let theta = theta_dj_m - theta_dj_c;
915        let theta_div_2 = theta / (F::one() + F::one());
916        let cos_2theta = theta_div_2.cos();
917        let sin_2theta = theta_div_2.sin();
918        let q_z = Self::of_rijk(cos_2theta, F::zero(), F::zero(), sin_2theta);
919        qi_c.conjugate() * q_z * qi_m
920    }
921
922    //cp weighted_average_pair
923    /// Calculate the weighted average of two unit quaternions
924    ///
925    /// w_a + w_b must be 1.
926    ///
927    /// See <http://www.acsu.buffalo.edu/~johnc/ave_quat07.pdf>
928    /// Averaging Quaternions by F. Landis Markley
929    #[must_use]
930    fn weighted_average_pair(&self, w_a: F, qb: &Self, w_b: F) -> Self {
931        quat::weighted_average_pair(self.as_ref(), w_a, qb.as_ref(), w_b).into()
932    }
933
934    //cp weighted_average_many
935    /// Calculate the weighted average of many unit quaternions
936    ///
937    /// weights need not add up to 1
938    ///
939    /// This is an approximation compared to the Landis Markley paper
940    #[must_use]
941    fn weighted_average_many<A: Into<[F; 4]>, I: Iterator<Item = (F, A)>>(value_iter: I) -> Self {
942        let value_iter = value_iter.map(|(w, v)| (w, v.into()));
943        quat::weighted_average_many(value_iter).into()
944    }
945
946    //cp of_rotation3
947    /// Find the unit quaternion of a Matrix3 assuming it is purely a rotation
948    #[must_use]
949    fn of_rotation3<M>(rotation: &M) -> Self
950    where
951        M: SqMatrix3<F>;
952
953    //fp set_rotation3
954    /// Set a Matrix3 to be the rotation matrix corresponding to the unit quaternion
955    fn set_rotation3<M>(&self, m: &mut M)
956    where
957        M: SqMatrix3<F>;
958
959    //fp set_rotation4
960    /// Set a Matrix4 to be the rotation matrix corresponding to the unit quaternion
961    fn set_rotation4<M>(&self, m: &mut M)
962    where
963        M: SqMatrix4<F>;
964
965    //fp apply3
966    /// Apply the quaternion to a V3
967    ///
968    /// This can either take other as &\[F;3\] and produce \[F; 3\], or
969    ///  &D where D:Deref<Target =\[F; 3\]> and D:From<\[F; 3\]>
970    ///
971    /// If it takes the former then it can operate on \[F;3\] and
972    /// anything that is Deref<Target=\[F;3\]>, but it needs its result
973    /// cast into the correct vector
974    ///
975    /// If it tkes the latter then it cannot operate on \[F;3\], but its
976    /// result need not be cast
977    #[must_use]
978    fn apply3<T>(&self, other: &T) -> T
979    where
980        T: std::ops::Deref<Target = [F; 3]>,
981        T: From<[F; 3]>,
982    {
983        quat::apply3(self.deref(), other.deref()).into()
984    }
985
986    /// Apply the quaternion to a [F; 3]
987    ///
988    /// See apply3 for why this is provided
989    ///
990    #[must_use]
991    fn apply3_arr(&self, other: &[F; 3]) -> [F; 3] {
992        quat::apply3(self.deref(), other)
993    }
994
995    //fp apply4
996    /// Apply the quaternion to a V4
997    #[must_use]
998    fn apply4<T>(&self, other: &T) -> T
999    where
1000        T: std::ops::Deref<Target = [F; 4]>,
1001        T: From<[F; 4]>,
1002    {
1003        quat::apply4(self.deref(), other.deref()).into()
1004    }
1005
1006    /// Apply the quaternion to a [F; 3]
1007    ///
1008    /// See apply3 for why this is provided
1009    ///
1010    #[must_use]
1011    fn apply4_arr(&self, other: &[F; 4]) -> [F; 4] {
1012        quat::apply4(self.deref(), other)
1013    }
1014
1015    //zz All done
1016}
1017
1018//a Transform
1019//tt Transform
1020/// The [Transform] trait describes a translation, rotation and
1021/// scaling for 3D, represented eventually as a Mat4
1022///
1023/// A transformation that is a translation . scaling . rotation
1024/// (i.e. it applies the rotation to an object, then scales it, then
1025/// translates it)
1026///
1027/// The transformation can be simply scaled using mul/div
1028///
1029/// The transformation can be applied to its Vec4 through multiplication
1030pub trait Transform<F>:
1031    Clone
1032    + Copy
1033    + std::fmt::Debug
1034    + std::fmt::Display
1035    + std::default::Default
1036    + std::ops::Mul<Self::Vec4, Output = Self::Vec4>
1037    + std::ops::Mul<F, Output = Self>
1038    + std::ops::MulAssign<F>
1039    + std::ops::Div<F, Output = Self>
1040    + std::ops::DivAssign<F>
1041where
1042    F: Float,
1043{
1044    /// Type of vector comprehended as the translation/scaling for this transform
1045    type Vec3: Vector3<F>;
1046    /// Type of vector comprehended as the translation/scaling for this transform
1047    type Vec4: Vector4<F>;
1048    /// Type of quaternion comprehended as the rotation for this transform
1049    type Quat: Quaternion<F>;
1050    /// Set to true if the transformation can only perform uniform scaling
1051    const UNIFORM_SCALING: bool;
1052    /// Create a transformation that is a translation, rotation and scaling
1053    fn of_trs<A: AsRef<[F; 3]>>(t: A, r: Self::Quat, s: A) -> Option<Self>;
1054    /// Create a transformation that is a translation, rotation and uniform scaling
1055    fn of_trsu<A: AsRef<[F; 3]>>(t: A, r: Self::Quat, s: F) -> Self;
1056    /// Get the scale of the transform in each of the axes
1057    fn scale(&self) -> Option<Self::Vec3>;
1058    /// Returns true if the scaling is uniform in each axis
1059    fn is_uniform_scale(&self) -> bool;
1060    /// Get the scale of the transform in each of the axes, if possible
1061    fn uniform_scale(&self) -> Option<F>;
1062    /// Get a translation by a vector
1063    fn translation(&self) -> Self::Vec3;
1064    /// Set to an identity transformation
1065    fn set_identity(&mut self);
1066    /// Get the rotation of the transformation, if possible
1067    fn rotation(&self) -> Option<Self::Quat>;
1068    /// Set the scale of the transformation
1069    ///
1070    /// Returns false if the scale cannot be set (as it is nonuniform, and the
1071    /// transform only supports uniform scaling)
1072    fn set_scale<A: AsRef<[F; 3]>>(&mut self, scale: A) -> bool;
1073    /// Set the scale of the transformation
1074    fn set_uniform_scale(&mut self, scale: F);
1075    /// Set the translation of the transformation
1076    fn set_translation<A: AsRef<[F; 3]>>(&mut self, translation: A);
1077    /// Set the rotation of a transformation
1078    fn set_rotation(&mut self, rotation: Self::Quat);
1079    /// Pre-apply a nonuniform scaling
1080    ///
1081    /// Returns false if this cannot be properly achieved (for example for a
1082    /// transformation that has a rotation that stores the rotation as a
1083    /// quaternion)
1084    fn scale_by<A: AsRef<[F; 3]>>(&mut self, scale: A) -> bool;
1085    /// Pre-apply a uniform scaling
1086    fn scale_uniform_by(&mut self, scale: F);
1087    /// Pre-apply a scaled translation to the transformation
1088    fn translate_by<A: AsRef<[F; 3]>>(&mut self, translation: A, scale: F);
1089    /// Rotate the transformation by a quaternion
1090    fn rotate_by(&mut self, quaternion: &Self::Quat);
1091    /// Transform this transformation by another *UNIFORM* scale transformation;
1092    /// if is not uniform scaling then return false
1093    fn transform_by<T: Transform<F, Quat = Self::Quat>>(&mut self, transformer: &T) -> bool;
1094    /// Get the inverse transformation
1095    ///
1096    /// This is only possible if the scaling is uniform
1097    #[must_use]
1098    fn inverse_transform(&self) -> Option<Self>;
1099    /// Invert the transformation
1100    ///
1101    /// This will return false if the scaling is not uniform
1102    fn set_inverse(&mut self) -> bool {
1103        if let Some(s) = self.inverse_transform() {
1104            *self = s;
1105            true
1106        } else {
1107            false
1108        }
1109    }
1110    /// Convert it to a 4-by-4 matrix and set it
1111    fn set_mat4<M: SqMatrix4<F>>(&self, mat4: &mut M) {
1112        *mat4 = self.as_mat4();
1113    }
1114    /// Convert it to a 4-by-4 matrix and set it
1115    fn set_mat3<M: SqMatrix3<F>>(&self, mat3: &mut M) {
1116        *mat3 = self.as_mat3();
1117    }
1118    /// Convert the non-translation to a 3-by-3 matrix
1119    #[must_use]
1120    fn as_mat3<M: SqMatrix3<F>>(&self) -> M;
1121    /// Convert it to a 4-by-4 matrix
1122    #[must_use]
1123    fn as_mat4<M: SqMatrix4<F>>(&self) -> M;
1124    /// Apply the quaternion to a vector or similar
1125    #[must_use]
1126    fn apply3<T>(&self, other: T) -> T
1127    where
1128        T: std::ops::Deref<Target = [F; 3]>,
1129        T: From<[F; 3]>,
1130    {
1131        self.apply3_arr(other.deref()).into()
1132    }
1133    /// Apply the transformation to a [F; 4]
1134    #[must_use]
1135    fn apply3_arr(&self, other: &[F; 3]) -> [F; 3];
1136    /// Apply the transformation to a vector or similar
1137    #[must_use]
1138    fn apply4<T>(&self, other: T) -> T
1139    where
1140        T: std::ops::Deref<Target = [F; 4]>,
1141        T: From<[F; 4]>,
1142    {
1143        self.apply4_arr(other.deref()).into()
1144    }
1145    /// Apply the transformation to a [F; 4]
1146    #[must_use]
1147    fn apply4_arr(&self, other: &[F; 4]) -> [F; 4];
1148}
1149
1150//a Vector3D, Geometry3D
1151//tt Vector3D
1152/// This is probably a temporary trait used until SIMD supports Geometry3D and Geometry2D
1153///
1154/// The [Vector3D] trait describes vectors that may be used for
1155/// 3D geometry
1156pub trait Vector3D<Scalar: Float> {
1157    /// The type of a 2D vector
1158    type Vec2: Vector<Scalar, 2>;
1159    /// The type of a 3D vector
1160    type Vec3: Vector<Scalar, 3>;
1161    /// The type of a 3D vector with an additional '1' expected in its extra element
1162    type Vec4: Vector<Scalar, 4>;
1163}
1164
1165//tt Geometry3D
1166/// The [Geometry3D] trait supplies a framework for implementing 3D
1167/// vector and matrix operations, and should also include the
1168/// quaternion type.
1169///
1170/// An implementation of [Geometry3D] can be used for OpenGL and Vulkan graphics, for example.
1171pub trait Geometry3D<Scalar: Float> {
1172    /// The type of a 3D vector
1173    type Vec3: Vector<Scalar, 3>;
1174    /// The type of a 3D vector with an additional '1' expected in its extra element if it is a position
1175    type Vec4: Vector<Scalar, 4>;
1176    /// The type of a 3D matrix that can transform Vec3
1177    type Mat3: SqMatrix3<Scalar>;
1178    /// The type of a 3D matrix which allows for translations, that can transform Vec4
1179    type Mat4: SqMatrix4<Scalar>;
1180    /// The quaternion type that provides for rotations in 3D
1181    type Quat: Quaternion<Scalar>;
1182    /// The transform type
1183    type Trans: Transform<Scalar, Quat = Self::Quat>;
1184    // fn of_transform3/4?
1185    // cross_product3
1186    // axis_of_rotation3/4
1187    // clamp
1188}
1189
1190//tt Geometry2D
1191/// This is an experimental trait - it bundles together a Vec2 and a Mat2.
1192///
1193/// The [Geometry2D] trait supplies a framework for implementing 2D
1194/// vector and matrix operations.
1195pub trait Geometry2D<Scalar: Float> {
1196    /// The type of a 2D vector
1197    type Vec2: Vector<Scalar, 2>;
1198    /// The type of a 2D matrix that can transform a Vec2
1199    type Mat2: SqMatrix<Scalar, 2, 4>;
1200}