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}