geo_nd/
lib.rs

1/*a To do
2
3remove indexing from quaternions
4
5Add matrix trait which takes out most of the sqmatrix traits
6
7Document and get transform to work
8
9Fix rotate_x, rotate_y, rotate_z
10
11quaternion distance functions?
12
13*/
14//a Documentation
15#![warn(missing_docs)]
16/*!
17
18# Geometry library
19
20This library provides for N-dimensional geometrical objects,
21particularly *Vector*s, *Matrix*, *Quaternion* operations.
22
23The underlying numeric type that must be supported for these
24operations is either a type supporting [Num] - which includes integers - or
25in most circumstances [Float]. Particularly the latter is
26provided by f32 anf f64.
27
28It provides libraries that provide functions that implement vector,
29matrix and quaternion operations using arrays of values. For
30quaternions this is `[F; 4]`, in the order i, j, k, r.
31
32It additionally provides traits for [Vector], [Quaternion], and
33[SqMatrix]. These traits provide consistent means of manipulating such
34items, which are expected to be in some manner a wrapper around a
35`[F;D]`, but with perhaps greater alignment restrictions. In theory
36this could be a SIMD type.
37
38The purpose of these traits is to provide simple access to the vector,
39matrix, and quaternion operations using methods, rather than invoking
40these operations through explicit function calls. For example,
41quaternions can be multiplied together with `a*b`, rather than
42invoking quat::multiply.
43
44The library mirrors the operation of 'glm' in some sense.
45
46The desire for the library is that it does not undergo much
47development; it provides a stable and simple basis for operations that
48are common mathematical operations, with no aim for it to grow into a
49larger linear algebra library.
50
51## Caveats
52
53The functions in the library use const generics, but as const generic
54evaulations are currently unstable it requires more consts than should
55be required. For example, to create an identity square matrix the
56`matrix::identity` function has the generic signature `<V:Num, const
57D2:usize, const D:usize>`. The value of `D2` *must* equal `D*D`. The
58function returns `[V; D2]`.
59
60Ideally the function should just take D as a const generic argument
61and the type would be `[V;D*D]`, but that is unstable (and there are
62some other issues).
63
64Additionally, the inference of a type for `V` is sometimes required to
65be forced, so there may be a small amount of turbofish notation such
66as `identity2::<f32>()`.
67
68# Trait method policy
69
70The purpose of the traits is to permit simple operation on arrays such
71as `[f32;4]`, without necessarily requiring conversion of those arrays
72into a specific type first. For example, it is simple to add `[1,2,3]`
73to a Vector type without having to convert that first into a Vector
74type - but it must also work for any Vector type too. Hence the
75arguments to methods are generally `&[F; D]`.
76
77However, for methods that return a (e.g.) Vector type (that is not
78Self), this would force the caller to convert the resultant type back
79to the required Vector type. The policy is therefore, for such
80methods, to use a generic on the method `T:Deref<Target = [}>`; to
81take an argument of type `&T`, and to return a `T`. This usually
82requires T to also provide `From<F;D>`. These methods can be described
83as 'apply M to type T to produce a modified T'. In general there will
84then be a method on the type T that operates on '&mut T' and
85explicitly takes a `&M'. These methods also return `&mut self` to
86permit chaining.
87
88For example, a matrix `M` can transform a vector `T` by using
89
90```
91    use geo_nd::{FArray, FArray2, SqMatrix, Vector};
92    let t : FArray::<f32, 3> = [0.0, 1.0, 2.0].into();
93    let m = FArray2::<f32, 3, 9>::identity();
94    let mut t = m.transform(&t);
95    // or
96    t.transformed_by_m(&m);
97
98```
99
100The downside to this policy is that one cannot apply a matrix to transform an array `[F;D]`
101
102```ignore
103    use geo_nd::{FArray, FArray2, SqMatrix, Vector};
104    let m = FArray2::<f32, 3, 9>::identity();
105    let t = m.transform(&[1.0,3.0,5.0]);
106```
107
108
109# Function operation
110
111The functions for geometry manipulation are provided in the [vector],
112[mat] and [quat] modules.
113
114## Basic operation
115
116```
117use geo_nd::vector;
118let y = [0., 1.];
119let x = [1., 0.];
120assert_eq!( vector::dot(&x, &y), 0., "Dot product of X and Y axis vectors is zero");
121let xy = vector::add(x,&y,2.);
122assert_eq!( xy, [1., 2.], "x + 2*y");
123assert_eq!( vector::length_sq(&xy), (5.), "|x + 2*y|^2 = 5");
124assert_eq!( vector::length(&xy), (5.0f64).sqrt(), "|x + 2*y| = sqrt(5)");
125```
126
127# Provided traits
128
129The library provides traits for types that can be vectors, matrices, and quaternions.
130
131## Vector
132
133Types that provide [Vector] can be manipulated with negation, addition,
134subtraction, and can be scaled with multiplication and division by
135their 'float'; their components can be accessed through indexing
136(e.g. a[0]) immutably and mutably.
137
138 As non-traditional vector operations they can be piece-wise
139multiplied and divided also, which can be useful in graphcis
140applications; they can also be piece-wise added and subtracted from
141using their 'float'.
142
143They also support [Copy], [std::default::Default], [std::fmt::Debug], and [std::fmt::Display],
144[serde::Serialize], [serde::Deserialize].
145
146They provide AsRef for float arrays of length 4 and slices for fast import and export from memory structures.
147
148### Vector3
149
150Vector3 types are 3-element vectors which additionally provide a
151[Vector3::cross_product] method, which does not exist (in a simply
152well defined manner) for other vector sizes.
153
154## SqMatrix
155
156Types that provide [SqMatrix] are square matrices that can be
157manipulated with negation, addition, subtraction, and multiplicaton, and can be
158scaled with multiplication and division by their 'float'; their
159components can be accessed through indexing (e.g. a[0]) immutably and
160mutably. The index is a usize, in row-major order (i.e. [0] is row
161zero column zero, [1] is row 0 column 1, and [nr] is row 1 column 0
162for a matrixt that is 'nr' by 'nc' rows by columns.)
163
164 They can also be piece-wise added and subtracted from using their
165'float'.
166
167They also support [Copy], [std::default::Default], [std::fmt::Debug], and [std::fmt::Display],
168[serde::Serialize], [serde::Deserialize].
169
170They provide AsRef for float arrays of length 4 and slices for fast import and export from memory structures.
171
172
173### SqMatrix4
174
175Types that provide [SqMatrix4] are 4-by-4 matrices. Additional methods
176are provided for graphics operations, and so the matrices are treated
177as 3-by-3 transformation matrices with a translation vector and the
178last element the distance scaling.
179
180They provide [SqMatrix] and additionally support graphically-useful
181constructors 'perspective' and 'look_at', and support translation by
182vectors.
183
184## Quaternion
185
186Quaternions are a mathematical means for describing a 3 dimensional rotation around
187the origin.
188
189Types that provide [Quaternion] can be
190manipulated with negation, addition, subtraction, multiplicaton, and division, and can be
191scaled with multiplication and division by their 'float'.
192
193They also support [Copy], [std::default::Default], [std::fmt::Debug], and [std::fmt::Display],
194[serde::Serialize], [serde::Deserialize].
195
196They Deref to their float arrays of length 4. The mapping of the
197arrays is (i, j, k, r).
198
199### Constructors
200
201Types providing the [Quaternion] trait can be constructed from:
202
203* a unit quaternion (1.0 + 0*i + 0*j + 0*k)
204
205* (r,i,j,k) tuples
206
207* the conjugate of another quaternion, i.e. (r,-i,-j,-k)
208
209* a rotation around a `[F; 3]` axis by an angle (in radians)
210
211* a rotation around one of the axes applied to another quaternion
212
213* another quaternion applied to a rotation around one of the axes
214
215* from a square matrix that describes a pure rotation (no scaling)
216
217* that describes a rotation of a camera looking down the negative Z
218  axis with the Y axis as up, to one looking along a specified
219  direction with a (perpendicular) up direction
220
221* the rotation that provides the shortest great circle path for one
222  unit vector to another (the axis of the rotation is the
223  perpendicular to both)
224
225* the weighted average of a number of quaternions
226
227The trait provides many application methods for quaternions, perhaps
228the most important being [Quaternion::apply3] and
229[Quaternion::apply4], which allow the quaternion to be applied to a
2303-element or 4-element vector (the latter being common in graphics,
231where the fourth element is usually 1 for a point, and 0 for a vector
232translation).
233
234# Provided types
235
236The library provides types that simply wrap `f32` and `f64` arrays,
237providing imlpementations of the traits and hence supporting vectors, matrices and quaternions. This is perhaps the
238simplest way to use the library.
239
240## Vector types
241
242The [FArray] type is a wrapper around an N-element array of floats,
243and it supports the [Vector] trait.
244
245## SqMatrix types
246
247The [FArray2] type is a wrapper around an N-by-N-element array of floats,
248and it supports the [SqMatrix] trait.
249
250## Quaternion types
251
252The [QArray] type is a wrapper around an 4-element array of floats,
253and it supports the [Quaternion] trait.
254
255# Examples
256
257## Two dimensions
258
259```
260// Import the traits
261use geo_nd::{Vector, SqMatrix};
262
263// Aliases for the types
264pub type Point2D = geo_nd::FArray<f64, 2>;
265pub type Mat2x2 = geo_nd::FArray2<f64, 2, 4>;
266
267let x : Point2D = [1.0, 0.0].into();
268let y : Point2D = [0.0, 1.0].into();
269
270let c = 30.0_f64.to_radians().cos();
271let s = 30.0_f64.to_radians().sin();
272let rot30 : Mat2x2 = [c, -s, s, c].into();
273
274let rot60 = rot30 * rot30;
275
276// Rotating x anticlockwise by 30 and 60 should turn it into y
277let is_it_y = rot60.transform(&rot30.transform(&x));
278
279// Check that the distance between them is tiny
280assert!((y-is_it_y).length_sq() < 1.0E-8);
281
282assert!(y.distance(&is_it_y) < 1.0E-8);
283
284let rot90 = rot60 * rot30;
285let rot180 = rot90 * rot90;
286
287let xy = x + y;
288let is_it_zero = xy + rot180.transform(&xy);
289assert!(is_it_zero.length() < 1.0E-8);
290```
291
292## Three dimensions
293
294```
295// Import the traits
296use geo_nd::{Quaternion, SqMatrix, Vector};
297
298// Aliases for the types
299pub type Point3D = geo_nd::FArray<f64, 3>;
300pub type Mat3x3 = geo_nd::FArray2<f64, 3, 9>;
301pub type Point4D = geo_nd::FArray<f64, 4>;
302pub type Quat = geo_nd::QArray<f64>;
303
304let x : Point3D = [1., 0., 0.].into();
305let y : Point3D = [0., 1., 0.].into();
306let z : Point3D = [0., 0., 1.].into();
307
308// qx rotates around the X axis by 90 degrees
309// [X,0,0] is unchanged
310// [0,1,0] maps to [0,0,1]
311// [0,0,1] maps to [0,-1,0]
312let qx = Quat::default().rotate_x(90.0_f64.to_radians());
313assert!(z.distance(&y.apply_q3(&qx)) < 1.0E-8);
314assert!(y.distance(&(-z).apply_q3(&qx)) < 1.0E-8);
315assert!(x.distance(&(x).apply_q3(&qx)) < 1.0E-8);
316
317// qy rotates around the Y axis by 90 degrees
318// [1,0,0] maps to [0,0,-1]
319// [0,Y,0] is unchanged
320// [0,0,1] maps to [1,0,0]
321let qy = Quat::default().rotate_y(90.0_f64.to_radians());
322assert!(x.distance(&(z).apply_q3(&qy)) < 1.0E-8);
323assert!(z.distance(&(-x).apply_q3(&qy)) < 1.0E-8);
324assert!(y.distance(&(y).apply_q3(&qy)) < 1.0E-8);
325
326// qx * qy applies qx to (qy applied to a vector)
327// Hence this chains the qx mapping onto the qy mapping
328// [1,0,0] -> [0,0,-1] -> [0,1,0]
329// [0,1,0] -> [0,1,0] -> [0,0,1]
330// [0,0,1] -> [1,0,0] -> [1,0,0]
331//
332// This is actually a 120 degree rotation around (1,1,1)
333// (qy * qx is a 120 degree rotation around (1,-1,1))
334let qxy = qx * qy;
335assert!(y.distance(&(x).apply_q3(&qxy)) < 1.0E-8);
336assert!(z.distance(&(y).apply_q3(&qxy)) < 1.0E-8);
337assert!(x.distance(&(z).apply_q3(&qxy)) < 1.0E-8);
338
339let mut m = Mat3x3::default();
340qxy.set_rotation3(&mut m);
341// qxy will be [0,0,1,  1,0,0, 0,1,0]
342// give or take floating point errors
343assert!((m.transform(&x) - y).length() < 1.0E-8);
344assert!((m.transform(&y) - z).length() < 1.0E-8);
345assert!((m.transform(&z) - x).length() < 1.0E-8);
346```
347
348# Trait discussion
349
350The libraries operate on arrays `[F;D]`, and so types that implement
351the Vector, Quaternion etc traits are expected to be wrappers around
352such array (but perhaps with greater alignment restrictions).
353
354An array `[f32/f64; D]` supports:
355
356 *   Copy, Clone, Debug, Default, PartialEq, PartialOrd
357
358 *   Index<usize> and IndexMut<usize>
359
360 *   IntoIterator for T, &T, &mut T
361
362 *   PartialEq of `[U;N]` and `[U]` (where T: PartialEq of U)
363
364 *   TryFrom of `&[T]`, `Vec<T, A>`, `Box<[T]>` with mut where appropriate; some times for `&[F; D]` too
365
366 *   AsRef[T], Borrow[T] (and mut for those three)
367
368 *   Serialize, Deserialize
369
370Note: Hash is not supported as f32/f64 do not support it
371
372Hence a [Vector] or [Quaternion] should provide:
373
374 *   Copy, Clone, Debug, Default, PartialEq
375
376 *   Index<usize> and IndexMut<usize>
377
378 *   Deref <Target = `[F; D]`>, DerefMut
379
380 *   AsRef and AsMut of `[F; D]`
381
382 *   From of `&[F]`, `[F;D]`,  `&[F;D]`
383
384 *   Into `[F;D]` (deref provides equivalent of &[F; D])
385
386 *   TryFrom of `&[F]`, `Vec<F>`
387
388 *   Serialize, Deserialize
389
390Note: Not PartialOrd, as vectors dont't have an ordering
391
392 Addition/Subtraction/Multiplication/Division
393
394 Add/Sub with Rhs of Self, &Self, Deref<Target = [F;D]> are
395    *required* for utility; we cannot *require* the last of these, as
396    Rust has no syntax for that.
397
398 Mul/Div with Rhs of F, &F are *required* for utility; previous
399    versions supported Self to do element-wise operations, which
400    has been removed This is in part because it would need to work
401    for Deref<Target = [F;D]>, but f32/f64 do not implement Deref,
402    and they might in the future do so which breaks the F and &F
403    operation.
404
405 Not AsRef/Mut of [F], as [F; D] implement that, and Vector gets it through Deref
406
407 Note AsRef<[F]> is implemented through Deref to [F; D]
408
409 Note AsMut<[F]> is implemented through DerefMut to [F; D]
410
411 if required, then it blocks Add<Deref<Target = [F;D]>>
412!*/
413
414//a Imports
415mod macros;
416pub(crate) use macros::{
417    convert_traits, elementwise_traits, ref_traits, scale_by_f_traits, serialize_traits,
418    unary_traits,
419};
420
421mod matrix_op;
422mod matrixr_op;
423mod quaternion_op;
424mod traits;
425mod vector_op;
426
427mod farray;
428mod farray2;
429mod fqarray;
430mod qarray;
431
432//a Exports
433pub use farray::FArray;
434pub use farray2::FArray2;
435pub use fqarray::FQArrayTrans;
436pub use qarray::QArray;
437pub use traits::{
438    Float, Geometry2D, Geometry3D, Num, Quaternion, SqMatrix, SqMatrix2, SqMatrix3, SqMatrix4,
439    Transform, Vector, Vector2, Vector3, Vector3D, Vector4,
440};
441
442/// Vector functions module
443///
444/// This module provides numerous N-dimensional vector operations operating on [Num; N] (or [Float; N]).
445pub mod vector {
446    pub use super::vector_op::*;
447}
448
449/// Quaternion module
450pub mod quat {
451    pub use super::quaternion_op::*;
452}
453
454/// Matrix library
455pub mod matrix {
456    pub use super::matrix_op::*;
457    pub use super::matrixr_op::*;
458}
459
460//a Vector3D and Geometry3D for f32/f64 using FArray/FArray2
461//ip Vector3D for f32
462impl Vector3D<f32> for f32 {
463    type Vec2 = FArray<f32, 2>;
464    type Vec3 = FArray<f32, 3>;
465    type Vec4 = FArray<f32, 4>;
466}
467
468//ip Geometry3D for f32
469impl Geometry3D<f32> for f32 {
470    type Vec3 = FArray<f32, 3>;
471    type Vec4 = FArray<f32, 4>;
472    type Mat3 = FArray2<f32, 3, 9>;
473    type Mat4 = FArray2<f32, 4, 16>;
474    type Quat = QArray<f32>;
475    type Trans = FQArrayTrans<f32>;
476}
477
478//ip Geometry2D for f32
479impl Geometry2D<f32> for f32 {
480    type Vec2 = FArray<f32, 2>;
481    type Mat2 = FArray2<f32, 2, 4>;
482}
483
484//ip Vector3D for f64
485impl Vector3D<f64> for f64 {
486    type Vec2 = FArray<f64, 2>;
487    type Vec3 = FArray<f64, 3>;
488    type Vec4 = FArray<f64, 4>;
489}
490
491//ip Geometry3D for f64
492impl Geometry3D<f64> for f64 {
493    type Vec3 = FArray<f64, 3>;
494    type Vec4 = FArray<f64, 4>;
495    type Mat3 = FArray2<f64, 3, 9>;
496    type Mat4 = FArray2<f64, 4, 16>;
497    type Quat = QArray<f64>;
498    type Trans = FQArrayTrans<f64>;
499}
500
501//ip Geometry2D for f64
502impl Geometry2D<f64> for f64 {
503    type Vec2 = FArray<f64, 2>;
504    type Mat2 = FArray2<f64, 2, 4>;
505}
506
507//a GLSL-compatible things - bit of a place holder currently
508/// The [glsl] module is a place-holder for types that are compatible with GLSL
509pub mod glsl {
510    /// GLSL 2-component vector of float
511    pub type Vec2 = [f32; 2];
512    /// GLSL 3-component vector of float
513    pub type Vec3 = [f32; 3];
514    /// GLSL 4-component vector of float
515    pub type Vec4 = [f32; 4];
516    /// GLSL 2-component vector of double
517    pub type DVec2 = [f64; 2];
518    /// GLSL 3-component vector of double
519    pub type DVec3 = [f64; 3];
520    /// GLSL 4-component vector of double
521    pub type DVec4 = [f64; 4];
522    /// GLSL 2-component vector of signed integer
523    pub type IVec2 = [i32; 2];
524    /// GLSL 3-component vector of signed integer
525    pub type IVec3 = [i32; 3];
526    /// GLSL 4-component vector of signed integer
527    pub type IVec4 = [i32; 4];
528    /// GLSL 2x2 floating-point matrix
529    pub type Mat2 = [f32; 4];
530    /// GLSL 3x3 floating-point matrix
531    pub type Mat3 = [f32; 9];
532    /// GLSL 4x4 floating-point matrix
533    pub type Mat4 = [f32; 16];
534    /// GLSL 2x2 double-precision floating-point matrix
535    pub type DMat2 = [f64; 4];
536    /// GLSL 3x3double-precision floating-point matrix
537    pub type DMat3 = [f64; 9];
538    /// GLSL 4x4 double-precision floating-point matrix
539    pub type DMat4 = [f64; 16];
540}