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}