1 | /**************************************************************************** |
---|---|

2 | ** |

3 | ** Copyright (C) 2016 The Qt Company Ltd. |

4 | ** Contact: https://www.qt.io/licensing/ |

5 | ** |

6 | ** This file is part of the QtGui module of the Qt Toolkit. |

7 | ** |

8 | ** $QT_BEGIN_LICENSE:LGPL$ |

9 | ** Commercial License Usage |

10 | ** Licensees holding valid commercial Qt licenses may use this file in |

11 | ** accordance with the commercial license agreement provided with the |

12 | ** Software or, alternatively, in accordance with the terms contained in |

13 | ** a written agreement between you and The Qt Company. For licensing terms |

14 | ** and conditions see https://www.qt.io/terms-conditions. For further |

15 | ** information use the contact form at https://www.qt.io/contact-us. |

16 | ** |

17 | ** GNU Lesser General Public License Usage |

18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |

19 | ** General Public License version 3 as published by the Free Software |

20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |

21 | ** packaging of this file. Please review the following information to |

22 | ** ensure the GNU Lesser General Public License version 3 requirements |

23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |

24 | ** |

25 | ** GNU General Public License Usage |

26 | ** Alternatively, this file may be used under the terms of the GNU |

27 | ** General Public License version 2.0 or (at your option) the GNU General |

28 | ** Public license version 3 or any later version approved by the KDE Free |

29 | ** Qt Foundation. The licenses are as published by the Free Software |

30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |

31 | ** included in the packaging of this file. Please review the following |

32 | ** information to ensure the GNU General Public License requirements will |

33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |

34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |

35 | ** |

36 | ** $QT_END_LICENSE$ |

37 | ** |

38 | ****************************************************************************/ |

39 | |

40 | #include "qmatrix.h" |

41 | |

42 | #include "qdatastream.h" |

43 | #include "qdebug.h" |

44 | #include "qhashfunctions.h" |

45 | #include "qregion.h" |

46 | #include "qpainterpath.h" |

47 | #include "qpainterpath_p.h" |

48 | #include "qvariant.h" |

49 | #include <qmath.h> |

50 | |

51 | #include <limits.h> |

52 | |

53 | QT_BEGIN_NAMESPACE |

54 | |

55 | /*! |

56 | \class QMatrix |

57 | \brief The QMatrix class specifies 2D transformations of a |

58 | coordinate system. |

59 | \obsolete |

60 | |

61 | \ingroup painting |

62 | \inmodule QtGui |

63 | |

64 | A matrix specifies how to translate, scale, shear or rotate the |

65 | coordinate system, and is typically used when rendering graphics. |

66 | QMatrix, in contrast to QTransform, does not allow perspective |

67 | transformations. QTransform is the recommended transformation |

68 | class in Qt. |

69 | |

70 | A QMatrix object can be built using the setMatrix(), scale(), |

71 | rotate(), translate() and shear() functions. Alternatively, it |

72 | can be built by applying \l {QMatrix#Basic Matrix |

73 | Operations}{basic matrix operations}. The matrix can also be |

74 | defined when constructed, and it can be reset to the identity |

75 | matrix (the default) using the reset() function. |

76 | |

77 | The QMatrix class supports mapping of graphic primitives: A given |

78 | point, line, polygon, region, or painter path can be mapped to the |

79 | coordinate system defined by \e this matrix using the map() |

80 | function. In case of a rectangle, its coordinates can be |

81 | transformed using the mapRect() function. A rectangle can also be |

82 | transformed into a \e polygon (mapped to the coordinate system |

83 | defined by \e this matrix), using the mapToPolygon() function. |

84 | |

85 | QMatrix provides the isIdentity() function which returns \c true if |

86 | the matrix is the identity matrix, and the isInvertible() function |

87 | which returns \c true if the matrix is non-singular (i.e. AB = BA = |

88 | I). The inverted() function returns an inverted copy of \e this |

89 | matrix if it is invertible (otherwise it returns the identity |

90 | matrix). In addition, QMatrix provides the determinant() function |

91 | returning the matrix's determinant. |

92 | |

93 | Finally, the QMatrix class supports matrix multiplication, and |

94 | objects of the class can be streamed as well as compared. |

95 | |

96 | \tableofcontents |

97 | |

98 | \section1 Rendering Graphics |

99 | |

100 | When rendering graphics, the matrix defines the transformations |

101 | but the actual transformation is performed by the drawing routines |

102 | in QPainter. |

103 | |

104 | By default, QPainter operates on the associated device's own |

105 | coordinate system. The standard coordinate system of a |

106 | QPaintDevice has its origin located at the top-left position. The |

107 | \e x values increase to the right; \e y values increase |

108 | downward. For a complete description, see the \l {Coordinate |

109 | System}{coordinate system} documentation. |

110 | |

111 | QPainter has functions to translate, scale, shear and rotate the |

112 | coordinate system without using a QMatrix. For example: |

113 | |

114 | \table 100% |

115 | \row |

116 | \li \inlineimage qmatrix-simpletransformation.png |

117 | \li |

118 | \snippet matrix/matrix.cpp 0 |

119 | \endtable |

120 | |

121 | Although these functions are very convenient, it can be more |

122 | efficient to build a QMatrix and call QPainter::setMatrix() if you |

123 | want to perform more than a single transform operation. For |

124 | example: |

125 | |

126 | \table 100% |

127 | \row |

128 | \li \inlineimage qmatrix-combinedtransformation.png |

129 | \li |

130 | \snippet matrix/matrix.cpp 1 |

131 | \endtable |

132 | |

133 | \section1 Basic Matrix Operations |

134 | |

135 | \image qmatrix-representation.png |

136 | |

137 | A QMatrix object contains a 3 x 3 matrix. The \c dx and \c dy |

138 | elements specify horizontal and vertical translation. The \c m11 |

139 | and \c m22 elements specify horizontal and vertical scaling. And |

140 | finally, the \c m21 and \c m12 elements specify horizontal and |

141 | vertical \e shearing. |

142 | |

143 | QMatrix transforms a point in the plane to another point using the |

144 | following formulas: |

145 | |

146 | \snippet code/src_gui_painting_qmatrix.cpp 0 |

147 | |

148 | The point \e (x, y) is the original point, and \e (x', y') is the |

149 | transformed point. \e (x', y') can be transformed back to \e (x, |

150 | y) by performing the same operation on the inverted() matrix. |

151 | |

152 | The various matrix elements can be set when constructing the |

153 | matrix, or by using the setMatrix() function later on. They can also |

154 | be manipulated using the translate(), rotate(), scale() and |

155 | shear() convenience functions, The currently set values can be |

156 | retrieved using the m11(), m12(), m21(), m22(), dx() and dy() |

157 | functions. |

158 | |

159 | Translation is the simplest transformation. Setting \c dx and \c |

160 | dy will move the coordinate system \c dx units along the X axis |

161 | and \c dy units along the Y axis. Scaling can be done by setting |

162 | \c m11 and \c m22. For example, setting \c m11 to 2 and \c m22 to |

163 | 1.5 will double the height and increase the width by 50%. The |

164 | identity matrix has \c m11 and \c m22 set to 1 (all others are set |

165 | to 0) mapping a point to itself. Shearing is controlled by \c m12 |

166 | and \c m21. Setting these elements to values different from zero |

167 | will twist the coordinate system. Rotation is achieved by |

168 | carefully setting both the shearing factors and the scaling |

169 | factors. |

170 | |

171 | Here's the combined transformations example using basic matrix |

172 | operations: |

173 | |

174 | \table 100% |

175 | \row |

176 | \li \inlineimage qmatrix-combinedtransformation.png |

177 | \li |

178 | \snippet matrix/matrix.cpp 2 |

179 | \endtable |

180 | |

181 | \sa QPainter, QTransform, {Coordinate System}, |

182 | {painting/affine}{Affine Transformations Example}, {Transformations Example} |

183 | */ |

184 | |

185 | |

186 | // some defines to inline some code |

187 | #define MAPDOUBLE(x, y, nx, ny) \ |

188 | { \ |

189 | qreal fx = x; \ |

190 | qreal fy = y; \ |

191 | nx = _m11*fx + _m21*fy + _dx; \ |

192 | ny = _m12*fx + _m22*fy + _dy; \ |

193 | } |

194 | |

195 | #define MAPINT(x, y, nx, ny) \ |

196 | { \ |

197 | qreal fx = x; \ |

198 | qreal fy = y; \ |

199 | nx = qRound(_m11*fx + _m21*fy + _dx); \ |

200 | ny = qRound(_m12*fx + _m22*fy + _dy); \ |

201 | } |

202 | |

203 | /***************************************************************************** |

204 | QMatrix member functions |

205 | *****************************************************************************/ |

206 | /*! |

207 | \fn QMatrix::QMatrix(Qt::Initialization) |

208 | \internal |

209 | */ |

210 | |

211 | /*! |

212 | Constructs an identity matrix. |

213 | |

214 | All elements are set to zero except \c m11 and \c m22 (specifying |

215 | the scale), which are set to 1. |

216 | |

217 | \sa reset() |

218 | */ |

219 | |

220 | QMatrix::QMatrix() |

221 | : _m11(1.) |

222 | , _m12(0.) |

223 | , _m21(0.) |

224 | , _m22(1.) |

225 | , _dx(0.) |

226 | , _dy(0.) |

227 | { |

228 | } |

229 | |

230 | /*! |

231 | Constructs a matrix with the elements, \a m11, \a m12, \a m21, \a |

232 | m22, \a dx and \a dy. |

233 | |

234 | \sa setMatrix() |

235 | */ |

236 | |

237 | QMatrix::QMatrix(qreal m11, qreal m12, qreal m21, qreal m22, qreal dx, qreal dy) |

238 | : _m11(m11) |

239 | , _m12(m12) |

240 | , _m21(m21) |

241 | , _m22(m22) |

242 | , _dx(dx) |

243 | , _dy(dy) |

244 | { |

245 | } |

246 | |

247 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) |

248 | /*! |

249 | Constructs a matrix that is a copy of the given \a matrix. |

250 | */ |

251 | QMatrix::QMatrix(const QMatrix &matrix) noexcept |

252 | : _m11(matrix._m11) |

253 | , _m12(matrix._m12) |

254 | , _m21(matrix._m21) |

255 | , _m22(matrix._m22) |

256 | , _dx(matrix._dx) |

257 | , _dy(matrix._dy) |

258 | { |

259 | } |

260 | #endif |

261 | |

262 | /*! |

263 | Sets the matrix elements to the specified values, \a m11, \a m12, |

264 | \a m21, \a m22, \a dx and \a dy. |

265 | |

266 | Note that this function replaces the previous values. QMatrix |

267 | provide the translate(), rotate(), scale() and shear() convenience |

268 | functions to manipulate the various matrix elements based on the |

269 | currently defined coordinate system. |

270 | |

271 | \sa QMatrix() |

272 | */ |

273 | |

274 | void QMatrix::setMatrix(qreal m11, qreal m12, qreal m21, qreal m22, qreal dx, qreal dy) |

275 | { |

276 | _m11 = m11; |

277 | _m12 = m12; |

278 | _m21 = m21; |

279 | _m22 = m22; |

280 | _dx = dx; |

281 | _dy = dy; |

282 | } |

283 | |

284 | |

285 | /*! |

286 | \fn qreal QMatrix::m11() const |

287 | |

288 | Returns the horizontal scaling factor. |

289 | |

290 | \sa scale(), {QMatrix#Basic Matrix Operations}{Basic Matrix |

291 | Operations} |

292 | */ |

293 | |

294 | /*! |

295 | \fn qreal QMatrix::m12() const |

296 | |

297 | Returns the vertical shearing factor. |

298 | |

299 | \sa shear(), {QMatrix#Basic Matrix Operations}{Basic Matrix |

300 | Operations} |

301 | */ |

302 | |

303 | /*! |

304 | \fn qreal QMatrix::m21() const |

305 | |

306 | Returns the horizontal shearing factor. |

307 | |

308 | \sa shear(), {QMatrix#Basic Matrix Operations}{Basic Matrix |

309 | Operations} |

310 | */ |

311 | |

312 | /*! |

313 | \fn qreal QMatrix::m22() const |

314 | |

315 | Returns the vertical scaling factor. |

316 | |

317 | \sa scale(), {QMatrix#Basic Matrix Operations}{Basic Matrix |

318 | Operations} |

319 | */ |

320 | |

321 | /*! |

322 | \fn qreal QMatrix::dx() const |

323 | |

324 | Returns the horizontal translation factor. |

325 | |

326 | \sa translate(), {QMatrix#Basic Matrix Operations}{Basic Matrix |

327 | Operations} |

328 | */ |

329 | |

330 | /*! |

331 | \fn qreal QMatrix::dy() const |

332 | |

333 | Returns the vertical translation factor. |

334 | |

335 | \sa translate(), {QMatrix#Basic Matrix Operations}{Basic Matrix |

336 | Operations} |

337 | */ |

338 | |

339 | |

340 | /*! |

341 | Maps the given coordinates \a x and \a y into the coordinate |

342 | system defined by this matrix. The resulting values are put in *\a |

343 | tx and *\a ty, respectively. |

344 | |

345 | The coordinates are transformed using the following formulas: |

346 | |

347 | \snippet code/src_gui_painting_qmatrix.cpp 1 |

348 | |

349 | The point (x, y) is the original point, and (x', y') is the |

350 | transformed point. |

351 | |

352 | \sa {QMatrix#Basic Matrix Operations}{Basic Matrix Operations} |

353 | */ |

354 | |

355 | void QMatrix::map(qreal x, qreal y, qreal *tx, qreal *ty) const |

356 | { |

357 | MAPDOUBLE(x, y, *tx, *ty); |

358 | } |

359 | |

360 | |

361 | |

362 | /*! |

363 | \overload |

364 | |

365 | Maps the given coordinates \a x and \a y into the coordinate |

366 | system defined by this matrix. The resulting values are put in *\a |

367 | tx and *\a ty, respectively. Note that the transformed coordinates |

368 | are rounded to the nearest integer. |

369 | */ |

370 | |

371 | void QMatrix::map(int x, int y, int *tx, int *ty) const |

372 | { |

373 | MAPINT(x, y, *tx, *ty); |

374 | } |

375 | |

376 | QRect QMatrix::mapRect(const QRect &rect) const |

377 | { |

378 | QRect result; |

379 | if (_m12 == 0.0F && _m21 == 0.0F) { |

380 | int x = qRound(_m11*rect.x() + _dx); |

381 | int y = qRound(_m22*rect.y() + _dy); |

382 | int w = qRound(_m11*rect.width()); |

383 | int h = qRound(_m22*rect.height()); |

384 | if (w < 0) { |

385 | w = -w; |

386 | x -= w; |

387 | } |

388 | if (h < 0) { |

389 | h = -h; |

390 | y -= h; |

391 | } |

392 | result = QRect(x, y, w, h); |

393 | } else { |

394 | // see mapToPolygon for explanations of the algorithm. |

395 | qreal x0, y0; |

396 | qreal x, y; |

397 | MAPDOUBLE(rect.left(), rect.top(), x0, y0); |

398 | qreal xmin = x0; |

399 | qreal ymin = y0; |

400 | qreal xmax = x0; |

401 | qreal ymax = y0; |

402 | MAPDOUBLE(rect.right() + 1, rect.top(), x, y); |

403 | xmin = qMin(xmin, x); |

404 | ymin = qMin(ymin, y); |

405 | xmax = qMax(xmax, x); |

406 | ymax = qMax(ymax, y); |

407 | MAPDOUBLE(rect.right() + 1, rect.bottom() + 1, x, y); |

408 | xmin = qMin(xmin, x); |

409 | ymin = qMin(ymin, y); |

410 | xmax = qMax(xmax, x); |

411 | ymax = qMax(ymax, y); |

412 | MAPDOUBLE(rect.left(), rect.bottom() + 1, x, y); |

413 | xmin = qMin(xmin, x); |

414 | ymin = qMin(ymin, y); |

415 | xmax = qMax(xmax, x); |

416 | ymax = qMax(ymax, y); |

417 | result = QRect(qRound(xmin), qRound(ymin), qRound(xmax)-qRound(xmin), qRound(ymax)-qRound(ymin)); |

418 | } |

419 | return result; |

420 | } |

421 | |

422 | /*! |

423 | \fn QRectF QMatrix::mapRect(const QRectF &rectangle) const |

424 | |

425 | Creates and returns a QRectF object that is a copy of the given \a |

426 | rectangle, mapped into the coordinate system defined by this |

427 | matrix. |

428 | |

429 | The rectangle's coordinates are transformed using the following |

430 | formulas: |

431 | |

432 | \snippet code/src_gui_painting_qmatrix.cpp 2 |

433 | |

434 | If rotation or shearing has been specified, this function returns |

435 | the \e bounding rectangle. To retrieve the exact region the given |

436 | \a rectangle maps to, use the mapToPolygon() function instead. |

437 | |

438 | \sa mapToPolygon(), {QMatrix#Basic Matrix Operations}{Basic Matrix |

439 | Operations} |

440 | */ |

441 | QRectF QMatrix::mapRect(const QRectF &rect) const |

442 | { |

443 | QRectF result; |

444 | if (_m12 == 0.0F && _m21 == 0.0F) { |

445 | qreal x = _m11*rect.x() + _dx; |

446 | qreal y = _m22*rect.y() + _dy; |

447 | qreal w = _m11*rect.width(); |

448 | qreal h = _m22*rect.height(); |

449 | if (w < 0) { |

450 | w = -w; |

451 | x -= w; |

452 | } |

453 | if (h < 0) { |

454 | h = -h; |

455 | y -= h; |

456 | } |

457 | result = QRectF(x, y, w, h); |

458 | } else { |

459 | qreal x0, y0; |

460 | qreal x, y; |

461 | MAPDOUBLE(rect.x(), rect.y(), x0, y0); |

462 | qreal xmin = x0; |

463 | qreal ymin = y0; |

464 | qreal xmax = x0; |

465 | qreal ymax = y0; |

466 | MAPDOUBLE(rect.x() + rect.width(), rect.y(), x, y); |

467 | xmin = qMin(xmin, x); |

468 | ymin = qMin(ymin, y); |

469 | xmax = qMax(xmax, x); |

470 | ymax = qMax(ymax, y); |

471 | MAPDOUBLE(rect.x() + rect.width(), rect.y() + rect.height(), x, y); |

472 | xmin = qMin(xmin, x); |

473 | ymin = qMin(ymin, y); |

474 | xmax = qMax(xmax, x); |

475 | ymax = qMax(ymax, y); |

476 | MAPDOUBLE(rect.x(), rect.y() + rect.height(), x, y); |

477 | xmin = qMin(xmin, x); |

478 | ymin = qMin(ymin, y); |

479 | xmax = qMax(xmax, x); |

480 | ymax = qMax(ymax, y); |

481 | result = QRectF(xmin, ymin, xmax-xmin, ymax - ymin); |

482 | } |

483 | return result; |

484 | } |

485 | |

486 | /*! |

487 | \fn QRect QMatrix::mapRect(const QRect &rectangle) const |

488 | \overload |

489 | |

490 | Creates and returns a QRect object that is a copy of the given \a |

491 | rectangle, mapped into the coordinate system defined by this |

492 | matrix. Note that the transformed coordinates are rounded to the |

493 | nearest integer. |

494 | */ |

495 | |

496 | |

497 | /*! |

498 | \fn QPoint operator*(const QPoint &point, const QMatrix &matrix) |

499 | \relates QMatrix |

500 | |

501 | This is the same as \a{matrix}.map(\a{point}). |

502 | |

503 | \sa QMatrix::map() |

504 | */ |

505 | |

506 | QPoint QMatrix::map(const QPoint &p) const |

507 | { |

508 | qreal fx = p.x(); |

509 | qreal fy = p.y(); |

510 | return QPoint(qRound(_m11*fx + _m21*fy + _dx), |

511 | qRound(_m12*fx + _m22*fy + _dy)); |

512 | } |

513 | |

514 | /*! |

515 | \fn QPointF operator*(const QPointF &point, const QMatrix &matrix) |

516 | \relates QMatrix |

517 | |

518 | Same as \a{matrix}.map(\a{point}). |

519 | |

520 | \sa QMatrix::map() |

521 | */ |

522 | |

523 | /*! |

524 | \overload |

525 | |

526 | Creates and returns a QPointF object that is a copy of the given |

527 | \a point, mapped into the coordinate system defined by this |

528 | matrix. |

529 | */ |

530 | QPointF QMatrix::map(const QPointF &point) const |

531 | { |

532 | qreal fx = point.x(); |

533 | qreal fy = point.y(); |

534 | return QPointF(_m11*fx + _m21*fy + _dx, _m12*fx + _m22*fy + _dy); |

535 | } |

536 | |

537 | /*! |

538 | \fn QPoint QMatrix::map(const QPoint &point) const |

539 | \overload |

540 | |

541 | Creates and returns a QPoint object that is a copy of the given \a |

542 | point, mapped into the coordinate system defined by this |

543 | matrix. Note that the transformed coordinates are rounded to the |

544 | nearest integer. |

545 | */ |

546 | |

547 | /*! |

548 | \fn QLineF operator*(const QLineF &line, const QMatrix &matrix) |

549 | \relates QMatrix |

550 | |

551 | This is the same as \a{matrix}.map(\a{line}). |

552 | |

553 | \sa QMatrix::map() |

554 | */ |

555 | |

556 | /*! |

557 | \fn QLine operator*(const QLine &line, const QMatrix &matrix) |

558 | \relates QMatrix |

559 | |

560 | This is the same as \a{matrix}.map(\a{line}). |

561 | |

562 | \sa QMatrix::map() |

563 | */ |

564 | |

565 | /*! |

566 | \overload |

567 | |

568 | Creates and returns a QLineF object that is a copy of the given \a |

569 | line, mapped into the coordinate system defined by this matrix. |

570 | */ |

571 | QLineF QMatrix::map(const QLineF &line) const |

572 | { |

573 | return QLineF(map(line.p1()), map(line.p2())); |

574 | } |

575 | |

576 | /*! |

577 | \overload |

578 | |

579 | Creates and returns a QLine object that is a copy of the given \a |

580 | line, mapped into the coordinate system defined by this matrix. |

581 | Note that the transformed coordinates are rounded to the nearest |

582 | integer. |

583 | */ |

584 | QLine QMatrix::map(const QLine &line) const |

585 | { |

586 | return QLine(map(line.p1()), map(line.p2())); |

587 | } |

588 | |

589 | /*! |

590 | \fn QPolygonF operator *(const QPolygonF &polygon, const QMatrix &matrix) |

591 | \relates QMatrix |

592 | |

593 | This is the same as \a{matrix}.map(\a{polygon}). |

594 | |

595 | \sa QMatrix::map() |

596 | */ |

597 | |

598 | /*! |

599 | \fn QPolygon operator*(const QPolygon &polygon, const QMatrix &matrix) |

600 | \relates QMatrix |

601 | |

602 | This is the same as \a{matrix}.map(\a{polygon}). |

603 | |

604 | \sa QMatrix::map() |

605 | */ |

606 | |

607 | QPolygon QMatrix::map(const QPolygon &a) const |

608 | { |

609 | int size = a.size(); |

610 | int i; |

611 | QPolygon p(size); |

612 | const QPoint *da = a.constData(); |

613 | QPoint *dp = p.data(); |

614 | for(i = 0; i < size; i++) { |

615 | MAPINT(da[i].x(), da[i].y(), dp[i].rx(), dp[i].ry()); |

616 | } |

617 | return p; |

618 | } |

619 | |

620 | /*! |

621 | \fn QPolygonF QMatrix::map(const QPolygonF &polygon) const |

622 | \overload |

623 | |

624 | Creates and returns a QPolygonF object that is a copy of the given |

625 | \a polygon, mapped into the coordinate system defined by this |

626 | matrix. |

627 | */ |

628 | QPolygonF QMatrix::map(const QPolygonF &a) const |

629 | { |

630 | int size = a.size(); |

631 | int i; |

632 | QPolygonF p(size); |

633 | const QPointF *da = a.constData(); |

634 | QPointF *dp = p.data(); |

635 | for(i = 0; i < size; i++) { |

636 | MAPDOUBLE(da[i].xp, da[i].yp, dp[i].xp, dp[i].yp); |

637 | } |

638 | return p; |

639 | } |

640 | |

641 | /*! |

642 | \fn QPolygon QMatrix::map(const QPolygon &polygon) const |

643 | \overload |

644 | |

645 | Creates and returns a QPolygon object that is a copy of the given |

646 | \a polygon, mapped into the coordinate system defined by this |

647 | matrix. Note that the transformed coordinates are rounded to the |

648 | nearest integer. |

649 | */ |

650 | |

651 | /*! |

652 | \fn QRegion operator*(const QRegion ®ion, const QMatrix &matrix) |

653 | \relates QMatrix |

654 | |

655 | This is the same as \a{matrix}.map(\a{region}). |

656 | |

657 | \sa QMatrix::map() |

658 | */ |

659 | |

660 | extern QPainterPath qt_regionToPath(const QRegion ®ion); |

661 | |

662 | /*! |

663 | \fn QRegion QMatrix::map(const QRegion ®ion) const |

664 | \overload |

665 | |

666 | Creates and returns a QRegion object that is a copy of the given |

667 | \a region, mapped into the coordinate system defined by this matrix. |

668 | |

669 | Calling this method can be rather expensive if rotations or |

670 | shearing are used. |

671 | */ |

672 | QRegion QMatrix::map(const QRegion &r) const |

673 | { |

674 | if (_m11 == 1.0 && _m22 == 1.0 && _m12 == 0.0 && _m21 == 0.0) { // translate or identity |

675 | if (_dx == 0.0 && _dy == 0.0) // Identity |

676 | return r; |

677 | QRegion copy(r); |

678 | copy.translate(qRound(_dx), qRound(_dy)); |

679 | return copy; |

680 | } |

681 | |

682 | QPainterPath p = map(qt_regionToPath(r)); |

683 | return p.toFillPolygon().toPolygon(); |

684 | } |

685 | |

686 | /*! |

687 | \fn QPainterPath operator *(const QPainterPath &path, const QMatrix &matrix) |

688 | \relates QMatrix |

689 | |

690 | This is the same as \a{matrix}.map(\a{path}). |

691 | |

692 | \sa QMatrix::map() |

693 | */ |

694 | |

695 | /*! |

696 | \overload |

697 | |

698 | Creates and returns a QPainterPath object that is a copy of the |

699 | given \a path, mapped into the coordinate system defined by this |

700 | matrix. |

701 | */ |

702 | QPainterPath QMatrix::map(const QPainterPath &path) const |

703 | { |

704 | if (path.isEmpty()) |

705 | return QPainterPath(); |

706 | |

707 | QPainterPath copy = path; |

708 | |

709 | // Translate or identity |

710 | if (_m11 == 1.0 && _m22 == 1.0 && _m12 == 0.0 && _m21 == 0.0) { |

711 | |

712 | // Translate |

713 | if (_dx != 0.0 || _dy != 0.0) { |

714 | copy.detach(); |

715 | for (int i=0; i<path.elementCount(); ++i) { |

716 | QPainterPath::Element &e = copy.d_ptr->elements[i]; |

717 | e.x += _dx; |

718 | e.y += _dy; |

719 | } |

720 | } |

721 | |

722 | // Full xform |

723 | } else { |

724 | copy.detach(); |

725 | for (int i=0; i<path.elementCount(); ++i) { |

726 | QPainterPath::Element &e = copy.d_ptr->elements[i]; |

727 | qreal fx = e.x, fy = e.y; |

728 | e.x = _m11*fx + _m21*fy + _dx; |

729 | e.y = _m12*fx + _m22*fy + _dy; |

730 | } |

731 | } |

732 | |

733 | return copy; |

734 | } |

735 | |

736 | /*! |

737 | \fn QPolygon QMatrix::mapToPolygon(const QRect &rectangle) const |

738 | |

739 | Creates and returns a QPolygon representation of the given \a |

740 | rectangle, mapped into the coordinate system defined by this |

741 | matrix. |

742 | |

743 | The rectangle's coordinates are transformed using the following |

744 | formulas: |

745 | |

746 | \snippet code/src_gui_painting_qmatrix.cpp 3 |

747 | |

748 | Polygons and rectangles behave slightly differently when |

749 | transformed (due to integer rounding), so |

750 | \c{matrix.map(QPolygon(rectangle))} is not always the same as |

751 | \c{matrix.mapToPolygon(rectangle)}. |

752 | |

753 | \sa mapRect(), {QMatrix#Basic Matrix Operations}{Basic Matrix |

754 | Operations} |

755 | */ |

756 | QPolygon QMatrix::mapToPolygon(const QRect &rect) const |

757 | { |

758 | QPolygon a(4); |

759 | qreal x[4], y[4]; |

760 | if (_m12 == 0.0F && _m21 == 0.0F) { |

761 | x[0] = _m11*rect.x() + _dx; |

762 | y[0] = _m22*rect.y() + _dy; |

763 | qreal w = _m11*rect.width(); |

764 | qreal h = _m22*rect.height(); |

765 | if (w < 0) { |

766 | w = -w; |

767 | x[0] -= w; |

768 | } |

769 | if (h < 0) { |

770 | h = -h; |

771 | y[0] -= h; |

772 | } |

773 | x[1] = x[0]+w; |

774 | x[2] = x[1]; |

775 | x[3] = x[0]; |

776 | y[1] = y[0]; |

777 | y[2] = y[0]+h; |

778 | y[3] = y[2]; |

779 | } else { |

780 | qreal right = rect.x() + rect.width(); |

781 | qreal bottom = rect.y() + rect.height(); |

782 | MAPDOUBLE(rect.x(), rect.y(), x[0], y[0]); |

783 | MAPDOUBLE(right, rect.y(), x[1], y[1]); |

784 | MAPDOUBLE(right, bottom, x[2], y[2]); |

785 | MAPDOUBLE(rect.x(), bottom, x[3], y[3]); |

786 | } |

787 | #if 0 |

788 | int i; |

789 | for(i = 0; i< 4; i++) |

790 | qDebug("coords(%d) = (%f/%f) (%d/%d)", i, x[i], y[i], qRound(x[i]), qRound(y[i])); |

791 | qDebug("width=%f, height=%f", qSqrt((x[ 1]-x[0])*(x[1]-x[0]) + (y[1]-y[0])*(y[1]-y[0])), |

792 | qSqrt((x[0]-x[3])*(x[0]-x[3]) + (y[0]-y[3])*(y[0]-y[3]))); |

793 | #endif |

794 | // all coordinates are correctly, tranform to a pointarray |

795 | // (rounding to the next integer) |

796 | a.setPoints(4, qRound(x[0]), qRound(y[0]), |

797 | qRound(x[1]), qRound(y[1]), |

798 | qRound(x[2]), qRound(y[2]), |

799 | qRound(x[3]), qRound(y[3])); |

800 | return a; |

801 | } |

802 | |

803 | /*! |

804 | Resets the matrix to an identity matrix, i.e. all elements are set |

805 | to zero, except \c m11 and \c m22 (specifying the scale) which are |

806 | set to 1. |

807 | |

808 | \sa QMatrix(), isIdentity(), {QMatrix#Basic Matrix |

809 | Operations}{Basic Matrix Operations} |

810 | */ |

811 | |

812 | void QMatrix::reset() |

813 | { |

814 | _m11 = _m22 = 1.0; |

815 | _m12 = _m21 = _dx = _dy = 0.0; |

816 | } |

817 | |

818 | /*! |

819 | \fn bool QMatrix::isIdentity() const |

820 | |

821 | Returns \c true if the matrix is the identity matrix, otherwise |

822 | returns \c false. |

823 | |

824 | \sa reset() |

825 | */ |

826 | |

827 | /*! |

828 | Moves the coordinate system \a dx along the x axis and \a dy along |

829 | the y axis, and returns a reference to the matrix. |

830 | |

831 | \sa setMatrix() |

832 | */ |

833 | |

834 | QMatrix &QMatrix::translate(qreal dx, qreal dy) |

835 | { |

836 | _dx += dx*_m11 + dy*_m21; |

837 | _dy += dy*_m22 + dx*_m12; |

838 | return *this; |

839 | } |

840 | |

841 | /*! |

842 | \fn QMatrix &QMatrix::scale(qreal sx, qreal sy) |

843 | |

844 | Scales the coordinate system by \a sx horizontally and \a sy |

845 | vertically, and returns a reference to the matrix. |

846 | |

847 | \sa setMatrix() |

848 | */ |

849 | |

850 | QMatrix &QMatrix::scale(qreal sx, qreal sy) |

851 | { |

852 | _m11 *= sx; |

853 | _m12 *= sx; |

854 | _m21 *= sy; |

855 | _m22 *= sy; |

856 | return *this; |

857 | } |

858 | |

859 | /*! |

860 | Shears the coordinate system by \a sh horizontally and \a sv |

861 | vertically, and returns a reference to the matrix. |

862 | |

863 | \sa setMatrix() |

864 | */ |

865 | |

866 | QMatrix &QMatrix::shear(qreal sh, qreal sv) |

867 | { |

868 | qreal tm11 = sv*_m21; |

869 | qreal tm12 = sv*_m22; |

870 | qreal tm21 = sh*_m11; |

871 | qreal tm22 = sh*_m12; |

872 | _m11 += tm11; |

873 | _m12 += tm12; |

874 | _m21 += tm21; |

875 | _m22 += tm22; |

876 | return *this; |

877 | } |

878 | |

879 | const qreal deg2rad = qreal(0.017453292519943295769); // pi/180 |

880 | |

881 | /*! |

882 | \fn QMatrix &QMatrix::rotate(qreal degrees) |

883 | |

884 | Rotates the coordinate system the given \a degrees |

885 | counterclockwise. |

886 | |

887 | Note that if you apply a QMatrix to a point defined in widget |

888 | coordinates, the direction of the rotation will be clockwise |

889 | because the y-axis points downwards. |

890 | |

891 | Returns a reference to the matrix. |

892 | |

893 | \sa setMatrix() |

894 | */ |

895 | |

896 | QMatrix &QMatrix::rotate(qreal a) |

897 | { |

898 | qreal sina = 0; |

899 | qreal cosa = 0; |

900 | if (a == 90. || a == -270.) |

901 | sina = 1.; |

902 | else if (a == 270. || a == -90.) |

903 | sina = -1.; |

904 | else if (a == 180.) |

905 | cosa = -1.; |

906 | else{ |

907 | qreal b = deg2rad*a; // convert to radians |

908 | sina = qSin(b); // fast and convenient |

909 | cosa = qCos(b); |

910 | } |

911 | qreal tm11 = cosa*_m11 + sina*_m21; |

912 | qreal tm12 = cosa*_m12 + sina*_m22; |

913 | qreal tm21 = -sina*_m11 + cosa*_m21; |

914 | qreal tm22 = -sina*_m12 + cosa*_m22; |

915 | _m11 = tm11; _m12 = tm12; |

916 | _m21 = tm21; _m22 = tm22; |

917 | return *this; |

918 | } |

919 | |

920 | /*! |

921 | \fn bool QMatrix::isInvertible() const |

922 | |

923 | Returns \c true if the matrix is invertible, otherwise returns \c false. |

924 | |

925 | \sa inverted() |

926 | */ |

927 | |

928 | /*! |

929 | \since 4.6 |

930 | \fn qreal QMatrix::determinant() const |

931 | |

932 | Returns the matrix's determinant. |

933 | */ |

934 | |

935 | /*! |

936 | Returns an inverted copy of this matrix. |

937 | |

938 | If the matrix is singular (not invertible), the returned matrix is |

939 | the identity matrix. If \a invertible is valid (i.e. not 0), its |

940 | value is set to true if the matrix is invertible, otherwise it is |

941 | set to false. |

942 | |

943 | \sa isInvertible() |

944 | */ |

945 | |

946 | QMatrix QMatrix::inverted(bool *invertible) const |

947 | { |

948 | qreal dtr = determinant(); |

949 | if (dtr == 0.0) { |

950 | if (invertible) |

951 | *invertible = false; // singular matrix |

952 | return QMatrix(true); |

953 | } |

954 | else { // invertible matrix |

955 | if (invertible) |

956 | *invertible = true; |

957 | qreal dinv = 1.0/dtr; |

958 | return QMatrix((_m22*dinv), (-_m12*dinv), |

959 | (-_m21*dinv), (_m11*dinv), |

960 | ((_m21*_dy - _m22*_dx)*dinv), |

961 | ((_m12*_dx - _m11*_dy)*dinv), |

962 | true); |

963 | } |

964 | } |

965 | |

966 | |

967 | /*! |

968 | \fn bool QMatrix::operator==(const QMatrix &matrix) const |

969 | |

970 | Returns \c true if this matrix is equal to the given \a matrix, |

971 | otherwise returns \c false. |

972 | */ |

973 | |

974 | bool QMatrix::operator==(const QMatrix &m) const |

975 | { |

976 | return _m11 == m._m11 && |

977 | _m12 == m._m12 && |

978 | _m21 == m._m21 && |

979 | _m22 == m._m22 && |

980 | _dx == m._dx && |

981 | _dy == m._dy; |

982 | } |

983 | |

984 | |

985 | /*! |

986 | \since 5.6 |

987 | \relates QMatrix |

988 | |

989 | Returns the hash value for \a key, using |

990 | \a seed to seed the calculation. |

991 | */ |

992 | uint qHash(const QMatrix &key, uint seed) noexcept |

993 | { |

994 | QtPrivate::QHashCombine hash; |

995 | seed = hash(seed, key.m11()); |

996 | seed = hash(seed, key.m12()); |

997 | seed = hash(seed, key.m21()); |

998 | seed = hash(seed, key.m22()); |

999 | seed = hash(seed, key.dx()); |

1000 | seed = hash(seed, key.dy()); |

1001 | return seed; |

1002 | } |

1003 | |

1004 | /*! |

1005 | \fn bool QMatrix::operator!=(const QMatrix &matrix) const |

1006 | |

1007 | Returns \c true if this matrix is not equal to the given \a matrix, |

1008 | otherwise returns \c false. |

1009 | */ |

1010 | |

1011 | bool QMatrix::operator!=(const QMatrix &m) const |

1012 | { |

1013 | return _m11 != m._m11 || |

1014 | _m12 != m._m12 || |

1015 | _m21 != m._m21 || |

1016 | _m22 != m._m22 || |

1017 | _dx != m._dx || |

1018 | _dy != m._dy; |

1019 | } |

1020 | |

1021 | /*! |

1022 | \fn QMatrix &QMatrix::operator *=(const QMatrix &matrix) |

1023 | \overload |

1024 | |

1025 | Returns the result of multiplying this matrix by the given \a |

1026 | matrix. |

1027 | */ |

1028 | |

1029 | QMatrix &QMatrix::operator *=(const QMatrix &m) |

1030 | { |

1031 | qreal tm11 = _m11*m._m11 + _m12*m._m21; |

1032 | qreal tm12 = _m11*m._m12 + _m12*m._m22; |

1033 | qreal tm21 = _m21*m._m11 + _m22*m._m21; |

1034 | qreal tm22 = _m21*m._m12 + _m22*m._m22; |

1035 | |

1036 | qreal tdx = _dx*m._m11 + _dy*m._m21 + m._dx; |

1037 | qreal tdy = _dx*m._m12 + _dy*m._m22 + m._dy; |

1038 | |

1039 | _m11 = tm11; _m12 = tm12; |

1040 | _m21 = tm21; _m22 = tm22; |

1041 | _dx = tdx; _dy = tdy; |

1042 | return *this; |

1043 | } |

1044 | |

1045 | /*! |

1046 | \fn QMatrix QMatrix::operator *(const QMatrix &matrix) const |

1047 | |

1048 | Returns the result of multiplying this matrix by the given \a |

1049 | matrix. |

1050 | |

1051 | Note that matrix multiplication is not commutative, i.e. a*b != |

1052 | b*a. |

1053 | */ |

1054 | |

1055 | QMatrix QMatrix::operator *(const QMatrix &m) const |

1056 | { |

1057 | qreal tm11 = _m11*m._m11 + _m12*m._m21; |

1058 | qreal tm12 = _m11*m._m12 + _m12*m._m22; |

1059 | qreal tm21 = _m21*m._m11 + _m22*m._m21; |

1060 | qreal tm22 = _m21*m._m12 + _m22*m._m22; |

1061 | |

1062 | qreal tdx = _dx*m._m11 + _dy*m._m21 + m._dx; |

1063 | qreal tdy = _dx*m._m12 + _dy*m._m22 + m._dy; |

1064 | return QMatrix(tm11, tm12, tm21, tm22, tdx, tdy, true); |

1065 | } |

1066 | |

1067 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) |

1068 | /*! |

1069 | Assigns the given \a matrix's values to this matrix. |

1070 | */ |

1071 | QMatrix &QMatrix::operator=(const QMatrix &matrix) noexcept |

1072 | { |

1073 | _m11 = matrix._m11; |

1074 | _m12 = matrix._m12; |

1075 | _m21 = matrix._m21; |

1076 | _m22 = matrix._m22; |

1077 | _dx = matrix._dx; |

1078 | _dy = matrix._dy; |

1079 | return *this; |

1080 | } |

1081 | #endif |

1082 | |

1083 | /*! |

1084 | \since 4.2 |

1085 | |

1086 | Returns the matrix as a QVariant. |

1087 | */ |

1088 | QMatrix::operator QVariant() const |

1089 | { |

1090 | return QVariant(QVariant::Matrix, this); |

1091 | } |

1092 | |

1093 | Q_GUI_EXPORT QPainterPath operator *(const QPainterPath &p, const QMatrix &m) |

1094 | { |

1095 | return m.map(p); |

1096 | } |

1097 | |

1098 | |

1099 | /***************************************************************************** |

1100 | QMatrix stream functions |

1101 | *****************************************************************************/ |

1102 | #ifndef QT_NO_DATASTREAM |

1103 | /*! |

1104 | \fn QDataStream &operator<<(QDataStream &stream, const QMatrix &matrix) |

1105 | \relates QMatrix |

1106 | |

1107 | Writes the given \a matrix to the given \a stream and returns a |

1108 | reference to the stream. |

1109 | |

1110 | \sa {Serializing Qt Data Types} |

1111 | */ |

1112 | |

1113 | QDataStream &operator<<(QDataStream &s, const QMatrix &m) |

1114 | { |

1115 | if (s.version() == 1) { |

1116 | s << (float)m.m11() << (float)m.m12() << (float)m.m21() |

1117 | << (float)m.m22() << (float)m.dx() << (float)m.dy(); |

1118 | } else { |

1119 | s << double(m.m11()) |

1120 | << double(m.m12()) |

1121 | << double(m.m21()) |

1122 | << double(m.m22()) |

1123 | << double(m.dx()) |

1124 | << double(m.dy()); |

1125 | } |

1126 | return s; |

1127 | } |

1128 | |

1129 | /*! |

1130 | \fn QDataStream &operator>>(QDataStream &stream, QMatrix &matrix) |

1131 | \relates QMatrix |

1132 | |

1133 | Reads the given \a matrix from the given \a stream and returns a |

1134 | reference to the stream. |

1135 | |

1136 | \sa {Serializing Qt Data Types} |

1137 | */ |

1138 | |

1139 | QDataStream &operator>>(QDataStream &s, QMatrix &m) |

1140 | { |

1141 | if (s.version() == 1) { |

1142 | float m11, m12, m21, m22, dx, dy; |

1143 | s >> m11; s >> m12; s >> m21; s >> m22; |

1144 | s >> dx; s >> dy; |

1145 | m.setMatrix(m11, m12, m21, m22, dx, dy); |

1146 | } |

1147 | else { |

1148 | double m11, m12, m21, m22, dx, dy; |

1149 | s >> m11; |

1150 | s >> m12; |

1151 | s >> m21; |

1152 | s >> m22; |

1153 | s >> dx; |

1154 | s >> dy; |

1155 | m.setMatrix(m11, m12, m21, m22, dx, dy); |

1156 | } |

1157 | return s; |

1158 | } |

1159 | #endif // QT_NO_DATASTREAM |

1160 | |

1161 | #ifndef QT_NO_DEBUG_STREAM |

1162 | QDebug operator<<(QDebug dbg, const QMatrix &m) |

1163 | { |

1164 | QDebugStateSaver saver(dbg); |

1165 | dbg.nospace() << "QMatrix(" |

1166 | << "11="<< m.m11() |

1167 | << " 12="<< m.m12() |

1168 | << " 21="<< m.m21() |

1169 | << " 22="<< m.m22() |

1170 | << " dx="<< m.dx() |

1171 | << " dy="<< m.dy() |

1172 | << ')'; |

1173 | return dbg; |

1174 | } |

1175 | #endif |

1176 | |

1177 | /*! |

1178 | \fn bool qFuzzyCompare(const QMatrix& m1, const QMatrix& m2) |

1179 | |

1180 | \relates QMatrix |

1181 | \since 4.6 |

1182 | |

1183 | \brief The qFuzzyCompare function is for comparing two matrices |

1184 | using a fuzziness factor. |

1185 | |

1186 | Returns \c true if \a m1 and \a m2 are equal, allowing for a small |

1187 | fuzziness factor for floating-point comparisons; false otherwise. |

1188 | */ |

1189 | |

1190 | QT_END_NAMESPACE |

1191 |