euclid/
transform3d.rs

1// Copyright 2013 The Servo Project Developers. See the COPYRIGHT
2// file at the top-level directory of this distribution.
3//
4// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
5// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
7// option. This file may not be copied, modified, or distributed
8// except according to those terms.
9
10#![allow(clippy::just_underscores_and_digits)]
11
12use crate::box2d::Box2D;
13use crate::box3d::Box3D;
14use crate::homogen::HomogeneousVector;
15use crate::num::{One, Zero};
16use crate::point::{point2, point3, Point2D, Point3D};
17use crate::rect::Rect;
18use crate::scale::Scale;
19use crate::transform2d::Transform2D;
20use crate::vector::{vec2, vec3, Vector2D, Vector3D};
21use crate::ScaleOffset2D;
22use crate::UnknownUnit;
23
24use core::cmp::{Eq, PartialEq};
25use core::fmt;
26use core::hash::Hash;
27use core::marker::PhantomData;
28use core::ops::{Add, Div, Mul, Neg, Sub};
29
30#[cfg(feature = "bytemuck")]
31use bytemuck::{Pod, Zeroable};
32#[cfg(feature = "malloc_size_of")]
33use malloc_size_of::{MallocSizeOf, MallocSizeOfOps};
34#[cfg(feature = "mint")]
35use mint;
36use num_traits::{NumCast, Signed};
37#[cfg(feature = "serde")]
38use serde::{Deserialize, Serialize};
39
40/// A 3d transform stored as a column-major 4 by 4 matrix.
41///
42/// Transforms can be parametrized over the source and destination units, to describe a
43/// transformation from a space to another.
44/// For example, `Transform3D<f32, WorldSpace, ScreenSpace>::transform_point3d`
45/// takes a `Point3D<f32, WorldSpace>` and returns a `Point3D<f32, ScreenSpace>`.
46///
47/// Transforms expose a set of convenience methods for pre- and post-transformations.
48/// Pre-transformations (`pre_*` methods) correspond to adding an operation that is
49/// applied before the rest of the transformation, while post-transformations (`then_*`
50/// methods) add an operation that is applied after.
51///
52/// When translating `Transform3D` into general matrix representations, consider that the
53/// representation follows the column major notation with column vectors.
54///
55/// ```text
56///  |x'|   | m11 m12 m13 m14 |   |x|
57///  |y'|   | m21 m22 m23 m24 |   |y|
58///  |z'| = | m31 m32 m33 m34 | x |z|
59///  |w |   | m41 m42 m43 m44 |   |1|
60/// ```
61///
62/// The translation terms are `m41`, `m42` and `m43`.
63#[repr(C)]
64#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
65#[cfg_attr(
66    feature = "serde",
67    serde(bound(serialize = "T: Serialize", deserialize = "T: Deserialize<'de>"))
68)]
69#[rustfmt::skip]
70pub struct Transform3D<T, Src, Dst> {
71    pub m11: T, pub m12: T, pub m13: T, pub m14: T,
72    pub m21: T, pub m22: T, pub m23: T, pub m24: T,
73    pub m31: T, pub m32: T, pub m33: T, pub m34: T,
74    pub m41: T, pub m42: T, pub m43: T, pub m44: T,
75    #[doc(hidden)]
76    pub _unit: PhantomData<(Src, Dst)>,
77}
78
79#[cfg(feature = "arbitrary")]
80impl<'a, T, Src, Dst> arbitrary::Arbitrary<'a> for Transform3D<T, Src, Dst>
81where
82    T: arbitrary::Arbitrary<'a>,
83{
84    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
85        let (m11, m12, m13, m14) = arbitrary::Arbitrary::arbitrary(u)?;
86        let (m21, m22, m23, m24) = arbitrary::Arbitrary::arbitrary(u)?;
87        let (m31, m32, m33, m34) = arbitrary::Arbitrary::arbitrary(u)?;
88        let (m41, m42, m43, m44) = arbitrary::Arbitrary::arbitrary(u)?;
89
90        Ok(Transform3D {
91            m11,
92            m12,
93            m13,
94            m14,
95            m21,
96            m22,
97            m23,
98            m24,
99            m31,
100            m32,
101            m33,
102            m34,
103            m41,
104            m42,
105            m43,
106            m44,
107            _unit: PhantomData,
108        })
109    }
110}
111
112#[cfg(feature = "bytemuck")]
113unsafe impl<T: Zeroable, Src, Dst> Zeroable for Transform3D<T, Src, Dst> {}
114
115#[cfg(feature = "bytemuck")]
116unsafe impl<T: Pod, Src: 'static, Dst: 'static> Pod for Transform3D<T, Src, Dst> {}
117
118#[cfg(feature = "malloc_size_of")]
119impl<T: MallocSizeOf, Src, Dst> MallocSizeOf for Transform3D<T, Src, Dst> {
120    fn size_of(&self, ops: &mut MallocSizeOfOps) -> usize {
121        self.m11.size_of(ops)
122            + self.m12.size_of(ops)
123            + self.m13.size_of(ops)
124            + self.m14.size_of(ops)
125            + self.m21.size_of(ops)
126            + self.m22.size_of(ops)
127            + self.m23.size_of(ops)
128            + self.m24.size_of(ops)
129            + self.m31.size_of(ops)
130            + self.m32.size_of(ops)
131            + self.m33.size_of(ops)
132            + self.m34.size_of(ops)
133            + self.m41.size_of(ops)
134            + self.m42.size_of(ops)
135            + self.m43.size_of(ops)
136            + self.m44.size_of(ops)
137    }
138}
139
140impl<T: Copy, Src, Dst> Copy for Transform3D<T, Src, Dst> {}
141
142impl<T: Clone, Src, Dst> Clone for Transform3D<T, Src, Dst> {
143    fn clone(&self) -> Self {
144        Transform3D {
145            m11: self.m11.clone(),
146            m12: self.m12.clone(),
147            m13: self.m13.clone(),
148            m14: self.m14.clone(),
149            m21: self.m21.clone(),
150            m22: self.m22.clone(),
151            m23: self.m23.clone(),
152            m24: self.m24.clone(),
153            m31: self.m31.clone(),
154            m32: self.m32.clone(),
155            m33: self.m33.clone(),
156            m34: self.m34.clone(),
157            m41: self.m41.clone(),
158            m42: self.m42.clone(),
159            m43: self.m43.clone(),
160            m44: self.m44.clone(),
161            _unit: PhantomData,
162        }
163    }
164}
165
166impl<T, Src, Dst> Eq for Transform3D<T, Src, Dst> where T: Eq {}
167
168impl<T, Src, Dst> PartialEq for Transform3D<T, Src, Dst>
169where
170    T: PartialEq,
171{
172    fn eq(&self, other: &Self) -> bool {
173        self.m11 == other.m11
174            && self.m12 == other.m12
175            && self.m13 == other.m13
176            && self.m14 == other.m14
177            && self.m21 == other.m21
178            && self.m22 == other.m22
179            && self.m23 == other.m23
180            && self.m24 == other.m24
181            && self.m31 == other.m31
182            && self.m32 == other.m32
183            && self.m33 == other.m33
184            && self.m34 == other.m34
185            && self.m41 == other.m41
186            && self.m42 == other.m42
187            && self.m43 == other.m43
188            && self.m44 == other.m44
189    }
190}
191
192impl<T, Src, Dst> Hash for Transform3D<T, Src, Dst>
193where
194    T: Hash,
195{
196    fn hash<H: core::hash::Hasher>(&self, h: &mut H) {
197        self.m11.hash(h);
198        self.m12.hash(h);
199        self.m13.hash(h);
200        self.m14.hash(h);
201        self.m21.hash(h);
202        self.m22.hash(h);
203        self.m23.hash(h);
204        self.m24.hash(h);
205        self.m31.hash(h);
206        self.m32.hash(h);
207        self.m33.hash(h);
208        self.m34.hash(h);
209        self.m41.hash(h);
210        self.m42.hash(h);
211        self.m43.hash(h);
212        self.m44.hash(h);
213    }
214}
215
216impl<T, Src, Dst> Transform3D<T, Src, Dst> {
217    /// Create a transform specifying all of it's component as a 4 by 4 matrix.
218    ///
219    /// Components are specified following column-major-column-vector matrix notation.
220    /// For example, the translation terms m41, m42, m43 are the 13rd, 14th and 15th parameters.
221    ///
222    /// ```
223    /// use euclid::default::Transform3D;
224    /// let tx = 1.0;
225    /// let ty = 2.0;
226    /// let tz = 3.0;
227    /// let translation = Transform3D::new(
228    ///   1.0, 0.0, 0.0, 0.0,
229    ///   0.0, 1.0, 0.0, 0.0,
230    ///   0.0, 0.0, 1.0, 0.0,
231    ///   tx,  ty,  tz,  1.0,
232    /// );
233    /// ```
234    #[inline]
235    #[allow(clippy::too_many_arguments)]
236    #[rustfmt::skip]
237    pub const fn new(
238        m11: T, m12: T, m13: T, m14: T,
239        m21: T, m22: T, m23: T, m24: T,
240        m31: T, m32: T, m33: T, m34: T,
241        m41: T, m42: T, m43: T, m44: T,
242    ) -> Self {
243        Transform3D {
244            m11, m12, m13, m14,
245            m21, m22, m23, m24,
246            m31, m32, m33, m34,
247            m41, m42, m43, m44,
248            _unit: PhantomData,
249        }
250    }
251
252    /// Create a transform representing a 2d transformation from the components
253    /// of a 2 by 3 matrix transformation.
254    ///
255    /// Components follow the column-major-column-vector notation (m41 and m42
256    /// representing the translation terms).
257    ///
258    /// ```text
259    /// m11  m12   0   0
260    /// m21  m22   0   0
261    ///   0    0   1   0
262    /// m41  m42   0   1
263    /// ```
264    #[inline]
265    #[rustfmt::skip]
266    pub fn new_2d(m11: T, m12: T, m21: T, m22: T, m41: T, m42: T) -> Self
267    where
268        T: Zero + One,
269    {
270        let _0 = || T::zero();
271        let _1 = || T::one();
272
273        Self::new(
274            m11,  m12,  _0(), _0(),
275            m21,  m22,  _0(), _0(),
276            _0(), _0(), _1(), _0(),
277            m41,  m42,  _0(), _1()
278       )
279    }
280
281    /// Returns `true` if this transform can be represented with a `Transform2D`.
282    ///
283    /// See <https://drafts.csswg.org/css-transforms/#2d-transform>
284    #[inline]
285    pub fn is_2d(&self) -> bool
286    where
287        T: Zero + One + PartialEq,
288    {
289        let (_0, _1): (T, T) = (Zero::zero(), One::one());
290        self.m31 == _0
291            && self.m32 == _0
292            && self.m13 == _0
293            && self.m23 == _0
294            && self.m43 == _0
295            && self.m14 == _0
296            && self.m24 == _0
297            && self.m34 == _0
298            && self.m33 == _1
299            && self.m44 == _1
300    }
301}
302
303impl<T: Copy, Src, Dst> Transform3D<T, Src, Dst> {
304    /// Returns an array containing this transform's terms.
305    ///
306    /// The terms are laid out in the same order as they are
307    /// specified in `Transform3D::new`, that is following the
308    /// column-major-column-vector matrix notation.
309    ///
310    /// For example the translation terms are found on the
311    /// 13th, 14th and 15th slots of the array.
312    #[inline]
313    #[rustfmt::skip]
314    pub fn to_array(&self) -> [T; 16] {
315        [
316            self.m11, self.m12, self.m13, self.m14,
317            self.m21, self.m22, self.m23, self.m24,
318            self.m31, self.m32, self.m33, self.m34,
319            self.m41, self.m42, self.m43, self.m44
320        ]
321    }
322
323    /// Returns an array containing this transform's terms transposed.
324    ///
325    /// The terms are laid out in transposed order from the same order of
326    /// `Transform3D::new` and `Transform3D::to_array`, that is following
327    /// the row-major-column-vector matrix notation.
328    ///
329    /// For example the translation terms are found at indices 3, 7 and 11
330    /// of the array.
331    #[inline]
332    #[rustfmt::skip]
333    pub fn to_array_transposed(&self) -> [T; 16] {
334        [
335            self.m11, self.m21, self.m31, self.m41,
336            self.m12, self.m22, self.m32, self.m42,
337            self.m13, self.m23, self.m33, self.m43,
338            self.m14, self.m24, self.m34, self.m44
339        ]
340    }
341
342    /// Equivalent to `to_array` with elements packed four at a time
343    /// in an array of arrays.
344    #[inline]
345    #[rustfmt::skip]
346    pub fn to_arrays(&self) -> [[T; 4]; 4] {
347        [
348            [self.m11, self.m12, self.m13, self.m14],
349            [self.m21, self.m22, self.m23, self.m24],
350            [self.m31, self.m32, self.m33, self.m34],
351            [self.m41, self.m42, self.m43, self.m44],
352        ]
353    }
354
355    /// Equivalent to `to_array_transposed` with elements packed
356    /// four at a time in an array of arrays.
357    #[inline]
358    #[rustfmt::skip]
359    pub fn to_arrays_transposed(&self) -> [[T; 4]; 4] {
360        [
361            [self.m11, self.m21, self.m31, self.m41],
362            [self.m12, self.m22, self.m32, self.m42],
363            [self.m13, self.m23, self.m33, self.m43],
364            [self.m14, self.m24, self.m34, self.m44],
365        ]
366    }
367
368    /// Create a transform providing its components via an array
369    /// of 16 elements instead of as individual parameters.
370    ///
371    /// The order of the components corresponds to the
372    /// column-major-column-vector matrix notation (the same order
373    /// as `Transform3D::new`).
374    #[inline]
375    #[rustfmt::skip]
376    pub fn from_array(array: [T; 16]) -> Self {
377        Self::new(
378            array[0],  array[1],  array[2],  array[3],
379            array[4],  array[5],  array[6],  array[7],
380            array[8],  array[9],  array[10], array[11],
381            array[12], array[13], array[14], array[15],
382        )
383    }
384
385    /// Equivalent to `from_array` with elements packed four at a time
386    /// in an array of arrays.
387    ///
388    /// The order of the components corresponds to the
389    /// column-major-column-vector matrix notation (the same order
390    /// as `Transform3D::new`).
391    #[inline]
392    #[rustfmt::skip]
393    pub fn from_arrays(array: [[T; 4]; 4]) -> Self {
394        Self::new(
395            array[0][0], array[0][1], array[0][2], array[0][3],
396            array[1][0], array[1][1], array[1][2], array[1][3],
397            array[2][0], array[2][1], array[2][2], array[2][3],
398            array[3][0], array[3][1], array[3][2], array[3][3],
399        )
400    }
401
402    /// Tag a unitless value with units.
403    #[inline]
404    #[rustfmt::skip]
405    pub fn from_untyped(m: &Transform3D<T, UnknownUnit, UnknownUnit>) -> Self {
406        Transform3D::new(
407            m.m11, m.m12, m.m13, m.m14,
408            m.m21, m.m22, m.m23, m.m24,
409            m.m31, m.m32, m.m33, m.m34,
410            m.m41, m.m42, m.m43, m.m44,
411        )
412    }
413
414    /// Drop the units, preserving only the numeric value.
415    #[inline]
416    #[rustfmt::skip]
417    pub fn to_untyped(&self) -> Transform3D<T, UnknownUnit, UnknownUnit> {
418        Transform3D::new(
419            self.m11, self.m12, self.m13, self.m14,
420            self.m21, self.m22, self.m23, self.m24,
421            self.m31, self.m32, self.m33, self.m34,
422            self.m41, self.m42, self.m43, self.m44,
423        )
424    }
425
426    /// Returns the same transform with a different source unit.
427    #[inline]
428    #[rustfmt::skip]
429    pub fn with_source<NewSrc>(&self) -> Transform3D<T, NewSrc, Dst> {
430        Transform3D::new(
431            self.m11, self.m12, self.m13, self.m14,
432            self.m21, self.m22, self.m23, self.m24,
433            self.m31, self.m32, self.m33, self.m34,
434            self.m41, self.m42, self.m43, self.m44,
435        )
436    }
437
438    /// Returns the same transform with a different destination unit.
439    #[inline]
440    #[rustfmt::skip]
441    pub fn with_destination<NewDst>(&self) -> Transform3D<T, Src, NewDst> {
442        Transform3D::new(
443            self.m11, self.m12, self.m13, self.m14,
444            self.m21, self.m22, self.m23, self.m24,
445            self.m31, self.m32, self.m33, self.m34,
446            self.m41, self.m42, self.m43, self.m44,
447        )
448    }
449
450    /// Create a 2D transform picking the relevant terms from this transform.
451    ///
452    /// This method assumes that self represents a 2d transformation, callers
453    /// should check that [`is_2d`] returns `true` beforehand.
454    ///
455    /// [`is_2d`]: Self::is_2d
456    pub fn to_2d(&self) -> Transform2D<T, Src, Dst> {
457        Transform2D::new(self.m11, self.m12, self.m21, self.m22, self.m41, self.m42)
458    }
459
460    /// Returns true if self can be represented as a 2d scale+offset
461    /// transform.
462    pub fn is_scale_offset_2d_eps(&self, epsilon: T) -> bool
463    where
464        T: Signed + PartialOrd,
465    {
466        (self.m12.abs() < epsilon)
467            & (self.m13.abs() < epsilon)
468            & (self.m14.abs() < epsilon)
469            & (self.m21.abs() < epsilon)
470            & (self.m23.abs() < epsilon)
471            & (self.m24.abs() < epsilon)
472            & (self.m31.abs() < epsilon)
473            & (self.m32.abs() < epsilon)
474            & ((self.m33 - T::one()).abs() < epsilon)
475            & (self.m34.abs() < epsilon)
476            & (self.m43.abs() < epsilon)
477            & ((self.m44 - T::one()).abs() < epsilon)
478    }
479
480    /// Creates a 2D scale+offset transform from the current transform.
481    ///
482    /// This method assumes that self can be represented as a 2d scale+offset
483    /// transformation, callers should check that [`is_scale_offset_2d`] or
484    /// [`is_scale_offset_2d_eps`] returns `true` beforehand.
485    pub fn to_scale_offset2d(&self) -> Option<ScaleOffset2D<T, Src, Dst>>
486    where
487        T: Signed + One + PartialOrd,
488    {
489        Some(ScaleOffset2D {
490            sx: self.m11,
491            sy: self.m22,
492            tx: self.m41,
493            ty: self.m42,
494            _unit: PhantomData,
495        })
496    }
497}
498
499impl<T, Src, Dst> Transform3D<T, Src, Dst>
500where
501    T: Zero + One,
502{
503    /// Creates an identity matrix:
504    ///
505    /// ```text
506    /// 1 0 0 0
507    /// 0 1 0 0
508    /// 0 0 1 0
509    /// 0 0 0 1
510    /// ```
511    #[inline]
512    pub fn identity() -> Self {
513        Self::translation(T::zero(), T::zero(), T::zero())
514    }
515
516    /// Intentional not public, because it checks for exact equivalence
517    /// while most consumers will probably want some sort of approximate
518    /// equivalence to deal with floating-point errors.
519    #[inline]
520    fn is_identity(&self) -> bool
521    where
522        T: PartialEq,
523    {
524        *self == Self::identity()
525    }
526
527    /// Create a simple perspective transform, projecting to the plane `z = -d`.
528    ///
529    /// ```text
530    /// 1   0   0   0
531    /// 0   1   0   0
532    /// 0   0   1 -1/d
533    /// 0   0   0   1
534    /// ```
535    ///
536    /// See <https://drafts.csswg.org/css-transforms-2/#PerspectiveDefined>.
537    pub fn perspective(d: T) -> Self
538    where
539        T: Neg<Output = T> + Div<Output = T>,
540    {
541        let _0 = || T::zero();
542        let _1 = || T::one();
543
544        Self::new(
545            _1(),
546            _0(),
547            _0(),
548            _0(),
549            _0(),
550            _1(),
551            _0(),
552            _0(),
553            _0(),
554            _0(),
555            _1(),
556            -_1() / d,
557            _0(),
558            _0(),
559            _0(),
560            _1(),
561        )
562    }
563}
564
565/// Methods for combining generic transformations
566impl<T, Src, Dst> Transform3D<T, Src, Dst>
567where
568    T: Copy + Add<Output = T> + Mul<Output = T>,
569{
570    /// Returns the multiplication of the two matrices such that mat's transformation
571    /// applies after self's transformation.
572    ///
573    /// Assuming row vectors, this is equivalent to self * mat
574    #[must_use]
575    #[rustfmt::skip]
576    pub fn then<NewDst>(&self, other: &Transform3D<T, Dst, NewDst>) -> Transform3D<T, Src, NewDst> {
577        Transform3D::new(
578            self.m11 * other.m11  +  self.m12 * other.m21  +  self.m13 * other.m31  +  self.m14 * other.m41,
579            self.m11 * other.m12  +  self.m12 * other.m22  +  self.m13 * other.m32  +  self.m14 * other.m42,
580            self.m11 * other.m13  +  self.m12 * other.m23  +  self.m13 * other.m33  +  self.m14 * other.m43,
581            self.m11 * other.m14  +  self.m12 * other.m24  +  self.m13 * other.m34  +  self.m14 * other.m44,
582
583            self.m21 * other.m11  +  self.m22 * other.m21  +  self.m23 * other.m31  +  self.m24 * other.m41,
584            self.m21 * other.m12  +  self.m22 * other.m22  +  self.m23 * other.m32  +  self.m24 * other.m42,
585            self.m21 * other.m13  +  self.m22 * other.m23  +  self.m23 * other.m33  +  self.m24 * other.m43,
586            self.m21 * other.m14  +  self.m22 * other.m24  +  self.m23 * other.m34  +  self.m24 * other.m44,
587
588            self.m31 * other.m11  +  self.m32 * other.m21  +  self.m33 * other.m31  +  self.m34 * other.m41,
589            self.m31 * other.m12  +  self.m32 * other.m22  +  self.m33 * other.m32  +  self.m34 * other.m42,
590            self.m31 * other.m13  +  self.m32 * other.m23  +  self.m33 * other.m33  +  self.m34 * other.m43,
591            self.m31 * other.m14  +  self.m32 * other.m24  +  self.m33 * other.m34  +  self.m34 * other.m44,
592
593            self.m41 * other.m11  +  self.m42 * other.m21  +  self.m43 * other.m31  +  self.m44 * other.m41,
594            self.m41 * other.m12  +  self.m42 * other.m22  +  self.m43 * other.m32  +  self.m44 * other.m42,
595            self.m41 * other.m13  +  self.m42 * other.m23  +  self.m43 * other.m33  +  self.m44 * other.m43,
596            self.m41 * other.m14  +  self.m42 * other.m24  +  self.m43 * other.m34  +  self.m44 * other.m44,
597        )
598    }
599}
600
601/// Methods for creating and combining translation transformations
602impl<T, Src, Dst> Transform3D<T, Src, Dst>
603where
604    T: Zero + One,
605{
606    /// Create a 3d translation transform:
607    ///
608    /// ```text
609    /// 1 0 0 0
610    /// 0 1 0 0
611    /// 0 0 1 0
612    /// x y z 1
613    /// ```
614    #[inline]
615    #[rustfmt::skip]
616    pub fn translation(x: T, y: T, z: T) -> Self {
617        let _0 = || T::zero();
618        let _1 = || T::one();
619
620        Self::new(
621            _1(), _0(), _0(), _0(),
622            _0(), _1(), _0(), _0(),
623            _0(), _0(), _1(), _0(),
624             x,    y,    z,   _1(),
625        )
626    }
627
628    /// Returns a transform with a translation applied before self's transformation.
629    #[must_use]
630    pub fn pre_translate(&self, v: Vector3D<T, Src>) -> Self
631    where
632        T: Copy + Add<Output = T> + Mul<Output = T>,
633    {
634        Transform3D::translation(v.x, v.y, v.z).then(self)
635    }
636
637    /// Returns a transform with a translation applied after self's transformation.
638    #[must_use]
639    pub fn then_translate(&self, v: Vector3D<T, Dst>) -> Self
640    where
641        T: Copy + Add<Output = T> + Mul<Output = T>,
642    {
643        self.then(&Transform3D::translation(v.x, v.y, v.z))
644    }
645}
646
647/// Methods for creating and combining scale transformations
648impl<T, Src, Dst> Transform3D<T, Src, Dst>
649where
650    T: Zero + One,
651{
652    /// Create a 3d scale transform:
653    ///
654    /// ```text
655    /// x 0 0 0
656    /// 0 y 0 0
657    /// 0 0 z 0
658    /// 0 0 0 1
659    /// ```
660    #[inline]
661    #[rustfmt::skip]
662    pub fn scale(x: T, y: T, z: T) -> Self {
663        let _0 = || T::zero();
664        let _1 = || T::one();
665
666        Self::new(
667             x,   _0(), _0(), _0(),
668            _0(),  y,   _0(), _0(),
669            _0(), _0(),  z,   _0(),
670            _0(), _0(), _0(), _1(),
671        )
672    }
673
674    /// Returns a transform with a scale applied before self's transformation.
675    #[must_use]
676    #[rustfmt::skip]
677    pub fn pre_scale(&self, x: T, y: T, z: T) -> Self
678    where
679        T: Copy + Add<Output = T> + Mul<Output = T>,
680    {
681        Transform3D::new(
682            self.m11 * x, self.m12 * x, self.m13 * x, self.m14 * x,
683            self.m21 * y, self.m22 * y, self.m23 * y, self.m24 * y,
684            self.m31 * z, self.m32 * z, self.m33 * z, self.m34 * z,
685            self.m41    , self.m42,     self.m43,     self.m44
686        )
687    }
688
689    /// Returns a transform with a scale applied after self's transformation.
690    #[must_use]
691    pub fn then_scale(&self, x: T, y: T, z: T) -> Self
692    where
693        T: Copy + Add<Output = T> + Mul<Output = T>,
694    {
695        self.then(&Transform3D::scale(x, y, z))
696    }
697}
698
699/// Methods for apply transformations to objects
700impl<T, Src, Dst> Transform3D<T, Src, Dst>
701where
702    T: Copy + Add<Output = T> + Mul<Output = T>,
703{
704    /// Returns the homogeneous vector corresponding to the transformed 2d point.
705    ///
706    /// The input point must be use the unit Src, and the returned point has the unit Dst.
707    #[inline]
708    #[rustfmt::skip]
709    pub fn transform_point2d_homogeneous(
710        &self, p: Point2D<T, Src>
711    ) -> HomogeneousVector<T, Dst> {
712        let x = p.x * self.m11 + p.y * self.m21 + self.m41;
713        let y = p.x * self.m12 + p.y * self.m22 + self.m42;
714        let z = p.x * self.m13 + p.y * self.m23 + self.m43;
715        let w = p.x * self.m14 + p.y * self.m24 + self.m44;
716
717        HomogeneousVector::new(x, y, z, w)
718    }
719
720    /// Returns the given 2d point transformed by this transform, if the transform makes sense,
721    /// or `None` otherwise.
722    ///
723    /// The input point must be use the unit Src, and the returned point has the unit Dst.
724    #[inline]
725    pub fn transform_point2d(&self, p: Point2D<T, Src>) -> Option<Point2D<T, Dst>>
726    where
727        T: Div<Output = T> + Zero + PartialOrd,
728    {
729        //Note: could use `transform_point2d_homogeneous()` but it would waste the calculus of `z`
730        let w = p.x * self.m14 + p.y * self.m24 + self.m44;
731        if w > T::zero() {
732            let x = p.x * self.m11 + p.y * self.m21 + self.m41;
733            let y = p.x * self.m12 + p.y * self.m22 + self.m42;
734
735            Some(Point2D::new(x / w, y / w))
736        } else {
737            None
738        }
739    }
740
741    /// Returns the given 2d vector transformed by this matrix.
742    ///
743    /// The input point must be use the unit Src, and the returned point has the unit Dst.
744    #[inline]
745    pub fn transform_vector2d(&self, v: Vector2D<T, Src>) -> Vector2D<T, Dst> {
746        vec2(
747            v.x * self.m11 + v.y * self.m21,
748            v.x * self.m12 + v.y * self.m22,
749        )
750    }
751
752    /// Returns the homogeneous vector corresponding to the transformed 3d point.
753    ///
754    /// The input point must be use the unit Src, and the returned point has the unit Dst.
755    #[inline]
756    pub fn transform_point3d_homogeneous(&self, p: Point3D<T, Src>) -> HomogeneousVector<T, Dst> {
757        let x = p.x * self.m11 + p.y * self.m21 + p.z * self.m31 + self.m41;
758        let y = p.x * self.m12 + p.y * self.m22 + p.z * self.m32 + self.m42;
759        let z = p.x * self.m13 + p.y * self.m23 + p.z * self.m33 + self.m43;
760        let w = p.x * self.m14 + p.y * self.m24 + p.z * self.m34 + self.m44;
761
762        HomogeneousVector::new(x, y, z, w)
763    }
764
765    /// Returns the given 3d point transformed by this transform, if the transform makes sense,
766    /// or `None` otherwise.
767    ///
768    /// The input point must be use the unit Src, and the returned point has the unit Dst.
769    #[inline]
770    pub fn transform_point3d(&self, p: Point3D<T, Src>) -> Option<Point3D<T, Dst>>
771    where
772        T: Div<Output = T> + Zero + PartialOrd,
773    {
774        self.transform_point3d_homogeneous(p).to_point3d()
775    }
776
777    /// Returns the given 3d vector transformed by this matrix.
778    ///
779    /// The input point must be use the unit Src, and the returned point has the unit Dst.
780    #[inline]
781    pub fn transform_vector3d(&self, v: Vector3D<T, Src>) -> Vector3D<T, Dst> {
782        vec3(
783            v.x * self.m11 + v.y * self.m21 + v.z * self.m31,
784            v.x * self.m12 + v.y * self.m22 + v.z * self.m32,
785            v.x * self.m13 + v.y * self.m23 + v.z * self.m33,
786        )
787    }
788
789    /// Returns a rectangle that encompasses the result of transforming the given rectangle by this
790    /// transform, if the transform makes sense for it, or `None` otherwise.
791    pub fn outer_transformed_rect(&self, rect: &Rect<T, Src>) -> Option<Rect<T, Dst>>
792    where
793        T: Sub<Output = T> + Div<Output = T> + Zero + PartialOrd,
794    {
795        let min = rect.min();
796        let max = rect.max();
797        Some(Rect::from_points(&[
798            self.transform_point2d(min)?,
799            self.transform_point2d(max)?,
800            self.transform_point2d(point2(max.x, min.y))?,
801            self.transform_point2d(point2(min.x, max.y))?,
802        ]))
803    }
804
805    /// Returns a 2d box that encompasses the result of transforming the given box by this
806    /// transform, if the transform makes sense for it, or `None` otherwise.
807    pub fn outer_transformed_box2d(&self, b: &Box2D<T, Src>) -> Option<Box2D<T, Dst>>
808    where
809        T: Sub<Output = T> + Div<Output = T> + Zero + PartialOrd,
810    {
811        Some(Box2D::from_points(&[
812            self.transform_point2d(b.min)?,
813            self.transform_point2d(b.max)?,
814            self.transform_point2d(point2(b.max.x, b.min.y))?,
815            self.transform_point2d(point2(b.min.x, b.max.y))?,
816        ]))
817    }
818
819    /// Returns a 3d box that encompasses the result of transforming the given box by this
820    /// transform, if the transform makes sense for it, or `None` otherwise.
821    pub fn outer_transformed_box3d(&self, b: &Box3D<T, Src>) -> Option<Box3D<T, Dst>>
822    where
823        T: Sub<Output = T> + Div<Output = T> + Zero + PartialOrd,
824    {
825        Some(Box3D::from_points(&[
826            self.transform_point3d(point3(b.min.x, b.min.y, b.min.z))?,
827            self.transform_point3d(point3(b.min.x, b.min.y, b.max.z))?,
828            self.transform_point3d(point3(b.min.x, b.max.y, b.min.z))?,
829            self.transform_point3d(point3(b.min.x, b.max.y, b.max.z))?,
830            self.transform_point3d(point3(b.max.x, b.min.y, b.min.z))?,
831            self.transform_point3d(point3(b.max.x, b.min.y, b.max.z))?,
832            self.transform_point3d(point3(b.max.x, b.max.y, b.min.z))?,
833            self.transform_point3d(point3(b.max.x, b.max.y, b.max.z))?,
834        ]))
835    }
836}
837
838impl<T, Src, Dst> Transform3D<T, Src, Dst>
839where
840    T: Copy
841        + Add<T, Output = T>
842        + Sub<T, Output = T>
843        + Mul<T, Output = T>
844        + Div<T, Output = T>
845        + Neg<Output = T>
846        + PartialOrd
847        + One
848        + Zero,
849{
850    /// Create an orthogonal projection transform.
851    #[rustfmt::skip]
852    pub fn ortho(left: T, right: T,
853                 bottom: T, top: T,
854                 near: T, far: T) -> Self {
855        let tx = -((right + left) / (right - left));
856        let ty = -((top + bottom) / (top - bottom));
857        let tz = -((far + near) / (far - near));
858
859        let (_0, _1): (T, T) = (Zero::zero(), One::one());
860        let _2 = _1 + _1;
861        Transform3D::new(
862            _2 / (right - left), _0                 , _0                , _0,
863            _0                 , _2 / (top - bottom), _0                , _0,
864            _0                 , _0                 , -_2 / (far - near), _0,
865            tx                 , ty                 , tz                , _1
866        )
867    }
868
869    /// Check whether shapes on the XY plane with Z pointing towards the
870    /// screen transformed by this matrix would be facing back.
871    #[rustfmt::skip]
872    pub fn is_backface_visible(&self) -> bool {
873        // inverse().m33 < 0;
874        let det = self.determinant();
875        let m33 = self.m12 * self.m24 * self.m41 - self.m14 * self.m22 * self.m41 +
876                  self.m14 * self.m21 * self.m42 - self.m11 * self.m24 * self.m42 -
877                  self.m12 * self.m21 * self.m44 + self.m11 * self.m22 * self.m44;
878        let _0: T = Zero::zero();
879        (m33 * det) < _0
880    }
881
882    /// Returns whether it is possible to compute the inverse transform.
883    #[inline]
884    pub fn is_invertible(&self) -> bool {
885        self.determinant() != Zero::zero()
886    }
887
888    /// Returns the inverse transform if possible.
889    pub fn inverse(&self) -> Option<Transform3D<T, Dst, Src>> {
890        let det = self.determinant();
891
892        if det == Zero::zero() {
893            return None;
894        }
895
896        // todo(gw): this could be made faster by special casing
897        // for simpler transform types.
898        #[rustfmt::skip]
899        let m = Transform3D::new(
900            self.m23*self.m34*self.m42 - self.m24*self.m33*self.m42 +
901            self.m24*self.m32*self.m43 - self.m22*self.m34*self.m43 -
902            self.m23*self.m32*self.m44 + self.m22*self.m33*self.m44,
903
904            self.m14*self.m33*self.m42 - self.m13*self.m34*self.m42 -
905            self.m14*self.m32*self.m43 + self.m12*self.m34*self.m43 +
906            self.m13*self.m32*self.m44 - self.m12*self.m33*self.m44,
907
908            self.m13*self.m24*self.m42 - self.m14*self.m23*self.m42 +
909            self.m14*self.m22*self.m43 - self.m12*self.m24*self.m43 -
910            self.m13*self.m22*self.m44 + self.m12*self.m23*self.m44,
911
912            self.m14*self.m23*self.m32 - self.m13*self.m24*self.m32 -
913            self.m14*self.m22*self.m33 + self.m12*self.m24*self.m33 +
914            self.m13*self.m22*self.m34 - self.m12*self.m23*self.m34,
915
916            self.m24*self.m33*self.m41 - self.m23*self.m34*self.m41 -
917            self.m24*self.m31*self.m43 + self.m21*self.m34*self.m43 +
918            self.m23*self.m31*self.m44 - self.m21*self.m33*self.m44,
919
920            self.m13*self.m34*self.m41 - self.m14*self.m33*self.m41 +
921            self.m14*self.m31*self.m43 - self.m11*self.m34*self.m43 -
922            self.m13*self.m31*self.m44 + self.m11*self.m33*self.m44,
923
924            self.m14*self.m23*self.m41 - self.m13*self.m24*self.m41 -
925            self.m14*self.m21*self.m43 + self.m11*self.m24*self.m43 +
926            self.m13*self.m21*self.m44 - self.m11*self.m23*self.m44,
927
928            self.m13*self.m24*self.m31 - self.m14*self.m23*self.m31 +
929            self.m14*self.m21*self.m33 - self.m11*self.m24*self.m33 -
930            self.m13*self.m21*self.m34 + self.m11*self.m23*self.m34,
931
932            self.m22*self.m34*self.m41 - self.m24*self.m32*self.m41 +
933            self.m24*self.m31*self.m42 - self.m21*self.m34*self.m42 -
934            self.m22*self.m31*self.m44 + self.m21*self.m32*self.m44,
935
936            self.m14*self.m32*self.m41 - self.m12*self.m34*self.m41 -
937            self.m14*self.m31*self.m42 + self.m11*self.m34*self.m42 +
938            self.m12*self.m31*self.m44 - self.m11*self.m32*self.m44,
939
940            self.m12*self.m24*self.m41 - self.m14*self.m22*self.m41 +
941            self.m14*self.m21*self.m42 - self.m11*self.m24*self.m42 -
942            self.m12*self.m21*self.m44 + self.m11*self.m22*self.m44,
943
944            self.m14*self.m22*self.m31 - self.m12*self.m24*self.m31 -
945            self.m14*self.m21*self.m32 + self.m11*self.m24*self.m32 +
946            self.m12*self.m21*self.m34 - self.m11*self.m22*self.m34,
947
948            self.m23*self.m32*self.m41 - self.m22*self.m33*self.m41 -
949            self.m23*self.m31*self.m42 + self.m21*self.m33*self.m42 +
950            self.m22*self.m31*self.m43 - self.m21*self.m32*self.m43,
951
952            self.m12*self.m33*self.m41 - self.m13*self.m32*self.m41 +
953            self.m13*self.m31*self.m42 - self.m11*self.m33*self.m42 -
954            self.m12*self.m31*self.m43 + self.m11*self.m32*self.m43,
955
956            self.m13*self.m22*self.m41 - self.m12*self.m23*self.m41 -
957            self.m13*self.m21*self.m42 + self.m11*self.m23*self.m42 +
958            self.m12*self.m21*self.m43 - self.m11*self.m22*self.m43,
959
960            self.m12*self.m23*self.m31 - self.m13*self.m22*self.m31 +
961            self.m13*self.m21*self.m32 - self.m11*self.m23*self.m32 -
962            self.m12*self.m21*self.m33 + self.m11*self.m22*self.m33
963        );
964
965        let _1: T = One::one();
966        Some(m.mul_s(_1 / det))
967    }
968
969    /// Compute the determinant of the transform.
970    #[rustfmt::skip]
971    pub fn determinant(&self) -> T {
972        self.m14 * self.m23 * self.m32 * self.m41 -
973        self.m13 * self.m24 * self.m32 * self.m41 -
974        self.m14 * self.m22 * self.m33 * self.m41 +
975        self.m12 * self.m24 * self.m33 * self.m41 +
976        self.m13 * self.m22 * self.m34 * self.m41 -
977        self.m12 * self.m23 * self.m34 * self.m41 -
978        self.m14 * self.m23 * self.m31 * self.m42 +
979        self.m13 * self.m24 * self.m31 * self.m42 +
980        self.m14 * self.m21 * self.m33 * self.m42 -
981        self.m11 * self.m24 * self.m33 * self.m42 -
982        self.m13 * self.m21 * self.m34 * self.m42 +
983        self.m11 * self.m23 * self.m34 * self.m42 +
984        self.m14 * self.m22 * self.m31 * self.m43 -
985        self.m12 * self.m24 * self.m31 * self.m43 -
986        self.m14 * self.m21 * self.m32 * self.m43 +
987        self.m11 * self.m24 * self.m32 * self.m43 +
988        self.m12 * self.m21 * self.m34 * self.m43 -
989        self.m11 * self.m22 * self.m34 * self.m43 -
990        self.m13 * self.m22 * self.m31 * self.m44 +
991        self.m12 * self.m23 * self.m31 * self.m44 +
992        self.m13 * self.m21 * self.m32 * self.m44 -
993        self.m11 * self.m23 * self.m32 * self.m44 -
994        self.m12 * self.m21 * self.m33 * self.m44 +
995        self.m11 * self.m22 * self.m33 * self.m44
996    }
997
998    /// Multiplies all of the transform's component by a scalar and returns the result.
999    #[must_use]
1000    #[rustfmt::skip]
1001    pub fn mul_s(&self, x: T) -> Self {
1002        Transform3D::new(
1003            self.m11 * x, self.m12 * x, self.m13 * x, self.m14 * x,
1004            self.m21 * x, self.m22 * x, self.m23 * x, self.m24 * x,
1005            self.m31 * x, self.m32 * x, self.m33 * x, self.m34 * x,
1006            self.m41 * x, self.m42 * x, self.m43 * x, self.m44 * x
1007        )
1008    }
1009
1010    /// Convenience function to create a scale transform from a `Scale`.
1011    pub fn from_scale(scale: Scale<T, Src, Dst>) -> Self {
1012        Transform3D::scale(scale.get(), scale.get(), scale.get())
1013    }
1014}
1015
1016impl<T, Src, Dst> Transform3D<T, Src, Dst>
1017where
1018    T: Copy + Mul<Output = T> + Div<Output = T> + Zero + One + PartialEq,
1019{
1020    /// Returns a projection of this transform in 2d space.
1021    pub fn project_to_2d(&self) -> Self {
1022        let (_0, _1): (T, T) = (Zero::zero(), One::one());
1023
1024        let mut result = self.clone();
1025
1026        result.m31 = _0;
1027        result.m32 = _0;
1028        result.m13 = _0;
1029        result.m23 = _0;
1030        result.m33 = _1;
1031        result.m43 = _0;
1032        result.m34 = _0;
1033
1034        // Try to normalize perspective when possible to convert to a 2d matrix.
1035        // Some matrices, such as those derived from perspective transforms, can
1036        // modify m44 from 1, while leaving the rest of the fourth column
1037        // (m14, m24) at 0. In this case, after resetting the third row and
1038        // third column above, the value of m44 functions only to scale the
1039        // coordinate transform divide by W. The matrix can be converted to
1040        // a true 2D matrix by normalizing out the scaling effect of m44 on
1041        // the remaining components ahead of time.
1042        if self.m14 == _0 && self.m24 == _0 && self.m44 != _0 && self.m44 != _1 {
1043            let scale = _1 / self.m44;
1044            result.m11 = result.m11 * scale;
1045            result.m12 = result.m12 * scale;
1046            result.m21 = result.m21 * scale;
1047            result.m22 = result.m22 * scale;
1048            result.m41 = result.m41 * scale;
1049            result.m42 = result.m42 * scale;
1050            result.m44 = _1;
1051        }
1052
1053        result
1054    }
1055}
1056
1057impl<T: NumCast + Copy, Src, Dst> Transform3D<T, Src, Dst> {
1058    /// Cast from one numeric representation to another, preserving the units.
1059    #[inline]
1060    pub fn cast<NewT: NumCast>(&self) -> Transform3D<NewT, Src, Dst> {
1061        self.try_cast().unwrap()
1062    }
1063
1064    /// Fallible cast from one numeric representation to another, preserving the units.
1065    #[rustfmt::skip]
1066    pub fn try_cast<NewT: NumCast>(&self) -> Option<Transform3D<NewT, Src, Dst>> {
1067        match (NumCast::from(self.m11), NumCast::from(self.m12),
1068               NumCast::from(self.m13), NumCast::from(self.m14),
1069               NumCast::from(self.m21), NumCast::from(self.m22),
1070               NumCast::from(self.m23), NumCast::from(self.m24),
1071               NumCast::from(self.m31), NumCast::from(self.m32),
1072               NumCast::from(self.m33), NumCast::from(self.m34),
1073               NumCast::from(self.m41), NumCast::from(self.m42),
1074               NumCast::from(self.m43), NumCast::from(self.m44)) {
1075            (Some(m11), Some(m12), Some(m13), Some(m14),
1076             Some(m21), Some(m22), Some(m23), Some(m24),
1077             Some(m31), Some(m32), Some(m33), Some(m34),
1078             Some(m41), Some(m42), Some(m43), Some(m44)) => {
1079                Some(Transform3D::new(m11, m12, m13, m14,
1080                                      m21, m22, m23, m24,
1081                                      m31, m32, m33, m34,
1082                                      m41, m42, m43, m44))
1083            },
1084            _ => None
1085        }
1086    }
1087}
1088
1089impl<T, Src, Dst> Default for Transform3D<T, Src, Dst>
1090where
1091    T: Zero + One,
1092{
1093    /// Returns the [identity transform](Self::identity).
1094    fn default() -> Self {
1095        Self::identity()
1096    }
1097}
1098
1099impl<T, Src, Dst> fmt::Debug for Transform3D<T, Src, Dst>
1100where
1101    T: Copy + fmt::Debug + PartialEq + One + Zero,
1102{
1103    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1104        if self.is_identity() {
1105            write!(f, "[I]")
1106        } else {
1107            self.to_array().fmt(f)
1108        }
1109    }
1110}
1111
1112#[cfg(feature = "mint")]
1113impl<T, Src, Dst> From<mint::RowMatrix4<T>> for Transform3D<T, Src, Dst> {
1114    #[rustfmt::skip]
1115    fn from(m: mint::RowMatrix4<T>) -> Self {
1116        Transform3D {
1117            m11: m.x.x, m12: m.x.y, m13: m.x.z, m14: m.x.w,
1118            m21: m.y.x, m22: m.y.y, m23: m.y.z, m24: m.y.w,
1119            m31: m.z.x, m32: m.z.y, m33: m.z.z, m34: m.z.w,
1120            m41: m.w.x, m42: m.w.y, m43: m.w.z, m44: m.w.w,
1121            _unit: PhantomData,
1122        }
1123    }
1124}
1125#[cfg(feature = "mint")]
1126impl<T, Src, Dst> From<Transform3D<T, Src, Dst>> for mint::RowMatrix4<T> {
1127    #[rustfmt::skip]
1128    fn from(t: Transform3D<T, Src, Dst>) -> Self {
1129        mint::RowMatrix4 {
1130            x: mint::Vector4 { x: t.m11, y: t.m12, z: t.m13, w: t.m14 },
1131            y: mint::Vector4 { x: t.m21, y: t.m22, z: t.m23, w: t.m24 },
1132            z: mint::Vector4 { x: t.m31, y: t.m32, z: t.m33, w: t.m34 },
1133            w: mint::Vector4 { x: t.m41, y: t.m42, z: t.m43, w: t.m44 },
1134        }
1135    }
1136}
1137
1138impl<T: Copy + Zero + One, Src, Dst> From<Transform2D<T, Src, Dst>> for Transform3D<T, Src, Dst> {
1139    fn from(t: Transform2D<T, Src, Dst>) -> Self {
1140        t.to_3d()
1141    }
1142}
1143
1144impl<T: Copy + Zero + One, Src, Dst> From<Scale<T, Src, Dst>> for Transform3D<T, Src, Dst> {
1145    fn from(s: Scale<T, Src, Dst>) -> Self {
1146        Transform3D::scale(s.get(), s.get(), s.get())
1147    }
1148}
1149
1150#[cfg(any(feature = "std", feature = "libm"))]
1151mod float {
1152    use super::Transform3D;
1153    use crate::num::{One, Zero};
1154    use crate::{approxeq::ApproxEq, Angle, Trig};
1155    use core::ops::{Add, Div, Mul, Sub};
1156    use num_traits::Signed;
1157
1158    impl<T, Src, Dst> Transform3D<T, Src, Dst> {
1159        /// Returns true if self can be represented as a 2d scale+offset
1160        /// transform, using `T`'s default epsilon value.
1161        pub fn is_scale_offset_2d(&self) -> bool
1162        where
1163            T: Copy + Signed + PartialOrd + ApproxEq<T>,
1164        {
1165            self.is_scale_offset_2d_eps(T::approx_epsilon())
1166        }
1167
1168        /// Create a 2d skew transform.
1169        ///
1170        /// See <https://drafts.csswg.org/css-transforms/#funcdef-skew>
1171        #[rustfmt::skip]
1172        pub fn skew(alpha: Angle<T>, beta: Angle<T>) -> Self
1173        where
1174            T: Trig + Zero + One,
1175        {
1176            let _0 = || T::zero();
1177            let _1 = || T::one();
1178            let (sx, sy) = (beta.radians.tan(), alpha.radians.tan());
1179
1180            Self::new(
1181                _1(), sx,   _0(), _0(),
1182                sy,   _1(), _0(), _0(),
1183                _0(), _0(), _1(), _0(),
1184                _0(), _0(), _0(), _1(),
1185            )
1186        }
1187    }
1188
1189    /// Methods for creating and combining rotation transformations
1190    impl<T, Src, Dst> Transform3D<T, Src, Dst>
1191    where
1192        T: Copy
1193            + Add<Output = T>
1194            + Sub<Output = T>
1195            + Mul<Output = T>
1196            + Div<Output = T>
1197            + Zero
1198            + One
1199            + Trig,
1200    {
1201        /// Create a 3d rotation transform from an angle / axis.
1202        /// The supplied axis must be normalized.
1203        #[rustfmt::skip]
1204        pub fn rotation(x: T, y: T, z: T, theta: Angle<T>) -> Self {
1205            let (_0, _1): (T, T) = (Zero::zero(), One::one());
1206            let _2 = _1 + _1;
1207
1208            let xx = x * x;
1209            let yy = y * y;
1210            let zz = z * z;
1211
1212            let half_theta = theta.get() / _2;
1213            let sc = half_theta.sin() * half_theta.cos();
1214            let sq = half_theta.sin() * half_theta.sin();
1215
1216            Transform3D::new(
1217                _1 - _2 * (yy + zz) * sq,
1218                _2 * (x * y * sq + z * sc),
1219                _2 * (x * z * sq - y * sc),
1220                _0,
1221
1222
1223                _2 * (x * y * sq - z * sc),
1224                _1 - _2 * (xx + zz) * sq,
1225                _2 * (y * z * sq + x * sc),
1226                _0,
1227
1228                _2 * (x * z * sq + y * sc),
1229                _2 * (y * z * sq - x * sc),
1230                _1 - _2 * (xx + yy) * sq,
1231                _0,
1232
1233                _0,
1234                _0,
1235                _0,
1236                _1
1237            )
1238        }
1239
1240        /// Returns a transform with a rotation applied after self's transformation.
1241        #[must_use]
1242        pub fn then_rotate(&self, x: T, y: T, z: T, theta: Angle<T>) -> Self {
1243            self.then(&Transform3D::rotation(x, y, z, theta))
1244        }
1245
1246        /// Returns a transform with a rotation applied before self's transformation.
1247        #[must_use]
1248        pub fn pre_rotate(&self, x: T, y: T, z: T, theta: Angle<T>) -> Self {
1249            Transform3D::rotation(x, y, z, theta).then(self)
1250        }
1251    }
1252
1253    impl<T: ApproxEq<T>, Src, Dst> Transform3D<T, Src, Dst> {
1254        /// Returns `true` if this transform is approximately equal to the other one, using
1255        /// `T`'s default epsilon value.
1256        ///
1257        /// The same as [`ApproxEq::approx_eq`] but available without importing trait.
1258        #[inline]
1259        pub fn approx_eq(&self, other: &Self) -> bool {
1260            <Self as ApproxEq<T>>::approx_eq(self, other)
1261        }
1262
1263        /// Returns `true` if this transform is approximately equal to the other one, using
1264        /// a provided epsilon value.
1265        ///
1266        /// The same as [`ApproxEq::approx_eq_eps`] but available without importing trait.
1267        #[inline]
1268        pub fn approx_eq_eps(&self, other: &Self, eps: &T) -> bool {
1269            <Self as ApproxEq<T>>::approx_eq_eps(self, other, eps)
1270        }
1271    }
1272
1273    impl<T: ApproxEq<T>, Src, Dst> ApproxEq<T> for Transform3D<T, Src, Dst> {
1274        #[inline]
1275        fn approx_epsilon() -> T {
1276            T::approx_epsilon()
1277        }
1278
1279        #[rustfmt::skip]
1280        fn approx_eq_eps(&self, other: &Self, eps: &T) -> bool {
1281            self.m11.approx_eq_eps(&other.m11, eps) && self.m12.approx_eq_eps(&other.m12, eps) &&
1282            self.m13.approx_eq_eps(&other.m13, eps) && self.m14.approx_eq_eps(&other.m14, eps) &&
1283            self.m21.approx_eq_eps(&other.m21, eps) && self.m22.approx_eq_eps(&other.m22, eps) &&
1284            self.m23.approx_eq_eps(&other.m23, eps) && self.m24.approx_eq_eps(&other.m24, eps) &&
1285            self.m31.approx_eq_eps(&other.m31, eps) && self.m32.approx_eq_eps(&other.m32, eps) &&
1286            self.m33.approx_eq_eps(&other.m33, eps) && self.m34.approx_eq_eps(&other.m34, eps) &&
1287            self.m41.approx_eq_eps(&other.m41, eps) && self.m42.approx_eq_eps(&other.m42, eps) &&
1288            self.m43.approx_eq_eps(&other.m43, eps) && self.m44.approx_eq_eps(&other.m44, eps)
1289        }
1290    }
1291}
1292
1293#[cfg(test)]
1294#[cfg(any(feature = "std", feature = "libm"))]
1295mod tests {
1296    use super::*;
1297    use crate::approxeq::ApproxEq;
1298    use crate::{default, Angle};
1299    use crate::{point2, point3};
1300
1301    use core::f32::consts::{FRAC_PI_2, PI};
1302
1303    type Mf32 = default::Transform3D<f32>;
1304
1305    // For convenience.
1306    fn rad(v: f32) -> Angle<f32> {
1307        Angle::radians(v)
1308    }
1309
1310    #[test]
1311    pub fn test_translation() {
1312        let t1 = Mf32::translation(1.0, 2.0, 3.0);
1313        let t2 = Mf32::identity().pre_translate(vec3(1.0, 2.0, 3.0));
1314        let t3 = Mf32::identity().then_translate(vec3(1.0, 2.0, 3.0));
1315        assert_eq!(t1, t2);
1316        assert_eq!(t1, t3);
1317
1318        assert_eq!(
1319            t1.transform_point3d(point3(1.0, 1.0, 1.0)),
1320            Some(point3(2.0, 3.0, 4.0))
1321        );
1322        assert_eq!(
1323            t1.transform_point2d(point2(1.0, 1.0)),
1324            Some(point2(2.0, 3.0))
1325        );
1326
1327        assert_eq!(t1.then(&t1), Mf32::translation(2.0, 4.0, 6.0));
1328
1329        assert!(!t1.is_2d());
1330        assert_eq!(
1331            Mf32::translation(1.0, 2.0, 3.0).to_2d(),
1332            Transform2D::translation(1.0, 2.0)
1333        );
1334    }
1335
1336    #[test]
1337    pub fn test_rotation() {
1338        let r1 = Mf32::rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2));
1339        let r2 = Mf32::identity().pre_rotate(0.0, 0.0, 1.0, rad(FRAC_PI_2));
1340        let r3 = Mf32::identity().then_rotate(0.0, 0.0, 1.0, rad(FRAC_PI_2));
1341        assert_eq!(r1, r2);
1342        assert_eq!(r1, r3);
1343
1344        assert!(r1
1345            .transform_point3d(point3(1.0, 2.0, 3.0))
1346            .unwrap()
1347            .approx_eq(&point3(-2.0, 1.0, 3.0)));
1348        assert!(r1
1349            .transform_point2d(point2(1.0, 2.0))
1350            .unwrap()
1351            .approx_eq(&point2(-2.0, 1.0)));
1352
1353        assert!(r1
1354            .then(&r1)
1355            .approx_eq(&Mf32::rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2 * 2.0))));
1356
1357        assert!(r1.is_2d());
1358        assert!(r1.to_2d().approx_eq(&Transform2D::rotation(rad(FRAC_PI_2))));
1359    }
1360
1361    #[test]
1362    pub fn test_scale() {
1363        let s1 = Mf32::scale(2.0, 3.0, 4.0);
1364        let s2 = Mf32::identity().pre_scale(2.0, 3.0, 4.0);
1365        let s3 = Mf32::identity().then_scale(2.0, 3.0, 4.0);
1366        assert_eq!(s1, s2);
1367        assert_eq!(s1, s3);
1368
1369        assert!(s1
1370            .transform_point3d(point3(2.0, 2.0, 2.0))
1371            .unwrap()
1372            .approx_eq(&point3(4.0, 6.0, 8.0)));
1373        assert!(s1
1374            .transform_point2d(point2(2.0, 2.0))
1375            .unwrap()
1376            .approx_eq(&point2(4.0, 6.0)));
1377
1378        assert_eq!(s1.then(&s1), Mf32::scale(4.0, 9.0, 16.0));
1379
1380        assert!(!s1.is_2d());
1381        assert_eq!(
1382            Mf32::scale(2.0, 3.0, 0.0).to_2d(),
1383            Transform2D::scale(2.0, 3.0)
1384        );
1385    }
1386
1387    #[test]
1388    pub fn test_pre_then_scale() {
1389        let m = Mf32::rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2)).then_translate(vec3(6.0, 7.0, 8.0));
1390        let s = Mf32::scale(2.0, 3.0, 4.0);
1391        assert_eq!(m.then(&s), m.then_scale(2.0, 3.0, 4.0));
1392    }
1393
1394    #[test]
1395    #[rustfmt::skip]
1396    pub fn test_ortho() {
1397        let (left, right, bottom, top) = (0.0f32, 1.0f32, 0.1f32, 1.0f32);
1398        let (near, far) = (-1.0f32, 1.0f32);
1399        let result = Mf32::ortho(left, right, bottom, top, near, far);
1400        let expected = Mf32::new(
1401             2.0,  0.0,         0.0, 0.0,
1402             0.0,  2.22222222,  0.0, 0.0,
1403             0.0,  0.0,        -1.0, 0.0,
1404            -1.0, -1.22222222, -0.0, 1.0
1405        );
1406        assert!(result.approx_eq(&expected));
1407    }
1408
1409    #[test]
1410    pub fn test_is_2d() {
1411        assert!(Mf32::identity().is_2d());
1412        assert!(Mf32::rotation(0.0, 0.0, 1.0, rad(0.7854)).is_2d());
1413        assert!(!Mf32::rotation(0.0, 1.0, 0.0, rad(0.7854)).is_2d());
1414    }
1415
1416    #[test]
1417    #[rustfmt::skip]
1418    pub fn test_new_2d() {
1419        let m1 = Mf32::new_2d(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);
1420        let m2 = Mf32::new(
1421            1.0, 2.0, 0.0, 0.0,
1422            3.0, 4.0, 0.0, 0.0,
1423            0.0, 0.0, 1.0, 0.0,
1424            5.0, 6.0, 0.0, 1.0
1425        );
1426        assert_eq!(m1, m2);
1427    }
1428
1429    #[test]
1430    pub fn test_inverse_simple() {
1431        let m1 = Mf32::identity();
1432        let m2 = m1.inverse().unwrap();
1433        assert!(m1.approx_eq(&m2));
1434    }
1435
1436    #[test]
1437    pub fn test_inverse_scale() {
1438        let m1 = Mf32::scale(1.5, 0.3, 2.1);
1439        let m2 = m1.inverse().unwrap();
1440        assert!(m1.then(&m2).approx_eq(&Mf32::identity()));
1441        assert!(m2.then(&m1).approx_eq(&Mf32::identity()));
1442    }
1443
1444    #[test]
1445    pub fn test_inverse_translate() {
1446        let m1 = Mf32::translation(-132.0, 0.3, 493.0);
1447        let m2 = m1.inverse().unwrap();
1448        assert!(m1.then(&m2).approx_eq(&Mf32::identity()));
1449        assert!(m2.then(&m1).approx_eq(&Mf32::identity()));
1450    }
1451
1452    #[test]
1453    pub fn test_inverse_rotate() {
1454        let m1 = Mf32::rotation(0.0, 1.0, 0.0, rad(1.57));
1455        let m2 = m1.inverse().unwrap();
1456        assert!(m1.then(&m2).approx_eq(&Mf32::identity()));
1457        assert!(m2.then(&m1).approx_eq(&Mf32::identity()));
1458    }
1459
1460    #[test]
1461    pub fn test_inverse_transform_point_2d() {
1462        let m1 = Mf32::translation(100.0, 200.0, 0.0);
1463        let m2 = m1.inverse().unwrap();
1464        assert!(m1.then(&m2).approx_eq(&Mf32::identity()));
1465        assert!(m2.then(&m1).approx_eq(&Mf32::identity()));
1466
1467        let p1 = point2(1000.0, 2000.0);
1468        let p2 = m1.transform_point2d(p1);
1469        assert_eq!(p2, Some(point2(1100.0, 2200.0)));
1470
1471        let p3 = m2.transform_point2d(p2.unwrap());
1472        assert_eq!(p3, Some(p1));
1473    }
1474
1475    #[test]
1476    fn test_inverse_none() {
1477        assert!(Mf32::scale(2.0, 0.0, 2.0).inverse().is_none());
1478        assert!(Mf32::scale(2.0, 2.0, 2.0).inverse().is_some());
1479    }
1480
1481    #[test]
1482    pub fn test_pre_post() {
1483        let m1 = default::Transform3D::identity()
1484            .then_scale(1.0, 2.0, 3.0)
1485            .then_translate(vec3(1.0, 2.0, 3.0));
1486        let m2 = default::Transform3D::identity()
1487            .pre_translate(vec3(1.0, 2.0, 3.0))
1488            .pre_scale(1.0, 2.0, 3.0);
1489        assert!(m1.approx_eq(&m2));
1490
1491        let r = Mf32::rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2));
1492        let t = Mf32::translation(2.0, 3.0, 0.0);
1493
1494        let a = point3(1.0, 1.0, 1.0);
1495
1496        assert!(r
1497            .then(&t)
1498            .transform_point3d(a)
1499            .unwrap()
1500            .approx_eq(&point3(1.0, 4.0, 1.0)));
1501        assert!(t
1502            .then(&r)
1503            .transform_point3d(a)
1504            .unwrap()
1505            .approx_eq(&point3(-4.0, 3.0, 1.0)));
1506        assert!(t.then(&r).transform_point3d(a).unwrap().approx_eq(
1507            &r.transform_point3d(t.transform_point3d(a).unwrap())
1508                .unwrap()
1509        ));
1510    }
1511
1512    #[test]
1513    fn test_size_of() {
1514        use core::mem::size_of;
1515        assert_eq!(
1516            size_of::<default::Transform3D<f32>>(),
1517            16 * size_of::<f32>()
1518        );
1519        assert_eq!(
1520            size_of::<default::Transform3D<f64>>(),
1521            16 * size_of::<f64>()
1522        );
1523    }
1524
1525    #[test]
1526    #[rustfmt::skip]
1527    pub fn test_transform_associativity() {
1528        let m1 = Mf32::new(3.0, 2.0, 1.5, 1.0,
1529                           0.0, 4.5, -1.0, -4.0,
1530                           0.0, 3.5, 2.5, 40.0,
1531                           0.0, 3.0, 0.0, 1.0);
1532        let m2 = Mf32::new(1.0, -1.0, 3.0, 0.0,
1533                           -1.0, 0.5, 0.0, 2.0,
1534                           1.5, -2.0, 6.0, 0.0,
1535                           -2.5, 6.0, 1.0, 1.0);
1536
1537        let p = point3(1.0, 3.0, 5.0);
1538        let p1 = m1.then(&m2).transform_point3d(p).unwrap();
1539        let p2 = m2.transform_point3d(m1.transform_point3d(p).unwrap()).unwrap();
1540        assert!(p1.approx_eq(&p2));
1541    }
1542
1543    #[test]
1544    pub fn test_is_identity() {
1545        let m1 = default::Transform3D::identity();
1546        assert!(m1.is_identity());
1547        let m2 = m1.then_translate(vec3(0.1, 0.0, 0.0));
1548        assert!(!m2.is_identity());
1549    }
1550
1551    #[test]
1552    pub fn test_transform_vector() {
1553        // Translation does not apply to vectors.
1554        let m = Mf32::translation(1.0, 2.0, 3.0);
1555        let v1 = vec3(10.0, -10.0, 3.0);
1556        assert_eq!(v1, m.transform_vector3d(v1));
1557        // While it does apply to points.
1558        assert_ne!(Some(v1.to_point()), m.transform_point3d(v1.to_point()));
1559
1560        // same thing with 2d vectors/points
1561        let v2 = vec2(10.0, -5.0);
1562        assert_eq!(v2, m.transform_vector2d(v2));
1563        assert_ne!(Some(v2.to_point()), m.transform_point2d(v2.to_point()));
1564    }
1565
1566    #[test]
1567    pub fn test_is_backface_visible() {
1568        // backface is not visible for rotate-x 0 degree.
1569        let r1 = Mf32::rotation(1.0, 0.0, 0.0, rad(0.0));
1570        assert!(!r1.is_backface_visible());
1571        // backface is not visible for rotate-x 45 degree.
1572        let r1 = Mf32::rotation(1.0, 0.0, 0.0, rad(PI * 0.25));
1573        assert!(!r1.is_backface_visible());
1574        // backface is visible for rotate-x 180 degree.
1575        let r1 = Mf32::rotation(1.0, 0.0, 0.0, rad(PI));
1576        assert!(r1.is_backface_visible());
1577        // backface is visible for rotate-x 225 degree.
1578        let r1 = Mf32::rotation(1.0, 0.0, 0.0, rad(PI * 1.25));
1579        assert!(r1.is_backface_visible());
1580        // backface is not visible for non-inverseable matrix
1581        let r1 = Mf32::scale(2.0, 0.0, 2.0);
1582        assert!(!r1.is_backface_visible());
1583    }
1584
1585    #[test]
1586    pub fn test_homogeneous() {
1587        #[rustfmt::skip]
1588        let m = Mf32::new(
1589            1.0, 2.0, 0.5, 5.0,
1590            3.0, 4.0, 0.25, 6.0,
1591            0.5, -1.0, 1.0, -1.0,
1592            -1.0, 1.0, -1.0, 2.0,
1593        );
1594        assert_eq!(
1595            m.transform_point2d_homogeneous(point2(1.0, 2.0)),
1596            HomogeneousVector::new(6.0, 11.0, 0.0, 19.0),
1597        );
1598        assert_eq!(
1599            m.transform_point3d_homogeneous(point3(1.0, 2.0, 4.0)),
1600            HomogeneousVector::new(8.0, 7.0, 4.0, 15.0),
1601        );
1602    }
1603
1604    #[test]
1605    pub fn test_perspective_division() {
1606        let p = point2(1.0, 2.0);
1607        let mut m = Mf32::identity();
1608        assert!(m.transform_point2d(p).is_some());
1609        m.m44 = 0.0;
1610        assert_eq!(None, m.transform_point2d(p));
1611        m.m44 = 1.0;
1612        m.m24 = -1.0;
1613        assert_eq!(None, m.transform_point2d(p));
1614    }
1615
1616    #[cfg(feature = "mint")]
1617    #[test]
1618    pub fn test_mint() {
1619        let m1 = Mf32::rotation(0.0, 0.0, 1.0, rad(FRAC_PI_2));
1620        let mm: mint::RowMatrix4<_> = m1.into();
1621        let m2 = Mf32::from(mm);
1622
1623        assert_eq!(m1, m2);
1624    }
1625}