1use core::ops::{Mul, MulAssign};
2use glam::{Affine3A, Mat3, Mat4, Quat, Vec3, Vec3A};
3
4#[repr(C)]
5#[derive(Debug, Default, Clone, Copy, PartialEq)]
6#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
7#[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
8pub struct Isometry3A {
9 pub translation: Vec3A,
10 pub rotation: Quat,
11}
12
13impl Isometry3A {
14 pub const ZERO: Self = Self {
19 translation: Vec3A::ZERO,
20 rotation: Quat::IDENTITY,
21 };
22
23 pub const IDENTITY: Self = Self {
27 translation: Vec3A::ZERO,
28 rotation: Quat::IDENTITY,
29 };
30
31 pub const NAN: Self = Self {
33 translation: Vec3A::NAN,
34 rotation: Quat::NAN,
35 };
36
37 #[inline]
39 #[must_use]
40 pub fn new(translation: Vec3, rotation: Quat) -> Self {
41 Self {
42 translation: translation.into(),
43 rotation,
44 }
45 }
46
47 #[inline]
49 #[must_use]
50 pub fn from_quat(rotation: Quat) -> Self {
51 Self {
52 translation: Vec3A::ZERO,
53 rotation,
54 }
55 }
56
57 #[inline]
60 #[must_use]
61 pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self {
62 Self {
63 translation: Vec3A::ZERO,
64 rotation: Quat::from_axis_angle(axis, angle),
65 }
66 }
67
68 #[inline]
71 #[must_use]
72 pub fn from_rotation_x(angle: f32) -> Self {
73 Self {
74 translation: Vec3A::ZERO,
75 rotation: Quat::from_rotation_x(angle),
76 }
77 }
78
79 #[inline]
82 #[must_use]
83 pub fn from_rotation_y(angle: f32) -> Self {
84 Self {
85 translation: Vec3A::ZERO,
86 rotation: Quat::from_rotation_y(angle),
87 }
88 }
89
90 #[inline]
93 #[must_use]
94 pub fn from_rotation_z(angle: f32) -> Self {
95 Self {
96 translation: Vec3A::ZERO,
97 rotation: Quat::from_rotation_z(angle),
98 }
99 }
100
101 #[inline]
103 #[must_use]
104 pub fn from_translation(translation: Vec3) -> Self {
105 Self {
106 translation: translation.into(),
107 rotation: Quat::IDENTITY,
108 }
109 }
110
111 #[inline]
113 #[must_use]
114 pub fn from_rotation_translation(rotation: Quat, translation: Vec3) -> Self {
115 Self {
116 translation: translation.into(),
117 rotation,
118 }
119 }
120
121 #[inline]
123 #[must_use]
124 pub fn from_mat3(mat3: Mat3) -> Self {
125 Self {
126 translation: Vec3A::ZERO,
127 rotation: Quat::from_mat3(&mat3),
128 }
129 }
130
131 #[inline]
133 #[must_use]
134 pub fn from_mat3_translation(mat3: Mat3, translation: Vec3) -> Self {
135 Self {
136 translation: translation.into(),
137 rotation: Quat::from_mat3(&mat3),
138 }
139 }
140
141 #[inline]
143 #[must_use]
144 pub fn from_mat4(mat4: Mat4) -> Self {
145 Self {
146 translation: mat4.w_axis.truncate().into(),
147 rotation: Quat::from_mat4(&mat4),
148 }
149 }
150
151 #[inline]
153 #[must_use]
154 pub fn to_rotation_translation(&self) -> (Quat, Vec3) {
155 (self.rotation, self.translation.into())
156 }
157
158 #[inline]
160 #[must_use]
161 pub fn transform_point3(&self, rhs: Vec3) -> Vec3 {
162 let translation: Vec3 = self.translation.into();
163 self.rotation * rhs + translation
164 }
165
166 #[inline]
168 #[must_use]
169 pub fn transform_vector3(&self, rhs: Vec3) -> Vec3 {
170 self.rotation * rhs
171 }
172
173 #[inline]
175 #[must_use]
176 pub fn transform_point3a(&self, rhs: Vec3A) -> Vec3A {
177 self.rotation * rhs + self.translation
178 }
179
180 #[inline]
182 #[must_use]
183 pub fn transform_vector3a(&self, rhs: Vec3A) -> Vec3A {
184 self.rotation * rhs
185 }
186
187 #[inline]
191 #[must_use]
192 pub fn is_finite(&self) -> bool {
193 self.translation.is_finite() && self.rotation.is_finite()
194 }
195
196 #[inline]
198 #[must_use]
199 pub fn is_nan(&self) -> bool {
200 self.translation.is_nan() && self.rotation.is_nan()
201 }
202
203 #[inline]
206 #[must_use]
207 pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool {
208 self.translation.abs_diff_eq(rhs.translation, max_abs_diff)
209 && self.rotation.abs_diff_eq(rhs.rotation, max_abs_diff)
210 }
211
212 #[inline]
216 #[must_use]
217 pub fn inverse(&self) -> Self {
218 let rotation = self.rotation.inverse();
219 Self {
220 translation: -(rotation * self.translation),
221 rotation,
222 }
223 }
224}
225
226impl From<Isometry3A> for Mat4 {
227 #[inline]
228 fn from(i: Isometry3A) -> Mat4 {
229 let mat3 = Mat3::from_quat(i.rotation);
230 Mat4::from_cols(
231 mat3.x_axis.extend(0.0),
232 mat3.y_axis.extend(0.0),
233 mat3.z_axis.extend(0.0),
234 i.translation.extend(1.0),
235 )
236 }
237}
238
239impl From<Isometry3A> for Affine3A {
240 #[inline]
241 fn from(i: Isometry3A) -> Affine3A {
242 Affine3A::from_scale_rotation_translation(Vec3::ONE, i.rotation, i.translation.into())
243 }
244}
245
246impl Mul for Isometry3A {
247 type Output = Isometry3A;
248
249 #[inline]
250 fn mul(self, rhs: Isometry3A) -> Self::Output {
251 Isometry3A {
252 translation: self.rotation * rhs.translation + self.translation,
253 rotation: self.rotation * rhs.rotation,
254 }
255 }
256}
257
258impl MulAssign for Isometry3A {
259 #[inline]
260 fn mul_assign(&mut self, rhs: Isometry3A) {
261 *self = self.mul(rhs);
262 }
263}
264
265impl Mul<Mat4> for Isometry3A {
266 type Output = Mat4;
267
268 #[inline]
269 fn mul(self, rhs: Mat4) -> Self::Output {
270 Mat4::from(self) * rhs
271 }
272}
273
274impl Mul<Isometry3A> for Mat4 {
275 type Output = Mat4;
276
277 #[inline]
278 fn mul(self, rhs: Isometry3A) -> Self::Output {
279 self * Mat4::from(rhs)
280 }
281}
282
283#[cfg(test)]
284mod test {
285 use super::*;
286
287 #[test]
288 fn test_from_mat4() {
289 let rot = Quat::from_rotation_y(0.6);
290 let pos = Vec3::new(1.0, 2.0, 3.0);
291 let mat = Mat4::from_rotation_translation(rot, pos);
292 let is = Isometry3A::from_mat4(mat);
293 assert!(Vec3::abs_diff_eq(is.translation.into(), pos, 1e-6));
294 assert!(Quat::abs_diff_eq(is.rotation, rot, 1e-6));
295 }
296
297 #[test]
298 fn test_transform_point3() {
299 let rot = Quat::from_rotation_x(0.6);
300 let pos = Vec3::new(1.0, 2.0, 3.0);
301 let mat = Mat4::from_rotation_translation(rot, pos);
302 let is = Isometry3A::from_mat4(mat);
303
304 let point = Vec3::new(5.0, -5.0, 5.0);
305 let p1 = mat.project_point3(point);
306 let p2 = is.transform_point3(point);
307 assert!(Vec3::abs_diff_eq(p1, p2, 1e-6));
308
309 let point = Vec3A::new(3.3, 4.4, 5.5);
310 let p1 = mat.project_point3a(point);
311 let p2 = is.transform_point3a(point);
312 assert!(Vec3A::abs_diff_eq(p1, p2, 1e-6));
313 }
314
315 #[test]
316 fn test_transform_vec3() {
317 let rot = Quat::from_rotation_z(-0.5);
318 let pos = Vec3::new(1.5, -2.0, -2.0);
319 let mat = Mat4::from_rotation_translation(rot, pos);
320 let is = Isometry3A::from_mat4(mat);
321
322 let vec = Vec3::new(1.0, 0.0, 0.7);
323 let v1 = mat.transform_vector3(vec);
324 let v2 = is.transform_vector3(vec);
325 assert!(Vec3::abs_diff_eq(v1, v2, 1e-6));
326
327 let vec = Vec3A::new(-0.5, 1.0, 0.0);
328 let v1 = mat.transform_vector3a(vec);
329 let v2 = is.transform_vector3a(vec);
330 assert!(Vec3A::abs_diff_eq(v1, v2, 1e-6));
331 }
332
333 #[test]
334 fn test_inverse() {
335 let rot = Quat::from_rotation_z(1.5) * Quat::from_rotation_x(1.0);
336 let pos = Vec3::new(1.99, 0.77, -1.55);
337 let mat = Mat4::from_rotation_translation(rot, pos);
338 let mat_inv = mat.inverse();
339 let is1 = Isometry3A::from_mat4(mat).inverse();
340 let is2 = Isometry3A::from_mat4(mat_inv);
341 assert!(Isometry3A::abs_diff_eq(is1, is2, 1e-6));
342 }
343
344 #[test]
345 fn test_mat4_from() {
346 let rot = Quat::from_rotation_y(-2.0);
347 let pos = Vec3::new(3.0, 3.3, 3.33);
348 let mat = Mat4::from_rotation_translation(rot, pos);
349 let is = Isometry3A::from_mat4(mat);
350 let mat2 = Mat4::from(is);
351 assert!(Mat4::abs_diff_eq(&mat, mat2, 1e-6));
352 }
353
354 #[test]
355 fn test_isometry_mul() {
356 let rot1 = Quat::from_rotation_x(0.77);
357 let pos1 = Vec3::new(6.6, -6.6, 3.3);
358 let mat1 = Mat4::from_rotation_translation(rot1, pos1);
359 let is1 = Isometry3A::from_rotation_translation(rot1, pos1);
360
361 let rot2 = Quat::from_rotation_z(-0.44);
362 let pos2 = Vec3::new(-1.1, -2.2, -3.3);
363 let mat2 = Mat4::from_rotation_translation(rot2, pos2);
364 let is2 = Isometry3A::from_rotation_translation(rot2, pos2);
365
366 let mat = mat1 * mat2;
367 let is = is1 * is2;
368 let is_mat = Isometry3A::from_mat4(mat);
369 assert!(Isometry3A::abs_diff_eq(is, is_mat, 1e-6));
370 }
371}