ruby_math/algebra/mat/
mat4d.rs

1#![allow(dead_code)]
2
3use std::{
4    fmt::Display,
5    ops::{Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Sub, SubAssign},
6};
7
8use crate::algebra::{vec4d, Mat2d, Mat3d, Mat4f, Vec3d, Vec4d};
9
10#[derive(Clone, Copy, PartialEq, Debug)]
11pub struct Mat4d {
12    x_axis: Vec4d,
13    y_axis: Vec4d,
14    z_axis: Vec4d,
15    w_axis: Vec4d,
16}
17
18pub fn mat4d(
19    m00: f64,
20    m01: f64,
21    m02: f64,
22    m03: f64,
23    m10: f64,
24    m11: f64,
25    m12: f64,
26    m13: f64,
27    m20: f64,
28    m21: f64,
29    m22: f64,
30    m23: f64,
31    m30: f64,
32    m31: f64,
33    m32: f64,
34    m33: f64,
35) -> Mat4d {
36    Mat4d::from_array([
37        m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33,
38    ])
39}
40
41impl Display for Mat4d {
42    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
43        let (m00, m01, m02, m03) = self.x_axis.to_tuple();
44        let (m10, m11, m12, m13) = self.y_axis.to_tuple();
45        let (m20, m21, m22, m23) = self.z_axis.to_tuple();
46        let (m30, m31, m32, m33) = self.w_axis.to_tuple();
47        write!(
48            f,
49            "Mat4d({}, {}, {}, {} | {}, {}, {}, {} | {}, {}, {}, {} | {}, {}, {}, {})",
50            m00, m01, m02, m03, m10, m11, m12, m13, m20, m21, m22, m23, m30, m31, m32, m33
51        )
52    }
53}
54
55impl Default for Mat4d {
56    fn default() -> Self {
57        Self {
58            x_axis: Vec4d::default(),
59            y_axis: Vec4d::default(),
60            z_axis: Vec4d::default(),
61            w_axis: Vec4d::default(),
62        }
63    }
64}
65
66impl Add<Mat4d> for Mat4d {
67    type Output = Mat4d;
68
69    fn add(self, rhs: Mat4d) -> Self::Output {
70        Mat4d::new(
71            self.x_axis + rhs.x_axis,
72            self.y_axis + rhs.y_axis,
73            self.z_axis + rhs.z_axis,
74            self.w_axis + rhs.w_axis,
75        )
76    }
77}
78
79impl Add<f64> for Mat4d {
80    type Output = Mat4d;
81
82    fn add(self, rhs: f64) -> Self::Output {
83        Mat4d::new(
84            self.x_axis + rhs,
85            self.y_axis + rhs,
86            self.z_axis + rhs,
87            self.w_axis + rhs,
88        )
89    }
90}
91
92impl Add<Mat4d> for f64 {
93    type Output = Mat4d;
94
95    fn add(self, rhs: Mat4d) -> Self::Output {
96        Mat4d::new(
97            self + rhs.x_axis,
98            self + rhs.y_axis,
99            self + rhs.z_axis,
100            self + rhs.w_axis,
101        )
102    }
103}
104
105impl AddAssign<Mat4d> for Mat4d {
106    fn add_assign(&mut self, rhs: Mat4d) {
107        *self = *self + rhs;
108    }
109}
110
111impl AddAssign<f64> for Mat4d {
112    fn add_assign(&mut self, rhs: f64) {
113        *self = *self + rhs;
114    }
115}
116
117impl Sub<Mat4d> for Mat4d {
118    type Output = Mat4d;
119
120    fn sub(self, rhs: Mat4d) -> Self::Output {
121        Mat4d::new(
122            self.x_axis - rhs.x_axis,
123            self.y_axis - rhs.y_axis,
124            self.z_axis - rhs.z_axis,
125            self.w_axis - rhs.w_axis,
126        )
127    }
128}
129
130impl Sub<f64> for Mat4d {
131    type Output = Mat4d;
132
133    fn sub(self, rhs: f64) -> Self::Output {
134        Mat4d::new(
135            self.x_axis - rhs,
136            self.y_axis - rhs,
137            self.z_axis - rhs,
138            self.w_axis - rhs,
139        )
140    }
141}
142
143impl Sub<Mat4d> for f64 {
144    type Output = Mat4d;
145
146    fn sub(self, rhs: Mat4d) -> Self::Output {
147        Mat4d::new(
148            self - rhs.x_axis,
149            self - rhs.y_axis,
150            self - rhs.z_axis,
151            self - rhs.w_axis,
152        )
153    }
154}
155
156impl SubAssign<Mat4d> for Mat4d {
157    fn sub_assign(&mut self, rhs: Mat4d) {
158        *self = *self - rhs;
159    }
160}
161
162impl SubAssign<f64> for Mat4d {
163    fn sub_assign(&mut self, rhs: f64) {
164        *self = *self - rhs;
165    }
166}
167
168impl Mul<Mat4d> for Mat4d {
169    type Output = Mat4d;
170
171    fn mul(self, rhs: Mat4d) -> Self::Output {
172        let m00 = self
173            .x_axis
174            .dot(vec4d(rhs[0][0], rhs[1][0], rhs[2][0], rhs[3][0]));
175        let m01 = self
176            .x_axis
177            .dot(vec4d(rhs[0][1], rhs[1][1], rhs[2][1], rhs[3][1]));
178        let m02 = self
179            .x_axis
180            .dot(vec4d(rhs[0][2], rhs[1][2], rhs[2][2], rhs[3][2]));
181        let m03 = self
182            .x_axis
183            .dot(vec4d(rhs[0][3], rhs[1][3], rhs[2][3], rhs[3][3]));
184
185        let m10 = self
186            .y_axis
187            .dot(vec4d(rhs[0][0], rhs[1][0], rhs[2][0], rhs[3][0]));
188        let m11 = self
189            .y_axis
190            .dot(vec4d(rhs[0][1], rhs[1][1], rhs[2][1], rhs[3][1]));
191        let m12 = self
192            .y_axis
193            .dot(vec4d(rhs[0][2], rhs[1][2], rhs[2][2], rhs[3][2]));
194        let m13 = self
195            .y_axis
196            .dot(vec4d(rhs[0][3], rhs[1][3], rhs[2][3], rhs[3][3]));
197
198        let m20 = self
199            .z_axis
200            .dot(vec4d(rhs[0][0], rhs[1][0], rhs[2][0], rhs[3][0]));
201        let m21 = self
202            .z_axis
203            .dot(vec4d(rhs[0][1], rhs[1][1], rhs[2][1], rhs[3][1]));
204        let m22 = self
205            .z_axis
206            .dot(vec4d(rhs[0][2], rhs[1][2], rhs[2][2], rhs[3][2]));
207        let m23 = self
208            .z_axis
209            .dot(vec4d(rhs[0][3], rhs[1][3], rhs[2][3], rhs[3][3]));
210
211        let m30 = self
212            .w_axis
213            .dot(vec4d(rhs[0][0], rhs[1][0], rhs[2][0], rhs[3][0]));
214        let m31 = self
215            .w_axis
216            .dot(vec4d(rhs[0][1], rhs[1][1], rhs[2][1], rhs[3][1]));
217        let m32 = self
218            .w_axis
219            .dot(vec4d(rhs[0][2], rhs[1][2], rhs[2][2], rhs[3][2]));
220        let m33 = self
221            .w_axis
222            .dot(vec4d(rhs[0][3], rhs[1][3], rhs[2][3], rhs[3][3]));
223
224        Mat4d::new(
225            vec4d(m00, m01, m02, m03),
226            vec4d(m10, m11, m12, m13),
227            vec4d(m20, m21, m22, m23),
228            vec4d(m30, m31, m32, m33),
229        )
230    }
231}
232
233impl Mul<Vec4d> for Mat4d {
234    type Output = Vec4d;
235
236    fn mul(self, rhs: Vec4d) -> Self::Output {
237        let v0 = self.x_axis.dot(rhs);
238        let v1 = self.y_axis.dot(rhs);
239        let v2 = self.z_axis.dot(rhs);
240        let v3 = self.w_axis.dot(rhs);
241        vec4d(v0, v1, v2, v3)
242    }
243}
244
245impl Mul<f64> for Mat4d {
246    type Output = Mat4d;
247
248    fn mul(self, rhs: f64) -> Self::Output {
249        Mat4d::new(
250            self.x_axis * rhs,
251            self.y_axis * rhs,
252            self.z_axis * rhs,
253            self.w_axis * rhs,
254        )
255    }
256}
257
258impl Mul<Mat4d> for f64 {
259    type Output = Mat4d;
260
261    fn mul(self, rhs: Mat4d) -> Self::Output {
262        Mat4d::new(
263            self * rhs.x_axis,
264            self * rhs.y_axis,
265            self * rhs.z_axis,
266            self * rhs.w_axis,
267        )
268    }
269}
270
271impl MulAssign<Mat4d> for Mat4d {
272    fn mul_assign(&mut self, rhs: Mat4d) {
273        *self = *self * rhs;
274    }
275}
276
277impl MulAssign<f64> for Mat4d {
278    fn mul_assign(&mut self, rhs: f64) {
279        *self = *self * rhs;
280    }
281}
282
283impl Div<f64> for Mat4d {
284    type Output = Mat4d;
285
286    fn div(self, rhs: f64) -> Self::Output {
287        Mat4d::new(
288            self.x_axis / rhs,
289            self.y_axis / rhs,
290            self.z_axis / rhs,
291            self.w_axis / rhs,
292        )
293    }
294}
295
296impl DivAssign<f64> for Mat4d {
297    fn div_assign(&mut self, rhs: f64) {
298        *self = *self / rhs;
299    }
300}
301
302impl Index<usize> for Mat4d {
303    type Output = Vec4d;
304
305    fn index(&self, index: usize) -> &Self::Output {
306        match index {
307            0 => &self.x_axis,
308            1 => &self.y_axis,
309            2 => &self.z_axis,
310            3 => &self.w_axis,
311            _ => panic!("`rmath::algebra::Mat4d::index`: index out of bounds."),
312        }
313    }
314}
315
316impl IndexMut<usize> for Mat4d {
317    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
318        match index {
319            0 => &mut self.x_axis,
320            1 => &mut self.y_axis,
321            2 => &mut self.z_axis,
322            3 => &mut self.w_axis,
323            _ => panic!("`rmath::algebra::Mat4d::index_mut`: index out of bounds."),
324        }
325    }
326}
327
328impl Mat4d {
329    pub fn new(x_axis: Vec4d, y_axis: Vec4d, z_axis: Vec4d, w_axis: Vec4d) -> Self {
330        Self {
331            x_axis,
332            y_axis,
333            z_axis,
334            w_axis,
335        }
336    }
337
338    pub fn zero() -> Self {
339        Self::new(
340            vec4d(0.0, 0.0, 0.0, 0.0),
341            vec4d(0.0, 0.0, 0.0, 0.0),
342            vec4d(0.0, 0.0, 0.0, 0.0),
343            vec4d(0.0, 0.0, 0.0, 0.0),
344        )
345    }
346
347    pub fn identity() -> Self {
348        Self::new(
349            vec4d(1.0, 0.0, 0.0, 0.0),
350            vec4d(0.0, 1.0, 0.0, 0.0),
351            vec4d(0.0, 0.0, 1.0, 0.0),
352            vec4d(0.0, 0.0, 0.0, 1.0),
353        )
354    }
355}
356
357impl Mat4d {
358    pub fn col(&self, index: usize) -> Vec4d {
359        match index {
360            0 => vec4d(self[0][0], self[1][0], self[2][0], self[3][0]),
361            1 => vec4d(self[0][1], self[1][1], self[2][1], self[3][1]),
362            2 => vec4d(self[0][2], self[1][2], self[2][2], self[3][2]),
363            3 => vec4d(self[0][3], self[1][3], self[2][3], self[3][3]),
364            _ => panic!("`rmath::algebra::Mat4d::col`: index out of bounds."),
365        }
366    }
367
368    pub fn row(&self, index: usize) -> Vec4d {
369        match index {
370            0 => self.x_axis,
371            1 => self.y_axis,
372            2 => self.z_axis,
373            3 => self.w_axis,
374            _ => panic!("`rmath::algebra::Mat4d::row`: index out of bounds."),
375        }
376    }
377
378    pub fn is_nan(&self) -> bool {
379        self.x_axis.is_nan() || self.y_axis.is_nan() || self.z_axis.is_nan() || self.w_axis.is_nan()
380    }
381
382    pub fn is_infinite(&self) -> bool {
383        self.x_axis.is_infinite()
384            || self.y_axis.is_infinite()
385            || self.z_axis.is_infinite()
386            || self.z_axis.is_infinite()
387    }
388
389    pub fn is_finite(&self) -> bool {
390        self.x_axis.is_finite()
391            && self.y_axis.is_finite()
392            && self.z_axis.is_finite()
393            && self.w_axis.is_finite()
394    }
395
396    pub fn transpose(&self) -> Self {
397        let (m00, m01, m02, m03) = self.x_axis.to_tuple();
398        let (m10, m11, m12, m13) = self.y_axis.to_tuple();
399        let (m20, m21, m22, m23) = self.z_axis.to_tuple();
400        let (m30, m31, m32, m33) = self.w_axis.to_tuple();
401        Self::new(
402            vec4d(m00, m10, m20, m30),
403            vec4d(m01, m11, m21, m31),
404            vec4d(m02, m12, m22, m32),
405            vec4d(m03, m13, m23, m33),
406        )
407    }
408
409    pub fn determinant(&self) -> f64 {
410        let (m00, m01, m02, m03) = self.x_axis.to_tuple();
411        let (m10, m11, m12, m13) = self.y_axis.to_tuple();
412        let (m20, m21, m22, m23) = self.z_axis.to_tuple();
413        let (m30, m31, m32, m33) = self.w_axis.to_tuple();
414
415        let c23 = m22 * m33 - m23 * m32;
416        let c13 = m21 * m33 - m23 * m31;
417        let c12 = m21 * m32 - m22 * m31;
418        let c03 = m20 * m33 - m23 * m30;
419        let c02 = m20 * m32 - m22 * m30;
420        let c01 = m20 * m31 - m21 * m30;
421
422        let a00 = m11 * c23 - m12 * c13 + m13 * c12;
423        let a01 = m10 * c23 - m12 * c03 + m13 * c02;
424        let a02 = m10 * c13 - m11 * c03 + m13 * c01;
425        let a03 = m10 * c12 - m11 * c02 + m12 * c01;
426
427        m00 * a00 - m01 * a01 + m02 * a02 - m03 * a03
428    }
429
430    pub fn inverse(&self) -> Self {
431        let det = self.determinant();
432        ruby_assert!(!(det.abs() < f64::EPSILON));
433
434        let (m00, m01, m02, m03) = self.x_axis.to_tuple();
435        let (m10, m11, m12, m13) = self.y_axis.to_tuple();
436        let (m20, m21, m22, m23) = self.z_axis.to_tuple();
437        let (m30, m31, m32, m33) = self.w_axis.to_tuple();
438
439        let c1201 = m10 * m21 - m11 * m20;
440        let c1202 = m10 * m22 - m12 * m20;
441        let c1203 = m10 * m23 - m13 * m20;
442        let c1212 = m11 * m22 - m12 * m21;
443        let c1213 = m11 * m23 - m13 * m21;
444        let c1223 = m12 * m23 - m13 * m22;
445
446        let c1301 = m10 * m31 - m11 * m30;
447        let c1302 = m10 * m32 - m12 * m30;
448        let c1303 = m10 * m33 - m13 * m30;
449        let c1312 = m11 * m32 - m12 * m31;
450        let c1313 = m11 * m33 - m13 * m31;
451        let c1323 = m12 * m33 - m13 * m32;
452
453        let c2301 = m20 * m31 - m21 * m30;
454        let c2302 = m20 * m32 - m22 * m30;
455        let c2303 = m20 * m33 - m23 * m30;
456        let c2312 = m21 * m32 - m22 * m31;
457        let c2313 = m21 * m33 - m22 * m31;
458        let c2323 = m22 * m33 - m23 * m32;
459
460        let a00 = m11 * c2323 - m12 * c2313 + m13 * c2312;
461        let a01 = -(m10 * c2323 - m12 * c2303 + m13 * c2302);
462        let a02 = m10 * c2313 - m11 * c2303 + m13 * c2301;
463        let a03 = -(m10 * c2312 - m11 * c2302 + m12 * c2301);
464
465        let a10 = -(m01 * c2323 - m02 * c2313 + m03 * c2312);
466        let a11 = m00 * c2323 - m02 * c2303 + m03 * c2302;
467        let a12 = -(m00 * c2313 - m01 * c2303 + m03 * c2301);
468        let a13 = m00 * c2312 - m01 * c2302 + m02 * c2301;
469
470        let a20 = m01 * c1323 - m02 * c1313 + m03 * c1312;
471        let a21 = -(m00 * c1323 - m02 * c1303 + m03 * c1302);
472        let a22 = m00 * c1313 - m01 * c1303 + m03 * c1301;
473        let a23 = -(m00 * c1312 - m01 * c1302 + m02 * c1301);
474
475        let a30 = -(m01 * c1223 - m02 * c1213 + m03 * c1212);
476        let a31 = m00 * c1223 - m02 * c1203 + m03 * c1202;
477        let a32 = -(m00 * c1213 - m01 * c1203 + m03 * c1201);
478        let a33 = m00 * c1212 - m01 * c1202 + m02 * c1201;
479
480        Self::new(
481            vec4d(a00, a10, a20, a30),
482            vec4d(a01, a11, a21, a31),
483            vec4d(a02, a12, a22, a32),
484            vec4d(a03, a13, a23, a33),
485        )
486        .mul(det.recip())
487    }
488
489    pub fn try_inverse(&self) -> Option<Self> {
490        let det = self.determinant();
491        if det.abs() < f64::EPSILON {
492            return None;
493        }
494
495        let (m00, m01, m02, m03) = self.x_axis.to_tuple();
496        let (m10, m11, m12, m13) = self.y_axis.to_tuple();
497        let (m20, m21, m22, m23) = self.z_axis.to_tuple();
498        let (m30, m31, m32, m33) = self.w_axis.to_tuple();
499
500        let c1201 = m10 * m21 - m11 * m20;
501        let c1202 = m10 * m22 - m12 * m20;
502        let c1203 = m10 * m23 - m13 * m20;
503        let c1212 = m11 * m22 - m12 * m21;
504        let c1213 = m11 * m23 - m13 * m21;
505        let c1223 = m12 * m23 - m13 * m22;
506
507        let c1301 = m10 * m31 - m11 * m30;
508        let c1302 = m10 * m32 - m12 * m30;
509        let c1303 = m10 * m33 - m13 * m30;
510        let c1312 = m11 * m32 - m12 * m31;
511        let c1313 = m11 * m33 - m13 * m31;
512        let c1323 = m12 * m33 - m13 * m32;
513
514        let c2301 = m20 * m31 - m21 * m30;
515        let c2302 = m20 * m32 - m22 * m30;
516        let c2303 = m20 * m33 - m23 * m30;
517        let c2312 = m21 * m32 - m22 * m31;
518        let c2313 = m21 * m33 - m22 * m31;
519        let c2323 = m22 * m33 - m23 * m32;
520
521        let a00 = m11 * c2323 - m12 * c2313 + m13 * c2312;
522        let a01 = -(m10 * c2323 - m12 * c2303 + m13 * c2302);
523        let a02 = m10 * c2313 - m11 * c2303 + m13 * c2301;
524        let a03 = -(m10 * c2312 - m11 * c2302 + m12 * c2301);
525
526        let a10 = -(m01 * c2323 - m02 * c2313 + m03 * c2312);
527        let a11 = m00 * c2323 - m02 * c2303 + m03 * c2302;
528        let a12 = -(m00 * c2313 - m01 * c2303 + m03 * c2301);
529        let a13 = m00 * c2312 - m01 * c2302 + m02 * c2301;
530
531        let a20 = m01 * c1323 - m02 * c1313 + m03 * c1312;
532        let a21 = -(m00 * c1323 - m02 * c1303 + m03 * c1302);
533        let a22 = m00 * c1313 - m01 * c1303 + m03 * c1301;
534        let a23 = -(m00 * c1312 - m01 * c1302 + m02 * c1301);
535
536        let a30 = -(m01 * c1223 - m02 * c1213 + m03 * c1212);
537        let a31 = m00 * c1223 - m02 * c1203 + m03 * c1202;
538        let a32 = -(m00 * c1213 - m01 * c1203 + m03 * c1201);
539        let a33 = m00 * c1212 - m01 * c1202 + m02 * c1201;
540
541        Some(
542            Self::new(
543                vec4d(a00, a10, a20, a30),
544                vec4d(a01, a11, a21, a31),
545                vec4d(a02, a12, a22, a32),
546                vec4d(a03, a13, a23, a33),
547            )
548            .mul(det.recip()),
549        )
550    }
551}
552
553impl From<Mat2d> for Mat4d {
554    fn from(m: Mat2d) -> Self {
555        mat4d(
556            m[0][0], m[0][1], 0.0, 0.0, m[1][0], m[1][1], 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
557            0.0, 1.0,
558        )
559    }
560}
561
562impl From<Mat3d> for Mat4d {
563    fn from(m: Mat3d) -> Self {
564        mat4d(
565            m[0][0], m[0][1], m[0][2], 0.0, m[1][0], m[1][1], m[1][2], 0.0, m[2][0], m[2][1],
566            m[2][2], 0.0, 0.0, 0.0, 0.0, 1.0,
567        )
568    }
569}
570
571impl Mat4d {
572    pub fn from_array(m: [f64; 16]) -> Self {
573        Self::new(
574            vec4d(m[0], m[1], m[2], m[3]),
575            vec4d(m[4], m[5], m[6], m[7]),
576            vec4d(m[8], m[9], m[10], m[11]),
577            vec4d(m[12], m[13], m[14], m[15]),
578        )
579    }
580
581    pub fn from_array_2d(m: [[f64; 4]; 4]) -> Self {
582        Self::new(
583            vec4d(m[0][0], m[0][1], m[0][2], m[0][3]),
584            vec4d(m[1][0], m[1][1], m[1][2], m[1][3]),
585            vec4d(m[2][0], m[2][1], m[2][2], m[2][3]),
586            vec4d(m[3][0], m[3][1], m[3][2], m[3][3]),
587        )
588    }
589
590    pub fn from_diagonal(diagonal: Vec4d) -> Self {
591        Self::new(
592            vec4d(diagonal.x(), 0.0, 0.0, 0.0),
593            vec4d(0.0, diagonal.y(), 0.0, 0.0),
594            vec4d(0.0, 0.0, diagonal.z(), 0.0),
595            vec4d(0.0, 0.0, 0.0, diagonal.w()),
596        )
597    }
598}
599
600impl Mat4d {
601    pub fn to_array(self) -> [f64; 16] {
602        [
603            self[0][0], self[0][1], self[0][2], self[0][3], self[1][0], self[1][1], self[1][2],
604            self[1][3], self[2][0], self[2][1], self[2][2], self[2][3], self[3][0], self[3][1],
605            self[3][2], self[3][3],
606        ]
607    }
608
609    pub fn to_array_2d(self) -> [[f64; 4]; 4] {
610        [
611            [self[0][0], self[0][1], self[0][2], self[0][3]],
612            [self[1][0], self[1][1], self[1][2], self[1][3]],
613            [self[2][0], self[2][1], self[2][2], self[2][3]],
614            [self[3][0], self[3][1], self[3][2], self[3][3]],
615        ]
616    }
617
618    pub fn to_mat2d(self) -> Mat2d {
619        Mat2d::from(self)
620    }
621
622    pub fn to_mat3d(self) -> Mat3d {
623        Mat3d::from(self)
624    }
625
626    pub fn to_mat4f(self) -> Mat4f {
627        Mat4f::new(
628            self.x_axis.to_vec4f(),
629            self.y_axis.to_vec4f(),
630            self.z_axis.to_vec4f(),
631            self.w_axis.to_vec4f(),
632        )
633    }
634}
635
636impl Mat4d {
637    pub fn translation(translate: Vec3d) -> Self {
638        Self::new(
639            vec4d(1.0, 0.0, 0.0, translate.x()),
640            vec4d(0.0, 1.0, 0.0, translate.y()),
641            vec4d(0.0, 0.0, 1.0, translate.z()),
642            vec4d(0.0, 0.0, 0.0, 1.0),
643        )
644    }
645
646    pub fn rotation_x(angle: f64) -> Self {
647        let (sin, cos) = angle.to_radians().sin_cos();
648        Self::new(
649            vec4d(1.0, 0.0, 0.0, 0.0),
650            vec4d(0.0, cos, -sin, 0.0),
651            vec4d(0.0, sin, cos, 0.0),
652            vec4d(0.0, 0.0, 0.0, 1.0),
653        )
654    }
655
656    pub fn rotation_y(angle: f64) -> Self {
657        let (sin, cos) = angle.to_radians().sin_cos();
658        Self::new(
659            vec4d(cos, 0.0, sin, 0.0),
660            vec4d(0.0, 1.0, 0.0, 0.0),
661            vec4d(-sin, 0.0, cos, 0.0),
662            vec4d(0.0, 0.0, 0.0, 1.0),
663        )
664    }
665
666    pub fn rotation_z(angle: f64) -> Self {
667        let (sin, cos) = angle.to_radians().sin_cos();
668        Self::new(
669            vec4d(cos, -sin, 0.0, 0.0),
670            vec4d(sin, cos, 0.0, 0.0),
671            vec4d(0.0, 0.0, 1.0, 0.0),
672            vec4d(0.0, 0.0, 0.0, 1.0),
673        )
674    }
675
676    pub fn rotation_axis(axis: Vec3d, angle: f64) -> Self {
677        let axis = axis.normalize();
678        let (sin, cos) = angle.to_radians().sin_cos();
679        let rotation = cos * Self::identity()
680            + (1.0 - cos)
681                * Self::new(
682                    axis.x().mul(axis).to_homogeneous_coord_vector(),
683                    axis.y().mul(axis).to_homogeneous_coord_vector(),
684                    axis.z().mul(axis).to_homogeneous_coord_vector(),
685                    Vec4d::zero(),
686                )
687            + sin
688                * Self::new(
689                    vec4d(0.0, -axis.z(), axis.y(), 0.0),
690                    vec4d(axis.z(), 0.0, -axis.x(), 0.0),
691                    vec4d(-axis.y(), axis.x(), 0.0, 0.0),
692                    Vec4d::zero(),
693                );
694        rotation
695    }
696
697    pub fn scale(scale: Vec3d) -> Self {
698        Self::new(
699            vec4d(scale.x(), 0.0, 0.0, 0.0),
700            vec4d(0.0, scale.y(), 0.0, 0.0),
701            vec4d(0.0, 0.0, scale.z(), 0.0),
702            vec4d(0.0, 0.0, 0.0, 1.0),
703        )
704    }
705
706    pub fn look_at(eye: Vec3d, target: Vec3d, up: Vec3d) -> Self {
707        let g = (target - eye).normalize();
708        let u = up.normalize();
709        let s = g.cross(u).normalize();
710        let u = s.cross(g);
711        let g = -g;
712
713        Self::new(
714            vec4d(s.x(), s.y(), s.z(), s.dot(-eye)),
715            vec4d(u.x(), u.y(), u.z(), u.dot(-eye)),
716            vec4d(g.x(), g.y(), g.z(), g.dot(-eye)),
717            vec4d(0.0, 0.0, 0.0, 1.0),
718        )
719    }
720
721    pub fn perspective(fovy: f64, aspect: f64, z_near: f64, z_far: f64) -> Self {
722        ruby_assert!(aspect.abs() > f64::EPSILON);
723
724        let (n, f) = (z_near, z_far);
725        let tan_half_theta = fovy.to_radians().mul(0.5).tan();
726
727        let perspective = Self::new(
728            vec4d(tan_half_theta.mul(aspect).recip(), 0.0, 0.0, 0.0),
729            vec4d(0.0, tan_half_theta.recip(), 0.0, 0.0),
730            vec4d(0.0, 0.0, -(n + f) / (f - n), -2.0 * n * f / (f - n)),
731            vec4d(0.0, 0.0, -1.0, 0.0),
732        );
733
734        perspective
735    }
736}