1// [Blend2D]
2// 2D Vector Graphics Powered by a JIT Compiler.
3//
4// [License]
5// Zlib - See LICENSE.md file in the package.
6
7#ifndef BLEND2D_BLMATRIX_H
8#define BLEND2D_BLMATRIX_H
9
10#include "./blgeometry.h"
11
12BL_DIAGNOSTIC_PUSH(BL_DIAGNOSTIC_NO_SHADOW)
13
14//! \addtogroup blend2d_api_geometry
15//! \{
16
17// ============================================================================
18// [Typedefs]
19// ============================================================================
20
21//! A generic function that can be used to transform an array of points that use
22//! `double` precision coordinates. This function will be 99.99% of time used with
23//! `BLMatrix2D` so the `ctx` would point to a `const BLMatrix2D*` instance.
24typedef BLResult (BL_CDECL* BLMapPointDArrayFunc)(const void* ctx, BLPoint* dst, const BLPoint* src, size_t count) BL_NOEXCEPT;
25
26// ============================================================================
27// [Constants]
28// ============================================================================
29
30//! 2D matrix type that can be obtained by calling `BLMatrix2D::type()`.
31//!
32//! ```
33//! Identity Transl. Scale Swap Affine
34//! [1 0] [1 0] [. 0] [0 .] [. .]
35//! [0 1] [0 1] [0 .] [. 0] [. .]
36//! [0 0] [. .] [. .] [. .] [. .]
37//! ```
38BL_DEFINE_ENUM(BLMatrix2DType) {
39 //! Identity matrix.
40 BL_MATRIX2D_TYPE_IDENTITY = 0,
41 //! Has translation part (the rest is like identity).
42 BL_MATRIX2D_TYPE_TRANSLATE = 1,
43 //! Has translation and scaling parts.
44 BL_MATRIX2D_TYPE_SCALE = 2,
45 //! Has translation and scaling parts, however scaling swaps X/Y.
46 BL_MATRIX2D_TYPE_SWAP = 3,
47 //! Generic affine matrix.
48 BL_MATRIX2D_TYPE_AFFINE = 4,
49 //! Invalid/degenerate matrix not useful for transformations.
50 BL_MATRIX2D_TYPE_INVALID = 5,
51
52 //! Count of matrix types.
53 BL_MATRIX2D_TYPE_COUNT = 6
54};
55
56//! 2D matrix data index.
57BL_DEFINE_ENUM(BLMatrix2DValue) {
58 //! Value at index 0 - M00.
59 BL_MATRIX2D_VALUE_00 = 0,
60 //! Value at index 1 - M01.
61 BL_MATRIX2D_VALUE_01 = 1,
62 //! Value at index 2 - M10.
63 BL_MATRIX2D_VALUE_10 = 2,
64 //! Value at index 3 - M11.
65 BL_MATRIX2D_VALUE_11 = 3,
66 //! Value at index 4 - M20.
67 BL_MATRIX2D_VALUE_20 = 4,
68 //! Value at index 5 - M21.
69 BL_MATRIX2D_VALUE_21 = 5,
70
71 //! Count of `BLMatrix2D` values.
72 BL_MATRIX2D_VALUE_COUNT = 6
73};
74
75//! 2D matrix operation.
76BL_DEFINE_ENUM(BLMatrix2DOp) {
77 //! Reset matrix to identity (argument ignored, should be nullptr).
78 BL_MATRIX2D_OP_RESET = 0,
79 //! Assign (copy) the other matrix.
80 BL_MATRIX2D_OP_ASSIGN = 1,
81
82 //! Translate the matrix by [x, y].
83 BL_MATRIX2D_OP_TRANSLATE = 2,
84 //! Scale the matrix by [x, y].
85 BL_MATRIX2D_OP_SCALE = 3,
86 //! Skew the matrix by [x, y].
87 BL_MATRIX2D_OP_SKEW = 4,
88 //! Rotate the matrix by the given angle about [0, 0].
89 BL_MATRIX2D_OP_ROTATE = 5,
90 //! Rotate the matrix by the given angle about [x, y].
91 BL_MATRIX2D_OP_ROTATE_PT = 6,
92 //! Transform this matrix by other `BLMatrix2D`.
93 BL_MATRIX2D_OP_TRANSFORM = 7,
94
95 //! Post-translate the matrix by [x, y].
96 BL_MATRIX2D_OP_POST_TRANSLATE = 8,
97 //! Post-scale the matrix by [x, y].
98 BL_MATRIX2D_OP_POST_SCALE = 9,
99 //! Post-skew the matrix by [x, y].
100 BL_MATRIX2D_OP_POST_SKEW = 10,
101 //! Post-rotate the matrix about [0, 0].
102 BL_MATRIX2D_OP_POST_ROTATE = 11,
103 //! Post-rotate the matrix about a reference BLPoint.
104 BL_MATRIX2D_OP_POST_ROTATE_PT = 12,
105 //! Post-transform this matrix by other `BLMatrix2D`.
106 BL_MATRIX2D_OP_POST_TRANSFORM = 13,
107
108 //! Count of matrix operations.
109 BL_MATRIX2D_OP_COUNT = 14
110};
111
112// ============================================================================
113// [BLMatrix2D]
114// ============================================================================
115
116//! 2D matrix represents an affine transformation matrix that can be used to
117//! transform geometry and images.
118struct BLMatrix2D {
119 union {
120 //! Matrix values, use `BL_MATRIX2D_VALUE` indexes to get a particular one.
121 double m[BL_MATRIX2D_VALUE_COUNT];
122 //! Matrix values that map `m` to named values that can be used directly.
123 struct {
124 double m00;
125 double m01;
126 double m10;
127 double m11;
128 double m20;
129 double m21;
130 };
131 };
132
133 // --------------------------------------------------------------------------
134 #ifdef __cplusplus
135
136 //! \name Construction & Destruction
137 //! \{
138
139 //! Creates an uninitialized 2D matrix, you must initialize all members before use.
140 BL_INLINE BLMatrix2D() noexcept = default;
141
142 //! Creates a new matrix initialized to a copy of `src` matrix.
143 constexpr BLMatrix2D(const BLMatrix2D& src) noexcept = default;
144
145 //! Creates a new matrix initialized to:
146 //!
147 //! ```
148 //! [m00 m01]
149 //! [m10 m11]
150 //! [m20 m21]
151 //! ```
152 constexpr BLMatrix2D(double m00, double m01, double m10, double m11, double m20, double m21) noexcept
153 : m00(m00), m01(m01),
154 m10(m10), m11(m11),
155 m20(m20), m21(m21) {}
156
157 //! \}
158
159 //! \name Static Constructors
160 //! \{
161
162 //! Creates a new matrix initialized to identity.
163 static constexpr BLMatrix2D makeIdentity() noexcept { return BLMatrix2D(1.0, 0.0, 0.0, 1.0, 0.0, 0.0); }
164
165 //! \overload
166 static constexpr BLMatrix2D makeTranslation(double x, double y) noexcept { return BLMatrix2D(1.0, 0.0, 0.0, 1.0, x, y); }
167 //! Creates a new matrix initialized to translation.
168 static constexpr BLMatrix2D makeTranslation(const BLPointI& p) noexcept { return BLMatrix2D(1.0, 0.0, 0.0, 1.0, double(p.x), double(p.y)); }
169 //! \overload
170 static constexpr BLMatrix2D makeTranslation(const BLPoint& p) noexcept { return BLMatrix2D(1.0, 0.0, 0.0, 1.0, p.x, p.y); }
171
172 //! \overload
173 static constexpr BLMatrix2D makeScaling(double xy) noexcept { return BLMatrix2D(xy, 0.0, 0.0, xy, 0.0, 0.0); }
174 //! \overload
175 static constexpr BLMatrix2D makeScaling(double x, double y) noexcept { return BLMatrix2D(x, 0.0, 0.0, y, 0.0, 0.0); }
176 //! \overload
177 static constexpr BLMatrix2D makeScaling(const BLPointI& p) noexcept { return BLMatrix2D(double(p.x), 0.0, 0.0, double(p.y), 0.0, 0.0); }
178 //! Creates a new matrix initialized to scaling.
179 static constexpr BLMatrix2D makeScaling(const BLPoint& p) noexcept { return BLMatrix2D(p.x, 0.0, 0.0, p.y, 0.0, 0.0); }
180
181 //! Creates a new matrix initialized to rotation.
182 static BL_INLINE BLMatrix2D makeRotation(double angle) noexcept {
183 BLMatrix2D result;
184 result.resetToRotation(angle, 0.0, 0.0);
185 return result;
186 }
187
188 //! \overload
189 static BL_INLINE BLMatrix2D makeRotation(double angle, double x, double y) noexcept {
190 BLMatrix2D result;
191 result.resetToRotation(angle, x, y);
192 return result;
193 }
194
195 //! \overload
196 static BL_INLINE BLMatrix2D makeRotation(double angle, const BLPoint& p) noexcept {
197 BLMatrix2D result;
198 result.resetToRotation(angle, p.x, p.y);
199 return result;
200 }
201
202 //! Create a new skewing matrix.
203 static BL_INLINE BLMatrix2D makeSkewing(double x, double y) noexcept {
204 BLMatrix2D result;
205 result.resetToSkewing(x, y);
206 return result;
207 }
208 //! \overload
209 static BL_INLINE BLMatrix2D makeSkewing(const BLPoint& p) noexcept {
210 BLMatrix2D result;
211 result.resetToSkewing(p.x, p.y);
212 return result;
213 }
214
215 static BL_INLINE BLMatrix2D makeSinCos(double sin, double cos, double tx = 0.0, double ty = 0.0) noexcept {
216 return BLMatrix2D(cos, sin, -sin, cos, tx, ty);
217 }
218
219 static BL_INLINE BLMatrix2D makeSinCos(double sin, double cos, const BLPoint& t) noexcept {
220 return makeSinCos(sin, cos, t.x, t.y);
221 }
222
223 //! \}
224
225 //! \name Reset Matrix
226 //! \{
227
228 //! Resets matrix to identity.
229 BL_INLINE void reset() noexcept {
230 reset(1.0, 0.0,
231 0.0, 1.0,
232 0.0, 0.0);
233 }
234
235 //! Resets matrix to `other` (copy its content to this matrix).
236 BL_INLINE void reset(const BLMatrix2D& other) noexcept {
237 reset(other.m00, other.m01,
238 other.m10, other.m11,
239 other.m20, other.m21);
240 }
241
242 //! Resets matrix to [`m00`, `m01`, `m10`, `m11`, `m20`, `m21`].
243 BL_INLINE void reset(double m00, double m01, double m10, double m11, double m20, double m21) noexcept {
244 this->m00 = m00;
245 this->m01 = m01;
246 this->m10 = m10;
247 this->m11 = m11;
248 this->m20 = m20;
249 this->m21 = m21;
250 }
251
252 //! Resets matrix to translation.
253 BL_INLINE void resetToTranslation(double x, double y) noexcept { reset(1.0, 0.0, 0.0, 1.0, x, y); }
254 //! Resets matrix to translation.
255 BL_INLINE void resetToTranslation(const BLPointI& p) noexcept { resetToTranslation(BLPoint(p)); }
256 //! Resets matrix to translation.
257 BL_INLINE void resetToTranslation(const BLPoint& p) noexcept { resetToTranslation(p.x, p.y); }
258
259 //! Resets matrix to scaling.
260 BL_INLINE void resetToScaling(double xy) noexcept { resetToScaling(xy, xy); }
261 //! Resets matrix to scaling.
262 BL_INLINE void resetToScaling(double x, double y) noexcept { reset(x, 0.0, 0.0, y, 0.0, 0.0); }
263 //! Resets matrix to scaling.
264 BL_INLINE void resetToScaling(const BLPointI& p) noexcept { resetToScaling(BLPoint(p)); }
265 //! Resets matrix to scaling.
266 BL_INLINE void resetToScaling(const BLPoint& p) noexcept { resetToScaling(p.x, p.y); }
267
268 //! Resets matrix to skewing.
269 BL_INLINE void resetToSkewing(double x, double y) noexcept { blMatrix2DSetSkewing(this, x, y); }
270 //! Resets matrix to skewing.
271 BL_INLINE void resetToSkewing(const BLPoint& p) noexcept { blMatrix2DSetSkewing(this, p.x, p.y); }
272
273 //! Resets matrix to rotation specified by `sin` and `cos` and optional translation `tx` and `ty`.
274 BL_INLINE void resetToSinCos(double sin, double cos, double tx = 0.0, double ty = 0.0) noexcept { reset(cos, sin, -sin, cos, tx, ty); }
275 //! Resets matrix to rotation specified by `sin` and `cos` and optional translation `t`.
276 BL_INLINE void resetToSinCos(double sin, double cos, const BLPoint& t) noexcept { resetToSinCos(sin, cos, t.x, t.y); }
277
278 //! Resets matrix to rotation.
279 BL_INLINE void resetToRotation(double angle) noexcept { blMatrix2DSetRotation(this, angle, 0.0, 0.0); }
280 //! Resets matrix to rotation around a point `[x, y]`.
281 BL_INLINE void resetToRotation(double angle, double x, double y) noexcept { blMatrix2DSetRotation(this, angle, x, y); }
282 //! Resets matrix to rotation around a point `p`.
283 BL_INLINE void resetToRotation(double angle, const BLPoint& p) noexcept { blMatrix2DSetRotation(this, angle, p.x, p.y); }
284
285 //! \}
286
287 //! \name Overloaded Operators
288 //! \{
289
290 BL_INLINE bool operator==(const BLMatrix2D& other) const noexcept { return equals(other); }
291 BL_INLINE bool operator!=(const BLMatrix2D& other) const noexcept { return !equals(other); }
292
293 //! \}
294
295 //! \name Common Functionality
296 //! \{
297
298 BL_INLINE bool equals(const BLMatrix2D& other) const noexcept {
299 return blEquals(this->m00, other.m00) &
300 blEquals(this->m01, other.m01) &
301 blEquals(this->m10, other.m10) &
302 blEquals(this->m11, other.m11) &
303 blEquals(this->m20, other.m20) &
304 blEquals(this->m21, other.m21) ;
305 }
306
307 //! \}
308
309 //! \name Matrix Properties
310 //! \{
311
312 //! Returns the matrix type, see `BLMatrix2DType`.
313 BL_INLINE uint32_t type() const noexcept { return blMatrix2DGetType(this); }
314
315 //! Calculates the matrix determinant.
316 BL_INLINE double determinant() noexcept { return this->m00 * this->m11 - this->m01 * this->m10; }
317
318 //! \}
319
320 //! \name Matrix Operations
321 //! \{
322
323 BL_INLINE BLResult translate(double x, double y) noexcept {
324 this->m20 += x * this->m00 + y * this->m10;
325 this->m21 += x * this->m01 + y * this->m11;
326
327 return BL_SUCCESS;
328 }
329
330 BL_INLINE BLResult translate(const BLPointI& p) noexcept { return translate(BLPoint(p)); }
331 BL_INLINE BLResult translate(const BLPoint& p) noexcept { return translate(p.x, p.y); }
332
333 BL_INLINE BLResult scale(double xy) noexcept { return scale(xy, xy); }
334 BL_INLINE BLResult scale(double x, double y) noexcept {
335 this->m00 *= x;
336 this->m01 *= x;
337 this->m10 *= y;
338 this->m11 *= y;
339
340 return BL_SUCCESS;
341 }
342
343 BL_INLINE BLResult scale(const BLPointI& p) noexcept { return scale(BLPoint(p)); }
344 BL_INLINE BLResult scale(const BLPoint& p) noexcept { return scale(p.x, p.y); }
345
346 BL_INLINE BLResult skew(double x, double y) noexcept { return skew(BLPoint(x, y)); }
347 BL_INLINE BLResult skew(const BLPoint& p) noexcept { return blMatrix2DApplyOp(this, BL_MATRIX2D_OP_SKEW, &p); }
348
349 BL_INLINE BLResult rotate(double angle) noexcept { return blMatrix2DApplyOp(this, BL_MATRIX2D_OP_ROTATE, &angle); }
350 BL_INLINE BLResult rotate(double angle, double x, double y) noexcept {
351 double opData[3] = { angle, x, y };
352 return blMatrix2DApplyOp(this, BL_MATRIX2D_OP_ROTATE_PT, opData);
353 }
354
355 BL_INLINE BLResult rotate(double angle, const BLPointI& p) noexcept { return rotate(angle, double(p.x), double(p.y)); }
356 BL_INLINE BLResult rotate(double angle, const BLPoint& p) noexcept { return rotate(angle, p.x, p.y); }
357
358 BL_INLINE BLResult transform(const BLMatrix2D& m) noexcept {
359 return blMatrix2DApplyOp(this, BL_MATRIX2D_OP_TRANSFORM, &m);
360 }
361
362 BL_INLINE BLResult postTranslate(double x, double y) noexcept {
363 this->m20 += x;
364 this->m21 += y;
365
366 return BL_SUCCESS;
367 }
368
369 BL_INLINE BLResult postTranslate(const BLPointI& p) noexcept { return postTranslate(BLPoint(p)); }
370 BL_INLINE BLResult postTranslate(const BLPoint& p) noexcept { return postTranslate(p.x, p.y); }
371
372 BL_INLINE BLResult postScale(double xy) noexcept { return postScale(xy, xy); }
373 BL_INLINE BLResult postScale(double x, double y) noexcept {
374 this->m00 *= x;
375 this->m01 *= y;
376 this->m10 *= x;
377 this->m11 *= y;
378 this->m20 *= x;
379 this->m21 *= y;
380
381 return BL_SUCCESS;
382 }
383 BL_INLINE BLResult postScale(const BLPointI& p) noexcept { return postScale(BLPoint(p)); }
384 BL_INLINE BLResult postScale(const BLPoint& p) noexcept { return postScale(p.x, p.y); }
385
386 BL_INLINE BLResult postSkew(double x, double y) noexcept { return postSkew(BLPoint(x, y)); }
387 BL_INLINE BLResult postSkew(const BLPoint& p) noexcept { return blMatrix2DApplyOp(this, BL_MATRIX2D_OP_POST_SKEW, &p); }
388
389 BL_INLINE BLResult postRotate(double angle) noexcept { return blMatrix2DApplyOp(this, BL_MATRIX2D_OP_POST_ROTATE, &angle); }
390 BL_INLINE BLResult postRotate(double angle, double x, double y) noexcept {
391 double params[3] = { angle, x, y };
392 return blMatrix2DApplyOp(this, BL_MATRIX2D_OP_POST_ROTATE_PT, params);
393 }
394
395 BL_INLINE BLResult postRotate(double angle, const BLPointI& p) noexcept { return postRotate(angle, BLPoint(p)); }
396 BL_INLINE BLResult postRotate(double angle, const BLPoint& p) noexcept { return postRotate(angle, p.x, p.y); }
397
398 BL_INLINE BLResult postTransform(const BLMatrix2D& m) noexcept { return blMatrix2DApplyOp(this, BL_MATRIX2D_OP_POST_TRANSFORM, &m); }
399
400 //! Inverts the matrix, returns `BL_SUCCESS` if the matrix has been inverted successfully.
401 BL_INLINE BLResult invert() noexcept { return blMatrix2DInvert(this, this); }
402
403 //! \}
404
405 //! \name Map Points and Primitives
406 //! \{
407
408 BL_INLINE BLPoint mapPoint(double x, double y) const noexcept { return BLPoint(x * m00 + y * m10 + m20, x * m01 + y * m11 + m21); }
409 BL_INLINE BLPoint mapPoint(const BLPoint& p) const noexcept { return mapPoint(p.x, p.y); }
410
411 BL_INLINE BLPoint mapVector(double x, double y) const noexcept { return BLPoint(x * m00 + y * m10, x * m01 + y * m11); }
412 BL_INLINE BLPoint mapVector(const BLPoint& v) const noexcept { return mapVector(v.x, v.y); }
413
414 //! \}
415
416 //! \name Static Operations
417 //! \{
418
419 //! Inverts `src` matrix and stores the result in `dst.
420 //!
421 //! \overload
422 static BL_INLINE BLResult invert(BLMatrix2D& dst, const BLMatrix2D& src) noexcept { return blMatrix2DInvert(&dst, &src); }
423
424 //! \}
425
426 #endif
427 // --------------------------------------------------------------------------
428};
429
430#ifdef __cplusplus
431extern "C" {
432#endif
433
434//! Array of functions for transforming points indexed by `BLMatrixType`. Each
435//! function is optimized for the respective type. This is mostly used internally,
436//! but exported for users that can take advantage of Blend2D SIMD optimziations.
437extern BL_API BLMapPointDArrayFunc blMatrix2DMapPointDArrayFuncs[BL_MATRIX2D_TYPE_COUNT];
438
439#ifdef __cplusplus
440} // {Extern:C}
441#endif
442
443//! \}
444
445BL_DIAGNOSTIC_POP
446
447#endif // BLEND2D_BLMATRIX_H
448