jagua_rs/geometry/
d_transformation.rs

1use std::borrow::Borrow;
2use std::f32::consts::PI;
3use std::fmt::Display;
4
5use crate::geometry::Transformation;
6use ordered_float::NotNan;
7
8#[derive(Clone, Debug, PartialEq, Eq, Hash, Copy, Default)]
9/// [Proper rigid transformation](https://en.wikipedia.org/wiki/Rigid_transformation),
10/// decomposed into a rotation followed by a translation.
11pub struct DTransformation {
12    /// The rotation in radians
13    pub rotation: NotNan<f32>,
14    /// The translation in the x and y-axis
15    pub translation: (NotNan<f32>, NotNan<f32>),
16}
17
18impl DTransformation {
19    pub fn new(rotation: f32, translation: (f32, f32)) -> Self {
20        Self {
21            rotation: NotNan::new(rotation).expect("rotation is NaN"),
22            translation: (
23                NotNan::new(translation.0).expect("translation.0 is NaN"),
24                NotNan::new(translation.1).expect("translation.1 is NaN"),
25            ),
26        }
27    }
28
29    pub const fn empty() -> Self {
30        const _0: NotNan<f32> = unsafe { NotNan::new_unchecked(0.0) };
31        Self {
32            rotation: _0,
33            translation: (_0, _0),
34        }
35    }
36
37    pub fn rotation(&self) -> f32 {
38        self.rotation.into()
39    }
40
41    pub fn translation(&self) -> (f32, f32) {
42        (self.translation.0.into(), self.translation.1.into())
43    }
44
45    pub fn compose(&self) -> Transformation {
46        self.into()
47    }
48}
49
50impl<T> From<T> for DTransformation
51where
52    T: Borrow<Transformation>,
53{
54    fn from(t: T) -> Self {
55        t.borrow().decompose()
56    }
57}
58
59impl Display for DTransformation {
60    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
61        write!(
62            f,
63            "r: {:.3}°, t: ({:.3}, {:.3})",
64            self.rotation.to_degrees(),
65            self.translation.0.into_inner(),
66            self.translation.1.into_inner()
67        )
68    }
69}
70
71/// Normalizes a rotation angle to the range [0, 2π).
72pub fn normalize_rotation(r: f32) -> f32 {
73    let normalized = r % (2.0 * PI);
74    if normalized < 0.0 {
75        normalized + 2.0 * PI
76    } else {
77        normalized
78    }
79}