Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qtransform.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3#include "qtransform.h"
4
5#include "qdatastream.h"
6#include "qdebug.h"
7#include "qhashfunctions.h"
8#include "qregion.h"
9#include "qpainterpath.h"
10#include "qpainterpath_p.h"
11#include "qvariant.h"
12#include "qmath_p.h"
13#include <qnumeric.h>
14
15#include <private/qbezier_p.h>
16
18
19#ifndef QT_NO_DEBUG
21static void nanWarning(const char *func)
22{
23 qWarning("QTransform::%s with NaN called", func);
24}
25#endif // QT_NO_DEBUG
26
27#define Q_NEAR_CLIP (sizeof(qreal) == sizeof(double) ? 0.000001 : 0.0001)
28
29#ifdef MAP
30# undef MAP
31#endif
32#define MAP(x, y, nx, ny) \
33 do { \
34 qreal FX_ = x; \
35 qreal FY_ = y; \
36 switch(t) { \
37 case TxNone: \
38 nx = FX_; \
39 ny = FY_; \
40 break; \
41 case TxTranslate: \
42 nx = FX_ + m_matrix[2][0]; \
43 ny = FY_ + m_matrix[2][1]; \
44 break; \
45 case TxScale: \
46 nx = m_matrix[0][0] * FX_ + m_matrix[2][0]; \
47 ny = m_matrix[1][1] * FY_ + m_matrix[2][1]; \
48 break; \
49 case TxRotate: \
50 case TxShear: \
51 case TxProject: \
52 nx = m_matrix[0][0] * FX_ + m_matrix[1][0] * FY_ + m_matrix[2][0]; \
53 ny = m_matrix[0][1] * FX_ + m_matrix[1][1] * FY_ + m_matrix[2][1]; \
54 if (t == TxProject) { \
55 qreal w = (m_matrix[0][2] * FX_ + m_matrix[1][2] * FY_ + m_matrix[2][2]); \
56 if (w < qreal(Q_NEAR_CLIP)) w = qreal(Q_NEAR_CLIP); \
57 w = qreal(1.)/w; \
58 nx *= w; \
59 ny *= w; \
60 } \
61 } \
62 } while (0)
63
263{
264 qreal h11, h12, h13,
265 h21, h22, h23,
266 h31, h32, h33;
267 h11 = m_matrix[1][1] * m_matrix[2][2] - m_matrix[1][2] * m_matrix[2][1];
268 h21 = m_matrix[1][2] * m_matrix[2][0] - m_matrix[1][0] * m_matrix[2][2];
269 h31 = m_matrix[1][0] * m_matrix[2][1] - m_matrix[1][1] * m_matrix[2][0];
270 h12 = m_matrix[0][2] * m_matrix[2][1] - m_matrix[0][1] * m_matrix[2][2];
271 h22 = m_matrix[0][0] * m_matrix[2][2] - m_matrix[0][2] * m_matrix[2][0];
272 h32 = m_matrix[0][1] * m_matrix[2][0] - m_matrix[0][0] * m_matrix[2][1];
273 h13 = m_matrix[0][1] * m_matrix[1][2] - m_matrix[0][2] * m_matrix[1][1];
274 h23 = m_matrix[0][2] * m_matrix[1][0] - m_matrix[0][0] * m_matrix[1][2];
275 h33 = m_matrix[0][0] * m_matrix[1][1] - m_matrix[0][1] * m_matrix[1][0];
276
277 return QTransform(h11, h12, h13,
278 h21, h22, h23,
279 h31, h32, h33);
280}
281
286{
287 QTransform t(m_matrix[0][0], m_matrix[1][0], m_matrix[2][0],
288 m_matrix[0][1], m_matrix[1][1], m_matrix[2][1],
289 m_matrix[0][2], m_matrix[1][2], m_matrix[2][2]);
290 return t;
291}
292
303QTransform QTransform::inverted(bool *invertible) const
304{
306 bool inv = true;
307
308 switch(inline_type()) {
309 case TxNone:
310 break;
311 case TxTranslate:
312 invert.m_matrix[2][0] = -m_matrix[2][0];
313 invert.m_matrix[2][1] = -m_matrix[2][1];
314 break;
315 case TxScale:
316 inv = !qFuzzyIsNull(m_matrix[0][0]);
317 inv &= !qFuzzyIsNull(m_matrix[1][1]);
318 if (inv) {
319 invert.m_matrix[0][0] = 1. / m_matrix[0][0];
320 invert.m_matrix[1][1] = 1. / m_matrix[1][1];
321 invert.m_matrix[2][0] = -m_matrix[2][0] * invert.m_matrix[0][0];
322 invert.m_matrix[2][1] = -m_matrix[2][1] * invert.m_matrix[1][1];
323 }
324 break;
325// case TxRotate:
326// case TxShear:
327// invert.affine = affine.inverted(&inv);
328// break;
329 default:
330 // general case
331 qreal det = determinant();
332 inv = !qFuzzyIsNull(det);
333 if (inv)
334 invert = adjoint() / det;
335 break;
336 }
337
338 if (invertible)
339 *invertible = inv;
340
341 if (inv) {
342 // inverting doesn't change the type
343 invert.m_type = m_type;
344 invert.m_dirty = m_dirty;
345 }
346
347 return invert;
348}
349
357{
358 if (dx == 0 && dy == 0)
359 return *this;
360#ifndef QT_NO_DEBUG
361 if (qIsNaN(dx) || qIsNaN(dy)) {
362 nanWarning("translate");
363 return *this;
364 }
365#endif
366
367 switch(inline_type()) {
368 case TxNone:
369 m_matrix[2][0] = dx;
370 m_matrix[2][1] = dy;
371 break;
372 case TxTranslate:
373 m_matrix[2][0] += dx;
374 m_matrix[2][1] += dy;
375 break;
376 case TxScale:
377 m_matrix[2][0] += dx * m_matrix[0][0];
378 m_matrix[2][1] += dy * m_matrix[1][1];
379 break;
380 case TxProject:
381 m_matrix[2][2] += dx * m_matrix[0][2] + dy * m_matrix[1][2];
383 case TxShear:
384 case TxRotate:
385 m_matrix[2][0] += dx * m_matrix[0][0] + dy * m_matrix[1][0];
386 m_matrix[2][1] += dy * m_matrix[1][1] + dx * m_matrix[0][1];
387 break;
388 }
389 if (m_dirty < TxTranslate)
390 m_dirty = TxTranslate;
391 return *this;
392}
393
402{
403#ifndef QT_NO_DEBUG
404 if (qIsNaN(dx) || qIsNaN(dy)) {
405 nanWarning("fromTranslate");
406 return QTransform();
407}
408#endif
409 QTransform transform(1, 0, 0, 0, 1, 0, dx, dy, 1);
410 if (dx == 0 && dy == 0)
411 transform.m_type = TxNone;
412 else
413 transform.m_type = TxTranslate;
414 transform.m_dirty = TxNone;
415 return transform;
416}
417
425{
426 if (sx == 1 && sy == 1)
427 return *this;
428#ifndef QT_NO_DEBUG
429 if (qIsNaN(sx) || qIsNaN(sy)) {
430 nanWarning("scale");
431 return *this;
432 }
433#endif
434
435 switch(inline_type()) {
436 case TxNone:
437 case TxTranslate:
438 m_matrix[0][0] = sx;
439 m_matrix[1][1] = sy;
440 break;
441 case TxProject:
442 m_matrix[0][2] *= sx;
443 m_matrix[1][2] *= sy;
445 case TxRotate:
446 case TxShear:
447 m_matrix[0][1] *= sx;
448 m_matrix[1][0] *= sy;
450 case TxScale:
451 m_matrix[0][0] *= sx;
452 m_matrix[1][1] *= sy;
453 break;
454 }
455 if (m_dirty < TxScale)
456 m_dirty = TxScale;
457 return *this;
458}
459
468{
469#ifndef QT_NO_DEBUG
470 if (qIsNaN(sx) || qIsNaN(sy)) {
471 nanWarning("fromScale");
472 return QTransform();
473}
474#endif
475 QTransform transform(sx, 0, 0, 0, sy, 0, 0, 0, 1);
476 if (sx == 1. && sy == 1.)
477 transform.m_type = TxNone;
478 else
479 transform.m_type = TxScale;
480 transform.m_dirty = TxNone;
481 return transform;
482}
483
491{
492 if (sh == 0 && sv == 0)
493 return *this;
494#ifndef QT_NO_DEBUG
495 if (qIsNaN(sh) || qIsNaN(sv)) {
496 nanWarning("shear");
497 return *this;
498 }
499#endif
500
501 switch(inline_type()) {
502 case TxNone:
503 case TxTranslate:
504 m_matrix[0][1] = sv;
505 m_matrix[1][0] = sh;
506 break;
507 case TxScale:
508 m_matrix[0][1] = sv*m_matrix[1][1];
509 m_matrix[1][0] = sh*m_matrix[0][0];
510 break;
511 case TxProject: {
512 qreal tm13 = sv * m_matrix[1][2];
513 qreal tm23 = sh * m_matrix[0][2];
514 m_matrix[0][2] += tm13;
515 m_matrix[1][2] += tm23;
516 }
518 case TxRotate:
519 case TxShear: {
520 qreal tm11 = sv * m_matrix[1][0];
521 qreal tm22 = sh * m_matrix[0][1];
522 qreal tm12 = sv * m_matrix[1][1];
523 qreal tm21 = sh * m_matrix[0][0];
524 m_matrix[0][0] += tm11;
525 m_matrix[0][1] += tm12;
526 m_matrix[1][0] += tm21;
527 m_matrix[1][1] += tm22;
528 break;
529 }
530 }
531 if (m_dirty < TxShear)
532 m_dirty = TxShear;
533 return *this;
534}
535
544
550
558{
559 if (a == 0)
560 return *this;
561#ifndef QT_NO_DEBUG
562 if (qIsNaN(a) || qIsNaN(distanceToPlane)) {
563 nanWarning("rotate");
564 return *this;
565 }
566#endif
567
568 qreal sina = 0;
569 qreal cosa = 0;
570 if (a == 90. || a == -270.)
571 sina = 1.;
572 else if (a == 270. || a == -90.)
573 sina = -1.;
574 else if (a == 180.)
575 cosa = -1.;
576 else{
578 sina = qSin(b); // fast and convenient
579 cosa = qCos(b);
580 }
581
582 if (axis == Qt::ZAxis) {
583 switch(inline_type()) {
584 case TxNone:
585 case TxTranslate:
586 m_matrix[0][0] = cosa;
587 m_matrix[0][1] = sina;
588 m_matrix[1][0] = -sina;
589 m_matrix[1][1] = cosa;
590 break;
591 case TxScale: {
592 qreal tm11 = cosa * m_matrix[0][0];
593 qreal tm12 = sina * m_matrix[1][1];
594 qreal tm21 = -sina * m_matrix[0][0];
595 qreal tm22 = cosa * m_matrix[1][1];
596 m_matrix[0][0] = tm11;
597 m_matrix[0][1] = tm12;
598 m_matrix[1][0] = tm21;
599 m_matrix[1][1] = tm22;
600 break;
601 }
602 case TxProject: {
603 qreal tm13 = cosa * m_matrix[0][2] + sina * m_matrix[1][2];
604 qreal tm23 = -sina * m_matrix[0][2] + cosa * m_matrix[1][2];
605 m_matrix[0][2] = tm13;
606 m_matrix[1][2] = tm23;
608 }
609 case TxRotate:
610 case TxShear: {
611 qreal tm11 = cosa * m_matrix[0][0] + sina * m_matrix[1][0];
612 qreal tm12 = cosa * m_matrix[0][1] + sina * m_matrix[1][1];
613 qreal tm21 = -sina * m_matrix[0][0] + cosa * m_matrix[1][0];
614 qreal tm22 = -sina * m_matrix[0][1] + cosa * m_matrix[1][1];
615 m_matrix[0][0] = tm11;
616 m_matrix[0][1] = tm12;
617 m_matrix[1][0] = tm21;
618 m_matrix[1][1] = tm22;
619 break;
620 }
621 }
622 if (m_dirty < TxRotate)
623 m_dirty = TxRotate;
624 } else {
625 if (!qIsNull(distanceToPlane))
626 sina /= distanceToPlane;
627
629 if (axis == Qt::YAxis) {
630 result.m_matrix[0][0] = cosa;
631 result.m_matrix[0][2] = -sina;
632 } else {
633 result.m_matrix[1][1] = cosa;
634 result.m_matrix[1][2] = -sina;
635 }
636 result.m_type = TxProject;
637 *this = result * *this;
638 }
639
640 return *this;
641}
642
643#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
656{
657 return rotate(a, axis, 1024.0);
658}
659#endif
660
669
675
683{
684#ifndef QT_NO_DEBUG
685 if (qIsNaN(a) || qIsNaN(distanceToPlane)) {
686 nanWarning("rotateRadians");
687 return *this;
688 }
689#endif
690 qreal sina = qSin(a);
691 qreal cosa = qCos(a);
692
693 if (axis == Qt::ZAxis) {
694 switch(inline_type()) {
695 case TxNone:
696 case TxTranslate:
697 m_matrix[0][0] = cosa;
698 m_matrix[0][1] = sina;
699 m_matrix[1][0] = -sina;
700 m_matrix[1][1] = cosa;
701 break;
702 case TxScale: {
703 qreal tm11 = cosa * m_matrix[0][0];
704 qreal tm12 = sina * m_matrix[1][1];
705 qreal tm21 = -sina * m_matrix[0][0];
706 qreal tm22 = cosa * m_matrix[1][1];
707 m_matrix[0][0] = tm11;
708 m_matrix[0][1] = tm12;
709 m_matrix[1][0] = tm21;
710 m_matrix[1][1] = tm22;
711 break;
712 }
713 case TxProject: {
714 qreal tm13 = cosa * m_matrix[0][2] + sina * m_matrix[1][2];
715 qreal tm23 = -sina * m_matrix[0][2] + cosa * m_matrix[1][2];
716 m_matrix[0][2] = tm13;
717 m_matrix[1][2] = tm23;
719 }
720 case TxRotate:
721 case TxShear: {
722 qreal tm11 = cosa * m_matrix[0][0] + sina * m_matrix[1][0];
723 qreal tm12 = cosa * m_matrix[0][1] + sina * m_matrix[1][1];
724 qreal tm21 = -sina * m_matrix[0][0] + cosa * m_matrix[1][0];
725 qreal tm22 = -sina * m_matrix[0][1] + cosa * m_matrix[1][1];
726 m_matrix[0][0] = tm11;
727 m_matrix[0][1] = tm12;
728 m_matrix[1][0] = tm21;
729 m_matrix[1][1] = tm22;
730 break;
731 }
732 }
733 if (m_dirty < TxRotate)
734 m_dirty = TxRotate;
735 } else {
736 if (!qIsNull(distanceToPlane))
737 sina /= distanceToPlane;
738
740 if (axis == Qt::YAxis) {
741 result.m_matrix[0][0] = cosa;
742 result.m_matrix[0][2] = -sina;
743 } else {
744 result.m_matrix[1][1] = cosa;
745 result.m_matrix[1][2] = -sina;
746 }
747 result.m_type = TxProject;
748 *this = result * *this;
749 }
750 return *this;
751}
752
753#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0)
766{
767 return rotateRadians(a, axis, 1024.0);
768}
769#endif
770
777{
778 return m_matrix[0][0] == o.m_matrix[0][0] &&
779 m_matrix[0][1] == o.m_matrix[0][1] &&
780 m_matrix[1][0] == o.m_matrix[1][0] &&
781 m_matrix[1][1] == o.m_matrix[1][1] &&
782 m_matrix[2][0] == o.m_matrix[2][0] &&
783 m_matrix[2][1] == o.m_matrix[2][1] &&
784 m_matrix[0][2] == o.m_matrix[0][2] &&
785 m_matrix[1][2] == o.m_matrix[1][2] &&
786 m_matrix[2][2] == o.m_matrix[2][2];
787}
788
796size_t qHash(const QTransform &key, size_t seed) noexcept
797{
799 seed = hash(seed, key.m11());
800 seed = hash(seed, key.m12());
801 seed = hash(seed, key.m21());
802 seed = hash(seed, key.m22());
803 seed = hash(seed, key.dx());
804 seed = hash(seed, key.dy());
805 seed = hash(seed, key.m13());
806 seed = hash(seed, key.m23());
807 seed = hash(seed, key.m33());
808 return seed;
809}
810
811
818{
819 return !operator==(o);
820}
821
830{
831 const TransformationType otherType = o.inline_type();
832 if (otherType == TxNone)
833 return *this;
834
835 const TransformationType thisType = inline_type();
836 if (thisType == TxNone)
837 return operator=(o);
838
839 TransformationType t = qMax(thisType, otherType);
840 switch(t) {
841 case TxNone:
842 break;
843 case TxTranslate:
844 m_matrix[2][0] += o.m_matrix[2][0];
845 m_matrix[2][1] += o.m_matrix[2][1];
846 break;
847 case TxScale:
848 {
849 qreal m11 = m_matrix[0][0] * o.m_matrix[0][0];
850 qreal m22 = m_matrix[1][1] * o.m_matrix[1][1];
851
852 qreal m31 = m_matrix[2][0] * o.m_matrix[0][0] + o.m_matrix[2][0];
853 qreal m32 = m_matrix[2][1] * o.m_matrix[1][1] + o.m_matrix[2][1];
854
855 m_matrix[0][0] = m11;
856 m_matrix[1][1] = m22;
857 m_matrix[2][0] = m31; m_matrix[2][1] = m32;
858 break;
859 }
860 case TxRotate:
861 case TxShear:
862 {
863 qreal m11 = m_matrix[0][0] * o.m_matrix[0][0] + m_matrix[0][1] * o.m_matrix[1][0];
864 qreal m12 = m_matrix[0][0] * o.m_matrix[0][1] + m_matrix[0][1] * o.m_matrix[1][1];
865
866 qreal m21 = m_matrix[1][0] * o.m_matrix[0][0] + m_matrix[1][1] * o.m_matrix[1][0];
867 qreal m22 = m_matrix[1][0] * o.m_matrix[0][1] + m_matrix[1][1] * o.m_matrix[1][1];
868
869 qreal m31 = m_matrix[2][0] * o.m_matrix[0][0] + m_matrix[2][1] * o.m_matrix[1][0] + o.m_matrix[2][0];
870 qreal m32 = m_matrix[2][0] * o.m_matrix[0][1] + m_matrix[2][1] * o.m_matrix[1][1] + o.m_matrix[2][1];
871
872 m_matrix[0][0] = m11;
873 m_matrix[0][1] = m12;
874 m_matrix[1][0] = m21;
875 m_matrix[1][1] = m22;
876 m_matrix[2][0] = m31;
877 m_matrix[2][1] = m32;
878 break;
879 }
880 case TxProject:
881 {
882 qreal m11 = m_matrix[0][0] * o.m_matrix[0][0] + m_matrix[0][1] * o.m_matrix[1][0] + m_matrix[0][2] * o.m_matrix[2][0];
883 qreal m12 = m_matrix[0][0] * o.m_matrix[0][1] + m_matrix[0][1] * o.m_matrix[1][1] + m_matrix[0][2] * o.m_matrix[2][1];
884 qreal m13 = m_matrix[0][0] * o.m_matrix[0][2] + m_matrix[0][1] * o.m_matrix[1][2] + m_matrix[0][2] * o.m_matrix[2][2];
885
886 qreal m21 = m_matrix[1][0] * o.m_matrix[0][0] + m_matrix[1][1] * o.m_matrix[1][0] + m_matrix[1][2] * o.m_matrix[2][0];
887 qreal m22 = m_matrix[1][0] * o.m_matrix[0][1] + m_matrix[1][1] * o.m_matrix[1][1] + m_matrix[1][2] * o.m_matrix[2][1];
888 qreal m23 = m_matrix[1][0] * o.m_matrix[0][2] + m_matrix[1][1] * o.m_matrix[1][2] + m_matrix[1][2] * o.m_matrix[2][2];
889
890 qreal m31 = m_matrix[2][0] * o.m_matrix[0][0] + m_matrix[2][1] * o.m_matrix[1][0] + m_matrix[2][2] * o.m_matrix[2][0];
891 qreal m32 = m_matrix[2][0] * o.m_matrix[0][1] + m_matrix[2][1] * o.m_matrix[1][1] + m_matrix[2][2] * o.m_matrix[2][1];
892 qreal m33 = m_matrix[2][0] * o.m_matrix[0][2] + m_matrix[2][1] * o.m_matrix[1][2] + m_matrix[2][2] * o.m_matrix[2][2];
893
894 m_matrix[0][0] = m11; m_matrix[0][1] = m12; m_matrix[0][2] = m13;
895 m_matrix[1][0] = m21; m_matrix[1][1] = m22; m_matrix[1][2] = m23;
896 m_matrix[2][0] = m31; m_matrix[2][1] = m32; m_matrix[2][2] = m33;
897 }
898 }
899
900 m_dirty = t;
901 m_type = t;
902
903 return *this;
904}
905
915{
916 const TransformationType otherType = m.inline_type();
917 if (otherType == TxNone)
918 return *this;
919
920 const TransformationType thisType = inline_type();
921 if (thisType == TxNone)
922 return m;
923
925 TransformationType type = qMax(thisType, otherType);
926 switch(type) {
927 case TxNone:
928 break;
929 case TxTranslate:
930 t.m_matrix[2][0] = m_matrix[2][0] + m.m_matrix[2][0];
931 t.m_matrix[2][1] = m_matrix[2][1] + m.m_matrix[2][1];
932 break;
933 case TxScale:
934 {
935 qreal m11 = m_matrix[0][0] * m.m_matrix[0][0];
936 qreal m22 = m_matrix[1][1] * m.m_matrix[1][1];
937
938 qreal m31 = m_matrix[2][0] * m.m_matrix[0][0] + m.m_matrix[2][0];
939 qreal m32 = m_matrix[2][1] * m.m_matrix[1][1] + m.m_matrix[2][1];
940
941 t.m_matrix[0][0] = m11;
942 t.m_matrix[1][1] = m22;
943 t.m_matrix[2][0] = m31;
944 t.m_matrix[2][1] = m32;
945 break;
946 }
947 case TxRotate:
948 case TxShear:
949 {
950 qreal m11 = m_matrix[0][0] * m.m_matrix[0][0] + m_matrix[0][1] * m.m_matrix[1][0];
951 qreal m12 = m_matrix[0][0] * m.m_matrix[0][1] + m_matrix[0][1] * m.m_matrix[1][1];
952
953 qreal m21 = m_matrix[1][0] * m.m_matrix[0][0] + m_matrix[1][1] * m.m_matrix[1][0];
954 qreal m22 = m_matrix[1][0] * m.m_matrix[0][1] + m_matrix[1][1] * m.m_matrix[1][1];
955
956 qreal m31 = m_matrix[2][0] * m.m_matrix[0][0] + m_matrix[2][1] * m.m_matrix[1][0] + m.m_matrix[2][0];
957 qreal m32 = m_matrix[2][0] * m.m_matrix[0][1] + m_matrix[2][1] * m.m_matrix[1][1] + m.m_matrix[2][1];
958
959 t.m_matrix[0][0] = m11; t.m_matrix[0][1] = m12;
960 t.m_matrix[1][0] = m21; t.m_matrix[1][1] = m22;
961 t.m_matrix[2][0] = m31; t.m_matrix[2][1] = m32;
962 break;
963 }
964 case TxProject:
965 {
966 qreal m11 = m_matrix[0][0] * m.m_matrix[0][0] + m_matrix[0][1] * m.m_matrix[1][0] + m_matrix[0][2] * m.m_matrix[2][0];
967 qreal m12 = m_matrix[0][0] * m.m_matrix[0][1] + m_matrix[0][1] * m.m_matrix[1][1] + m_matrix[0][2] * m.m_matrix[2][1];
968 qreal m13 = m_matrix[0][0] * m.m_matrix[0][2] + m_matrix[0][1] * m.m_matrix[1][2] + m_matrix[0][2] * m.m_matrix[2][2];
969
970 qreal m21 = m_matrix[1][0] * m.m_matrix[0][0] + m_matrix[1][1] * m.m_matrix[1][0] + m_matrix[1][2] * m.m_matrix[2][0];
971 qreal m22 = m_matrix[1][0] * m.m_matrix[0][1] + m_matrix[1][1] * m.m_matrix[1][1] + m_matrix[1][2] * m.m_matrix[2][1];
972 qreal m23 = m_matrix[1][0] * m.m_matrix[0][2] + m_matrix[1][1] * m.m_matrix[1][2] + m_matrix[1][2] * m.m_matrix[2][2];
973
974 qreal m31 = m_matrix[2][0] * m.m_matrix[0][0] + m_matrix[2][1] * m.m_matrix[1][0] + m_matrix[2][2] * m.m_matrix[2][0];
975 qreal m32 = m_matrix[2][0] * m.m_matrix[0][1] + m_matrix[2][1] * m.m_matrix[1][1] + m_matrix[2][2] * m.m_matrix[2][1];
976 qreal m33 = m_matrix[2][0] * m.m_matrix[0][2] + m_matrix[2][1] * m.m_matrix[1][2] + m_matrix[2][2] * m.m_matrix[2][2];
977
978 t.m_matrix[0][0] = m11; t.m_matrix[0][1] = m12; t.m_matrix[0][2] = m13;
979 t.m_matrix[1][0] = m21; t.m_matrix[1][1] = m22; t.m_matrix[1][2] = m23;
980 t.m_matrix[2][0] = m31; t.m_matrix[2][1] = m32; t.m_matrix[2][2] = m33;
981 }
982 }
983
984 t.m_dirty = type;
985 t.m_type = type;
986
987 return t;
988}
989
1037{
1038 *this = QTransform();
1039}
1040
1041#ifndef QT_NO_DATASTREAM
1053{
1054 s << double(m.m11())
1055 << double(m.m12())
1056 << double(m.m13())
1057 << double(m.m21())
1058 << double(m.m22())
1059 << double(m.m23())
1060 << double(m.m31())
1061 << double(m.m32())
1062 << double(m.m33());
1063 return s;
1064}
1065
1077{
1078 double m11, m12, m13,
1079 m21, m22, m23,
1080 m31, m32, m33;
1081
1082 s >> m11;
1083 s >> m12;
1084 s >> m13;
1085 s >> m21;
1086 s >> m22;
1087 s >> m23;
1088 s >> m31;
1089 s >> m32;
1090 s >> m33;
1091 t.setMatrix(m11, m12, m13,
1092 m21, m22, m23,
1093 m31, m32, m33);
1094 return s;
1095}
1096
1097#endif // QT_NO_DATASTREAM
1098
1099#ifndef QT_NO_DEBUG_STREAM
1101{
1102 static const char typeStr[][12] =
1103 {
1104 "TxNone",
1105 "TxTranslate",
1106 "TxScale",
1107 "",
1108 "TxRotate",
1109 "", "", "",
1110 "TxShear",
1111 "", "", "", "", "", "", "",
1112 "TxProject"
1113 };
1114
1115 QDebugStateSaver saver(dbg);
1116 dbg.nospace() << "QTransform(type=" << typeStr[m.type()] << ','
1117 << " 11=" << m.m11()
1118 << " 12=" << m.m12()
1119 << " 13=" << m.m13()
1120 << " 21=" << m.m21()
1121 << " 22=" << m.m22()
1122 << " 23=" << m.m23()
1123 << " 31=" << m.m31()
1124 << " 32=" << m.m32()
1125 << " 33=" << m.m33()
1126 << ')';
1127
1128 return dbg;
1129}
1130#endif
1131
1141{
1142 qreal fx = p.x();
1143 qreal fy = p.y();
1144
1145 qreal x = 0, y = 0;
1146
1147 TransformationType t = inline_type();
1148 MAP(fx, fy, x, y);
1149
1150 return QPoint(qRound(x), qRound(y));
1151}
1152
1153
1170{
1171 qreal fx = p.x();
1172 qreal fy = p.y();
1173
1174 qreal x = 0, y = 0;
1175
1176 TransformationType t = inline_type();
1177 MAP(fx, fy, x, y);
1178
1179 return QPointF(x, y);
1180}
1181
1217{
1218 qreal fx1 = l.x1();
1219 qreal fy1 = l.y1();
1220 qreal fx2 = l.x2();
1221 qreal fy2 = l.y2();
1222
1223 qreal x1 = 0, y1 = 0, x2 = 0, y2 = 0;
1224
1225 TransformationType t = inline_type();
1226 MAP(fx1, fy1, x1, y1);
1227 MAP(fx2, fy2, x2, y2);
1228
1229 return QLine(qRound(x1), qRound(y1), qRound(x2), qRound(y2));
1230}
1231
1244{
1245 qreal fx1 = l.x1();
1246 qreal fy1 = l.y1();
1247 qreal fx2 = l.x2();
1248 qreal fy2 = l.y2();
1249
1250 qreal x1 = 0, y1 = 0, x2 = 0, y2 = 0;
1251
1252 TransformationType t = inline_type();
1253 MAP(fx1, fy1, x1, y1);
1254 MAP(fx2, fy2, x2, y2);
1255
1256 return QLineF(x1, y1, x2, y2);
1257}
1258
1287{
1288 TransformationType t = inline_type();
1289 if (t <= TxTranslate)
1290 return a.translated(m_matrix[2][0], m_matrix[2][1]);
1291
1292 int size = a.size();
1293 int i;
1294 QPolygonF p(size);
1295 const QPointF *da = a.constData();
1296 QPointF *dp = p.data();
1297
1298 for(i = 0; i < size; ++i) {
1299 MAP(da[i].xp, da[i].yp, dp[i].xp, dp[i].yp);
1300 }
1301 return p;
1302}
1303
1314{
1315 TransformationType t = inline_type();
1316 if (t <= TxTranslate)
1317 return a.translated(qRound(m_matrix[2][0]), qRound(m_matrix[2][1]));
1318
1319 int size = a.size();
1320 int i;
1321 QPolygon p(size);
1322 const QPoint *da = a.constData();
1323 QPoint *dp = p.data();
1324
1325 for(i = 0; i < size; ++i) {
1326 qreal nx = 0, ny = 0;
1327 MAP(da[i].xp, da[i].yp, nx, ny);
1328 dp[i].xp = qRound(nx);
1329 dp[i].yp = qRound(ny);
1330 }
1331 return p;
1332}
1333
1343extern QPainterPath qt_regionToPath(const QRegion &region);
1344
1356{
1357 TransformationType t = inline_type();
1358 if (t == TxNone)
1359 return r;
1360
1361 if (t == TxTranslate) {
1362 QRegion copy(r);
1363 copy.translate(qRound(m_matrix[2][0]), qRound(m_matrix[2][1]));
1364 return copy;
1365 }
1366
1367 if (t == TxScale) {
1368 QRegion res;
1369 if (m11() < 0 || m22() < 0) {
1370 for (const QRect &rect : r)
1371 res += qt_mapFillRect(QRectF(rect), *this);
1372 } else {
1373 QVarLengthArray<QRect, 32> rects;
1374 rects.reserve(r.rectCount());
1375 for (const QRect &rect : r) {
1376 QRect nr = qt_mapFillRect(QRectF(rect), *this);
1377 if (!nr.isEmpty())
1378 rects.append(nr);
1379 }
1380 res.setRects(rects.constData(), rects.size());
1381 }
1382 return res;
1383 }
1384
1386 return p.toFillPolygon().toPolygon();
1387}
1388
1390{
1394
1396 QHomogeneousCoordinate(qreal x_, qreal y_, qreal w_) : x(x_), y(y_), w(w_) {}
1397
1398 const QPointF toPoint() const {
1399 qreal iw = 1. / w;
1400 return QPointF(x * iw, y * iw);
1401 }
1402};
1403
1405{
1407 c.x = transform.m11() * p.x() + transform.m21() * p.y() + transform.m31();
1408 c.y = transform.m12() * p.x() + transform.m22() * p.y() + transform.m32();
1409 c.w = transform.m13() * p.x() + transform.m23() * p.y() + transform.m33();
1410 return c;
1411}
1412
1413static inline bool lineTo_clipped(QPainterPath &path, const QTransform &transform, const QPointF &a, const QPointF &b,
1414 bool needsMoveTo, bool needsLineTo = true)
1415{
1418
1419 if (ha.w < Q_NEAR_CLIP && hb.w < Q_NEAR_CLIP)
1420 return false;
1421
1422 if (hb.w < Q_NEAR_CLIP) {
1423 const qreal t = (Q_NEAR_CLIP - hb.w) / (ha.w - hb.w);
1424
1425 hb.x += (ha.x - hb.x) * t;
1426 hb.y += (ha.y - hb.y) * t;
1427 hb.w = qreal(Q_NEAR_CLIP);
1428 } else if (ha.w < Q_NEAR_CLIP) {
1429 const qreal t = (Q_NEAR_CLIP - ha.w) / (hb.w - ha.w);
1430
1431 ha.x += (hb.x - ha.x) * t;
1432 ha.y += (hb.y - ha.y) * t;
1433 ha.w = qreal(Q_NEAR_CLIP);
1434
1435 const QPointF p = ha.toPoint();
1436 if (needsMoveTo) {
1437 path.moveTo(p);
1438 needsMoveTo = false;
1439 } else {
1440 path.lineTo(p);
1441 }
1442 }
1443
1444 if (needsMoveTo)
1445 path.moveTo(ha.toPoint());
1446
1447 if (needsLineTo)
1448 path.lineTo(hb.toPoint());
1449
1450 return true;
1451}
1452Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale);
1453
1454static inline bool cubicTo_clipped(QPainterPath &path, const QTransform &transform, const QPointF &a, const QPointF &b, const QPointF &c, const QPointF &d, bool needsMoveTo)
1455{
1456 // Convert projective xformed curves to line
1457 // segments so they can be transformed more accurately
1458
1459 qreal scale;
1461
1462 qreal curveThreshold = scale == 0 ? qreal(0.25) : (qreal(0.25) / scale);
1463
1464 QPolygonF segment = QBezier::fromPoints(a, b, c, d).toPolygon(curveThreshold);
1465
1466 for (int i = 0; i < segment.size() - 1; ++i)
1467 if (lineTo_clipped(path, transform, segment.at(i), segment.at(i+1), needsMoveTo))
1468 needsMoveTo = false;
1469
1470 return !needsMoveTo;
1471}
1472
1474{
1476
1477 QPointF last;
1478 QPointF lastMoveTo;
1479 bool needsMoveTo = true;
1480 for (int i = 0; i < path.elementCount(); ++i) {
1481 switch (path.elementAt(i).type) {
1483 if (i > 0 && lastMoveTo != last)
1484 lineTo_clipped(result, transform, last, lastMoveTo, needsMoveTo);
1485
1486 lastMoveTo = path.elementAt(i);
1487 last = path.elementAt(i);
1488 needsMoveTo = true;
1489 break;
1491 if (lineTo_clipped(result, transform, last, path.elementAt(i), needsMoveTo))
1492 needsMoveTo = false;
1493 last = path.elementAt(i);
1494 break;
1496 if (cubicTo_clipped(result, transform, last, path.elementAt(i), path.elementAt(i+1), path.elementAt(i+2), needsMoveTo))
1497 needsMoveTo = false;
1498 i += 2;
1499 last = path.elementAt(i);
1500 break;
1501 default:
1502 Q_ASSERT(false);
1503 }
1504 }
1505
1506 if (path.elementCount() > 0 && lastMoveTo != last)
1507 lineTo_clipped(result, transform, last, lastMoveTo, needsMoveTo, false);
1508
1509 result.setFillRule(path.fillRule());
1510 return result;
1511}
1512
1531{
1532 TransformationType t = inline_type();
1533 if (t == TxNone || path.elementCount() == 0)
1534 return path;
1535
1536 if (t >= TxProject)
1537 return mapProjective(*this, path);
1538
1540
1541 if (t == TxTranslate) {
1542 copy.translate(m_matrix[2][0], m_matrix[2][1]);
1543 } else {
1544 copy.detach();
1545 // Full xform
1546 for (int i=0; i<path.elementCount(); ++i) {
1547 QPainterPath::Element &e = copy.d_ptr->elements[i];
1548 MAP(e.x, e.y, e.x, e.y);
1549 }
1550 }
1551
1552 return copy;
1553}
1554
1576{
1577 TransformationType t = inline_type();
1578
1579 QPolygon a(4);
1580 qreal x[4] = { 0, 0, 0, 0 }, y[4] = { 0, 0, 0, 0 };
1581 if (t <= TxScale) {
1582 x[0] = m_matrix[0][0]*rect.x() + m_matrix[2][0];
1583 y[0] = m_matrix[1][1]*rect.y() + m_matrix[2][1];
1584 qreal w = m_matrix[0][0]*rect.width();
1585 qreal h = m_matrix[1][1]*rect.height();
1586 if (w < 0) {
1587 w = -w;
1588 x[0] -= w;
1589 }
1590 if (h < 0) {
1591 h = -h;
1592 y[0] -= h;
1593 }
1594 x[1] = x[0]+w;
1595 x[2] = x[1];
1596 x[3] = x[0];
1597 y[1] = y[0];
1598 y[2] = y[0]+h;
1599 y[3] = y[2];
1600 } else {
1601 qreal right = rect.x() + rect.width();
1602 qreal bottom = rect.y() + rect.height();
1603 MAP(rect.x(), rect.y(), x[0], y[0]);
1604 MAP(right, rect.y(), x[1], y[1]);
1605 MAP(right, bottom, x[2], y[2]);
1606 MAP(rect.x(), bottom, x[3], y[3]);
1607 }
1608
1609 // all coordinates are correctly, transform to a pointarray
1610 // (rounding to the next integer)
1611 a.setPoints(4, qRound(x[0]), qRound(y[0]),
1612 qRound(x[1]), qRound(y[1]),
1613 qRound(x[2]), qRound(y[2]),
1614 qRound(x[3]), qRound(y[3]));
1615 return a;
1616}
1617
1626{
1627 if (quad.size() != 4)
1628 return false;
1629
1630 qreal dx0 = quad[0].x();
1631 qreal dx1 = quad[1].x();
1632 qreal dx2 = quad[2].x();
1633 qreal dx3 = quad[3].x();
1634
1635 qreal dy0 = quad[0].y();
1636 qreal dy1 = quad[1].y();
1637 qreal dy2 = quad[2].y();
1638 qreal dy3 = quad[3].y();
1639
1640 double ax = dx0 - dx1 + dx2 - dx3;
1641 double ay = dy0 - dy1 + dy2 - dy3;
1642
1643 if (!ax && !ay) { //afine transform
1644 trans.setMatrix(dx1 - dx0, dy1 - dy0, 0,
1645 dx2 - dx1, dy2 - dy1, 0,
1646 dx0, dy0, 1);
1647 } else {
1648 double ax1 = dx1 - dx2;
1649 double ax2 = dx3 - dx2;
1650 double ay1 = dy1 - dy2;
1651 double ay2 = dy3 - dy2;
1652
1653 /*determinants */
1654 double gtop = ax * ay2 - ax2 * ay;
1655 double htop = ax1 * ay - ax * ay1;
1656 double bottom = ax1 * ay2 - ax2 * ay1;
1657
1658 double a, b, c, d, e, f, g, h; /*i is always 1*/
1659
1660 if (!bottom)
1661 return false;
1662
1663 g = gtop/bottom;
1664 h = htop/bottom;
1665
1666 a = dx1 - dx0 + g * dx1;
1667 b = dx3 - dx0 + h * dx3;
1668 c = dx0;
1669 d = dy1 - dy0 + g * dy1;
1670 e = dy3 - dy0 + h * dy3;
1671 f = dy0;
1672
1673 trans.setMatrix(a, d, g,
1674 b, e, h,
1675 c, f, 1.0);
1676 }
1677
1678 return true;
1679}
1680
1691{
1692 if (!squareToQuad(quad, trans))
1693 return false;
1694
1695 bool invertible = false;
1696 trans = trans.inverted(&invertible);
1697
1698 return invertible;
1699}
1700
1714 const QPolygonF &two,
1715 QTransform &trans)
1716{
1717 QTransform stq;
1718 if (!quadToSquare(one, trans))
1719 return false;
1720 if (!squareToQuad(two, stq))
1721 return false;
1722 trans *= stq;
1723 //qDebug()<<"Final = "<<trans;
1724 return true;
1725}
1726
1739 qreal m21, qreal m22, qreal m23,
1740 qreal m31, qreal m32, qreal m33)
1741{
1742 m_matrix[0][0] = m11; m_matrix[0][1] = m12; m_matrix[0][2] = m13;
1743 m_matrix[1][0] = m21; m_matrix[1][1] = m22; m_matrix[1][2] = m23;
1744 m_matrix[2][0] = m31; m_matrix[2][1] = m32; m_matrix[2][2] = m33;
1745 m_type = TxNone;
1746 m_dirty = TxProject;
1747}
1748
1750{
1751 TransformationType t = inline_type();
1752 if (t <= TxTranslate)
1753 return rect.translated(qRound(m_matrix[2][0]), qRound(m_matrix[2][1]));
1754
1755 if (t <= TxScale) {
1756 int x = qRound(m_matrix[0][0] * rect.x() + m_matrix[2][0]);
1757 int y = qRound(m_matrix[1][1] * rect.y() + m_matrix[2][1]);
1758 int w = qRound(m_matrix[0][0] * rect.width());
1759 int h = qRound(m_matrix[1][1] * rect.height());
1760 if (w < 0) {
1761 w = -w;
1762 x -= w;
1763 }
1764 if (h < 0) {
1765 h = -h;
1766 y -= h;
1767 }
1768 return QRect(x, y, w, h);
1769 } else {
1770 qreal x = 0, y = 0;
1771 MAP(rect.left(), rect.top(), x, y);
1772 qreal xmin = x;
1773 qreal ymin = y;
1774 qreal xmax = x;
1775 qreal ymax = y;
1776 MAP(rect.right() + 1, rect.top(), x, y);
1777 xmin = qMin(xmin, x);
1778 ymin = qMin(ymin, y);
1779 xmax = qMax(xmax, x);
1780 ymax = qMax(ymax, y);
1781 MAP(rect.right() + 1, rect.bottom() + 1, x, y);
1782 xmin = qMin(xmin, x);
1783 ymin = qMin(ymin, y);
1784 xmax = qMax(xmax, x);
1785 ymax = qMax(ymax, y);
1786 MAP(rect.left(), rect.bottom() + 1, x, y);
1787 xmin = qMin(xmin, x);
1788 ymin = qMin(ymin, y);
1789 xmax = qMax(xmax, x);
1790 ymax = qMax(ymax, y);
1791 return QRectF(xmin, ymin, xmax-xmin, ymax-ymin).toRect();
1792 }
1793}
1794
1815{
1816 TransformationType t = inline_type();
1817 if (t <= TxTranslate)
1818 return rect.translated(m_matrix[2][0], m_matrix[2][1]);
1819
1820 if (t <= TxScale) {
1821 qreal x = m_matrix[0][0] * rect.x() + m_matrix[2][0];
1822 qreal y = m_matrix[1][1] * rect.y() + m_matrix[2][1];
1823 qreal w = m_matrix[0][0] * rect.width();
1824 qreal h = m_matrix[1][1] * rect.height();
1825 if (w < 0) {
1826 w = -w;
1827 x -= w;
1828 }
1829 if (h < 0) {
1830 h = -h;
1831 y -= h;
1832 }
1833 return QRectF(x, y, w, h);
1834 } else {
1835 qreal x = 0, y = 0;
1836 MAP(rect.x(), rect.y(), x, y);
1837 qreal xmin = x;
1838 qreal ymin = y;
1839 qreal xmax = x;
1840 qreal ymax = y;
1841 MAP(rect.x() + rect.width(), rect.y(), x, y);
1842 xmin = qMin(xmin, x);
1843 ymin = qMin(ymin, y);
1844 xmax = qMax(xmax, x);
1845 ymax = qMax(ymax, y);
1846 MAP(rect.x() + rect.width(), rect.y() + rect.height(), x, y);
1847 xmin = qMin(xmin, x);
1848 ymin = qMin(ymin, y);
1849 xmax = qMax(xmax, x);
1850 ymax = qMax(ymax, y);
1851 MAP(rect.x(), rect.y() + rect.height(), x, y);
1852 xmin = qMin(xmin, x);
1853 ymin = qMin(ymin, y);
1854 xmax = qMax(xmax, x);
1855 ymax = qMax(ymax, y);
1856 return QRectF(xmin, ymin, xmax-xmin, ymax - ymin);
1857 }
1858}
1859
1885{
1886 TransformationType t = inline_type();
1887 MAP(x, y, *tx, *ty);
1888}
1889
1898void QTransform::map(int x, int y, int *tx, int *ty) const
1899{
1900 TransformationType t = inline_type();
1901 qreal fx = 0, fy = 0;
1902 MAP(x, y, fx, fy);
1903 *tx = qRound(fx);
1904 *ty = qRound(fy);
1905}
1906
1920{
1921 if (m_dirty == TxNone || m_dirty < m_type)
1922 return static_cast<TransformationType>(m_type);
1923
1924 switch (static_cast<TransformationType>(m_dirty)) {
1925 case TxProject:
1926 if (!qFuzzyIsNull(m_matrix[0][2]) || !qFuzzyIsNull(m_matrix[1][2]) || !qFuzzyIsNull(m_matrix[2][2] - 1)) {
1927 m_type = TxProject;
1928 break;
1929 }
1930 Q_FALLTHROUGH();
1931 case TxShear:
1932 case TxRotate:
1933 if (!qFuzzyIsNull(m_matrix[0][1]) || !qFuzzyIsNull(m_matrix[1][0])) {
1934 const qreal dot = m_matrix[0][0] * m_matrix[1][0] + m_matrix[0][1] * m_matrix[1][1];
1935 if (qFuzzyIsNull(dot))
1936 m_type = TxRotate;
1937 else
1938 m_type = TxShear;
1939 break;
1940 }
1941 Q_FALLTHROUGH();
1942 case TxScale:
1943 if (!qFuzzyIsNull(m_matrix[0][0] - 1) || !qFuzzyIsNull(m_matrix[1][1] - 1)) {
1944 m_type = TxScale;
1945 break;
1946 }
1947 Q_FALLTHROUGH();
1948 case TxTranslate:
1949 if (!qFuzzyIsNull(m_matrix[2][0]) || !qFuzzyIsNull(m_matrix[2][1])) {
1950 m_type = TxTranslate;
1951 break;
1952 }
1953 Q_FALLTHROUGH();
1954 case TxNone:
1955 m_type = TxNone;
1956 break;
1957 }
1958
1959 m_dirty = TxNone;
1960 return static_cast<TransformationType>(m_type);
1961}
1962
1967QTransform::operator QVariant() const
1968{
1969 return QVariant::fromValue(*this);
1970}
1971
1972
2144// returns true if the transform is uniformly scaling
2145// (same scale in x and y direction)
2146// scale is set to the max of x and y scaling factors
2147Q_GUI_EXPORT
2149{
2152 if (scale)
2153 *scale = 1;
2154 return true;
2155 } else if (type == QTransform::TxScale) {
2156 const qreal xScale = qAbs(transform.m11());
2157 const qreal yScale = qAbs(transform.m22());
2158 if (scale)
2159 *scale = qMax(xScale, yScale);
2160 return qFuzzyCompare(xScale, yScale);
2161 }
2162
2163 // rotate then scale: compare columns
2164 const qreal xScale1 = transform.m11() * transform.m11()
2165 + transform.m21() * transform.m21();
2166 const qreal yScale1 = transform.m12() * transform.m12()
2167 + transform.m22() * transform.m22();
2168
2169 // scale then rotate: compare rows
2170 const qreal xScale2 = transform.m11() * transform.m11()
2171 + transform.m12() * transform.m12();
2172 const qreal yScale2 = transform.m21() * transform.m21()
2173 + transform.m22() * transform.m22();
2174
2175 // decide the order of rotate and scale operations
2176 if (qAbs(xScale1 - yScale1) > qAbs(xScale2 - yScale2)) {
2177 if (scale)
2178 *scale = qSqrt(qMax(xScale1, yScale1));
2179
2180 return type == QTransform::TxRotate && qFuzzyCompare(xScale1, yScale1);
2181 } else {
2182 if (scale)
2183 *scale = qSqrt(qMax(xScale2, yScale2));
2184
2185 return type == QTransform::TxRotate && qFuzzyCompare(xScale2, yScale2);
2186 }
2187}
2188
2189QDataStream & operator>>(QDataStream &s, QTransform::Affine &m)
2190{
2191 if (s.version() == 1) {
2192 float m11, m12, m21, m22, dx, dy;
2193 s >> m11; s >> m12; s >> m21; s >> m22; s >> dx; s >> dy;
2194
2195 m.m_matrix[0][0] = m11;
2196 m.m_matrix[0][1] = m12;
2197 m.m_matrix[1][0] = m21;
2198 m.m_matrix[1][1] = m22;
2199 m.m_matrix[2][0] = dx;
2200 m.m_matrix[2][1] = dy;
2201 } else {
2202 s >> m.m_matrix[0][0];
2203 s >> m.m_matrix[0][1];
2204 s >> m.m_matrix[1][0];
2205 s >> m.m_matrix[1][1];
2206 s >> m.m_matrix[2][0];
2207 s >> m.m_matrix[2][1];
2208 }
2209 m.m_matrix[0][2] = 0;
2210 m.m_matrix[1][2] = 0;
2211 m.m_matrix[2][2] = 1;
2212 return s;
2213}
2214
2215QDataStream &operator<<(QDataStream &s, const QTransform::Affine &m)
2216{
2217 if (s.version() == 1) {
2218 s << (float)m.m_matrix[0][0]
2219 << (float)m.m_matrix[0][1]
2220 << (float)m.m_matrix[1][0]
2221 << (float)m.m_matrix[1][1]
2222 << (float)m.m_matrix[2][0]
2223 << (float)m.m_matrix[2][1];
2224 } else {
2225 s << m.m_matrix[0][0]
2226 << m.m_matrix[0][1]
2227 << m.m_matrix[1][0]
2228 << m.m_matrix[1][1]
2229 << m.m_matrix[2][0]
2230 << m.m_matrix[2][1];
2231 }
2232 return s;
2233}
2234
static QBezier fromPoints(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4)
Definition qbezier_p.h:33
\inmodule QtCore\reentrant
Definition qdatastream.h:46
\inmodule QtCore
\inmodule QtCore
\inmodule QtCore\compares equality \compareswith equality QLine \endcompareswith
Definition qline.h:192
constexpr qreal x1() const
Returns the x-coordinate of the line's start point.
Definition qline.h:292
constexpr qreal y2() const
Returns the y-coordinate of the line's end point.
Definition qline.h:307
constexpr qreal x2() const
Returns the x-coordinate of the line's end point.
Definition qline.h:302
constexpr qreal y1() const
Returns the y-coordinate of the line's start point.
Definition qline.h:297
\inmodule QtCore\compares equality \compareswith equality QLineF \endcompareswith
Definition qline.h:18
constexpr int x2() const
Returns the x-coordinate of the line's end point.
Definition qline.h:94
constexpr int y2() const
Returns the y-coordinate of the line's end point.
Definition qline.h:99
constexpr int y1() const
Returns the y-coordinate of the line's start point.
Definition qline.h:89
constexpr int x1() const
Returns the x-coordinate of the line's start point.
Definition qline.h:84
\inmodule QtGui
\inmodule QtGui
\inmodule QtCore\reentrant
Definition qpoint.h:217
constexpr QPoint toPoint() const
Rounds the coordinates of this point to the nearest integer, and returns a QPoint object with the rou...
Definition qpoint.h:404
\inmodule QtCore\reentrant
Definition qpoint.h:25
constexpr int x() const noexcept
Returns the x coordinate of this point.
Definition qpoint.h:130
The QPolygonF class provides a list of points using floating point precision.
Definition qpolygon.h:96
The QPolygon class provides a list of points using integer precision.
Definition qpolygon.h:23
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr QRect toRect() const noexcept
Returns a QRect based on the values of this rectangle.
Definition qrect.h:859
\inmodule QtCore\reentrant
Definition qrect.h:30
The QRegion class specifies a clip region for a painter.
Definition qregion.h:27
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
QTransform & rotate(qreal a, Qt::Axis axis=Qt::ZAxis, qreal distanceToPlane=1024.0f)
static bool quadToQuad(const QPolygonF &one, const QPolygonF &two, QTransform &result)
Creates a transformation matrix, trans, that maps a four-sided polygon, one, to another four-sided po...
qreal m21() const
Returns the horizontal shearing factor.
Definition qtransform.h:211
QTransform & operator*=(const QTransform &)
This is an overloaded member function, provided for convenience. It differs from the above function o...
qreal m23() const
Returns the vertical projection factor.
Definition qtransform.h:219
static QTransform fromScale(qreal dx, qreal dy)
Creates a matrix which corresponds to a scaling of sx horizontally and sy vertically.
static bool quadToSquare(const QPolygonF &quad, QTransform &result)
Creates a transformation matrix, trans, that maps a four-sided polygon, quad, to a unit square.
QTransform adjoint() const
Returns the adjoint of this matrix.
QTransform & scale(qreal sx, qreal sy)
Scales the coordinate system by sx horizontally and sy vertically, and returns a reference to the mat...
qreal m12() const
Returns the vertical shearing factor.
Definition qtransform.h:203
bool operator==(const QTransform &) const
Returns true if this matrix is equal to the given matrix, otherwise returns false.
qreal m33() const
Returns the division factor.
Definition qtransform.h:231
QTransform operator*(const QTransform &o) const
Returns the result of multiplying this matrix by the given matrix.
qreal dx() const
Returns the horizontal translation factor.
Definition qtransform.h:235
QPoint map(const QPoint &p) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
qreal m31() const
Returns the horizontal translation factor.
Definition qtransform.h:223
qreal m32() const
Returns the vertical translation factor.
Definition qtransform.h:227
QTransform & shear(qreal sh, qreal sv)
Shears the coordinate system by sh horizontally and sv vertically, and returns a reference to the mat...
QTransform & operator=(QTransform &&other) noexcept=default
qreal m11() const
Returns the horizontal scaling factor.
Definition qtransform.h:199
static bool squareToQuad(const QPolygonF &square, QTransform &result)
Creates a transformation matrix, trans, that maps a unit square to a four-sided polygon,...
void setMatrix(qreal m11, qreal m12, qreal m13, qreal m21, qreal m22, qreal m23, qreal m31, qreal m32, qreal m33)
Sets the matrix elements to the specified values, m11, m12, m13 m21, m22, m23 m31,...
size_t qHash(const QTransform &key, size_t seed) noexcept
static QTransform fromTranslate(qreal dx, qreal dy)
Creates a matrix which corresponds to a translation of dx along the x axis and dy along the y axis.
QTransform inverted(bool *invertible=nullptr) const
Returns an inverted copy of this matrix.
bool operator!=(const QTransform &) const
Returns true if this matrix is not equal to the given matrix, otherwise returns false.
QPolygon mapToPolygon(const QRect &r) const
Creates and returns a QPolygon representation of the given rectangle, mapped into the coordinate syst...
void reset()
Resets the matrix to an identity matrix, i.e.
QTransform()
Constructs an identity matrix.
Definition qtransform.h:32
TransformationType type() const
Returns the transformation type of this matrix.
qreal determinant() const
Returns the matrix's determinant.
Definition qtransform.h:193
QTransform & translate(qreal dx, qreal dy)
Moves the coordinate system dx along the x axis and dy along the y axis, and returns a reference to t...
qreal m13() const
Returns the horizontal projection factor.
Definition qtransform.h:207
QTransform transposed() const
Returns the transpose of this matrix.
qreal m22() const
Returns the vertical scaling factor.
Definition qtransform.h:215
QRect mapRect(const QRect &) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
QTransform & rotateRadians(qreal a, Qt::Axis axis=Qt::ZAxis, qreal distanceToPlane=1024.0f)
TransformationType
\value TxNone \value TxTranslate \value TxScale \value TxRotate \value TxShear \value TxProject
Definition qtransform.h:22
qreal dy() const
Returns the vertical translation factor.
Definition qtransform.h:239
\inmodule QtCore
Definition qvariant.h:65
static auto fromValue(T &&value) noexcept(std::is_nothrow_copy_constructible_v< T > &&Private::CanUseInternalSpace< T >) -> std::enable_if_t< std::conjunction_v< std::is_copy_constructible< T >, std::is_destructible< T > >, QVariant >
Definition qvariant.h:536
QHash< int, QWidget * > hash
[35multi]
QMap< QString, QString > map
[6]
rect
[4]
Combined button and popup list for selecting options.
@ ZAxis
@ YAxis
static jboolean copy(JNIEnv *, jobject)
#define Q_FALLTHROUGH()
#define Q_NEVER_INLINE
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
bool qFuzzyIsNull(qfloat16 f) noexcept
Definition qfloat16.h:349
bool qIsNaN(qfloat16 f) noexcept
Definition qfloat16.h:284
bool qIsNull(qfloat16 f) noexcept
Definition qfloat16.h:354
qfloat16 qSqrt(qfloat16 f)
Definition qfloat16.h:289
int qRound(qfloat16 d) noexcept
Definition qfloat16.h:327
#define qWarning
Definition qlogging.h:166
auto qCos(T v)
Definition qmath.h:60
auto qSin(T v)
Definition qmath.h:54
constexpr float qDegreesToRadians(float degrees)
Definition qmath.h:260
QRect qt_mapFillRect(const QRectF &rect, const QTransform &xf)
Definition qmath_p.h:27
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
constexpr T qAbs(const T &t)
Definition qnumeric.h:328
GLboolean GLboolean GLboolean b
GLint GLint GLint GLint GLint x
[0]
const GLfloat * m
GLuint64 key
GLfloat GLfloat GLfloat w
[0]
GLboolean GLboolean GLboolean GLboolean a
[7]
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLuint GLfloat GLfloat GLfloat x1
GLdouble GLdouble right
GLfloat GLfloat f
GLenum type
GLint GLint bottom
GLboolean GLboolean g
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLuint GLenum GLenum transform
GLdouble s
[6]
Definition qopenglext.h:235
GLenum func
Definition qopenglext.h:663
GLbyte nx
GLuint res
const GLubyte * c
GLfixed GLfixed GLfixed y2
GLuint segment
GLfixed ny
GLfixed GLfixed x2
GLdouble GLdouble t
Definition qopenglext.h:243
GLsizei const GLchar *const * path
GLuint64EXT * result
[6]
GLfloat GLfloat p
[1]
GLenum GLenum GLenum GLenum GLenum scale
GLbyte ty
GLboolean invert
Definition qopenglext.h:226
QPainterPath qt_regionToPath(const QRegion &region)
Definition qregion.cpp:1007
static qreal dot(const QPointF &a, const QPointF &b)
static Q_CONSTINIT QBasicAtomicInteger< unsigned > seed
Definition qrandom.cpp:196
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
static const struct TessellationModeTab quad[]
static QLatin1StringView typeStr(QShaderDescription::VariableType t)
#define Q_NEAR_CLIP
#define MAP(x, y, nx, ny)
static QHomogeneousCoordinate mapHomogeneous(const QTransform &transform, const QPointF &p)
Q_GUI_EXPORT bool qt_scaleForTransform(const QTransform &transform, qreal *scale)
static QPainterPath mapProjective(const QTransform &transform, const QPainterPath &path)
static bool lineTo_clipped(QPainterPath &path, const QTransform &transform, const QPointF &a, const QPointF &b, bool needsMoveTo, bool needsLineTo=true)
QT_BEGIN_NAMESPACE static Q_NEVER_INLINE void nanWarning(const char *func)
static bool cubicTo_clipped(QPainterPath &path, const QTransform &transform, const QPointF &a, const QPointF &b, const QPointF &c, const QPointF &d, bool needsMoveTo)
QPainterPath qt_regionToPath(const QRegion &region)
Definition qregion.cpp:1007
QDataStream & operator>>(QDataStream &s, QTransform &t)
QDataStream & operator<<(QDataStream &s, const QTransform &m)
double qreal
Definition qtypes.h:187
const QPointF toPoint() const
QHomogeneousCoordinate(qreal x_, qreal y_, qreal w_)