1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 The Qt Company Ltd. |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the QtGui module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "qmatrix.h" |
41 | |
42 | #include "qdatastream.h" |
43 | #include "qdebug.h" |
44 | #include "qhashfunctions.h" |
45 | #include "qregion.h" |
46 | #include "qpainterpath.h" |
47 | #include "qpainterpath_p.h" |
48 | #include "qtransform.h" |
49 | #include "qvariant.h" |
50 | #include <qmath.h> |
51 | |
52 | #include <limits.h> |
53 | |
54 | QT_BEGIN_NAMESPACE |
55 | |
56 | /*! |
57 | \class QMatrix |
58 | \brief The QMatrix class specifies 2D transformations of a |
59 | coordinate system. |
60 | \obsolete |
61 | |
62 | \ingroup painting |
63 | \inmodule QtGui |
64 | |
65 | A matrix specifies how to translate, scale, shear or rotate the |
66 | coordinate system, and is typically used when rendering graphics. |
67 | QMatrix, in contrast to QTransform, does not allow perspective |
68 | transformations. QTransform is the recommended transformation |
69 | class in Qt. |
70 | |
71 | A QMatrix object can be built using the setMatrix(), scale(), |
72 | rotate(), translate() and shear() functions. Alternatively, it |
73 | can be built by applying \l {QMatrix#Basic Matrix |
74 | Operations}{basic matrix operations}. The matrix can also be |
75 | defined when constructed, and it can be reset to the identity |
76 | matrix (the default) using the reset() function. |
77 | |
78 | The QMatrix class supports mapping of graphic primitives: A given |
79 | point, line, polygon, region, or painter path can be mapped to the |
80 | coordinate system defined by \e this matrix using the map() |
81 | function. In case of a rectangle, its coordinates can be |
82 | transformed using the mapRect() function. A rectangle can also be |
83 | transformed into a \e polygon (mapped to the coordinate system |
84 | defined by \e this matrix), using the mapToPolygon() function. |
85 | |
86 | QMatrix provides the isIdentity() function which returns \c true if |
87 | the matrix is the identity matrix, and the isInvertible() function |
88 | which returns \c true if the matrix is non-singular (i.e. AB = BA = |
89 | I). The inverted() function returns an inverted copy of \e this |
90 | matrix if it is invertible (otherwise it returns the identity |
91 | matrix). In addition, QMatrix provides the determinant() function |
92 | returning the matrix's determinant. |
93 | |
94 | Finally, the QMatrix class supports matrix multiplication, and |
95 | objects of the class can be streamed as well as compared. |
96 | |
97 | \tableofcontents |
98 | |
99 | \section1 Rendering Graphics |
100 | |
101 | When rendering graphics, the matrix defines the transformations |
102 | but the actual transformation is performed by the drawing routines |
103 | in QPainter. |
104 | |
105 | By default, QPainter operates on the associated device's own |
106 | coordinate system. The standard coordinate system of a |
107 | QPaintDevice has its origin located at the top-left position. The |
108 | \e x values increase to the right; \e y values increase |
109 | downward. For a complete description, see the \l {Coordinate |
110 | System}{coordinate system} documentation. |
111 | |
112 | QPainter has functions to translate, scale, shear and rotate the |
113 | coordinate system without using a QMatrix. For example: |
114 | |
115 | \table 100% |
116 | \row |
117 | \li \inlineimage qmatrix-simpletransformation.png |
118 | \li |
119 | \snippet matrix/matrix.cpp 0 |
120 | \endtable |
121 | |
122 | Although these functions are very convenient, it can be more |
123 | efficient to build a QMatrix and call QPainter::setMatrix() if you |
124 | want to perform more than a single transform operation. For |
125 | example: |
126 | |
127 | \table 100% |
128 | \row |
129 | \li \inlineimage qmatrix-combinedtransformation.png |
130 | \li |
131 | \snippet matrix/matrix.cpp 1 |
132 | \endtable |
133 | |
134 | \section1 Basic Matrix Operations |
135 | |
136 | \image qmatrix-representation.png |
137 | |
138 | A QMatrix object contains a 3 x 3 matrix. The \c dx and \c dy |
139 | elements specify horizontal and vertical translation. The \c m11 |
140 | and \c m22 elements specify horizontal and vertical scaling. And |
141 | finally, the \c m21 and \c m12 elements specify horizontal and |
142 | vertical \e shearing. |
143 | |
144 | QMatrix transforms a point in the plane to another point using the |
145 | following formulas: |
146 | |
147 | \snippet code/src_gui_painting_qmatrix.cpp 0 |
148 | |
149 | The point \e (x, y) is the original point, and \e (x', y') is the |
150 | transformed point. \e (x', y') can be transformed back to \e (x, |
151 | y) by performing the same operation on the inverted() matrix. |
152 | |
153 | The various matrix elements can be set when constructing the |
154 | matrix, or by using the setMatrix() function later on. They can also |
155 | be manipulated using the translate(), rotate(), scale() and |
156 | shear() convenience functions, The currently set values can be |
157 | retrieved using the m11(), m12(), m21(), m22(), dx() and dy() |
158 | functions. |
159 | |
160 | Translation is the simplest transformation. Setting \c dx and \c |
161 | dy will move the coordinate system \c dx units along the X axis |
162 | and \c dy units along the Y axis. Scaling can be done by setting |
163 | \c m11 and \c m22. For example, setting \c m11 to 2 and \c m22 to |
164 | 1.5 will double the height and increase the width by 50%. The |
165 | identity matrix has \c m11 and \c m22 set to 1 (all others are set |
166 | to 0) mapping a point to itself. Shearing is controlled by \c m12 |
167 | and \c m21. Setting these elements to values different from zero |
168 | will twist the coordinate system. Rotation is achieved by |
169 | carefully setting both the shearing factors and the scaling |
170 | factors. |
171 | |
172 | Here's the combined transformations example using basic matrix |
173 | operations: |
174 | |
175 | \table 100% |
176 | \row |
177 | \li \inlineimage qmatrix-combinedtransformation.png |
178 | \li |
179 | \snippet matrix/matrix.cpp 2 |
180 | \endtable |
181 | |
182 | \sa QPainter, QTransform, {Coordinate System}, |
183 | {painting/affine}{Affine Transformations Example}, {Transformations Example} |
184 | */ |
185 | |
186 | |
187 | // some defines to inline some code |
188 | #define MAPDOUBLE(x, y, nx, ny) \ |
189 | { \ |
190 | qreal fx = x; \ |
191 | qreal fy = y; \ |
192 | nx = _m11*fx + _m21*fy + _dx; \ |
193 | ny = _m12*fx + _m22*fy + _dy; \ |
194 | } |
195 | |
196 | #define MAPINT(x, y, nx, ny) \ |
197 | { \ |
198 | qreal fx = x; \ |
199 | qreal fy = y; \ |
200 | nx = qRound(_m11*fx + _m21*fy + _dx); \ |
201 | ny = qRound(_m12*fx + _m22*fy + _dy); \ |
202 | } |
203 | |
204 | /***************************************************************************** |
205 | QMatrix member functions |
206 | *****************************************************************************/ |
207 | /*! |
208 | \fn QMatrix::QMatrix(Qt::Initialization) |
209 | \internal |
210 | */ |
211 | |
212 | /*! |
213 | Constructs an identity matrix. |
214 | |
215 | All elements are set to zero except \c m11 and \c m22 (specifying |
216 | the scale), which are set to 1. |
217 | |
218 | \sa reset() |
219 | */ |
220 | |
221 | QMatrix::QMatrix() |
222 | : _m11(1.) |
223 | , _m12(0.) |
224 | , _m21(0.) |
225 | , _m22(1.) |
226 | , _dx(0.) |
227 | , _dy(0.) |
228 | { |
229 | } |
230 | |
231 | /*! |
232 | Constructs a matrix with the elements, \a m11, \a m12, \a m21, \a |
233 | m22, \a dx and \a dy. |
234 | |
235 | \sa setMatrix() |
236 | */ |
237 | |
238 | QMatrix::QMatrix(qreal m11, qreal m12, qreal m21, qreal m22, qreal dx, qreal dy) |
239 | : _m11(m11) |
240 | , _m12(m12) |
241 | , _m21(m21) |
242 | , _m22(m22) |
243 | , _dx(dx) |
244 | , _dy(dy) |
245 | { |
246 | } |
247 | |
248 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) |
249 | /*! |
250 | Constructs a matrix that is a copy of the given \a matrix. |
251 | */ |
252 | QMatrix::QMatrix(const QMatrix &matrix) noexcept |
253 | : _m11(matrix._m11) |
254 | , _m12(matrix._m12) |
255 | , _m21(matrix._m21) |
256 | , _m22(matrix._m22) |
257 | , _dx(matrix._dx) |
258 | , _dy(matrix._dy) |
259 | { |
260 | } |
261 | #endif |
262 | |
263 | /*! |
264 | Sets the matrix elements to the specified values, \a m11, \a m12, |
265 | \a m21, \a m22, \a dx and \a dy. |
266 | |
267 | Note that this function replaces the previous values. QMatrix |
268 | provide the translate(), rotate(), scale() and shear() convenience |
269 | functions to manipulate the various matrix elements based on the |
270 | currently defined coordinate system. |
271 | |
272 | \sa QMatrix() |
273 | */ |
274 | |
275 | void QMatrix::setMatrix(qreal m11, qreal m12, qreal m21, qreal m22, qreal dx, qreal dy) |
276 | { |
277 | _m11 = m11; |
278 | _m12 = m12; |
279 | _m21 = m21; |
280 | _m22 = m22; |
281 | _dx = dx; |
282 | _dy = dy; |
283 | } |
284 | |
285 | |
286 | /*! |
287 | \fn qreal QMatrix::m11() const |
288 | |
289 | Returns the horizontal scaling factor. |
290 | |
291 | \sa scale(), {QMatrix#Basic Matrix Operations}{Basic Matrix |
292 | Operations} |
293 | */ |
294 | |
295 | /*! |
296 | \fn qreal QMatrix::m12() const |
297 | |
298 | Returns the vertical shearing factor. |
299 | |
300 | \sa shear(), {QMatrix#Basic Matrix Operations}{Basic Matrix |
301 | Operations} |
302 | */ |
303 | |
304 | /*! |
305 | \fn qreal QMatrix::m21() const |
306 | |
307 | Returns the horizontal shearing factor. |
308 | |
309 | \sa shear(), {QMatrix#Basic Matrix Operations}{Basic Matrix |
310 | Operations} |
311 | */ |
312 | |
313 | /*! |
314 | \fn qreal QMatrix::m22() const |
315 | |
316 | Returns the vertical scaling factor. |
317 | |
318 | \sa scale(), {QMatrix#Basic Matrix Operations}{Basic Matrix |
319 | Operations} |
320 | */ |
321 | |
322 | /*! |
323 | \fn qreal QMatrix::dx() const |
324 | |
325 | Returns the horizontal translation factor. |
326 | |
327 | \sa translate(), {QMatrix#Basic Matrix Operations}{Basic Matrix |
328 | Operations} |
329 | */ |
330 | |
331 | /*! |
332 | \fn qreal QMatrix::dy() const |
333 | |
334 | Returns the vertical translation factor. |
335 | |
336 | \sa translate(), {QMatrix#Basic Matrix Operations}{Basic Matrix |
337 | Operations} |
338 | */ |
339 | |
340 | |
341 | /*! |
342 | Maps the given coordinates \a x and \a y into the coordinate |
343 | system defined by this matrix. The resulting values are put in *\a |
344 | tx and *\a ty, respectively. |
345 | |
346 | The coordinates are transformed using the following formulas: |
347 | |
348 | \snippet code/src_gui_painting_qmatrix.cpp 1 |
349 | |
350 | The point (x, y) is the original point, and (x', y') is the |
351 | transformed point. |
352 | |
353 | \sa {QMatrix#Basic Matrix Operations}{Basic Matrix Operations} |
354 | */ |
355 | |
356 | void QMatrix::map(qreal x, qreal y, qreal *tx, qreal *ty) const |
357 | { |
358 | MAPDOUBLE(x, y, *tx, *ty); |
359 | } |
360 | |
361 | |
362 | |
363 | /*! |
364 | \overload |
365 | |
366 | Maps the given coordinates \a x and \a y into the coordinate |
367 | system defined by this matrix. The resulting values are put in *\a |
368 | tx and *\a ty, respectively. Note that the transformed coordinates |
369 | are rounded to the nearest integer. |
370 | */ |
371 | |
372 | void QMatrix::map(int x, int y, int *tx, int *ty) const |
373 | { |
374 | MAPINT(x, y, *tx, *ty); |
375 | } |
376 | |
377 | QRect QMatrix::mapRect(const QRect &rect) const |
378 | { |
379 | QRect result; |
380 | if (_m12 == 0.0F && _m21 == 0.0F) { |
381 | int x = qRound(d: _m11*rect.x() + _dx); |
382 | int y = qRound(d: _m22*rect.y() + _dy); |
383 | int w = qRound(d: _m11*rect.width()); |
384 | int h = qRound(d: _m22*rect.height()); |
385 | if (w < 0) { |
386 | w = -w; |
387 | x -= w; |
388 | } |
389 | if (h < 0) { |
390 | h = -h; |
391 | y -= h; |
392 | } |
393 | result = QRect(x, y, w, h); |
394 | } else { |
395 | // see mapToPolygon for explanations of the algorithm. |
396 | qreal x0, y0; |
397 | qreal x, y; |
398 | MAPDOUBLE(rect.left(), rect.top(), x0, y0); |
399 | qreal xmin = x0; |
400 | qreal ymin = y0; |
401 | qreal xmax = x0; |
402 | qreal ymax = y0; |
403 | MAPDOUBLE(rect.right() + 1, rect.top(), x, y); |
404 | xmin = qMin(a: xmin, b: x); |
405 | ymin = qMin(a: ymin, b: y); |
406 | xmax = qMax(a: xmax, b: x); |
407 | ymax = qMax(a: ymax, b: y); |
408 | MAPDOUBLE(rect.right() + 1, rect.bottom() + 1, x, y); |
409 | xmin = qMin(a: xmin, b: x); |
410 | ymin = qMin(a: ymin, b: y); |
411 | xmax = qMax(a: xmax, b: x); |
412 | ymax = qMax(a: ymax, b: y); |
413 | MAPDOUBLE(rect.left(), rect.bottom() + 1, x, y); |
414 | xmin = qMin(a: xmin, b: x); |
415 | ymin = qMin(a: ymin, b: y); |
416 | xmax = qMax(a: xmax, b: x); |
417 | ymax = qMax(a: ymax, b: y); |
418 | result = QRect(qRound(d: xmin), qRound(d: ymin), qRound(d: xmax)-qRound(d: xmin), qRound(d: ymax)-qRound(d: ymin)); |
419 | } |
420 | return result; |
421 | } |
422 | |
423 | /*! |
424 | \fn QRectF QMatrix::mapRect(const QRectF &rectangle) const |
425 | |
426 | Creates and returns a QRectF object that is a copy of the given \a |
427 | rectangle, mapped into the coordinate system defined by this |
428 | matrix. |
429 | |
430 | The rectangle's coordinates are transformed using the following |
431 | formulas: |
432 | |
433 | \snippet code/src_gui_painting_qmatrix.cpp 2 |
434 | |
435 | If rotation or shearing has been specified, this function returns |
436 | the \e bounding rectangle. To retrieve the exact region the given |
437 | \a rectangle maps to, use the mapToPolygon() function instead. |
438 | |
439 | \sa mapToPolygon(), {QMatrix#Basic Matrix Operations}{Basic Matrix |
440 | Operations} |
441 | */ |
442 | QRectF QMatrix::mapRect(const QRectF &rect) const |
443 | { |
444 | QRectF result; |
445 | if (_m12 == 0.0F && _m21 == 0.0F) { |
446 | qreal x = _m11*rect.x() + _dx; |
447 | qreal y = _m22*rect.y() + _dy; |
448 | qreal w = _m11*rect.width(); |
449 | qreal h = _m22*rect.height(); |
450 | if (w < 0) { |
451 | w = -w; |
452 | x -= w; |
453 | } |
454 | if (h < 0) { |
455 | h = -h; |
456 | y -= h; |
457 | } |
458 | result = QRectF(x, y, w, h); |
459 | } else { |
460 | qreal x0, y0; |
461 | qreal x, y; |
462 | MAPDOUBLE(rect.x(), rect.y(), x0, y0); |
463 | qreal xmin = x0; |
464 | qreal ymin = y0; |
465 | qreal xmax = x0; |
466 | qreal ymax = y0; |
467 | MAPDOUBLE(rect.x() + rect.width(), rect.y(), x, y); |
468 | xmin = qMin(a: xmin, b: x); |
469 | ymin = qMin(a: ymin, b: y); |
470 | xmax = qMax(a: xmax, b: x); |
471 | ymax = qMax(a: ymax, b: y); |
472 | MAPDOUBLE(rect.x() + rect.width(), rect.y() + rect.height(), x, y); |
473 | xmin = qMin(a: xmin, b: x); |
474 | ymin = qMin(a: ymin, b: y); |
475 | xmax = qMax(a: xmax, b: x); |
476 | ymax = qMax(a: ymax, b: y); |
477 | MAPDOUBLE(rect.x(), rect.y() + rect.height(), x, y); |
478 | xmin = qMin(a: xmin, b: x); |
479 | ymin = qMin(a: ymin, b: y); |
480 | xmax = qMax(a: xmax, b: x); |
481 | ymax = qMax(a: ymax, b: y); |
482 | result = QRectF(xmin, ymin, xmax-xmin, ymax - ymin); |
483 | } |
484 | return result; |
485 | } |
486 | |
487 | /*! |
488 | \fn QRect QMatrix::mapRect(const QRect &rectangle) const |
489 | \overload |
490 | |
491 | Creates and returns a QRect object that is a copy of the given \a |
492 | rectangle, mapped into the coordinate system defined by this |
493 | matrix. Note that the transformed coordinates are rounded to the |
494 | nearest integer. |
495 | */ |
496 | |
497 | |
498 | /*! |
499 | \fn QPoint operator*(const QPoint &point, const QMatrix &matrix) |
500 | \relates QMatrix |
501 | |
502 | This is the same as \a{matrix}.map(\a{point}). |
503 | |
504 | \sa QMatrix::map() |
505 | */ |
506 | |
507 | QPoint QMatrix::map(const QPoint &p) const |
508 | { |
509 | qreal fx = p.x(); |
510 | qreal fy = p.y(); |
511 | return QPoint(qRound(d: _m11*fx + _m21*fy + _dx), |
512 | qRound(d: _m12*fx + _m22*fy + _dy)); |
513 | } |
514 | |
515 | /*! |
516 | \fn QPointF operator*(const QPointF &point, const QMatrix &matrix) |
517 | \relates QMatrix |
518 | |
519 | Same as \a{matrix}.map(\a{point}). |
520 | |
521 | \sa QMatrix::map() |
522 | */ |
523 | |
524 | /*! |
525 | \overload |
526 | |
527 | Creates and returns a QPointF object that is a copy of the given |
528 | \a point, mapped into the coordinate system defined by this |
529 | matrix. |
530 | */ |
531 | QPointF QMatrix::map(const QPointF &point) const |
532 | { |
533 | qreal fx = point.x(); |
534 | qreal fy = point.y(); |
535 | return QPointF(_m11*fx + _m21*fy + _dx, _m12*fx + _m22*fy + _dy); |
536 | } |
537 | |
538 | /*! |
539 | \fn QPoint QMatrix::map(const QPoint &point) const |
540 | \overload |
541 | |
542 | Creates and returns a QPoint object that is a copy of the given \a |
543 | point, mapped into the coordinate system defined by this |
544 | matrix. Note that the transformed coordinates are rounded to the |
545 | nearest integer. |
546 | */ |
547 | |
548 | /*! |
549 | \fn QLineF operator*(const QLineF &line, const QMatrix &matrix) |
550 | \relates QMatrix |
551 | |
552 | This is the same as \a{matrix}.map(\a{line}). |
553 | |
554 | \sa QMatrix::map() |
555 | */ |
556 | |
557 | /*! |
558 | \fn QLine operator*(const QLine &line, const QMatrix &matrix) |
559 | \relates QMatrix |
560 | |
561 | This is the same as \a{matrix}.map(\a{line}). |
562 | |
563 | \sa QMatrix::map() |
564 | */ |
565 | |
566 | /*! |
567 | \overload |
568 | |
569 | Creates and returns a QLineF object that is a copy of the given \a |
570 | line, mapped into the coordinate system defined by this matrix. |
571 | */ |
572 | QLineF QMatrix::map(const QLineF &line) const |
573 | { |
574 | return QLineF(map(point: line.p1()), map(point: line.p2())); |
575 | } |
576 | |
577 | /*! |
578 | \overload |
579 | |
580 | Creates and returns a QLine object that is a copy of the given \a |
581 | line, mapped into the coordinate system defined by this matrix. |
582 | Note that the transformed coordinates are rounded to the nearest |
583 | integer. |
584 | */ |
585 | QLine QMatrix::map(const QLine &line) const |
586 | { |
587 | return QLine(map(p: line.p1()), map(p: line.p2())); |
588 | } |
589 | |
590 | /*! |
591 | \fn QPolygonF operator *(const QPolygonF &polygon, const QMatrix &matrix) |
592 | \relates QMatrix |
593 | |
594 | This is the same as \a{matrix}.map(\a{polygon}). |
595 | |
596 | \sa QMatrix::map() |
597 | */ |
598 | |
599 | /*! |
600 | \fn QPolygon operator*(const QPolygon &polygon, const QMatrix &matrix) |
601 | \relates QMatrix |
602 | |
603 | This is the same as \a{matrix}.map(\a{polygon}). |
604 | |
605 | \sa QMatrix::map() |
606 | */ |
607 | |
608 | QPolygon QMatrix::map(const QPolygon &a) const |
609 | { |
610 | int size = a.size(); |
611 | int i; |
612 | QPolygon p(size); |
613 | const QPoint *da = a.constData(); |
614 | QPoint *dp = p.data(); |
615 | for(i = 0; i < size; i++) { |
616 | MAPINT(da[i].x(), da[i].y(), dp[i].rx(), dp[i].ry()); |
617 | } |
618 | return p; |
619 | } |
620 | |
621 | /*! |
622 | \fn QPolygonF QMatrix::map(const QPolygonF &polygon) const |
623 | \overload |
624 | |
625 | Creates and returns a QPolygonF object that is a copy of the given |
626 | \a polygon, mapped into the coordinate system defined by this |
627 | matrix. |
628 | */ |
629 | QPolygonF QMatrix::map(const QPolygonF &a) const |
630 | { |
631 | int size = a.size(); |
632 | int i; |
633 | QPolygonF p(size); |
634 | const QPointF *da = a.constData(); |
635 | QPointF *dp = p.data(); |
636 | for(i = 0; i < size; i++) { |
637 | MAPDOUBLE(da[i].xp, da[i].yp, dp[i].xp, dp[i].yp); |
638 | } |
639 | return p; |
640 | } |
641 | |
642 | /*! |
643 | \fn QPolygon QMatrix::map(const QPolygon &polygon) const |
644 | \overload |
645 | |
646 | Creates and returns a QPolygon object that is a copy of the given |
647 | \a polygon, mapped into the coordinate system defined by this |
648 | matrix. Note that the transformed coordinates are rounded to the |
649 | nearest integer. |
650 | */ |
651 | |
652 | /*! |
653 | \fn QRegion operator*(const QRegion ®ion, const QMatrix &matrix) |
654 | \relates QMatrix |
655 | |
656 | This is the same as \a{matrix}.map(\a{region}). |
657 | |
658 | \sa QMatrix::map() |
659 | */ |
660 | |
661 | extern QPainterPath qt_regionToPath(const QRegion ®ion); |
662 | |
663 | /*! |
664 | \fn QRegion QMatrix::map(const QRegion ®ion) const |
665 | \overload |
666 | |
667 | Creates and returns a QRegion object that is a copy of the given |
668 | \a region, mapped into the coordinate system defined by this matrix. |
669 | |
670 | Calling this method can be rather expensive if rotations or |
671 | shearing are used. |
672 | */ |
673 | QRegion QMatrix::map(const QRegion &r) const |
674 | { |
675 | if (_m11 == 1.0 && _m22 == 1.0 && _m12 == 0.0 && _m21 == 0.0) { // translate or identity |
676 | if (_dx == 0.0 && _dy == 0.0) // Identity |
677 | return r; |
678 | QRegion copy(r); |
679 | copy.translate(dx: qRound(d: _dx), dy: qRound(d: _dy)); |
680 | return copy; |
681 | } |
682 | |
683 | QPainterPath p = map(p: qt_regionToPath(region: r)); |
684 | return p.toFillPolygon(matrix: QTransform()).toPolygon(); |
685 | } |
686 | |
687 | /*! |
688 | \fn QPainterPath operator *(const QPainterPath &path, const QMatrix &matrix) |
689 | \relates QMatrix |
690 | |
691 | This is the same as \a{matrix}.map(\a{path}). |
692 | |
693 | \sa QMatrix::map() |
694 | */ |
695 | |
696 | /*! |
697 | \overload |
698 | |
699 | Creates and returns a QPainterPath object that is a copy of the |
700 | given \a path, mapped into the coordinate system defined by this |
701 | matrix. |
702 | */ |
703 | QPainterPath QMatrix::map(const QPainterPath &path) const |
704 | { |
705 | if (path.isEmpty()) |
706 | return QPainterPath(); |
707 | |
708 | QPainterPath copy = path; |
709 | |
710 | // Translate or identity |
711 | if (_m11 == 1.0 && _m22 == 1.0 && _m12 == 0.0 && _m21 == 0.0) { |
712 | |
713 | // Translate |
714 | if (_dx != 0.0 || _dy != 0.0) { |
715 | copy.detach(); |
716 | for (int i=0; i<path.elementCount(); ++i) { |
717 | QPainterPath::Element &e = copy.d_ptr->elements[i]; |
718 | e.x += _dx; |
719 | e.y += _dy; |
720 | } |
721 | } |
722 | |
723 | // Full xform |
724 | } else { |
725 | copy.detach(); |
726 | for (int i=0; i<path.elementCount(); ++i) { |
727 | QPainterPath::Element &e = copy.d_ptr->elements[i]; |
728 | qreal fx = e.x, fy = e.y; |
729 | e.x = _m11*fx + _m21*fy + _dx; |
730 | e.y = _m12*fx + _m22*fy + _dy; |
731 | } |
732 | } |
733 | |
734 | return copy; |
735 | } |
736 | |
737 | /*! |
738 | \fn QPolygon QMatrix::mapToPolygon(const QRect &rectangle) const |
739 | |
740 | Creates and returns a QPolygon representation of the given \a |
741 | rectangle, mapped into the coordinate system defined by this |
742 | matrix. |
743 | |
744 | The rectangle's coordinates are transformed using the following |
745 | formulas: |
746 | |
747 | \snippet code/src_gui_painting_qmatrix.cpp 3 |
748 | |
749 | Polygons and rectangles behave slightly differently when |
750 | transformed (due to integer rounding), so |
751 | \c{matrix.map(QPolygon(rectangle))} is not always the same as |
752 | \c{matrix.mapToPolygon(rectangle)}. |
753 | |
754 | \sa mapRect(), {QMatrix#Basic Matrix Operations}{Basic Matrix |
755 | Operations} |
756 | */ |
757 | QPolygon QMatrix::mapToPolygon(const QRect &rect) const |
758 | { |
759 | QPolygon a(4); |
760 | qreal x[4], y[4]; |
761 | if (_m12 == 0.0F && _m21 == 0.0F) { |
762 | x[0] = _m11*rect.x() + _dx; |
763 | y[0] = _m22*rect.y() + _dy; |
764 | qreal w = _m11*rect.width(); |
765 | qreal h = _m22*rect.height(); |
766 | if (w < 0) { |
767 | w = -w; |
768 | x[0] -= w; |
769 | } |
770 | if (h < 0) { |
771 | h = -h; |
772 | y[0] -= h; |
773 | } |
774 | x[1] = x[0]+w; |
775 | x[2] = x[1]; |
776 | x[3] = x[0]; |
777 | y[1] = y[0]; |
778 | y[2] = y[0]+h; |
779 | y[3] = y[2]; |
780 | } else { |
781 | qreal right = rect.x() + rect.width(); |
782 | qreal bottom = rect.y() + rect.height(); |
783 | MAPDOUBLE(rect.x(), rect.y(), x[0], y[0]); |
784 | MAPDOUBLE(right, rect.y(), x[1], y[1]); |
785 | MAPDOUBLE(right, bottom, x[2], y[2]); |
786 | MAPDOUBLE(rect.x(), bottom, x[3], y[3]); |
787 | } |
788 | #if 0 |
789 | int i; |
790 | for(i = 0; i< 4; i++) |
791 | qDebug("coords(%d) = (%f/%f) (%d/%d)" , i, x[i], y[i], qRound(x[i]), qRound(y[i])); |
792 | qDebug("width=%f, height=%f" , qSqrt((x[1]-x[0])*(x[1]-x[0]) + (y[1]-y[0])*(y[1]-y[0])), |
793 | qSqrt((x[0]-x[3])*(x[0]-x[3]) + (y[0]-y[3])*(y[0]-y[3]))); |
794 | #endif |
795 | // all coordinates are correctly, tranform to a pointarray |
796 | // (rounding to the next integer) |
797 | a.setPoints(nPoints: 4, firstx: qRound(d: x[0]), firsty: qRound(d: y[0]), |
798 | qRound(d: x[1]), qRound(d: y[1]), |
799 | qRound(d: x[2]), qRound(d: y[2]), |
800 | qRound(d: x[3]), qRound(d: y[3])); |
801 | return a; |
802 | } |
803 | |
804 | /*! |
805 | Resets the matrix to an identity matrix, i.e. all elements are set |
806 | to zero, except \c m11 and \c m22 (specifying the scale) which are |
807 | set to 1. |
808 | |
809 | \sa QMatrix(), isIdentity(), {QMatrix#Basic Matrix |
810 | Operations}{Basic Matrix Operations} |
811 | */ |
812 | |
813 | void QMatrix::reset() |
814 | { |
815 | _m11 = _m22 = 1.0; |
816 | _m12 = _m21 = _dx = _dy = 0.0; |
817 | } |
818 | |
819 | /*! |
820 | \fn bool QMatrix::isIdentity() const |
821 | |
822 | Returns \c true if the matrix is the identity matrix, otherwise |
823 | returns \c false. |
824 | |
825 | \sa reset() |
826 | */ |
827 | |
828 | /*! |
829 | Moves the coordinate system \a dx along the x axis and \a dy along |
830 | the y axis, and returns a reference to the matrix. |
831 | |
832 | \sa setMatrix() |
833 | */ |
834 | |
835 | QMatrix &QMatrix::translate(qreal dx, qreal dy) |
836 | { |
837 | _dx += dx*_m11 + dy*_m21; |
838 | _dy += dy*_m22 + dx*_m12; |
839 | return *this; |
840 | } |
841 | |
842 | /*! |
843 | \fn QMatrix &QMatrix::scale(qreal sx, qreal sy) |
844 | |
845 | Scales the coordinate system by \a sx horizontally and \a sy |
846 | vertically, and returns a reference to the matrix. |
847 | |
848 | \sa setMatrix() |
849 | */ |
850 | |
851 | QMatrix &QMatrix::scale(qreal sx, qreal sy) |
852 | { |
853 | _m11 *= sx; |
854 | _m12 *= sx; |
855 | _m21 *= sy; |
856 | _m22 *= sy; |
857 | return *this; |
858 | } |
859 | |
860 | /*! |
861 | Shears the coordinate system by \a sh horizontally and \a sv |
862 | vertically, and returns a reference to the matrix. |
863 | |
864 | \sa setMatrix() |
865 | */ |
866 | |
867 | QMatrix &QMatrix::shear(qreal sh, qreal sv) |
868 | { |
869 | qreal tm11 = sv*_m21; |
870 | qreal tm12 = sv*_m22; |
871 | qreal tm21 = sh*_m11; |
872 | qreal tm22 = sh*_m12; |
873 | _m11 += tm11; |
874 | _m12 += tm12; |
875 | _m21 += tm21; |
876 | _m22 += tm22; |
877 | return *this; |
878 | } |
879 | |
880 | const qreal deg2rad = qreal(0.017453292519943295769); // pi/180 |
881 | |
882 | /*! |
883 | \fn QMatrix &QMatrix::rotate(qreal degrees) |
884 | |
885 | Rotates the coordinate system the given \a degrees |
886 | counterclockwise. |
887 | |
888 | Note that if you apply a QMatrix to a point defined in widget |
889 | coordinates, the direction of the rotation will be clockwise |
890 | because the y-axis points downwards. |
891 | |
892 | Returns a reference to the matrix. |
893 | |
894 | \sa setMatrix() |
895 | */ |
896 | |
897 | QMatrix &QMatrix::rotate(qreal a) |
898 | { |
899 | qreal sina = 0; |
900 | qreal cosa = 0; |
901 | if (a == 90. || a == -270.) |
902 | sina = 1.; |
903 | else if (a == 270. || a == -90.) |
904 | sina = -1.; |
905 | else if (a == 180.) |
906 | cosa = -1.; |
907 | else{ |
908 | qreal b = deg2rad*a; // convert to radians |
909 | sina = qSin(v: b); // fast and convenient |
910 | cosa = qCos(v: b); |
911 | } |
912 | qreal tm11 = cosa*_m11 + sina*_m21; |
913 | qreal tm12 = cosa*_m12 + sina*_m22; |
914 | qreal tm21 = -sina*_m11 + cosa*_m21; |
915 | qreal tm22 = -sina*_m12 + cosa*_m22; |
916 | _m11 = tm11; _m12 = tm12; |
917 | _m21 = tm21; _m22 = tm22; |
918 | return *this; |
919 | } |
920 | |
921 | /*! |
922 | \fn bool QMatrix::isInvertible() const |
923 | |
924 | Returns \c true if the matrix is invertible, otherwise returns \c false. |
925 | |
926 | \sa inverted() |
927 | */ |
928 | |
929 | /*! |
930 | \since 4.6 |
931 | \fn qreal QMatrix::determinant() const |
932 | |
933 | Returns the matrix's determinant. |
934 | */ |
935 | |
936 | /*! |
937 | Returns an inverted copy of this matrix. |
938 | |
939 | If the matrix is singular (not invertible), the returned matrix is |
940 | the identity matrix. If \a invertible is valid (i.e. not 0), its |
941 | value is set to true if the matrix is invertible, otherwise it is |
942 | set to false. |
943 | |
944 | \sa isInvertible() |
945 | */ |
946 | |
947 | QMatrix QMatrix::inverted(bool *invertible) const |
948 | { |
949 | qreal dtr = determinant(); |
950 | if (dtr == 0.0) { |
951 | if (invertible) |
952 | *invertible = false; // singular matrix |
953 | return QMatrix(true); |
954 | } |
955 | else { // invertible matrix |
956 | if (invertible) |
957 | *invertible = true; |
958 | qreal dinv = 1.0/dtr; |
959 | return QMatrix((_m22*dinv), (-_m12*dinv), |
960 | (-_m21*dinv), (_m11*dinv), |
961 | ((_m21*_dy - _m22*_dx)*dinv), |
962 | ((_m12*_dx - _m11*_dy)*dinv), |
963 | true); |
964 | } |
965 | } |
966 | |
967 | |
968 | /*! |
969 | \fn bool QMatrix::operator==(const QMatrix &matrix) const |
970 | |
971 | Returns \c true if this matrix is equal to the given \a matrix, |
972 | otherwise returns \c false. |
973 | */ |
974 | |
975 | bool QMatrix::operator==(const QMatrix &m) const |
976 | { |
977 | return _m11 == m._m11 && |
978 | _m12 == m._m12 && |
979 | _m21 == m._m21 && |
980 | _m22 == m._m22 && |
981 | _dx == m._dx && |
982 | _dy == m._dy; |
983 | } |
984 | |
985 | |
986 | /*! |
987 | \since 5.6 |
988 | \relates QMatrix |
989 | |
990 | Returns the hash value for \a key, using |
991 | \a seed to seed the calculation. |
992 | */ |
993 | uint qHash(const QMatrix &key, uint seed) noexcept |
994 | { |
995 | QtPrivate::QHashCombine hash; |
996 | seed = hash(seed, key.m11()); |
997 | seed = hash(seed, key.m12()); |
998 | seed = hash(seed, key.m21()); |
999 | seed = hash(seed, key.m22()); |
1000 | seed = hash(seed, key.dx()); |
1001 | seed = hash(seed, key.dy()); |
1002 | return seed; |
1003 | } |
1004 | |
1005 | /*! |
1006 | \fn bool QMatrix::operator!=(const QMatrix &matrix) const |
1007 | |
1008 | Returns \c true if this matrix is not equal to the given \a matrix, |
1009 | otherwise returns \c false. |
1010 | */ |
1011 | |
1012 | bool QMatrix::operator!=(const QMatrix &m) const |
1013 | { |
1014 | return _m11 != m._m11 || |
1015 | _m12 != m._m12 || |
1016 | _m21 != m._m21 || |
1017 | _m22 != m._m22 || |
1018 | _dx != m._dx || |
1019 | _dy != m._dy; |
1020 | } |
1021 | |
1022 | /*! |
1023 | \fn QMatrix &QMatrix::operator *=(const QMatrix &matrix) |
1024 | \overload |
1025 | |
1026 | Returns the result of multiplying this matrix by the given \a |
1027 | matrix. |
1028 | */ |
1029 | |
1030 | QMatrix &QMatrix::operator *=(const QMatrix &m) |
1031 | { |
1032 | qreal tm11 = _m11*m._m11 + _m12*m._m21; |
1033 | qreal tm12 = _m11*m._m12 + _m12*m._m22; |
1034 | qreal tm21 = _m21*m._m11 + _m22*m._m21; |
1035 | qreal tm22 = _m21*m._m12 + _m22*m._m22; |
1036 | |
1037 | qreal tdx = _dx*m._m11 + _dy*m._m21 + m._dx; |
1038 | qreal tdy = _dx*m._m12 + _dy*m._m22 + m._dy; |
1039 | |
1040 | _m11 = tm11; _m12 = tm12; |
1041 | _m21 = tm21; _m22 = tm22; |
1042 | _dx = tdx; _dy = tdy; |
1043 | return *this; |
1044 | } |
1045 | |
1046 | /*! |
1047 | \fn QMatrix QMatrix::operator *(const QMatrix &matrix) const |
1048 | |
1049 | Returns the result of multiplying this matrix by the given \a |
1050 | matrix. |
1051 | |
1052 | Note that matrix multiplication is not commutative, i.e. a*b != |
1053 | b*a. |
1054 | */ |
1055 | |
1056 | QMatrix QMatrix::operator *(const QMatrix &m) const |
1057 | { |
1058 | qreal tm11 = _m11*m._m11 + _m12*m._m21; |
1059 | qreal tm12 = _m11*m._m12 + _m12*m._m22; |
1060 | qreal tm21 = _m21*m._m11 + _m22*m._m21; |
1061 | qreal tm22 = _m21*m._m12 + _m22*m._m22; |
1062 | |
1063 | qreal tdx = _dx*m._m11 + _dy*m._m21 + m._dx; |
1064 | qreal tdy = _dx*m._m12 + _dy*m._m22 + m._dy; |
1065 | return QMatrix(tm11, tm12, tm21, tm22, tdx, tdy, true); |
1066 | } |
1067 | |
1068 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) |
1069 | /*! |
1070 | Assigns the given \a matrix's values to this matrix. |
1071 | */ |
1072 | QMatrix &QMatrix::operator=(const QMatrix &matrix) noexcept |
1073 | { |
1074 | _m11 = matrix._m11; |
1075 | _m12 = matrix._m12; |
1076 | _m21 = matrix._m21; |
1077 | _m22 = matrix._m22; |
1078 | _dx = matrix._dx; |
1079 | _dy = matrix._dy; |
1080 | return *this; |
1081 | } |
1082 | #endif |
1083 | |
1084 | /*! |
1085 | \since 4.2 |
1086 | |
1087 | Returns the matrix as a QVariant. |
1088 | */ |
1089 | QMatrix::operator QVariant() const |
1090 | { |
1091 | return QVariant(QMetaType::QMatrix, this); |
1092 | } |
1093 | |
1094 | Q_GUI_EXPORT QPainterPath operator *(const QPainterPath &p, const QMatrix &m) |
1095 | { |
1096 | return m.map(path: p); |
1097 | } |
1098 | |
1099 | |
1100 | /***************************************************************************** |
1101 | QMatrix stream functions |
1102 | *****************************************************************************/ |
1103 | #ifndef QT_NO_DATASTREAM |
1104 | /*! |
1105 | \fn QDataStream &operator<<(QDataStream &stream, const QMatrix &matrix) |
1106 | \relates QMatrix |
1107 | |
1108 | Writes the given \a matrix to the given \a stream and returns a |
1109 | reference to the stream. |
1110 | |
1111 | \sa {Serializing Qt Data Types} |
1112 | */ |
1113 | |
1114 | QDataStream &operator<<(QDataStream &s, const QMatrix &m) |
1115 | { |
1116 | if (s.version() == 1) { |
1117 | s << (float)m.m11() << (float)m.m12() << (float)m.m21() |
1118 | << (float)m.m22() << (float)m.dx() << (float)m.dy(); |
1119 | } else { |
1120 | s << double(m.m11()) |
1121 | << double(m.m12()) |
1122 | << double(m.m21()) |
1123 | << double(m.m22()) |
1124 | << double(m.dx()) |
1125 | << double(m.dy()); |
1126 | } |
1127 | return s; |
1128 | } |
1129 | |
1130 | /*! |
1131 | \fn QDataStream &operator>>(QDataStream &stream, QMatrix &matrix) |
1132 | \relates QMatrix |
1133 | |
1134 | Reads the given \a matrix from the given \a stream and returns a |
1135 | reference to the stream. |
1136 | |
1137 | \sa {Serializing Qt Data Types} |
1138 | */ |
1139 | |
1140 | QDataStream &operator>>(QDataStream &s, QMatrix &m) |
1141 | { |
1142 | if (s.version() == 1) { |
1143 | float m11, m12, m21, m22, dx, dy; |
1144 | s >> m11; s >> m12; s >> m21; s >> m22; |
1145 | s >> dx; s >> dy; |
1146 | m.setMatrix(m11, m12, m21, m22, dx, dy); |
1147 | } |
1148 | else { |
1149 | double m11, m12, m21, m22, dx, dy; |
1150 | s >> m11; |
1151 | s >> m12; |
1152 | s >> m21; |
1153 | s >> m22; |
1154 | s >> dx; |
1155 | s >> dy; |
1156 | m.setMatrix(m11, m12, m21, m22, dx, dy); |
1157 | } |
1158 | return s; |
1159 | } |
1160 | #endif // QT_NO_DATASTREAM |
1161 | |
1162 | #ifndef QT_NO_DEBUG_STREAM |
1163 | QDebug operator<<(QDebug dbg, const QMatrix &m) |
1164 | { |
1165 | QDebugStateSaver saver(dbg); |
1166 | dbg.nospace() << "QMatrix(" |
1167 | << "11=" << m.m11() |
1168 | << " 12=" << m.m12() |
1169 | << " 21=" << m.m21() |
1170 | << " 22=" << m.m22() |
1171 | << " dx=" << m.dx() |
1172 | << " dy=" << m.dy() |
1173 | << ')'; |
1174 | return dbg; |
1175 | } |
1176 | #endif |
1177 | |
1178 | /*! |
1179 | \fn bool qFuzzyCompare(const QMatrix& m1, const QMatrix& m2) |
1180 | |
1181 | \relates QMatrix |
1182 | \since 4.6 |
1183 | |
1184 | \brief The qFuzzyCompare function is for comparing two matrices |
1185 | using a fuzziness factor. |
1186 | |
1187 | Returns \c true if \a m1 and \a m2 are equal, allowing for a small |
1188 | fuzziness factor for floating-point comparisons; false otherwise. |
1189 | */ |
1190 | |
1191 | QT_END_NAMESPACE |
1192 | |