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 test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
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 General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29
30#include <QtTest/QtTest>
31#include <qpainterpath.h>
32#include <qpolygon.h>
33#include <qtransform.h>
34#include <qdebug.h>
35
36class tst_QTransform : public QObject
37{
38 Q_OBJECT
39
40private slots:
41 void mapRect_data();
42 void mapToPolygon_data();
43 void mapRect();
44 void assignments();
45 void mapToPolygon();
46 void qhash();
47 void translate();
48 void scale();
49 void matrix();
50 void testOffset();
51 void types();
52 void types2_data();
53 void types2();
54 void scalarOps();
55 void transform();
56 void mapEmptyPath();
57 void boundingRect();
58 void controlPointRect();
59 void inverted_data();
60 void inverted();
61 void projectivePathMapping();
62 void mapInt();
63 void mapPathWithPoint();
64
65private:
66 void mapping_data();
67};
68
69Q_DECLARE_METATYPE(QTransform)
70Q_DECLARE_METATYPE(QTransform::TransformationType)
71
72void tst_QTransform::mapRect_data()
73{
74 mapping_data();
75
76 // rotations that are not multiples of 90 degrees. mapRect returns the bounding rect here.
77 qreal deg = -45;
78 QTest::newRow( dataTag: "rot 45 a" )
79 << QTransform().rotate(a: deg)
80 << QRect( 0, 0, 10, 10 )
81 << QPolygon( QRect( 0, -7, 14, 14 ) );
82 QTest::newRow( dataTag: "rot 45 b" )
83 << QTransform().rotate(a: deg)
84 << QRect( 10, 20, 30, 40 )
85 << QPolygon( QRect( 21, -14, 50, 49 ) );
86 QTest::newRow( dataTag: "rot 45 c" )
87 << QTransform().rotate(a: deg).scale(sx: 10, sy: 10)
88 << QRect( 0, 0, 10, 10 )
89 << QPolygon( QRect( 0, -71, 141, 142 ) );
90 QTest::newRow( dataTag: "rot 45 d" )
91 << QTransform().rotate(a: deg).scale(sx: 10, sy: 10)
92 << QRect( 10, 20, 30, 40 )
93 << QPolygon( QRect( 212, -141, 495, 495 ) );
94
95 deg = 45;
96 QTest::newRow( dataTag: "rot -45 a" )
97 << QTransform().rotate(a: deg)
98 << QRect( 0, 0, 10, 10 )
99 << QPolygon( QRect( -7, 0, 14, 14 ) );
100 QTest::newRow( dataTag: "rot -45 b" )
101 << QTransform().rotate(a: deg)
102 << QRect( 10, 20, 30, 40 )
103 << QPolygon( QRect( -35, 21, 49, 50 ) );
104 QTest::newRow( dataTag: "rot -45 c" )
105 << QTransform().rotate(a: deg).scale(sx: 10, sy: 10)
106 << QRect( 0, 0, 10, 10 )
107 << QPolygon( QRect( -71, 0, 142, 141 ) );
108 QTest::newRow( dataTag: "rot -45 d" )
109 << QTransform().rotate(a: deg).scale(sx: 10, sy: 10)
110 << QRect( 10, 20, 30, 40 )
111 << QPolygon( QRect( -354, 212, 495, 495 ) );
112}
113
114void tst_QTransform::mapToPolygon_data()
115{
116 mapping_data();
117}
118
119void tst_QTransform::mapping_data()
120{
121 //create the testtable instance and define the elements
122 QTest::addColumn<QTransform>(name: "matrix");
123 QTest::addColumn<QRect>(name: "src");
124 QTest::addColumn<QPolygon>(name: "res");
125
126 //next we fill it with data
127
128 // identity
129 QTest::newRow( dataTag: "identity" )
130 << QTransform()
131 << QRect( 10, 20, 30, 40 )
132 << QPolygon( QRect( 10, 20, 30, 40 ) );
133 // scaling
134 QTest::newRow( dataTag: "scale 0" )
135 << QTransform().scale(sx: 2, sy: 2)
136 << QRect( 10, 20, 30, 40 )
137 << QPolygon( QRect( 20, 40, 60, 80 ) );
138 QTest::newRow( dataTag: "scale 1" )
139 << QTransform().scale(sx: 10, sy: 10)
140 << QRect( 10, 20, 30, 40 )
141 << QPolygon( QRect( 100, 200, 300, 400 ) );
142 // mirroring
143 QTest::newRow( dataTag: "mirror 0" )
144 << QTransform().scale(sx: -1, sy: 1)
145 << QRect( 10, 20, 30, 40 )
146 << QPolygon( QRect( -40, 20, 30, 40 ) );
147 QTest::newRow( dataTag: "mirror 1" )
148 << QTransform().scale(sx: 1, sy: -1)
149 << QRect( 10, 20, 30, 40 )
150 << QPolygon( QRect( 10, -60, 30, 40 ) );
151 QTest::newRow( dataTag: "mirror 2" )
152 << QTransform().scale(sx: -1, sy: -1)
153 << QRect( 10, 20, 30, 40 )
154 << QPolygon( QRect( -40, -60, 30, 40 ) );
155 QTest::newRow( dataTag: "mirror 3" )
156 << QTransform().scale(sx: -2, sy: -2)
157 << QRect( 10, 20, 30, 40 )
158 << QPolygon( QRect( -80, -120, 60, 80 ) );
159 QTest::newRow( dataTag: "mirror 4" )
160 << QTransform().scale(sx: -10, sy: -10)
161 << QRect( 10, 20, 30, 40 )
162 << QPolygon( QRect( -400, -600, 300, 400 ) );
163 QTest::newRow( dataTag: "mirror 5" )
164 << QTransform().scale(sx: -1, sy: 1)
165 << QRect( 0, 0, 30, 40 )
166 << QPolygon( QRect( -30, 0, 30, 40 ) );
167 QTest::newRow( dataTag: "mirror 6" )
168 << QTransform().scale(sx: 1, sy: -1)
169 << QRect( 0, 0, 30, 40 )
170 << QPolygon( QRect( 0, -40, 30, 40 ) );
171 QTest::newRow( dataTag: "mirror 7" )
172 << QTransform().scale(sx: -1, sy: -1)
173 << QRect( 0, 0, 30, 40 )
174 << QPolygon( QRect( -30, -40, 30, 40 ) );
175 QTest::newRow( dataTag: "mirror 8" )
176 << QTransform().scale(sx: -2, sy: -2)
177 << QRect( 0, 0, 30, 40 )
178 << QPolygon( QRect( -60, -80, 60, 80 ) );
179 QTest::newRow( dataTag: "mirror 9" )
180 << QTransform().scale(sx: -10, sy: -10) << QRect( 0, 0, 30, 40 )
181 << QPolygon( QRect( -300, -400, 300, 400 ) );
182
183 // rotations
184 float deg = 0.;
185 QTest::newRow( dataTag: "rot 0 a" )
186 << QTransform().rotate(a: deg)
187 << QRect( 0, 0, 30, 40 )
188 << QPolygon ( QRect( 0, 0, 30, 40 ) );
189 deg = 0.00001f;
190 QTest::newRow( dataTag: "rot 0 b" )
191 << QTransform().rotate(a: deg)
192 << QRect( 0, 0, 30, 40 )
193 << QPolygon ( QRect( 0, 0, 30, 40 ) );
194 deg = 0.;
195 QTest::newRow( dataTag: "rot 0 c" )
196 << QTransform().rotate(a: deg)
197 << QRect( 10, 20, 30, 40 )
198 << QPolygon ( QRect( 10, 20, 30, 40 ) );
199 deg = 0.00001f;
200 QTest::newRow( dataTag: "rot 0 d" )
201 << QTransform().rotate(a: deg)
202 << QRect( 10, 20, 30, 40 )
203 << QPolygon ( QRect( 10, 20, 30, 40 ) );
204
205 // rotations
206 deg = -90.f;
207 QTest::newRow( dataTag: "rotscale 90 a" )
208 << QTransform().rotate(a: deg).scale(sx: 10, sy: 10)
209 << QRect( 0, 0, 30, 40 )
210 << QPolygon( QRect( 0, -300, 400, 300 ) );
211 deg = -90.00001f;
212 QTest::newRow( dataTag: "rotscale 90 b" )
213 << QTransform().rotate(a: deg).scale(sx: 10, sy: 10)
214 << QRect( 0, 0, 30, 40 )
215 << QPolygon( QRect( 0, -300, 400, 300 ) );
216 deg = -90.f;
217 QTest::newRow( dataTag: "rotscale 90 c" )
218 << QTransform().rotate(a: deg).scale(sx: 10, sy: 10)
219 << QRect( 10, 20, 30, 40 )
220 << QPolygon( QRect( 200, -400, 400, 300 ) );
221 deg = -90.00001f;
222 QTest::newRow( dataTag: "rotscale 90 d" )
223 << QTransform().rotate(a: deg).scale(sx: 10, sy: 10)
224 << QRect( 10, 20, 30, 40 )
225 << QPolygon( QRect( 200, -400, 400, 300 ) );
226
227 deg = 180.f;
228 QTest::newRow( dataTag: "rotscale 180 a" )
229 << QTransform().rotate(a: deg).scale(sx: 10, sy: 10)
230 << QRect( 0, 0, 30, 40 )
231 << QPolygon( QRect( -300, -400, 300, 400 ) );
232 deg = 180.000001f;
233 QTest::newRow( dataTag: "rotscale 180 b" )
234 << QTransform().rotate(a: deg).scale(sx: 10, sy: 10)
235 << QRect( 0, 0, 30, 40 )
236 << QPolygon( QRect( -300, -400, 300, 400 ) );
237 deg = 180.f;
238 QTest::newRow( dataTag: "rotscale 180 c" )
239 << QTransform().rotate(a: deg).scale(sx: 10, sy: 10)
240 << QRect( 10, 20, 30, 40 )
241 << QPolygon( QRect( -400, -600, 300, 400 ) );
242 deg = 180.000001f;
243 QTest::newRow( dataTag: "rotscale 180 d" )
244 << QTransform().rotate(a: deg).scale(sx: 10, sy: 10)
245 << QRect( 10, 20, 30, 40 )
246 << QPolygon( QRect( -400, -600, 300, 400 ) );
247
248 deg = -270.f;
249 QTest::newRow( dataTag: "rotscale 270 a" )
250 << QTransform().rotate(a: deg).scale(sx: 10, sy: 10)
251 << QRect( 0, 0, 30, 40 )
252 << QPolygon( QRect( -400, 0, 400, 300 ) );
253 deg = -270.0000001f;
254 QTest::newRow( dataTag: "rotscale 270 b" )
255 << QTransform().rotate(a: deg).scale(sx: 10, sy: 10)
256 << QRect( 0, 0, 30, 40 )
257 << QPolygon( QRect( -400, 0, 400, 300 ) );
258 deg = -270.f;
259 QTest::newRow( dataTag: "rotscale 270 c" )
260 << QTransform().rotate(a: deg).scale(sx: 10, sy: 10)
261 << QRect( 10, 20, 30, 40 )
262 << QPolygon( QRect( -600, 100, 400, 300 ) );
263 deg = -270.000001f;
264 QTest::newRow( dataTag: "rotscale 270 d" )
265 << QTransform().rotate(a: deg).scale(sx: 10, sy: 10)
266 << QRect( 10, 20, 30, 40 )
267 << QPolygon( QRect( -600, 100, 400, 300 ) );
268}
269
270void tst_QTransform::mapRect()
271{
272 QFETCH( QTransform, matrix );
273 QFETCH( QRect, src );
274 QFETCH( QPolygon, res );
275 QRect mapped = matrix.mapRect(src);
276 QCOMPARE( mapped, res.boundingRect().adjusted(0, 0, -1, -1) );
277
278 QRectF r = matrix.mapRect(QRectF(src));
279 QRect ir(r.topLeft().toPoint(), r.bottomRight().toPoint() - QPoint(1, 1));
280 QCOMPARE( mapped, ir );
281}
282
283void tst_QTransform::assignments()
284{
285 QTransform m;
286 m.scale(sx: 2, sy: 3);
287 m.rotate(a: 45);
288 m.shear(sh: 4, sv: 5);
289
290 QTransform c1(m);
291
292 QCOMPARE(m.m11(), c1.m11());
293 QCOMPARE(m.m12(), c1.m12());
294 QCOMPARE(m.m21(), c1.m21());
295 QCOMPARE(m.m22(), c1.m22());
296 QCOMPARE(m.dx(), c1.dx());
297 QCOMPARE(m.dy(), c1.dy());
298
299 QTransform c2 = m;
300 QCOMPARE(m.m11(), c2.m11());
301 QCOMPARE(m.m12(), c2.m12());
302 QCOMPARE(m.m21(), c2.m21());
303 QCOMPARE(m.m22(), c2.m22());
304 QCOMPARE(m.dx(), c2.dx());
305 QCOMPARE(m.dy(), c2.dy());
306}
307
308
309void tst_QTransform::mapToPolygon()
310{
311 QFETCH( QTransform, matrix );
312 QFETCH( QRect, src );
313 QFETCH( QPolygon, res );
314
315 QPolygon poly = matrix.mapToPolygon(r: src);
316
317 // don't care about starting point
318 bool equal = false;
319 for (int i = 0; i < poly.size(); ++i) {
320 QPolygon rot;
321 for (int j = i; j < poly.size(); ++j)
322 rot << poly[j];
323 for (int j = 0; j < i; ++j)
324 rot << poly[j];
325 if (rot == res)
326 equal = true;
327 }
328
329 QVERIFY(equal);
330}
331
332void tst_QTransform::qhash()
333{
334 QTransform t1;
335 t1.shear(sh: 3.0, sv: 2.0);
336 t1.rotate(a: 44);
337
338 QTransform t2 = t1;
339
340 // not really much to test here, so just the bare minimum:
341 QCOMPARE(qHash(t1), qHash(t2));
342}
343
344
345void tst_QTransform::translate()
346{
347 QTransform m( 1, 2, 3, 4, 5, 6 );
348 QTransform res2( m );
349 QTransform res( 1, 2, 3, 4, 75, 106 );
350 m.translate( dx: 10, dy: 20 );
351 QVERIFY( m == res );
352 m.translate( dx: -10, dy: -20 );
353 QVERIFY( m == res2 );
354 QVERIFY( QTransform::fromTranslate( 0, 0 ).type() == QTransform::TxNone );
355 QVERIFY( QTransform::fromTranslate( 10, 0 ).type() == QTransform::TxTranslate );
356 QVERIFY( QTransform::fromTranslate( -1, 5 ) == QTransform().translate( -1, 5 ));
357 QVERIFY( QTransform::fromTranslate( 0, 0 ) == QTransform());
358}
359
360void tst_QTransform::scale()
361{
362 QTransform m( 1, 2, 3, 4, 5, 6 );
363 QTransform res2( m );
364 QTransform res( 10, 20, 60, 80, 5, 6 );
365 m.scale( sx: 10, sy: 20 );
366 QVERIFY( m == res );
367 m.scale( sx: 1./10., sy: 1./20. );
368 QVERIFY( m == res2 );
369 QVERIFY( QTransform::fromScale( 1, 1 ).type() == QTransform::TxNone );
370 QVERIFY( QTransform::fromScale( 2, 4 ).type() == QTransform::TxScale );
371 QVERIFY( QTransform::fromScale( 2, 4 ) == QTransform().scale( 2, 4 ));
372 QVERIFY( QTransform::fromScale( 1, 1 ) == QTransform());
373}
374
375#if QT_DEPRECATED_SINCE(5, 15)
376QT_WARNING_PUSH
377QT_WARNING_DISABLE_DEPRECATED
378void tst_QTransform::matrix()
379{
380 QMatrix mat1;
381 mat1.scale(sx: 0.3, sy: 0.7);
382 mat1.translate(dx: 53.3, dy: 94.4);
383 mat1.rotate(a: 45);
384
385 QMatrix mat2;
386 mat2.rotate(a: 33);
387 mat2.scale(sx: 0.6, sy: 0.6);
388 mat2.translate(dx: 13.333, dy: 7.777);
389
390 QTransform tran1(mat1);
391 QTransform tran2(mat2);
392 QTransform dummy;
393 dummy.setMatrix(m11: mat1.m11(), m12: mat1.m12(), m13: 0,
394 m21: mat1.m21(), m22: mat1.m22(), m23: 0,
395 m31: mat1.dx(), m32: mat1.dy(), m33: 1);
396
397 QCOMPARE(tran1, dummy);
398 QCOMPARE(tran1.inverted(), dummy.inverted());
399 QCOMPARE(tran1.inverted(), QTransform(mat1.inverted()));
400 QCOMPARE(tran2.inverted(), QTransform(mat2.inverted()));
401
402 QMatrix mat3 = mat1 * mat2;
403 QTransform tran3 = tran1 * tran2;
404 QCOMPARE(QTransform(mat3), tran3);
405
406 /* QMatrix::operator==() doesn't use qFuzzyCompare(), which
407 * on win32-g++ results in a failure. So we work around it by
408 * calling QTranform::operator==(), which performs a fuzzy compare. */
409 QCOMPARE(QTransform(mat3), QTransform(tran3.toAffine()));
410
411 QTransform tranInv = tran1.inverted();
412 QMatrix matInv = mat1.inverted();
413
414 QRect rect(43, 70, 200, 200);
415 QPoint pt(43, 66);
416 QCOMPARE(tranInv.mapRect(rect), matInv.mapRect(rect));
417 QCOMPARE(tranInv.map(pt), matInv.map(pt));
418
419 QPainterPath path;
420 path.moveTo(x: 55, y: 60);
421 path.lineTo(x: 110, y: 110);
422 path.quadTo(ctrlPtx: 220, ctrlPty: 50, endPtx: 10, endPty: 20);
423 path.closeSubpath();
424 QCOMPARE(tranInv.map(path), matInv.map(path));
425}
426
427void tst_QTransform::testOffset()
428{
429 QTransform trans;
430 const QMatrix &aff = trans.toAffine();
431 QCOMPARE((void*)(&aff), (void*)(&trans));
432}
433QT_WARNING_POP
434#endif
435
436void tst_QTransform::types()
437{
438 QTransform m1;
439 QCOMPARE(m1.type(), QTransform::TxNone);
440
441 m1.translate(dx: 1.0f, dy: 0.0f);
442 QCOMPARE(m1.type(), QTransform::TxTranslate);
443 QCOMPARE(m1.inverted().type(), QTransform::TxTranslate);
444
445 m1.scale(sx: 1.0f, sy: 2.0f);
446 QCOMPARE(m1.type(), QTransform::TxScale);
447 QCOMPARE(m1.inverted().type(), QTransform::TxScale);
448
449 m1.rotate(a: 45.0f);
450 // Rotation after non-uniform scaling -> shearing. Uniform scale + rotate tested below.
451 QCOMPARE(m1.type(), QTransform::TxShear);
452 QCOMPARE(m1.inverted().type(), QTransform::TxShear);
453
454 m1.shear(sh: 0.5f, sv: 0.25f);
455 QCOMPARE(m1.type(), QTransform::TxShear);
456 QCOMPARE(m1.inverted().type(), QTransform::TxShear);
457
458 m1.rotate(a: 45.0f, axis: Qt::XAxis);
459 QCOMPARE(m1.type(), QTransform::TxProject);
460 m1.shear(sh: 0.5f, sv: 0.25f);
461 QCOMPARE(m1.type(), QTransform::TxProject);
462 m1.rotate(a: 45.0f);
463 QCOMPARE(m1.type(), QTransform::TxProject);
464 m1.scale(sx: 1.0f, sy: 2.0f);
465 QCOMPARE(m1.type(), QTransform::TxProject);
466 m1.translate(dx: 1.0f, dy: 0.0f);
467 QCOMPARE(m1.type(), QTransform::TxProject);
468
469 QTransform m2(1.0f, 0.0f, 0.0f,
470 0.0f, 1.0f, 0.0f,
471 -1.0f, -1.0f, 1.0f);
472
473 QCOMPARE(m2.type(), QTransform::TxTranslate);
474 QCOMPARE((m1 * m2).type(), QTransform::TxProject);
475
476 m1 *= QTransform();
477 QCOMPARE(m1.type(), QTransform::TxProject);
478
479 m1 *= QTransform(1.0f, 0.0f, 0.0f,
480 0.0f, 1.0f, 0.0f,
481 1.0f, 0.0f, 1.0f);
482 QCOMPARE(m1.type(), QTransform::TxProject);
483
484 m2.reset();
485 QCOMPARE(m2.type(), QTransform::TxNone);
486
487 m2.setMatrix(m11: 1.0f, m12: 0.0f, m13: 0.0f,
488 m21: 0.0f, m22: 1.0f, m23: 0.0f,
489 m31: 0.0f, m32: 0.0f, m33: 1.0f);
490 QCOMPARE(m2.type(), QTransform::TxNone);
491
492 m2 *= QTransform();
493 QCOMPARE(m2.type(), QTransform::TxNone);
494
495 m2.setMatrix(m11: 2.0f, m12: 0.0f, m13: 0.0f,
496 m21: 0.0f, m22: 1.0f, m23: 0.0f,
497 m31: 0.0f, m32: 0.0f, m33: 1.0f);
498 QCOMPARE(m2.type(), QTransform::TxScale);
499 m2 *= QTransform();
500 QCOMPARE(m2.type(), QTransform::TxScale);
501
502 m2.setMatrix(m11: 0.0f, m12: 1.0f, m13: 0.0f,
503 m21: 1.0f, m22: 0.0f, m23: 0.0f,
504 m31: 0.0f, m32: 1.0f, m33: 1.0f);
505 QCOMPARE(m2.type(), QTransform::TxRotate);
506 m2 *= QTransform();
507 QCOMPARE(m2.type(), QTransform::TxRotate);
508
509 m2.setMatrix(m11: 1.0f, m12: 0.0f, m13: 0.5f,
510 m21: 0.0f, m22: 1.0f, m23: 0.0f,
511 m31: 0.0f, m32: 0.0f, m33: 1.0f);
512 QCOMPARE(m2.type(), QTransform::TxProject);
513 m2 *= QTransform();
514 QCOMPARE(m2.type(), QTransform::TxProject);
515
516 m2.setMatrix(m11: 1.0f, m12: 1.0f, m13: 0.0f,
517 m21: 1.0f, m22: 0.0f, m23: 0.0f,
518 m31: 0.0f, m32: 1.0f, m33: 1.0f);
519 QCOMPARE(m2.type(), QTransform::TxShear);
520
521 m2 *= m2.inverted();
522 QCOMPARE(m2.type(), QTransform::TxNone);
523
524 m2.translate(dx: 5.0f, dy: 5.0f);
525 m2.rotate(a: 45.0f);
526 m2.rotate(a: -45.0f);
527 QCOMPARE(m2.type(), QTransform::TxTranslate);
528
529 m2.scale(sx: 2.0f, sy: 3.0f);
530 m2.shear(sh: 1.0f, sv: 0.0f);
531 m2.shear(sh: -1.0f, sv: 0.0f);
532 QCOMPARE(m2.type(), QTransform::TxScale);
533
534 m2 *= QTransform(1.0f, 1.0f, 0.0f,
535 0.0f, 1.0f, 0.0f,
536 0.0f, 0.0f, 1.0f);
537 QCOMPARE(m2.type(), QTransform::TxShear);
538
539 m2 *= QTransform(1.0f, 0.0f, 0.0f,
540 0.0f, 1.0f, 0.0f,
541 1.0f, 0.0f, 1.0f);
542 QCOMPARE(m2.type(), QTransform::TxShear);
543
544 QTransform m3(1.8f, 0.0f, 0.0f,
545 0.0f, 1.8f, 0.0f,
546 0.0f, 0.0f, 1.0f);
547
548 QCOMPARE(m3.type(), QTransform::TxScale);
549 m3.translate(dx: 5.0f, dy: 5.0f);
550 QCOMPARE(m3.type(), QTransform::TxScale);
551 QCOMPARE(m3.inverted().type(), QTransform::TxScale);
552
553 m3.setMatrix(m11: 1.0f, m12: 0.0f, m13: 0.0f,
554 m21: 0.0f, m22: 1.0f, m23: 0.0f,
555 m31: 0.0f, m32: 0.0f, m33: 2.0f);
556 QCOMPARE(m3.type(), QTransform::TxProject);
557
558 m3.setMatrix(m11: 0.0f, m12: 2.0f, m13: 0.0f,
559 m21: 1.0f, m22: 0.0f, m23: 0.0f,
560 m31: 0.0f, m32: 0.0f, m33: 2.0f);
561 QCOMPARE(m3.type(), QTransform::TxProject);
562
563 QTransform m4;
564 m4.scale(sx: 5, sy: 5);
565 m4.translate(dx: 4, dy: 2);
566 m4.rotate(a: 45);
567
568 QCOMPARE(m4.type(), QTransform::TxRotate);
569
570 QTransform m5;
571 m5.scale(sx: 5, sy: 5);
572 m5 = m5.adjoint() / m5.determinant();
573 QCOMPARE(m5.type(), QTransform::TxScale);
574}
575
576void tst_QTransform::types2_data()
577{
578 QTest::addColumn<QTransform>(name: "t1");
579 QTest::addColumn<QTransform::TransformationType>(name: "type");
580
581 QTest::newRow( dataTag: "identity" ) << QTransform() << QTransform::TxNone;
582 QTest::newRow( dataTag: "translate" ) << QTransform().translate(dx: 10, dy: -0.1) << QTransform::TxTranslate;
583 QTest::newRow( dataTag: "scale" ) << QTransform().scale(sx: 10, sy: -0.1) << QTransform::TxScale;
584 QTest::newRow( dataTag: "rotate" ) << QTransform().rotate(a: 10) << QTransform::TxRotate;
585 QTest::newRow( dataTag: "shear" ) << QTransform().shear(sh: 10, sv: -0.1) << QTransform::TxShear;
586 QTest::newRow( dataTag: "project" ) << QTransform().rotate(a: 10, axis: Qt::XAxis) << QTransform::TxProject;
587 QTest::newRow( dataTag: "combined" ) << QTransform().translate(dx: 10, dy: -0.1).scale(sx: 10, sy: -0.1).rotate(a: 10, axis: Qt::YAxis) << QTransform::TxProject;
588}
589
590void tst_QTransform::types2()
591{
592#define CHECKTXTYPE(func) { QTransform t2(func); \
593 QTransform t3(t2.m11(), t2.m12(), t2.m13(), t2.m21(), t2.m22(), t2.m23(), t2.m31(), t2.m32(), t2.m33()); \
594 QVERIFY2(t3.type() == t2.type(), #func); \
595 }
596
597 QFETCH( QTransform, t1 );
598 QFETCH( QTransform::TransformationType, type );
599
600 Q_ASSERT(t1.type() == type);
601
602 CHECKTXTYPE(t1.adjoint());
603 CHECKTXTYPE(t1.inverted());
604 CHECKTXTYPE(t1.transposed());
605
606#undef CHECKTXTYPE
607}
608
609void tst_QTransform::scalarOps()
610{
611 QTransform t;
612 QCOMPARE(t.m11(), 1.);
613 QCOMPARE(t.m33(), 1.);
614 QCOMPARE(t.m21(), 0.);
615
616 t = QTransform() + 3;
617 QCOMPARE(t.m11(), 4.);
618 QCOMPARE(t.m33(), 4.);
619 QCOMPARE(t.m21(), 3.);
620
621 t = t - 3;
622 QCOMPARE(t.m11(), 1.);
623 QCOMPARE(t.m33(), 1.);
624 QCOMPARE(t.m21(), 0.);
625 QCOMPARE(t.isIdentity(), true);
626
627 t += 3;
628 t = t * 2;
629 QCOMPARE(t.m11(), 8.);
630 QCOMPARE(t.m33(), 8.);
631 QCOMPARE(t.m21(), 6.);
632}
633
634void tst_QTransform::transform()
635{
636 QTransform t;
637 t.rotate(a: 30, axis: Qt::YAxis);
638 t.translate(dx: 15, dy: 10);
639 t.scale(sx: 2, sy: 2);
640 t.rotate(a: 30);
641 t.shear(sh: 0.5, sv: 0.5);
642
643 QTransform a, b, c, d, e;
644 a.rotate(a: 30, axis: Qt::YAxis);
645 b.translate(dx: 15, dy: 10);
646 c.scale(sx: 2, sy: 2);
647 d.rotate(a: 30);
648 e.shear(sh: 0.5, sv: 0.5);
649
650 QVERIFY(qFuzzyCompare(t, e * d * c * b * a));
651}
652
653void tst_QTransform::mapEmptyPath()
654{
655 QPainterPath path;
656 path.moveTo(x: 10, y: 10);
657 path.lineTo(x: 10, y: 10);
658 QCOMPARE(QTransform().map(path), path);
659}
660
661void tst_QTransform::boundingRect()
662{
663 QPainterPath path;
664 path.moveTo(x: 10, y: 10);
665 path.lineTo(x: 10, y: 10);
666 QCOMPARE(path.boundingRect(), QRectF(10, 10, 0, 0));
667}
668
669void tst_QTransform::controlPointRect()
670{
671 QPainterPath path;
672 path.moveTo(x: 10, y: 10);
673 path.lineTo(x: 10, y: 10);
674 QCOMPARE(path.controlPointRect(), QRectF(10, 10, 0, 0));
675}
676
677void tst_QTransform::inverted_data()
678{
679 QTest::addColumn<QTransform>(name: "matrix");
680
681 QTest::newRow(dataTag: "identity")
682 << QTransform();
683
684 QTest::newRow(dataTag: "TxTranslate")
685 << QTransform().translate(dx: 200, dy: 10);
686
687 QTest::newRow(dataTag: "TxScale")
688 << QTransform().scale(sx: 5, sy: 2);
689
690 QTest::newRow(dataTag: "TxTranslate TxScale")
691 << QTransform().translate(dx: 100, dy: -10).scale(sx: 40, sy: 2);
692
693 QTest::newRow(dataTag: "TxScale TxTranslate")
694 << QTransform().scale(sx: 40, sy: 2).translate(dx: 100, dy: -10);
695
696 QTest::newRow(dataTag: "TxRotate")
697 << QTransform().rotate(a: 40, axis: Qt::ZAxis);
698
699 QTest::newRow(dataTag: "TxRotate TxScale")
700 << QTransform().rotate(a: 60, axis: Qt::ZAxis).scale(sx: 2, sy: 0.25);
701
702 QTest::newRow(dataTag: "TxScale TxRotate")
703 << QTransform().scale(sx: 2, sy: 0.25).rotate(a: 30, axis: Qt::ZAxis);
704
705 QTest::newRow(dataTag: "TxRotate TxScale TxTranslate")
706 << QTransform().rotate(a: 60, axis: Qt::ZAxis).scale(sx: 2, sy: 0.25).translate(dx: 200, dy: -3000);
707
708 QTest::newRow(dataTag: "TxRotate TxTranslate TxScale")
709 << QTransform().rotate(a: 60, axis: Qt::ZAxis).translate(dx: 200, dy: -3000).scale(sx: 19, sy: 77);
710
711 QTest::newRow(dataTag: "TxShear")
712 << QTransform().shear(sh: 10, sv: 10);
713
714 QTest::newRow(dataTag: "TxShear TxRotate")
715 << QTransform().shear(sh: 10, sv: 10).rotate(a: 45, axis: Qt::ZAxis);
716
717 QTest::newRow(dataTag: "TxShear TxRotate TxScale")
718 << QTransform().shear(sh: 10, sv: 10).rotate(a: 45, axis: Qt::ZAxis).scale(sx: 19, sy: 81);
719
720 QTest::newRow(dataTag: "TxTranslate TxShear TxRotate TxScale")
721 << QTransform().translate(dx: 150, dy: -1).shear(sh: 10, sv: 10).rotate(a: 45, axis: Qt::ZAxis).scale(sx: 19, sy: 81);
722
723 const qreal s = 500000;
724
725 QTransform big;
726 big.scale(sx: s, sy: s);
727
728 QTest::newRow(dataTag: "big") << big;
729
730 QTransform smallTransform;
731 smallTransform.scale(sx: 1/s, sy: 1/s);
732
733 QTest::newRow(dataTag: "small") << smallTransform;
734}
735
736void tst_QTransform::inverted()
737{
738 if (sizeof(qreal) != sizeof(double))
739 QSKIP("precision error if qreal is not double");
740
741 QFETCH(QTransform, matrix);
742
743 const QTransform inverted = matrix.inverted();
744
745 QCOMPARE(matrix.isIdentity(), inverted.isIdentity());
746 QCOMPARE(matrix.type(), inverted.type());
747
748 QVERIFY((matrix * inverted).isIdentity());
749 QVERIFY((inverted * matrix).isIdentity());
750}
751
752void tst_QTransform::projectivePathMapping()
753{
754 QPainterPath path;
755 path.addRect(x: -50, y: -50, w: 100, h: 100);
756
757 const QRectF view(0, 0, 1024, 1024);
758
759 QVERIFY(view.intersects(path.boundingRect()));
760
761 for (int i = 0; i < 85; i += 5) {
762 QTransform transform;
763 transform.translate(dx: 512, dy: 512);
764 transform.rotate(a: i, axis: Qt::YAxis);
765
766 const QPainterPath mapped = transform.map(p: path);
767
768 QVERIFY(view.intersects(mapped.boundingRect()));
769 QVERIFY(transform.inverted().mapRect(view).intersects(path.boundingRect()));
770 }
771}
772
773void tst_QTransform::mapInt()
774{
775 int x = 0;
776 int y = 0;
777
778 QTransform::fromTranslate(dx: 10, dy: 10).map(x, y, tx: &x, ty: &y);
779
780 QCOMPARE(x, 10);
781 QCOMPARE(y, 10);
782}
783
784void tst_QTransform::mapPathWithPoint()
785{
786 QPainterPath p(QPointF(10, 10));
787 p = QTransform::fromTranslate(dx: 10, dy: 10).map(p);
788 QCOMPARE(p.currentPosition(), QPointF(20, 20));
789}
790
791QTEST_APPLESS_MAIN(tst_QTransform)
792
793
794#include "tst_qtransform.moc"
795

source code of qtbase/tests/auto/gui/painting/qtransform/tst_qtransform.cpp