mod3d_base/
transformation.rs

1//a Imports
2use geo_nd::{matrix, quat, vector};
3
4use crate::{Mat4, Quat, Vec3};
5
6//a Transformation
7//tp Transformation
8/// A transformation corresponds to a translation of a rotation of a
9/// scaling
10///
11/// The rotation here is encoded by a [Quat]ernion
12#[derive(Clone, Copy, Debug)]
13pub struct Transformation {
14    /// Translation to apply after rotation
15    translation: Vec3,
16    /// Rotation to apply after scaling
17    rotation: Quat,
18    /// Scaling to apply first
19    scale: Vec3,
20}
21
22impl std::default::Default for Transformation {
23    fn default() -> Self {
24        let translation = vector::zero();
25        let scale = [1.; 3];
26        let rotation = quat::new();
27        Self {
28            translation,
29            scale,
30            rotation,
31        }
32    }
33}
34
35//ip Transformation
36impl Transformation {
37    //fp new
38    /// Create a new identity transformation
39    pub fn new() -> Self {
40        Default::default()
41    }
42
43    //cp with_scale
44    /// Set the scaling of a transformation
45    pub fn with_scale(mut self, scale: Vec3) -> Self {
46        self.scale = scale;
47        self
48    }
49
50    //cp with_translation
51    /// Set the translation of a transformation
52    pub fn with_translation(mut self, translation: Vec3) -> Self {
53        self.translation = translation;
54        self
55    }
56
57    //cp with_rotation
58    /// Set the rotation of a transformation
59    pub fn with_rotation(mut self, rotation: Quat) -> Self {
60        self.rotation = rotation;
61        self
62    }
63
64    //ap scale
65    /// Get the scale
66    pub fn scale(&mut self) -> Vec3 {
67        self.scale
68    }
69
70    //ap translation
71    /// Set the translation of a transformation
72    pub fn translation(&mut self) -> Vec3 {
73        self.translation
74    }
75
76    //ap rotation
77    /// Set the rotation of a transformation
78    pub fn rotation(&self) -> Quat {
79        self.rotation
80    }
81
82    //mp set_scale
83    /// Set the scaling of a transformation
84    pub fn set_scale(&mut self, scale: Vec3) {
85        self.scale = scale;
86    }
87
88    //mp set_translation
89    /// Set the translation of a transformation
90    pub fn set_translation(&mut self, translation: Vec3) {
91        self.translation = translation;
92    }
93
94    //mp set_rotation
95    /// Set the rotation of a transformation
96    pub fn set_rotation(&mut self, rotation: Quat) {
97        self.rotation = rotation;
98    }
99
100    //cp copy_from
101    /// Copy the transformation from another
102    pub fn copy_from(&mut self, other: &Self) {
103        self.translation = other.translation;
104        self.scale = other.scale;
105        self.rotation = other.rotation;
106    }
107
108    //mp combine
109    /// Combine two transformations into this
110    ///
111    /// To operate correctly the scales must be
112    pub fn combine(&mut self, base: &Self, other: &Self) {
113        self.rotation = quat::multiply(&base.rotation, &other.rotation);
114        self.translation = base.translation;
115        self.translation = vector::add(self.translation, &other.translation, 1.);
116        for i in 0..3 {
117            self.scale[i] = base.scale[i] * other.scale[i];
118        }
119    }
120
121    //mp translate
122    /// Pre-apply a translation to the transformation
123    pub fn translate(&mut self, translation: &Vec3, scale: f32) {
124        self.translation = vector::add(self.translation, translation, scale);
125    }
126
127    //mp rotate_axis_angle
128    /// Rotate the transformation by an angle about an axis
129    pub fn rotate_axis_angle(&mut self, axis: &Vec3, angle: f32) {
130        let q = quat::of_axis_angle(axis, angle);
131        self.rotation = quat::multiply(&q, &self.rotation);
132        // Glm.quat.multiply(self.translation, q, self.translation)
133        // # self.translation = q * self.translation # type: ignore
134    }
135
136    //mp rotate_by
137    /// Rotate the transformation by an angle about an axis
138    pub fn rotate_by(&mut self, quaternion: &Quat) {
139        self.rotation = quat::multiply(quaternion, &self.rotation);
140    }
141
142    //mp mat4
143    /// Create a mat4 from the Transformation
144    pub fn mat4(&self) -> Mat4 {
145        let mut m = matrix::from_quat4(self.rotation);
146        for i in 0..3 {
147            m[4 * i] *= self.scale[i];
148            m[4 * i + 1] *= self.scale[i];
149            m[4 * i + 2] *= self.scale[i];
150        }
151        m[12] += self.translation[0];
152        m[13] += self.translation[1];
153        m[14] += self.translation[2];
154        m
155    }
156
157    //mp mat4_inverse
158    /// Create a mat4 from the inverse of this Transformation
159    pub fn mat4_inverse(&self) -> Mat4 {
160        let r = quat::conjugate(&self.rotation);
161        let mut m = matrix::from_quat4(r);
162        for i in 0..3 {
163            let sc = 1. / self.scale[i];
164            m[i] *= sc;
165            m[i + 4] *= sc;
166            m[i + 8] *= sc;
167        }
168        m[12] -= self.translation[0];
169        m[13] -= self.translation[1];
170        m[14] -= self.translation[2];
171        m
172    }
173
174    //mp from_mat4
175    /// Set this translation from a Mat4 (assuming it can be done)
176    pub fn from_mat4(&mut self, m: Mat4) {
177        self.translation = [m[12], m[13], m[14]];
178        let mut rotation = [0.; 9];
179        for i in 0..3 {
180            let v = [m[4 * i], m[4 * i + 1], m[4 * i + 2]];
181            let l = vector::length(&v);
182            self.scale[i] = l;
183            rotation[3 * i] = v[0] / l;
184            rotation[3 * i + 1] = v[1] / l;
185            rotation[3 * i + 2] = v[2] / l;
186        }
187        self.rotation = quat::of_rotation(&rotation);
188    }
189
190    //mp mat4_after
191    /// Calculate a Mat4 of this transformation premultiplied by another Mat4
192    pub fn mat4_after(&self, pre_mat: &Mat4) -> Mat4 {
193        let m = self.mat4();
194        matrix::multiply4(pre_mat, &m)
195    }
196
197    //mp interpolate
198    /// Set this transformation to be an interpolation between two others
199    pub fn interpolate(&mut self, t: f32, in0: &Self, in1: &Self) {
200        let tn = 1.0 - t;
201        for i in 0..3 {
202            self.translation[i] = t * in0.translation[i] + tn * in1.translation[i];
203            self.scale[i] = t * in0.scale[i] + tn * in1.scale[i];
204        }
205        self.rotation = quat::nlerp(t, &in0.rotation, &in1.rotation);
206    }
207
208    //mp distance
209    /// Calculate an approximate 'distance' between two transformations
210    pub fn distance(&self, other: &Self) -> f32 {
211        let td = vector::distance(&self.translation, &other.translation);
212        let sd = vector::distance(&self.scale, &other.scale);
213        let qd = quat::distance(&self.rotation, &other.rotation);
214        td + sd + qd
215    }
216    //zz All done
217}
218
219//ip Display for Transformation
220impl std::fmt::Display for Transformation {
221    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
222        write!(
223            f,
224            "Transform +{:?}:@{:?}:*{:?}",
225            self.translation, self.rotation, self.scale
226        )
227    }
228}