1use crate::rot2::{DRot2, Rot2};
4use core::ops::{Mul, MulAssign};
5
6macro_rules! impl_pose2 {
8 ($Pose2:ident, $Rot2:ident, $Real:ty, $Vec2:ty, $Vec3:ty, $Mat2:ty, $Mat3:ty $(, #[$attr:meta])*) => {
9 #[doc = concat!("A 2D pose (rotation + translation), representing a rigid body transformation (", stringify!($Real), " precision).")]
10 #[derive(Copy, Clone, Debug, PartialEq)]
11 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
12 #[cfg_attr(feature = "rkyv", derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize))]
13 #[repr(C)]
14 $(#[$attr])*
15 pub struct $Pose2 {
16 pub rotation: $Rot2,
18 pub translation: $Vec2,
20 }
21
22 impl $Pose2 {
23 pub const IDENTITY: Self = Self {
25 rotation: $Rot2::IDENTITY,
26 translation: <$Vec2>::ZERO,
27 };
28
29 #[inline]
31 pub fn identity() -> Self {
32 Self::IDENTITY
33 }
34
35 #[inline]
37 pub fn from_translation(translation: $Vec2) -> Self {
38 Self {
39 rotation: $Rot2::IDENTITY,
40 translation,
41 }
42 }
43
44 #[inline]
46 pub fn translation(x: $Real, y: $Real) -> Self {
47 Self::from_translation(<$Vec2>::new(x, y))
48 }
49
50 #[inline]
52 pub fn from_rotation(rotation: $Rot2) -> Self {
53 Self {
54 rotation,
55 translation: <$Vec2>::ZERO,
56 }
57 }
58
59 #[inline]
61 pub fn rotation(angle: $Real) -> Self {
62 Self::from_rotation(<$Rot2>::new(angle))
63 }
64
65 #[inline]
67 pub fn from_parts(translation: $Vec2, rotation: $Rot2) -> Self {
68 Self {
69 rotation,
70 translation,
71 }
72 }
73
74 #[inline]
76 pub fn new(translation: $Vec2, angle: $Real) -> Self {
77 Self {
78 rotation: $Rot2::new(angle),
79 translation,
80 }
81 }
82
83 #[inline]
85 pub fn prepend_translation(self, translation: $Vec2) -> Self {
86 Self {
87 rotation: self.rotation,
88 translation: self.translation + self.rotation * translation,
89 }
90 }
91
92 #[inline]
94 pub fn append_translation(self, translation: $Vec2) -> Self {
95 Self {
96 rotation: self.rotation,
97 translation: self.translation + translation,
98 }
99 }
100
101 #[inline]
103 pub fn inverse(&self) -> Self {
104 let inv_rot = self.rotation.inverse();
105 Self {
106 rotation: inv_rot,
107 translation: inv_rot.transform_vector(-self.translation),
108 }
109 }
110
111 #[inline]
113 pub fn inv_mul(&self, rhs: &Self) -> Self {
114 self.inverse() * *rhs
115 }
116
117 #[inline]
121 pub fn transform_point(&self, p: $Vec2) -> $Vec2 {
122 self.rotation.transform_vector(p) + self.translation
123 }
124
125 #[inline]
129 pub fn transform_vector(&self, v: $Vec2) -> $Vec2 {
130 self.rotation.transform_vector(v)
131 }
132
133 #[inline]
135 pub fn inverse_transform_point(&self, p: $Vec2) -> $Vec2 {
136 self.rotation.inverse_transform_vector(p - self.translation)
137 }
138
139 #[inline]
141 pub fn inverse_transform_vector(&self, v: $Vec2) -> $Vec2 {
142 self.rotation.inverse_transform_vector(v)
143 }
144
145 #[inline]
149 pub fn lerp(&self, other: &Self, t: $Real) -> Self {
150 Self {
151 rotation: self.rotation.slerp(&other.rotation, t),
152 translation: self.translation.lerp(other.translation, t),
153 }
154 }
155
156 #[inline]
158 pub fn is_finite(&self) -> bool {
159 self.rotation.is_finite() && self.translation.is_finite()
160 }
161
162 #[inline]
164 pub fn is_nan(&self) -> bool {
165 self.rotation.is_nan() || self.translation.is_nan()
166 }
167
168 #[inline]
170 pub fn to_mat3(&self) -> $Mat3 {
171 let (sin, cos) = (self.rotation.sin(), self.rotation.cos());
172 <$Mat3>::from_cols(
173 <$Vec3>::new(cos, sin, 0.0),
174 <$Vec3>::new(-sin, cos, 0.0),
175 <$Vec3>::new(self.translation.x, self.translation.y, 1.0),
176 )
177 }
178
179 #[inline]
184 pub fn from_mat3(mat: $Mat3) -> Self {
185 let rotation = $Rot2::from_mat(<$Mat2>::from_cols(
186 mat.x_axis.truncate(),
187 mat.y_axis.truncate(),
188 ));
189 let translation = mat.z_axis.truncate();
190 Self { rotation, translation }
191 }
192 }
193
194 impl Mul<$Pose2> for $Pose2 {
196 type Output = Self;
197
198 #[inline]
199 fn mul(self, rhs: Self) -> Self::Output {
200 Self {
201 rotation: self.rotation * rhs.rotation,
202 translation: self.translation + self.rotation.transform_vector(rhs.translation),
203 }
204 }
205 }
206
207 impl MulAssign<$Pose2> for $Pose2 {
208 #[inline]
209 fn mul_assign(&mut self, rhs: Self) {
210 *self = *self * rhs;
211 }
212 }
213
214 impl Mul<$Vec2> for $Pose2 {
216 type Output = $Vec2;
217
218 #[inline]
219 fn mul(self, rhs: $Vec2) -> Self::Output {
220 self.transform_point(rhs)
221 }
222 }
223
224 impl Mul<$Vec2> for &$Pose2 {
225 type Output = $Vec2;
226
227 #[inline]
228 fn mul(self, rhs: $Vec2) -> Self::Output {
229 self.transform_point(rhs)
230 }
231 }
232
233 impl Mul<&$Vec2> for $Pose2 {
234 type Output = $Vec2;
235
236 #[inline]
237 fn mul(self, rhs: &$Vec2) -> Self::Output {
238 self.transform_point(*rhs)
239 }
240 }
241
242 impl Default for $Pose2 {
243 fn default() -> Self {
244 Self::IDENTITY
245 }
246 }
247
248 impl Mul<&$Pose2> for &$Pose2 {
250 type Output = $Pose2;
251
252 #[inline]
253 fn mul(self, rhs: &$Pose2) -> Self::Output {
254 *self * *rhs
255 }
256 }
257
258 impl Mul<&$Pose2> for $Pose2 {
260 type Output = $Pose2;
261
262 #[inline]
263 fn mul(self, rhs: &$Pose2) -> Self::Output {
264 self * *rhs
265 }
266 }
267
268 impl Mul<$Pose2> for &$Pose2 {
270 type Output = $Pose2;
271
272 #[inline]
273 fn mul(self, rhs: $Pose2) -> Self::Output {
274 *self * rhs
275 }
276 }
277
278 impl Mul<$Pose2> for $Rot2 {
279 type Output = $Pose2;
280
281 #[inline]
282 fn mul(self, rhs: $Pose2) -> Self::Output {
283 $Pose2 {
284 translation: self * rhs.translation,
285 rotation: self * rhs.rotation,
286 }
287 }
288 }
289
290 impl Mul<$Rot2> for $Pose2 {
291 type Output = $Pose2;
292
293 #[inline]
294 fn mul(self, rhs: $Rot2) -> Self::Output {
295 $Pose2 {
296 translation: self.translation,
297 rotation: self.rotation * rhs,
298 }
299 }
300 }
301
302 impl MulAssign<$Rot2> for $Pose2 {
303 #[inline]
304 fn mul_assign(&mut self, rhs: $Rot2) {
305 *self = *self * rhs;
306 }
307 }
308
309 impl From<$Rot2> for $Pose2 {
310 #[inline]
311 fn from(rotation: $Rot2) -> Self {
312 Self::from_rotation(rotation)
313 }
314 }
315
316 #[cfg(feature = "approx")]
317 impl approx::AbsDiffEq for $Pose2 {
318 type Epsilon = $Real;
319
320 fn default_epsilon() -> Self::Epsilon {
321 <$Real>::EPSILON
322 }
323
324 fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
325 self.rotation.abs_diff_eq(&other.rotation, epsilon)
326 && self.translation.abs_diff_eq(other.translation, epsilon)
327 }
328 }
329
330 #[cfg(feature = "approx")]
331 impl approx::RelativeEq for $Pose2 {
332 fn default_max_relative() -> Self::Epsilon {
333 <$Real>::EPSILON
334 }
335
336 fn relative_eq(
337 &self,
338 other: &Self,
339 epsilon: Self::Epsilon,
340 max_relative: Self::Epsilon,
341 ) -> bool {
342 self.rotation.relative_eq(&other.rotation, epsilon, max_relative)
343 && self.translation.abs_diff_eq(other.translation, epsilon.max(max_relative))
344 }
345 }
346 };
347}
348
349impl_pose2!(
350 Pose2,
351 Rot2,
352 f32,
353 glam::Vec2,
354 glam::Vec3,
355 glam::Mat2,
356 glam::Mat3,
357 #[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))]
358);
359impl_pose2!(
360 DPose2,
361 DRot2,
362 f64,
363 glam::DVec2,
364 glam::DVec3,
365 glam::DMat2,
366 glam::DMat3
367);
368
369impl From<Pose2> for DPose2 {
371 #[inline]
372 fn from(p: Pose2) -> Self {
373 Self {
374 rotation: p.rotation.into(),
375 translation: p.translation.into(),
376 }
377 }
378}
379
380impl From<DPose2> for Pose2 {
381 #[inline]
382 fn from(p: DPose2) -> Self {
383 Self {
384 rotation: p.rotation.into(),
385 translation: p.translation.as_vec2(),
386 }
387 }
388}
389
390#[cfg(feature = "nalgebra")]
392mod nalgebra_conv {
393 use super::*;
394
395 impl From<Pose2> for nalgebra::Isometry2<f32> {
396 fn from(p: Pose2) -> Self {
397 nalgebra::Isometry2 {
398 translation: p.translation.into(),
399 rotation: p.rotation.into(),
400 }
401 }
402 }
403
404 impl From<nalgebra::Isometry2<f32>> for Pose2 {
405 fn from(iso: nalgebra::Isometry2<f32>) -> Self {
406 Self {
407 rotation: Rot2::from_cos_sin_unchecked(iso.rotation.re, iso.rotation.im),
408 translation: glam::Vec2::new(iso.translation.x, iso.translation.y),
409 }
410 }
411 }
412
413 impl From<DPose2> for nalgebra::Isometry2<f64> {
414 fn from(p: DPose2) -> Self {
415 nalgebra::Isometry2 {
416 translation: p.translation.into(),
417 rotation: p.rotation.into(),
418 }
419 }
420 }
421
422 impl From<nalgebra::Isometry2<f64>> for DPose2 {
423 fn from(iso: nalgebra::Isometry2<f64>) -> Self {
424 Self {
425 rotation: DRot2::from_cos_sin_unchecked(iso.rotation.re, iso.rotation.im),
426 translation: glam::DVec2::new(iso.translation.x, iso.translation.y),
427 }
428 }
429 }
430}
431
432#[cfg(test)]
433mod tests {
434 use super::*;
435 use approx::assert_relative_eq;
436 use core::f32::consts::PI;
437
438 #[test]
439 fn test_pose2_identity() {
440 let p = Pose2::IDENTITY;
441 assert_eq!(p.rotation, Rot2::IDENTITY);
442 assert_eq!(p.translation, glam::Vec2::ZERO);
443 assert!(p.is_finite());
444 }
445
446 #[test]
447 fn test_pose2_from_translation() {
448 let t = glam::Vec2::new(1.0, 2.0);
449 let p = Pose2::from_translation(t);
450 assert_eq!(p.translation, t);
451 assert_eq!(p.rotation, Rot2::IDENTITY);
452 }
453
454 #[test]
455 fn test_pose2_from_rotation_translation() {
456 let t = glam::Vec2::new(1.0, 2.0);
457 let r = Rot2::new(PI / 4.0);
458 let p = Pose2::from_parts(t, r);
459 assert_eq!(p.translation, t);
460 assert_eq!(p.rotation, r);
461 }
462
463 #[test]
464 fn test_pose2_transform_point() {
465 let p = Pose2::new(glam::Vec2::new(1.0, 0.0), PI / 2.0);
466 let point = glam::Vec2::new(1.0, 0.0);
467 let result = p.transform_point(point);
468 assert_relative_eq!(result.x, 1.0, epsilon = 1e-6);
469 assert_relative_eq!(result.y, 1.0, epsilon = 1e-6);
470 let result2 = p * point;
472 assert_relative_eq!(result2.x, 1.0, epsilon = 1e-6);
473 assert_relative_eq!(result2.y, 1.0, epsilon = 1e-6);
474 }
475
476 #[test]
477 fn test_pose2_transform_vector() {
478 let p = Pose2::new(glam::Vec2::new(100.0, 200.0), PI / 2.0);
479 let vector = glam::Vec2::new(1.0, 0.0);
480 let result = p.transform_vector(vector);
482 assert_relative_eq!(result.x, 0.0, epsilon = 1e-6);
483 assert_relative_eq!(result.y, 1.0, epsilon = 1e-6);
484 }
485
486 #[test]
487 fn test_pose2_inverse() {
488 let p = Pose2::new(glam::Vec2::new(1.0, 2.0), 0.5);
489 let inv = p.inverse();
490 let identity = p * inv;
491 assert_relative_eq!(identity.rotation.re, 1.0, epsilon = 1e-6);
492 assert_relative_eq!(identity.rotation.im, 0.0, epsilon = 1e-6);
493 assert_relative_eq!(identity.translation.x, 0.0, epsilon = 1e-6);
494 assert_relative_eq!(identity.translation.y, 0.0, epsilon = 1e-6);
495 }
496
497 #[test]
498 fn test_pose2_to_from_mat3() {
499 let p = Pose2::new(glam::Vec2::new(1.0, 2.0), PI / 4.0);
500 let m = p.to_mat3();
501 let p2 = Pose2::from_mat3(m);
502 assert_relative_eq!(p.rotation.re, p2.rotation.re, epsilon = 1e-6);
503 assert_relative_eq!(p.rotation.im, p2.rotation.im, epsilon = 1e-6);
504 assert_relative_eq!(p.translation.x, p2.translation.x, epsilon = 1e-6);
505 assert_relative_eq!(p.translation.y, p2.translation.y, epsilon = 1e-6);
506 }
507
508 #[test]
509 fn test_dpose2_new() {
510 let p = DPose2::new(glam::DVec2::new(1.0, 2.0), core::f64::consts::PI / 4.0);
511 assert_relative_eq!(p.translation.x, 1.0, epsilon = 1e-10);
512 assert_relative_eq!(p.translation.y, 2.0, epsilon = 1e-10);
513 }
514}