cgmath/
matrix.rs

1// Copyright 2013-2014 The CGMath Developers. For a full listing of the authors,
2// refer to the Cargo.toml file at the top-level directory of this distribution.
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8//     http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15
16use num_traits::{cast, NumCast};
17#[cfg(feature = "rand")]
18use rand::{
19    distributions::{Distribution, Standard},
20    Rng,
21};
22use std::fmt;
23use std::iter;
24use std::mem;
25use std::ops::*;
26use std::ptr;
27
28use structure::*;
29
30use angle::Rad;
31use approx;
32use euler::Euler;
33use num::BaseFloat;
34use point::{Point2, Point3};
35use quaternion::Quaternion;
36use transform::{Transform, Transform2, Transform3};
37use vector::{Vector2, Vector3, Vector4};
38
39#[cfg(feature = "mint")]
40use mint;
41
42/// A 2 x 2, column major matrix
43///
44/// This type is marked as `#[repr(C)]`.
45#[repr(C)]
46#[derive(Copy, Clone, PartialEq)]
47#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
48pub struct Matrix2<S> {
49    /// The first column of the matrix.
50    pub x: Vector2<S>,
51    /// The second column of the matrix.
52    pub y: Vector2<S>,
53}
54
55/// A 3 x 3, column major matrix
56///
57/// This type is marked as `#[repr(C)]`.
58#[repr(C)]
59#[derive(Copy, Clone, PartialEq)]
60#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
61pub struct Matrix3<S> {
62    /// The first column of the matrix.
63    pub x: Vector3<S>,
64    /// The second column of the matrix.
65    pub y: Vector3<S>,
66    /// The third column of the matrix.
67    pub z: Vector3<S>,
68}
69
70/// A 4 x 4, column major matrix
71///
72/// This type is marked as `#[repr(C)]`.
73#[repr(C)]
74#[derive(Copy, Clone, PartialEq)]
75#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
76pub struct Matrix4<S> {
77    /// The first column of the matrix.
78    pub x: Vector4<S>,
79    /// The second column of the matrix.
80    pub y: Vector4<S>,
81    /// The third column of the matrix.
82    pub z: Vector4<S>,
83    /// The fourth column of the matrix.
84    pub w: Vector4<S>,
85}
86
87impl<S> Matrix2<S> {
88    /// Create a new matrix, providing values for each index.
89    #[inline]
90    pub const fn new(c0r0: S, c0r1: S, c1r0: S, c1r1: S) -> Matrix2<S> {
91        Matrix2::from_cols(Vector2::new(c0r0, c0r1), Vector2::new(c1r0, c1r1))
92    }
93
94    /// Create a new matrix, providing columns.
95    #[inline]
96    pub const fn from_cols(c0: Vector2<S>, c1: Vector2<S>) -> Matrix2<S> {
97        Matrix2 { x: c0, y: c1 }
98    }
99}
100
101impl<S: BaseFloat> Matrix2<S> {
102    /// Create a transformation matrix that will cause `unit_x()` to point at
103    /// `dir`. `unit_y()` will be perpendicular to `dir`, and the closest to `up`.
104    pub fn look_at(dir: Vector2<S>, up: Vector2<S>) -> Matrix2<S> {
105        Matrix2::look_at_stable(dir, up.x * dir.y >= up.y * dir.x)
106    }
107
108    /// Crate a transformation that will cause `unit_x()` to point at
109    /// `dir`. This is similar to `look_at`, but does not take an `up` vector.
110    /// This will not cause `unit_y()` to flip when `dir` crosses over the `up` vector.
111    pub fn look_at_stable(dir: Vector2<S>, flip: bool) -> Matrix2<S> {
112        let basis1 = dir.normalize();
113        let basis2 = if flip {
114            Vector2::new(basis1.y, -basis1.x)
115        } else {
116            Vector2::new(-basis1.y, basis1.x)
117        };
118        Matrix2::from_cols(basis1, basis2)
119    }
120
121    #[inline]
122    pub fn from_angle<A: Into<Rad<S>>>(theta: A) -> Matrix2<S> {
123        let (s, c) = Rad::sin_cos(theta.into());
124
125        Matrix2::new(c, s, -s, c)
126    }
127
128    /// Are all entries in the matrix finite.
129    pub fn is_finite(&self) -> bool {
130        self.x.is_finite() && self.y.is_finite()
131    }
132}
133
134impl<S> Matrix3<S> {
135    /// Create a new matrix, providing values for each index.
136    #[inline]
137    #[cfg_attr(rustfmt, rustfmt_skip)]
138    pub const fn new(
139        c0r0:S, c0r1:S, c0r2:S,
140        c1r0:S, c1r1:S, c1r2:S,
141        c2r0:S, c2r1:S, c2r2:S,
142    ) -> Matrix3<S> {
143        Matrix3::from_cols(
144            Vector3::new(c0r0, c0r1, c0r2),
145            Vector3::new(c1r0, c1r1, c1r2),
146            Vector3::new(c2r0, c2r1, c2r2),
147        )
148    }
149
150    /// Create a new matrix, providing columns.
151    #[inline]
152    pub const fn from_cols(c0: Vector3<S>, c1: Vector3<S>, c2: Vector3<S>) -> Matrix3<S> {
153        Matrix3 {
154            x: c0,
155            y: c1,
156            z: c2,
157        }
158    }
159}
160
161impl<S: BaseFloat> Matrix3<S> {
162    /// Create a homogeneous transformation matrix from a translation vector.
163    #[inline]
164    pub fn from_translation(v: Vector2<S>) -> Matrix3<S> {
165        #[cfg_attr(rustfmt, rustfmt_skip)]
166        Matrix3::new(
167            S::one(), S::zero(), S::zero(),
168            S::zero(), S::one(), S::zero(),
169            v.x, v.y, S::one(),
170        )
171    }
172
173    /// Create a homogeneous transformation matrix from a scale value.
174    #[inline]
175    pub fn from_scale(value: S) -> Matrix3<S> {
176        Matrix3::from_nonuniform_scale(value, value)
177    }
178
179    /// Create a homogeneous transformation matrix from a set of scale values.
180    #[inline]
181    pub fn from_nonuniform_scale(x: S, y: S) -> Matrix3<S> {
182        #[cfg_attr(rustfmt, rustfmt_skip)]
183        Matrix3::new(
184            x, S::zero(), S::zero(),
185            S::zero(), y, S::zero(),
186            S::zero(), S::zero(), S::one(),
187        )
188    }
189
190    /// Create a rotation matrix that will cause a vector to point at
191    /// `dir`, using `up` for orientation.
192    #[deprecated = "Use Matrix3::look_to_lh"]
193    pub fn look_at(dir: Vector3<S>, up: Vector3<S>) -> Matrix3<S> {
194        Matrix3::look_to_lh(dir, up)
195    }
196
197    /// Create a rotation matrix that will cause a vector to point at
198    /// `dir`, using `up` for orientation.
199    pub fn look_to_lh(dir: Vector3<S>, up: Vector3<S>) -> Matrix3<S> {
200        let dir = dir.normalize();
201        let side = up.cross(dir).normalize();
202        let up = dir.cross(side).normalize();
203
204        Matrix3::from_cols(side, up, dir).transpose()
205    }
206
207    /// Create a rotation matrix that will cause a vector to point at
208    /// `dir`, using `up` for orientation.
209    pub fn look_to_rh(dir: Vector3<S>, up: Vector3<S>) -> Matrix3<S> {
210        Matrix3::look_to_lh(-dir, up)
211    }
212
213    /// Create a rotation matrix from a rotation around the `x` axis (pitch).
214    pub fn from_angle_x<A: Into<Rad<S>>>(theta: A) -> Matrix3<S> {
215        // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
216        let (s, c) = Rad::sin_cos(theta.into());
217
218        #[cfg_attr(rustfmt, rustfmt_skip)]
219        Matrix3::new(
220            S::one(), S::zero(), S::zero(),
221            S::zero(), c, s,
222            S::zero(), -s, c,
223        )
224    }
225
226    /// Create a rotation matrix from a rotation around the `y` axis (yaw).
227    pub fn from_angle_y<A: Into<Rad<S>>>(theta: A) -> Matrix3<S> {
228        // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
229        let (s, c) = Rad::sin_cos(theta.into());
230
231        #[cfg_attr(rustfmt, rustfmt_skip)]
232        Matrix3::new(
233            c, S::zero(), -s,
234            S::zero(), S::one(), S::zero(),
235            s, S::zero(), c,
236        )
237    }
238
239    /// Create a rotation matrix from a rotation around the `z` axis (roll).
240    pub fn from_angle_z<A: Into<Rad<S>>>(theta: A) -> Matrix3<S> {
241        // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
242        let (s, c) = Rad::sin_cos(theta.into());
243
244        #[cfg_attr(rustfmt, rustfmt_skip)]
245        Matrix3::new(
246            c, s, S::zero(),
247            -s, c, S::zero(),
248            S::zero(), S::zero(), S::one(),
249        )
250    }
251
252    /// Create a rotation matrix from an angle around an arbitrary axis.
253    ///
254    /// The specified axis **must be normalized**, or it represents an invalid rotation.
255    pub fn from_axis_angle<A: Into<Rad<S>>>(axis: Vector3<S>, angle: A) -> Matrix3<S> {
256        let (s, c) = Rad::sin_cos(angle.into());
257        let _1subc = S::one() - c;
258
259        #[cfg_attr(rustfmt, rustfmt_skip)]
260        Matrix3::new(
261            _1subc * axis.x * axis.x + c,
262            _1subc * axis.x * axis.y + s * axis.z,
263            _1subc * axis.x * axis.z - s * axis.y,
264
265            _1subc * axis.x * axis.y - s * axis.z,
266            _1subc * axis.y * axis.y + c,
267            _1subc * axis.y * axis.z + s * axis.x,
268
269            _1subc * axis.x * axis.z + s * axis.y,
270            _1subc * axis.y * axis.z - s * axis.x,
271            _1subc * axis.z * axis.z + c,
272        )
273    }
274
275    /// Are all entries in the matrix finite.
276    pub fn is_finite(&self) -> bool {
277        self.x.is_finite() && self.y.is_finite() && self.z.is_finite()
278    }
279}
280
281impl<S> Matrix4<S> {
282    /// Create a new matrix, providing values for each index.
283    #[inline]
284    #[cfg_attr(rustfmt, rustfmt_skip)]
285    pub const fn new(
286        c0r0: S, c0r1: S, c0r2: S, c0r3: S,
287        c1r0: S, c1r1: S, c1r2: S, c1r3: S,
288        c2r0: S, c2r1: S, c2r2: S, c2r3: S,
289        c3r0: S, c3r1: S, c3r2: S, c3r3: S,
290    ) -> Matrix4<S>  {
291        Matrix4::from_cols(
292            Vector4::new(c0r0, c0r1, c0r2, c0r3),
293            Vector4::new(c1r0, c1r1, c1r2, c1r3),
294            Vector4::new(c2r0, c2r1, c2r2, c2r3),
295            Vector4::new(c3r0, c3r1, c3r2, c3r3),
296        )
297    }
298
299    /// Create a new matrix, providing columns.
300    #[inline]
301    pub const fn from_cols(
302        c0: Vector4<S>,
303        c1: Vector4<S>,
304        c2: Vector4<S>,
305        c3: Vector4<S>,
306    ) -> Matrix4<S> {
307        Matrix4 {
308            x: c0,
309            y: c1,
310            z: c2,
311            w: c3,
312        }
313    }
314}
315
316impl<S: BaseFloat> Matrix4<S> {
317    /// Create a homogeneous transformation matrix from a translation vector.
318    #[inline]
319    pub fn from_translation(v: Vector3<S>) -> Matrix4<S> {
320        #[cfg_attr(rustfmt, rustfmt_skip)]
321        Matrix4::new(
322            S::one(), S::zero(), S::zero(), S::zero(),
323            S::zero(), S::one(), S::zero(), S::zero(),
324            S::zero(), S::zero(), S::one(), S::zero(),
325            v.x, v.y, v.z, S::one(),
326        )
327    }
328
329    /// Create a homogeneous transformation matrix from a scale value.
330    #[inline]
331    pub fn from_scale(value: S) -> Matrix4<S> {
332        Matrix4::from_nonuniform_scale(value, value, value)
333    }
334
335    /// Create a homogeneous transformation matrix from a set of scale values.
336    #[inline]
337    pub fn from_nonuniform_scale(x: S, y: S, z: S) -> Matrix4<S> {
338        #[cfg_attr(rustfmt, rustfmt_skip)]
339        Matrix4::new(
340            x, S::zero(), S::zero(), S::zero(),
341            S::zero(), y, S::zero(), S::zero(),
342            S::zero(), S::zero(), z, S::zero(),
343            S::zero(), S::zero(), S::zero(), S::one(),
344        )
345    }
346
347    /// Create a homogeneous transformation matrix that will cause a vector to point at
348    /// `dir`, using `up` for orientation.
349    #[deprecated = "Use Matrix4::look_to_rh"]
350    pub fn look_at_dir(eye: Point3<S>, dir: Vector3<S>, up: Vector3<S>) -> Matrix4<S> {
351        let f = dir.normalize();
352        let s = f.cross(up).normalize();
353        let u = s.cross(f);
354
355        #[cfg_attr(rustfmt, rustfmt_skip)]
356        Matrix4::new(
357            s.x.clone(), u.x.clone(), -f.x.clone(), S::zero(),
358            s.y.clone(), u.y.clone(), -f.y.clone(), S::zero(),
359            s.z.clone(), u.z.clone(), -f.z.clone(), S::zero(),
360            -eye.dot(s), -eye.dot(u), eye.dot(f), S::one(),
361        )
362    }
363
364    /// Create a homogeneous transformation matrix that will cause a vector to point at
365    /// `dir`, using `up` for orientation.
366    pub fn look_to_rh(eye: Point3<S>, dir: Vector3<S>, up: Vector3<S>) -> Matrix4<S> {
367        let f = dir.normalize();
368        let s = f.cross(up).normalize();
369        let u = s.cross(f);
370
371        #[cfg_attr(rustfmt, rustfmt_skip)]
372        Matrix4::new(
373            s.x.clone(), u.x.clone(), -f.x.clone(), S::zero(),
374            s.y.clone(), u.y.clone(), -f.y.clone(), S::zero(),
375            s.z.clone(), u.z.clone(), -f.z.clone(), S::zero(),
376            -eye.dot(s), -eye.dot(u), eye.dot(f), S::one(),
377        )
378    }
379
380    /// Create a homogeneous transformation matrix that will cause a vector to point at
381    /// `dir`, using `up` for orientation.
382    pub fn look_to_lh(eye: Point3<S>, dir: Vector3<S>, up: Vector3<S>) -> Matrix4<S> {
383        Matrix4::look_to_rh(eye, -dir, up)
384    }
385
386    /// Create a homogeneous transformation matrix that will cause a vector to point at
387    /// `center`, using `up` for orientation.
388    #[deprecated = "Use Matrix4::look_at_rh"]
389    pub fn look_at(eye: Point3<S>, center: Point3<S>, up: Vector3<S>) -> Matrix4<S> {
390        Matrix4::look_at_rh(eye, center, up)
391    }
392
393    /// Create a homogeneous transformation matrix that will cause a vector to point at
394    /// `center`, using `up` for orientation.
395    pub fn look_at_rh(eye: Point3<S>, center: Point3<S>, up: Vector3<S>) -> Matrix4<S> {
396        Matrix4::look_to_rh(eye, center - eye, up)
397    }
398
399    /// Create a homogeneous transformation matrix that will cause a vector to point at
400    /// `center`, using `up` for orientation.
401    pub fn look_at_lh(eye: Point3<S>, center: Point3<S>, up: Vector3<S>) -> Matrix4<S> {
402        Matrix4::look_to_lh(eye, center - eye, up)
403    }
404
405    /// Create a homogeneous transformation matrix from a rotation around the `x` axis (pitch).
406    pub fn from_angle_x<A: Into<Rad<S>>>(theta: A) -> Matrix4<S> {
407        // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
408        let (s, c) = Rad::sin_cos(theta.into());
409
410        #[cfg_attr(rustfmt, rustfmt_skip)]
411        Matrix4::new(
412            S::one(), S::zero(), S::zero(), S::zero(),
413            S::zero(), c, s, S::zero(),
414            S::zero(), -s, c, S::zero(),
415            S::zero(), S::zero(), S::zero(), S::one(),
416        )
417    }
418
419    /// Create a homogeneous transformation matrix from a rotation around the `y` axis (yaw).
420    pub fn from_angle_y<A: Into<Rad<S>>>(theta: A) -> Matrix4<S> {
421        // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
422        let (s, c) = Rad::sin_cos(theta.into());
423
424        #[cfg_attr(rustfmt, rustfmt_skip)]
425        Matrix4::new(
426            c, S::zero(), -s, S::zero(),
427            S::zero(), S::one(), S::zero(), S::zero(),
428            s, S::zero(), c, S::zero(),
429            S::zero(), S::zero(), S::zero(), S::one(),
430        )
431    }
432
433    /// Create a homogeneous transformation matrix from a rotation around the `z` axis (roll).
434    pub fn from_angle_z<A: Into<Rad<S>>>(theta: A) -> Matrix4<S> {
435        // http://en.wikipedia.org/wiki/Rotation_matrix#Basic_rotations
436        let (s, c) = Rad::sin_cos(theta.into());
437
438        #[cfg_attr(rustfmt, rustfmt_skip)]
439        Matrix4::new(
440            c, s, S::zero(), S::zero(),
441            -s, c, S::zero(), S::zero(),
442            S::zero(), S::zero(), S::one(), S::zero(),
443            S::zero(), S::zero(), S::zero(), S::one(),
444        )
445    }
446
447    /// Create a homogeneous transformation matrix from an angle around an arbitrary axis.
448    ///
449    /// The specified axis **must be normalized**, or it represents an invalid rotation.
450    pub fn from_axis_angle<A: Into<Rad<S>>>(axis: Vector3<S>, angle: A) -> Matrix4<S> {
451        let (s, c) = Rad::sin_cos(angle.into());
452        let _1subc = S::one() - c;
453
454        #[cfg_attr(rustfmt, rustfmt_skip)]
455        Matrix4::new(
456            _1subc * axis.x * axis.x + c,
457            _1subc * axis.x * axis.y + s * axis.z,
458            _1subc * axis.x * axis.z - s * axis.y,
459            S::zero(),
460
461            _1subc * axis.x * axis.y - s * axis.z,
462            _1subc * axis.y * axis.y + c,
463            _1subc * axis.y * axis.z + s * axis.x,
464            S::zero(),
465
466            _1subc * axis.x * axis.z + s * axis.y,
467            _1subc * axis.y * axis.z - s * axis.x,
468            _1subc * axis.z * axis.z + c,
469            S::zero(),
470
471            S::zero(), S::zero(), S::zero(), S::one(),
472        )
473    }
474
475    /// Are all entries in the matrix finite.
476    pub fn is_finite(&self) -> bool {
477        self.w.is_finite() && self.x.is_finite() && self.y.is_finite() && self.z.is_finite()
478    }
479}
480
481impl<S: BaseFloat> Zero for Matrix2<S> {
482    #[inline]
483    fn zero() -> Matrix2<S> {
484        #[cfg_attr(rustfmt, rustfmt_skip)]
485        Matrix2::new(
486            S::zero(), S::zero(),
487            S::zero(), S::zero(),
488        )
489    }
490
491    #[inline]
492    fn is_zero(&self) -> bool {
493        ulps_eq!(self, &Self::zero())
494    }
495}
496
497impl<S: BaseFloat> Zero for Matrix3<S> {
498    #[inline]
499    fn zero() -> Matrix3<S> {
500        #[cfg_attr(rustfmt, rustfmt_skip)]
501        Matrix3::new(
502            S::zero(), S::zero(), S::zero(),
503            S::zero(), S::zero(), S::zero(),
504            S::zero(), S::zero(), S::zero(),
505        )
506    }
507
508    #[inline]
509    fn is_zero(&self) -> bool {
510        ulps_eq!(self, &Self::zero())
511    }
512}
513
514impl<S: BaseFloat> Zero for Matrix4<S> {
515    #[inline]
516    fn zero() -> Matrix4<S> {
517        #[cfg_attr(rustfmt, rustfmt_skip)]
518        Matrix4::new(
519            S::zero(), S::zero(), S::zero(), S::zero(),
520            S::zero(), S::zero(), S::zero(), S::zero(),
521            S::zero(), S::zero(), S::zero(), S::zero(),
522            S::zero(), S::zero(), S::zero(), S::zero(),
523        )
524    }
525
526    #[inline]
527    fn is_zero(&self) -> bool {
528        ulps_eq!(self, &Self::zero())
529    }
530}
531
532impl<S: BaseFloat> One for Matrix2<S> {
533    #[inline]
534    fn one() -> Matrix2<S> {
535        Matrix2::from_value(S::one())
536    }
537}
538
539impl<S: BaseFloat> One for Matrix3<S> {
540    #[inline]
541    fn one() -> Matrix3<S> {
542        Matrix3::from_value(S::one())
543    }
544}
545
546impl<S: BaseFloat> One for Matrix4<S> {
547    #[inline]
548    fn one() -> Matrix4<S> {
549        Matrix4::from_value(S::one())
550    }
551}
552
553impl<S: BaseFloat> VectorSpace for Matrix2<S> {
554    type Scalar = S;
555}
556
557impl<S: BaseFloat> VectorSpace for Matrix3<S> {
558    type Scalar = S;
559}
560
561impl<S: BaseFloat> VectorSpace for Matrix4<S> {
562    type Scalar = S;
563}
564
565impl<S: BaseFloat> Matrix for Matrix2<S> {
566    type Column = Vector2<S>;
567    type Row = Vector2<S>;
568    type Transpose = Matrix2<S>;
569
570    #[inline]
571    fn row(&self, r: usize) -> Vector2<S> {
572        Vector2::new(self[0][r], self[1][r])
573    }
574
575    #[inline]
576    fn swap_rows(&mut self, a: usize, b: usize) {
577        self[0].swap_elements(a, b);
578        self[1].swap_elements(a, b);
579    }
580
581    #[inline]
582    fn swap_columns(&mut self, a: usize, b: usize) {
583        unsafe { ptr::swap(&mut self[a], &mut self[b]) };
584    }
585
586    #[inline]
587    fn swap_elements(&mut self, a: (usize, usize), b: (usize, usize)) {
588        let (ac, ar) = a;
589        let (bc, br) = b;
590        unsafe { ptr::swap(&mut self[ac][ar], &mut self[bc][br]) };
591    }
592
593    fn transpose(&self) -> Matrix2<S> {
594        #[cfg_attr(rustfmt, rustfmt_skip)]
595        Matrix2::new(
596            self[0][0], self[1][0],
597            self[0][1], self[1][1],
598        )
599    }
600}
601
602impl<S: BaseFloat> SquareMatrix for Matrix2<S> {
603    type ColumnRow = Vector2<S>;
604
605    #[inline]
606    fn from_value(value: S) -> Matrix2<S> {
607        #[cfg_attr(rustfmt, rustfmt_skip)]
608        Matrix2::new(
609            value, S::zero(),
610            S::zero(), value,
611        )
612    }
613
614    #[inline]
615    fn from_diagonal(value: Vector2<S>) -> Matrix2<S> {
616        #[cfg_attr(rustfmt, rustfmt_skip)]
617        Matrix2::new(
618            value.x, S::zero(),
619            S::zero(), value.y,
620        )
621    }
622
623    #[inline]
624    fn transpose_self(&mut self) {
625        self.swap_elements((0, 1), (1, 0));
626    }
627
628    #[inline]
629    fn determinant(&self) -> S {
630        self[0][0] * self[1][1] - self[1][0] * self[0][1]
631    }
632
633    #[inline]
634    fn diagonal(&self) -> Vector2<S> {
635        Vector2::new(self[0][0], self[1][1])
636    }
637
638    #[inline]
639    fn invert(&self) -> Option<Matrix2<S>> {
640        let det = self.determinant();
641        if det == S::zero() {
642            None
643        } else {
644            #[cfg_attr(rustfmt, rustfmt_skip)]
645            Some(Matrix2::new(
646                self[1][1] / det, -self[0][1] / det,
647                -self[1][0] / det, self[0][0] / det,
648            ))
649        }
650    }
651
652    #[inline]
653    fn is_diagonal(&self) -> bool {
654        ulps_eq!(self[0][1], &S::zero()) && ulps_eq!(self[1][0], &S::zero())
655    }
656
657    #[inline]
658    fn is_symmetric(&self) -> bool {
659        ulps_eq!(self[0][1], &self[1][0]) && ulps_eq!(self[1][0], &self[0][1])
660    }
661}
662
663impl<S: BaseFloat> Matrix for Matrix3<S> {
664    type Column = Vector3<S>;
665    type Row = Vector3<S>;
666    type Transpose = Matrix3<S>;
667
668    #[inline]
669    fn row(&self, r: usize) -> Vector3<S> {
670        Vector3::new(self[0][r], self[1][r], self[2][r])
671    }
672
673    #[inline]
674    fn swap_rows(&mut self, a: usize, b: usize) {
675        self[0].swap_elements(a, b);
676        self[1].swap_elements(a, b);
677        self[2].swap_elements(a, b);
678    }
679
680    #[inline]
681    fn swap_columns(&mut self, a: usize, b: usize) {
682        unsafe { ptr::swap(&mut self[a], &mut self[b]) };
683    }
684
685    #[inline]
686    fn swap_elements(&mut self, a: (usize, usize), b: (usize, usize)) {
687        let (ac, ar) = a;
688        let (bc, br) = b;
689        unsafe { ptr::swap(&mut self[ac][ar], &mut self[bc][br]) };
690    }
691
692    fn transpose(&self) -> Matrix3<S> {
693        #[cfg_attr(rustfmt, rustfmt_skip)]
694        Matrix3::new(
695            self[0][0], self[1][0], self[2][0],
696            self[0][1], self[1][1], self[2][1],
697            self[0][2], self[1][2], self[2][2],
698        )
699    }
700}
701
702impl<S: BaseFloat> SquareMatrix for Matrix3<S> {
703    type ColumnRow = Vector3<S>;
704
705    #[inline]
706    fn from_value(value: S) -> Matrix3<S> {
707        #[cfg_attr(rustfmt, rustfmt_skip)]
708        Matrix3::new(
709            value, S::zero(), S::zero(),
710            S::zero(), value, S::zero(),
711            S::zero(), S::zero(), value,
712        )
713    }
714
715    #[inline]
716    fn from_diagonal(value: Vector3<S>) -> Matrix3<S> {
717        #[cfg_attr(rustfmt, rustfmt_skip)]
718        Matrix3::new(
719            value.x, S::zero(), S::zero(),
720            S::zero(), value.y, S::zero(),
721            S::zero(), S::zero(), value.z,
722        )
723    }
724
725    #[inline]
726    fn transpose_self(&mut self) {
727        self.swap_elements((0, 1), (1, 0));
728        self.swap_elements((0, 2), (2, 0));
729        self.swap_elements((1, 2), (2, 1));
730    }
731
732    fn determinant(&self) -> S {
733        self[0][0] * (self[1][1] * self[2][2] - self[2][1] * self[1][2])
734            - self[1][0] * (self[0][1] * self[2][2] - self[2][1] * self[0][2])
735            + self[2][0] * (self[0][1] * self[1][2] - self[1][1] * self[0][2])
736    }
737
738    #[inline]
739    fn diagonal(&self) -> Vector3<S> {
740        Vector3::new(self[0][0], self[1][1], self[2][2])
741    }
742
743    fn invert(&self) -> Option<Matrix3<S>> {
744        let det = self.determinant();
745        if det == S::zero() {
746            None
747        } else {
748            Some(
749                Matrix3::from_cols(
750                    self[1].cross(self[2]) / det,
751                    self[2].cross(self[0]) / det,
752                    self[0].cross(self[1]) / det,
753                )
754                .transpose(),
755            )
756        }
757    }
758
759    fn is_diagonal(&self) -> bool {
760        ulps_eq!(self[0][1], &S::zero())
761            && ulps_eq!(self[0][2], &S::zero())
762            && ulps_eq!(self[1][0], &S::zero())
763            && ulps_eq!(self[1][2], &S::zero())
764            && ulps_eq!(self[2][0], &S::zero())
765            && ulps_eq!(self[2][1], &S::zero())
766    }
767
768    fn is_symmetric(&self) -> bool {
769        ulps_eq!(self[0][1], &self[1][0])
770            && ulps_eq!(self[0][2], &self[2][0])
771            && ulps_eq!(self[1][0], &self[0][1])
772            && ulps_eq!(self[1][2], &self[2][1])
773            && ulps_eq!(self[2][0], &self[0][2])
774            && ulps_eq!(self[2][1], &self[1][2])
775    }
776}
777
778impl<S: BaseFloat> Matrix for Matrix4<S> {
779    type Column = Vector4<S>;
780    type Row = Vector4<S>;
781    type Transpose = Matrix4<S>;
782
783    #[inline]
784    fn row(&self, r: usize) -> Vector4<S> {
785        Vector4::new(self[0][r], self[1][r], self[2][r], self[3][r])
786    }
787
788    #[inline]
789    fn swap_rows(&mut self, a: usize, b: usize) {
790        self[0].swap_elements(a, b);
791        self[1].swap_elements(a, b);
792        self[2].swap_elements(a, b);
793        self[3].swap_elements(a, b);
794    }
795
796    #[inline]
797    fn swap_columns(&mut self, a: usize, b: usize) {
798        unsafe { ptr::swap(&mut self[a], &mut self[b]) };
799    }
800
801    #[inline]
802    fn swap_elements(&mut self, a: (usize, usize), b: (usize, usize)) {
803        let (ac, ar) = a;
804        let (bc, br) = b;
805        unsafe { ptr::swap(&mut self[ac][ar], &mut self[bc][br]) };
806    }
807
808    fn transpose(&self) -> Matrix4<S> {
809        #[cfg_attr(rustfmt, rustfmt_skip)]
810        Matrix4::new(
811            self[0][0], self[1][0], self[2][0], self[3][0],
812            self[0][1], self[1][1], self[2][1], self[3][1],
813            self[0][2], self[1][2], self[2][2], self[3][2],
814            self[0][3], self[1][3], self[2][3], self[3][3],
815        )
816    }
817}
818
819impl<S: BaseFloat> SquareMatrix for Matrix4<S> {
820    type ColumnRow = Vector4<S>;
821
822    #[inline]
823    fn from_value(value: S) -> Matrix4<S> {
824        #[cfg_attr(rustfmt, rustfmt_skip)]
825        Matrix4::new(
826            value, S::zero(), S::zero(), S::zero(),
827            S::zero(), value, S::zero(), S::zero(),
828            S::zero(), S::zero(), value, S::zero(),
829            S::zero(), S::zero(), S::zero(), value,
830        )
831    }
832
833    #[inline]
834    fn from_diagonal(value: Vector4<S>) -> Matrix4<S> {
835        #[cfg_attr(rustfmt, rustfmt_skip)]
836        Matrix4::new(
837            value.x, S::zero(), S::zero(), S::zero(),
838            S::zero(), value.y, S::zero(), S::zero(),
839            S::zero(), S::zero(), value.z, S::zero(),
840            S::zero(), S::zero(), S::zero(), value.w,
841        )
842    }
843
844    fn transpose_self(&mut self) {
845        self.swap_elements((0, 1), (1, 0));
846        self.swap_elements((0, 2), (2, 0));
847        self.swap_elements((0, 3), (3, 0));
848        self.swap_elements((1, 2), (2, 1));
849        self.swap_elements((1, 3), (3, 1));
850        self.swap_elements((2, 3), (3, 2));
851    }
852
853    fn determinant(&self) -> S {
854        let tmp = unsafe { det_sub_proc_unsafe(self, 1, 2, 3) };
855        tmp.dot(Vector4::new(self[0][0], self[1][0], self[2][0], self[3][0]))
856    }
857
858    #[inline]
859    fn diagonal(&self) -> Vector4<S> {
860        Vector4::new(self[0][0], self[1][1], self[2][2], self[3][3])
861    }
862
863    // The new implementation results in negative optimization when used
864    // without SIMD. so we opt them in with configuration.
865    // A better option would be using specialization. But currently somewhat
866    // specialization is too buggy, and it won't apply here. I'm getting
867    // weird error msgs. Help wanted.
868    #[cfg(not(feature = "simd"))]
869    fn invert(&self) -> Option<Matrix4<S>> {
870        let det = self.determinant();
871        if det == S::zero() {
872            None
873        } else {
874            let inv_det = S::one() / det;
875            let t = self.transpose();
876            let cf = |i, j| {
877                let mat = match i {
878                    0 => {
879                        Matrix3::from_cols(t.y.truncate_n(j), t.z.truncate_n(j), t.w.truncate_n(j))
880                    }
881                    1 => {
882                        Matrix3::from_cols(t.x.truncate_n(j), t.z.truncate_n(j), t.w.truncate_n(j))
883                    }
884                    2 => {
885                        Matrix3::from_cols(t.x.truncate_n(j), t.y.truncate_n(j), t.w.truncate_n(j))
886                    }
887                    3 => {
888                        Matrix3::from_cols(t.x.truncate_n(j), t.y.truncate_n(j), t.z.truncate_n(j))
889                    }
890                    _ => panic!("out of range"),
891                };
892                let sign = if (i + j) & 1 == 1 {
893                    -S::one()
894                } else {
895                    S::one()
896                };
897                mat.determinant() * sign * inv_det
898            };
899
900            #[cfg_attr(rustfmt, rustfmt_skip)]
901            Some(Matrix4::new(
902                cf(0, 0), cf(0, 1), cf(0, 2), cf(0, 3),
903                cf(1, 0), cf(1, 1), cf(1, 2), cf(1, 3),
904                cf(2, 0), cf(2, 1), cf(2, 2), cf(2, 3),
905                cf(3, 0), cf(3, 1), cf(3, 2), cf(3, 3),
906            ))
907        }
908    }
909    #[cfg(feature = "simd")]
910    fn invert(&self) -> Option<Matrix4<S>> {
911        let tmp0 = unsafe { det_sub_proc_unsafe(self, 1, 2, 3) };
912        let det = tmp0.dot(Vector4::new(self[0][0], self[1][0], self[2][0], self[3][0]));
913
914        if det == S::zero() {
915            None
916        } else {
917            let inv_det = S::one() / det;
918            let tmp0 = tmp0 * inv_det;
919            let tmp1 = unsafe { det_sub_proc_unsafe(self, 0, 3, 2) * inv_det };
920            let tmp2 = unsafe { det_sub_proc_unsafe(self, 0, 1, 3) * inv_det };
921            let tmp3 = unsafe { det_sub_proc_unsafe(self, 0, 2, 1) * inv_det };
922            Some(Matrix4::from_cols(tmp0, tmp1, tmp2, tmp3))
923        }
924    }
925
926    fn is_diagonal(&self) -> bool {
927        ulps_eq!(self[0][1], &S::zero())
928            && ulps_eq!(self[0][2], &S::zero())
929            && ulps_eq!(self[0][3], &S::zero())
930            && ulps_eq!(self[1][0], &S::zero())
931            && ulps_eq!(self[1][2], &S::zero())
932            && ulps_eq!(self[1][3], &S::zero())
933            && ulps_eq!(self[2][0], &S::zero())
934            && ulps_eq!(self[2][1], &S::zero())
935            && ulps_eq!(self[2][3], &S::zero())
936            && ulps_eq!(self[3][0], &S::zero())
937            && ulps_eq!(self[3][1], &S::zero())
938            && ulps_eq!(self[3][2], &S::zero())
939    }
940
941    fn is_symmetric(&self) -> bool {
942        ulps_eq!(self[0][1], &self[1][0])
943            && ulps_eq!(self[0][2], &self[2][0])
944            && ulps_eq!(self[0][3], &self[3][0])
945            && ulps_eq!(self[1][0], &self[0][1])
946            && ulps_eq!(self[1][2], &self[2][1])
947            && ulps_eq!(self[1][3], &self[3][1])
948            && ulps_eq!(self[2][0], &self[0][2])
949            && ulps_eq!(self[2][1], &self[1][2])
950            && ulps_eq!(self[2][3], &self[3][2])
951            && ulps_eq!(self[3][0], &self[0][3])
952            && ulps_eq!(self[3][1], &self[1][3])
953            && ulps_eq!(self[3][2], &self[2][3])
954    }
955}
956
957impl<S: BaseFloat> approx::AbsDiffEq for Matrix2<S> {
958    type Epsilon = S::Epsilon;
959
960    #[inline]
961    fn default_epsilon() -> S::Epsilon {
962        cast(1.0e-6f64).unwrap()
963    }
964
965    #[inline]
966    fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool {
967        Vector2::abs_diff_eq(&self[0], &other[0], epsilon)
968            && Vector2::abs_diff_eq(&self[1], &other[1], epsilon)
969    }
970}
971
972impl<S: BaseFloat> approx::RelativeEq for Matrix2<S> {
973    #[inline]
974    fn default_max_relative() -> S::Epsilon {
975        S::default_max_relative()
976    }
977
978    #[inline]
979    fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool {
980        Vector2::relative_eq(&self[0], &other[0], epsilon, max_relative)
981            && Vector2::relative_eq(&self[1], &other[1], epsilon, max_relative)
982    }
983}
984
985impl<S: BaseFloat> approx::UlpsEq for Matrix2<S> {
986    #[inline]
987    fn default_max_ulps() -> u32 {
988        S::default_max_ulps()
989    }
990
991    #[inline]
992    fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool {
993        Vector2::ulps_eq(&self[0], &other[0], epsilon, max_ulps)
994            && Vector2::ulps_eq(&self[1], &other[1], epsilon, max_ulps)
995    }
996}
997
998impl<S: BaseFloat> approx::AbsDiffEq for Matrix3<S> {
999    type Epsilon = S::Epsilon;
1000
1001    #[inline]
1002    fn default_epsilon() -> S::Epsilon {
1003        cast(1.0e-6f64).unwrap()
1004    }
1005
1006    #[inline]
1007    fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool {
1008        Vector3::abs_diff_eq(&self[0], &other[0], epsilon)
1009            && Vector3::abs_diff_eq(&self[1], &other[1], epsilon)
1010            && Vector3::abs_diff_eq(&self[2], &other[2], epsilon)
1011    }
1012}
1013
1014impl<S: BaseFloat> approx::RelativeEq for Matrix3<S> {
1015    #[inline]
1016    fn default_max_relative() -> S::Epsilon {
1017        S::default_max_relative()
1018    }
1019
1020    #[inline]
1021    fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool {
1022        Vector3::relative_eq(&self[0], &other[0], epsilon, max_relative)
1023            && Vector3::relative_eq(&self[1], &other[1], epsilon, max_relative)
1024            && Vector3::relative_eq(&self[2], &other[2], epsilon, max_relative)
1025    }
1026}
1027
1028impl<S: BaseFloat> approx::UlpsEq for Matrix3<S> {
1029    #[inline]
1030    fn default_max_ulps() -> u32 {
1031        S::default_max_ulps()
1032    }
1033
1034    #[inline]
1035    fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool {
1036        Vector3::ulps_eq(&self[0], &other[0], epsilon, max_ulps)
1037            && Vector3::ulps_eq(&self[1], &other[1], epsilon, max_ulps)
1038            && Vector3::ulps_eq(&self[2], &other[2], epsilon, max_ulps)
1039    }
1040}
1041
1042impl<S: BaseFloat> approx::AbsDiffEq for Matrix4<S> {
1043    type Epsilon = S::Epsilon;
1044
1045    #[inline]
1046    fn default_epsilon() -> S::Epsilon {
1047        cast(1.0e-6f64).unwrap()
1048    }
1049
1050    #[inline]
1051    fn abs_diff_eq(&self, other: &Self, epsilon: S::Epsilon) -> bool {
1052        Vector4::abs_diff_eq(&self[0], &other[0], epsilon)
1053            && Vector4::abs_diff_eq(&self[1], &other[1], epsilon)
1054            && Vector4::abs_diff_eq(&self[2], &other[2], epsilon)
1055            && Vector4::abs_diff_eq(&self[3], &other[3], epsilon)
1056    }
1057}
1058
1059impl<S: BaseFloat> approx::RelativeEq for Matrix4<S> {
1060    #[inline]
1061    fn default_max_relative() -> S::Epsilon {
1062        S::default_max_relative()
1063    }
1064
1065    #[inline]
1066    fn relative_eq(&self, other: &Self, epsilon: S::Epsilon, max_relative: S::Epsilon) -> bool {
1067        Vector4::relative_eq(&self[0], &other[0], epsilon, max_relative)
1068            && Vector4::relative_eq(&self[1], &other[1], epsilon, max_relative)
1069            && Vector4::relative_eq(&self[2], &other[2], epsilon, max_relative)
1070            && Vector4::relative_eq(&self[3], &other[3], epsilon, max_relative)
1071    }
1072}
1073
1074impl<S: BaseFloat> approx::UlpsEq for Matrix4<S> {
1075    #[inline]
1076    fn default_max_ulps() -> u32 {
1077        S::default_max_ulps()
1078    }
1079
1080    #[inline]
1081    fn ulps_eq(&self, other: &Self, epsilon: S::Epsilon, max_ulps: u32) -> bool {
1082        Vector4::ulps_eq(&self[0], &other[0], epsilon, max_ulps)
1083            && Vector4::ulps_eq(&self[1], &other[1], epsilon, max_ulps)
1084            && Vector4::ulps_eq(&self[2], &other[2], epsilon, max_ulps)
1085            && Vector4::ulps_eq(&self[3], &other[3], epsilon, max_ulps)
1086    }
1087}
1088
1089impl<S: BaseFloat> Transform<Point2<S>> for Matrix3<S> {
1090    fn look_at(eye: Point2<S>, center: Point2<S>, up: Vector2<S>) -> Matrix3<S> {
1091        let dir = center - eye;
1092        Matrix3::from(Matrix2::look_at(dir, up))
1093    }
1094
1095    fn look_at_lh(eye: Point2<S>, center: Point2<S>, up: Vector2<S>) -> Matrix3<S> {
1096        let dir = center - eye;
1097        Matrix3::from(Matrix2::look_at(dir, up))
1098    }
1099
1100    fn look_at_rh(eye: Point2<S>, center: Point2<S>, up: Vector2<S>) -> Matrix3<S> {
1101        let dir = eye - center;
1102        Matrix3::from(Matrix2::look_at(dir, up))
1103    }
1104
1105    fn transform_vector(&self, vec: Vector2<S>) -> Vector2<S> {
1106        (self * vec.extend(S::zero())).truncate()
1107    }
1108
1109    fn transform_point(&self, point: Point2<S>) -> Point2<S> {
1110        Point2::from_vec((self * Point3::new(point.x, point.y, S::one()).to_vec()).truncate())
1111    }
1112
1113    fn concat(&self, other: &Matrix3<S>) -> Matrix3<S> {
1114        self * other
1115    }
1116
1117    fn inverse_transform(&self) -> Option<Matrix3<S>> {
1118        SquareMatrix::invert(self)
1119    }
1120}
1121
1122impl<S: BaseFloat> Transform<Point3<S>> for Matrix3<S> {
1123    fn look_at(eye: Point3<S>, center: Point3<S>, up: Vector3<S>) -> Matrix3<S> {
1124        let dir = center - eye;
1125        Matrix3::look_to_lh(dir, up)
1126    }
1127
1128    fn look_at_lh(eye: Point3<S>, center: Point3<S>, up: Vector3<S>) -> Matrix3<S> {
1129        let dir = center - eye;
1130        Matrix3::look_to_lh(dir, up)
1131    }
1132
1133    fn look_at_rh(eye: Point3<S>, center: Point3<S>, up: Vector3<S>) -> Matrix3<S> {
1134        let dir = center - eye;
1135        Matrix3::look_to_rh(dir, up)
1136    }
1137
1138    fn transform_vector(&self, vec: Vector3<S>) -> Vector3<S> {
1139        self * vec
1140    }
1141
1142    fn transform_point(&self, point: Point3<S>) -> Point3<S> {
1143        Point3::from_vec(self * point.to_vec())
1144    }
1145
1146    fn concat(&self, other: &Matrix3<S>) -> Matrix3<S> {
1147        self * other
1148    }
1149
1150    fn inverse_transform(&self) -> Option<Matrix3<S>> {
1151        SquareMatrix::invert(self)
1152    }
1153}
1154
1155impl<S: BaseFloat> Transform<Point3<S>> for Matrix4<S> {
1156
1157    fn look_at(eye: Point3<S>, center: Point3<S>, up: Vector3<S>) -> Matrix4<S> {
1158        Matrix4::look_at_rh(eye, center, up)
1159    }
1160
1161    fn look_at_lh(eye: Point3<S>, center: Point3<S>, up: Vector3<S>) -> Matrix4<S> {
1162        Matrix4::look_at_lh(eye, center, up)
1163    }
1164
1165    fn look_at_rh(eye: Point3<S>, center: Point3<S>, up: Vector3<S>) -> Matrix4<S> {
1166        Matrix4::look_at_rh(eye, center, up)
1167    }
1168
1169    fn transform_vector(&self, vec: Vector3<S>) -> Vector3<S> {
1170        (self * vec.extend(S::zero())).truncate()
1171    }
1172
1173    fn transform_point(&self, point: Point3<S>) -> Point3<S> {
1174        Point3::from_homogeneous(self * point.to_homogeneous())
1175    }
1176
1177    fn concat(&self, other: &Matrix4<S>) -> Matrix4<S> {
1178        self * other
1179    }
1180
1181    fn inverse_transform(&self) -> Option<Matrix4<S>> {
1182        SquareMatrix::invert(self)
1183    }
1184}
1185
1186impl<S: BaseFloat> Transform2 for Matrix3<S> {
1187    type Scalar = S;
1188}
1189
1190impl<S: BaseFloat> Transform3 for Matrix3<S> {
1191    type Scalar = S;
1192}
1193
1194impl<S: BaseFloat> Transform3 for Matrix4<S> {
1195    type Scalar = S;
1196}
1197
1198macro_rules! impl_matrix {
1199    ($MatrixN:ident, $VectorN:ident { $($field:ident : $row_index:expr),+ }) => {
1200        impl_operator!(<S: BaseFloat> Neg for $MatrixN<S> {
1201            fn neg(matrix) -> $MatrixN<S> { $MatrixN { $($field: -matrix.$field),+ } }
1202        });
1203
1204        impl_operator!(<S: BaseFloat> Mul<S> for $MatrixN<S> {
1205            fn mul(matrix, scalar) -> $MatrixN<S> { $MatrixN { $($field: matrix.$field * scalar),+ } }
1206        });
1207        impl_operator!(<S: BaseFloat> Div<S> for $MatrixN<S> {
1208            fn div(matrix, scalar) -> $MatrixN<S> { $MatrixN { $($field: matrix.$field / scalar),+ } }
1209        });
1210        impl_operator!(<S: BaseFloat> Rem<S> for $MatrixN<S> {
1211            fn rem(matrix, scalar) -> $MatrixN<S> { $MatrixN { $($field: matrix.$field % scalar),+ } }
1212        });
1213        impl_assignment_operator!(<S: BaseFloat> MulAssign<S> for $MatrixN<S> {
1214            fn mul_assign(&mut self, scalar) { $(self.$field *= scalar);+ }
1215        });
1216        impl_assignment_operator!(<S: BaseFloat> DivAssign<S> for $MatrixN<S> {
1217            fn div_assign(&mut self, scalar) { $(self.$field /= scalar);+ }
1218        });
1219        impl_assignment_operator!(<S: BaseFloat> RemAssign<S> for $MatrixN<S> {
1220            fn rem_assign(&mut self, scalar) { $(self.$field %= scalar);+ }
1221        });
1222
1223        impl_operator!(<S: BaseFloat> Add<$MatrixN<S> > for $MatrixN<S> {
1224            fn add(lhs, rhs) -> $MatrixN<S> { $MatrixN { $($field: lhs.$field + rhs.$field),+ } }
1225        });
1226        impl_operator!(<S: BaseFloat> Sub<$MatrixN<S> > for $MatrixN<S> {
1227            fn sub(lhs, rhs) -> $MatrixN<S> { $MatrixN { $($field: lhs.$field - rhs.$field),+ } }
1228        });
1229        impl<S: BaseFloat + AddAssign<S>> AddAssign<$MatrixN<S>> for $MatrixN<S> {
1230            fn add_assign(&mut self, other: $MatrixN<S>) { $(self.$field += other.$field);+ }
1231        }
1232        impl<S: BaseFloat + SubAssign<S>> SubAssign<$MatrixN<S>> for $MatrixN<S> {
1233            fn sub_assign(&mut self, other: $MatrixN<S>) { $(self.$field -= other.$field);+ }
1234        }
1235
1236        impl<S: BaseFloat> iter::Sum<$MatrixN<S>> for $MatrixN<S> {
1237            #[inline]
1238            fn sum<I: Iterator<Item=$MatrixN<S>>>(iter: I) -> $MatrixN<S> {
1239                iter.fold($MatrixN::zero(), Add::add)
1240            }
1241        }
1242
1243        impl<'a, S: 'a + BaseFloat> iter::Sum<&'a $MatrixN<S>> for $MatrixN<S> {
1244            #[inline]
1245            fn sum<I: Iterator<Item=&'a $MatrixN<S>>>(iter: I) -> $MatrixN<S> {
1246                iter.fold($MatrixN::zero(), Add::add)
1247            }
1248        }
1249
1250        impl<S: BaseFloat> iter::Product for $MatrixN<S> {
1251            #[inline]
1252            fn product<I: Iterator<Item=$MatrixN<S>>>(iter: I) -> $MatrixN<S> {
1253                iter.fold($MatrixN::identity(), Mul::mul)
1254            }
1255        }
1256
1257        impl<'a, S: 'a + BaseFloat> iter::Product<&'a $MatrixN<S>> for $MatrixN<S> {
1258            #[inline]
1259            fn product<I: Iterator<Item=&'a $MatrixN<S>>>(iter: I) -> $MatrixN<S> {
1260                iter.fold($MatrixN::identity(), Mul::mul)
1261            }
1262        }
1263
1264        impl_scalar_ops!($MatrixN<usize> { $($field),+ });
1265        impl_scalar_ops!($MatrixN<u8> { $($field),+ });
1266        impl_scalar_ops!($MatrixN<u16> { $($field),+ });
1267        impl_scalar_ops!($MatrixN<u32> { $($field),+ });
1268        impl_scalar_ops!($MatrixN<u64> { $($field),+ });
1269        impl_scalar_ops!($MatrixN<isize> { $($field),+ });
1270        impl_scalar_ops!($MatrixN<i8> { $($field),+ });
1271        impl_scalar_ops!($MatrixN<i16> { $($field),+ });
1272        impl_scalar_ops!($MatrixN<i32> { $($field),+ });
1273        impl_scalar_ops!($MatrixN<i64> { $($field),+ });
1274        impl_scalar_ops!($MatrixN<f32> { $($field),+ });
1275        impl_scalar_ops!($MatrixN<f64> { $($field),+ });
1276
1277
1278        impl<S: NumCast + Copy> $MatrixN<S> {
1279            /// Component-wise casting to another type
1280            #[inline]
1281            pub fn cast<T: NumCast>(&self) -> Option<$MatrixN<T>> {
1282                $(
1283                    let $field = match self.$field.cast() {
1284                        Some(field) => field,
1285                        None => return None
1286                    };
1287                )+
1288                Some($MatrixN { $($field),+ })
1289            }
1290        }
1291    }
1292}
1293
1294macro_rules! impl_scalar_ops {
1295    ($MatrixN:ident<$S:ident> { $($field:ident),+ }) => {
1296        impl_operator!(Mul<$MatrixN<$S>> for $S {
1297            fn mul(scalar, matrix) -> $MatrixN<$S> { $MatrixN { $($field: scalar * matrix.$field),+ } }
1298        });
1299        impl_operator!(Div<$MatrixN<$S>> for $S {
1300            fn div(scalar, matrix) -> $MatrixN<$S> { $MatrixN { $($field: scalar / matrix.$field),+ } }
1301        });
1302        impl_operator!(Rem<$MatrixN<$S>> for $S {
1303            fn rem(scalar, matrix) -> $MatrixN<$S> { $MatrixN { $($field: scalar % matrix.$field),+ } }
1304        });
1305    };
1306}
1307
1308impl_matrix!(Matrix2, Vector2 { x: 0, y: 1 });
1309impl_matrix!(Matrix3, Vector3 { x: 0, y: 1, z: 2 });
1310#[cfg_attr(rustfmt, rustfmt_skip)]
1311impl_matrix!(Matrix4, Vector4 { x: 0, y: 1, z: 2, w: 3 });
1312
1313macro_rules! impl_mv_operator {
1314    ($MatrixN:ident, $VectorN:ident { $($field:ident : $row_index:expr),+ }) => {
1315        impl_operator!(<S: BaseFloat> Mul<$VectorN<S> > for $MatrixN<S> {
1316            fn mul(matrix, vector) -> $VectorN<S> {$VectorN::new($(matrix.row($row_index).dot(vector.clone())),+)}
1317        });
1318    }
1319}
1320
1321impl_mv_operator!(Matrix2, Vector2 { x: 0, y: 1 });
1322impl_mv_operator!(Matrix3, Vector3 { x: 0, y: 1, z: 2 });
1323#[cfg(not(feature = "simd"))]
1324#[cfg_attr(rustfmt, rustfmt_skip)]
1325impl_mv_operator!(Matrix4, Vector4 { x: 0, y: 1, z: 2, w: 3 });
1326
1327#[cfg(feature = "simd")]
1328impl_operator!(<S: BaseFloat> Mul<Vector4<S> > for Matrix4<S> {
1329    fn mul(matrix, vector) -> Vector4<S> {
1330        matrix[0] * vector[0] + matrix[1] * vector[1] + matrix[2] * vector[2] + matrix[3] * vector[3]
1331    }
1332});
1333
1334impl_operator!(<S: BaseFloat> Mul<Matrix2<S> > for Matrix2<S> {
1335    fn mul(lhs, rhs) -> Matrix2<S> {
1336        Matrix2::new(lhs.row(0).dot(rhs[0]), lhs.row(1).dot(rhs[0]),
1337                     lhs.row(0).dot(rhs[1]), lhs.row(1).dot(rhs[1]))
1338    }
1339});
1340
1341impl_operator!(<S: BaseFloat> Mul<Matrix3<S> > for Matrix3<S> {
1342    fn mul(lhs, rhs) -> Matrix3<S> {
1343        Matrix3::new(lhs.row(0).dot(rhs[0]), lhs.row(1).dot(rhs[0]), lhs.row(2).dot(rhs[0]),
1344                     lhs.row(0).dot(rhs[1]), lhs.row(1).dot(rhs[1]), lhs.row(2).dot(rhs[1]),
1345                     lhs.row(0).dot(rhs[2]), lhs.row(1).dot(rhs[2]), lhs.row(2).dot(rhs[2]))
1346    }
1347});
1348
1349// Using self.row(0).dot(other[0]) like the other matrix multiplies
1350// causes the LLVM to miss identical loads and multiplies. This optimization
1351// causes the code to be auto vectorized properly increasing the performance
1352// around ~4 times.
1353// Update: this should now be a bit more efficient
1354
1355impl_operator!(<S: BaseFloat> Mul<Matrix4<S> > for Matrix4<S> {
1356    fn mul(lhs, rhs) -> Matrix4<S> {
1357        {
1358            let a = lhs[0];
1359            let b = lhs[1];
1360            let c = lhs[2];
1361            let d = lhs[3];
1362
1363            #[cfg_attr(rustfmt, rustfmt_skip)]
1364            Matrix4::from_cols(
1365                a*rhs[0][0] + b*rhs[0][1] + c*rhs[0][2] + d*rhs[0][3],
1366                a*rhs[1][0] + b*rhs[1][1] + c*rhs[1][2] + d*rhs[1][3],
1367                a*rhs[2][0] + b*rhs[2][1] + c*rhs[2][2] + d*rhs[2][3],
1368                a*rhs[3][0] + b*rhs[3][1] + c*rhs[3][2] + d*rhs[3][3],
1369            )
1370        }
1371    }
1372});
1373
1374macro_rules! index_operators {
1375    ($MatrixN:ident<$S:ident>, $n:expr, $Output:ty, $I:ty) => {
1376        impl<$S> Index<$I> for $MatrixN<$S> {
1377            type Output = $Output;
1378
1379            #[inline]
1380            fn index<'a>(&'a self, i: $I) -> &'a $Output {
1381                let v: &[[$S; $n]; $n] = self.as_ref();
1382                From::from(&v[i])
1383            }
1384        }
1385
1386        impl<$S> IndexMut<$I> for $MatrixN<$S> {
1387            #[inline]
1388            fn index_mut<'a>(&'a mut self, i: $I) -> &'a mut $Output {
1389                let v: &mut [[$S; $n]; $n] = self.as_mut();
1390                From::from(&mut v[i])
1391            }
1392        }
1393    };
1394}
1395
1396index_operators!(Matrix2<S>, 2, Vector2<S>, usize);
1397index_operators!(Matrix3<S>, 3, Vector3<S>, usize);
1398index_operators!(Matrix4<S>, 4, Vector4<S>, usize);
1399// index_operators!(Matrix2<S>, 2, [Vector2<S>], Range<usize>);
1400// index_operators!(Matrix3<S>, 3, [Vector3<S>], Range<usize>);
1401// index_operators!(Matrix4<S>, 4, [Vector4<S>], Range<usize>);
1402// index_operators!(Matrix2<S>, 2, [Vector2<S>], RangeTo<usize>);
1403// index_operators!(Matrix3<S>, 3, [Vector3<S>], RangeTo<usize>);
1404// index_operators!(Matrix4<S>, 4, [Vector4<S>], RangeTo<usize>);
1405// index_operators!(Matrix2<S>, 2, [Vector2<S>], RangeFrom<usize>);
1406// index_operators!(Matrix3<S>, 3, [Vector3<S>], RangeFrom<usize>);
1407// index_operators!(Matrix4<S>, 4, [Vector4<S>], RangeFrom<usize>);
1408// index_operators!(Matrix2<S>, 2, [Vector2<S>], RangeFull);
1409// index_operators!(Matrix3<S>, 3, [Vector3<S>], RangeFull);
1410// index_operators!(Matrix4<S>, 4, [Vector4<S>], RangeFull);
1411
1412impl<A> From<Euler<A>> for Matrix3<A::Unitless>
1413where
1414    A: Angle + Into<Rad<<A as Angle>::Unitless>>,
1415{
1416    fn from(src: Euler<A>) -> Matrix3<A::Unitless> {
1417        // Page A-2: http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf
1418        let (sx, cx) = Rad::sin_cos(src.x.into());
1419        let (sy, cy) = Rad::sin_cos(src.y.into());
1420        let (sz, cz) = Rad::sin_cos(src.z.into());
1421
1422        #[cfg_attr(rustfmt, rustfmt_skip)]
1423        Matrix3::new(
1424            cy * cz, cx * sz + sx * sy * cz, sx * sz - cx * sy * cz,
1425            -cy * sz, cx * cz - sx * sy * sz, sx * cz + cx * sy * sz,
1426            sy, -sx * cy, cx * cy,
1427        )
1428    }
1429}
1430
1431impl<A> From<Euler<A>> for Matrix4<A::Unitless>
1432where
1433    A: Angle + Into<Rad<<A as Angle>::Unitless>>,
1434{
1435    fn from(src: Euler<A>) -> Matrix4<A::Unitless> {
1436        // Page A-2: http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf
1437        let (sx, cx) = Rad::sin_cos(src.x.into());
1438        let (sy, cy) = Rad::sin_cos(src.y.into());
1439        let (sz, cz) = Rad::sin_cos(src.z.into());
1440
1441        #[cfg_attr(rustfmt, rustfmt_skip)]
1442        Matrix4::new(
1443            cy * cz, cx * sz + sx * sy * cz, sx * sz - cx * sy * cz, A::Unitless::zero(),
1444            -cy * sz, cx * cz - sx * sy * sz, sx * cz + cx * sy * sz, A::Unitless::zero(),
1445            sy, -sx * cy, cx * cy, A::Unitless::zero(),
1446            A::Unitless::zero(), A::Unitless::zero(), A::Unitless::zero(), A::Unitless::one(),
1447        )
1448    }
1449}
1450
1451macro_rules! fixed_array_conversions {
1452    ($MatrixN:ident <$S:ident> { $($field:ident : $index:expr),+ }, $n:expr) => {
1453        impl<$S> Into<[[$S; $n]; $n]> for $MatrixN<$S> {
1454            #[inline]
1455            fn into(self) -> [[$S; $n]; $n] {
1456                match self { $MatrixN { $($field),+ } => [$($field.into()),+] }
1457            }
1458        }
1459
1460        impl<$S> AsRef<[[$S; $n]; $n]> for $MatrixN<$S> {
1461            #[inline]
1462            fn as_ref(&self) -> &[[$S; $n]; $n] {
1463                unsafe { mem::transmute(self) }
1464            }
1465        }
1466
1467        impl<$S> AsMut<[[$S; $n]; $n]> for $MatrixN<$S> {
1468            #[inline]
1469            fn as_mut(&mut self) -> &mut [[$S; $n]; $n] {
1470                unsafe { mem::transmute(self) }
1471            }
1472        }
1473
1474        impl<$S: Copy> From<[[$S; $n]; $n]> for $MatrixN<$S> {
1475            #[inline]
1476            fn from(m: [[$S; $n]; $n]) -> $MatrixN<$S> {
1477                // We need to use a copy here because we can't pattern match on arrays yet
1478                $MatrixN { $($field: From::from(m[$index])),+ }
1479            }
1480        }
1481
1482        impl<'a, $S> From<&'a [[$S; $n]; $n]> for &'a $MatrixN<$S> {
1483            #[inline]
1484            fn from(m: &'a [[$S; $n]; $n]) -> &'a $MatrixN<$S> {
1485                unsafe { mem::transmute(m) }
1486            }
1487        }
1488
1489        impl<'a, $S> From<&'a mut [[$S; $n]; $n]> for &'a mut $MatrixN<$S> {
1490            #[inline]
1491            fn from(m: &'a mut [[$S; $n]; $n]) -> &'a mut $MatrixN<$S> {
1492                unsafe { mem::transmute(m) }
1493            }
1494        }
1495
1496        // impl<$S> Into<[$S; ($n * $n)]> for $MatrixN<$S> {
1497        //     #[inline]
1498        //     fn into(self) -> [[$S; $n]; $n] {
1499        //         // TODO: Not sure how to implement this...
1500        //         unimplemented!()
1501        //     }
1502        // }
1503
1504        impl<$S> AsRef<[$S; ($n * $n)]> for $MatrixN<$S> {
1505            #[inline]
1506            fn as_ref(&self) -> &[$S; ($n * $n)] {
1507                unsafe { mem::transmute(self) }
1508            }
1509        }
1510
1511        impl<$S> AsMut<[$S; ($n * $n)]> for $MatrixN<$S> {
1512            #[inline]
1513            fn as_mut(&mut self) -> &mut [$S; ($n * $n)] {
1514                unsafe { mem::transmute(self) }
1515            }
1516        }
1517
1518        // impl<$S> From<[$S; ($n * $n)]> for $MatrixN<$S> {
1519        //     #[inline]
1520        //     fn from(m: [$S; ($n * $n)]) -> $MatrixN<$S> {
1521        //         // TODO: Not sure how to implement this...
1522        //         unimplemented!()
1523        //     }
1524        // }
1525
1526        impl<'a, $S> From<&'a [$S; ($n * $n)]> for &'a $MatrixN<$S> {
1527            #[inline]
1528            fn from(m: &'a [$S; ($n * $n)]) -> &'a $MatrixN<$S> {
1529                unsafe { mem::transmute(m) }
1530            }
1531        }
1532
1533        impl<'a, $S> From<&'a mut [$S; ($n * $n)]> for &'a mut $MatrixN<$S> {
1534            #[inline]
1535            fn from(m: &'a mut [$S; ($n * $n)]) -> &'a mut $MatrixN<$S> {
1536                unsafe { mem::transmute(m) }
1537            }
1538        }
1539    }
1540}
1541
1542fixed_array_conversions!(Matrix2<S> { x:0, y:1 }, 2);
1543fixed_array_conversions!(Matrix3<S> { x:0, y:1, z:2 }, 3);
1544fixed_array_conversions!(Matrix4<S> { x:0, y:1, z:2, w:3 }, 4);
1545
1546#[cfg(feature = "mint")]
1547macro_rules! mint_conversions {
1548    ($MatrixN:ident { $($field:ident),+ }, $MintN:ident) => {
1549        impl<S: Clone> Into<mint::$MintN<S>> for $MatrixN<S> {
1550            #[inline]
1551            fn into(self) -> mint::$MintN<S> {
1552                mint::$MintN { $($field: self.$field.into()),+ }
1553            }
1554        }
1555
1556        impl<S> From<mint::$MintN<S>> for $MatrixN<S> {
1557            #[inline]
1558            fn from(m: mint::$MintN<S>) -> Self {
1559                $MatrixN { $($field: m.$field.into()),+ }
1560            }
1561        }
1562
1563    }
1564}
1565
1566#[cfg(feature = "mint")]
1567mint_conversions!(Matrix2 { x, y }, ColumnMatrix2);
1568#[cfg(feature = "mint")]
1569mint_conversions!(Matrix3 { x, y, z }, ColumnMatrix3);
1570#[cfg(feature = "mint")]
1571mint_conversions!(Matrix4 { x, y, z, w }, ColumnMatrix4);
1572
1573impl<S: BaseFloat> From<Matrix2<S>> for Matrix3<S> {
1574    /// Clone the elements of a 2-dimensional matrix into the top-left corner
1575    /// of a 3-dimensional identity matrix.
1576    fn from(m: Matrix2<S>) -> Matrix3<S> {
1577        #[cfg_attr(rustfmt, rustfmt_skip)]
1578        Matrix3::new(
1579            m[0][0], m[0][1], S::zero(),
1580            m[1][0], m[1][1], S::zero(),
1581            S::zero(), S::zero(), S::one(),
1582        )
1583    }
1584}
1585
1586impl<S: BaseFloat> From<Matrix2<S>> for Matrix4<S> {
1587    /// Clone the elements of a 2-dimensional matrix into the top-left corner
1588    /// of a 4-dimensional identity matrix.
1589    fn from(m: Matrix2<S>) -> Matrix4<S> {
1590        #[cfg_attr(rustfmt, rustfmt_skip)]
1591        Matrix4::new(
1592            m[0][0], m[0][1], S::zero(), S::zero(),
1593            m[1][0], m[1][1], S::zero(), S::zero(),
1594            S::zero(), S::zero(), S::one(), S::zero(),
1595            S::zero(), S::zero(), S::zero(), S::one(),
1596        )
1597    }
1598}
1599
1600impl<S: BaseFloat> From<Matrix3<S>> for Matrix4<S> {
1601    /// Clone the elements of a 3-dimensional matrix into the top-left corner
1602    /// of a 4-dimensional identity matrix.
1603    fn from(m: Matrix3<S>) -> Matrix4<S> {
1604        #[cfg_attr(rustfmt, rustfmt_skip)]
1605        Matrix4::new(
1606            m[0][0], m[0][1], m[0][2], S::zero(),
1607            m[1][0], m[1][1], m[1][2], S::zero(),
1608            m[2][0], m[2][1], m[2][2], S::zero(),
1609            S::zero(), S::zero(), S::zero(), S::one(),
1610        )
1611    }
1612}
1613
1614impl<S: BaseFloat> From<Matrix3<S>> for Quaternion<S> {
1615    /// Convert the matrix to a quaternion
1616    fn from(mat: Matrix3<S>) -> Quaternion<S> {
1617        // http://www.cs.ucr.edu/~vbz/resources/quatut.pdf
1618        let trace = mat.trace();
1619        let half: S = cast(0.5f64).unwrap();
1620
1621        if trace >= S::zero() {
1622            let s = (S::one() + trace).sqrt();
1623            let w = half * s;
1624            let s = half / s;
1625            let x = (mat[1][2] - mat[2][1]) * s;
1626            let y = (mat[2][0] - mat[0][2]) * s;
1627            let z = (mat[0][1] - mat[1][0]) * s;
1628            Quaternion::new(w, x, y, z)
1629        } else if (mat[0][0] > mat[1][1]) && (mat[0][0] > mat[2][2]) {
1630            let s = ((mat[0][0] - mat[1][1] - mat[2][2]) + S::one()).sqrt();
1631            let x = half * s;
1632            let s = half / s;
1633            let y = (mat[1][0] + mat[0][1]) * s;
1634            let z = (mat[0][2] + mat[2][0]) * s;
1635            let w = (mat[1][2] - mat[2][1]) * s;
1636            Quaternion::new(w, x, y, z)
1637        } else if mat[1][1] > mat[2][2] {
1638            let s = ((mat[1][1] - mat[0][0] - mat[2][2]) + S::one()).sqrt();
1639            let y = half * s;
1640            let s = half / s;
1641            let z = (mat[2][1] + mat[1][2]) * s;
1642            let x = (mat[1][0] + mat[0][1]) * s;
1643            let w = (mat[2][0] - mat[0][2]) * s;
1644            Quaternion::new(w, x, y, z)
1645        } else {
1646            let s = ((mat[2][2] - mat[0][0] - mat[1][1]) + S::one()).sqrt();
1647            let z = half * s;
1648            let s = half / s;
1649            let x = (mat[0][2] + mat[2][0]) * s;
1650            let y = (mat[2][1] + mat[1][2]) * s;
1651            let w = (mat[0][1] - mat[1][0]) * s;
1652            Quaternion::new(w, x, y, z)
1653        }
1654    }
1655}
1656
1657impl<S: fmt::Debug> fmt::Debug for Matrix2<S> {
1658    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1659        write!(f, "Matrix2 ")?;
1660        <[[S; 2]; 2] as fmt::Debug>::fmt(self.as_ref(), f)
1661    }
1662}
1663
1664impl<S: fmt::Debug> fmt::Debug for Matrix3<S> {
1665    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1666        write!(f, "Matrix3 ")?;
1667        <[[S; 3]; 3] as fmt::Debug>::fmt(self.as_ref(), f)
1668    }
1669}
1670
1671impl<S: fmt::Debug> fmt::Debug for Matrix4<S> {
1672    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1673        write!(f, "Matrix4 ")?;
1674        <[[S; 4]; 4] as fmt::Debug>::fmt(self.as_ref(), f)
1675    }
1676}
1677
1678#[cfg(feature = "rand")]
1679impl<S> Distribution<Matrix2<S>> for Standard
1680where
1681    Standard: Distribution<Vector2<S>>,
1682    S: BaseFloat,
1683{
1684    #[inline]
1685    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Matrix2<S> {
1686        Matrix2 {
1687            x: self.sample(rng),
1688            y: self.sample(rng),
1689        }
1690    }
1691}
1692
1693#[cfg(feature = "rand")]
1694impl<S> Distribution<Matrix3<S>> for Standard
1695where
1696    Standard: Distribution<Vector3<S>>,
1697    S: BaseFloat,
1698{
1699    #[inline]
1700    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Matrix3<S> {
1701        Matrix3 {
1702            x: rng.gen(),
1703            y: rng.gen(),
1704            z: rng.gen(),
1705        }
1706    }
1707}
1708
1709#[cfg(feature = "rand")]
1710impl<S> Distribution<Matrix4<S>> for Standard
1711where
1712    Standard: Distribution<Vector4<S>>,
1713    S: BaseFloat,
1714{
1715    #[inline]
1716    fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Matrix4<S> {
1717        Matrix4 {
1718            x: rng.gen(),
1719            y: rng.gen(),
1720            z: rng.gen(),
1721            w: rng.gen(),
1722        }
1723    }
1724}
1725
1726// Sub procedure for SIMD when dealing with determinant and inversion
1727#[inline]
1728unsafe fn det_sub_proc_unsafe<S: BaseFloat>(
1729    m: &Matrix4<S>,
1730    x: usize,
1731    y: usize,
1732    z: usize,
1733) -> Vector4<S> {
1734    let s: &[S; 16] = m.as_ref();
1735    let a = Vector4::new(
1736        *s.get_unchecked(4 + x),
1737        *s.get_unchecked(12 + x),
1738        *s.get_unchecked(x),
1739        *s.get_unchecked(8 + x),
1740    );
1741    let b = Vector4::new(
1742        *s.get_unchecked(8 + y),
1743        *s.get_unchecked(8 + y),
1744        *s.get_unchecked(4 + y),
1745        *s.get_unchecked(4 + y),
1746    );
1747    let c = Vector4::new(
1748        *s.get_unchecked(12 + z),
1749        *s.get_unchecked(z),
1750        *s.get_unchecked(12 + z),
1751        *s.get_unchecked(z),
1752    );
1753
1754    let d = Vector4::new(
1755        *s.get_unchecked(8 + x),
1756        *s.get_unchecked(8 + x),
1757        *s.get_unchecked(4 + x),
1758        *s.get_unchecked(4 + x),
1759    );
1760    let e = Vector4::new(
1761        *s.get_unchecked(12 + y),
1762        *s.get_unchecked(y),
1763        *s.get_unchecked(12 + y),
1764        *s.get_unchecked(y),
1765    );
1766    let f = Vector4::new(
1767        *s.get_unchecked(4 + z),
1768        *s.get_unchecked(12 + z),
1769        *s.get_unchecked(z),
1770        *s.get_unchecked(8 + z),
1771    );
1772
1773    let g = Vector4::new(
1774        *s.get_unchecked(12 + x),
1775        *s.get_unchecked(x),
1776        *s.get_unchecked(12 + x),
1777        *s.get_unchecked(x),
1778    );
1779    let h = Vector4::new(
1780        *s.get_unchecked(4 + y),
1781        *s.get_unchecked(12 + y),
1782        *s.get_unchecked(y),
1783        *s.get_unchecked(8 + y),
1784    );
1785    let i = Vector4::new(
1786        *s.get_unchecked(8 + z),
1787        *s.get_unchecked(8 + z),
1788        *s.get_unchecked(4 + z),
1789        *s.get_unchecked(4 + z),
1790    );
1791    let mut tmp = a.mul_element_wise(b.mul_element_wise(c));
1792    tmp += d.mul_element_wise(e.mul_element_wise(f));
1793    tmp += g.mul_element_wise(h.mul_element_wise(i));
1794    tmp -= a.mul_element_wise(e.mul_element_wise(i));
1795    tmp -= d.mul_element_wise(h.mul_element_wise(c));
1796    tmp -= g.mul_element_wise(b.mul_element_wise(f));
1797    tmp
1798}