| 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 | #include <QtTest/QtTest> | 
| 30 | #include <QtCore/qmath.h> | 
| 31 | #include <QtGui/qmatrix4x4.h> | 
| 32 |  | 
| 33 | class tst_QMatrixNxN : public QObject | 
| 34 | { | 
| 35 |     Q_OBJECT | 
| 36 | public: | 
| 37 |     tst_QMatrixNxN() {} | 
| 38 |     ~tst_QMatrixNxN() {} | 
| 39 |  | 
| 40 | private slots: | 
| 41 |     void create2x2(); | 
| 42 |     void create3x3(); | 
| 43 |     void create4x4(); | 
| 44 |     void create4x3(); | 
| 45 |  | 
| 46 |     void isIdentity2x2(); | 
| 47 |     void isIdentity3x3(); | 
| 48 |     void isIdentity4x4(); | 
| 49 |     void isIdentity4x3(); | 
| 50 |  | 
| 51 |     void compare2x2(); | 
| 52 |     void compare3x3(); | 
| 53 |     void compare4x4(); | 
| 54 |     void compare4x3(); | 
| 55 |  | 
| 56 |     void transposed2x2(); | 
| 57 |     void transposed3x3(); | 
| 58 |     void transposed4x4(); | 
| 59 |     void transposed4x3(); | 
| 60 |  | 
| 61 |     void add2x2_data(); | 
| 62 |     void add2x2(); | 
| 63 |     void add3x3_data(); | 
| 64 |     void add3x3(); | 
| 65 |     void add4x4_data(); | 
| 66 |     void add4x4(); | 
| 67 |     void add4x3_data(); | 
| 68 |     void add4x3(); | 
| 69 |  | 
| 70 |     void subtract2x2_data(); | 
| 71 |     void subtract2x2(); | 
| 72 |     void subtract3x3_data(); | 
| 73 |     void subtract3x3(); | 
| 74 |     void subtract4x4_data(); | 
| 75 |     void subtract4x4(); | 
| 76 |     void subtract4x3_data(); | 
| 77 |     void subtract4x3(); | 
| 78 |  | 
| 79 |     void multiply2x2_data(); | 
| 80 |     void multiply2x2(); | 
| 81 |     void multiply3x3_data(); | 
| 82 |     void multiply3x3(); | 
| 83 |     void multiply4x4_data(); | 
| 84 |     void multiply4x4(); | 
| 85 |     void multiply4x3_data(); | 
| 86 |     void multiply4x3(); | 
| 87 |  | 
| 88 |     void multiplyFactor2x2_data(); | 
| 89 |     void multiplyFactor2x2(); | 
| 90 |     void multiplyFactor3x3_data(); | 
| 91 |     void multiplyFactor3x3(); | 
| 92 |     void multiplyFactor4x4_data(); | 
| 93 |     void multiplyFactor4x4(); | 
| 94 |     void multiplyFactor4x3_data(); | 
| 95 |     void multiplyFactor4x3(); | 
| 96 |  | 
| 97 |     void divideFactor2x2_data(); | 
| 98 |     void divideFactor2x2(); | 
| 99 |     void divideFactor3x3_data(); | 
| 100 |     void divideFactor3x3(); | 
| 101 |     void divideFactor4x4_data(); | 
| 102 |     void divideFactor4x4(); | 
| 103 |     void divideFactor4x3_data(); | 
| 104 |     void divideFactor4x3(); | 
| 105 |  | 
| 106 |     void negate2x2_data(); | 
| 107 |     void negate2x2(); | 
| 108 |     void negate3x3_data(); | 
| 109 |     void negate3x3(); | 
| 110 |     void negate4x4_data(); | 
| 111 |     void negate4x4(); | 
| 112 |     void negate4x3_data(); | 
| 113 |     void negate4x3(); | 
| 114 |  | 
| 115 |     void inverted4x4_data(); | 
| 116 |     void inverted4x4(); | 
| 117 |  | 
| 118 |     void orthonormalInverse4x4(); | 
| 119 |  | 
| 120 |     void scale4x4_data(); | 
| 121 |     void scale4x4(); | 
| 122 |  | 
| 123 |     void translate4x4_data(); | 
| 124 |     void translate4x4(); | 
| 125 |  | 
| 126 |     void rotate4x4_data(); | 
| 127 |     void rotate4x4(); | 
| 128 |  | 
| 129 |     void normalMatrix_data(); | 
| 130 |     void normalMatrix(); | 
| 131 |  | 
| 132 |     void optimizedTransforms(); | 
| 133 |  | 
| 134 |     void ortho(); | 
| 135 |     void frustum(); | 
| 136 |     void perspective(); | 
| 137 |     void viewport(); | 
| 138 |     void flipCoordinates(); | 
| 139 |  | 
| 140 |     void convertGeneric(); | 
| 141 |  | 
| 142 |     void optimize_data(); | 
| 143 |     void optimize(); | 
| 144 |  | 
| 145 |     void columnsAndRows(); | 
| 146 |  | 
| 147 |     void convertQMatrix(); | 
| 148 |     void convertQTransform(); | 
| 149 |  | 
| 150 |     void fill(); | 
| 151 |  | 
| 152 |     void mapRect_data(); | 
| 153 |     void mapRect(); | 
| 154 |  | 
| 155 |     void mapVector_data(); | 
| 156 |     void mapVector(); | 
| 157 |  | 
| 158 |     void properties(); | 
| 159 |     void metaTypes(); | 
| 160 |  | 
| 161 | private: | 
| 162 |     static void setMatrix(QMatrix2x2& m, const float *values); | 
| 163 |     static void setMatrixDirect(QMatrix2x2& m, const float *values); | 
| 164 |     static bool isSame(const QMatrix2x2& m, const float *values); | 
| 165 |     static bool isIdentity(const QMatrix2x2& m); | 
| 166 |  | 
| 167 |     static void setMatrix(QMatrix3x3& m, const float *values); | 
| 168 |     static void setMatrixDirect(QMatrix3x3& m, const float *values); | 
| 169 |     static bool isSame(const QMatrix3x3& m, const float *values); | 
| 170 |     static bool isIdentity(const QMatrix3x3& m); | 
| 171 |  | 
| 172 |     static void setMatrix(QMatrix4x4& m, const float *values); | 
| 173 |     static void setMatrixDirect(QMatrix4x4& m, const float *values); | 
| 174 |     static bool isSame(const QMatrix4x4& m, const float *values); | 
| 175 |     static bool isIdentity(const QMatrix4x4& m); | 
| 176 |  | 
| 177 |     static void setMatrix(QMatrix4x3& m, const float *values); | 
| 178 |     static void setMatrixDirect(QMatrix4x3& m, const float *values); | 
| 179 |     static bool isSame(const QMatrix4x3& m, const float *values); | 
| 180 |     static bool isIdentity(const QMatrix4x3& m); | 
| 181 | }; | 
| 182 |  | 
| 183 | static const float nullValues2[] = | 
| 184 |     {0.0f, 0.0f, | 
| 185 |      0.0f, 0.0f}; | 
| 186 |  | 
| 187 | static float const identityValues2[16] = | 
| 188 |     {1.0f, 0.0f, | 
| 189 |      0.0f, 1.0f}; | 
| 190 |  | 
| 191 | static const float doubleIdentity2[] = | 
| 192 |     {2.0f, 0.0f, | 
| 193 |      0.0f, 2.0f}; | 
| 194 |  | 
| 195 | static float const uniqueValues2[16] = | 
| 196 |     {1.0f, 2.0f, | 
| 197 |      5.0f, 6.0f}; | 
| 198 |  | 
| 199 | static float const transposedValues2[16] = | 
| 200 |     {1.0f, 5.0f, | 
| 201 |      2.0f, 6.0f}; | 
| 202 |  | 
| 203 | static const float nullValues3[] = | 
| 204 |     {0.0f, 0.0f, 0.0f, | 
| 205 |      0.0f, 0.0f, 0.0f, | 
| 206 |      0.0f, 0.0f, 0.0f}; | 
| 207 |  | 
| 208 | static float const identityValues3[16] = | 
| 209 |     {1.0f, 0.0f, 0.0f, | 
| 210 |      0.0f, 1.0f, 0.0f, | 
| 211 |      0.0f, 0.0f, 1.0f}; | 
| 212 |  | 
| 213 | static const float doubleIdentity3[] = | 
| 214 |     {2.0f, 0.0f, 0.0f, | 
| 215 |      0.0f, 2.0f, 0.0f, | 
| 216 |      0.0f, 0.0f, 2.0f}; | 
| 217 |  | 
| 218 | static float const uniqueValues3[16] = | 
| 219 |     {1.0f, 2.0f, 3.0f, | 
| 220 |      5.0f, 6.0f, 7.0f, | 
| 221 |      9.0f, 10.0f, 11.0f}; | 
| 222 |  | 
| 223 | static float const transposedValues3[16] = | 
| 224 |     {1.0f, 5.0f, 9.0f, | 
| 225 |      2.0f, 6.0f, 10.0f, | 
| 226 |      3.0f, 7.0f, 11.0f}; | 
| 227 |  | 
| 228 | static const float nullValues4[] = | 
| 229 |     {0.0f, 0.0f, 0.0f, 0.0f, | 
| 230 |      0.0f, 0.0f, 0.0f, 0.0f, | 
| 231 |      0.0f, 0.0f, 0.0f, 0.0f, | 
| 232 |      0.0f, 0.0f, 0.0f, 0.0f}; | 
| 233 |  | 
| 234 | static float const identityValues4[16] = | 
| 235 |     {1.0f, 0.0f, 0.0f, 0.0f, | 
| 236 |      0.0f, 1.0f, 0.0f, 0.0f, | 
| 237 |      0.0f, 0.0f, 1.0f, 0.0f, | 
| 238 |      0.0f, 0.0f, 0.0f, 1.0f}; | 
| 239 |  | 
| 240 | static const float doubleIdentity4[] = | 
| 241 |     {2.0f, 0.0f, 0.0f, 0.0f, | 
| 242 |      0.0f, 2.0f, 0.0f, 0.0f, | 
| 243 |      0.0f, 0.0f, 2.0f, 0.0f, | 
| 244 |      0.0f, 0.0f, 0.0f, 2.0f}; | 
| 245 |  | 
| 246 | static float const uniqueValues4[16] = | 
| 247 |     {1.0f, 2.0f, 3.0f, 4.0f, | 
| 248 |      5.0f, 6.0f, 7.0f, 8.0f, | 
| 249 |      9.0f, 10.0f, 11.0f, 12.0f, | 
| 250 |      13.0f, 14.0f, 15.0f, 16.0f}; | 
| 251 |  | 
| 252 | static float const transposedValues4[16] = | 
| 253 |     {1.0f, 5.0f, 9.0f, 13.0f, | 
| 254 |      2.0f, 6.0f, 10.0f, 14.0f, | 
| 255 |      3.0f, 7.0f, 11.0f, 15.0f, | 
| 256 |      4.0f, 8.0f, 12.0f, 16.0f}; | 
| 257 |  | 
| 258 | static const float nullValues4x3[] = | 
| 259 |     {0.0f, 0.0f, 0.0f, 0.0f, | 
| 260 |      0.0f, 0.0f, 0.0f, 0.0f, | 
| 261 |      0.0f, 0.0f, 0.0f, 0.0f}; | 
| 262 |  | 
| 263 | static float const identityValues4x3[12] = | 
| 264 |     {1.0f, 0.0f, 0.0f, 0.0f, | 
| 265 |      0.0f, 1.0f, 0.0f, 0.0f, | 
| 266 |      0.0f, 0.0f, 1.0f, 0.0f}; | 
| 267 |  | 
| 268 | static float const doubleIdentity4x3[12] = | 
| 269 |     {2.0f, 0.0f, 0.0f, 0.0f, | 
| 270 |      0.0f, 2.0f, 0.0f, 0.0f, | 
| 271 |      0.0f, 0.0f, 2.0f, 0.0f}; | 
| 272 |  | 
| 273 | static float const uniqueValues4x3[12] = | 
| 274 |     {1.0f, 2.0f, 3.0f, 4.0f, | 
| 275 |      5.0f, 6.0f, 7.0f, 8.0f, | 
| 276 |      9.0f, 10.0f, 11.0f, 12.0f}; | 
| 277 |  | 
| 278 | static float const transposedValues3x4[12] = | 
| 279 |     {1.0f, 5.0f, 9.0f, | 
| 280 |      2.0f, 6.0f, 10.0f, | 
| 281 |      3.0f, 7.0f, 11.0f, | 
| 282 |      4.0f, 8.0f, 12.0f}; | 
| 283 |  | 
| 284 | // We use a slightly better implementation of qFuzzyCompare here that | 
| 285 | // handles the case where one of the values is exactly 0 | 
| 286 | static inline bool fuzzyCompare(float p1, float p2) | 
| 287 | { | 
| 288 |     if (qFuzzyIsNull(f: p1)) | 
| 289 |         return qFuzzyIsNull(f: p2); | 
| 290 |     else if (qFuzzyIsNull(f: p2)) | 
| 291 |         return false; | 
| 292 |     else | 
| 293 |         return qFuzzyCompare(p1, p2); | 
| 294 | } | 
| 295 |  | 
| 296 | // Set a matrix to a specified array of values, which are assumed | 
| 297 | // to be in row-major order.  This sets the values using floating-point. | 
| 298 | void tst_QMatrixNxN::setMatrix(QMatrix2x2& m, const float *values) | 
| 299 | { | 
| 300 |     for (int row = 0; row < 2; ++row) | 
| 301 |         for (int col = 0; col < 2; ++col) | 
| 302 |             m(row, col) = values[row * 2 + col]; | 
| 303 | } | 
| 304 | void tst_QMatrixNxN::setMatrix(QMatrix3x3& m, const float *values) | 
| 305 | { | 
| 306 |     for (int row = 0; row < 3; ++row) | 
| 307 |         for (int col = 0; col < 3; ++col) | 
| 308 |             m(row, col) = values[row * 3 + col]; | 
| 309 | } | 
| 310 | void tst_QMatrixNxN::setMatrix(QMatrix4x4& m, const float *values) | 
| 311 | { | 
| 312 |     for (int row = 0; row < 4; ++row) | 
| 313 |         for (int col = 0; col < 4; ++col) | 
| 314 |             m(row, col) = values[row * 4 + col]; | 
| 315 | } | 
| 316 | void tst_QMatrixNxN::setMatrix(QMatrix4x3& m, const float *values) | 
| 317 | { | 
| 318 |     for (int row = 0; row < 3; ++row) | 
| 319 |         for (int col = 0; col < 4; ++col) | 
| 320 |             m(row, col) = values[row * 4 + col]; | 
| 321 | } | 
| 322 |  | 
| 323 | // Set a matrix to a specified array of values, which are assumed | 
| 324 | // to be in row-major order.  This sets the values directly into | 
| 325 | // the internal data() array. | 
| 326 | void tst_QMatrixNxN::setMatrixDirect(QMatrix2x2& m, const float *values) | 
| 327 | { | 
| 328 |     float *data = m.data(); | 
| 329 |     for (int row = 0; row < 2; ++row) { | 
| 330 |         for (int col = 0; col < 2; ++col) { | 
| 331 |             data[row + col * 2] = values[row * 2 + col]; | 
| 332 |         } | 
| 333 |     } | 
| 334 | } | 
| 335 | void tst_QMatrixNxN::setMatrixDirect(QMatrix3x3& m, const float *values) | 
| 336 | { | 
| 337 |     float *data = m.data(); | 
| 338 |     for (int row = 0; row < 3; ++row) { | 
| 339 |         for (int col = 0; col < 3; ++col) { | 
| 340 |             data[row + col * 3] = values[row * 3 + col]; | 
| 341 |         } | 
| 342 |     } | 
| 343 | } | 
| 344 | void tst_QMatrixNxN::setMatrixDirect(QMatrix4x4& m, const float *values) | 
| 345 | { | 
| 346 |     float *data = m.data(); | 
| 347 |     for (int row = 0; row < 4; ++row) { | 
| 348 |         for (int col = 0; col < 4; ++col) { | 
| 349 |             data[row + col * 4] = values[row * 4 + col]; | 
| 350 |         } | 
| 351 |     } | 
| 352 | } | 
| 353 | void tst_QMatrixNxN::setMatrixDirect(QMatrix4x3& m, const float *values) | 
| 354 | { | 
| 355 |     float *data = m.data(); | 
| 356 |     for (int row = 0; row < 3; ++row) { | 
| 357 |         for (int col = 0; col < 4; ++col) { | 
| 358 |             data[row + col * 3] = values[row * 4 + col]; | 
| 359 |         } | 
| 360 |     } | 
| 361 | } | 
| 362 |  | 
| 363 | // Determine if a matrix is the same as a specified array of values. | 
| 364 | // The values are assumed to be specified in row-major order. | 
| 365 | bool tst_QMatrixNxN::isSame(const QMatrix2x2& m, const float *values) | 
| 366 | { | 
| 367 |     const float *mv = m.constData(); | 
| 368 |     for (int row = 0; row < 2; ++row) { | 
| 369 |         for (int col = 0; col < 2; ++col) { | 
| 370 |             // Check the values using the operator() function. | 
| 371 |             if (!fuzzyCompare(p1: m(row, col), p2: values[row * 2 + col])) { | 
| 372 |                 qDebug() << "floating-point failure at"  << row << col << "actual ="  << m(row, col) << "expected ="  << values[row * 2 + col]; | 
| 373 |                 return false; | 
| 374 |             } | 
| 375 |  | 
| 376 |             // Check the values using direct access, which verifies that the values | 
| 377 |             // are stored internally in column-major order. | 
| 378 |             if (!fuzzyCompare(p1: mv[col * 2 + row], p2: values[row * 2 + col])) { | 
| 379 |                 qDebug() << "column floating-point failure at"  << row << col << "actual ="  << mv[col * 2 + row] << "expected ="  << values[row * 2 + col]; | 
| 380 |                 return false; | 
| 381 |             } | 
| 382 |         } | 
| 383 |     } | 
| 384 |     return true; | 
| 385 | } | 
| 386 | bool tst_QMatrixNxN::isSame(const QMatrix3x3& m, const float *values) | 
| 387 | { | 
| 388 |     const float *mv = m.constData(); | 
| 389 |     for (int row = 0; row < 3; ++row) { | 
| 390 |         for (int col = 0; col < 3; ++col) { | 
| 391 |             // Check the values using the operator() access function. | 
| 392 |             if (!fuzzyCompare(p1: m(row, col), p2: values[row * 3 + col])) { | 
| 393 |                 qDebug() << "floating-point failure at"  << row << col << "actual ="  << m(row, col) << "expected ="  << values[row * 3 + col]; | 
| 394 |                 return false; | 
| 395 |             } | 
| 396 |  | 
| 397 |             // Check the values using direct access, which verifies that the values | 
| 398 |             // are stored internally in column-major order. | 
| 399 |             if (!fuzzyCompare(p1: mv[col * 3 + row], p2: values[row * 3 + col])) { | 
| 400 |                 qDebug() << "column floating-point failure at"  << row << col << "actual ="  << mv[col * 3 + row] << "expected ="  << values[row * 3 + col]; | 
| 401 |                 return false; | 
| 402 |             } | 
| 403 |         } | 
| 404 |     } | 
| 405 |     return true; | 
| 406 | } | 
| 407 | bool tst_QMatrixNxN::isSame(const QMatrix4x4& m, const float *values) | 
| 408 | { | 
| 409 |     const float *mv = m.constData(); | 
| 410 |     for (int row = 0; row < 4; ++row) { | 
| 411 |         for (int col = 0; col < 4; ++col) { | 
| 412 |             // Check the values using the operator() access function. | 
| 413 |             if (!fuzzyCompare(p1: m(row, col), p2: values[row * 4 + col])) { | 
| 414 |                 qDebug() << "floating-point failure at"  << row << col << "actual ="  << m(row, col) << "expected ="  << values[row * 4 + col]; | 
| 415 |                 return false; | 
| 416 |             } | 
| 417 |  | 
| 418 |             // Check the values using direct access, which verifies that the values | 
| 419 |             // are stored internally in column-major order. | 
| 420 |             if (!fuzzyCompare(p1: mv[col * 4 + row], p2: values[row * 4 + col])) { | 
| 421 |                 qDebug() << "column floating-point failure at"  << row << col << "actual ="  << mv[col * 4 + row] << "expected ="  << values[row * 4 + col]; | 
| 422 |                 return false; | 
| 423 |             } | 
| 424 |         } | 
| 425 |     } | 
| 426 |     return true; | 
| 427 | } | 
| 428 | bool tst_QMatrixNxN::isSame(const QMatrix4x3& m, const float *values) | 
| 429 | { | 
| 430 |     const float *mv = m.constData(); | 
| 431 |     for (int row = 0; row < 3; ++row) { | 
| 432 |         for (int col = 0; col < 4; ++col) { | 
| 433 |             // Check the values using the operator() access function. | 
| 434 |             if (!fuzzyCompare(p1: m(row, col), p2: values[row * 4 + col])) { | 
| 435 |                 qDebug() << "floating-point failure at"  << row << col << "actual ="  << m(row, col) << "expected ="  << values[row * 4 + col]; | 
| 436 |                 return false; | 
| 437 |             } | 
| 438 |  | 
| 439 |             // Check the values using direct access, which verifies that the values | 
| 440 |             // are stored internally in column-major order. | 
| 441 |             if (!fuzzyCompare(p1: mv[col * 3 + row], p2: values[row * 4 + col])) { | 
| 442 |                 qDebug() << "column floating-point failure at"  << row << col << "actual ="  << mv[col * 3 + row] << "expected ="  << values[row * 4 + col]; | 
| 443 |                 return false; | 
| 444 |             } | 
| 445 |         } | 
| 446 |     } | 
| 447 |     return true; | 
| 448 | } | 
| 449 |  | 
| 450 | // Determine if a matrix is the identity. | 
| 451 | bool tst_QMatrixNxN::isIdentity(const QMatrix2x2& m) | 
| 452 | { | 
| 453 |     return isSame(m, values: identityValues2); | 
| 454 | } | 
| 455 | bool tst_QMatrixNxN::isIdentity(const QMatrix3x3& m) | 
| 456 | { | 
| 457 |     return isSame(m, values: identityValues3); | 
| 458 | } | 
| 459 | bool tst_QMatrixNxN::isIdentity(const QMatrix4x4& m) | 
| 460 | { | 
| 461 |     return isSame(m, values: identityValues4); | 
| 462 | } | 
| 463 | bool tst_QMatrixNxN::isIdentity(const QMatrix4x3& m) | 
| 464 | { | 
| 465 |     return isSame(m, values: identityValues4x3); | 
| 466 | } | 
| 467 |  | 
| 468 | // Test the creation of QMatrix2x2 objects in various ways: | 
| 469 | // construct, copy, and modify. | 
| 470 | void tst_QMatrixNxN::create2x2() | 
| 471 | { | 
| 472 |     QMatrix2x2 m1; | 
| 473 |     QVERIFY(isIdentity(m1)); | 
| 474 |     QVERIFY(m1.isIdentity()); | 
| 475 |  | 
| 476 |     QMatrix2x2 m2; | 
| 477 |     setMatrix(m&: m2, values: uniqueValues2); | 
| 478 |     QVERIFY(isSame(m2, uniqueValues2)); | 
| 479 |     QVERIFY(!m2.isIdentity()); | 
| 480 |  | 
| 481 |     QMatrix2x2 m3; | 
| 482 |     setMatrixDirect(m&: m3, values: uniqueValues2); | 
| 483 |     QVERIFY(isSame(m3, uniqueValues2)); | 
| 484 |  | 
| 485 |     QMatrix2x2 m4(m3); | 
| 486 |     QVERIFY(isSame(m4, uniqueValues2)); | 
| 487 |  | 
| 488 |     QMatrix2x2 m5; | 
| 489 |     m5 = m3; | 
| 490 |     QVERIFY(isSame(m5, uniqueValues2)); | 
| 491 |  | 
| 492 |     m5.setToIdentity(); | 
| 493 |     QVERIFY(isIdentity(m5)); | 
| 494 |  | 
| 495 |     QMatrix2x2 m6(uniqueValues2); | 
| 496 |     QVERIFY(isSame(m6, uniqueValues2)); | 
| 497 |     float vals[4]; | 
| 498 |     m6.copyDataTo(values: vals); | 
| 499 |     for (int index = 0; index < 4; ++index) | 
| 500 |         QCOMPARE(vals[index], uniqueValues2[index]); | 
| 501 | } | 
| 502 |  | 
| 503 | // Test the creation of QMatrix3x3 objects in various ways: | 
| 504 | // construct, copy, and modify. | 
| 505 | void tst_QMatrixNxN::create3x3() | 
| 506 | { | 
| 507 |     QMatrix3x3 m1; | 
| 508 |     QVERIFY(isIdentity(m1)); | 
| 509 |     QVERIFY(m1.isIdentity()); | 
| 510 |  | 
| 511 |     QMatrix3x3 m2; | 
| 512 |     setMatrix(m&: m2, values: uniqueValues3); | 
| 513 |     QVERIFY(isSame(m2, uniqueValues3)); | 
| 514 |     QVERIFY(!m2.isIdentity()); | 
| 515 |  | 
| 516 |     QMatrix3x3 m3; | 
| 517 |     setMatrixDirect(m&: m3, values: uniqueValues3); | 
| 518 |     QVERIFY(isSame(m3, uniqueValues3)); | 
| 519 |  | 
| 520 |     QMatrix3x3 m4(m3); | 
| 521 |     QVERIFY(isSame(m4, uniqueValues3)); | 
| 522 |  | 
| 523 |     QMatrix3x3 m5; | 
| 524 |     m5 = m3; | 
| 525 |     QVERIFY(isSame(m5, uniqueValues3)); | 
| 526 |  | 
| 527 |     m5.setToIdentity(); | 
| 528 |     QVERIFY(isIdentity(m5)); | 
| 529 |  | 
| 530 |     QMatrix3x3 m6(uniqueValues3); | 
| 531 |     QVERIFY(isSame(m6, uniqueValues3)); | 
| 532 |     float vals[9]; | 
| 533 |     m6.copyDataTo(values: vals); | 
| 534 |     for (int index = 0; index < 9; ++index) | 
| 535 |         QCOMPARE(vals[index], uniqueValues3[index]); | 
| 536 | } | 
| 537 |  | 
| 538 | // Test the creation of QMatrix4x4 objects in various ways: | 
| 539 | // construct, copy, and modify. | 
| 540 | void tst_QMatrixNxN::create4x4() | 
| 541 | { | 
| 542 |     QMatrix4x4 m1; | 
| 543 |     QVERIFY(isIdentity(m1)); | 
| 544 |     QVERIFY(m1.isIdentity()); | 
| 545 |  | 
| 546 |     QMatrix4x4 m2; | 
| 547 |     setMatrix(m&: m2, values: uniqueValues4); | 
| 548 |     QVERIFY(isSame(m2, uniqueValues4)); | 
| 549 |     QVERIFY(!m2.isIdentity()); | 
| 550 |  | 
| 551 |     QMatrix4x4 m3; | 
| 552 |     setMatrixDirect(m&: m3, values: uniqueValues4); | 
| 553 |     QVERIFY(isSame(m3, uniqueValues4)); | 
| 554 |  | 
| 555 |     QMatrix4x4 m4(m3); | 
| 556 |     QVERIFY(isSame(m4, uniqueValues4)); | 
| 557 |  | 
| 558 |     QMatrix4x4 m5; | 
| 559 |     m5 = m3; | 
| 560 |     QVERIFY(isSame(m5, uniqueValues4)); | 
| 561 |  | 
| 562 |     m5.setToIdentity(); | 
| 563 |     QVERIFY(isIdentity(m5)); | 
| 564 |  | 
| 565 |     QMatrix4x4 m6(uniqueValues4); | 
| 566 |     QVERIFY(isSame(m6, uniqueValues4)); | 
| 567 |     float vals[16]; | 
| 568 |     m6.copyDataTo(values: vals); | 
| 569 |     for (int index = 0; index < 16; ++index) | 
| 570 |         QCOMPARE(vals[index], uniqueValues4[index]); | 
| 571 |  | 
| 572 |     QMatrix4x4 m8 | 
| 573 |         (uniqueValues4[0], uniqueValues4[1], uniqueValues4[2], uniqueValues4[3], | 
| 574 |          uniqueValues4[4], uniqueValues4[5], uniqueValues4[6], uniqueValues4[7], | 
| 575 |          uniqueValues4[8], uniqueValues4[9], uniqueValues4[10], uniqueValues4[11], | 
| 576 |          uniqueValues4[12], uniqueValues4[13], uniqueValues4[14], uniqueValues4[15]); | 
| 577 |     QVERIFY(isSame(m8, uniqueValues4)); | 
| 578 | } | 
| 579 |  | 
| 580 | // Test the creation of QMatrix4x3 objects in various ways: | 
| 581 | // construct, copy, and modify. | 
| 582 | void tst_QMatrixNxN::create4x3() | 
| 583 | { | 
| 584 |     QMatrix4x3 m1; | 
| 585 |     QVERIFY(isIdentity(m1)); | 
| 586 |     QVERIFY(m1.isIdentity()); | 
| 587 |  | 
| 588 |     QMatrix4x3 m2; | 
| 589 |     setMatrix(m&: m2, values: uniqueValues4x3); | 
| 590 |     QVERIFY(isSame(m2, uniqueValues4x3)); | 
| 591 |     QVERIFY(!m2.isIdentity()); | 
| 592 |  | 
| 593 |     QMatrix4x3 m3; | 
| 594 |     setMatrixDirect(m&: m3, values: uniqueValues4x3); | 
| 595 |     QVERIFY(isSame(m3, uniqueValues4x3)); | 
| 596 |  | 
| 597 |     QMatrix4x3 m4(m3); | 
| 598 |     QVERIFY(isSame(m4, uniqueValues4x3)); | 
| 599 |  | 
| 600 |     QMatrix4x3 m5; | 
| 601 |     m5 = m3; | 
| 602 |     QVERIFY(isSame(m5, uniqueValues4x3)); | 
| 603 |  | 
| 604 |     m5.setToIdentity(); | 
| 605 |     QVERIFY(isIdentity(m5)); | 
| 606 |  | 
| 607 |     QMatrix4x3 m6(uniqueValues4x3); | 
| 608 |     QVERIFY(isSame(m6, uniqueValues4x3)); | 
| 609 |     float vals[12]; | 
| 610 |     m6.copyDataTo(values: vals); | 
| 611 |     for (int index = 0; index < 12; ++index) | 
| 612 |         QCOMPARE(vals[index], uniqueValues4x3[index]); | 
| 613 | } | 
| 614 |  | 
| 615 | // Test isIdentity() for 2x2 matrices. | 
| 616 | void tst_QMatrixNxN::isIdentity2x2() | 
| 617 | { | 
| 618 |     for (int i = 0; i < 2 * 2; ++i) { | 
| 619 |         QMatrix2x2 m; | 
| 620 |         QVERIFY(m.isIdentity()); | 
| 621 |         m.data()[i] = 42.0f; | 
| 622 |         QVERIFY(!m.isIdentity()); | 
| 623 |     } | 
| 624 | } | 
| 625 |  | 
| 626 | // Test isIdentity() for 3x3 matrices. | 
| 627 | void tst_QMatrixNxN::isIdentity3x3() | 
| 628 | { | 
| 629 |     for (int i = 0; i < 3 * 3; ++i) { | 
| 630 |         QMatrix3x3 m; | 
| 631 |         QVERIFY(m.isIdentity()); | 
| 632 |         m.data()[i] = 42.0f; | 
| 633 |         QVERIFY(!m.isIdentity()); | 
| 634 |     } | 
| 635 | } | 
| 636 |  | 
| 637 | // Test isIdentity() for 4x4 matrices. | 
| 638 | void tst_QMatrixNxN::isIdentity4x4() | 
| 639 | { | 
| 640 |     for (int i = 0; i < 4 * 4; ++i) { | 
| 641 |         QMatrix4x4 m; | 
| 642 |         QVERIFY(m.isIdentity()); | 
| 643 |         m.data()[i] = 42.0f; | 
| 644 |         QVERIFY(!m.isIdentity()); | 
| 645 |     } | 
| 646 |  | 
| 647 |     // Force the "Identity" flag bit to be lost and check again. | 
| 648 |     QMatrix4x4 m2; | 
| 649 |     m2.data()[0] = 1.0f; | 
| 650 |     QVERIFY(m2.isIdentity()); | 
| 651 | } | 
| 652 |  | 
| 653 | // Test isIdentity() for 4x3 matrices. | 
| 654 | void tst_QMatrixNxN::isIdentity4x3() | 
| 655 | { | 
| 656 |     for (int i = 0; i < 4 * 3; ++i) { | 
| 657 |         QMatrix4x3 m; | 
| 658 |         QVERIFY(m.isIdentity()); | 
| 659 |         m.data()[i] = 42.0f; | 
| 660 |         QVERIFY(!m.isIdentity()); | 
| 661 |     } | 
| 662 | } | 
| 663 |  | 
| 664 | // Test 2x2 matrix comparisons. | 
| 665 | void tst_QMatrixNxN::compare2x2() | 
| 666 | { | 
| 667 |     QMatrix2x2 m1(uniqueValues2); | 
| 668 |     QMatrix2x2 m2(uniqueValues2); | 
| 669 |     QMatrix2x2 m3(transposedValues2); | 
| 670 |  | 
| 671 |     QCOMPARE(m1, m2); | 
| 672 |     QVERIFY(!(m1 != m2)); | 
| 673 |     QVERIFY(m1 != m3); | 
| 674 |     QVERIFY(!(m1 == m3)); | 
| 675 | } | 
| 676 |  | 
| 677 | // Test 3x3 matrix comparisons. | 
| 678 | void tst_QMatrixNxN::compare3x3() | 
| 679 | { | 
| 680 |     QMatrix3x3 m1(uniqueValues3); | 
| 681 |     QMatrix3x3 m2(uniqueValues3); | 
| 682 |     QMatrix3x3 m3(transposedValues3); | 
| 683 |  | 
| 684 |     QCOMPARE(m1, m2); | 
| 685 |     QVERIFY(!(m1 != m2)); | 
| 686 |     QVERIFY(m1 != m3); | 
| 687 |     QVERIFY(!(m1 == m3)); | 
| 688 | } | 
| 689 |  | 
| 690 | // Test 4x4 matrix comparisons. | 
| 691 | void tst_QMatrixNxN::compare4x4() | 
| 692 | { | 
| 693 |     QMatrix4x4 m1(uniqueValues4); | 
| 694 |     QMatrix4x4 m2(uniqueValues4); | 
| 695 |     QMatrix4x4 m3(transposedValues4); | 
| 696 |  | 
| 697 |     QCOMPARE(m1, m2); | 
| 698 |     QVERIFY(!(m1 != m2)); | 
| 699 |     QVERIFY(m1 != m3); | 
| 700 |     QVERIFY(!(m1 == m3)); | 
| 701 | } | 
| 702 |  | 
| 703 | // Test 4x3 matrix comparisons. | 
| 704 | void tst_QMatrixNxN::compare4x3() | 
| 705 | { | 
| 706 |     QMatrix4x3 m1(uniqueValues4x3); | 
| 707 |     QMatrix4x3 m2(uniqueValues4x3); | 
| 708 |     QMatrix4x3 m3(transposedValues3x4); | 
| 709 |  | 
| 710 |     QCOMPARE(m1, m2); | 
| 711 |     QVERIFY(!(m1 != m2)); | 
| 712 |     QVERIFY(m1 != m3); | 
| 713 |     QVERIFY(!(m1 == m3)); | 
| 714 | } | 
| 715 |  | 
| 716 | // Test matrix 2x2 transpose operations. | 
| 717 | void tst_QMatrixNxN::transposed2x2() | 
| 718 | { | 
| 719 |     // Transposing the identity should result in the identity. | 
| 720 |     QMatrix2x2 m1; | 
| 721 |     QMatrix2x2 m2 = m1.transposed(); | 
| 722 |     QVERIFY(isIdentity(m2)); | 
| 723 |  | 
| 724 |     // Transpose a more interesting matrix that allows us to track | 
| 725 |     // exactly where each source element ends up. | 
| 726 |     QMatrix2x2 m3(uniqueValues2); | 
| 727 |     QMatrix2x2 m4 = m3.transposed(); | 
| 728 |     QVERIFY(isSame(m4, transposedValues2)); | 
| 729 |  | 
| 730 |     // Transpose in-place, just to check that the compiler is sane. | 
| 731 |     m3 = m3.transposed(); | 
| 732 |     QVERIFY(isSame(m3, transposedValues2)); | 
| 733 | } | 
| 734 |  | 
| 735 | // Test matrix 3x3 transpose operations. | 
| 736 | void tst_QMatrixNxN::transposed3x3() | 
| 737 | { | 
| 738 |     // Transposing the identity should result in the identity. | 
| 739 |     QMatrix3x3 m1; | 
| 740 |     QMatrix3x3 m2 = m1.transposed(); | 
| 741 |     QVERIFY(isIdentity(m2)); | 
| 742 |  | 
| 743 |     // Transpose a more interesting matrix that allows us to track | 
| 744 |     // exactly where each source element ends up. | 
| 745 |     QMatrix3x3 m3(uniqueValues3); | 
| 746 |     QMatrix3x3 m4 = m3.transposed(); | 
| 747 |     QVERIFY(isSame(m4, transposedValues3)); | 
| 748 |  | 
| 749 |     // Transpose in-place, just to check that the compiler is sane. | 
| 750 |     m3 = m3.transposed(); | 
| 751 |     QVERIFY(isSame(m3, transposedValues3)); | 
| 752 | } | 
| 753 |  | 
| 754 | // Test matrix 4x4 transpose operations. | 
| 755 | void tst_QMatrixNxN::transposed4x4() | 
| 756 | { | 
| 757 |     // Transposing the identity should result in the identity. | 
| 758 |     QMatrix4x4 m1; | 
| 759 |     QMatrix4x4 m2 = m1.transposed(); | 
| 760 |     QVERIFY(isIdentity(m2)); | 
| 761 |  | 
| 762 |     // Transpose a more interesting matrix that allows us to track | 
| 763 |     // exactly where each source element ends up. | 
| 764 |     QMatrix4x4 m3(uniqueValues4); | 
| 765 |     QMatrix4x4 m4 = m3.transposed(); | 
| 766 |     QVERIFY(isSame(m4, transposedValues4)); | 
| 767 |  | 
| 768 |     // Transpose in-place, just to check that the compiler is sane. | 
| 769 |     m3 = m3.transposed(); | 
| 770 |     QVERIFY(isSame(m3, transposedValues4)); | 
| 771 | } | 
| 772 |  | 
| 773 | // Test matrix 4x3 transpose operations. | 
| 774 | void tst_QMatrixNxN::transposed4x3() | 
| 775 | { | 
| 776 |     QMatrix4x3 m3(uniqueValues4x3); | 
| 777 |     QMatrix3x4 m4 = m3.transposed(); | 
| 778 |     float values[12]; | 
| 779 |     m4.copyDataTo(values); | 
| 780 |     for (int index = 0; index < 12; ++index) | 
| 781 |         QCOMPARE(values[index], transposedValues3x4[index]); | 
| 782 | } | 
| 783 |  | 
| 784 | // Test matrix addition for 2x2 matrices. | 
| 785 | void tst_QMatrixNxN::add2x2_data() | 
| 786 | { | 
| 787 |     QTest::addColumn<void *>(name: "m1Values" ); | 
| 788 |     QTest::addColumn<void *>(name: "m2Values" ); | 
| 789 |     QTest::addColumn<void *>(name: "m3Values" ); | 
| 790 |  | 
| 791 |     QTest::newRow(dataTag: "null" ) | 
| 792 |         << (void *)nullValues2 << (void *)nullValues2 << (void *)nullValues2; | 
| 793 |  | 
| 794 |     QTest::newRow(dataTag: "identity/null" ) | 
| 795 |         << (void *)identityValues2 << (void *)nullValues2 << (void *)identityValues2; | 
| 796 |  | 
| 797 |     QTest::newRow(dataTag: "identity/identity" ) | 
| 798 |         << (void *)identityValues2 << (void *)identityValues2 << (void *)doubleIdentity2; | 
| 799 |  | 
| 800 |     static float const sumValues[16] = | 
| 801 |         {2.0f, 7.0f, | 
| 802 |          7.0f, 12.0f}; | 
| 803 |     QTest::newRow(dataTag: "unique" ) | 
| 804 |         << (void *)uniqueValues2 << (void *)transposedValues2 << (void *)sumValues; | 
| 805 | } | 
| 806 | void tst_QMatrixNxN::add2x2() | 
| 807 | { | 
| 808 |     QFETCH(void *, m1Values); | 
| 809 |     QFETCH(void *, m2Values); | 
| 810 |     QFETCH(void *, m3Values); | 
| 811 |  | 
| 812 |     QMatrix2x2 m1((const float *)m1Values); | 
| 813 |     QMatrix2x2 m2((const float *)m2Values); | 
| 814 |  | 
| 815 |     QMatrix2x2 m4(m1); | 
| 816 |     m4 += m2; | 
| 817 |     QVERIFY(isSame(m4, (const float *)m3Values)); | 
| 818 |  | 
| 819 |     QMatrix2x2 m5; | 
| 820 |     m5 = m1 + m2; | 
| 821 |     QVERIFY(isSame(m5, (const float *)m3Values)); | 
| 822 | } | 
| 823 |  | 
| 824 | // Test matrix addition for 3x3 matrices. | 
| 825 | void tst_QMatrixNxN::add3x3_data() | 
| 826 | { | 
| 827 |     QTest::addColumn<void *>(name: "m1Values" ); | 
| 828 |     QTest::addColumn<void *>(name: "m2Values" ); | 
| 829 |     QTest::addColumn<void *>(name: "m3Values" ); | 
| 830 |  | 
| 831 |     QTest::newRow(dataTag: "null" ) | 
| 832 |         << (void *)nullValues3 << (void *)nullValues3 << (void *)nullValues3; | 
| 833 |  | 
| 834 |     QTest::newRow(dataTag: "identity/null" ) | 
| 835 |         << (void *)identityValues3 << (void *)nullValues3 << (void *)identityValues3; | 
| 836 |  | 
| 837 |     QTest::newRow(dataTag: "identity/identity" ) | 
| 838 |         << (void *)identityValues3 << (void *)identityValues3 << (void *)doubleIdentity3; | 
| 839 |  | 
| 840 |     static float const sumValues[16] = | 
| 841 |         {2.0f, 7.0f, 12.0f, | 
| 842 |          7.0f, 12.0f, 17.0f, | 
| 843 |          12.0f, 17.0f, 22.0f}; | 
| 844 |     QTest::newRow(dataTag: "unique" ) | 
| 845 |         << (void *)uniqueValues3 << (void *)transposedValues3 << (void *)sumValues; | 
| 846 | } | 
| 847 | void tst_QMatrixNxN::add3x3() | 
| 848 | { | 
| 849 |     QFETCH(void *, m1Values); | 
| 850 |     QFETCH(void *, m2Values); | 
| 851 |     QFETCH(void *, m3Values); | 
| 852 |  | 
| 853 |     QMatrix3x3 m1((const float *)m1Values); | 
| 854 |     QMatrix3x3 m2((const float *)m2Values); | 
| 855 |  | 
| 856 |     QMatrix3x3 m4(m1); | 
| 857 |     m4 += m2; | 
| 858 |     QVERIFY(isSame(m4, (const float *)m3Values)); | 
| 859 |  | 
| 860 |     QMatrix3x3 m5; | 
| 861 |     m5 = m1 + m2; | 
| 862 |     QVERIFY(isSame(m5, (const float *)m3Values)); | 
| 863 | } | 
| 864 |  | 
| 865 | // Test matrix addition for 4x4 matrices. | 
| 866 | void tst_QMatrixNxN::add4x4_data() | 
| 867 | { | 
| 868 |     QTest::addColumn<void *>(name: "m1Values" ); | 
| 869 |     QTest::addColumn<void *>(name: "m2Values" ); | 
| 870 |     QTest::addColumn<void *>(name: "m3Values" ); | 
| 871 |  | 
| 872 |     QTest::newRow(dataTag: "null" ) | 
| 873 |         << (void *)nullValues4 << (void *)nullValues4 << (void *)nullValues4; | 
| 874 |  | 
| 875 |     QTest::newRow(dataTag: "identity/null" ) | 
| 876 |         << (void *)identityValues4 << (void *)nullValues4 << (void *)identityValues4; | 
| 877 |  | 
| 878 |     QTest::newRow(dataTag: "identity/identity" ) | 
| 879 |         << (void *)identityValues4 << (void *)identityValues4 << (void *)doubleIdentity4; | 
| 880 |  | 
| 881 |     static float const sumValues[16] = | 
| 882 |         {2.0f, 7.0f, 12.0f, 17.0f, | 
| 883 |          7.0f, 12.0f, 17.0f, 22.0f, | 
| 884 |          12.0f, 17.0f, 22.0f, 27.0f, | 
| 885 |          17.0f, 22.0f, 27.0f, 32.0f}; | 
| 886 |     QTest::newRow(dataTag: "unique" ) | 
| 887 |         << (void *)uniqueValues4 << (void *)transposedValues4 << (void *)sumValues; | 
| 888 | } | 
| 889 | void tst_QMatrixNxN::add4x4() | 
| 890 | { | 
| 891 |     QFETCH(void *, m1Values); | 
| 892 |     QFETCH(void *, m2Values); | 
| 893 |     QFETCH(void *, m3Values); | 
| 894 |  | 
| 895 |     QMatrix4x4 m1((const float *)m1Values); | 
| 896 |     QMatrix4x4 m2((const float *)m2Values); | 
| 897 |  | 
| 898 |     QMatrix4x4 m4(m1); | 
| 899 |     m4 += m2; | 
| 900 |     QVERIFY(isSame(m4, (const float *)m3Values)); | 
| 901 |  | 
| 902 |     QMatrix4x4 m5; | 
| 903 |     m5 = m1 + m2; | 
| 904 |     QVERIFY(isSame(m5, (const float *)m3Values)); | 
| 905 | } | 
| 906 |  | 
| 907 | // Test matrix addition for 4x3 matrices. | 
| 908 | void tst_QMatrixNxN::add4x3_data() | 
| 909 | { | 
| 910 |     QTest::addColumn<void *>(name: "m1Values" ); | 
| 911 |     QTest::addColumn<void *>(name: "m2Values" ); | 
| 912 |     QTest::addColumn<void *>(name: "m3Values" ); | 
| 913 |  | 
| 914 |     QTest::newRow(dataTag: "null" ) | 
| 915 |         << (void *)nullValues4x3 << (void *)nullValues4x3 << (void *)nullValues4x3; | 
| 916 |  | 
| 917 |     QTest::newRow(dataTag: "identity/null" ) | 
| 918 |         << (void *)identityValues4x3 << (void *)nullValues4x3 << (void *)identityValues4x3; | 
| 919 |  | 
| 920 |     QTest::newRow(dataTag: "identity/identity" ) | 
| 921 |         << (void *)identityValues4x3 << (void *)identityValues4x3 << (void *)doubleIdentity4x3; | 
| 922 |  | 
| 923 |     static float const sumValues[16] = | 
| 924 |         {2.0f, 7.0f, 12.0f, 6.0f, | 
| 925 |          11.0f, 16.0f, 10.0f, 15.0f, | 
| 926 |          20.0f, 14.0f, 19.0f, 24.0f}; | 
| 927 |     QTest::newRow(dataTag: "unique" ) | 
| 928 |         << (void *)uniqueValues4x3 << (void *)transposedValues3x4 << (void *)sumValues; | 
| 929 | } | 
| 930 | void tst_QMatrixNxN::add4x3() | 
| 931 | { | 
| 932 |     QFETCH(void *, m1Values); | 
| 933 |     QFETCH(void *, m2Values); | 
| 934 |     QFETCH(void *, m3Values); | 
| 935 |  | 
| 936 |     QMatrix4x3 m1((const float *)m1Values); | 
| 937 |     QMatrix4x3 m2((const float *)m2Values); | 
| 938 |  | 
| 939 |     QMatrix4x3 m4(m1); | 
| 940 |     m4 += m2; | 
| 941 |     QVERIFY(isSame(m4, (const float *)m3Values)); | 
| 942 |  | 
| 943 |     QMatrix4x3 m5; | 
| 944 |     m5 = m1 + m2; | 
| 945 |     QVERIFY(isSame(m5, (const float *)m3Values)); | 
| 946 | } | 
| 947 |  | 
| 948 | // Test matrix subtraction for 2x2 matrices. | 
| 949 | void tst_QMatrixNxN::subtract2x2_data() | 
| 950 | { | 
| 951 |     // Use the same test cases as the add test. | 
| 952 |     add2x2_data(); | 
| 953 | } | 
| 954 | void tst_QMatrixNxN::subtract2x2() | 
| 955 | { | 
| 956 |     QFETCH(void *, m1Values); | 
| 957 |     QFETCH(void *, m2Values); | 
| 958 |     QFETCH(void *, m3Values); | 
| 959 |  | 
| 960 |     QMatrix2x2 m1((const float *)m1Values); | 
| 961 |     QMatrix2x2 m2((const float *)m2Values); | 
| 962 |     QMatrix2x2 m3((const float *)m3Values); | 
| 963 |  | 
| 964 |     QMatrix2x2 m4(m3); | 
| 965 |     m4 -= m1; | 
| 966 |     QVERIFY(isSame(m4, (const float *)m2Values)); | 
| 967 |  | 
| 968 |     QMatrix2x2 m5; | 
| 969 |     m5 = m3 - m1; | 
| 970 |     QVERIFY(isSame(m5, (const float *)m2Values)); | 
| 971 |  | 
| 972 |     QMatrix2x2 m6(m3); | 
| 973 |     m6 -= m2; | 
| 974 |     QVERIFY(isSame(m6, (const float *)m1Values)); | 
| 975 |  | 
| 976 |     QMatrix2x2 m7; | 
| 977 |     m7 = m3 - m2; | 
| 978 |     QVERIFY(isSame(m7, (const float *)m1Values)); | 
| 979 | } | 
| 980 |  | 
| 981 | // Test matrix subtraction for 3x3 matrices. | 
| 982 | void tst_QMatrixNxN::subtract3x3_data() | 
| 983 | { | 
| 984 |     // Use the same test cases as the add test. | 
| 985 |     add3x3_data(); | 
| 986 | } | 
| 987 | void tst_QMatrixNxN::subtract3x3() | 
| 988 | { | 
| 989 |     QFETCH(void *, m1Values); | 
| 990 |     QFETCH(void *, m2Values); | 
| 991 |     QFETCH(void *, m3Values); | 
| 992 |  | 
| 993 |     QMatrix3x3 m1((const float *)m1Values); | 
| 994 |     QMatrix3x3 m2((const float *)m2Values); | 
| 995 |     QMatrix3x3 m3((const float *)m3Values); | 
| 996 |  | 
| 997 |     QMatrix3x3 m4(m3); | 
| 998 |     m4 -= m1; | 
| 999 |     QVERIFY(isSame(m4, (const float *)m2Values)); | 
| 1000 |  | 
| 1001 |     QMatrix3x3 m5; | 
| 1002 |     m5 = m3 - m1; | 
| 1003 |     QVERIFY(isSame(m5, (const float *)m2Values)); | 
| 1004 |  | 
| 1005 |     QMatrix3x3 m6(m3); | 
| 1006 |     m6 -= m2; | 
| 1007 |     QVERIFY(isSame(m6, (const float *)m1Values)); | 
| 1008 |  | 
| 1009 |     QMatrix3x3 m7; | 
| 1010 |     m7 = m3 - m2; | 
| 1011 |     QVERIFY(isSame(m7, (const float *)m1Values)); | 
| 1012 | } | 
| 1013 |  | 
| 1014 | // Test matrix subtraction for 4x4 matrices. | 
| 1015 | void tst_QMatrixNxN::subtract4x4_data() | 
| 1016 | { | 
| 1017 |     // Use the same test cases as the add test. | 
| 1018 |     add4x4_data(); | 
| 1019 | } | 
| 1020 | void tst_QMatrixNxN::subtract4x4() | 
| 1021 | { | 
| 1022 |     QFETCH(void *, m1Values); | 
| 1023 |     QFETCH(void *, m2Values); | 
| 1024 |     QFETCH(void *, m3Values); | 
| 1025 |  | 
| 1026 |     QMatrix4x4 m1((const float *)m1Values); | 
| 1027 |     QMatrix4x4 m2((const float *)m2Values); | 
| 1028 |     QMatrix4x4 m3((const float *)m3Values); | 
| 1029 |  | 
| 1030 |     QMatrix4x4 m4(m3); | 
| 1031 |     m4 -= m1; | 
| 1032 |     QVERIFY(isSame(m4, (const float *)m2Values)); | 
| 1033 |  | 
| 1034 |     QMatrix4x4 m5; | 
| 1035 |     m5 = m3 - m1; | 
| 1036 |     QVERIFY(isSame(m5, (const float *)m2Values)); | 
| 1037 |  | 
| 1038 |     QMatrix4x4 m6(m3); | 
| 1039 |     m6 -= m2; | 
| 1040 |     QVERIFY(isSame(m6, (const float *)m1Values)); | 
| 1041 |  | 
| 1042 |     QMatrix4x4 m7; | 
| 1043 |     m7 = m3 - m2; | 
| 1044 |     QVERIFY(isSame(m7, (const float *)m1Values)); | 
| 1045 | } | 
| 1046 |  | 
| 1047 | // Test matrix subtraction for 4x3 matrices. | 
| 1048 | void tst_QMatrixNxN::subtract4x3_data() | 
| 1049 | { | 
| 1050 |     // Use the same test cases as the add test. | 
| 1051 |     add4x3_data(); | 
| 1052 | } | 
| 1053 | void tst_QMatrixNxN::subtract4x3() | 
| 1054 | { | 
| 1055 |     QFETCH(void *, m1Values); | 
| 1056 |     QFETCH(void *, m2Values); | 
| 1057 |     QFETCH(void *, m3Values); | 
| 1058 |  | 
| 1059 |     QMatrix4x3 m1((const float *)m1Values); | 
| 1060 |     QMatrix4x3 m2((const float *)m2Values); | 
| 1061 |     QMatrix4x3 m3((const float *)m3Values); | 
| 1062 |  | 
| 1063 |     QMatrix4x3 m4(m3); | 
| 1064 |     m4 -= m1; | 
| 1065 |     QVERIFY(isSame(m4, (const float *)m2Values)); | 
| 1066 |  | 
| 1067 |     QMatrix4x3 m5; | 
| 1068 |     m5 = m3 - m1; | 
| 1069 |     QVERIFY(isSame(m5, (const float *)m2Values)); | 
| 1070 |  | 
| 1071 |     QMatrix4x3 m6(m3); | 
| 1072 |     m6 -= m2; | 
| 1073 |     QVERIFY(isSame(m6, (const float *)m1Values)); | 
| 1074 |  | 
| 1075 |     QMatrix4x3 m7; | 
| 1076 |     m7 = m3 - m2; | 
| 1077 |     QVERIFY(isSame(m7, (const float *)m1Values)); | 
| 1078 | } | 
| 1079 |  | 
| 1080 | // Test matrix multiplication for 2x2 matrices. | 
| 1081 | void tst_QMatrixNxN::multiply2x2_data() | 
| 1082 | { | 
| 1083 |     QTest::addColumn<void *>(name: "m1Values" ); | 
| 1084 |     QTest::addColumn<void *>(name: "m2Values" ); | 
| 1085 |     QTest::addColumn<void *>(name: "m3Values" ); | 
| 1086 |  | 
| 1087 |     QTest::newRow(dataTag: "null" ) | 
| 1088 |         << (void *)nullValues2 << (void *)nullValues2 << (void *)nullValues2; | 
| 1089 |  | 
| 1090 |     QTest::newRow(dataTag: "null/unique" ) | 
| 1091 |         << (void *)nullValues2 << (void *)uniqueValues2 << (void *)nullValues2; | 
| 1092 |  | 
| 1093 |     QTest::newRow(dataTag: "unique/null" ) | 
| 1094 |         << (void *)uniqueValues2 << (void *)nullValues2 << (void *)nullValues2; | 
| 1095 |  | 
| 1096 |     QTest::newRow(dataTag: "unique/identity" ) | 
| 1097 |         << (void *)uniqueValues2 << (void *)identityValues2 << (void *)uniqueValues2; | 
| 1098 |  | 
| 1099 |     QTest::newRow(dataTag: "identity/unique" ) | 
| 1100 |         << (void *)identityValues2 << (void *)uniqueValues2 << (void *)uniqueValues2; | 
| 1101 |  | 
| 1102 |     static float uniqueResult[4]; | 
| 1103 |     for (int row = 0; row < 2; ++row) { | 
| 1104 |         for (int col = 0; col < 2; ++col) { | 
| 1105 |             float sum = 0.0f; | 
| 1106 |             for (int j = 0; j < 2; ++j) | 
| 1107 |                 sum += uniqueValues2[row * 2 + j] * transposedValues2[j * 2 + col]; | 
| 1108 |             uniqueResult[row * 2 + col] = sum; | 
| 1109 |         } | 
| 1110 |     } | 
| 1111 |  | 
| 1112 |     QTest::newRow(dataTag: "unique/transposed" ) | 
| 1113 |         << (void *)uniqueValues2 << (void *)transposedValues2 << (void *)uniqueResult; | 
| 1114 | } | 
| 1115 | void tst_QMatrixNxN::multiply2x2() | 
| 1116 | { | 
| 1117 |     QFETCH(void *, m1Values); | 
| 1118 |     QFETCH(void *, m2Values); | 
| 1119 |     QFETCH(void *, m3Values); | 
| 1120 |  | 
| 1121 |     QMatrix2x2 m1((const float *)m1Values); | 
| 1122 |     QMatrix2x2 m2((const float *)m2Values); | 
| 1123 |  | 
| 1124 |     QMatrix2x2 m5; | 
| 1125 |     m5 = m1 * m2; | 
| 1126 |     QVERIFY(isSame(m5, (const float *)m3Values)); | 
| 1127 | } | 
| 1128 |  | 
| 1129 | // Test matrix multiplication for 3x3 matrices. | 
| 1130 | void tst_QMatrixNxN::multiply3x3_data() | 
| 1131 | { | 
| 1132 |     QTest::addColumn<void *>(name: "m1Values" ); | 
| 1133 |     QTest::addColumn<void *>(name: "m2Values" ); | 
| 1134 |     QTest::addColumn<void *>(name: "m3Values" ); | 
| 1135 |  | 
| 1136 |     QTest::newRow(dataTag: "null" ) | 
| 1137 |         << (void *)nullValues3 << (void *)nullValues3 << (void *)nullValues3; | 
| 1138 |  | 
| 1139 |     QTest::newRow(dataTag: "null/unique" ) | 
| 1140 |         << (void *)nullValues3 << (void *)uniqueValues3 << (void *)nullValues3; | 
| 1141 |  | 
| 1142 |     QTest::newRow(dataTag: "unique/null" ) | 
| 1143 |         << (void *)uniqueValues3 << (void *)nullValues3 << (void *)nullValues3; | 
| 1144 |  | 
| 1145 |     QTest::newRow(dataTag: "unique/identity" ) | 
| 1146 |         << (void *)uniqueValues3 << (void *)identityValues3 << (void *)uniqueValues3; | 
| 1147 |  | 
| 1148 |     QTest::newRow(dataTag: "identity/unique" ) | 
| 1149 |         << (void *)identityValues3 << (void *)uniqueValues3 << (void *)uniqueValues3; | 
| 1150 |  | 
| 1151 |     static float uniqueResult[9]; | 
| 1152 |     for (int row = 0; row < 3; ++row) { | 
| 1153 |         for (int col = 0; col < 3; ++col) { | 
| 1154 |             float sum = 0.0f; | 
| 1155 |             for (int j = 0; j < 3; ++j) | 
| 1156 |                 sum += uniqueValues3[row * 3 + j] * transposedValues3[j * 3 + col]; | 
| 1157 |             uniqueResult[row * 3 + col] = sum; | 
| 1158 |         } | 
| 1159 |     } | 
| 1160 |  | 
| 1161 |     QTest::newRow(dataTag: "unique/transposed" ) | 
| 1162 |         << (void *)uniqueValues3 << (void *)transposedValues3 << (void *)uniqueResult; | 
| 1163 | } | 
| 1164 | void tst_QMatrixNxN::multiply3x3() | 
| 1165 | { | 
| 1166 |     QFETCH(void *, m1Values); | 
| 1167 |     QFETCH(void *, m2Values); | 
| 1168 |     QFETCH(void *, m3Values); | 
| 1169 |  | 
| 1170 |     QMatrix3x3 m1((const float *)m1Values); | 
| 1171 |     QMatrix3x3 m2((const float *)m2Values); | 
| 1172 |  | 
| 1173 |     QMatrix3x3 m5; | 
| 1174 |     m5 = m1 * m2; | 
| 1175 |     QVERIFY(isSame(m5, (const float *)m3Values)); | 
| 1176 | } | 
| 1177 |  | 
| 1178 | // Test matrix multiplication for 4x4 matrices. | 
| 1179 | void tst_QMatrixNxN::multiply4x4_data() | 
| 1180 | { | 
| 1181 |     QTest::addColumn<void *>(name: "m1Values" ); | 
| 1182 |     QTest::addColumn<void *>(name: "m2Values" ); | 
| 1183 |     QTest::addColumn<void *>(name: "m3Values" ); | 
| 1184 |  | 
| 1185 |     QTest::newRow(dataTag: "null" ) | 
| 1186 |         << (void *)nullValues4 << (void *)nullValues4 << (void *)nullValues4; | 
| 1187 |  | 
| 1188 |     QTest::newRow(dataTag: "null/unique" ) | 
| 1189 |         << (void *)nullValues4 << (void *)uniqueValues4 << (void *)nullValues4; | 
| 1190 |  | 
| 1191 |     QTest::newRow(dataTag: "unique/null" ) | 
| 1192 |         << (void *)uniqueValues4 << (void *)nullValues4 << (void *)nullValues4; | 
| 1193 |  | 
| 1194 |     QTest::newRow(dataTag: "unique/identity" ) | 
| 1195 |         << (void *)uniqueValues4 << (void *)identityValues4 << (void *)uniqueValues4; | 
| 1196 |  | 
| 1197 |     QTest::newRow(dataTag: "identity/unique" ) | 
| 1198 |         << (void *)identityValues4 << (void *)uniqueValues4 << (void *)uniqueValues4; | 
| 1199 |  | 
| 1200 |     static float uniqueResult[16]; | 
| 1201 |     for (int row = 0; row < 4; ++row) { | 
| 1202 |         for (int col = 0; col < 4; ++col) { | 
| 1203 |             float sum = 0.0f; | 
| 1204 |             for (int j = 0; j < 4; ++j) | 
| 1205 |                 sum += uniqueValues4[row * 4 + j] * transposedValues4[j * 4 + col]; | 
| 1206 |             uniqueResult[row * 4 + col] = sum; | 
| 1207 |         } | 
| 1208 |     } | 
| 1209 |  | 
| 1210 |     QTest::newRow(dataTag: "unique/transposed" ) | 
| 1211 |         << (void *)uniqueValues4 << (void *)transposedValues4 << (void *)uniqueResult; | 
| 1212 | } | 
| 1213 | void tst_QMatrixNxN::multiply4x4() | 
| 1214 | { | 
| 1215 |     QFETCH(void *, m1Values); | 
| 1216 |     QFETCH(void *, m2Values); | 
| 1217 |     QFETCH(void *, m3Values); | 
| 1218 |  | 
| 1219 |     QMatrix4x4 m1((const float *)m1Values); | 
| 1220 |     QMatrix4x4 m2((const float *)m2Values); | 
| 1221 |  | 
| 1222 |     QMatrix4x4 m4; | 
| 1223 |     m4 = m1; | 
| 1224 |     m4 *= m2; | 
| 1225 |     QVERIFY(isSame(m4, (const float *)m3Values)); | 
| 1226 |  | 
| 1227 |     QMatrix4x4 m5; | 
| 1228 |     m5 = m1 * m2; | 
| 1229 |     QVERIFY(isSame(m5, (const float *)m3Values)); | 
| 1230 |  | 
| 1231 |     QMatrix4x4 m1xm1 = m1 * m1; | 
| 1232 |     m1 *= m1; | 
| 1233 |     QCOMPARE(m1, m1xm1); | 
| 1234 | } | 
| 1235 |  | 
| 1236 | // Test matrix multiplication for 4x3 matrices. | 
| 1237 | void tst_QMatrixNxN::multiply4x3_data() | 
| 1238 | { | 
| 1239 |     QTest::addColumn<void *>(name: "m1Values" ); | 
| 1240 |     QTest::addColumn<void *>(name: "m2Values" ); | 
| 1241 |     QTest::addColumn<void *>(name: "m3Values" ); | 
| 1242 |  | 
| 1243 |     QTest::newRow(dataTag: "null" ) | 
| 1244 |         << (void *)nullValues4x3 << (void *)nullValues4x3 << (void *)nullValues3; | 
| 1245 |  | 
| 1246 |     QTest::newRow(dataTag: "null/unique" ) | 
| 1247 |         << (void *)nullValues4x3 << (void *)uniqueValues4x3 << (void *)nullValues3; | 
| 1248 |  | 
| 1249 |     QTest::newRow(dataTag: "unique/null" ) | 
| 1250 |         << (void *)uniqueValues4x3 << (void *)nullValues4x3 << (void *)nullValues3; | 
| 1251 |  | 
| 1252 |     static float uniqueResult[9]; | 
| 1253 |     for (int row = 0; row < 3; ++row) { | 
| 1254 |         for (int col = 0; col < 3; ++col) { | 
| 1255 |             float sum = 0.0f; | 
| 1256 |             for (int j = 0; j < 4; ++j) | 
| 1257 |                 sum += uniqueValues4x3[row * 4 + j] * transposedValues3x4[j * 3 + col]; | 
| 1258 |             uniqueResult[row * 3 + col] = sum; | 
| 1259 |         } | 
| 1260 |     } | 
| 1261 |  | 
| 1262 |     QTest::newRow(dataTag: "unique/transposed" ) | 
| 1263 |         << (void *)uniqueValues4x3 << (void *)transposedValues3x4 << (void *)uniqueResult; | 
| 1264 | } | 
| 1265 | void tst_QMatrixNxN::multiply4x3() | 
| 1266 | { | 
| 1267 |     QFETCH(void *, m1Values); | 
| 1268 |     QFETCH(void *, m2Values); | 
| 1269 |     QFETCH(void *, m3Values); | 
| 1270 |  | 
| 1271 |     QMatrix4x3 m1((const float *)m1Values); | 
| 1272 |     QMatrix3x4 m2((const float *)m2Values); | 
| 1273 |  | 
| 1274 |     QGenericMatrix<3, 3, float> m4; | 
| 1275 |     m4 = m1 * m2; | 
| 1276 |     float values[9]; | 
| 1277 |     m4.copyDataTo(values); | 
| 1278 |     for (int index = 0; index < 9; ++index) | 
| 1279 |         QCOMPARE(values[index], ((const float *)m3Values)[index]); | 
| 1280 | } | 
| 1281 |  | 
| 1282 | // Test matrix multiplication by a factor for 2x2 matrices. | 
| 1283 | void tst_QMatrixNxN::multiplyFactor2x2_data() | 
| 1284 | { | 
| 1285 |     QTest::addColumn<void *>(name: "m1Values" ); | 
| 1286 |     QTest::addColumn<float>(name: "factor" ); | 
| 1287 |     QTest::addColumn<void *>(name: "m2Values" ); | 
| 1288 |  | 
| 1289 |     QTest::newRow(dataTag: "null" ) | 
| 1290 |         << (void *)nullValues2 << (float)1.0f << (void *)nullValues2; | 
| 1291 |  | 
| 1292 |     QTest::newRow(dataTag: "double identity" ) | 
| 1293 |         << (void *)identityValues2 << (float)2.0f << (void *)doubleIdentity2; | 
| 1294 |  | 
| 1295 |     static float const values[16] = | 
| 1296 |         {1.0f, 2.0f, | 
| 1297 |          5.0f, 6.0f}; | 
| 1298 |     static float const doubleValues[16] = | 
| 1299 |         {2.0f, 4.0f, | 
| 1300 |          10.0f, 12.0f}; | 
| 1301 |     static float const negDoubleValues[16] = | 
| 1302 |         {-2.0f, -4.0f, | 
| 1303 |          -10.0f, -12.0f}; | 
| 1304 |  | 
| 1305 |     QTest::newRow(dataTag: "unique" ) | 
| 1306 |         << (void *)values << (float)2.0f << (void *)doubleValues; | 
| 1307 |  | 
| 1308 |     QTest::newRow(dataTag: "neg" ) | 
| 1309 |         << (void *)values << (float)-2.0f << (void *)negDoubleValues; | 
| 1310 |  | 
| 1311 |     QTest::newRow(dataTag: "zero" ) | 
| 1312 |         << (void *)values << (float)0.0f << (void *)nullValues4; | 
| 1313 | } | 
| 1314 | void tst_QMatrixNxN::multiplyFactor2x2() | 
| 1315 | { | 
| 1316 |     QFETCH(void *, m1Values); | 
| 1317 |     QFETCH(float, factor); | 
| 1318 |     QFETCH(void *, m2Values); | 
| 1319 |  | 
| 1320 |     QMatrix2x2 m1((const float *)m1Values); | 
| 1321 |  | 
| 1322 |     QMatrix2x2 m3; | 
| 1323 |     m3 = m1; | 
| 1324 |     m3 *= factor; | 
| 1325 |     QVERIFY(isSame(m3, (const float *)m2Values)); | 
| 1326 |  | 
| 1327 |     QMatrix2x2 m4; | 
| 1328 |     m4 = m1 * factor; | 
| 1329 |     QVERIFY(isSame(m4, (const float *)m2Values)); | 
| 1330 |  | 
| 1331 |     QMatrix2x2 m5; | 
| 1332 |     m5 = factor * m1; | 
| 1333 |     QVERIFY(isSame(m5, (const float *)m2Values)); | 
| 1334 | } | 
| 1335 |  | 
| 1336 | // Test matrix multiplication by a factor for 3x3 matrices. | 
| 1337 | void tst_QMatrixNxN::multiplyFactor3x3_data() | 
| 1338 | { | 
| 1339 |     QTest::addColumn<void *>(name: "m1Values" ); | 
| 1340 |     QTest::addColumn<float>(name: "factor" ); | 
| 1341 |     QTest::addColumn<void *>(name: "m2Values" ); | 
| 1342 |  | 
| 1343 |     QTest::newRow(dataTag: "null" ) | 
| 1344 |         << (void *)nullValues3 << (float)1.0f << (void *)nullValues3; | 
| 1345 |  | 
| 1346 |     QTest::newRow(dataTag: "double identity" ) | 
| 1347 |         << (void *)identityValues3 << (float)2.0f << (void *)doubleIdentity3; | 
| 1348 |  | 
| 1349 |     static float const values[16] = | 
| 1350 |         {1.0f, 2.0f, 3.0f, | 
| 1351 |          5.0f, 6.0f, 7.0f, | 
| 1352 |          9.0f, 10.0f, 11.0f}; | 
| 1353 |     static float const doubleValues[16] = | 
| 1354 |         {2.0f, 4.0f, 6.0f, | 
| 1355 |          10.0f, 12.0f, 14.0f, | 
| 1356 |          18.0f, 20.0f, 22.0f}; | 
| 1357 |     static float const negDoubleValues[16] = | 
| 1358 |         {-2.0f, -4.0f, -6.0f, | 
| 1359 |          -10.0f, -12.0f, -14.0f, | 
| 1360 |          -18.0f, -20.0f, -22.0f}; | 
| 1361 |  | 
| 1362 |     QTest::newRow(dataTag: "unique" ) | 
| 1363 |         << (void *)values << (float)2.0f << (void *)doubleValues; | 
| 1364 |  | 
| 1365 |     QTest::newRow(dataTag: "neg" ) | 
| 1366 |         << (void *)values << (float)-2.0f << (void *)negDoubleValues; | 
| 1367 |  | 
| 1368 |     QTest::newRow(dataTag: "zero" ) | 
| 1369 |         << (void *)values << (float)0.0f << (void *)nullValues4; | 
| 1370 | } | 
| 1371 | void tst_QMatrixNxN::multiplyFactor3x3() | 
| 1372 | { | 
| 1373 |     QFETCH(void *, m1Values); | 
| 1374 |     QFETCH(float, factor); | 
| 1375 |     QFETCH(void *, m2Values); | 
| 1376 |  | 
| 1377 |     QMatrix3x3 m1((const float *)m1Values); | 
| 1378 |  | 
| 1379 |     QMatrix3x3 m3; | 
| 1380 |     m3 = m1; | 
| 1381 |     m3 *= factor; | 
| 1382 |     QVERIFY(isSame(m3, (const float *)m2Values)); | 
| 1383 |  | 
| 1384 |     QMatrix3x3 m4; | 
| 1385 |     m4 = m1 * factor; | 
| 1386 |     QVERIFY(isSame(m4, (const float *)m2Values)); | 
| 1387 |  | 
| 1388 |     QMatrix3x3 m5; | 
| 1389 |     m5 = factor * m1; | 
| 1390 |     QVERIFY(isSame(m5, (const float *)m2Values)); | 
| 1391 | } | 
| 1392 |  | 
| 1393 | // Test matrix multiplication by a factor for 4x4 matrices. | 
| 1394 | void tst_QMatrixNxN::multiplyFactor4x4_data() | 
| 1395 | { | 
| 1396 |     QTest::addColumn<void *>(name: "m1Values" ); | 
| 1397 |     QTest::addColumn<float>(name: "factor" ); | 
| 1398 |     QTest::addColumn<void *>(name: "m2Values" ); | 
| 1399 |  | 
| 1400 |     QTest::newRow(dataTag: "null" ) | 
| 1401 |         << (void *)nullValues4 << (float)1.0f << (void *)nullValues4; | 
| 1402 |  | 
| 1403 |     QTest::newRow(dataTag: "double identity" ) | 
| 1404 |         << (void *)identityValues4 << (float)2.0f << (void *)doubleIdentity4; | 
| 1405 |  | 
| 1406 |     static float const values[16] = | 
| 1407 |         {1.0f, 2.0f, 3.0f, 4.0f, | 
| 1408 |          5.0f, 6.0f, 7.0f, 8.0f, | 
| 1409 |          9.0f, 10.0f, 11.0f, 12.0f, | 
| 1410 |          13.0f, 14.0f, 15.0f, 16.0f}; | 
| 1411 |     static float const doubleValues[16] = | 
| 1412 |         {2.0f, 4.0f, 6.0f, 8.0f, | 
| 1413 |          10.0f, 12.0f, 14.0f, 16.0f, | 
| 1414 |          18.0f, 20.0f, 22.0f, 24.0f, | 
| 1415 |          26.0f, 28.0f, 30.0f, 32.0f}; | 
| 1416 |     static float const negDoubleValues[16] = | 
| 1417 |         {-2.0f, -4.0f, -6.0f, -8.0f, | 
| 1418 |          -10.0f, -12.0f, -14.0f, -16.0f, | 
| 1419 |          -18.0f, -20.0f, -22.0f, -24.0f, | 
| 1420 |          -26.0f, -28.0f, -30.0f, -32.0f}; | 
| 1421 |  | 
| 1422 |     QTest::newRow(dataTag: "unique" ) | 
| 1423 |         << (void *)values << (float)2.0f << (void *)doubleValues; | 
| 1424 |  | 
| 1425 |     QTest::newRow(dataTag: "neg" ) | 
| 1426 |         << (void *)values << (float)-2.0f << (void *)negDoubleValues; | 
| 1427 |  | 
| 1428 |     QTest::newRow(dataTag: "zero" ) | 
| 1429 |         << (void *)values << (float)0.0f << (void *)nullValues4; | 
| 1430 | } | 
| 1431 | void tst_QMatrixNxN::multiplyFactor4x4() | 
| 1432 | { | 
| 1433 |     QFETCH(void *, m1Values); | 
| 1434 |     QFETCH(float, factor); | 
| 1435 |     QFETCH(void *, m2Values); | 
| 1436 |  | 
| 1437 |     QMatrix4x4 m1((const float *)m1Values); | 
| 1438 |  | 
| 1439 |     QMatrix4x4 m3; | 
| 1440 |     m3 = m1; | 
| 1441 |     m3 *= factor; | 
| 1442 |     QVERIFY(isSame(m3, (const float *)m2Values)); | 
| 1443 |  | 
| 1444 |     QMatrix4x4 m4; | 
| 1445 |     m4 = m1 * factor; | 
| 1446 |     QVERIFY(isSame(m4, (const float *)m2Values)); | 
| 1447 |  | 
| 1448 |     QMatrix4x4 m5; | 
| 1449 |     m5 = factor * m1; | 
| 1450 |     QVERIFY(isSame(m5, (const float *)m2Values)); | 
| 1451 | } | 
| 1452 |  | 
| 1453 | // Test matrix multiplication by a factor for 4x3 matrices. | 
| 1454 | void tst_QMatrixNxN::multiplyFactor4x3_data() | 
| 1455 | { | 
| 1456 |     QTest::addColumn<void *>(name: "m1Values" ); | 
| 1457 |     QTest::addColumn<float>(name: "factor" ); | 
| 1458 |     QTest::addColumn<void *>(name: "m2Values" ); | 
| 1459 |  | 
| 1460 |     QTest::newRow(dataTag: "null" ) | 
| 1461 |         << (void *)nullValues4x3 << (float)1.0f << (void *)nullValues4x3; | 
| 1462 |  | 
| 1463 |     QTest::newRow(dataTag: "double identity" ) | 
| 1464 |         << (void *)identityValues4x3 << (float)2.0f << (void *)doubleIdentity4x3; | 
| 1465 |  | 
| 1466 |     static float const values[12] = | 
| 1467 |         {1.0f, 2.0f, 3.0f, 4.0f, | 
| 1468 |          5.0f, 6.0f, 7.0f, 8.0f, | 
| 1469 |          9.0f, 10.0f, 11.0f, 12.0f}; | 
| 1470 |     static float const doubleValues[12] = | 
| 1471 |         {2.0f, 4.0f, 6.0f, 8.0f, | 
| 1472 |          10.0f, 12.0f, 14.0f, 16.0f, | 
| 1473 |          18.0f, 20.0f, 22.0f, 24.0f}; | 
| 1474 |     static float const negDoubleValues[12] = | 
| 1475 |         {-2.0f, -4.0f, -6.0f, -8.0f, | 
| 1476 |          -10.0f, -12.0f, -14.0f, -16.0f, | 
| 1477 |          -18.0f, -20.0f, -22.0f, -24.0f}; | 
| 1478 |  | 
| 1479 |     QTest::newRow(dataTag: "unique" ) | 
| 1480 |         << (void *)values << (float)2.0f << (void *)doubleValues; | 
| 1481 |  | 
| 1482 |     QTest::newRow(dataTag: "neg" ) | 
| 1483 |         << (void *)values << (float)-2.0f << (void *)negDoubleValues; | 
| 1484 |  | 
| 1485 |     QTest::newRow(dataTag: "zero" ) | 
| 1486 |         << (void *)values << (float)0.0f << (void *)nullValues4x3; | 
| 1487 | } | 
| 1488 | void tst_QMatrixNxN::multiplyFactor4x3() | 
| 1489 | { | 
| 1490 |     QFETCH(void *, m1Values); | 
| 1491 |     QFETCH(float, factor); | 
| 1492 |     QFETCH(void *, m2Values); | 
| 1493 |  | 
| 1494 |     QMatrix4x3 m1((const float *)m1Values); | 
| 1495 |  | 
| 1496 |     QMatrix4x3 m3; | 
| 1497 |     m3 = m1; | 
| 1498 |     m3 *= factor; | 
| 1499 |     QVERIFY(isSame(m3, (const float *)m2Values)); | 
| 1500 |  | 
| 1501 |     QMatrix4x3 m4; | 
| 1502 |     m4 = m1 * factor; | 
| 1503 |     QVERIFY(isSame(m4, (const float *)m2Values)); | 
| 1504 |  | 
| 1505 |     QMatrix4x3 m5; | 
| 1506 |     m5 = factor * m1; | 
| 1507 |     QVERIFY(isSame(m5, (const float *)m2Values)); | 
| 1508 | } | 
| 1509 |  | 
| 1510 | // Test matrix division by a factor for 2x2 matrices. | 
| 1511 | void tst_QMatrixNxN::divideFactor2x2_data() | 
| 1512 | { | 
| 1513 |     // Use the same test cases as the multiplyFactor test. | 
| 1514 |     multiplyFactor2x2_data(); | 
| 1515 | } | 
| 1516 | void tst_QMatrixNxN::divideFactor2x2() | 
| 1517 | { | 
| 1518 |     QFETCH(void *, m1Values); | 
| 1519 |     QFETCH(float, factor); | 
| 1520 |     QFETCH(void *, m2Values); | 
| 1521 |  | 
| 1522 |     if (factor == 0.0f) | 
| 1523 |         return; | 
| 1524 |  | 
| 1525 |     QMatrix2x2 m2((const float *)m2Values); | 
| 1526 |  | 
| 1527 |     QMatrix2x2 m3; | 
| 1528 |     m3 = m2; | 
| 1529 |     m3 /= factor; | 
| 1530 |     QVERIFY(isSame(m3, (const float *)m1Values)); | 
| 1531 |  | 
| 1532 |     QMatrix2x2 m4; | 
| 1533 |     m4 = m2 / factor; | 
| 1534 |     QVERIFY(isSame(m4, (const float *)m1Values)); | 
| 1535 | } | 
| 1536 |  | 
| 1537 | // Test matrix division by a factor for 3x3 matrices. | 
| 1538 | void tst_QMatrixNxN::divideFactor3x3_data() | 
| 1539 | { | 
| 1540 |     // Use the same test cases as the multiplyFactor test. | 
| 1541 |     multiplyFactor3x3_data(); | 
| 1542 | } | 
| 1543 | void tst_QMatrixNxN::divideFactor3x3() | 
| 1544 | { | 
| 1545 |     QFETCH(void *, m1Values); | 
| 1546 |     QFETCH(float, factor); | 
| 1547 |     QFETCH(void *, m2Values); | 
| 1548 |  | 
| 1549 |     if (factor == 0.0f) | 
| 1550 |         return; | 
| 1551 |  | 
| 1552 |     QMatrix3x3 m2((const float *)m2Values); | 
| 1553 |  | 
| 1554 |     QMatrix3x3 m3; | 
| 1555 |     m3 = m2; | 
| 1556 |     m3 /= factor; | 
| 1557 |     QVERIFY(isSame(m3, (const float *)m1Values)); | 
| 1558 |  | 
| 1559 |     QMatrix3x3 m4; | 
| 1560 |     m4 = m2 / factor; | 
| 1561 |     QVERIFY(isSame(m4, (const float *)m1Values)); | 
| 1562 | } | 
| 1563 |  | 
| 1564 | // Test matrix division by a factor for 4x4 matrices. | 
| 1565 | void tst_QMatrixNxN::divideFactor4x4_data() | 
| 1566 | { | 
| 1567 |     // Use the same test cases as the multiplyFactor test. | 
| 1568 |     multiplyFactor4x4_data(); | 
| 1569 | } | 
| 1570 | void tst_QMatrixNxN::divideFactor4x4() | 
| 1571 | { | 
| 1572 |     QFETCH(void *, m1Values); | 
| 1573 |     QFETCH(float, factor); | 
| 1574 |     QFETCH(void *, m2Values); | 
| 1575 |  | 
| 1576 |     if (factor == 0.0f) | 
| 1577 |         return; | 
| 1578 |  | 
| 1579 |     QMatrix4x4 m2((const float *)m2Values); | 
| 1580 |  | 
| 1581 |     QMatrix4x4 m3; | 
| 1582 |     m3 = m2; | 
| 1583 |     m3 /= factor; | 
| 1584 |     QVERIFY(isSame(m3, (const float *)m1Values)); | 
| 1585 |  | 
| 1586 |     QMatrix4x4 m4; | 
| 1587 |     m4 = m2 / factor; | 
| 1588 |     QVERIFY(isSame(m4, (const float *)m1Values)); | 
| 1589 | } | 
| 1590 |  | 
| 1591 | // Test matrix division by a factor for 4x3 matrices. | 
| 1592 | void tst_QMatrixNxN::divideFactor4x3_data() | 
| 1593 | { | 
| 1594 |     // Use the same test cases as the multiplyFactor test. | 
| 1595 |     multiplyFactor4x3_data(); | 
| 1596 | } | 
| 1597 | void tst_QMatrixNxN::divideFactor4x3() | 
| 1598 | { | 
| 1599 |     QFETCH(void *, m1Values); | 
| 1600 |     QFETCH(float, factor); | 
| 1601 |     QFETCH(void *, m2Values); | 
| 1602 |  | 
| 1603 |     if (factor == 0.0f) | 
| 1604 |         return; | 
| 1605 |  | 
| 1606 |     QMatrix4x3 m2((const float *)m2Values); | 
| 1607 |  | 
| 1608 |     QMatrix4x3 m3; | 
| 1609 |     m3 = m2; | 
| 1610 |     m3 /= factor; | 
| 1611 |     QVERIFY(isSame(m3, (const float *)m1Values)); | 
| 1612 |  | 
| 1613 |     QMatrix4x3 m4; | 
| 1614 |     m4 = m2 / factor; | 
| 1615 |     QVERIFY(isSame(m4, (const float *)m1Values)); | 
| 1616 | } | 
| 1617 |  | 
| 1618 | // Test matrix negation for 2x2 matrices. | 
| 1619 | void tst_QMatrixNxN::negate2x2_data() | 
| 1620 | { | 
| 1621 |     // Use the same test cases as the multiplyFactor test. | 
| 1622 |     multiplyFactor2x2_data(); | 
| 1623 | } | 
| 1624 | void tst_QMatrixNxN::negate2x2() | 
| 1625 | { | 
| 1626 |     QFETCH(void *, m1Values); | 
| 1627 |  | 
| 1628 |     const float *values = (const float *)m1Values; | 
| 1629 |  | 
| 1630 |     QMatrix2x2 m1(values); | 
| 1631 |  | 
| 1632 |     float negated[4]; | 
| 1633 |     for (int index = 0; index < 4; ++index) | 
| 1634 |         negated[index] = -values[index]; | 
| 1635 |  | 
| 1636 |     QMatrix2x2 m2; | 
| 1637 |     m2 = -m1; | 
| 1638 |     QVERIFY(isSame(m2, negated)); | 
| 1639 | } | 
| 1640 |  | 
| 1641 | // Test matrix negation for 3x3 matrices. | 
| 1642 | void tst_QMatrixNxN::negate3x3_data() | 
| 1643 | { | 
| 1644 |     // Use the same test cases as the multiplyFactor test. | 
| 1645 |     multiplyFactor3x3_data(); | 
| 1646 | } | 
| 1647 | void tst_QMatrixNxN::negate3x3() | 
| 1648 | { | 
| 1649 |     QFETCH(void *, m1Values); | 
| 1650 |  | 
| 1651 |     const float *values = (const float *)m1Values; | 
| 1652 |  | 
| 1653 |     QMatrix3x3 m1(values); | 
| 1654 |  | 
| 1655 |     float negated[9]; | 
| 1656 |     for (int index = 0; index < 9; ++index) | 
| 1657 |         negated[index] = -values[index]; | 
| 1658 |  | 
| 1659 |     QMatrix3x3 m2; | 
| 1660 |     m2 = -m1; | 
| 1661 |     QVERIFY(isSame(m2, negated)); | 
| 1662 | } | 
| 1663 |  | 
| 1664 | // Test matrix negation for 4x4 matrices. | 
| 1665 | void tst_QMatrixNxN::negate4x4_data() | 
| 1666 | { | 
| 1667 |     // Use the same test cases as the multiplyFactor test. | 
| 1668 |     multiplyFactor4x4_data(); | 
| 1669 | } | 
| 1670 | void tst_QMatrixNxN::negate4x4() | 
| 1671 | { | 
| 1672 |     QFETCH(void *, m1Values); | 
| 1673 |  | 
| 1674 |     const float *values = (const float *)m1Values; | 
| 1675 |  | 
| 1676 |     QMatrix4x4 m1(values); | 
| 1677 |  | 
| 1678 |     float negated[16]; | 
| 1679 |     for (int index = 0; index < 16; ++index) | 
| 1680 |         negated[index] = -values[index]; | 
| 1681 |  | 
| 1682 |     QMatrix4x4 m2; | 
| 1683 |     m2 = -m1; | 
| 1684 |     QVERIFY(isSame(m2, negated)); | 
| 1685 | } | 
| 1686 |  | 
| 1687 | // Test matrix negation for 4x3 matrices. | 
| 1688 | void tst_QMatrixNxN::negate4x3_data() | 
| 1689 | { | 
| 1690 |     // Use the same test cases as the multiplyFactor test. | 
| 1691 |     multiplyFactor4x3_data(); | 
| 1692 | } | 
| 1693 | void tst_QMatrixNxN::negate4x3() | 
| 1694 | { | 
| 1695 |     QFETCH(void *, m1Values); | 
| 1696 |  | 
| 1697 |     const float *values = (const float *)m1Values; | 
| 1698 |  | 
| 1699 |     QMatrix4x3 m1(values); | 
| 1700 |  | 
| 1701 |     float negated[12]; | 
| 1702 |     for (int index = 0; index < 12; ++index) | 
| 1703 |         negated[index] = -values[index]; | 
| 1704 |  | 
| 1705 |     QMatrix4x3 m2; | 
| 1706 |     m2 = -m1; | 
| 1707 |     QVERIFY(isSame(m2, negated)); | 
| 1708 | } | 
| 1709 |  | 
| 1710 | // Matrix inverted.  This is a more straight-forward implementation | 
| 1711 | // of the algorithm at http://www.j3d.org/matrix_faq/matrfaq_latest.html#Q24 | 
| 1712 | // than the optimized version in the QMatrix4x4 code.  Hopefully it is | 
| 1713 | // easier to verify that this version is the same as the reference. | 
| 1714 |  | 
| 1715 | struct Matrix3 | 
| 1716 | { | 
| 1717 |     float v[9]; | 
| 1718 | }; | 
| 1719 | struct Matrix4 | 
| 1720 | { | 
| 1721 |     float v[16]; | 
| 1722 | }; | 
| 1723 |  | 
| 1724 | static float m3Determinant(const Matrix3& m) | 
| 1725 | { | 
| 1726 |     return m.v[0] * (m.v[4] * m.v[8] - m.v[7] * m.v[5]) - | 
| 1727 |            m.v[1] * (m.v[3] * m.v[8] - m.v[6] * m.v[5]) + | 
| 1728 |            m.v[2] * (m.v[3] * m.v[7] - m.v[6] * m.v[4]); | 
| 1729 | } | 
| 1730 |  | 
| 1731 | static bool m3Inverse(const Matrix3& min, Matrix3& mout) | 
| 1732 | { | 
| 1733 |     float det = m3Determinant(m: min); | 
| 1734 |     if (det == 0.0f) | 
| 1735 |         return false; | 
| 1736 |     mout.v[0] =  (min.v[4] * min.v[8] - min.v[5] * min.v[7]) / det; | 
| 1737 |     mout.v[1] = -(min.v[1] * min.v[8] - min.v[2] * min.v[7]) / det; | 
| 1738 |     mout.v[2] =  (min.v[1] * min.v[5] - min.v[4] * min.v[2]) / det; | 
| 1739 |     mout.v[3] = -(min.v[3] * min.v[8] - min.v[5] * min.v[6]) / det; | 
| 1740 |     mout.v[4] =  (min.v[0] * min.v[8] - min.v[6] * min.v[2]) / det; | 
| 1741 |     mout.v[5] = -(min.v[0] * min.v[5] - min.v[3] * min.v[2]) / det; | 
| 1742 |     mout.v[6] =  (min.v[3] * min.v[7] - min.v[6] * min.v[4]) / det; | 
| 1743 |     mout.v[7] = -(min.v[0] * min.v[7] - min.v[6] * min.v[1]) / det; | 
| 1744 |     mout.v[8] =  (min.v[0] * min.v[4] - min.v[1] * min.v[3]) / det; | 
| 1745 |     return true; | 
| 1746 | } | 
| 1747 |  | 
| 1748 | static void m3Transpose(Matrix3& m) | 
| 1749 | { | 
| 1750 |     qSwap(value1&: m.v[1], value2&: m.v[3]); | 
| 1751 |     qSwap(value1&: m.v[2], value2&: m.v[6]); | 
| 1752 |     qSwap(value1&: m.v[5], value2&: m.v[7]); | 
| 1753 | } | 
| 1754 |  | 
| 1755 | static void m4Submatrix(const Matrix4& min, Matrix3& mout, int i, int j) | 
| 1756 | { | 
| 1757 |     for (int di = 0; di < 3; ++di) { | 
| 1758 |         for (int dj = 0; dj < 3; ++dj) { | 
| 1759 |             int si = di + ((di >= i) ? 1 : 0); | 
| 1760 |             int sj = dj + ((dj >= j) ? 1 : 0); | 
| 1761 |             mout.v[di * 3 + dj] = min.v[si * 4 + sj]; | 
| 1762 |         } | 
| 1763 |     } | 
| 1764 | } | 
| 1765 |  | 
| 1766 | static float m4Determinant(const Matrix4& m) | 
| 1767 | { | 
| 1768 |     float det; | 
| 1769 |     float result = 0.0f; | 
| 1770 |     float i = 1.0f; | 
| 1771 |     Matrix3 msub; | 
| 1772 |     for (int n = 0; n < 4; ++n, i *= -1.0f) { | 
| 1773 |         m4Submatrix(min: m, mout&: msub, i: 0, j: n); | 
| 1774 |         det = m3Determinant(m: msub); | 
| 1775 |         result += m.v[n] * det * i; | 
| 1776 |     } | 
| 1777 |     return result; | 
| 1778 | } | 
| 1779 |  | 
| 1780 | static void m4Inverse(const Matrix4& min, Matrix4& mout) | 
| 1781 | { | 
| 1782 |     float det = m4Determinant(m: min); | 
| 1783 |     Matrix3 msub; | 
| 1784 |     for (int i = 0; i < 4; ++i) { | 
| 1785 |         for (int j = 0; j < 4; ++j) { | 
| 1786 |             float sign = 1.0f - ((i + j) % 2) * 2.0f; | 
| 1787 |             m4Submatrix(min, mout&: msub, i, j); | 
| 1788 |             mout.v[i + j * 4] = (m3Determinant(m: msub) * sign) / det; | 
| 1789 |         } | 
| 1790 |     } | 
| 1791 | } | 
| 1792 |  | 
| 1793 | // Test matrix inverted for 4x4 matrices. | 
| 1794 | void tst_QMatrixNxN::inverted4x4_data() | 
| 1795 | { | 
| 1796 |     QTest::addColumn<void *>(name: "m1Values" ); | 
| 1797 |     QTest::addColumn<void *>(name: "m2Values" ); | 
| 1798 |     QTest::addColumn<bool>(name: "invertible" ); | 
| 1799 |  | 
| 1800 |     QTest::newRow(dataTag: "null" ) | 
| 1801 |         << (void *)nullValues4 << (void *)identityValues4 << false; | 
| 1802 |  | 
| 1803 |     QTest::newRow(dataTag: "identity" ) | 
| 1804 |         << (void *)identityValues4 << (void *)identityValues4 << true; | 
| 1805 |  | 
| 1806 |     QTest::newRow(dataTag: "unique" ) | 
| 1807 |         << (void *)uniqueValues4 << (void *)identityValues4 << false; | 
| 1808 |  | 
| 1809 |     static Matrix4 const invertible = { | 
| 1810 |         .v: {5.0f, 0.0f, 0.0f, 2.0f, | 
| 1811 |          0.0f, 6.0f, 0.0f, 3.0f, | 
| 1812 |          0.0f, 0.0f, 7.0f, 4.0f, | 
| 1813 |          0.0f, 0.0f, 0.0f, 1.0f} | 
| 1814 |     }; | 
| 1815 |     static Matrix4 inverted; | 
| 1816 |     m4Inverse(min: invertible, mout&: inverted); | 
| 1817 |  | 
| 1818 |     QTest::newRow(dataTag: "invertible" ) | 
| 1819 |         << (void *)invertible.v << (void *)inverted.v << true; | 
| 1820 |  | 
| 1821 |     static Matrix4 const invertible2 = { | 
| 1822 |         .v: {1.0f, 2.0f, 4.0f, 2.0f, | 
| 1823 |          8.0f, 3.0f, 5.0f, 3.0f, | 
| 1824 |          6.0f, 7.0f, 9.0f, 4.0f, | 
| 1825 |          0.0f, 0.0f, 0.0f, 1.0f} | 
| 1826 |     }; | 
| 1827 |     static Matrix4 inverted2; | 
| 1828 |     m4Inverse(min: invertible2, mout&: inverted2); | 
| 1829 |  | 
| 1830 |     QTest::newRow(dataTag: "invertible2" ) | 
| 1831 |         << (void *)invertible2.v << (void *)inverted2.v << true; | 
| 1832 |  | 
| 1833 |     static Matrix4 const translate = { | 
| 1834 |         .v: {1.0f, 0.0f, 0.0f, 2.0f, | 
| 1835 |          0.0f, 1.0f, 0.0f, 3.0f, | 
| 1836 |          0.0f, 0.0f, 1.0f, 4.0f, | 
| 1837 |          0.0f, 0.0f, 0.0f, 1.0f} | 
| 1838 |     }; | 
| 1839 |     static Matrix4 const inverseTranslate = { | 
| 1840 |         .v: {1.0f, 0.0f, 0.0f, -2.0f, | 
| 1841 |          0.0f, 1.0f, 0.0f, -3.0f, | 
| 1842 |          0.0f, 0.0f, 1.0f, -4.0f, | 
| 1843 |          0.0f, 0.0f, 0.0f, 1.0f} | 
| 1844 |     }; | 
| 1845 |  | 
| 1846 |     QTest::newRow(dataTag: "translate" ) | 
| 1847 |         << (void *)translate.v << (void *)inverseTranslate.v << true; | 
| 1848 | } | 
| 1849 | void tst_QMatrixNxN::inverted4x4() | 
| 1850 | { | 
| 1851 |     QFETCH(void *, m1Values); | 
| 1852 |     QFETCH(void *, m2Values); | 
| 1853 |     QFETCH(bool, invertible); | 
| 1854 |  | 
| 1855 |     QMatrix4x4 m1((const float *)m1Values); | 
| 1856 |  | 
| 1857 |     if (invertible) | 
| 1858 |         QVERIFY(m1.determinant() != 0.0f); | 
| 1859 |     else | 
| 1860 |         QCOMPARE(m1.determinant(), 0.0f); | 
| 1861 |  | 
| 1862 |     Matrix4 m1alt; | 
| 1863 |     memcpy(dest: m1alt.v, src: (const float *)m1Values, n: sizeof(m1alt.v)); | 
| 1864 |  | 
| 1865 |     QCOMPARE(m1.determinant(), m4Determinant(m1alt)); | 
| 1866 |  | 
| 1867 |     QMatrix4x4 m2; | 
| 1868 |     bool inv; | 
| 1869 |     m2 = m1.inverted(invertible: &inv); | 
| 1870 |     QVERIFY(isSame(m2, (const float *)m2Values)); | 
| 1871 |  | 
| 1872 |     if (invertible) { | 
| 1873 |         QVERIFY(inv); | 
| 1874 |  | 
| 1875 |         Matrix4 m2alt; | 
| 1876 |         m4Inverse(min: m1alt, mout&: m2alt); | 
| 1877 |         QVERIFY(isSame(m2, m2alt.v)); | 
| 1878 |  | 
| 1879 |         QMatrix4x4 m3; | 
| 1880 |         m3 = m1 * m2; | 
| 1881 |         QVERIFY(isIdentity(m3)); | 
| 1882 |  | 
| 1883 |         QMatrix4x4 m4; | 
| 1884 |         m4 = m2 * m1; | 
| 1885 |         QVERIFY(isIdentity(m4)); | 
| 1886 |     } else { | 
| 1887 |         QVERIFY(!inv); | 
| 1888 |     } | 
| 1889 |  | 
| 1890 |     // Test again, after inferring the special matrix type. | 
| 1891 |     m1.optimize(); | 
| 1892 |     m2 = m1.inverted(invertible: &inv); | 
| 1893 |     QVERIFY(isSame(m2, (const float *)m2Values)); | 
| 1894 |     QCOMPARE(inv, invertible); | 
| 1895 | } | 
| 1896 |  | 
| 1897 | void tst_QMatrixNxN::orthonormalInverse4x4() | 
| 1898 | { | 
| 1899 |     QMatrix4x4 m1; | 
| 1900 |     QVERIFY(qFuzzyCompare(m1.inverted(), m1)); | 
| 1901 |  | 
| 1902 |     QMatrix4x4 m2; | 
| 1903 |     m2.rotate(angle: 45.0, x: 1.0, y: 0.0, z: 0.0); | 
| 1904 |     m2.translate(x: 10.0, y: 0.0, z: 0.0); | 
| 1905 |  | 
| 1906 |     // Use operator() to drop the internal flags that | 
| 1907 |     // mark the matrix as orthonormal.  This will force inverted() | 
| 1908 |     // to compute m3.inverted() the long way.  We can then compare | 
| 1909 |     // the result to what the faster algorithm produces on m2. | 
| 1910 |     QMatrix4x4 m3 = m2; | 
| 1911 |     m3(0, 0); | 
| 1912 |     bool invertible; | 
| 1913 |     QVERIFY(qFuzzyCompare(m2.inverted(&invertible), m3.inverted())); | 
| 1914 |     QVERIFY(invertible); | 
| 1915 |  | 
| 1916 |     QMatrix4x4 m4; | 
| 1917 |     m4.rotate(angle: 45.0, x: 0.0, y: 1.0, z: 0.0); | 
| 1918 |     QMatrix4x4 m5 = m4; | 
| 1919 |     m5(0, 0); | 
| 1920 |     QVERIFY(qFuzzyCompare(m4.inverted(), m5.inverted())); | 
| 1921 |  | 
| 1922 |     QMatrix4x4 m6; | 
| 1923 |     m1.rotate(angle: 88, x: 0.0, y: 0.0, z: 1.0); | 
| 1924 |     m1.translate(x: -20.0, y: 20.0, z: 15.0); | 
| 1925 |     m1.rotate(angle: 25, x: 1.0, y: 0.0, z: 0.0); | 
| 1926 |     QMatrix4x4 m7 = m6; | 
| 1927 |     m7(0, 0); | 
| 1928 |     QVERIFY(qFuzzyCompare(m6.inverted(), m7.inverted())); | 
| 1929 | } | 
| 1930 |  | 
| 1931 | // Test the generation and use of 4x4 scale matrices. | 
| 1932 | void tst_QMatrixNxN::scale4x4_data() | 
| 1933 | { | 
| 1934 |     QTest::addColumn<float>(name: "x" ); | 
| 1935 |     QTest::addColumn<float>(name: "y" ); | 
| 1936 |     QTest::addColumn<float>(name: "z" ); | 
| 1937 |     QTest::addColumn<void *>(name: "resultValues" ); | 
| 1938 |  | 
| 1939 |     static const float nullScale[] = | 
| 1940 |         {0.0f, 0.0f, 0.0f, 0.0f, | 
| 1941 |          0.0f, 0.0f, 0.0f, 0.0f, | 
| 1942 |          0.0f, 0.0f, 0.0f, 0.0f, | 
| 1943 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 1944 |     QTest::newRow(dataTag: "null" ) | 
| 1945 |         << (float)0.0f << (float)0.0f << (float)0.0f << (void *)nullScale; | 
| 1946 |  | 
| 1947 |     QTest::newRow(dataTag: "identity" ) | 
| 1948 |         << (float)1.0f << (float)1.0f << (float)1.0f << (void *)identityValues4; | 
| 1949 |  | 
| 1950 |     static const float doubleScale[] = | 
| 1951 |         {2.0f, 0.0f, 0.0f, 0.0f, | 
| 1952 |          0.0f, 2.0f, 0.0f, 0.0f, | 
| 1953 |          0.0f, 0.0f, 2.0f, 0.0f, | 
| 1954 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 1955 |     QTest::newRow(dataTag: "double" ) | 
| 1956 |         << (float)2.0f << (float)2.0f << (float)2.0f << (void *)doubleScale; | 
| 1957 |  | 
| 1958 |     static const float complexScale[] = | 
| 1959 |         {2.0f, 0.0f, 0.0f, 0.0f, | 
| 1960 |          0.0f, 11.0f, 0.0f, 0.0f, | 
| 1961 |          0.0f, 0.0f, -6.5f, 0.0f, | 
| 1962 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 1963 |     QTest::newRow(dataTag: "complex" ) | 
| 1964 |         << (float)2.0f << (float)11.0f << (float)-6.5f << (void *)complexScale; | 
| 1965 |  | 
| 1966 |     static const float complexScale2D[] = | 
| 1967 |         {2.0f, 0.0f, 0.0f, 0.0f, | 
| 1968 |          0.0f, -11.0f, 0.0f, 0.0f, | 
| 1969 |          0.0f, 0.0f, 1.0f, 0.0f, | 
| 1970 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 1971 |     QTest::newRow(dataTag: "complex2D" ) | 
| 1972 |         << (float)2.0f << (float)-11.0f << (float)1.0f << (void *)complexScale2D; | 
| 1973 | } | 
| 1974 | void tst_QMatrixNxN::scale4x4() | 
| 1975 | { | 
| 1976 |     QFETCH(float, x); | 
| 1977 |     QFETCH(float, y); | 
| 1978 |     QFETCH(float, z); | 
| 1979 |     QFETCH(void *, resultValues); | 
| 1980 |  | 
| 1981 |     QMatrix4x4 result((const float *)resultValues); | 
| 1982 |  | 
| 1983 |     QMatrix4x4 m1; | 
| 1984 |     m1.scale(vector: QVector3D(x, y, z)); | 
| 1985 |     QVERIFY(isSame(m1, (const float *)resultValues)); | 
| 1986 |  | 
| 1987 |     QMatrix4x4 m2; | 
| 1988 |     m2.scale(x, y, z); | 
| 1989 |     QVERIFY(isSame(m2, (const float *)resultValues)); | 
| 1990 |  | 
| 1991 |     if (z == 1.0f) { | 
| 1992 |         QMatrix4x4 m2b; | 
| 1993 |         m2b.scale(x, y); | 
| 1994 |         QCOMPARE(m2b, m2); | 
| 1995 |     } | 
| 1996 |  | 
| 1997 |     QVector3D v1(2.0f, 3.0f, -4.0f); | 
| 1998 |     QVector3D v2 = m1 * v1; | 
| 1999 |     QCOMPARE(v2.x(), (float)(2.0f * x)); | 
| 2000 |     QCOMPARE(v2.y(), (float)(3.0f * y)); | 
| 2001 |     QCOMPARE(v2.z(), (float)(-4.0f * z)); | 
| 2002 |  | 
| 2003 |     v2 = v1 * m1; | 
| 2004 |     QCOMPARE(v2.x(), (float)(2.0f * x)); | 
| 2005 |     QCOMPARE(v2.y(), (float)(3.0f * y)); | 
| 2006 |     QCOMPARE(v2.z(), (float)(-4.0f * z)); | 
| 2007 |  | 
| 2008 |     QVector4D v3(2.0f, 3.0f, -4.0f, 34.0f); | 
| 2009 |     QVector4D v4 = m1 * v3; | 
| 2010 |     QCOMPARE(v4.x(), (float)(2.0f * x)); | 
| 2011 |     QCOMPARE(v4.y(), (float)(3.0f * y)); | 
| 2012 |     QCOMPARE(v4.z(), (float)(-4.0f * z)); | 
| 2013 |     QCOMPARE(v4.w(), (float)34.0f); | 
| 2014 |  | 
| 2015 |     v4 = v3 * m1; | 
| 2016 |     QCOMPARE(v4.x(), (float)(2.0f * x)); | 
| 2017 |     QCOMPARE(v4.y(), (float)(3.0f * y)); | 
| 2018 |     QCOMPARE(v4.z(), (float)(-4.0f * z)); | 
| 2019 |     QCOMPARE(v4.w(), (float)34.0f); | 
| 2020 |  | 
| 2021 |     QPoint p1(2, 3); | 
| 2022 |     QPoint p2 = m1 * p1; | 
| 2023 |     QCOMPARE(p2.x(), (int)(2.0f * x)); | 
| 2024 |     QCOMPARE(p2.y(), (int)(3.0f * y)); | 
| 2025 |  | 
| 2026 |     p2 = p1 * m1; | 
| 2027 |     QCOMPARE(p2.x(), (int)(2.0f * x)); | 
| 2028 |     QCOMPARE(p2.y(), (int)(3.0f * y)); | 
| 2029 |  | 
| 2030 |     QPointF p3(2.0f, 3.0f); | 
| 2031 |     QPointF p4 = m1 * p3; | 
| 2032 |     QCOMPARE(p4.x(), (float)(2.0f * x)); | 
| 2033 |     QCOMPARE(p4.y(), (float)(3.0f * y)); | 
| 2034 |  | 
| 2035 |     p4 = p3 * m1; | 
| 2036 |     QCOMPARE(p4.x(), (float)(2.0f * x)); | 
| 2037 |     QCOMPARE(p4.y(), (float)(3.0f * y)); | 
| 2038 |  | 
| 2039 |     QMatrix4x4 m3(uniqueValues4); | 
| 2040 |     QMatrix4x4 m4(m3); | 
| 2041 |     m4.scale(x, y, z); | 
| 2042 |     QVERIFY(m4 == m3 * m1); | 
| 2043 |  | 
| 2044 |     if (x == y && y == z) { | 
| 2045 |         QMatrix4x4 m5; | 
| 2046 |         m5.scale(factor: x); | 
| 2047 |         QVERIFY(isSame(m5, (const float *)resultValues)); | 
| 2048 |     } | 
| 2049 |  | 
| 2050 |     if (z == 1.0f) { | 
| 2051 |         QMatrix4x4 m4b(m3); | 
| 2052 |         m4b.scale(x, y); | 
| 2053 |         QCOMPARE(m4b, m4); | 
| 2054 |     } | 
| 2055 |  | 
| 2056 |     // Test coverage when the special matrix type is unknown. | 
| 2057 |  | 
| 2058 |     QMatrix4x4 m6; | 
| 2059 |     m6(0, 0) = 1.0f; | 
| 2060 |     m6.scale(vector: QVector3D(x, y, z)); | 
| 2061 |     QVERIFY(isSame(m6, (const float *)resultValues)); | 
| 2062 |  | 
| 2063 |     QMatrix4x4 m7; | 
| 2064 |     m7(0, 0) = 1.0f; | 
| 2065 |     m7.scale(x, y, z); | 
| 2066 |     QVERIFY(isSame(m7, (const float *)resultValues)); | 
| 2067 |  | 
| 2068 |     if (x == y && y == z) { | 
| 2069 |         QMatrix4x4 m8; | 
| 2070 |         m8(0, 0) = 1.0f; | 
| 2071 |         m8.scale(factor: x); | 
| 2072 |         QVERIFY(isSame(m8, (const float *)resultValues)); | 
| 2073 |  | 
| 2074 |         m8.optimize(); | 
| 2075 |         m8.scale(factor: 1.0f); | 
| 2076 |         QVERIFY(isSame(m8, (const float *)resultValues)); | 
| 2077 |  | 
| 2078 |         QMatrix4x4 m9; | 
| 2079 |         m9.translate(x: 0.0f, y: 0.0f, z: 0.0f); | 
| 2080 |         m9.scale(factor: x); | 
| 2081 |         QVERIFY(isSame(m9, (const float *)resultValues)); | 
| 2082 |     } | 
| 2083 | } | 
| 2084 |  | 
| 2085 | // Test the generation and use of 4x4 translation matrices. | 
| 2086 | void tst_QMatrixNxN::translate4x4_data() | 
| 2087 | { | 
| 2088 |     QTest::addColumn<float>(name: "x" ); | 
| 2089 |     QTest::addColumn<float>(name: "y" ); | 
| 2090 |     QTest::addColumn<float>(name: "z" ); | 
| 2091 |     QTest::addColumn<void *>(name: "resultValues" ); | 
| 2092 |  | 
| 2093 |     QTest::newRow(dataTag: "null" ) | 
| 2094 |         << (float)0.0f << (float)0.0f << (float)0.0f << (void *)identityValues4; | 
| 2095 |  | 
| 2096 |     static const float identityTranslate[] = | 
| 2097 |         {1.0f, 0.0f, 0.0f, 1.0f, | 
| 2098 |          0.0f, 1.0f, 0.0f, 1.0f, | 
| 2099 |          0.0f, 0.0f, 1.0f, 1.0f, | 
| 2100 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2101 |     QTest::newRow(dataTag: "identity" ) | 
| 2102 |         << (float)1.0f << (float)1.0f << (float)1.0f << (void *)identityTranslate; | 
| 2103 |  | 
| 2104 |     static const float [] = | 
| 2105 |         {1.0f, 0.0f, 0.0f, 2.0f, | 
| 2106 |          0.0f, 1.0f, 0.0f, 11.0f, | 
| 2107 |          0.0f, 0.0f, 1.0f, -6.5f, | 
| 2108 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2109 |     QTest::newRow(dataTag: "complex" ) | 
| 2110 |         << (float)2.0f << (float)11.0f << (float)-6.5f << (void *)complexTranslate; | 
| 2111 |  | 
| 2112 |     static const float [] = | 
| 2113 |         {1.0f, 0.0f, 0.0f, 2.0f, | 
| 2114 |          0.0f, 1.0f, 0.0f, -11.0f, | 
| 2115 |          0.0f, 0.0f, 1.0f, 0.0f, | 
| 2116 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2117 |     QTest::newRow(dataTag: "complex2D" ) | 
| 2118 |         << (float)2.0f << (float)-11.0f << (float)0.0f << (void *)complexTranslate2D; | 
| 2119 | } | 
| 2120 | void tst_QMatrixNxN::translate4x4() | 
| 2121 | { | 
| 2122 |     QFETCH(float, x); | 
| 2123 |     QFETCH(float, y); | 
| 2124 |     QFETCH(float, z); | 
| 2125 |     QFETCH(void *, resultValues); | 
| 2126 |  | 
| 2127 |     QMatrix4x4 result((const float *)resultValues); | 
| 2128 |  | 
| 2129 |     QMatrix4x4 m1; | 
| 2130 |     m1.translate(vector: QVector3D(x, y, z)); | 
| 2131 |     QVERIFY(isSame(m1, (const float *)resultValues)); | 
| 2132 |  | 
| 2133 |     QMatrix4x4 m2; | 
| 2134 |     m2.translate(x, y, z); | 
| 2135 |     QVERIFY(isSame(m2, (const float *)resultValues)); | 
| 2136 |  | 
| 2137 |     if (z == 0.0f) { | 
| 2138 |         QMatrix4x4 m2b; | 
| 2139 |         m2b.translate(x, y); | 
| 2140 |         QCOMPARE(m2b, m2); | 
| 2141 |     } | 
| 2142 |  | 
| 2143 |     QVector3D v1(2.0f, 3.0f, -4.0f); | 
| 2144 |     QVector3D v2 = m1 * v1; | 
| 2145 |     QCOMPARE(v2.x(), (float)(2.0f + x)); | 
| 2146 |     QCOMPARE(v2.y(), (float)(3.0f + y)); | 
| 2147 |     QCOMPARE(v2.z(), (float)(-4.0f + z)); | 
| 2148 |  | 
| 2149 |     QVector4D v3(2.0f, 3.0f, -4.0f, 1.0f); | 
| 2150 |     QVector4D v4 = m1 * v3; | 
| 2151 |     QCOMPARE(v4.x(), (float)(2.0f + x)); | 
| 2152 |     QCOMPARE(v4.y(), (float)(3.0f + y)); | 
| 2153 |     QCOMPARE(v4.z(), (float)(-4.0f + z)); | 
| 2154 |     QCOMPARE(v4.w(), (float)1.0f); | 
| 2155 |  | 
| 2156 |     QVector4D v5(2.0f, 3.0f, -4.0f, 34.0f); | 
| 2157 |     QVector4D v6 = m1 * v5; | 
| 2158 |     QCOMPARE(v6.x(), (float)(2.0f + x * 34.0f)); | 
| 2159 |     QCOMPARE(v6.y(), (float)(3.0f + y * 34.0f)); | 
| 2160 |     QCOMPARE(v6.z(), (float)(-4.0f + z * 34.0f)); | 
| 2161 |     QCOMPARE(v6.w(), (float)34.0f); | 
| 2162 |  | 
| 2163 |     QPoint p1(2, 3); | 
| 2164 |     QPoint p2 = m1 * p1; | 
| 2165 |     QCOMPARE(p2.x(), (int)(2.0f + x)); | 
| 2166 |     QCOMPARE(p2.y(), (int)(3.0f + y)); | 
| 2167 |  | 
| 2168 |     QPointF p3(2.0f, 3.0f); | 
| 2169 |     QPointF p4 = m1 * p3; | 
| 2170 |     QCOMPARE(p4.x(), (float)(2.0f + x)); | 
| 2171 |     QCOMPARE(p4.y(), (float)(3.0f + y)); | 
| 2172 |  | 
| 2173 |     QMatrix4x4 m3(uniqueValues4); | 
| 2174 |     QMatrix4x4 m4(m3); | 
| 2175 |     m4.translate(x, y, z); | 
| 2176 |     QVERIFY(m4 == m3 * m1); | 
| 2177 |  | 
| 2178 |     if (z == 0.0f) { | 
| 2179 |         QMatrix4x4 m4b(m3); | 
| 2180 |         m4b.translate(x, y); | 
| 2181 |         QCOMPARE(m4b, m4); | 
| 2182 |     } | 
| 2183 | } | 
| 2184 |  | 
| 2185 | // Test the generation and use of 4x4 rotation matrices. | 
| 2186 | void tst_QMatrixNxN::rotate4x4_data() | 
| 2187 | { | 
| 2188 |     QTest::addColumn<float>(name: "angle" ); | 
| 2189 |     QTest::addColumn<float>(name: "x" ); | 
| 2190 |     QTest::addColumn<float>(name: "y" ); | 
| 2191 |     QTest::addColumn<float>(name: "z" ); | 
| 2192 |     QTest::addColumn<void *>(name: "resultValues" ); | 
| 2193 |  | 
| 2194 |     static const float nullRotate[] = | 
| 2195 |         {0.0f, 0.0f, 0.0f, 0.0f, | 
| 2196 |          0.0f, 0.0f, 0.0f, 0.0f, | 
| 2197 |          0.0f, 0.0f, 0.0f, 0.0f, | 
| 2198 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2199 |     QTest::newRow(dataTag: "null" ) | 
| 2200 |         << (float)90.0f | 
| 2201 |         << (float)0.0f << (float)0.0f << (float)0.0f | 
| 2202 |         << (void *)nullRotate; | 
| 2203 |  | 
| 2204 |     static const float noRotate[] = | 
| 2205 |         {1.0f, 0.0f, 0.0f, 0.0f, | 
| 2206 |          0.0f, 1.0f, 0.0f, 0.0f, | 
| 2207 |          0.0f, 0.0f, 1.0f, 0.0f, | 
| 2208 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2209 |     QTest::newRow(dataTag: "zerodegrees" ) | 
| 2210 |         << (float)0.0f | 
| 2211 |         << (float)2.0f << (float)3.0f << (float)-4.0f | 
| 2212 |         << (void *)noRotate; | 
| 2213 |  | 
| 2214 |     static const float xRotate[] = | 
| 2215 |         {1.0f, 0.0f, 0.0f, 0.0f, | 
| 2216 |          0.0f, 0.0f, -1.0f, 0.0f, | 
| 2217 |          0.0f, 1.0f, 0.0f, 0.0f, | 
| 2218 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2219 |     QTest::newRow(dataTag: "xrotate" ) | 
| 2220 |         << (float)90.0f | 
| 2221 |         << (float)1.0f << (float)0.0f << (float)0.0f | 
| 2222 |         << (void *)xRotate; | 
| 2223 |  | 
| 2224 |     static const float xRotateNeg[] = | 
| 2225 |         {1.0f, 0.0f, 0.0f, 0.0f, | 
| 2226 |          0.0f, 0.0f, 1.0f, 0.0f, | 
| 2227 |          0.0f, -1.0f, 0.0f, 0.0f, | 
| 2228 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2229 |     QTest::newRow(dataTag: "-xrotate" ) | 
| 2230 |         << (float)90.0f | 
| 2231 |         << (float)-1.0f << (float)0.0f << (float)0.0f | 
| 2232 |         << (void *)xRotateNeg; | 
| 2233 |  | 
| 2234 |     static const float yRotate[] = | 
| 2235 |         {0.0f, 0.0f, 1.0f, 0.0f, | 
| 2236 |          0.0f, 1.0f, 0.0f, 0.0f, | 
| 2237 |          -1.0f, 0.0f, 0.0f, 0.0f, | 
| 2238 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2239 |     QTest::newRow(dataTag: "yrotate" ) | 
| 2240 |         << (float)90.0f | 
| 2241 |         << (float)0.0f << (float)1.0f << (float)0.0f | 
| 2242 |         << (void *)yRotate; | 
| 2243 |  | 
| 2244 |     static const float yRotateNeg[] = | 
| 2245 |         {0.0f, 0.0f, -1.0f, 0.0f, | 
| 2246 |          0.0f, 1.0f, 0.0f, 0.0f, | 
| 2247 |          1.0f, 0.0f, 0.0f, 0.0f, | 
| 2248 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2249 |     QTest::newRow(dataTag: "-yrotate" ) | 
| 2250 |         << (float)90.0f | 
| 2251 |         << (float)0.0f << (float)-1.0f << (float)0.0f | 
| 2252 |         << (void *)yRotateNeg; | 
| 2253 |  | 
| 2254 |     static const float zRotate[] = | 
| 2255 |         {0.0f, -1.0f, 0.0f, 0.0f, | 
| 2256 |          1.0f, 0.0f, 0.0f, 0.0f, | 
| 2257 |          0.0f, 0.0f, 1.0f, 0.0f, | 
| 2258 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2259 |     QTest::newRow(dataTag: "zrotate" ) | 
| 2260 |         << (float)90.0f | 
| 2261 |         << (float)0.0f << (float)0.0f << (float)1.0f | 
| 2262 |         << (void *)zRotate; | 
| 2263 |  | 
| 2264 |     static const float zRotateNeg[] = | 
| 2265 |         {0.0f, 1.0f, 0.0f, 0.0f, | 
| 2266 |          -1.0f, 0.0f, 0.0f, 0.0f, | 
| 2267 |          0.0f, 0.0f, 1.0f, 0.0f, | 
| 2268 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2269 |     QTest::newRow(dataTag: "-zrotate" ) | 
| 2270 |         << (float)90.0f | 
| 2271 |         << (float)0.0f << (float)0.0f << (float)-1.0f | 
| 2272 |         << (void *)zRotateNeg; | 
| 2273 |  | 
| 2274 |     // Algorithm from http://en.wikipedia.org/wiki/Rotation_matrix. | 
| 2275 |     // Deliberately different from the one in the code for cross-checking. | 
| 2276 |     static float complexRotate[16]; | 
| 2277 |     float x = 1.0f; | 
| 2278 |     float y = 2.0f; | 
| 2279 |     float z = -6.0f; | 
| 2280 |     float angle = -45.0f; | 
| 2281 |     float c = std::cos(x: qDegreesToRadians(degrees: angle)); | 
| 2282 |     float s = std::sin(x: qDegreesToRadians(degrees: angle)); | 
| 2283 |     float len = std::sqrt(x: x * x + y * y + z * z); | 
| 2284 |     float xu = x / len; | 
| 2285 |     float yu = y / len; | 
| 2286 |     float zu = z / len; | 
| 2287 |     complexRotate[0] = (float)((1 - xu * xu) * c + xu * xu); | 
| 2288 |     complexRotate[1] = (float)(-zu * s - xu * yu * c + xu * yu); | 
| 2289 |     complexRotate[2] = (float)(yu * s - xu * zu * c + xu * zu); | 
| 2290 |     complexRotate[3] = 0; | 
| 2291 |     complexRotate[4] = (float)(zu * s - xu * yu * c + xu * yu); | 
| 2292 |     complexRotate[5] = (float)((1 - yu * yu) * c + yu * yu); | 
| 2293 |     complexRotate[6] = (float)(-xu * s - yu * zu * c + yu * zu); | 
| 2294 |     complexRotate[7] = 0; | 
| 2295 |     complexRotate[8] = (float)(-yu * s - xu * zu * c + xu * zu); | 
| 2296 |     complexRotate[9] = (float)(xu * s - yu * zu * c + yu * zu); | 
| 2297 |     complexRotate[10] = (float)((1 - zu * zu) * c + zu * zu); | 
| 2298 |     complexRotate[11] = 0; | 
| 2299 |     complexRotate[12] = 0; | 
| 2300 |     complexRotate[13] = 0; | 
| 2301 |     complexRotate[14] = 0; | 
| 2302 |     complexRotate[15] = 1; | 
| 2303 |  | 
| 2304 |     QTest::newRow(dataTag: "complex" ) | 
| 2305 |         << (float)angle | 
| 2306 |         << (float)x << (float)y << (float)z | 
| 2307 |         << (void *)complexRotate; | 
| 2308 | } | 
| 2309 | void tst_QMatrixNxN::rotate4x4() | 
| 2310 | { | 
| 2311 |     QFETCH(float, angle); | 
| 2312 |     QFETCH(float, x); | 
| 2313 |     QFETCH(float, y); | 
| 2314 |     QFETCH(float, z); | 
| 2315 |     QFETCH(void *, resultValues); | 
| 2316 |  | 
| 2317 |     QMatrix4x4 m1; | 
| 2318 |     m1.rotate(angle, vector: QVector3D(x, y, z)); | 
| 2319 |     QVERIFY(isSame(m1, (const float *)resultValues)); | 
| 2320 |  | 
| 2321 |     QMatrix4x4 m2; | 
| 2322 |     m2.rotate(angle, x, y, z); | 
| 2323 |     QVERIFY(isSame(m2, (const float *)resultValues)); | 
| 2324 |  | 
| 2325 |     QMatrix4x4 m3(uniqueValues4); | 
| 2326 |     QMatrix4x4 m4(m3); | 
| 2327 |     m4.rotate(angle, x, y, z); | 
| 2328 |     QVERIFY(qFuzzyCompare(m4, m3 * m1)); | 
| 2329 |  | 
| 2330 |     // Null vectors don't make sense for quaternion rotations. | 
| 2331 |     if (x != 0 || y != 0 || z != 0) { | 
| 2332 |         QMatrix4x4 m5; | 
| 2333 |         m5.rotate(quaternion: QQuaternion::fromAxisAndAngle(axis: QVector3D(x, y, z), angle)); | 
| 2334 |         QVERIFY(isSame(m5, (const float *)resultValues)); | 
| 2335 |     } | 
| 2336 |  | 
| 2337 | #define ROTATE4(xin,yin,zin,win,xout,yout,zout,wout) \ | 
| 2338 |     do { \ | 
| 2339 |         xout = ((const float *)resultValues)[0] * xin + \ | 
| 2340 |                ((const float *)resultValues)[1] * yin + \ | 
| 2341 |                ((const float *)resultValues)[2] * zin + \ | 
| 2342 |                ((const float *)resultValues)[3] * win; \ | 
| 2343 |         yout = ((const float *)resultValues)[4] * xin + \ | 
| 2344 |                ((const float *)resultValues)[5] * yin + \ | 
| 2345 |                ((const float *)resultValues)[6] * zin + \ | 
| 2346 |                ((const float *)resultValues)[7] * win; \ | 
| 2347 |         zout = ((const float *)resultValues)[8] * xin + \ | 
| 2348 |                ((const float *)resultValues)[9] * yin + \ | 
| 2349 |                ((const float *)resultValues)[10] * zin + \ | 
| 2350 |                ((const float *)resultValues)[11] * win; \ | 
| 2351 |         wout = ((const float *)resultValues)[12] * xin + \ | 
| 2352 |                ((const float *)resultValues)[13] * yin + \ | 
| 2353 |                ((const float *)resultValues)[14] * zin + \ | 
| 2354 |                ((const float *)resultValues)[15] * win; \ | 
| 2355 |     } while (0) | 
| 2356 |  | 
| 2357 |     // Rotate various test vectors using the straight-forward approach. | 
| 2358 |     float v1x, v1y, v1z, v1w; | 
| 2359 |     ROTATE4(2.0f, 3.0f, -4.0f, 1.0f, v1x, v1y, v1z, v1w); | 
| 2360 |     v1x /= v1w; | 
| 2361 |     v1y /= v1w; | 
| 2362 |     v1z /= v1w; | 
| 2363 |     float v3x, v3y, v3z, v3w; | 
| 2364 |     ROTATE4(2.0f, 3.0f, -4.0f, 1.0f, v3x, v3y, v3z, v3w); | 
| 2365 |     float v5x, v5y, v5z, v5w; | 
| 2366 |     ROTATE4(2.0f, 3.0f, -4.0f, 34.0f, v5x, v5y, v5z, v5w); | 
| 2367 |     float p1x, p1y, p1z, p1w; | 
| 2368 |     ROTATE4(2.0f, 3.0f, 0.0f, 1.0f, p1x, p1y, p1z, p1w); | 
| 2369 |     p1x /= p1w; | 
| 2370 |     p1y /= p1w; | 
| 2371 |     p1z /= p1w; | 
| 2372 |  | 
| 2373 |     QVector3D v1(2.0f, 3.0f, -4.0f); | 
| 2374 |     QVector3D v2 = m1 * v1; | 
| 2375 |     QVERIFY(qFuzzyCompare(v2.x(), v1x)); | 
| 2376 |     QVERIFY(qFuzzyCompare(v2.y(), v1y)); | 
| 2377 |     QVERIFY(qFuzzyCompare(v2.z(), v1z)); | 
| 2378 |  | 
| 2379 |     QVector4D v3(2.0f, 3.0f, -4.0f, 1.0f); | 
| 2380 |     QVector4D v4 = m1 * v3; | 
| 2381 |     QVERIFY(qFuzzyCompare(v4.x(), v3x)); | 
| 2382 |     QVERIFY(qFuzzyCompare(v4.y(), v3y)); | 
| 2383 |     QVERIFY(qFuzzyCompare(v4.z(), v3z)); | 
| 2384 |     QVERIFY(qFuzzyCompare(v4.w(), v3w)); | 
| 2385 |  | 
| 2386 |     QVector4D v5(2.0f, 3.0f, -4.0f, 34.0f); | 
| 2387 |     QVector4D v6 = m1 * v5; | 
| 2388 |     QVERIFY(qFuzzyCompare(v6.x(), v5x)); | 
| 2389 |     QVERIFY(qFuzzyCompare(v6.y(), v5y)); | 
| 2390 |     QVERIFY(qFuzzyCompare(v6.z(), v5z)); | 
| 2391 |     QVERIFY(qFuzzyCompare(v6.w(), v5w)); | 
| 2392 |  | 
| 2393 |     QPoint p1(2, 3); | 
| 2394 |     QPoint p2 = m1 * p1; | 
| 2395 |     QCOMPARE(p2.x(), qRound(p1x)); | 
| 2396 |     QCOMPARE(p2.y(), qRound(p1y)); | 
| 2397 |  | 
| 2398 |     QPointF p3(2.0f, 3.0f); | 
| 2399 |     QPointF p4 = m1 * p3; | 
| 2400 |     QVERIFY(qFuzzyCompare(float(p4.x()), p1x)); | 
| 2401 |     QVERIFY(qFuzzyCompare(float(p4.y()), p1y)); | 
| 2402 |  | 
| 2403 |     if (x != 0 || y != 0 || z != 0) { | 
| 2404 |         QQuaternion q = QQuaternion::fromAxisAndAngle(axis: QVector3D(x, y, z), angle); | 
| 2405 |         QVector3D vq = q.rotatedVector(vector: v1); | 
| 2406 |         QVERIFY(qFuzzyCompare(vq.x(), v1x)); | 
| 2407 |         QVERIFY(qFuzzyCompare(vq.y(), v1y)); | 
| 2408 |         QVERIFY(qFuzzyCompare(vq.z(), v1z)); | 
| 2409 |     } | 
| 2410 | } | 
| 2411 |  | 
| 2412 | static bool isSame(const QMatrix3x3& m1, const Matrix3& m2) | 
| 2413 | { | 
| 2414 |     for (int row = 0; row < 3; ++row) { | 
| 2415 |         for (int col = 0; col < 3; ++col) { | 
| 2416 |             if (!qFuzzyCompare(p1: m1(row, col), p2: m2.v[row * 3 + col])) | 
| 2417 |                 return false; | 
| 2418 |         } | 
| 2419 |     } | 
| 2420 |     return true; | 
| 2421 | } | 
| 2422 |  | 
| 2423 | // Test the computation of normal matrices from 4x4 transformation matrices. | 
| 2424 | void tst_QMatrixNxN::normalMatrix_data() | 
| 2425 | { | 
| 2426 |     QTest::addColumn<void *>(name: "mValues" ); | 
| 2427 |  | 
| 2428 |     QTest::newRow(dataTag: "identity" ) | 
| 2429 |         << (void *)identityValues4; | 
| 2430 |     QTest::newRow(dataTag: "unique" ) | 
| 2431 |         << (void *)uniqueValues4;   // Not invertible because determinant == 0. | 
| 2432 |  | 
| 2433 |     static float const translateValues[16] = | 
| 2434 |         {1.0f, 0.0f, 0.0f, 4.0f, | 
| 2435 |          0.0f, 1.0f, 0.0f, 5.0f, | 
| 2436 |          0.0f, 0.0f, 1.0f, -3.0f, | 
| 2437 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2438 |     static float const scaleValues[16] = | 
| 2439 |         {2.0f, 0.0f, 0.0f, 0.0f, | 
| 2440 |          0.0f, 7.0f, 0.0f, 0.0f, | 
| 2441 |          0.0f, 0.0f, 9.0f, 0.0f, | 
| 2442 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2443 |     static float const bothValues[16] = | 
| 2444 |         {2.0f, 0.0f, 0.0f, 4.0f, | 
| 2445 |          0.0f, 7.0f, 0.0f, 5.0f, | 
| 2446 |          0.0f, 0.0f, 9.0f, -3.0f, | 
| 2447 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2448 |     static float const rotateValues[16] = | 
| 2449 |         {0.0f, 0.0f, 1.0f, 0.0f, | 
| 2450 |          1.0f, 0.0f, 0.0f, 0.0f, | 
| 2451 |          0.0f, 1.0f, 0.0f, 0.0f, | 
| 2452 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2453 |     static float const nullScaleValues1[16] = | 
| 2454 |         {0.0f, 0.0f, 0.0f, 4.0f, | 
| 2455 |          0.0f, 7.0f, 0.0f, 5.0f, | 
| 2456 |          0.0f, 0.0f, 9.0f, -3.0f, | 
| 2457 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2458 |     static float const nullScaleValues2[16] = | 
| 2459 |         {2.0f, 0.0f, 0.0f, 4.0f, | 
| 2460 |          0.0f, 0.0f, 0.0f, 5.0f, | 
| 2461 |          0.0f, 0.0f, 9.0f, -3.0f, | 
| 2462 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2463 |     static float const nullScaleValues3[16] = | 
| 2464 |         {2.0f, 0.0f, 0.0f, 4.0f, | 
| 2465 |          0.0f, 7.0f, 0.0f, 5.0f, | 
| 2466 |          0.0f, 0.0f, 0.0f, -3.0f, | 
| 2467 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2468 |  | 
| 2469 |     QTest::newRow(dataTag: "translate" ) << (void *)translateValues; | 
| 2470 |     QTest::newRow(dataTag: "scale" ) << (void *)scaleValues; | 
| 2471 |     QTest::newRow(dataTag: "both" ) << (void *)bothValues; | 
| 2472 |     QTest::newRow(dataTag: "rotate" ) << (void *)rotateValues; | 
| 2473 |     QTest::newRow(dataTag: "null scale 1" ) << (void *)nullScaleValues1; | 
| 2474 |     QTest::newRow(dataTag: "null scale 2" ) << (void *)nullScaleValues2; | 
| 2475 |     QTest::newRow(dataTag: "null scale 3" ) << (void *)nullScaleValues3; | 
| 2476 | } | 
| 2477 | void tst_QMatrixNxN::normalMatrix() | 
| 2478 | { | 
| 2479 |     QFETCH(void *, mValues); | 
| 2480 |     const float *values = (const float *)mValues; | 
| 2481 |  | 
| 2482 |     // Compute the expected answer the long way. | 
| 2483 |     Matrix3 min; | 
| 2484 |     Matrix3 answer; | 
| 2485 |     min.v[0] = values[0]; | 
| 2486 |     min.v[1] = values[1]; | 
| 2487 |     min.v[2] = values[2]; | 
| 2488 |     min.v[3] = values[4]; | 
| 2489 |     min.v[4] = values[5]; | 
| 2490 |     min.v[5] = values[6]; | 
| 2491 |     min.v[6] = values[8]; | 
| 2492 |     min.v[7] = values[9]; | 
| 2493 |     min.v[8] = values[10]; | 
| 2494 |     bool invertible = m3Inverse(min, mout&: answer); | 
| 2495 |     m3Transpose(m&: answer); | 
| 2496 |  | 
| 2497 |     // Perform the test. | 
| 2498 |     QMatrix4x4 m1(values); | 
| 2499 |     QMatrix3x3 n1 = m1.normalMatrix(); | 
| 2500 |  | 
| 2501 |     if (invertible) | 
| 2502 |         QVERIFY(::isSame(n1, answer)); | 
| 2503 |     else | 
| 2504 |         QVERIFY(isIdentity(n1)); | 
| 2505 |  | 
| 2506 |     // Perform the test again, after inferring special matrix types. | 
| 2507 |     // This tests the optimized paths in the normalMatrix() function. | 
| 2508 |     m1.optimize(); | 
| 2509 |     n1 = m1.normalMatrix(); | 
| 2510 |  | 
| 2511 |     if (invertible) | 
| 2512 |         QVERIFY(::isSame(n1, answer)); | 
| 2513 |     else | 
| 2514 |         QVERIFY(isIdentity(n1)); | 
| 2515 | } | 
| 2516 |  | 
| 2517 | // Test optimized transformations on 4x4 matrices. | 
| 2518 | void tst_QMatrixNxN::optimizedTransforms() | 
| 2519 | { | 
| 2520 |     static float const translateValues[16] = | 
| 2521 |         {1.0f, 0.0f, 0.0f, 4.0f, | 
| 2522 |          0.0f, 1.0f, 0.0f, 5.0f, | 
| 2523 |          0.0f, 0.0f, 1.0f, -3.0f, | 
| 2524 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2525 |     static float const translateDoubleValues[16] = | 
| 2526 |         {1.0f, 0.0f, 0.0f, 8.0f, | 
| 2527 |          0.0f, 1.0f, 0.0f, 10.0f, | 
| 2528 |          0.0f, 0.0f, 1.0f, -6.0f, | 
| 2529 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2530 |     static float const scaleValues[16] = | 
| 2531 |         {2.0f, 0.0f, 0.0f, 0.0f, | 
| 2532 |          0.0f, 7.0f, 0.0f, 0.0f, | 
| 2533 |          0.0f, 0.0f, 9.0f, 0.0f, | 
| 2534 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2535 |     static float const scaleDoubleValues[16] = | 
| 2536 |         {4.0f, 0.0f, 0.0f, 0.0f, | 
| 2537 |          0.0f, 49.0f, 0.0f, 0.0f, | 
| 2538 |          0.0f, 0.0f, 81.0f, 0.0f, | 
| 2539 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2540 |     static float const bothValues[16] = | 
| 2541 |         {2.0f, 0.0f, 0.0f, 4.0f, | 
| 2542 |          0.0f, 7.0f, 0.0f, 5.0f, | 
| 2543 |          0.0f, 0.0f, 9.0f, -3.0f, | 
| 2544 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2545 |     static float const bothReverseValues[16] = | 
| 2546 |         {2.0f, 0.0f, 0.0f, 4.0f * 2.0f, | 
| 2547 |          0.0f, 7.0f, 0.0f, 5.0f * 7.0f, | 
| 2548 |          0.0f, 0.0f, 9.0f, -3.0f * 9.0f, | 
| 2549 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2550 |     static float const bothThenTranslateValues[16] = | 
| 2551 |         {2.0f, 0.0f, 0.0f, 4.0f + 2.0f * 4.0f, | 
| 2552 |          0.0f, 7.0f, 0.0f, 5.0f + 7.0f * 5.0f, | 
| 2553 |          0.0f, 0.0f, 9.0f, -3.0f + 9.0f * -3.0f, | 
| 2554 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2555 |     static float const bothThenScaleValues[16] = | 
| 2556 |         {4.0f, 0.0f, 0.0f, 4.0f, | 
| 2557 |          0.0f, 49.0f, 0.0f, 5.0f, | 
| 2558 |          0.0f, 0.0f, 81.0f, -3.0f, | 
| 2559 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 2560 |  | 
| 2561 |     QMatrix4x4 translate(translateValues); | 
| 2562 |     QMatrix4x4 scale(scaleValues); | 
| 2563 |     QMatrix4x4 both(bothValues); | 
| 2564 |  | 
| 2565 |     QMatrix4x4 m1; | 
| 2566 |     m1.translate(x: 4.0f, y: 5.0f, z: -3.0f); | 
| 2567 |     QVERIFY(isSame(m1, translateValues)); | 
| 2568 |     m1.translate(x: 4.0f, y: 5.0f, z: -3.0f); | 
| 2569 |     QVERIFY(isSame(m1, translateDoubleValues)); | 
| 2570 |  | 
| 2571 |     QMatrix4x4 m2; | 
| 2572 |     m2.translate(vector: QVector3D(4.0f, 5.0f, -3.0f)); | 
| 2573 |     QVERIFY(isSame(m2, translateValues)); | 
| 2574 |     m2.translate(vector: QVector3D(4.0f, 5.0f, -3.0f)); | 
| 2575 |     QVERIFY(isSame(m2, translateDoubleValues)); | 
| 2576 |  | 
| 2577 |     QMatrix4x4 m3; | 
| 2578 |     m3.scale(x: 2.0f, y: 7.0f, z: 9.0f); | 
| 2579 |     QVERIFY(isSame(m3, scaleValues)); | 
| 2580 |     m3.scale(x: 2.0f, y: 7.0f, z: 9.0f); | 
| 2581 |     QVERIFY(isSame(m3, scaleDoubleValues)); | 
| 2582 |  | 
| 2583 |     QMatrix4x4 m4; | 
| 2584 |     m4.scale(vector: QVector3D(2.0f, 7.0f, 9.0f)); | 
| 2585 |     QVERIFY(isSame(m4, scaleValues)); | 
| 2586 |     m4.scale(vector: QVector3D(2.0f, 7.0f, 9.0f)); | 
| 2587 |     QVERIFY(isSame(m4, scaleDoubleValues)); | 
| 2588 |  | 
| 2589 |     QMatrix4x4 m5; | 
| 2590 |     m5.translate(x: 4.0f, y: 5.0f, z: -3.0f); | 
| 2591 |     m5.scale(x: 2.0f, y: 7.0f, z: 9.0f); | 
| 2592 |     QVERIFY(isSame(m5, bothValues)); | 
| 2593 |     m5.translate(x: 4.0f, y: 5.0f, z: -3.0f); | 
| 2594 |     QVERIFY(isSame(m5, bothThenTranslateValues)); | 
| 2595 |  | 
| 2596 |     QMatrix4x4 m6; | 
| 2597 |     m6.translate(vector: QVector3D(4.0f, 5.0f, -3.0f)); | 
| 2598 |     m6.scale(vector: QVector3D(2.0f, 7.0f, 9.0f)); | 
| 2599 |     QVERIFY(isSame(m6, bothValues)); | 
| 2600 |     m6.translate(vector: QVector3D(4.0f, 5.0f, -3.0f)); | 
| 2601 |     QVERIFY(isSame(m6, bothThenTranslateValues)); | 
| 2602 |  | 
| 2603 |     QMatrix4x4 m7; | 
| 2604 |     m7.scale(x: 2.0f, y: 7.0f, z: 9.0f); | 
| 2605 |     m7.translate(x: 4.0f, y: 5.0f, z: -3.0f); | 
| 2606 |     QVERIFY(isSame(m7, bothReverseValues)); | 
| 2607 |  | 
| 2608 |     QMatrix4x4 m8; | 
| 2609 |     m8.scale(vector: QVector3D(2.0f, 7.0f, 9.0f)); | 
| 2610 |     m8.translate(vector: QVector3D(4.0f, 5.0f, -3.0f)); | 
| 2611 |     QVERIFY(isSame(m8, bothReverseValues)); | 
| 2612 |  | 
| 2613 |     QMatrix4x4 m9; | 
| 2614 |     m9.translate(x: 4.0f, y: 5.0f, z: -3.0f); | 
| 2615 |     m9.scale(x: 2.0f, y: 7.0f, z: 9.0f); | 
| 2616 |     QVERIFY(isSame(m9, bothValues)); | 
| 2617 |     m9.scale(x: 2.0f, y: 7.0f, z: 9.0f); | 
| 2618 |     QVERIFY(isSame(m9, bothThenScaleValues)); | 
| 2619 |  | 
| 2620 |     QMatrix4x4 m10; | 
| 2621 |     m10.translate(vector: QVector3D(4.0f, 5.0f, -3.0f)); | 
| 2622 |     m10.scale(vector: QVector3D(2.0f, 7.0f, 9.0f)); | 
| 2623 |     QVERIFY(isSame(m10, bothValues)); | 
| 2624 |     m10.scale(vector: QVector3D(2.0f, 7.0f, 9.0f)); | 
| 2625 |     QVERIFY(isSame(m10, bothThenScaleValues)); | 
| 2626 | } | 
| 2627 |  | 
| 2628 | // Test orthographic projections. | 
| 2629 | void tst_QMatrixNxN::ortho() | 
| 2630 | { | 
| 2631 |     QMatrix4x4 m1; | 
| 2632 |     m1.ortho(rect: QRect(0, 0, 300, 150)); | 
| 2633 |     QPointF p1 = m1 * QPointF(0, 0); | 
| 2634 |     QPointF p2 = m1 * QPointF(300, 0); | 
| 2635 |     QPointF p3 = m1 * QPointF(0, 150); | 
| 2636 |     QPointF p4 = m1 * QPointF(300, 150); | 
| 2637 |     QVector3D p5 = m1 * QVector3D(300, 150, 1); | 
| 2638 |     QVERIFY(qFuzzyCompare(float(p1.x()), -1.0f)); | 
| 2639 |     QVERIFY(qFuzzyCompare(float(p1.y()), 1.0f)); | 
| 2640 |     QVERIFY(qFuzzyCompare(float(p2.x()), 1.0f)); | 
| 2641 |     QVERIFY(qFuzzyCompare(float(p2.y()), 1.0f)); | 
| 2642 |     QVERIFY(qFuzzyCompare(float(p3.x()), -1.0f)); | 
| 2643 |     QVERIFY(qFuzzyCompare(float(p3.y()), -1.0f)); | 
| 2644 |     QVERIFY(qFuzzyCompare(float(p4.x()), 1.0f)); | 
| 2645 |     QVERIFY(qFuzzyCompare(float(p4.y()), -1.0f)); | 
| 2646 |     QVERIFY(qFuzzyCompare(float(p5.x()), 1.0f)); | 
| 2647 |     QVERIFY(qFuzzyCompare(float(p5.y()), -1.0f)); | 
| 2648 |     QVERIFY(qFuzzyCompare(float(p5.z()), -1.0f)); | 
| 2649 |  | 
| 2650 |     QMatrix4x4 m2; | 
| 2651 |     m2.ortho(rect: QRectF(0, 0, 300, 150)); | 
| 2652 |     p1 = m2 * QPointF(0, 0); | 
| 2653 |     p2 = m2 * QPointF(300, 0); | 
| 2654 |     p3 = m2 * QPointF(0, 150); | 
| 2655 |     p4 = m2 * QPointF(300, 150); | 
| 2656 |     p5 = m2 * QVector3D(300, 150, 1); | 
| 2657 |     QVERIFY(qFuzzyCompare(float(p1.x()), -1.0f)); | 
| 2658 |     QVERIFY(qFuzzyCompare(float(p1.y()), 1.0f)); | 
| 2659 |     QVERIFY(qFuzzyCompare(float(p2.x()), 1.0f)); | 
| 2660 |     QVERIFY(qFuzzyCompare(float(p2.y()), 1.0f)); | 
| 2661 |     QVERIFY(qFuzzyCompare(float(p3.x()), -1.0f)); | 
| 2662 |     QVERIFY(qFuzzyCompare(float(p3.y()), -1.0f)); | 
| 2663 |     QVERIFY(qFuzzyCompare(float(p4.x()), 1.0f)); | 
| 2664 |     QVERIFY(qFuzzyCompare(float(p4.y()), -1.0f)); | 
| 2665 |     QVERIFY(qFuzzyCompare(float(p5.x()), 1.0f)); | 
| 2666 |     QVERIFY(qFuzzyCompare(float(p5.y()), -1.0f)); | 
| 2667 |     QVERIFY(qFuzzyCompare(float(p5.z()), -1.0f)); | 
| 2668 |  | 
| 2669 |     QMatrix4x4 m3; | 
| 2670 |     m3.ortho(left: 0, right: 300, bottom: 150, top: 0, nearPlane: -1, farPlane: 1); | 
| 2671 |     p1 = m3 * QPointF(0, 0); | 
| 2672 |     p2 = m3 * QPointF(300, 0); | 
| 2673 |     p3 = m3 * QPointF(0, 150); | 
| 2674 |     p4 = m3 * QPointF(300, 150); | 
| 2675 |     p5 = m3 * QVector3D(300, 150, 1); | 
| 2676 |     QVERIFY(qFuzzyCompare(float(p1.x()), -1.0f)); | 
| 2677 |     QVERIFY(qFuzzyCompare(float(p1.y()), 1.0f)); | 
| 2678 |     QVERIFY(qFuzzyCompare(float(p2.x()), 1.0f)); | 
| 2679 |     QVERIFY(qFuzzyCompare(float(p2.y()), 1.0f)); | 
| 2680 |     QVERIFY(qFuzzyCompare(float(p3.x()), -1.0f)); | 
| 2681 |     QVERIFY(qFuzzyCompare(float(p3.y()), -1.0f)); | 
| 2682 |     QVERIFY(qFuzzyCompare(float(p4.x()), 1.0f)); | 
| 2683 |     QVERIFY(qFuzzyCompare(float(p4.y()), -1.0f)); | 
| 2684 |     QVERIFY(qFuzzyCompare(float(p5.x()), 1.0f)); | 
| 2685 |     QVERIFY(qFuzzyCompare(float(p5.y()), -1.0f)); | 
| 2686 |     QVERIFY(qFuzzyCompare(float(p5.z()), -1.0f)); | 
| 2687 |  | 
| 2688 |     QMatrix4x4 m4; | 
| 2689 |     m4.ortho(left: 0, right: 300, bottom: 150, top: 0, nearPlane: -2, farPlane: 3); | 
| 2690 |     p1 = m4 * QPointF(0, 0); | 
| 2691 |     p2 = m4 * QPointF(300, 0); | 
| 2692 |     p3 = m4 * QPointF(0, 150); | 
| 2693 |     p4 = m4 * QPointF(300, 150); | 
| 2694 |     p5 = m4 * QVector3D(300, 150, 1); | 
| 2695 |     QVERIFY(qFuzzyCompare(float(p1.x()), -1.0f)); | 
| 2696 |     QVERIFY(qFuzzyCompare(float(p1.y()), 1.0f)); | 
| 2697 |     QVERIFY(qFuzzyCompare(float(p2.x()), 1.0f)); | 
| 2698 |     QVERIFY(qFuzzyCompare(float(p2.y()), 1.0f)); | 
| 2699 |     QVERIFY(qFuzzyCompare(float(p3.x()), -1.0f)); | 
| 2700 |     QVERIFY(qFuzzyCompare(float(p3.y()), -1.0f)); | 
| 2701 |     QVERIFY(qFuzzyCompare(float(p4.x()), 1.0f)); | 
| 2702 |     QVERIFY(qFuzzyCompare(float(p4.y()), -1.0f)); | 
| 2703 |     QVERIFY(qFuzzyCompare(float(p5.x()), 1.0f)); | 
| 2704 |     QVERIFY(qFuzzyCompare(float(p5.y()), -1.0f)); | 
| 2705 |     QVERIFY(qFuzzyCompare(float(p5.z()), -0.6f)); | 
| 2706 |  | 
| 2707 |     // An empty view volume should leave the matrix alone. | 
| 2708 |     QMatrix4x4 m5; | 
| 2709 |     m5.ortho(left: 0, right: 0, bottom: 150, top: 0, nearPlane: -2, farPlane: 3); | 
| 2710 |     QVERIFY(m5.isIdentity()); | 
| 2711 |     m5.ortho(left: 0, right: 300, bottom: 150, top: 150, nearPlane: -2, farPlane: 3); | 
| 2712 |     QVERIFY(m5.isIdentity()); | 
| 2713 |     m5.ortho(left: 0, right: 300, bottom: 150, top: 0, nearPlane: 2, farPlane: 2); | 
| 2714 |     QVERIFY(m5.isIdentity()); | 
| 2715 | } | 
| 2716 |  | 
| 2717 | // Test perspective frustum projections. | 
| 2718 | void tst_QMatrixNxN::frustum() | 
| 2719 | { | 
| 2720 |     QMatrix4x4 m1; | 
| 2721 |     m1.frustum(left: -1.0f, right: 1.0f, bottom: -1.0f, top: 1.0f, nearPlane: -1.0f, farPlane: 1.0f); | 
| 2722 |     QVector3D p1 = m1 * QVector3D(-1.0f, -1.0f, 1.0f); | 
| 2723 |     QVector3D p2 = m1 * QVector3D(1.0f, -1.0f, 1.0f); | 
| 2724 |     QVector3D p3 = m1 * QVector3D(-1.0f, 1.0f, 1.0f); | 
| 2725 |     QVector3D p4 = m1 * QVector3D(1.0f, 1.0f, 1.0f); | 
| 2726 |     QVector3D p5 = m1 * QVector3D(0.0f, 0.0f, 2.0f); | 
| 2727 |     QVERIFY(qFuzzyCompare(p1.x(), -1.0f)); | 
| 2728 |     QVERIFY(qFuzzyCompare(p1.y(), -1.0f)); | 
| 2729 |     QVERIFY(qFuzzyCompare(p1.z(), -1.0f)); | 
| 2730 |     QVERIFY(qFuzzyCompare(p2.x(), 1.0f)); | 
| 2731 |     QVERIFY(qFuzzyCompare(p2.y(), -1.0f)); | 
| 2732 |     QVERIFY(qFuzzyCompare(p2.z(), -1.0f)); | 
| 2733 |     QVERIFY(qFuzzyCompare(p3.x(), -1.0f)); | 
| 2734 |     QVERIFY(qFuzzyCompare(p3.y(), 1.0f)); | 
| 2735 |     QVERIFY(qFuzzyCompare(p3.z(), -1.0f)); | 
| 2736 |     QVERIFY(qFuzzyCompare(p4.x(), 1.0f)); | 
| 2737 |     QVERIFY(qFuzzyCompare(p4.y(), 1.0f)); | 
| 2738 |     QVERIFY(qFuzzyCompare(p4.z(), -1.0f)); | 
| 2739 |     QVERIFY(qFuzzyCompare(p5.x(), 0.0f)); | 
| 2740 |     QVERIFY(qFuzzyCompare(p5.y(), 0.0f)); | 
| 2741 |     QVERIFY(qFuzzyCompare(p5.z(), -0.5f)); | 
| 2742 |  | 
| 2743 |     // An empty view volume should leave the matrix alone. | 
| 2744 |     QMatrix4x4 m5; | 
| 2745 |     m5.frustum(left: 0, right: 0, bottom: 150, top: 0, nearPlane: -2, farPlane: 3); | 
| 2746 |     QVERIFY(m5.isIdentity()); | 
| 2747 |     m5.frustum(left: 0, right: 300, bottom: 150, top: 150, nearPlane: -2, farPlane: 3); | 
| 2748 |     QVERIFY(m5.isIdentity()); | 
| 2749 |     m5.frustum(left: 0, right: 300, bottom: 150, top: 0, nearPlane: 2, farPlane: 2); | 
| 2750 |     QVERIFY(m5.isIdentity()); | 
| 2751 | } | 
| 2752 |  | 
| 2753 | // Test perspective field-of-view projections. | 
| 2754 | void tst_QMatrixNxN::perspective() | 
| 2755 | { | 
| 2756 |     QMatrix4x4 m1; | 
| 2757 |     m1.perspective(verticalAngle: 45.0f, aspectRatio: 1.0f, nearPlane: -1.0f, farPlane: 1.0f); | 
| 2758 |     QVector3D p1 = m1 * QVector3D(-1.0f, -1.0f, 1.0f); | 
| 2759 |     QVector3D p2 = m1 * QVector3D(1.0f, -1.0f, 1.0f); | 
| 2760 |     QVector3D p3 = m1 * QVector3D(-1.0f, 1.0f, 1.0f); | 
| 2761 |     QVector3D p4 = m1 * QVector3D(1.0f, 1.0f, 1.0f); | 
| 2762 |     QVector3D p5 = m1 * QVector3D(0.0f, 0.0f, 2.0f); | 
| 2763 |     QVERIFY(qFuzzyCompare(p1.x(), 2.41421f)); | 
| 2764 |     QVERIFY(qFuzzyCompare(p1.y(), 2.41421f)); | 
| 2765 |     QVERIFY(qFuzzyCompare(p1.z(), -1.0f)); | 
| 2766 |     QVERIFY(qFuzzyCompare(p2.x(), -2.41421f)); | 
| 2767 |     QVERIFY(qFuzzyCompare(p2.y(), 2.41421f)); | 
| 2768 |     QVERIFY(qFuzzyCompare(p2.z(), -1.0f)); | 
| 2769 |     QVERIFY(qFuzzyCompare(p3.x(), 2.41421f)); | 
| 2770 |     QVERIFY(qFuzzyCompare(p3.y(), -2.41421f)); | 
| 2771 |     QVERIFY(qFuzzyCompare(p3.z(), -1.0f)); | 
| 2772 |     QVERIFY(qFuzzyCompare(p4.x(), -2.41421f)); | 
| 2773 |     QVERIFY(qFuzzyCompare(p4.y(), -2.41421f)); | 
| 2774 |     QVERIFY(qFuzzyCompare(p4.z(), -1.0f)); | 
| 2775 |     QVERIFY(qFuzzyCompare(p5.x(), 0.0f)); | 
| 2776 |     QVERIFY(qFuzzyCompare(p5.y(), 0.0f)); | 
| 2777 |     QVERIFY(qFuzzyCompare(p5.z(), -0.5f)); | 
| 2778 |  | 
| 2779 |     // An empty view volume should leave the matrix alone. | 
| 2780 |     QMatrix4x4 m5; | 
| 2781 |     m5.perspective(verticalAngle: 45.0f, aspectRatio: 1.0f, nearPlane: 0.0f, farPlane: 0.0f); | 
| 2782 |     QVERIFY(m5.isIdentity()); | 
| 2783 |     m5.perspective(verticalAngle: 45.0f, aspectRatio: 0.0f, nearPlane: -1.0f, farPlane: 1.0f); | 
| 2784 |     QVERIFY(m5.isIdentity()); | 
| 2785 |     m5.perspective(verticalAngle: 0.0f, aspectRatio: 1.0f, nearPlane: -1.0f, farPlane: 1.0f); | 
| 2786 |     QVERIFY(m5.isIdentity()); | 
| 2787 | } | 
| 2788 |  | 
| 2789 | // Test viewport transformations | 
| 2790 | void tst_QMatrixNxN::viewport() | 
| 2791 | { | 
| 2792 |     // Uses default depth range of 0->1 | 
| 2793 |     QMatrix4x4 m1; | 
| 2794 |     m1.viewport(left: 0.0f, bottom: 0.0f, width: 1024.0f, height: 768.0f); | 
| 2795 |  | 
| 2796 |     // Lower left | 
| 2797 |     QVector4D p1 = m1 * QVector4D(-1.0f, -1.0f, 0.0f, 1.0f); | 
| 2798 |     QVERIFY(qFuzzyIsNull(p1.x())); | 
| 2799 |     QVERIFY(qFuzzyIsNull(p1.y())); | 
| 2800 |     QVERIFY(qFuzzyCompare(p1.z(), 0.5f)); | 
| 2801 |  | 
| 2802 |     // Lower right | 
| 2803 |     QVector4D p2 = m1 * QVector4D(1.0f, -1.0f, 0.0f, 1.0f); | 
| 2804 |     QVERIFY(qFuzzyCompare(p2.x(), 1024.0f)); | 
| 2805 |     QVERIFY(qFuzzyIsNull(p2.y())); | 
| 2806 |  | 
| 2807 |     // Upper right | 
| 2808 |     QVector4D p3 = m1 * QVector4D(1.0f, 1.0f, 0.0f, 1.0f); | 
| 2809 |     QVERIFY(qFuzzyCompare(p3.x(), 1024.0f)); | 
| 2810 |     QVERIFY(qFuzzyCompare(p3.y(), 768.0f)); | 
| 2811 |  | 
| 2812 |     // Upper left | 
| 2813 |     QVector4D p4 = m1 * QVector4D(-1.0f, 1.0f, 0.0f, 1.0f); | 
| 2814 |     QVERIFY(qFuzzyIsNull(p4.x())); | 
| 2815 |     QVERIFY(qFuzzyCompare(p4.y(), 768.0f)); | 
| 2816 |  | 
| 2817 |     // Center | 
| 2818 |     QVector4D p5 = m1 * QVector4D(0.0f, 0.0f, 0.0f, 1.0f); | 
| 2819 |     QVERIFY(qFuzzyCompare(p5.x(), 1024.0f / 2.0f)); | 
| 2820 |     QVERIFY(qFuzzyCompare(p5.y(), 768.0f / 2.0f)); | 
| 2821 | } | 
| 2822 |  | 
| 2823 | // Test left-handed vs right-handed coordinate flipping. | 
| 2824 | void tst_QMatrixNxN::flipCoordinates() | 
| 2825 | { | 
| 2826 |     QMatrix4x4 m1; | 
| 2827 |     m1.flipCoordinates(); | 
| 2828 |     QVector3D p1 = m1 * QVector3D(2, 3, 4); | 
| 2829 |     QVERIFY(p1 == QVector3D(2, -3, -4)); | 
| 2830 |  | 
| 2831 |     QMatrix4x4 m2; | 
| 2832 |     m2.scale(x: 2.0f, y: 3.0f, z: 1.0f); | 
| 2833 |     m2.flipCoordinates(); | 
| 2834 |     QVector3D p2 = m2 * QVector3D(2, 3, 4); | 
| 2835 |     QVERIFY(p2 == QVector3D(4, -9, -4)); | 
| 2836 |  | 
| 2837 |     QMatrix4x4 m3; | 
| 2838 |     m3.translate(x: 2.0f, y: 3.0f, z: 1.0f); | 
| 2839 |     m3.flipCoordinates(); | 
| 2840 |     QVector3D p3 = m3 * QVector3D(2, 3, 4); | 
| 2841 |     QVERIFY(p3 == QVector3D(4, 0, -3)); | 
| 2842 |  | 
| 2843 |     QMatrix4x4 m4; | 
| 2844 |     m4.rotate(angle: 90.0f, x: 0.0f, y: 0.0f, z: 1.0f); | 
| 2845 |     m4.flipCoordinates(); | 
| 2846 |     QVector3D p4 = m4 * QVector3D(2, 3, 4); | 
| 2847 |     QVERIFY(p4 == QVector3D(3, 2, -4)); | 
| 2848 | } | 
| 2849 |  | 
| 2850 | // Test conversion of generic matrices to and from the non-generic types. | 
| 2851 | void tst_QMatrixNxN::convertGeneric() | 
| 2852 | { | 
| 2853 |     QMatrix4x3 m1(uniqueValues4x3); | 
| 2854 |  | 
| 2855 |     static float const unique4x4[16] = { | 
| 2856 |         1.0f, 2.0f, 3.0f, 4.0f, | 
| 2857 |         5.0f, 6.0f, 7.0f, 8.0f, | 
| 2858 |         9.0f, 10.0f, 11.0f, 12.0f, | 
| 2859 |         0.0f, 0.0f, 0.0f, 1.0f | 
| 2860 |     }; | 
| 2861 |     QMatrix4x4 m4(m1); | 
| 2862 |     QVERIFY(isSame(m4, unique4x4)); | 
| 2863 |  | 
| 2864 | #if QT_DEPRECATED_SINCE(5, 0) | 
| 2865 |     QMatrix4x4 m5 = qGenericMatrixToMatrix4x4(matrix: m1); | 
| 2866 |     QVERIFY(isSame(m5, unique4x4)); | 
| 2867 | #endif | 
| 2868 |  | 
| 2869 |     static float const conv4x4[12] = { | 
| 2870 |         1.0f, 2.0f, 3.0f, 4.0f, | 
| 2871 |         5.0f, 6.0f, 7.0f, 8.0f, | 
| 2872 |         9.0f, 10.0f, 11.0f, 12.0f | 
| 2873 |     }; | 
| 2874 |     QMatrix4x4 m9(uniqueValues4); | 
| 2875 |  | 
| 2876 |     QMatrix4x3 m10 = m9.toGenericMatrix<4, 3>(); | 
| 2877 |     QVERIFY(isSame(m10, conv4x4)); | 
| 2878 |  | 
| 2879 | #if QT_DEPRECATED_SINCE(5, 0) | 
| 2880 |     QMatrix4x3 m11 = qGenericMatrixFromMatrix4x4<4, 3>(matrix: m9); | 
| 2881 |     QVERIFY(isSame(m11, conv4x4)); | 
| 2882 | #endif | 
| 2883 | } | 
| 2884 |  | 
| 2885 | // Copy of "flagBits" in qmatrix4x4.h. | 
| 2886 | enum { | 
| 2887 |     Identity        = 0x0000, // Identity matrix | 
| 2888 |     Translation     = 0x0001, // Contains a translation | 
| 2889 |     Scale           = 0x0002, // Contains a scale | 
| 2890 |     Rotation2D      = 0x0004, // Contains a rotation about the Z axis | 
| 2891 |     Rotation        = 0x0008, // Contains an arbitrary rotation | 
| 2892 |     Perspective     = 0x0010, // Last row is different from (0, 0, 0, 1) | 
| 2893 |     General         = 0x001f  // General matrix, unknown contents | 
| 2894 | }; | 
| 2895 |  | 
| 2896 | // Structure that allows direct access to "flagBits" for testing. | 
| 2897 | struct Matrix4x4 | 
| 2898 | { | 
| 2899 |     float m[4][4]; | 
| 2900 |     int flagBits; | 
| 2901 | }; | 
| 2902 |  | 
| 2903 | // Test the inferring of special matrix types. | 
| 2904 | void tst_QMatrixNxN::optimize_data() | 
| 2905 | { | 
| 2906 |     QTest::addColumn<void *>(name: "mValues" ); | 
| 2907 |     QTest::addColumn<int>(name: "flagBits" ); | 
| 2908 |  | 
| 2909 |     QTest::newRow(dataTag: "null" ) | 
| 2910 |         << (void *)nullValues4 << (int)General; | 
| 2911 |     QTest::newRow(dataTag: "identity" ) | 
| 2912 |         << (void *)identityValues4 << (int)Identity; | 
| 2913 |     QTest::newRow(dataTag: "unique" ) | 
| 2914 |         << (void *)uniqueValues4 << (int)General; | 
| 2915 |  | 
| 2916 |     static float scaleValues[16] = { | 
| 2917 |         2.0f, 0.0f, 0.0f, 0.0f, | 
| 2918 |         0.0f, 3.0f, 0.0f, 0.0f, | 
| 2919 |         0.0f, 0.0f, 4.0f, 0.0f, | 
| 2920 |         0.0f, 0.0f, 0.0f, 1.0f | 
| 2921 |     }; | 
| 2922 |     QTest::newRow(dataTag: "scale" ) | 
| 2923 |         << (void *)scaleValues << (int)Scale; | 
| 2924 |  | 
| 2925 |     static float translateValues[16] = { | 
| 2926 |         1.0f, 0.0f, 0.0f, 2.0f, | 
| 2927 |         0.0f, 1.0f, 0.0f, 3.0f, | 
| 2928 |         0.0f, 0.0f, 1.0f, 4.0f, | 
| 2929 |         0.0f, 0.0f, 0.0f, 1.0f | 
| 2930 |     }; | 
| 2931 |     QTest::newRow(dataTag: "translate" ) | 
| 2932 |         << (void *)translateValues << (int)Translation; | 
| 2933 |  | 
| 2934 |     static float scaleTranslateValues[16] = { | 
| 2935 |         1.0f, 0.0f, 0.0f, 2.0f, | 
| 2936 |         0.0f, 2.0f, 0.0f, 0.0f, | 
| 2937 |         0.0f, 0.0f, 1.0f, 4.0f, | 
| 2938 |         0.0f, 0.0f, 0.0f, 1.0f | 
| 2939 |     }; | 
| 2940 |     QTest::newRow(dataTag: "scaleTranslate" ) | 
| 2941 |         << (void *)scaleTranslateValues << (int)(Scale | Translation); | 
| 2942 |  | 
| 2943 |     static float rotateValues[16] = { | 
| 2944 |         0.0f, 1.0f, 0.0f, 0.0f, | 
| 2945 |         -1.0f, 0.0f, 0.0f, 0.0f, | 
| 2946 |         0.0f, 0.0f, 1.0f, 0.0f, | 
| 2947 |         0.0f, 0.0f, 0.0f, 1.0f | 
| 2948 |     }; | 
| 2949 |     QTest::newRow(dataTag: "rotate" ) | 
| 2950 |         << (void *)rotateValues << (int)Rotation2D; | 
| 2951 |  | 
| 2952 |     // Left-handed system, not a simple rotation. | 
| 2953 |     static float scaleRotateValues[16] = { | 
| 2954 |         0.0f, 1.0f, 0.0f, 0.0f, | 
| 2955 |         1.0f, 0.0f, 0.0f, 0.0f, | 
| 2956 |         0.0f, 0.0f, 1.0f, 0.0f, | 
| 2957 |         0.0f, 0.0f, 0.0f, 1.0f | 
| 2958 |     }; | 
| 2959 |     QTest::newRow(dataTag: "scaleRotate" ) | 
| 2960 |         << (void *)scaleRotateValues << (int)(Scale | Rotation2D); | 
| 2961 |  | 
| 2962 |     static float matrix2x2Values[16] = { | 
| 2963 |         1.0f, 2.0f, 0.0f, 0.0f, | 
| 2964 |         8.0f, 3.0f, 0.0f, 0.0f, | 
| 2965 |         0.0f, 0.0f, 9.0f, 0.0f, | 
| 2966 |         0.0f, 0.0f, 0.0f, 1.0f | 
| 2967 |     }; | 
| 2968 |     QTest::newRow(dataTag: "matrix2x2" ) | 
| 2969 |         << (void *)matrix2x2Values << (int)(Scale | Rotation2D); | 
| 2970 |  | 
| 2971 |     static float matrix3x3Values[16] = { | 
| 2972 |         1.0f, 2.0f, 4.0f, 0.0f, | 
| 2973 |         8.0f, 3.0f, 5.0f, 0.0f, | 
| 2974 |         6.0f, 7.0f, 9.0f, 0.0f, | 
| 2975 |         0.0f, 0.0f, 0.0f, 1.0f | 
| 2976 |     }; | 
| 2977 |     QTest::newRow(dataTag: "matrix3x3" ) | 
| 2978 |         << (void *)matrix3x3Values << (int)(Scale | Rotation2D | Rotation); | 
| 2979 |  | 
| 2980 |     static float rotateTranslateValues[16] = { | 
| 2981 |         0.0f, 1.0f, 0.0f, 1.0f, | 
| 2982 |         -1.0f, 0.0f, 0.0f, 2.0f, | 
| 2983 |         0.0f, 0.0f, 1.0f, 3.0f, | 
| 2984 |         0.0f, 0.0f, 0.0f, 1.0f | 
| 2985 |     }; | 
| 2986 |     QTest::newRow(dataTag: "rotateTranslate" ) | 
| 2987 |         << (void *)rotateTranslateValues << (int)(Translation | Rotation2D); | 
| 2988 |  | 
| 2989 |     // Left-handed system, not a simple rotation. | 
| 2990 |     static float scaleRotateTranslateValues[16] = { | 
| 2991 |         0.0f, 1.0f, 0.0f, 1.0f, | 
| 2992 |         1.0f, 0.0f, 0.0f, 2.0f, | 
| 2993 |         0.0f, 0.0f, 1.0f, 3.0f, | 
| 2994 |         0.0f, 0.0f, 0.0f, 1.0f | 
| 2995 |     }; | 
| 2996 |     QTest::newRow(dataTag: "scaleRotateTranslate" ) | 
| 2997 |         << (void *)scaleRotateTranslateValues << (int)(Translation | Scale | Rotation2D); | 
| 2998 |  | 
| 2999 |     static float belowValues[16] = { | 
| 3000 |         1.0f, 0.0f, 0.0f, 0.0f, | 
| 3001 |         0.0f, 1.0f, 0.0f, 0.0f, | 
| 3002 |         0.0f, 0.0f, 1.0f, 0.0f, | 
| 3003 |         4.0f, 0.0f, 0.0f, 1.0f | 
| 3004 |     }; | 
| 3005 |     QTest::newRow(dataTag: "below" ) | 
| 3006 |         << (void *)belowValues << (int)General; | 
| 3007 | } | 
| 3008 | void tst_QMatrixNxN::optimize() | 
| 3009 | { | 
| 3010 |     QFETCH(void *, mValues); | 
| 3011 |     QFETCH(int, flagBits); | 
| 3012 |  | 
| 3013 |     QMatrix4x4 m((const float *)mValues); | 
| 3014 |     m.optimize(); | 
| 3015 |  | 
| 3016 |     QCOMPARE(reinterpret_cast<Matrix4x4 *>(&m)->flagBits, flagBits); | 
| 3017 | } | 
| 3018 |  | 
| 3019 | void tst_QMatrixNxN::columnsAndRows() | 
| 3020 | { | 
| 3021 |     QMatrix4x4 m1(uniqueValues4); | 
| 3022 |  | 
| 3023 |     QVERIFY(m1.column(0) == QVector4D(1, 5, 9, 13)); | 
| 3024 |     QVERIFY(m1.column(1) == QVector4D(2, 6, 10, 14)); | 
| 3025 |     QVERIFY(m1.column(2) == QVector4D(3, 7, 11, 15)); | 
| 3026 |     QVERIFY(m1.column(3) == QVector4D(4, 8, 12, 16)); | 
| 3027 |  | 
| 3028 |     QVERIFY(m1.row(0) == QVector4D(1, 2, 3, 4)); | 
| 3029 |     QVERIFY(m1.row(1) == QVector4D(5, 6, 7, 8)); | 
| 3030 |     QVERIFY(m1.row(2) == QVector4D(9, 10, 11, 12)); | 
| 3031 |     QVERIFY(m1.row(3) == QVector4D(13, 14, 15, 16)); | 
| 3032 |  | 
| 3033 |     m1.setColumn(index: 0, value: QVector4D(-1, -5, -9, -13)); | 
| 3034 |     m1.setColumn(index: 1, value: QVector4D(-2, -6, -10, -14)); | 
| 3035 |     m1.setColumn(index: 2, value: QVector4D(-3, -7, -11, -15)); | 
| 3036 |     m1.setColumn(index: 3, value: QVector4D(-4, -8, -12, -16)); | 
| 3037 |  | 
| 3038 |     QVERIFY(m1.column(0) == QVector4D(-1, -5, -9, -13)); | 
| 3039 |     QVERIFY(m1.column(1) == QVector4D(-2, -6, -10, -14)); | 
| 3040 |     QVERIFY(m1.column(2) == QVector4D(-3, -7, -11, -15)); | 
| 3041 |     QVERIFY(m1.column(3) == QVector4D(-4, -8, -12, -16)); | 
| 3042 |  | 
| 3043 |     QVERIFY(m1.row(0) == QVector4D(-1, -2, -3, -4)); | 
| 3044 |     QVERIFY(m1.row(1) == QVector4D(-5, -6, -7, -8)); | 
| 3045 |     QVERIFY(m1.row(2) == QVector4D(-9, -10, -11, -12)); | 
| 3046 |     QVERIFY(m1.row(3) == QVector4D(-13, -14, -15, -16)); | 
| 3047 |  | 
| 3048 |     m1.setRow(index: 0, value: QVector4D(1, 5, 9, 13)); | 
| 3049 |     m1.setRow(index: 1, value: QVector4D(2, 6, 10, 14)); | 
| 3050 |     m1.setRow(index: 2, value: QVector4D(3, 7, 11, 15)); | 
| 3051 |     m1.setRow(index: 3, value: QVector4D(4, 8, 12, 16)); | 
| 3052 |  | 
| 3053 |     QVERIFY(m1.column(0) == QVector4D(1, 2, 3, 4)); | 
| 3054 |     QVERIFY(m1.column(1) == QVector4D(5, 6, 7, 8)); | 
| 3055 |     QVERIFY(m1.column(2) == QVector4D(9, 10, 11, 12)); | 
| 3056 |     QVERIFY(m1.column(3) == QVector4D(13, 14, 15, 16)); | 
| 3057 |  | 
| 3058 |     QVERIFY(m1.row(0) == QVector4D(1, 5, 9, 13)); | 
| 3059 |     QVERIFY(m1.row(1) == QVector4D(2, 6, 10, 14)); | 
| 3060 |     QVERIFY(m1.row(2) == QVector4D(3, 7, 11, 15)); | 
| 3061 |     QVERIFY(m1.row(3) == QVector4D(4, 8, 12, 16)); | 
| 3062 | } | 
| 3063 |  | 
| 3064 | #if QT_DEPRECATED_SINCE(5, 15) | 
| 3065 | QT_WARNING_PUSH | 
| 3066 | QT_WARNING_DISABLE_DEPRECATED | 
| 3067 | // Test converting QMatrix objects into QMatrix4x4 and then | 
| 3068 | // checking that transformations in the original perform the | 
| 3069 | // equivalent transformations in the new matrix. | 
| 3070 | void tst_QMatrixNxN::convertQMatrix() | 
| 3071 | { | 
| 3072 |     QMatrix m1; | 
| 3073 |     m1.translate(dx: -3.5, dy: 2.0); | 
| 3074 |     QPointF p1 = m1.map(p: QPointF(100.0, 150.0)); | 
| 3075 |     QCOMPARE(p1.x(), 100.0 - 3.5); | 
| 3076 |     QCOMPARE(p1.y(), 150.0 + 2.0); | 
| 3077 |  | 
| 3078 |     QMatrix4x4 m2(m1); | 
| 3079 |     QPointF p2 = m2 * QPointF(100.0, 150.0); | 
| 3080 |     QCOMPARE((double)p2.x(), 100.0 - 3.5); | 
| 3081 |     QCOMPARE((double)p2.y(), 150.0 + 2.0); | 
| 3082 |     QCOMPARE(m1, m2.toAffine()); | 
| 3083 |  | 
| 3084 |     QMatrix m3; | 
| 3085 |     m3.scale(sx: 1.5, sy: -2.0); | 
| 3086 |     QPointF p3 = m3.map(p: QPointF(100.0, 150.0)); | 
| 3087 |     QCOMPARE(p3.x(), 1.5 * 100.0); | 
| 3088 |     QCOMPARE(p3.y(), -2.0 * 150.0); | 
| 3089 |  | 
| 3090 |     QMatrix4x4 m4(m3); | 
| 3091 |     QPointF p4 = m4 * QPointF(100.0, 150.0); | 
| 3092 |     QCOMPARE((double)p4.x(), 1.5 * 100.0); | 
| 3093 |     QCOMPARE((double)p4.y(), -2.0 * 150.0); | 
| 3094 |     QCOMPARE(m3, m4.toAffine()); | 
| 3095 |  | 
| 3096 |     QMatrix m5; | 
| 3097 |     m5.rotate(a: 45.0); | 
| 3098 |     QPointF p5 = m5.map(p: QPointF(100.0, 150.0)); | 
| 3099 |  | 
| 3100 |     QMatrix4x4 m6(m5); | 
| 3101 |     QPointF p6 = m6 * QPointF(100.0, 150.0); | 
| 3102 |     QVERIFY(qFuzzyCompare(float(p5.x()), float(p6.x()))); | 
| 3103 |     QVERIFY(qFuzzyCompare(float(p5.y()), float(p6.y()))); | 
| 3104 |  | 
| 3105 |     QMatrix m7 = m6.toAffine(); | 
| 3106 |     QVERIFY(qFuzzyCompare(float(m5.m11()), float(m7.m11()))); | 
| 3107 |     QVERIFY(qFuzzyCompare(float(m5.m12()), float(m7.m12()))); | 
| 3108 |     QVERIFY(qFuzzyCompare(float(m5.m21()), float(m7.m21()))); | 
| 3109 |     QVERIFY(qFuzzyCompare(float(m5.m22()), float(m7.m22()))); | 
| 3110 |     QVERIFY(qFuzzyCompare(float(m5.dx()), float(m7.dx()))); | 
| 3111 |     QVERIFY(qFuzzyCompare(float(m5.dy()), float(m7.dy()))); | 
| 3112 | } | 
| 3113 | QT_WARNING_POP | 
| 3114 | #endif | 
| 3115 |  | 
| 3116 | // Test converting QTransform objects into QMatrix4x4 and then | 
| 3117 | // checking that transformations in the original perform the | 
| 3118 | // equivalent transformations in the new matrix. | 
| 3119 | void tst_QMatrixNxN::convertQTransform() | 
| 3120 | { | 
| 3121 |     QTransform m1; | 
| 3122 |     m1.translate(dx: -3.5, dy: 2.0); | 
| 3123 |     QPointF p1 = m1.map(p: QPointF(100.0, 150.0)); | 
| 3124 |     QCOMPARE(p1.x(), 100.0 - 3.5); | 
| 3125 |     QCOMPARE(p1.y(), 150.0 + 2.0); | 
| 3126 |  | 
| 3127 |     QMatrix4x4 m2(m1); | 
| 3128 |     QPointF p2 = m2 * QPointF(100.0, 150.0); | 
| 3129 |     QCOMPARE((double)p2.x(), 100.0 - 3.5); | 
| 3130 |     QCOMPARE((double)p2.y(), 150.0 + 2.0); | 
| 3131 |     QCOMPARE(m1, m2.toTransform()); | 
| 3132 |  | 
| 3133 |     QTransform m3; | 
| 3134 |     m3.scale(sx: 1.5, sy: -2.0); | 
| 3135 |     QPointF p3 = m3.map(p: QPointF(100.0, 150.0)); | 
| 3136 |     QCOMPARE(p3.x(), 1.5 * 100.0); | 
| 3137 |     QCOMPARE(p3.y(), -2.0 * 150.0); | 
| 3138 |  | 
| 3139 |     QMatrix4x4 m4(m3); | 
| 3140 |     QPointF p4 = m4 * QPointF(100.0, 150.0); | 
| 3141 |     QCOMPARE((double)p4.x(), 1.5 * 100.0); | 
| 3142 |     QCOMPARE((double)p4.y(), -2.0 * 150.0); | 
| 3143 |     QCOMPARE(m3, m4.toTransform()); | 
| 3144 |  | 
| 3145 |     QTransform m5; | 
| 3146 |     m5.rotate(a: 45.0); | 
| 3147 |     QPointF p5 = m5.map(p: QPointF(100.0, 150.0)); | 
| 3148 |  | 
| 3149 |     QMatrix4x4 m6(m5); | 
| 3150 |     QPointF p6 = m6 * QPointF(100.0, 150.0); | 
| 3151 |     QVERIFY(qFuzzyCompare(float(p5.x()), float(p6.x()))); | 
| 3152 |     QVERIFY(qFuzzyCompare(float(p5.y()), float(p6.y()))); | 
| 3153 |  | 
| 3154 |     QTransform m7 = m6.toTransform(); | 
| 3155 |     QVERIFY(qFuzzyCompare(float(m5.m11()), float(m7.m11()))); | 
| 3156 |     QVERIFY(qFuzzyCompare(float(m5.m12()), float(m7.m12()))); | 
| 3157 |     QVERIFY(qFuzzyCompare(float(m5.m21()), float(m7.m21()))); | 
| 3158 |     QVERIFY(qFuzzyCompare(float(m5.m22()), float(m7.m22()))); | 
| 3159 |     QVERIFY(qFuzzyCompare(float(m5.dx()), float(m7.dx()))); | 
| 3160 |     QVERIFY(qFuzzyCompare(float(m5.dy()), float(m7.dy()))); | 
| 3161 |     QVERIFY(qFuzzyCompare(float(m5.m13()), float(m7.m13()))); | 
| 3162 |     QVERIFY(qFuzzyCompare(float(m5.m23()), float(m7.m23()))); | 
| 3163 |     QVERIFY(qFuzzyCompare(float(m5.m33()), float(m7.m33()))); | 
| 3164 | } | 
| 3165 |  | 
| 3166 | // Test filling matrices with specific values. | 
| 3167 | void tst_QMatrixNxN::fill() | 
| 3168 | { | 
| 3169 |     QMatrix4x4 m1; | 
| 3170 |     m1.fill(value: 0.0f); | 
| 3171 |     QVERIFY(isSame(m1, nullValues4)); | 
| 3172 |  | 
| 3173 |     static const float fillValues4[] = | 
| 3174 |         {2.5f, 2.5f, 2.5f, 2.5f, | 
| 3175 |          2.5f, 2.5f, 2.5f, 2.5f, | 
| 3176 |          2.5f, 2.5f, 2.5f, 2.5f, | 
| 3177 |          2.5f, 2.5f, 2.5f, 2.5f}; | 
| 3178 |     m1.fill(value: 2.5f); | 
| 3179 |     QVERIFY(isSame(m1, fillValues4)); | 
| 3180 |  | 
| 3181 |     QMatrix4x3 m2; | 
| 3182 |     m2.fill(value: 0.0f); | 
| 3183 |     QVERIFY(isSame(m2, nullValues4x3)); | 
| 3184 |  | 
| 3185 |     static const float fillValues4x3[] = | 
| 3186 |         {2.5f, 2.5f, 2.5f, 2.5f, | 
| 3187 |          2.5f, 2.5f, 2.5f, 2.5f, | 
| 3188 |          2.5f, 2.5f, 2.5f, 2.5f}; | 
| 3189 |     m2.fill(value: 2.5f); | 
| 3190 |     QVERIFY(isSame(m2, fillValues4x3)); | 
| 3191 | } | 
| 3192 |  | 
| 3193 | // Test the mapRect() function for QRect and QRectF. | 
| 3194 | void tst_QMatrixNxN::mapRect_data() | 
| 3195 | { | 
| 3196 |     QTest::addColumn<float>(name: "x" ); | 
| 3197 |     QTest::addColumn<float>(name: "y" ); | 
| 3198 |     QTest::addColumn<float>(name: "width" ); | 
| 3199 |     QTest::addColumn<float>(name: "height" ); | 
| 3200 |  | 
| 3201 |     QTest::newRow(dataTag: "null" ) | 
| 3202 |         << (float)0.0f << (float)0.0f << (float)0.0f << (float)0.0f; | 
| 3203 |     QTest::newRow(dataTag: "rect" ) | 
| 3204 |         << (float)1.0f << (float)-20.5f << (float)100.0f << (float)63.75f; | 
| 3205 | } | 
| 3206 | void tst_QMatrixNxN::mapRect() | 
| 3207 | { | 
| 3208 |     QFETCH(float, x); | 
| 3209 |     QFETCH(float, y); | 
| 3210 |     QFETCH(float, width); | 
| 3211 |     QFETCH(float, height); | 
| 3212 |  | 
| 3213 |     QRectF rect(x, y, width, height); | 
| 3214 |     QRect recti(qRound(d: x), qRound(d: y), qRound(d: width), qRound(d: height)); | 
| 3215 |  | 
| 3216 |     QMatrix4x4 m1; | 
| 3217 |     QCOMPARE(m1.mapRect(rect), rect); | 
| 3218 |     QCOMPARE(m1.mapRect(recti), recti); | 
| 3219 |  | 
| 3220 |     QMatrix4x4 m2; | 
| 3221 |     m2.translate(x: -100.5f, y: 64.0f); | 
| 3222 |     QRectF translated = rect.translated(dx: -100.5f, dy: 64.0f); | 
| 3223 |     QRect translatedi = QRect(qRound(d: recti.x() - 100.5f), recti.y() + 64, | 
| 3224 |                               recti.width(), recti.height()); | 
| 3225 |     QCOMPARE(m2.mapRect(rect), translated); | 
| 3226 |     QCOMPARE(m2.mapRect(recti), translatedi); | 
| 3227 |  | 
| 3228 |     QMatrix4x4 m3; | 
| 3229 |     m3.scale(x: -100.5f, y: 64.0f); | 
| 3230 |     float scalex = x * -100.5f; | 
| 3231 |     float scaley = y * 64.0f; | 
| 3232 |     float scalewid = width * -100.5f; | 
| 3233 |     float scaleht = height * 64.0f; | 
| 3234 |     if (scalewid < 0.0f) { | 
| 3235 |         scalewid = -scalewid; | 
| 3236 |         scalex -= scalewid; | 
| 3237 |     } | 
| 3238 |     if (scaleht < 0.0f) { | 
| 3239 |         scaleht = -scaleht; | 
| 3240 |         scaley -= scaleht; | 
| 3241 |     } | 
| 3242 |     QRectF scaled(scalex, scaley, scalewid, scaleht); | 
| 3243 |     QCOMPARE(m3.mapRect(rect), scaled); | 
| 3244 |     scalex = recti.x() * -100.5f; | 
| 3245 |     scaley = recti.y() * 64.0f; | 
| 3246 |     scalewid = recti.width() * -100.5f; | 
| 3247 |     scaleht = recti.height() * 64.0f; | 
| 3248 |     if (scalewid < 0.0f) { | 
| 3249 |         scalewid = -scalewid; | 
| 3250 |         scalex -= scalewid; | 
| 3251 |     } | 
| 3252 |     if (scaleht < 0.0f) { | 
| 3253 |         scaleht = -scaleht; | 
| 3254 |         scaley -= scaleht; | 
| 3255 |     } | 
| 3256 |     QRect scaledi(qRound(d: scalex), qRound(d: scaley), | 
| 3257 |                   qRound(d: scalewid), qRound(d: scaleht)); | 
| 3258 |     QCOMPARE(m3.mapRect(recti), scaledi); | 
| 3259 |  | 
| 3260 |     QMatrix4x4 m4; | 
| 3261 |     m4.translate(x: -100.5f, y: 64.0f); | 
| 3262 |     m4.scale(x: -2.5f, y: 4.0f); | 
| 3263 |     float transx1 = x * -2.5f - 100.5f; | 
| 3264 |     float transy1 = y * 4.0f + 64.0f; | 
| 3265 |     float transx2 = (x + width) * -2.5f - 100.5f; | 
| 3266 |     float transy2 = (y + height) * 4.0f + 64.0f; | 
| 3267 |     if (transx1 > transx2) | 
| 3268 |         qSwap(value1&: transx1, value2&: transx2); | 
| 3269 |     if (transy1 > transy2) | 
| 3270 |         qSwap(value1&: transy1, value2&: transy2); | 
| 3271 |     QRectF trans(transx1, transy1, transx2 - transx1, transy2 - transy1); | 
| 3272 |     QCOMPARE(m4.mapRect(rect), trans); | 
| 3273 |     transx1 = recti.x() * -2.5f - 100.5f; | 
| 3274 |     transy1 = recti.y() * 4.0f + 64.0f; | 
| 3275 |     transx2 = (recti.x() + recti.width()) * -2.5f - 100.5f; | 
| 3276 |     transy2 = (recti.y() + recti.height()) * 4.0f + 64.0f; | 
| 3277 |     if (transx1 > transx2) | 
| 3278 |         qSwap(value1&: transx1, value2&: transx2); | 
| 3279 |     if (transy1 > transy2) | 
| 3280 |         qSwap(value1&: transy1, value2&: transy2); | 
| 3281 |     QRect transi(qRound(d: transx1), qRound(d: transy1), | 
| 3282 |                  qRound(d: transx2) - qRound(d: transx1), | 
| 3283 |                  qRound(d: transy2) - qRound(d: transy1)); | 
| 3284 |     QCOMPARE(m4.mapRect(recti), transi); | 
| 3285 |  | 
| 3286 |     m4.rotate(angle: 45.0f, x: 0.0f, y: 0.0f, z: 1.0f); | 
| 3287 |  | 
| 3288 |     QTransform t4; | 
| 3289 |     t4.translate(dx: -100.5f, dy: 64.0f); | 
| 3290 |     t4.scale(sx: -2.5f, sy: 4.0f); | 
| 3291 |     t4.rotate(a: 45.0f); | 
| 3292 |     QRectF mr = m4.mapRect(rect); | 
| 3293 |     QRectF tr = t4.mapRect(rect); | 
| 3294 |     QVERIFY(qFuzzyCompare(float(mr.x()), float(tr.x()))); | 
| 3295 |     QVERIFY(qFuzzyCompare(float(mr.y()), float(tr.y()))); | 
| 3296 |     QVERIFY(qFuzzyCompare(float(mr.width()), float(tr.width()))); | 
| 3297 |     QVERIFY(qFuzzyCompare(float(mr.height()), float(tr.height()))); | 
| 3298 |  | 
| 3299 |     QRect mri = m4.mapRect(rect: recti); | 
| 3300 |     QRect tri = t4.mapRect(recti); | 
| 3301 |     QCOMPARE(mri, tri); | 
| 3302 | } | 
| 3303 |  | 
| 3304 | void tst_QMatrixNxN::mapVector_data() | 
| 3305 | { | 
| 3306 |     QTest::addColumn<void *>(name: "mValues" ); | 
| 3307 |  | 
| 3308 |     QTest::newRow(dataTag: "null" ) | 
| 3309 |         << (void *)nullValues4; | 
| 3310 |  | 
| 3311 |     QTest::newRow(dataTag: "identity" ) | 
| 3312 |         << (void *)identityValues4; | 
| 3313 |  | 
| 3314 |     QTest::newRow(dataTag: "unique" ) | 
| 3315 |         << (void *)uniqueValues4; | 
| 3316 |  | 
| 3317 |     static const float scale[] = | 
| 3318 |         {2.0f, 0.0f, 0.0f, 0.0f, | 
| 3319 |          0.0f, 11.0f, 0.0f, 0.0f, | 
| 3320 |          0.0f, 0.0f, -6.5f, 0.0f, | 
| 3321 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 3322 |     QTest::newRow(dataTag: "scale" ) | 
| 3323 |         << (void *)scale; | 
| 3324 |  | 
| 3325 |     static const float scaleTranslate[] = | 
| 3326 |         {2.0f, 0.0f, 0.0f, 1.0f, | 
| 3327 |          0.0f, 11.0f, 0.0f, 2.0f, | 
| 3328 |          0.0f, 0.0f, -6.5f, 3.0f, | 
| 3329 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 3330 |     QTest::newRow(dataTag: "scaleTranslate" ) | 
| 3331 |         << (void *)scaleTranslate; | 
| 3332 |  | 
| 3333 |     static const float translate[] = | 
| 3334 |         {1.0f, 0.0f, 0.0f, 1.0f, | 
| 3335 |          0.0f, 1.0f, 0.0f, 2.0f, | 
| 3336 |          0.0f, 0.0f, 1.0f, 3.0f, | 
| 3337 |          0.0f, 0.0f, 0.0f, 1.0f}; | 
| 3338 |     QTest::newRow(dataTag: "translate" ) | 
| 3339 |         << (void *)translate; | 
| 3340 | } | 
| 3341 | void tst_QMatrixNxN::mapVector() | 
| 3342 | { | 
| 3343 |     QFETCH(void *, mValues); | 
| 3344 |  | 
| 3345 |     QMatrix4x4 m1((const float *)mValues); | 
| 3346 |  | 
| 3347 |     QVector3D v(3.5f, -1.0f, 2.5f); | 
| 3348 |  | 
| 3349 |     QVector3D expected | 
| 3350 |         (v.x() * m1(0, 0) + v.y() * m1(0, 1) + v.z() * m1(0, 2), | 
| 3351 |          v.x() * m1(1, 0) + v.y() * m1(1, 1) + v.z() * m1(1, 2), | 
| 3352 |          v.x() * m1(2, 0) + v.y() * m1(2, 1) + v.z() * m1(2, 2)); | 
| 3353 |  | 
| 3354 |     QVector3D actual = m1.mapVector(vector: v); | 
| 3355 |     m1.optimize(); | 
| 3356 |     QVector3D actual2 = m1.mapVector(vector: v); | 
| 3357 |  | 
| 3358 |     QVERIFY(qFuzzyCompare(actual.x(), expected.x())); | 
| 3359 |     QVERIFY(qFuzzyCompare(actual.y(), expected.y())); | 
| 3360 |     QVERIFY(qFuzzyCompare(actual.z(), expected.z())); | 
| 3361 |     QVERIFY(qFuzzyCompare(actual2.x(), expected.x())); | 
| 3362 |     QVERIFY(qFuzzyCompare(actual2.y(), expected.y())); | 
| 3363 |     QVERIFY(qFuzzyCompare(actual2.z(), expected.z())); | 
| 3364 | } | 
| 3365 |  | 
| 3366 | class tst_QMatrixNxN4x4Properties : public QObject | 
| 3367 | { | 
| 3368 |     Q_OBJECT | 
| 3369 |     Q_PROPERTY(QMatrix4x4 matrix READ matrix WRITE setMatrix) | 
| 3370 | public: | 
| 3371 |     tst_QMatrixNxN4x4Properties(QObject *parent = 0) : QObject(parent) {} | 
| 3372 |  | 
| 3373 |     QMatrix4x4 matrix() const { return m; } | 
| 3374 |     void setMatrix(const QMatrix4x4& value) { m = value; } | 
| 3375 |  | 
| 3376 | private: | 
| 3377 |     QMatrix4x4 m; | 
| 3378 | }; | 
| 3379 |  | 
| 3380 | // Test getting and setting matrix properties via the metaobject system. | 
| 3381 | void tst_QMatrixNxN::properties() | 
| 3382 | { | 
| 3383 |     tst_QMatrixNxN4x4Properties obj; | 
| 3384 |  | 
| 3385 |     QMatrix4x4 m1(uniqueValues4); | 
| 3386 |     obj.setMatrix(m1); | 
| 3387 |  | 
| 3388 |     QMatrix4x4 m2 = qvariant_cast<QMatrix4x4>(v: obj.property(name: "matrix" )); | 
| 3389 |     QVERIFY(isSame(m2, uniqueValues4)); | 
| 3390 |  | 
| 3391 |     QMatrix4x4 m3(transposedValues4); | 
| 3392 |     obj.setProperty(name: "matrix" , value: QVariant::fromValue(value: m3)); | 
| 3393 |  | 
| 3394 |     m2 = qvariant_cast<QMatrix4x4>(v: obj.property(name: "matrix" )); | 
| 3395 |     QVERIFY(isSame(m2, transposedValues4)); | 
| 3396 | } | 
| 3397 |  | 
| 3398 | void tst_QMatrixNxN::metaTypes() | 
| 3399 | { | 
| 3400 |     QCOMPARE(QMetaType::type("QMatrix4x4" ), int(QMetaType::QMatrix4x4)); | 
| 3401 |  | 
| 3402 |     QCOMPARE(QByteArray(QMetaType::typeName(QMetaType::QMatrix4x4)), | 
| 3403 |              QByteArray("QMatrix4x4" )); | 
| 3404 |  | 
| 3405 |     QVERIFY(QMetaType::isRegistered(QMetaType::QMatrix4x4)); | 
| 3406 |  | 
| 3407 |     QCOMPARE(qMetaTypeId<QMatrix4x4>(), int(QMetaType::QMatrix4x4)); | 
| 3408 | } | 
| 3409 |  | 
| 3410 | QTEST_APPLESS_MAIN(tst_QMatrixNxN) | 
| 3411 |  | 
| 3412 | #include "tst_qmatrixnxn.moc" | 
| 3413 |  |