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}