1#[cfg(feature = "approx")]
2use approx::{AbsDiffEq, RelativeEq, UlpsEq};
3use core::ops::{Mul, MulAssign};
4use glam::{Affine3A, Mat3, Mat4, Quat, Vec3, Vec3A};
5
6#[repr(C)]
7#[derive(Debug, Default, Clone, Copy, PartialEq)]
8#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
9#[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
10pub struct Isometry3A {
11 pub translation: Vec3A,
12 pub rotation: Quat,
13}
14
15impl Isometry3A {
16 pub const ZERO: Self = Self {
21 translation: Vec3A::ZERO,
22 rotation: Quat::IDENTITY,
23 };
24
25 pub const IDENTITY: Self = Self {
29 translation: Vec3A::ZERO,
30 rotation: Quat::IDENTITY,
31 };
32
33 pub const NAN: Self = Self {
35 translation: Vec3A::NAN,
36 rotation: Quat::NAN,
37 };
38
39 #[inline]
41 #[must_use]
42 pub fn new(translation: Vec3, rotation: Quat) -> Self {
43 Self {
44 translation: translation.into(),
45 rotation,
46 }
47 }
48
49 #[inline]
51 #[must_use]
52 pub fn from_quat(rotation: Quat) -> Self {
53 Self {
54 translation: Vec3A::ZERO,
55 rotation,
56 }
57 }
58
59 #[inline]
62 #[must_use]
63 pub fn from_axis_angle(axis: Vec3, angle: f32) -> Self {
64 Self {
65 translation: Vec3A::ZERO,
66 rotation: Quat::from_axis_angle(axis, angle),
67 }
68 }
69
70 #[inline]
73 #[must_use]
74 pub fn from_rotation_x(angle: f32) -> Self {
75 Self {
76 translation: Vec3A::ZERO,
77 rotation: Quat::from_rotation_x(angle),
78 }
79 }
80
81 #[inline]
84 #[must_use]
85 pub fn from_rotation_y(angle: f32) -> Self {
86 Self {
87 translation: Vec3A::ZERO,
88 rotation: Quat::from_rotation_y(angle),
89 }
90 }
91
92 #[inline]
95 #[must_use]
96 pub fn from_rotation_z(angle: f32) -> Self {
97 Self {
98 translation: Vec3A::ZERO,
99 rotation: Quat::from_rotation_z(angle),
100 }
101 }
102
103 #[inline]
105 #[must_use]
106 pub fn from_translation(translation: Vec3) -> Self {
107 Self {
108 translation: translation.into(),
109 rotation: Quat::IDENTITY,
110 }
111 }
112
113 #[inline]
115 #[must_use]
116 pub fn from_rotation_translation(rotation: Quat, translation: Vec3) -> Self {
117 Self {
118 translation: translation.into(),
119 rotation,
120 }
121 }
122
123 #[inline]
125 #[must_use]
126 pub fn from_mat3(mat3: Mat3) -> Self {
127 Self {
128 translation: Vec3A::ZERO,
129 rotation: Quat::from_mat3(&mat3),
130 }
131 }
132
133 #[inline]
135 #[must_use]
136 pub fn from_mat3_translation(mat3: Mat3, translation: Vec3) -> Self {
137 Self {
138 translation: translation.into(),
139 rotation: Quat::from_mat3(&mat3),
140 }
141 }
142
143 #[inline]
145 #[must_use]
146 pub fn from_mat4(mat4: Mat4) -> Self {
147 Self {
148 translation: mat4.w_axis.truncate().into(),
149 rotation: Quat::from_mat4(&mat4),
150 }
151 }
152
153 #[inline]
155 #[must_use]
156 pub fn to_rotation_translation(&self) -> (Quat, Vec3) {
157 (self.rotation, self.translation.into())
158 }
159
160 #[inline]
162 #[must_use]
163 pub fn transform_point3(&self, rhs: Vec3) -> Vec3 {
164 let translation: Vec3 = self.translation.into();
165 self.rotation * rhs + translation
166 }
167
168 #[inline]
170 #[must_use]
171 pub fn transform_vector3(&self, rhs: Vec3) -> Vec3 {
172 self.rotation * rhs
173 }
174
175 #[inline]
177 #[must_use]
178 pub fn transform_point3a(&self, rhs: Vec3A) -> Vec3A {
179 self.rotation * rhs + self.translation
180 }
181
182 #[inline]
184 #[must_use]
185 pub fn transform_vector3a(&self, rhs: Vec3A) -> Vec3A {
186 self.rotation * rhs
187 }
188
189 #[inline]
193 #[must_use]
194 pub fn is_finite(&self) -> bool {
195 self.translation.is_finite() && self.rotation.is_finite()
196 }
197
198 #[inline]
200 #[must_use]
201 pub fn is_nan(&self) -> bool {
202 self.translation.is_nan() && self.rotation.is_nan()
203 }
204
205 #[inline]
208 #[must_use]
209 pub fn abs_diff_eq(self, rhs: Self, max_abs_diff: f32) -> bool {
210 self.translation.abs_diff_eq(rhs.translation, max_abs_diff)
211 && self.rotation.abs_diff_eq(rhs.rotation, max_abs_diff)
212 }
213
214 #[inline]
218 #[must_use]
219 pub fn inverse(&self) -> Self {
220 let rotation = self.rotation.inverse();
221 Self {
222 translation: -(rotation * self.translation),
223 rotation,
224 }
225 }
226}
227
228impl From<Isometry3A> for Mat4 {
229 #[inline]
230 fn from(i: Isometry3A) -> Mat4 {
231 let mat3 = Mat3::from_quat(i.rotation);
232 Mat4::from_cols(
233 mat3.x_axis.extend(0.0),
234 mat3.y_axis.extend(0.0),
235 mat3.z_axis.extend(0.0),
236 i.translation.extend(1.0),
237 )
238 }
239}
240
241impl From<Isometry3A> for Affine3A {
242 #[inline]
243 fn from(i: Isometry3A) -> Affine3A {
244 Affine3A::from_scale_rotation_translation(Vec3::ONE, i.rotation, i.translation.into())
245 }
246}
247
248impl Mul for Isometry3A {
249 type Output = Isometry3A;
250
251 #[inline]
252 fn mul(self, rhs: Isometry3A) -> Self::Output {
253 Isometry3A {
254 translation: self.rotation * rhs.translation + self.translation,
255 rotation: self.rotation * rhs.rotation,
256 }
257 }
258}
259
260impl MulAssign for Isometry3A {
261 #[inline]
262 fn mul_assign(&mut self, rhs: Isometry3A) {
263 *self = self.mul(rhs);
264 }
265}
266
267impl Mul<Mat4> for Isometry3A {
268 type Output = Mat4;
269
270 #[inline]
271 fn mul(self, rhs: Mat4) -> Self::Output {
272 Mat4::from(self) * rhs
273 }
274}
275
276impl Mul<Isometry3A> for Mat4 {
277 type Output = Mat4;
278
279 #[inline]
280 fn mul(self, rhs: Isometry3A) -> Self::Output {
281 self * Mat4::from(rhs)
282 }
283}
284
285#[cfg(feature = "approx")]
286impl AbsDiffEq for Isometry3A {
287 type Epsilon = <f32 as AbsDiffEq>::Epsilon;
288
289 #[inline]
290 fn default_epsilon() -> Self::Epsilon {
291 f32::default_epsilon()
292 }
293
294 #[inline]
295 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
296 self.translation.abs_diff_eq(other.translation, epsilon) && self.rotation.abs_diff_eq(other.rotation, epsilon)
297 }
298}
299
300#[cfg(feature = "approx")]
301impl RelativeEq for Isometry3A {
302 #[inline]
303 fn default_max_relative() -> Self::Epsilon {
304 f32::default_max_relative()
305 }
306
307 #[inline]
308 fn relative_eq(&self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon) -> bool {
309 self.translation.relative_eq(&other.translation, epsilon, max_relative)
310 && self.rotation.relative_eq(&other.rotation, epsilon, max_relative)
311 }
312}
313
314#[cfg(feature = "approx")]
315impl UlpsEq for Isometry3A {
316 #[inline]
317 fn default_max_ulps() -> u32 {
318 f32::default_max_ulps()
319 }
320
321 #[inline]
322 fn ulps_eq(&self, other: &Self, epsilon: Self::Epsilon, max_ulps: u32) -> bool {
323 self.translation.ulps_eq(&other.translation, epsilon, max_ulps)
324 && self.rotation.ulps_eq(&other.rotation, epsilon, max_ulps)
325 }
326}
327
328#[cfg(test)]
329mod test {
330 use super::*;
331
332 #[test]
333 fn test_from_mat4() {
334 let rot = Quat::from_rotation_y(0.6);
335 let pos = Vec3::new(1.0, 2.0, 3.0);
336 let mat = Mat4::from_rotation_translation(rot, pos);
337 let is = Isometry3A::from_mat4(mat);
338 assert!(Vec3::abs_diff_eq(is.translation.into(), pos, 1e-6));
339 assert!(Quat::abs_diff_eq(is.rotation, rot, 1e-6));
340 }
341
342 #[test]
343 fn test_transform_point3() {
344 let rot = Quat::from_rotation_x(0.6);
345 let pos = Vec3::new(1.0, 2.0, 3.0);
346 let mat = Mat4::from_rotation_translation(rot, pos);
347 let is = Isometry3A::from_mat4(mat);
348
349 let point = Vec3::new(5.0, -5.0, 5.0);
350 let p1 = mat.project_point3(point);
351 let p2 = is.transform_point3(point);
352 assert!(Vec3::abs_diff_eq(p1, p2, 1e-6));
353
354 let point = Vec3A::new(3.3, 4.4, 5.5);
355 let p1 = mat.project_point3a(point);
356 let p2 = is.transform_point3a(point);
357 assert!(Vec3A::abs_diff_eq(p1, p2, 1e-6));
358 }
359
360 #[test]
361 fn test_transform_vec3() {
362 let rot = Quat::from_rotation_z(-0.5);
363 let pos = Vec3::new(1.5, -2.0, -2.0);
364 let mat = Mat4::from_rotation_translation(rot, pos);
365 let is = Isometry3A::from_mat4(mat);
366
367 let vec = Vec3::new(1.0, 0.0, 0.7);
368 let v1 = mat.transform_vector3(vec);
369 let v2 = is.transform_vector3(vec);
370 assert!(Vec3::abs_diff_eq(v1, v2, 1e-6));
371
372 let vec = Vec3A::new(-0.5, 1.0, 0.0);
373 let v1 = mat.transform_vector3a(vec);
374 let v2 = is.transform_vector3a(vec);
375 assert!(Vec3A::abs_diff_eq(v1, v2, 1e-6));
376 }
377
378 #[test]
379 fn test_inverse() {
380 let rot = Quat::from_rotation_z(1.5) * Quat::from_rotation_x(1.0);
381 let pos = Vec3::new(1.99, 0.77, -1.55);
382 let mat = Mat4::from_rotation_translation(rot, pos);
383 let mat_inv = mat.inverse();
384 let is1 = Isometry3A::from_mat4(mat).inverse();
385 let is2 = Isometry3A::from_mat4(mat_inv);
386 assert!(Isometry3A::abs_diff_eq(is1, is2, 1e-6));
387 }
388
389 #[test]
390 fn test_mat4_from() {
391 let rot = Quat::from_rotation_y(-2.0);
392 let pos = Vec3::new(3.0, 3.3, 3.33);
393 let mat = Mat4::from_rotation_translation(rot, pos);
394 let is = Isometry3A::from_mat4(mat);
395 let mat2 = Mat4::from(is);
396 assert!(Mat4::abs_diff_eq(&mat, mat2, 1e-6));
397 }
398
399 #[test]
400 fn test_isometry_mul() {
401 let rot1 = Quat::from_rotation_x(0.77);
402 let pos1 = Vec3::new(6.6, -6.6, 3.3);
403 let mat1 = Mat4::from_rotation_translation(rot1, pos1);
404 let is1 = Isometry3A::from_rotation_translation(rot1, pos1);
405
406 let rot2 = Quat::from_rotation_z(-0.44);
407 let pos2 = Vec3::new(-1.1, -2.2, -3.3);
408 let mat2 = Mat4::from_rotation_translation(rot2, pos2);
409 let is2 = Isometry3A::from_rotation_translation(rot2, pos2);
410
411 let mat = mat1 * mat2;
412 let is = is1 * is2;
413 let is_mat = Isometry3A::from_mat4(mat);
414 assert!(Isometry3A::abs_diff_eq(is, is_mat, 1e-6));
415 }
416}