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 #[inline]
87 pub fn from_scale_about(scale: f64, focus: impl Into<Point>) -> Self {
88 let focus = focus.into().to_vec2();
92 let translation = focus - focus * scale;
93 Self::new(translation, scale)
94 }
95
96 #[inline]
104 pub fn inverse(self) -> TranslateScale {
105 let scale_recip = self.scale.recip();
106 TranslateScale {
107 translation: self.translation * -scale_recip,
108 scale: scale_recip,
109 }
110 }
111
112 #[inline]
116 pub fn is_finite(&self) -> bool {
117 self.translation.is_finite() && self.scale.is_finite()
118 }
119
120 #[inline]
124 pub fn is_nan(&self) -> bool {
125 self.translation.is_nan() || self.scale.is_nan()
126 }
127}
128
129impl Default for TranslateScale {
130 #[inline(always)]
131 fn default() -> TranslateScale {
132 TranslateScale::new(Vec2::ZERO, 1.0)
133 }
134}
135
136impl From<TranslateScale> for Affine {
137 #[inline(always)]
138 fn from(ts: TranslateScale) -> Affine {
139 let TranslateScale { translation, scale } = ts;
140 Affine::new([scale, 0.0, 0.0, scale, translation.x, translation.y])
141 }
142}
143
144impl Mul<Point> for TranslateScale {
145 type Output = Point;
146
147 #[inline]
148 fn mul(self, other: Point) -> Point {
149 (self.scale * other.to_vec2()).to_point() + self.translation
150 }
151}
152
153impl Mul for TranslateScale {
154 type Output = TranslateScale;
155
156 #[inline]
157 fn mul(self, other: TranslateScale) -> TranslateScale {
158 TranslateScale {
159 translation: self.translation + self.scale * other.translation,
160 scale: self.scale * other.scale,
161 }
162 }
163}
164
165impl MulAssign for TranslateScale {
166 #[inline]
167 fn mul_assign(&mut self, other: TranslateScale) {
168 *self = self.mul(other);
169 }
170}
171
172impl Mul<TranslateScale> for f64 {
173 type Output = TranslateScale;
174
175 #[inline]
176 fn mul(self, other: TranslateScale) -> TranslateScale {
177 TranslateScale {
178 translation: other.translation * self,
179 scale: other.scale * self,
180 }
181 }
182}
183
184impl Add<Vec2> for TranslateScale {
185 type Output = TranslateScale;
186
187 #[inline]
188 fn add(self, other: Vec2) -> TranslateScale {
189 TranslateScale {
190 translation: self.translation + other,
191 scale: self.scale,
192 }
193 }
194}
195
196impl Add<TranslateScale> for Vec2 {
197 type Output = TranslateScale;
198
199 #[inline]
200 fn add(self, other: TranslateScale) -> TranslateScale {
201 other + self
202 }
203}
204
205impl AddAssign<Vec2> for TranslateScale {
206 #[inline]
207 fn add_assign(&mut self, other: Vec2) {
208 *self = self.add(other);
209 }
210}
211
212impl Sub<Vec2> for TranslateScale {
213 type Output = TranslateScale;
214
215 #[inline]
216 fn sub(self, other: Vec2) -> TranslateScale {
217 TranslateScale {
218 translation: self.translation - other,
219 scale: self.scale,
220 }
221 }
222}
223
224impl SubAssign<Vec2> for TranslateScale {
225 #[inline]
226 fn sub_assign(&mut self, other: Vec2) {
227 *self = self.sub(other);
228 }
229}
230
231impl Mul<Circle> for TranslateScale {
232 type Output = Circle;
233
234 #[inline]
235 fn mul(self, other: Circle) -> Circle {
236 Circle::new(self * other.center, self.scale * other.radius)
237 }
238}
239
240impl Mul<Line> for TranslateScale {
241 type Output = Line;
242
243 #[inline]
244 fn mul(self, other: Line) -> Line {
245 Line::new(self * other.p0, self * other.p1)
246 }
247}
248
249impl Mul<Rect> for TranslateScale {
250 type Output = Rect;
251
252 #[inline]
253 fn mul(self, other: Rect) -> Rect {
254 let pt0 = self * Point::new(other.x0, other.y0);
255 let pt1 = self * Point::new(other.x1, other.y1);
256 (pt0, pt1).into()
257 }
258}
259
260impl Mul<RoundedRect> for TranslateScale {
261 type Output = RoundedRect;
262
263 #[inline]
264 fn mul(self, other: RoundedRect) -> RoundedRect {
265 RoundedRect::from_rect(self * other.rect(), self * other.radii())
266 }
267}
268
269impl Mul<RoundedRectRadii> for TranslateScale {
270 type Output = RoundedRectRadii;
271
272 #[inline]
273 fn mul(self, other: RoundedRectRadii) -> RoundedRectRadii {
274 RoundedRectRadii::new(
275 self.scale * other.top_left,
276 self.scale * other.top_right,
277 self.scale * other.bottom_right,
278 self.scale * other.bottom_left,
279 )
280 }
281}
282
283impl Mul<QuadBez> for TranslateScale {
284 type Output = QuadBez;
285
286 #[inline]
287 fn mul(self, other: QuadBez) -> QuadBez {
288 QuadBez::new(self * other.p0, self * other.p1, self * other.p2)
289 }
290}
291
292impl Mul<CubicBez> for TranslateScale {
293 type Output = CubicBez;
294
295 #[inline]
296 fn mul(self, other: CubicBez) -> CubicBez {
297 CubicBez::new(
298 self * other.p0,
299 self * other.p1,
300 self * other.p2,
301 self * other.p3,
302 )
303 }
304}
305
306#[cfg(test)]
307mod tests {
308 use crate::{Affine, Point, TranslateScale, Vec2};
309
310 fn assert_near(p0: Point, p1: Point) {
311 assert!((p1 - p0).hypot() < 1e-9, "{p0:?} != {p1:?}");
312 }
313
314 #[test]
315 fn translate_scale() {
316 let p = Point::new(3.0, 4.0);
317 let ts = TranslateScale::new(Vec2::new(5.0, 6.0), 2.0);
318
319 assert_near(ts * p, Point::new(11.0, 14.0));
320 }
321
322 #[test]
323 fn conversions() {
324 let p = Point::new(3.0, 4.0);
325 let s = 2.0;
326 let t = Vec2::new(5.0, 6.0);
327 let ts = TranslateScale::new(t, s);
328
329 let a: Affine = ts.into();
331 assert_near(ts * p, a * p);
332
333 assert_near((s * p.to_vec2()).to_point(), TranslateScale::scale(s) * p);
334 assert_near(p + t, TranslateScale::translate(t) * p);
335 }
336
337 #[test]
338 fn inverse() {
339 let p = Point::new(3.0, 4.0);
340 let ts = TranslateScale::new(Vec2::new(5.0, 6.0), 2.0);
341
342 assert_near(p, (ts * ts.inverse()) * p);
343 assert_near(p, (ts.inverse() * ts) * p);
344 }
345}