1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
//!
//! The prelude specifies most of the features provided by the objects of the framework.
//! This goes from math properties to array conversion and vectors concatenation.
//!

/// Construct objects either filled with ones or zeros
pub trait Initializer {
    /// Object filled with zeros
    fn zeros() -> Self;
    /// Object filled with ones
    fn ones() -> Self;
}

/// Fill an object with a value
pub trait Reset<T> {
    /// Fills an object with zeros
    fn reset0(&mut self) -> &mut Self;
    /// Fills a object with ones
    fn reset1(&mut self) -> &mut Self;

    /// Fills a object with a given value
    fn reset(&mut self, val: &T) -> &mut Self;
}

/// Set an object from an array and convert an object onto an array
pub trait Array<T> {
    /// Convert the object to array
    fn to_array(&self) -> T;
    /// Set the object from array
    fn set_array(&mut self, arr: &T) -> &mut Self;
}

/// Set an object from a vector and convert an object onto a vector
pub trait Vector<T> {
    /// Convert the object to vector
    fn to_vector(&self) -> T;
    /// Set the object from vector
    fn set_vector(&mut self, arr: &T) -> &mut Self;
}

/// Split an object onto two part that can be concatenated or accessed separately
///
/// It aims to be the upper and lower parts of a vector or the upper diagonal and lower diagonal parts of a matrix.
pub trait Split<T> {
    /// Get the two parts of the split object
    fn split(&self) -> [T; 2];
    /// Concatenates two part to construct an object
    fn concat(lhs: &T, rhs: &T) -> Self;
    /// Get the first part of the object
    fn upper(&self) -> T;
    /// Get the second part of the object
    fn lower(&self) -> T;
    /// Set the first part of the object
    fn set_upper(&mut self, val: &T) -> &mut Self;
    /// Set the second part of the object
    fn set_lower(&mut self, val: &T) -> &mut Self;
}

/// Operations between objects of a metric space
///
/// A metric space is considered as a space where it exists a norm based on dot product.
/// It can be the metric operations between two vectors or matrices such as the distance or the magnitude.
///
/// **Note :** For matrices and vectors you can also use operators : `%` for distance, `|` for dot product, `!` for magnitude
pub trait Metric where
    Self: Copy {
    /// Dot product of the two objects
    fn dot(&self, other: &Self) -> f64;
    /// Squared distance between the two objects
    fn distance2(&self, other: &Self) -> f64;
    /// Distance between the two objects
    fn distance(&self, other: &Self) -> f64;
    /// Squared magnitude of an object
    fn magnitude2(&self) -> f64;
    /// Magnitude of an object
    fn magnitude(&self) -> f64;
    /// Get the normalized vector, ie. vector with same direction and magnitude 1
    fn normalized(&self) -> Self {
        let mut ret = *self;
        ret.set_normalized();
        ret
    }
    /// Normalizes the vector, ie. sets magnitude to 1 without changing direction
    fn set_normalized(&mut self) -> &mut Self;
}

/// Operations related to the angle of two vectors
///
/// Do not use theses features with zero vector since divisions with the magnitude are performed.
pub trait Angle where
    Self: Metric {
    /// Cosine of the angle between the two vectors, non-oriented
    fn cos(&self, rhs: &Self) -> f64 {
        self.dot(rhs) / (self.magnitude() * rhs.magnitude())
    }
    /// Sine of the angle between the two vectors, non-oriented
    fn sin(&self, rhs: &Self) -> f64 {
        self.area(rhs) / (self.magnitude() * rhs.magnitude())
    }
    /// Area of the parallelepiped formed by two vectors, non-oriented
    fn area(&self, rhs: &Self) -> f64;
    /// Angle between two vectors, non-oriented
    fn angle(&self, rhs: &Self) -> f64 {
        self.cos(rhs).acos()
    }
}

/// Stable cross product of two vectors
pub trait Cross where
    Self: Copy + Clone {
    /// Get the cross product between two vectors
    fn cross(&self, rhs: &Self) -> Self {
        let mut ret = *self;
        ret.set_cross(rhs);
        ret
    }
    /// Set the cross product between two vectors
    fn set_cross(&mut self, rhs: &Self) -> &mut Self;
}

/// Interpolations between two objects
pub trait Interpolation {
    /// Get linear interpolation
    fn lerp(&self, other: &Self, s: f64) -> Self where
        Self: Copy + Clone {
        let mut ret = *self;
        ret.set_lerp(other, s);
        ret
    }
    /// Get cubic Hermite's interpolation, ie. with two tangent values
    fn herp(&mut self, other: &Self, other1: &Self, other2: &Self, s: f64) -> Self where
        Self: Copy + Clone {
        let mut ret = *self;
        ret.set_herp(other, other1, other2, s);
        ret
    }

    /// Get cubic Bezier's interpolation, ie. with two control points
    fn berp(&mut self, other: &Self, other1: &Self, other2: &Self, s: f64) -> Self where
        Self: Copy + Clone {
        let mut ret = *self;
        ret.set_berp(other, other1, other2, s);
        ret
    }

    /// Set the linear interpolation
    fn set_lerp(&mut self, other: &Self, s: f64) -> &mut Self;
    /// Set the Hermite's interpolation
    fn set_herp(&mut self, other: &Self, other1: &Self, other2: &Self, s: f64) -> &mut Self;
    /// Set the Bezier's interpolation
    fn set_berp(&mut self, other: &Self, other1: &Self, other2: &Self, s: f64) -> &mut Self;
}

/// Access the matrix as an array of rows ordered from left to right
pub trait Rows<T> where
    Self: std::marker::Sized + Initializer {
    /// Get a matrix from rows array
    fn from_rows(rows: &T) -> Self {
        let mut ret = Self::zeros();
        ret.set_rows(rows);
        ret
    }
    /// Get the rows of a matrix
    fn rows(&self) -> T;

    /// Set the rows of a matrix
    fn set_rows(&mut self, rows: &T) -> &mut Self;
}

/// Square matrices algebra
pub trait Algebra<T> where
    Self: std::marker::Sized + Copy + Clone,
    T: std::marker::Sized + Copy + Clone {
    /// Get the determinant of the matrix
    fn determinant(&self) -> f64;

    /// Get the inverse matrix
    fn inverse(&self) -> Self {
        let mut ret = *self;
        ret.set_inverse();
        ret
    }

    /// Get the transposed matrix
    fn transposed(&self) -> Self {
        let mut ret = *self;
        ret.set_transposed();
        ret
    }

    /// Get the adjugate matrix
    fn adjugate(&self) -> Self {
        let mut ret = *self;
        ret.set_adjugate();
        ret
    }

    /// Set inverse matrix
    fn set_inverse(&mut self) -> &mut Self;

    /// Set transposed matrix
    fn set_transposed(&mut self) -> &mut Self;

    /// Set adjugate matrix
    fn set_adjugate(&mut self) -> &mut Self;
}

/// Coordinates accessors
///
/// Get and Set coordinates of 2D and 3D vectors.
///
/// ## Conventions
/// A coherent naming convention between polar, cylindrical and spherical coordinates has been established.
///
/// ### Coordinates naming
/// ![coordinates](https://github.com/samiBendou/geomath/raw/dev/media/coordinates_diagram.png)
///
/// **3D coordinates representation in geomath**
///
/// The four basic coordinates systems are represented
/// * (x, y, z) the cartesian coordinates
/// * (rho, phi, z) the polar/cylindrical coordinates
/// * (r, phi, theta) the spherical coordinates
///
/// The traits are implemented such that there is no code repetition between the systems that have coordinates
/// in common. For example, since the angle phi is common to polar and spherical coordinates
/// systems it will be only defined in the `Polar` trait.
///
/// **Notes :**
///
/// * The value of phi remains the same in both polar/cylindrical and spherical coordinates systems
/// * The value of r in the schema above is denoted `radius` in the code
/// * The z coordinate is common to cartesian and cylindrical coordinates systems
///
/// ### Local basis
/// You can generate vectors of the local basis of each coordinate system, the convention is described
/// in the schemas bellow.
///
/// ![coordinates](https://github.com/samiBendou/geomath/raw/dev/media/local_%20basis_diagram.png)
///
pub mod coordinates {
    /// Polar coordinates accessors
    pub trait Polar {
        /// Get a vector from polar coordinates
        fn from_polar(rho: f64, phi: f64) -> Self;

        /// Set a vector from polar coordinates
        fn set_polar(&mut self, rho: f64, phi: f64) -> &mut Self;

        /// Get a unit polar radial vector from angle
        fn unit_rho(phi: f64) -> Self;

        /// Get a unit tangent/prograde vector from angle
        fn unit_phi(phi: f64) -> Self;

        /// Get the rho coordinate
        fn rho(&self) -> f64;

        /// Get the phi coordinate
        fn phi(&self) -> f64;

        /// Set the rho coordinate
        fn set_rho(&mut self, rho: f64) -> &mut Self;

        /// Set the phi coordinate
        fn set_phi(&mut self, phi: f64) -> &mut Self;
    }

    /// Cylindrical coordinates accessors
    pub trait Cylindrical {
        /// Get a vector from cylindrical coordinates
        fn from_cylindrical(rho: f64, phi: f64, z: f64) -> Self;

        /// Set a vector from cylindrical coordinates
        fn set_cylindrical(&mut self, rho: f64, phi: f64, z: f64) -> &mut Self;
    }

    /// Spherical coordinates accessors
    pub trait Spherical {
        /// Get a vector from spherical coordinates
        fn from_spherical(radius: f64, phi: f64, theta: f64) -> Self;
        /// Set a vector from spherical coordinates
        fn set_spherical(&mut self, radius: f64, phi: f64, theta: f64) -> &mut Self;
        /// Get a unit spherical radial vector from angles
        fn unit_radius(phi: f64, theta: f64) -> Self;
        /// Get a unit tangent/normal vector from angles
        fn unit_theta(phi: f64, theta: f64) -> Self;
        /// Get the theta coordinate
        fn theta(&self) -> f64;
        /// Set the theta coordinates
        fn set_theta(&mut self, theta: f64) -> &mut Self;
    }

    /// Homogeneous coordinates transforms
    pub trait Homogeneous<T> {
        /// Get a inhomogeneous vector from an homogeneous vector
        ///
        /// The inhomogeneous vector has the last component removed and the others
        /// divided by the value of the last component of the homogeneous vector.
        fn from_homogeneous(vector: &T) -> Self;

        /// Get a vector transformed to an homogeneous vector
        ///
        /// It is the same vector but with a component with the value 1 added.
        fn to_homogeneous(&self) -> T;
    }
}

/// Transform matrix
///
/// Set and generate transform matrices.
/// The transform matrices can represent common 2D and 3D geometrical operations such as translation, rotation, ...
pub mod transforms {
    use crate::prelude::Initializer;
    use crate::vector::Vector3;

    /// Translation matrix
    pub trait Translation<T> where
        Self: std::marker::Sized + Copy + Clone + Initializer {
        /// Get a translation matrix from translation vector
        fn from_translation(vector: &T) -> Self {
            let mut ret = Self::zeros();
            ret.set_translation(vector);
            ret
        }

        /// Set a translation matrix from translation vector
        fn set_translation(&mut self, vector: &T) -> &mut Self;
    }

    /// Rigid body matrix
    ///
    /// A rigid body transform is the combination of a rotation and a translation.
    pub trait Rigid<U, T> where
        Self: std::marker::Sized + Copy + Clone + Initializer {
        /// Get a rigid body matrix from rotation matrix and translation vector
        fn from_rigid(rotation: &U, vector: &T) -> Self {
            let mut ret = Self::zeros();
            ret.set_rigid(rotation, vector);
            ret
        }

        /// Set a rigid body matrix from the given rotation matrix and translation vector
        fn set_rigid(&mut self, rotation: &U, vector: &T) -> &mut Self;
    }

    /// Similarity matrix
    ///
    /// A similarity is the combination of a scaling, a rotation and a translation.
    pub trait Similarity<U, T> where
        Self: std::marker::Sized + Copy + Clone + Initializer {
        /// Get a similarity matrix from scale factor, rotation matrix and translation vector
        fn from_similarity(scale: f64, rotation: &U, vector: &T) -> Self {
            let mut ret = Self::zeros();
            ret.set_similarity(scale, rotation, vector);
            ret
        }

        /// Set a similarity matrix from scale factor, rotation matrix and translation vector
        fn set_similarity(&mut self, scale: f64, rotation: &U, vector: &T) -> &mut Self;
    }

    /// 2D rotations matrix
    pub trait Rotation2 where
        Self: std::marker::Sized + Copy + Clone + Initializer {
        /// Get a rotation matrix from angle
        fn from_rotation(angle: f64) -> Self {
            let mut ret = Self::zeros();
            ret.set_rotation(angle);
            ret
        }

        /// Set a rotation matrix from angle
        fn set_rotation(&mut self, angle: f64) -> &mut Self;
    }

    /// 3D rotations matrix
    pub trait Rotation3 where
        Self: std::marker::Sized + Copy + Clone + Initializer {
        /// Get a rotation matrix from axis and angle
        fn from_rotation(angle: f64, axis: &Vector3) -> Self {
            let mut ret = Self::zeros();
            ret.set_rotation(angle, axis);
            ret
        }

        /// Get a rotation matrix around x-axis from given angle
        fn from_rotation_x(angle: f64) -> Self {
            let mut ret = Self::zeros();
            ret.set_rotation_x(angle);
            ret
        }

        /// Get a rotation matrix around y-axis from given angle
        fn from_rotation_y(angle: f64) -> Self {
            let mut ret = Self::zeros();
            ret.set_rotation_y(angle);
            ret
        }

        /// Get a rotation matrix around z-axis from given angle
        fn from_rotation_z(angle: f64) -> Self {
            let mut ret = Self::zeros();
            ret.set_rotation_z(angle);
            ret
        }

        /// Set a rotation matrix from axis and angle
        fn set_rotation(&mut self, angle: f64, axis: &Vector3) -> &mut Self;

        /// Set a rotation matrix around x-axis from given angle
        fn set_rotation_x(&mut self, angle: f64) -> &mut Self;

        /// Set a rotation matrix around y-axis from given angle
        fn set_rotation_y(&mut self, angle: f64) -> &mut Self;

        /// Set a rotation matrix around z-axis from given angle
        fn set_rotation_z(&mut self, angle: f64) -> &mut Self;
    }
}