| 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 <qmatrix.h> | 
| 32 | #include <qmath.h> | 
| 33 | #include <qpolygon.h> | 
| 34 |  | 
| 35 | #if QT_DEPRECATED_SINCE(5, 15) | 
| 36 | QT_WARNING_PUSH | 
| 37 | QT_WARNING_DISABLE_DEPRECATED | 
| 38 |  | 
| 39 | class tst_QWMatrix : public QObject | 
| 40 | { | 
| 41 |     Q_OBJECT | 
| 42 |  | 
| 43 | private slots: | 
| 44 |     void mapRect_data(); | 
| 45 |     void mapToPolygon_data(); | 
| 46 |     void mapRect(); | 
| 47 |     void operator_star_qwmatrix(); | 
| 48 |     void assignments(); | 
| 49 |     void mapToPolygon(); | 
| 50 |     void translate(); | 
| 51 |     void scale(); | 
| 52 |     void mapPolygon(); | 
| 53 |  | 
| 54 | private: | 
| 55 |     void mapping_data(); | 
| 56 | }; | 
| 57 |  | 
| 58 | void tst_QWMatrix::mapRect_data() | 
| 59 | { | 
| 60 |     mapping_data(); | 
| 61 | } | 
| 62 |  | 
| 63 | void tst_QWMatrix::mapToPolygon_data() | 
| 64 | { | 
| 65 |     mapping_data(); | 
| 66 | } | 
| 67 |  | 
| 68 | void tst_QWMatrix::mapping_data() | 
| 69 | { | 
| 70 |     //create the testtable instance and define the elements | 
| 71 |     QTest::addColumn<QMatrix>(name: "matrix" ); | 
| 72 |     QTest::addColumn<QRect>(name: "src" ); | 
| 73 |     QTest::addColumn<QPolygon>(name: "res" ); | 
| 74 |  | 
| 75 |     //next we fill it with data | 
| 76 |  | 
| 77 |     // identity | 
| 78 |     QTest::newRow( dataTag: "identity"  ) << QMatrix( 1, 0, 0, 1, 0, 0 ) | 
| 79 |                                 << QRect( 10, 20, 30, 40 ) | 
| 80 |                                 << QPolygon( QRect( 10, 20, 30, 40 ) ); | 
| 81 |     // scaling | 
| 82 |     QTest::newRow( dataTag: "scale 0"  )  << QMatrix( 2, 0, 0, 2, 0, 0 ) | 
| 83 |                                 << QRect( 10, 20, 30, 40 ) | 
| 84 |                                 << QPolygon( QRect( 20, 40, 60, 80 ) ); | 
| 85 |     QTest::newRow( dataTag: "scale 1"  )  << QMatrix( 10, 0, 0, 10, 0, 0 ) | 
| 86 |                                 << QRect( 10, 20, 30, 40 ) | 
| 87 |                                 << QPolygon( QRect( 100, 200, 300, 400 ) ); | 
| 88 |     // mirroring | 
| 89 |     QTest::newRow( dataTag: "mirror 0"  ) << QMatrix( -1, 0, 0, 1, 0, 0 ) | 
| 90 |                                 << QRect( 10, 20, 30, 40 ) | 
| 91 |                                 << QPolygon( QRect( -40, 20, 30, 40 ) ); | 
| 92 |     QTest::newRow( dataTag: "mirror 1"  ) << QMatrix( 1, 0, 0, -1, 0, 0 ) | 
| 93 |                                 << QRect( 10, 20, 30, 40 ) | 
| 94 |                                 << QPolygon( QRect( 10, -60, 30, 40 ) ); | 
| 95 |     QTest::newRow( dataTag: "mirror 2"  ) << QMatrix( -1, 0, 0, -1, 0, 0 ) | 
| 96 |                                 << QRect( 10, 20, 30, 40 ) | 
| 97 |                                 << QPolygon( QRect( -40, -60, 30, 40 ) ); | 
| 98 |     QTest::newRow( dataTag: "mirror 3"  ) << QMatrix( -2, 0, 0, -2, 0, 0 ) | 
| 99 |                                 << QRect( 10, 20, 30, 40 ) | 
| 100 |                                 << QPolygon( QRect( -80, -120, 60, 80 ) ); | 
| 101 |     QTest::newRow( dataTag: "mirror 4"  ) << QMatrix( -10, 0, 0, -10, 0, 0 ) | 
| 102 |                                 << QRect( 10, 20, 30, 40 ) | 
| 103 |                                 << QPolygon( QRect( -400, -600, 300, 400 ) ); | 
| 104 |     QTest::newRow( dataTag: "mirror 5"  ) << QMatrix( -1, 0, 0, 1, 0, 0 ) | 
| 105 |                                 << QRect( 0, 0, 30, 40 ) | 
| 106 |                                 << QPolygon( QRect( -30, 0, 30, 40 ) ); | 
| 107 |     QTest::newRow( dataTag: "mirror 6"  ) << QMatrix( 1, 0, 0, -1, 0, 0 ) | 
| 108 |                                 << QRect( 0, 0, 30, 40 ) | 
| 109 |                                 << QPolygon( QRect( 0, -40, 30, 40 ) ); | 
| 110 |     QTest::newRow( dataTag: "mirror 7"  ) << QMatrix( -1, 0, 0, -1, 0, 0 ) | 
| 111 |                                 << QRect( 0, 0, 30, 40 ) | 
| 112 |                                 << QPolygon( QRect( -30, -40, 30, 40 ) ); | 
| 113 |     QTest::newRow( dataTag: "mirror 8"  ) << QMatrix( -2, 0, 0, -2, 0, 0 ) | 
| 114 |                                 << QRect( 0, 0, 30, 40 ) | 
| 115 |                                 << QPolygon( QRect( -60, -80, 60, 80 ) ); | 
| 116 |     QTest::newRow( dataTag: "mirror 9"  ) << QMatrix( -10, 0, 0, -10, 0, 0 ) | 
| 117 |                                 << QRect( 0, 0, 30, 40 ) | 
| 118 |                                 << QPolygon( QRect( -300, -400, 300, 400 ) ); | 
| 119 |  | 
| 120 |     const auto rotate = [](qreal degrees) { | 
| 121 |         const qreal rad = qDegreesToRadians(degrees); | 
| 122 |         return QMatrix(std::cos(x: rad), -std::sin(x: rad), | 
| 123 |                        std::sin(x: rad),  std::cos(x: rad), 0, 0); | 
| 124 |     }; | 
| 125 |  | 
| 126 |     // rotations | 
| 127 |     QTest::newRow( dataTag: "rot 0 a"  )  << rotate(0.) | 
| 128 |                                 << QRect( 0, 0, 30, 40 ) | 
| 129 |                                 << QPolygon ( QRect( 0, 0, 30, 40 ) ); | 
| 130 |     QTest::newRow( dataTag: "rot 0 b"  )  << rotate(0.00001f) | 
| 131 |                                 << QRect( 0, 0, 30, 40 ) | 
| 132 |                                 << QPolygon ( QRect( 0, 0, 30, 40 ) ); | 
| 133 |     QTest::newRow( dataTag: "rot 0 c"  )  << rotate(0.) | 
| 134 |                                 << QRect( 10, 20, 30, 40 ) | 
| 135 |                                 << QPolygon ( QRect( 10, 20, 30, 40 ) ); | 
| 136 |     QTest::newRow( dataTag: "rot 0 d"  )  << rotate(0.00001f) | 
| 137 |                                 << QRect( 10, 20, 30, 40 ) | 
| 138 |                                 << QPolygon ( QRect( 10, 20, 30, 40 ) ); | 
| 139 |  | 
| 140 | #if 0 | 
| 141 |     const auto rotScale = [](qreal degrees, qreal scale) { | 
| 142 |         const qreal rad = qDegreesToRadians(degrees); | 
| 143 |         return QMatrix(scale * std::cos(rad), -scale * std::sin(rad), | 
| 144 |                        scale * std::sin(rad),  scale * std::cos(rad), 0, 0); | 
| 145 |     }; | 
| 146 |     // rotations with scaling | 
| 147 |     QTest::newRow( "rotscale 90 a"  )  << rotScale(90., 10) | 
| 148 |                                       << QRect( 0, 0, 30, 40 ) | 
| 149 |                                       << QPolygon( QRect( 0, -299, 400, 300 ) ); | 
| 150 |     QTest::newRow( "rotscale 90 b"  )  << rotScale(90.00001, 10) | 
| 151 |                                       << QRect( 0, 0, 30, 40 ) | 
| 152 |                                       << QPolygon( QRect( 0, -299, 400, 300 ) ); | 
| 153 |     QTest::newRow( "rotscale 90 c"  )  << rotScale(90., 10) | 
| 154 |                                       << QRect( 10, 20, 30, 40 ) | 
| 155 |                                       << QPolygon( QRect( 200, -399, 400, 300 ) ); | 
| 156 |     QTest::newRow( "rotscale 90 d"  )  << rotScale(90.00001, 10) | 
| 157 |                                       << QRect( 10, 20, 30, 40 ) | 
| 158 |                                       << QPolygon( QRect( 200, -399, 400, 300 ) ); | 
| 159 |  | 
| 160 |     QTest::newRow( "rotscale 180 a"  )  << rotScale(180., 10) | 
| 161 |                                        << QRect( 0, 0, 30, 40 ) | 
| 162 |                                        << QPolygon( QRect( -299, -399, 300, 400 ) ); | 
| 163 |     QTest::newRow( "rotscale 180 b"  )  << rotScale(180.000001, 10) | 
| 164 |                                        << QRect( 0, 0, 30, 40 ) | 
| 165 |                                        << QPolygon( QRect( -299, -399, 300, 400 ) ); | 
| 166 |     QTest::newRow( "rotscale 180 c"  )  << rotScale(180., 10) | 
| 167 |                                        << QRect( 10, 20, 30, 40 ) | 
| 168 |                                        << QPolygon( QRect( -399, -599, 300, 400 ) ); | 
| 169 |     QTest::newRow( "rotscale 180 d"  )  << rotScale(180.000001, 10) | 
| 170 |                                        << QRect( 10, 20, 30, 40 ) | 
| 171 |                                        << QPolygon( QRect( -399, -599, 300, 400 ) ); | 
| 172 |  | 
| 173 |     QTest::newRow( "rotscale 270 a"  )  << rotScale(270., 10) | 
| 174 |                                        << QRect( 0, 0, 30, 40 ) | 
| 175 |                                        << QPolygon( QRect( -399, 00, 400, 300 ) ); | 
| 176 |     QTest::newRow( "rotscale 270 b"  )  << rotScale(270.0000001, 10) | 
| 177 |                                        << QRect( 0, 0, 30, 40 ) | 
| 178 |                                        << QPolygon( QRect( -399, 00, 400, 300 ) ); | 
| 179 |     QTest::newRow( "rotscale 270 c"  )  << rotScale(270., 10) | 
| 180 |                                        << QRect( 10, 20, 30, 40 ) | 
| 181 |                                        << QPolygon( QRect( -599, 100, 400, 300 ) ); | 
| 182 |     QTest::newRow( "rotscale 270 d"  )  << rotScale(270.000001, 10) | 
| 183 |                                        << QRect( 10, 20, 30, 40 ) | 
| 184 |                                        << QPolygon( QRect( -599, 100, 400, 300 ) ); | 
| 185 |  | 
| 186 |     // rotations that are not multiples of 90 degrees. mapRect returns the bounding rect here. | 
| 187 |     QTest::newRow( "rot 45 a"  )  << rotate(45) | 
| 188 |                                  << QRect( 0, 0, 10, 10 ) | 
| 189 |                                  << QPolygon( QRect( 0, -7, 14, 14 ) ); | 
| 190 |     QTest::newRow( "rot 45 b"  )  << rotate(45) | 
| 191 |                                  << QRect( 10, 20, 30, 40 ) | 
| 192 |                                  << QPolygon( QRect( 21, -14, 49, 49 ) ); | 
| 193 |     QTest::newRow( "rot 45 c"  )  << rotScale(45, 10) | 
| 194 |                                  << QRect( 0, 0, 10, 10 ) | 
| 195 |                                  << QPolygon( QRect( 0, -70, 141, 141 ) ); | 
| 196 |     QTest::newRow( "rot 45 d"  )  << rotScale(45, 10) | 
| 197 |                                  << QRect( 10, 20, 30, 40 ) | 
| 198 |                                  << QPolygon( QRect( 212, -141, 495, 495 ) ); | 
| 199 |  | 
| 200 |     QTest::newRow( "rot -45 a"  )  << rotate(-45) | 
| 201 |                                   << QRect( 0, 0, 10, 10 ) | 
| 202 |                                   << QPolygon( QRect( -7, 0, 14, 14 ) ); | 
| 203 |     QTest::newRow( "rot -45 b"  )  << rotate(-45) | 
| 204 |                                   << QRect( 10, 20, 30, 40 ) | 
| 205 |                                   << QPolygon( QRect( -35, 21, 49, 49 ) ); | 
| 206 |     QTest::newRow( "rot -45 c"  )  << rotScale(-45, 10) | 
| 207 |                                   << QRect( 0, 0, 10, 10 ) | 
| 208 |                                   << QPolygon( QRect( -70, 0, 141, 141 ) ); | 
| 209 |     QTest::newRow( "rot -45 d"  )  << rotScale(-45, 10) | 
| 210 |                                   << QRect( 10, 20, 30, 40 ) | 
| 211 |                                   << QPolygon( QRect( -353, 212, 495, 495 ) ); | 
| 212 | #endif | 
| 213 | } | 
| 214 |  | 
| 215 | void tst_QWMatrix::mapRect() | 
| 216 | { | 
| 217 |     QFETCH( QMatrix, matrix ); | 
| 218 |     QFETCH( QRect, src ); | 
| 219 | //     qDebug( "got src: %d/%d (%d/%d), matrix=[ %f %f %f %f %f %f ]", | 
| 220 | //         src.x(), src.y(), src.width(), src.height(), | 
| 221 | //         matrix.m11(), matrix.m12(), matrix.m21(), matrix.m22(), matrix.dx(), matrix.dy() ); | 
| 222 |     QTEST( QPolygon( matrix.mapRect(src) ), "res"  ); | 
| 223 | } | 
| 224 |  | 
| 225 | void tst_QWMatrix::operator_star_qwmatrix() | 
| 226 | { | 
| 227 |     QMatrix m1( 2, 3, 4, 5, 6, 7 ); | 
| 228 |     QMatrix m2( 3, 4, 5, 6, 7, 8 ); | 
| 229 |  | 
| 230 |     QMatrix result1x2( 21, 26, 37, 46, 60, 74 ); | 
| 231 |     QMatrix result2x1( 22, 29, 34, 45, 52, 68); | 
| 232 |  | 
| 233 |     QMatrix product12 = m1*m2; | 
| 234 |     QMatrix product21 = m2*m1; | 
| 235 |  | 
| 236 |     QVERIFY( product12==result1x2 ); | 
| 237 |     QVERIFY( product21==result2x1 ); | 
| 238 | } | 
| 239 |  | 
| 240 |  | 
| 241 | void tst_QWMatrix::assignments() | 
| 242 | { | 
| 243 |     QMatrix m; | 
| 244 |     m.scale(sx: 2, sy: 3); | 
| 245 |     m.rotate(a: 45); | 
| 246 |     m.shear(sh: 4, sv: 5); | 
| 247 |  | 
| 248 |     QMatrix c1(m); | 
| 249 |  | 
| 250 |     QCOMPARE(m.m11(), c1.m11()); | 
| 251 |     QCOMPARE(m.m12(), c1.m12()); | 
| 252 |     QCOMPARE(m.m21(), c1.m21()); | 
| 253 |     QCOMPARE(m.m22(), c1.m22()); | 
| 254 |     QCOMPARE(m.dx(), c1.dx()); | 
| 255 |     QCOMPARE(m.dy(), c1.dy()); | 
| 256 |  | 
| 257 |     QMatrix c2 = m; | 
| 258 |     QCOMPARE(m.m11(), c2.m11()); | 
| 259 |     QCOMPARE(m.m12(), c2.m12()); | 
| 260 |     QCOMPARE(m.m21(), c2.m21()); | 
| 261 |     QCOMPARE(m.m22(), c2.m22()); | 
| 262 |     QCOMPARE(m.dx(),  c2.dx()); | 
| 263 |     QCOMPARE(m.dy(),  c2.dy()); | 
| 264 | } | 
| 265 |  | 
| 266 |  | 
| 267 | void tst_QWMatrix::mapToPolygon() | 
| 268 | { | 
| 269 |     QFETCH( QMatrix, matrix ); | 
| 270 |     QFETCH( QRect, src ); | 
| 271 |     QFETCH( QPolygon, res ); | 
| 272 |  | 
| 273 |     QCOMPARE( matrix.mapToPolygon( src ), res ); | 
| 274 | } | 
| 275 |  | 
| 276 |  | 
| 277 | void tst_QWMatrix::translate() | 
| 278 | { | 
| 279 |     QMatrix m( 1, 2, 3, 4, 5, 6 ); | 
| 280 |     QMatrix res2( m ); | 
| 281 |     QMatrix res( 1, 2, 3, 4, 75, 106 ); | 
| 282 |     m.translate( dx: 10,  dy: 20 ); | 
| 283 |     QVERIFY( m == res ); | 
| 284 |     m.translate( dx: -10,  dy: -20 ); | 
| 285 |     QVERIFY( m == res2 ); | 
| 286 | } | 
| 287 |  | 
| 288 | void tst_QWMatrix::scale() | 
| 289 | { | 
| 290 |     QMatrix m( 1, 2, 3, 4, 5, 6 ); | 
| 291 |     QMatrix res2( m ); | 
| 292 |     QMatrix res( 10, 20, 60, 80, 5, 6 ); | 
| 293 |     m.scale( sx: 10,  sy: 20 ); | 
| 294 |     QVERIFY( m == res ); | 
| 295 |     m.scale( sx: 1./10.,  sy: 1./20. ); | 
| 296 |     QVERIFY( m == res2 ); | 
| 297 | } | 
| 298 |  | 
| 299 | void tst_QWMatrix::mapPolygon() | 
| 300 | { | 
| 301 |     QPolygon poly; | 
| 302 |     poly << QPoint(0, 0) << QPoint(1, 1) << QPoint(100, 1) << QPoint(1, 100) << QPoint(-1, -1) << QPoint(-1000, 1000); | 
| 303 |  | 
| 304 |     { | 
| 305 |         QMatrix m; | 
| 306 |         m.rotate(a: 90); | 
| 307 |  | 
| 308 |         // rotating 90 degrees four times should result in original poly | 
| 309 |         QPolygon mapped = m.map(a: m.map(a: m.map(a: m.map(a: poly)))); | 
| 310 |         QCOMPARE(mapped, poly); | 
| 311 |  | 
| 312 |         QMatrix m2; | 
| 313 |         m2.scale(sx: 10, sy: 10); | 
| 314 |         QMatrix m3; | 
| 315 |         m3.scale(sx: 0.1, sy: 0.1); | 
| 316 |  | 
| 317 |         mapped = m3.map(a: m2.map(a: poly)); | 
| 318 |         QCOMPARE(mapped, poly); | 
| 319 |     } | 
| 320 |  | 
| 321 |     { | 
| 322 |         QMatrix m(1, 2, 3, 4, 5, 6); | 
| 323 |  | 
| 324 |         QPolygon mapped = m.map(a: poly); | 
| 325 |         for (int i = 0; i < mapped.size(); ++i) | 
| 326 |             QCOMPARE(mapped.at(i), m.map(poly.at(i))); | 
| 327 |     } | 
| 328 | } | 
| 329 |  | 
| 330 | QT_WARNING_POP | 
| 331 | #endif | 
| 332 |  | 
| 333 | QTEST_APPLESS_MAIN(tst_QWMatrix) | 
| 334 | #include "tst_qwmatrix.moc" | 
| 335 |  |