1// pathfinder/geometry/src/basic/transform2d.rs
2//
3// Copyright © 2019 The Pathfinder Project Developers.
4//
5// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8// option. This file may not be copied, modified, or distributed
9// except according to those terms.
10
11//! 2D affine transforms.
12
13use crate::line_segment::LineSegment2F;
14use crate::rect::RectF;
15use crate::transform3d::Transform4F;
16use crate::unit_vector::UnitVector;
17use crate::vector::{IntoVector2F, Vector2F, vec2f};
18use pathfinder_simd::default::F32x4;
19use std::ops::{Mul, MulAssign, Sub};
20
21/// A 2x2 matrix, optimized with SIMD, in column-major order.
22#[derive(Clone, Copy, Debug, PartialEq)]
23pub struct Matrix2x2F(pub F32x4);
24
25impl Default for Matrix2x2F {
26 #[inline]
27 fn default() -> Matrix2x2F {
28 Self::from_scale(1.0)
29 }
30}
31
32impl Matrix2x2F {
33 #[inline]
34 pub fn from_scale<S>(scale: S) -> Matrix2x2F where S: IntoVector2F {
35 let scale = scale.into_vector_2f();
36 Matrix2x2F(F32x4::new(scale.x(), 0.0, 0.0, scale.y()))
37 }
38
39 #[inline]
40 pub fn from_rotation(theta: f32) -> Matrix2x2F {
41 Matrix2x2F::from_rotation_vector(UnitVector::from_angle(theta))
42 }
43
44 #[inline]
45 pub fn from_rotation_vector(vector: UnitVector) -> Matrix2x2F {
46 Matrix2x2F((vector.0).0.to_f32x4().xyyx() * F32x4::new(1.0, 1.0, -1.0, 1.0))
47 }
48
49 #[inline]
50 pub fn row_major(m00: f32, m01: f32, m10: f32, m11: f32) -> Matrix2x2F {
51 Matrix2x2F(F32x4::new(m00, m10, m01, m11))
52 }
53
54 #[inline]
55 pub fn entrywise_mul(&self, other: &Matrix2x2F) -> Matrix2x2F {
56 Matrix2x2F(self.0 * other.0)
57 }
58
59 #[inline]
60 pub fn adjugate(&self) -> Matrix2x2F {
61 Matrix2x2F(self.0.wyzx() * F32x4::new(1.0, -1.0, -1.0, 1.0))
62 }
63
64 #[inline]
65 pub fn det(&self) -> f32 {
66 self.0[0] * self.0[3] - self.0[2] * self.0[1]
67 }
68
69 #[inline]
70 pub fn inverse(&self) -> Matrix2x2F {
71 Matrix2x2F(F32x4::splat(1.0 / self.det()) * self.adjugate().0)
72 }
73
74 #[inline]
75 pub fn scale(&self, factor: f32) -> Matrix2x2F {
76 Matrix2x2F(self.0 * F32x4::splat(factor))
77 }
78
79 /// Extracts the scale from this matrix.
80 #[inline]
81 pub fn extract_scale(&self) -> Vector2F {
82 let squared = self.0 * self.0;
83 Vector2F((squared.xy() + squared.zw()).sqrt())
84 }
85
86 #[inline]
87 pub fn m11(&self) -> f32 {
88 self.0[0]
89 }
90
91 #[inline]
92 pub fn m21(&self) -> f32 {
93 self.0[1]
94 }
95
96 #[inline]
97 pub fn m12(&self) -> f32 {
98 self.0[2]
99 }
100
101 #[inline]
102 pub fn m22(&self) -> f32 {
103 self.0[3]
104 }
105}
106
107impl Sub<Matrix2x2F> for Matrix2x2F {
108 type Output = Matrix2x2F;
109 #[inline]
110 fn sub(self, other: Matrix2x2F) -> Matrix2x2F {
111 Matrix2x2F(self.0 - other.0)
112 }
113}
114
115impl Mul<Matrix2x2F> for Matrix2x2F {
116 type Output = Matrix2x2F;
117 #[inline]
118 fn mul(self, other: Matrix2x2F) -> Matrix2x2F {
119 Matrix2x2F(self.0.xyxy() * other.0.xxzz() + self.0.zwzw() * other.0.yyww())
120 }
121}
122
123impl Mul<Vector2F> for Matrix2x2F {
124 type Output = Vector2F;
125 #[inline]
126 fn mul(self, vector: Vector2F) -> Vector2F {
127 let halves: F32x4 = self.0 * vector.0.to_f32x4().xxyy();
128 Vector2F(halves.xy() + halves.zw())
129 }
130}
131
132/// An affine transform, optimized with SIMD.
133#[derive(Clone, Copy, Debug, PartialEq)]
134pub struct Transform2F {
135 pub matrix: Matrix2x2F,
136 pub vector: Vector2F,
137}
138
139impl Default for Transform2F {
140 #[inline]
141 fn default() -> Transform2F {
142 Self::from_scale(vec2f(x:1.0, y:1.0))
143 }
144}
145
146impl Transform2F {
147 #[inline]
148 pub fn from_scale<S>(scale: S) -> Transform2F where S: IntoVector2F {
149 let scale = scale.into_vector_2f();
150 Transform2F {
151 matrix: Matrix2x2F::from_scale(scale),
152 vector: Vector2F::zero(),
153 }
154 }
155
156 #[inline]
157 pub fn from_rotation(theta: f32) -> Transform2F {
158 Transform2F {
159 matrix: Matrix2x2F::from_rotation(theta),
160 vector: Vector2F::zero(),
161 }
162 }
163
164 #[inline]
165 pub fn from_rotation_vector(vector: UnitVector) -> Transform2F {
166 Transform2F {
167 matrix: Matrix2x2F::from_rotation_vector(vector),
168 vector: Vector2F::zero(),
169 }
170 }
171
172 #[inline]
173 pub fn from_translation(vector: Vector2F) -> Transform2F {
174 Transform2F { matrix: Matrix2x2F::default(), vector }
175 }
176
177 #[inline]
178 pub fn from_scale_rotation_translation<S>(scale: S, theta: f32, translation: Vector2F)
179 -> Transform2F where S: IntoVector2F {
180 let scale = scale.into_vector_2f();
181 let rotation = Transform2F::from_rotation(theta);
182 let translation = Transform2F::from_translation(translation);
183 Transform2F::from_scale(scale) * rotation * translation
184 }
185
186 #[inline]
187 pub fn row_major(m11: f32, m12: f32, m21: f32, m22: f32, m31: f32, m32: f32) -> Transform2F {
188 Transform2F {
189 matrix: Matrix2x2F::row_major(m11, m12, m21, m22),
190 vector: Vector2F::new(m31, m32),
191 }
192 }
193
194 // TODO(pcwalton): Optimize better with SIMD.
195 #[inline]
196 pub fn to_3d(&self) -> Transform4F {
197 Transform4F::row_major(
198 self.matrix.0[0],
199 self.matrix.0[1],
200 0.0,
201 self.vector.x(),
202 self.matrix.0[2],
203 self.matrix.0[3],
204 0.0,
205 self.vector.y(),
206 0.0,
207 0.0,
208 0.0,
209 0.0,
210 0.0,
211 0.0,
212 0.0,
213 1.0,
214 )
215 }
216
217 #[inline]
218 pub fn is_identity(&self) -> bool {
219 *self == Transform2F::default()
220 }
221
222 /// Extracts the scale from this matrix.
223 #[inline]
224 pub fn extract_scale(&self) -> Vector2F {
225 self.matrix.extract_scale()
226 }
227
228 #[inline]
229 pub fn m11(&self) -> f32 {
230 self.matrix.m11()
231 }
232 #[inline]
233 pub fn m21(&self) -> f32 {
234 self.matrix.m21()
235 }
236 #[inline]
237 pub fn m12(&self) -> f32 {
238 self.matrix.m12()
239 }
240 #[inline]
241 pub fn m22(&self) -> f32 {
242 self.matrix.m22()
243 }
244 #[inline]
245 pub fn m31(&self) -> f32 {
246 self.vector.x()
247 }
248 #[inline]
249 pub fn m32(&self) -> f32 {
250 self.vector.y()
251 }
252
253 #[inline]
254 pub fn translate(&self, vector: Vector2F) -> Transform2F {
255 Transform2F::from_translation(vector) * *self
256 }
257
258 #[inline]
259 pub fn rotate(&self, theta: f32) -> Transform2F {
260 Transform2F::from_rotation(theta) * *self
261 }
262
263 #[inline]
264 pub fn scale<S>(&self, scale: S) -> Transform2F where S: IntoVector2F {
265 let scale = scale.into_vector_2f();
266 Transform2F::from_scale(scale) * *self
267 }
268
269 /// Returns the translation part of this matrix.
270 ///
271 /// This decomposition assumes that scale, rotation, and translation are applied in that order.
272 #[inline]
273 pub fn translation(&self) -> Vector2F {
274 self.vector
275 }
276
277 /// Returns the rotation angle of this matrix.
278 ///
279 /// This decomposition assumes that scale, rotation, and translation are applied in that order.
280 #[inline]
281 pub fn rotation(&self) -> f32 {
282 f32::atan2(self.m21(), self.m11())
283 }
284
285 /// Returns the scale factor of this matrix.
286 ///
287 /// This decomposition assumes that scale, rotation, and translation are applied in that order.
288 #[inline]
289 pub fn scale_factor(&self) -> f32 {
290 Vector2F(self.matrix.0.zw()).length()
291 }
292
293 #[inline]
294 pub fn inverse(&self) -> Transform2F {
295 let matrix_inv = self.matrix.inverse();
296 let vector_inv = -(matrix_inv * self.vector);
297 Transform2F { matrix: matrix_inv, vector: vector_inv }
298 }
299}
300
301impl Mul<Transform2F> for Transform2F {
302 type Output = Transform2F;
303 #[inline]
304 fn mul(self, other: Transform2F) -> Transform2F {
305 Transform2F {
306 matrix: self.matrix * other.matrix,
307 vector: self * other.vector,
308 }
309 }
310}
311
312impl Mul<Vector2F> for Transform2F {
313 type Output = Vector2F;
314 #[inline]
315 fn mul(self, vector: Vector2F) -> Vector2F {
316 self.matrix * vector + self.vector
317 }
318}
319
320impl Mul<LineSegment2F> for Transform2F {
321 type Output = LineSegment2F;
322 #[inline]
323 fn mul(self, line_segment: LineSegment2F) -> LineSegment2F {
324 LineSegment2F::new(self * line_segment.from(), self * line_segment.to())
325 }
326}
327
328impl Mul<RectF> for Transform2F {
329 type Output = RectF;
330 #[inline]
331 fn mul(self, rect: RectF) -> RectF {
332 let (upper_left: Vector2F, upper_right: Vector2F) = (self * rect.origin(), self * rect.upper_right());
333 let (lower_left: Vector2F, lower_right: Vector2F) = (self * rect.lower_left(), self * rect.lower_right());
334 let min_point: Vector2F = upper_left.min(upper_right).min(lower_left).min(lower_right);
335 let max_point: Vector2F = upper_left.max(upper_right).max(lower_left).max(lower_right);
336 RectF::from_points(origin:min_point, lower_right:max_point)
337 }
338}
339
340impl MulAssign for Transform2F {
341 #[inline]
342 fn mul_assign(&mut self, other: Transform2F) {
343 *self = *self * other
344 }
345}
346