dioxus_motion/animations/
transform.rs1use crate::Animatable;
11use wide::f32x4;
12
13#[derive(Debug, Copy, Clone, PartialEq)]
22pub struct Transform {
23 pub x: f32,
25 pub y: f32,
27 pub scale: f32,
29 pub rotation: f32,
31}
32
33impl Transform {
34 pub fn new(x: f32, y: f32, scale: f32, rotation: f32) -> Self {
36 Self {
37 x,
38 y,
39 scale,
40 rotation,
41 }
42 }
43
44 pub fn identity() -> Self {
46 Self {
47 x: 0.0,
48 y: 0.0,
49 scale: 1.0,
50 rotation: 0.0,
51 }
52 }
53}
54
55impl Default for Transform {
56 fn default() -> Self {
57 Transform::identity()
58 }
59}
60
61impl std::ops::Add for Transform {
62 type Output = Self;
63
64 fn add(self, other: Self) -> Self {
65 Transform::new(
66 self.x + other.x,
67 self.y + other.y,
68 self.scale + other.scale,
69 self.rotation + other.rotation,
70 )
71 }
72}
73
74impl std::ops::Sub for Transform {
75 type Output = Self;
76
77 fn sub(self, other: Self) -> Self {
78 Transform::new(
79 self.x - other.x,
80 self.y - other.y,
81 self.scale - other.scale,
82 self.rotation - other.rotation,
83 )
84 }
85}
86
87impl std::ops::Mul<f32> for Transform {
88 type Output = Self;
89
90 fn mul(self, factor: f32) -> Self {
91 Transform::new(
92 self.x * factor,
93 self.y * factor,
94 self.scale * factor,
95 self.rotation * factor,
96 )
97 }
98}
99
100impl Animatable for f32 {
103 fn interpolate(&self, target: &Self, t: f32) -> Self {
104 self + (target - self) * t
105 }
106
107 fn magnitude(&self) -> f32 {
108 self.abs()
109 }
110
111 }
113
114impl Animatable for Transform {
117 fn interpolate(&self, target: &Self, t: f32) -> Self {
118 let a = [self.x, self.y, self.scale, 0.0];
120 let b = [target.x, target.y, target.scale, 0.0];
121 let va = f32x4::new(a);
122 let vb = f32x4::new(b);
123 let vt = f32x4::splat(t.clamp(0.0, 1.0));
124 let result = va + (vb - va) * vt;
125 let out = result.to_array();
126
127 let mut rotation_diff = target.rotation - self.rotation;
129 if rotation_diff > std::f32::consts::PI {
130 rotation_diff -= 2.0 * std::f32::consts::PI;
131 } else if rotation_diff < -std::f32::consts::PI {
132 rotation_diff += 2.0 * std::f32::consts::PI;
133 }
134 let rotation = self.rotation + rotation_diff * t;
135
136 Transform::new(out[0], out[1], out[2], rotation)
137 }
138
139 fn magnitude(&self) -> f32 {
140 (self.x * self.x
141 + self.y * self.y
142 + self.scale * self.scale
143 + self.rotation * self.rotation)
144 .sqrt()
145 }
146
147 }
149
150#[cfg(test)]
151mod tests {
152 use super::*;
153 use std::f32::consts::PI;
154
155 #[test]
156 fn test_transform_new() {
157 let transform = Transform::new(100.0, 50.0, 1.5, PI / 4.0);
158 assert_eq!(transform.x, 100.0);
159 assert_eq!(transform.y, 50.0);
160 assert_eq!(transform.scale, 1.5);
161 assert!((transform.rotation - PI / 4.0).abs() < f32::EPSILON);
162 }
163
164 #[test]
165 fn test_transform_default() {
166 let transform = Transform::identity();
167 assert_eq!(transform.x, 0.0);
168 assert_eq!(transform.y, 0.0);
169 assert_eq!(transform.scale, 1.0);
170 assert_eq!(transform.rotation, 0.0);
171 }
172
173 #[test]
174 fn test_transform_lerp() {
175 let start = Transform::new(0.0, 0.0, 1.0, 0.0);
176 let end = Transform::new(100.0, 100.0, 2.0, PI);
177 let mid = start.interpolate(&end, 0.5);
178
179 assert_eq!(mid.x, 50.0);
180 assert_eq!(mid.y, 50.0);
181 assert_eq!(mid.scale, 1.5);
182 assert!((mid.rotation - PI / 2.0).abs() < f32::EPSILON);
183 }
184}