1use core::ops::{Add, AddAssign, Mul, MulAssign, Sub, SubAssign};
7
8use crate::{
9 Affine, Circle, CubicBez, Line, Point, QuadBez, Rect, RoundedRect, RoundedRectRadii, Vec2,
10};
11
12#[derive(Clone, Copy, Debug)]
42#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
43#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
44pub struct TranslateScale {
45 pub translation: Vec2,
47 pub scale: f64,
49}
50
51impl TranslateScale {
52 #[inline(always)]
54 pub const fn new(translation: Vec2, scale: f64) -> TranslateScale {
55 TranslateScale { translation, scale }
56 }
57
58 #[inline(always)]
60 pub const fn scale(s: f64) -> TranslateScale {
61 TranslateScale::new(Vec2::ZERO, s)
62 }
63
64 #[inline(always)]
66 pub fn translate(translation: impl Into<Vec2>) -> TranslateScale {
67 TranslateScale::new(translation.into(), 1.0)
68 }
69
70 #[deprecated(note = "use the struct fields directly")]
72 #[inline(always)]
73 pub const fn as_tuple(self) -> (Vec2, f64) {
74 (self.translation, self.scale)
75 }
76
77 #[inline]
94 pub fn from_scale_about(scale: f64, focus: impl Into<Point>) -> Self {
95 let focus = focus.into().to_vec2();
99 let translation = focus - focus * scale;
100 Self::new(translation, scale)
101 }
102
103 #[inline]
111 pub fn inverse(self) -> TranslateScale {
112 let scale_recip = self.scale.recip();
113 TranslateScale {
114 translation: self.translation * -scale_recip,
115 scale: scale_recip,
116 }
117 }
118
119 #[inline]
123 pub fn is_finite(&self) -> bool {
124 self.translation.is_finite() && self.scale.is_finite()
125 }
126
127 #[inline]
131 pub fn is_nan(&self) -> bool {
132 self.translation.is_nan() || self.scale.is_nan()
133 }
134}
135
136impl Default for TranslateScale {
137 #[inline(always)]
138 fn default() -> TranslateScale {
139 TranslateScale::new(Vec2::ZERO, 1.0)
140 }
141}
142
143impl From<TranslateScale> for Affine {
144 #[inline(always)]
145 fn from(ts: TranslateScale) -> Affine {
146 let TranslateScale { translation, scale } = ts;
147 Affine::new([scale, 0.0, 0.0, scale, translation.x, translation.y])
148 }
149}
150
151impl Mul<Point> for TranslateScale {
152 type Output = Point;
153
154 #[inline]
155 fn mul(self, other: Point) -> Point {
156 (self.scale * other.to_vec2()).to_point() + self.translation
157 }
158}
159
160impl Mul for TranslateScale {
161 type Output = TranslateScale;
162
163 #[inline]
164 fn mul(self, other: TranslateScale) -> TranslateScale {
165 TranslateScale {
166 translation: self.translation + self.scale * other.translation,
167 scale: self.scale * other.scale,
168 }
169 }
170}
171
172impl MulAssign for TranslateScale {
173 #[inline]
174 fn mul_assign(&mut self, other: TranslateScale) {
175 *self = self.mul(other);
176 }
177}
178
179impl Mul<TranslateScale> for f64 {
180 type Output = TranslateScale;
181
182 #[inline]
183 fn mul(self, other: TranslateScale) -> TranslateScale {
184 TranslateScale {
185 translation: other.translation * self,
186 scale: other.scale * self,
187 }
188 }
189}
190
191impl Add<Vec2> for TranslateScale {
192 type Output = TranslateScale;
193
194 #[inline]
195 fn add(self, other: Vec2) -> TranslateScale {
196 TranslateScale {
197 translation: self.translation + other,
198 scale: self.scale,
199 }
200 }
201}
202
203impl Add<TranslateScale> for Vec2 {
204 type Output = TranslateScale;
205
206 #[inline]
207 fn add(self, other: TranslateScale) -> TranslateScale {
208 other + self
209 }
210}
211
212impl AddAssign<Vec2> for TranslateScale {
213 #[inline]
214 fn add_assign(&mut self, other: Vec2) {
215 *self = self.add(other);
216 }
217}
218
219impl Sub<Vec2> for TranslateScale {
220 type Output = TranslateScale;
221
222 #[inline]
223 fn sub(self, other: Vec2) -> TranslateScale {
224 TranslateScale {
225 translation: self.translation - other,
226 scale: self.scale,
227 }
228 }
229}
230
231impl SubAssign<Vec2> for TranslateScale {
232 #[inline]
233 fn sub_assign(&mut self, other: Vec2) {
234 *self = self.sub(other);
235 }
236}
237
238impl Mul<Circle> for TranslateScale {
239 type Output = Circle;
240
241 #[inline]
242 fn mul(self, other: Circle) -> Circle {
243 Circle::new(self * other.center, self.scale * other.radius)
244 }
245}
246
247impl Mul<Line> for TranslateScale {
248 type Output = Line;
249
250 #[inline]
251 fn mul(self, other: Line) -> Line {
252 Line::new(self * other.p0, self * other.p1)
253 }
254}
255
256impl Mul<Rect> for TranslateScale {
257 type Output = Rect;
258
259 #[inline]
260 fn mul(self, other: Rect) -> Rect {
261 let pt0 = self * Point::new(other.x0, other.y0);
262 let pt1 = self * Point::new(other.x1, other.y1);
263 (pt0, pt1).into()
264 }
265}
266
267impl Mul<RoundedRect> for TranslateScale {
268 type Output = RoundedRect;
269
270 #[inline]
271 fn mul(self, other: RoundedRect) -> RoundedRect {
272 RoundedRect::from_rect(self * other.rect(), self * other.radii())
273 }
274}
275
276impl Mul<RoundedRectRadii> for TranslateScale {
277 type Output = RoundedRectRadii;
278
279 #[inline]
280 fn mul(self, other: RoundedRectRadii) -> RoundedRectRadii {
281 RoundedRectRadii::new(
282 self.scale * other.top_left,
283 self.scale * other.top_right,
284 self.scale * other.bottom_right,
285 self.scale * other.bottom_left,
286 )
287 }
288}
289
290impl Mul<QuadBez> for TranslateScale {
291 type Output = QuadBez;
292
293 #[inline]
294 fn mul(self, other: QuadBez) -> QuadBez {
295 QuadBez::new(self * other.p0, self * other.p1, self * other.p2)
296 }
297}
298
299impl Mul<CubicBez> for TranslateScale {
300 type Output = CubicBez;
301
302 #[inline]
303 fn mul(self, other: CubicBez) -> CubicBez {
304 CubicBez::new(
305 self * other.p0,
306 self * other.p1,
307 self * other.p2,
308 self * other.p3,
309 )
310 }
311}
312
313#[cfg(test)]
314mod tests {
315 use crate::{Affine, Point, TranslateScale, Vec2};
316
317 fn assert_near(p0: Point, p1: Point) {
318 assert!((p1 - p0).hypot() < 1e-9, "{p0:?} != {p1:?}");
319 }
320
321 #[test]
322 fn translate_scale() {
323 let p = Point::new(3.0, 4.0);
324 let ts = TranslateScale::new(Vec2::new(5.0, 6.0), 2.0);
325
326 assert_near(ts * p, Point::new(11.0, 14.0));
327 }
328
329 #[test]
330 fn conversions() {
331 let p = Point::new(3.0, 4.0);
332 let s = 2.0;
333 let t = Vec2::new(5.0, 6.0);
334 let ts = TranslateScale::new(t, s);
335
336 let a: Affine = ts.into();
338 assert_near(ts * p, a * p);
339
340 assert_near((s * p.to_vec2()).to_point(), TranslateScale::scale(s) * p);
341 assert_near(p + t, TranslateScale::translate(t) * p);
342 }
343
344 #[test]
345 fn inverse() {
346 let p = Point::new(3.0, 4.0);
347 let ts = TranslateScale::new(Vec2::new(5.0, 6.0), 2.0);
348
349 assert_near(p, (ts * ts.inverse()) * p);
350 assert_near(p, (ts.inverse() * ts) * p);
351 }
352}