matmath/
game.rs

1use matrix::{Matrix, MatrixElement};
2use std::cmp::PartialOrd;
3use std::convert::{From, Into};
4use std::fmt::{Display, Formatter, Result};
5use std::ops::{Add, Div, Mul, Neg, Sub};
6use vector::Vector;
7
8/// A Vector class that has specifically 2 dimensions, never more or less
9pub mod vec2 {
10    use super::vec3::Vector3;
11    use super::*;
12
13    #[derive(Debug, Clone, PartialEq, Eq)]
14    pub struct Vector2<T> {
15        pub x: T,
16        pub y: T,
17    }
18
19    impl<T> Vector2<T> {
20        pub fn new(x: T, y: T) -> Self {
21            Self { x, y }
22        }
23
24        /// Multiplies the vector with a scalar
25        pub fn scaled<U, O>(self, scalar: U) -> Vector2<O>
26        where
27            T: Mul<U, Output = O>,
28            U: Clone,
29        {
30            self.map(|x| x * scalar.clone())
31        }
32
33        pub(crate) fn zip<U>(self, rhs: Vector2<U>) -> Vector2<(T, U)> {
34            ((self.x, rhs.x), (self.y, rhs.y)).into()
35        }
36
37        /// Creates a `Vector3` where the `z` coordinate is 1. For more info, see [Homogeneous Coordinates](https://en.wikipedia.org/wiki/Homogeneous_coordinates)
38        pub fn homogenous(self) -> Vector3<T>
39        where
40            T: MatrixElement,
41        {
42            (self.x, self.y, T::one()).into()
43        }
44
45        /// Applies a function to every element of the vector
46        pub fn map<F: Fn(T) -> U, U>(self, f: F) -> Vector2<U> {
47            Vector2::new(f(self.x), f(self.y))
48        }
49    }
50
51    impl<T: Display> Display for Vector2<T> {
52        fn fmt(&self, f: &mut Formatter) -> Result {
53            write!(f, "Vector2({}, {})", self.x, self.y)
54        }
55    }
56
57    /// A Vector can be cast to a matrix and back
58    impl<T> Into<Matrix<T>> for Vector2<T> {
59        fn into(self) -> Matrix<T> {
60            Matrix::from_vec(2, 1, vec![self.x, self.y]).unwrap()
61        }
62    }
63
64    /// A Vector can be cast to a matrix and back
65    impl<T> From<Matrix<T>> for Vector2<T> {
66        fn from(mat: Matrix<T>) -> Self {
67            let (rows, cols, mut data) = mat.split();
68            assert_eq!(cols, 1, "dimensions don't match");
69            assert_eq!(rows, 2, "dimensions don't match");
70            let y = data.pop().unwrap();
71            let x = data.pop().unwrap();
72
73            Self { x, y }
74        }
75    }
76
77    impl<T> Into<Vector<T>> for Vector2<T> {
78        fn into(self) -> Vector<T> {
79            Vector::new(vec![self.x, self.y])
80        }
81    }
82
83    impl<T> From<Vector<T>> for Vector2<T> {
84        fn from(mut vec: Vector<T>) -> Self {
85            let dim = vec.dim();
86            assert_eq!(dim, 2, "dimensions don't match");
87            let y = vec.data.pop().unwrap();
88            let x = vec.data.pop().unwrap();
89            Self { x, y }
90        }
91    }
92
93    impl<T> Into<(T, T)> for Vector2<T> {
94        fn into(self) -> (T, T) {
95            (self.x, self.y)
96        }
97    }
98
99    impl<T> From<(T, T)> for Vector2<T> {
100        fn from(t: (T, T)) -> Self {
101            Self { x: t.0, y: t.1 }
102        }
103    }
104
105    /// Adds two vectors element by element
106    impl<T, U, O> Add<Vector2<U>> for Vector2<T>
107    where
108        T: Add<U, Output = O>,
109    {
110        type Output = Vector2<O>;
111
112        fn add(self, rhs: Vector2<U>) -> Vector2<O> {
113            self.zip(rhs).map(|(a, b)| a + b)
114        }
115    }
116
117    /// Subtracts two vectors element by element
118    impl<T, U, O> Sub<Vector2<U>> for Vector2<T>
119    where
120        T: Sub<U, Output = O>,
121    {
122        type Output = Vector2<O>;
123
124        fn sub(self, rhs: Vector2<U>) -> Vector2<O> {
125            self.zip(rhs).map(|(a, b)| a - b)
126        }
127    }
128
129    impl<T, O> Neg for Vector2<T>
130    where
131        T: Neg<Output = O>,
132    {
133        type Output = Vector2<O>;
134
135        fn neg(self) -> Vector2<O> {
136            self.map(|x| x.neg())
137        }
138    }
139}
140
141/// A Vector class that has specifically 3 dimensions, never more or less. It also has a `cross_product` method
142pub mod vec3 {
143    use super::vec4::Vector4;
144    use super::*;
145
146    #[derive(Debug, Clone, PartialEq, Eq)]
147    pub struct Vector3<T> {
148        pub x: T,
149        pub y: T,
150        pub z: T,
151    }
152
153    impl<T> Vector3<T> {
154        pub fn new(x: T, y: T, z: T) -> Self {
155            Self { x, y, z }
156        }
157
158        /// Multiplies the vector with a scalar
159        pub fn scaled<U, O>(self, scalar: U) -> Vector3<O>
160        where
161            T: Mul<U, Output = O>,
162            U: Clone,
163        {
164            self.map(|x| x * scalar.clone())
165        }
166
167        pub fn cross_product<U, O>(self, other: Vector3<U>) -> Vector3<O>
168        where
169            T: Mul<U, Output = O> + Clone,
170            U: Clone,
171            O: Sub<Output = O>,
172        {
173            let (u1, u2, u3): (T, T, T) = self.into();
174            let (v1, v2, v3): (U, U, U) = other.into();
175            let (uu1, uu2, uu3, vv1, vv2, vv3) = (
176                u1.clone(),
177                u2.clone(),
178                u3.clone(),
179                v1.clone(),
180                v2.clone(),
181                v3.clone(),
182            );
183            let s1 = uu2 * vv3 - uu3 * vv2;
184            let s2 = u3 * vv1 - uu1 * v3;
185            let s3 = u1 * v2 - u2 * v1;
186            (s1, s2, s3).into()
187        }
188
189        /// Creates a `Vector4` where the `w` coordinate is 1. For more info, see [Homogeneous Coordinates](https://en.wikipedia.org/wiki/Homogeneous_coordinates)
190        pub fn homogenous(self) -> Vector4<T>
191        where
192            T: MatrixElement,
193        {
194            (self.x, self.y, self.z, T::one()).into()
195        }
196
197        /// Normalizes `self` so the `z` coordinate is 1. For more info, see [Homogeneous Coordinates](https://en.wikipedia.org/wiki/Homogeneous_coordinates)
198        pub fn normalize_homogeneous(self) -> Vector3<T>
199        where
200            T: Div<Output = T> + Clone + MatrixElement,
201        {
202            (self.x / self.z.clone(), self.y / self.z, T::one()).into()
203        }
204
205        pub(crate) fn zip<U>(self, rhs: Vector3<U>) -> Vector3<(T, U)> {
206            ((self.x, rhs.x), (self.y, rhs.y), (self.z, rhs.z)).into()
207        }
208
209        /// Applies a function to every element of the vector
210        pub fn map<F, U>(self, f: F) -> Vector3<U>
211        where
212            F: Fn(T) -> U,
213        {
214            Vector3::new(f(self.x), f(self.y), f(self.z))
215        }
216    }
217
218    impl<T> Display for Vector3<T>
219    where
220        T: Display + Clone,
221    {
222        fn fmt(&self, f: &mut Formatter) -> Result {
223            write!(f, "Vector3({}, {}, {})", self.x, self.y, self.z)
224        }
225    }
226
227    impl<T> Into<Matrix<T>> for Vector3<T> {
228        fn into(self) -> Matrix<T> {
229            Matrix::from_vec(3, 1, vec![self.x, self.y, self.z]).unwrap()
230        }
231    }
232
233    impl<T> From<Matrix<T>> for Vector3<T>
234    where
235        T: Clone,
236    {
237        fn from(mat: Matrix<T>) -> Self {
238            let (rows, cols, mut data) = mat.split();
239            assert_eq!(cols, 1, "dimensions don't match");
240            assert_eq!(rows, 3, "dimensions don't match");
241            let z = data.pop().unwrap();
242            let y = data.pop().unwrap();
243            let x = data.pop().unwrap();
244
245            Self { x, y, z }
246        }
247    }
248
249    impl<T> Into<Vector<T>> for Vector3<T> {
250        fn into(self) -> Vector<T> {
251            Vector::new(vec![self.x, self.y, self.z])
252        }
253    }
254
255    impl<T> From<Vector<T>> for Vector3<T> {
256        fn from(mut vec: Vector<T>) -> Self {
257            let dim = vec.dim();
258            assert_eq!(dim, 3, "dimensions don't match");
259            let z = vec.data.pop().unwrap();
260            let y = vec.data.pop().unwrap();
261            let x = vec.data.pop().unwrap();
262            Self { x, y, z }
263        }
264    }
265
266    impl<T> Into<(T, T, T)> for Vector3<T> {
267        fn into(self) -> (T, T, T) {
268            (self.x, self.y, self.z)
269        }
270    }
271
272    impl<T> From<(T, T, T)> for Vector3<T> {
273        fn from(t: (T, T, T)) -> Self {
274            Self {
275                x: t.0,
276                y: t.1,
277                z: t.2,
278            }
279        }
280    }
281
282    /// Adds two vectors element by element
283    impl<T, U, O> Add<Vector3<U>> for Vector3<T>
284    where
285        T: Add<U, Output = O>,
286    {
287        type Output = Vector3<O>;
288
289        fn add(self, rhs: Vector3<U>) -> Vector3<O> {
290            self.zip(rhs).map(|(a, b)| a + b)
291        }
292    }
293
294    /// Subtracts two vectors element by element
295    impl<T, U, O> Sub<Vector3<U>> for Vector3<T>
296    where
297        T: Sub<U, Output = O>,
298    {
299        type Output = Vector3<O>;
300
301        fn sub(self, rhs: Vector3<U>) -> Vector3<O> {
302            self.zip(rhs).map(|(a, b)| a - b)
303        }
304    }
305
306    impl<T, O> Neg for Vector3<T>
307    where
308        T: Neg<Output = O>,
309    {
310        type Output = Vector3<O>;
311
312        fn neg(self) -> Vector3<O> {
313            self.map(|x| x.neg())
314        }
315    }
316}
317
318/// A Vector class that has specifically 4 dimensions, never more or less
319pub mod vec4 {
320    use super::*;
321
322    #[derive(Debug, Clone, PartialEq, Eq)]
323    pub struct Vector4<T> {
324        pub x: T,
325        pub y: T,
326        pub z: T,
327        pub w: T,
328    }
329
330    impl<T> Vector4<T> {
331        pub fn new(x: T, y: T, z: T, w: T) -> Self {
332            Self { x, y, z, w }
333        }
334
335        /// Multiplies the vector with a scalar
336        pub fn scaled<U, O>(self, scalar: U) -> Vector4<O>
337        where
338            T: Mul<U, Output = O>,
339            U: Clone,
340        {
341            self.map(|x| x * scalar.clone())
342        }
343
344        /// Normalizes `self` so the `w` coordinate is 1. For more info, see [Homogeneous Coordinates](https://en.wikipedia.org/wiki/Homogeneous_coordinates)
345        pub fn normalize_homogeneous(self) -> Vector4<T>
346        where
347            T: Div<Output = T> + Clone + MatrixElement,
348        {
349            (
350                self.x / self.w.clone(),
351                self.y / self.w.clone(),
352                self.z / self.w,
353                T::one(),
354            )
355                .into()
356        }
357
358        pub(crate) fn zip<U>(self, rhs: Vector4<U>) -> Vector4<(T, U)> {
359            (
360                (self.x, rhs.x),
361                (self.y, rhs.y),
362                (self.z, rhs.z),
363                (self.w, rhs.w),
364            )
365                .into()
366        }
367
368        /// Applies a function to every element of the vector
369        pub fn map<F, U>(self, f: F) -> Vector4<U>
370        where
371            F: Fn(T) -> U,
372        {
373            Vector4::new(f(self.x), f(self.y), f(self.z), f(self.w))
374        }
375    }
376
377    impl<T> Display for Vector4<T>
378    where
379        T: Display + Clone,
380    {
381        fn fmt(&self, f: &mut Formatter) -> Result {
382            write!(f, "Vector4({}, {}, {}, {})", self.x, self.y, self.z, self.w)
383        }
384    }
385
386    impl<T> Into<Matrix<T>> for Vector4<T> {
387        fn into(self) -> Matrix<T> {
388            Matrix::from_vec(4, 1, vec![self.x, self.y, self.z, self.w]).unwrap()
389        }
390    }
391
392    impl<T> From<Matrix<T>> for Vector4<T>
393    where
394        T: Clone,
395    {
396        fn from(mat: Matrix<T>) -> Self {
397            let (rows, cols, data) = mat.split();
398            assert_eq!(cols, 1, "dimensions don't match");
399            assert_eq!(rows, 4, "dimensions don't match");
400            Self {
401                x: data[0].clone(),
402                y: data[1].clone(),
403                z: data[2].clone(),
404                w: data[3].clone(),
405            }
406        }
407    }
408
409    impl<T> Into<Vector<T>> for Vector4<T> {
410        fn into(self) -> Vector<T> {
411            Vector::new(vec![self.x, self.y, self.z, self.w])
412        }
413    }
414
415    impl<T> From<Vector<T>> for Vector4<T> {
416        fn from(mut vec: Vector<T>) -> Self {
417            let dim = vec.dim();
418            assert_eq!(dim, 4, "dimensions don't match");
419            let w = vec.data.pop().unwrap();
420            let z = vec.data.pop().unwrap();
421            let y = vec.data.pop().unwrap();
422            let x = vec.data.pop().unwrap();
423            Self { x, y, z, w }
424        }
425    }
426
427    impl<T> Into<(T, T, T, T)> for Vector4<T> {
428        fn into(self) -> (T, T, T, T) {
429            (self.x, self.y, self.z, self.w)
430        }
431    }
432
433    impl<T> From<(T, T, T, T)> for Vector4<T> {
434        fn from(t: (T, T, T, T)) -> Self {
435            Self {
436                x: t.0,
437                y: t.1,
438                z: t.2,
439                w: t.3,
440            }
441        }
442    }
443
444    /// Adds two vectors element by element
445    impl<T, U, O> Add<Vector4<U>> for Vector4<T>
446    where
447        T: Add<U, Output = O>,
448    {
449        type Output = Vector4<O>;
450
451        fn add(self, rhs: Vector4<U>) -> Vector4<O> {
452            self.zip(rhs).map(|(a, b)| a + b)
453        }
454    }
455
456    /// Subtracts two vectors element by element
457    impl<T, U, O> Sub<Vector4<U>> for Vector4<T>
458    where
459        T: Sub<U, Output = O>,
460    {
461        type Output = Vector4<O>;
462
463        fn sub(self, rhs: Vector4<U>) -> Vector4<O> {
464            self.zip(rhs).map(|(a, b)| a - b)
465        }
466    }
467
468    impl<T, O> Neg for Vector4<T>
469    where
470        T: Neg<Output = O>,
471    {
472        type Output = Vector4<O>;
473
474        fn neg(self) -> Vector4<O> {
475            self.map(|x| x.neg())
476        }
477    }
478}
479
480pub type Vector2f = self::vec2::Vector2<f64>;
481pub type Vector3f = self::vec3::Vector3<f64>;
482pub type Vector4f = self::vec4::Vector4<f64>;
483
484/// A 3D Camera Object that automatically projects vectors
485pub mod cam3d {
486    use super::vec2::Vector2;
487    use super::vec3::Vector3;
488    use super::*;
489    use special_matrices::misc;
490    use special_matrices::rotation::Trig;
491
492    /// A 3d Camera using transformation matrices (**BEWARE** this is not tested and maynot work correctly)
493    ///
494    /// In Camera space, z is forward, x is left, y is up
495    pub struct Cam3d<T> {
496        pub pos: Vector3<T>,
497        pub rot: Vector3<T>,
498        pub focal_length: T,
499    }
500
501    impl<T> Cam3d<T> {
502        pub fn new(pos: (T, T, T), rot: (T, T, T), focal_length: T) -> Self {
503            Self {
504                pos: pos.into(),
505                rot: rot.into(),
506                focal_length,
507            }
508        }
509
510        fn undo_camera_rot(&self, v: Vector3<T>) -> Vector3<T>
511        where
512            T: Clone
513                + Neg<Output = T>
514                + Trig<Output = T>
515                + Add<Output = T>
516                + Sub<Output = T>
517                + Mul<Output = T>
518                + MatrixElement,
519        {
520            let (rx, ry, rz) = self.rot.clone().into();
521            let rmx = misc::rotmat3x().insert_rotation_value(-rx);
522            let rmy = misc::rotmat3y().insert_rotation_value(-ry);
523            let rmz = misc::rotmat3z().insert_rotation_value(-rz);
524            let rm = rmx * rmy * rmz;
525
526            let vec: Vector<T> = v.into();
527            let res = rm * vec;
528            res.into()
529        }
530
531        fn apply_camera_rot(&self, v: Vector3<T>) -> Vector3<T>
532        where
533            T: Clone
534                + Neg<Output = T>
535                + Trig<Output = T>
536                + Add<Output = T>
537                + Sub<Output = T>
538                + Mul<Output = T>
539                + MatrixElement,
540        {
541            let (rx, ry, rz) = self.rot.clone().into();
542            let rmx = misc::rotmat3x().insert_rotation_value(rx);
543            let rmy = misc::rotmat3y().insert_rotation_value(ry);
544            let rmz = misc::rotmat3z().insert_rotation_value(rz);
545            let rm = rmx * rmy * rmz;
546
547            let vec: Vector<T> = v.into();
548            let res = rm * vec;
549            res.into()
550        }
551
552        fn undo_camera_pos(&self, v: Vector3<T>) -> Vector3<T>
553        where
554            T: Clone + Sub<Output = T>,
555        {
556            v - self.pos.clone()
557        }
558
559        /// performs a perspective Projection on `v` using the current position, rotation and focal length, returns `Err` if the `v` is behind the camera (-z direction)
560        pub fn project(&self, v: Vector3<T>) -> ::std::result::Result<Vector2<T>, Vector2<T>>
561        where
562            T: Clone
563                + Neg<Output = T>
564                + Trig<Output = T>
565                + Add<Output = T>
566                + Sub<Output = T>
567                + Mul<Output = T>
568                + MatrixElement
569                + Div<Output = T>
570                + PartialOrd,
571        {
572            // great visual understanding: https://en.wikipedia.org/wiki/3D_projection#Diagram
573            // also: http://www.scratchapixel.com/lessons/3d-basic-rendering/computing-pixel-coordinates-of-3d-point/mathematics-computing-2d-coordinates-of-3d-points
574            let (x, y, z) = self.undo_camera_rot(self.undo_camera_pos(v)).into();
575            let f = self.focal_length.clone();
576            let m = f / z.clone();
577            let bx = m.clone() * x;
578            let by = m * -y;
579            if z > T::zero() {
580                Ok(Vector2::new(bx, by))
581            } else {
582                Err(Vector2::new(bx, by))
583            }
584        }
585
586        /// Move the Camera to v in global space
587        pub fn move_to(&mut self, v: Vector3<T>)
588        where
589            T: Add<Output = T> + Clone,
590        {
591            self.pos = v;
592        }
593
594        /// Set the Camera's rotation vector to v in global space
595        pub fn rotate_to(&mut self, v: Vector3<T>)
596        where
597            T: Add<Output = T> + Clone,
598        {
599            self.rot = v;
600        }
601
602        // TODO: get local x,y,z => rotate around those for local rotation
603
604        /// Move the Camera by v in camera space
605        pub fn move_local(&mut self, v: Vector3<T>)
606        where
607            T: Clone
608                + Neg<Output = T>
609                + Trig<Output = T>
610                + Add<Output = T>
611                + Sub<Output = T>
612                + Mul<Output = T>
613                + MatrixElement,
614        {
615            let v_in_global_space = self.apply_camera_rot(v) + self.pos.clone();
616            self.move_to(v_in_global_space);
617        }
618
619        /// Rotate the Camera by v in camera space
620        pub fn rotate_local(&mut self, v: Vector3<T>)
621        where
622            T: Clone
623                + Neg<Output = T>
624                + Trig<Output = T>
625                + Add<Output = T>
626                + Sub<Output = T>
627                + Mul<Output = T>
628                + MatrixElement,
629        {
630            let v_in_global_space = self.apply_camera_rot(v) + self.pos.clone();
631            self.rotate_to(v_in_global_space);
632        }
633    }
634}