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