/**************************************************************************** | |
** | |
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). | |
** All rights reserved. | |
** Contact: Nokia Corporation (qt-info@nokia.com) | |
** | |
** This file is part of the QtGui module of the Qt Toolkit. | |
** | |
** $QT_BEGIN_LICENSE:LGPL$ | |
** GNU Lesser General Public License Usage | |
** This file may be used under the terms of the GNU Lesser General Public | |
** License version 2.1 as published by the Free Software Foundation and | |
** appearing in the file LICENSE.LGPL included in the packaging of this | |
** file. Please review the following information to ensure the GNU Lesser | |
** General Public License version 2.1 requirements will be met: | |
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. | |
** | |
** In addition, as a special exception, Nokia gives you certain additional | |
** rights. These rights are described in the Nokia Qt LGPL Exception | |
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. | |
** | |
** GNU General Public License Usage | |
** Alternatively, this file may be used under the terms of the GNU General | |
** Public License version 3.0 as published by the Free Software Foundation | |
** and appearing in the file LICENSE.GPL included in the packaging of this | |
** file. Please review the following information to ensure the GNU General | |
** Public License version 3.0 requirements will be met: | |
** http://www.gnu.org/copyleft/gpl.html. | |
** | |
** Other Usage | |
** Alternatively, this file may be used in accordance with the terms and | |
** conditions contained in a signed written agreement between you and Nokia. | |
** | |
** | |
** | |
** | |
** | |
** $QT_END_LICENSE$ | |
** | |
****************************************************************************/ | |
#include "qdatastream.h" | |
#include "qdebug.h" | |
#include "qmatrix.h" | |
#include "qregion.h" | |
#include "qpainterpath.h" | |
#include "qvariant.h" | |
#include <qmath.h> | |
#include <limits.h> | |
QT_BEGIN_NAMESPACE | |
/*! | |
\class QMatrix | |
\brief The QMatrix class specifies 2D transformations of a | |
coordinate system. | |
\obsolete | |
\ingroup painting | |
A matrix specifies how to translate, scale, shear or rotate the | |
coordinate system, and is typically used when rendering graphics. | |
QMatrix, in contrast to QTransform, does not allow perspective | |
transformations. QTransform is the recommended transformation | |
class in Qt. | |
A QMatrix object can be built using the setMatrix(), scale(), | |
rotate(), translate() and shear() functions. Alternatively, it | |
can be built by applying \l {QMatrix#Basic Matrix | |
Operations}{basic matrix operations}. The matrix can also be | |
defined when constructed, and it can be reset to the identity | |
matrix (the default) using the reset() function. | |
The QMatrix class supports mapping of graphic primitives: A given | |
point, line, polygon, region, or painter path can be mapped to the | |
coordinate system defined by \e this matrix using the map() | |
function. In case of a rectangle, its coordinates can be | |
transformed using the mapRect() function. A rectangle can also be | |
transformed into a \e polygon (mapped to the coordinate system | |
defined by \e this matrix), using the mapToPolygon() function. | |
QMatrix provides the isIdentity() function which returns true if | |
the matrix is the identity matrix, and the isInvertible() function | |
which returns true if the matrix is non-singular (i.e. AB = BA = | |
I). The inverted() function returns an inverted copy of \e this | |
matrix if it is invertible (otherwise it returns the identity | |
matrix). In addition, QMatrix provides the determinant() function | |
returning the matrix's determinant. | |
Finally, the QMatrix class supports matrix multiplication, and | |
objects of the class can be streamed as well as compared. | |
\tableofcontents | |
\section1 Rendering Graphics | |
When rendering graphics, the matrix defines the transformations | |
but the actual transformation is performed by the drawing routines | |
in QPainter. | |
By default, QPainter operates on the associated device's own | |
coordinate system. The standard coordinate system of a | |
QPaintDevice has its origin located at the top-left position. The | |
\e x values increase to the right; \e y values increase | |
downward. For a complete description, see the \l {Coordinate | |
System}{coordinate system} documentation. | |
QPainter has functions to translate, scale, shear and rotate the | |
coordinate system without using a QMatrix. For example: | |
\table 100% | |
\row | |
\o \inlineimage qmatrix-simpletransformation.png | |
\o | |
\snippet doc/src/snippets/matrix/matrix.cpp 0 | |
\endtable | |
Although these functions are very convenient, it can be more | |
efficient to build a QMatrix and call QPainter::setMatrix() if you | |
want to perform more than a single transform operation. For | |
example: | |
\table 100% | |
\row | |
\o \inlineimage qmatrix-combinedtransformation.png | |
\o | |
\snippet doc/src/snippets/matrix/matrix.cpp 1 | |
\endtable | |
\section1 Basic Matrix Operations | |
\image qmatrix-representation.png | |
A QMatrix object contains a 3 x 3 matrix. The \c dx and \c dy | |
elements specify horizontal and vertical translation. The \c m11 | |
and \c m22 elements specify horizontal and vertical scaling. And | |
finally, the \c m21 and \c m12 elements specify horizontal and | |
vertical \e shearing. | |
QMatrix transforms a point in the plane to another point using the | |
following formulas: | |
\snippet doc/src/snippets/code/src_gui_painting_qmatrix.cpp 0 | |
The point \e (x, y) is the original point, and \e (x', y') is the | |
transformed point. \e (x', y') can be transformed back to \e (x, | |
y) by performing the same operation on the inverted() matrix. | |
The various matrix elements can be set when constructing the | |
matrix, or by using the setMatrix() function later on. They can also | |
be manipulated using the translate(), rotate(), scale() and | |
shear() convenience functions, The currently set values can be | |
retrieved using the m11(), m12(), m21(), m22(), dx() and dy() | |
functions. | |
Translation is the simplest transformation. Setting \c dx and \c | |
dy will move the coordinate system \c dx units along the X axis | |
and \c dy units along the Y axis. Scaling can be done by setting | |
\c m11 and \c m22. For example, setting \c m11 to 2 and \c m22 to | |
1.5 will double the height and increase the width by 50%. The | |
identity matrix has \c m11 and \c m22 set to 1 (all others are set | |
to 0) mapping a point to itself. Shearing is controlled by \c m12 | |
and \c m21. Setting these elements to values different from zero | |
will twist the coordinate system. Rotation is achieved by | |
carefully setting both the shearing factors and the scaling | |
factors. | |
Here's the combined transformations example using basic matrix | |
operations: | |
\table 100% | |
\row | |
\o \inlineimage qmatrix-combinedtransformation.png | |
\o | |
\snippet doc/src/snippets/matrix/matrix.cpp 2 | |
\endtable | |
\sa QPainter, QTransform, {Coordinate System}, | |
{demos/affine}{Affine Transformations Demo}, {Transformations Example} | |
*/ | |
// some defines to inline some code | |
#define MAPDOUBLE(x, y, nx, ny) \ | |
{ \ | |
qreal fx = x; \ | |
qreal fy = y; \ | |
nx = _m11*fx + _m21*fy + _dx; \ | |
ny = _m12*fx + _m22*fy + _dy; \ | |
} | |
#define MAPINT(x, y, nx, ny) \ | |
{ \ | |
qreal fx = x; \ | |
qreal fy = y; \ | |
nx = qRound(_m11*fx + _m21*fy + _dx); \ | |
ny = qRound(_m12*fx + _m22*fy + _dy); \ | |
} | |
/***************************************************************************** | |
QMatrix member functions | |
*****************************************************************************/ | |
/*! | |
\fn QMatrix::QMatrix(Qt::Initialization) | |
\internal | |
*/ | |
/*! | |
Constructs an identity matrix. | |
All elements are set to zero except \c m11 and \c m22 (specifying | |
the scale), which are set to 1. | |
\sa reset() | |
*/ | |
QMatrix::QMatrix() | |
: _m11(1.) | |
, _m12(0.) | |
, _m21(0.) | |
, _m22(1.) | |
, _dx(0.) | |
, _dy(0.) | |
{ | |
} | |
/*! | |
Constructs a matrix with the elements, \a m11, \a m12, \a m21, \a | |
m22, \a dx and \a dy. | |
\sa setMatrix() | |
*/ | |
QMatrix::QMatrix(qreal m11, qreal m12, qreal m21, qreal m22, qreal dx, qreal dy) | |
: _m11(m11) | |
, _m12(m12) | |
, _m21(m21) | |
, _m22(m22) | |
, _dx(dx) | |
, _dy(dy) | |
{ | |
} | |
/*! | |
Constructs a matrix that is a copy of the given \a matrix. | |
*/ | |
QMatrix::QMatrix(const QMatrix &matrix) | |
: _m11(matrix._m11) | |
, _m12(matrix._m12) | |
, _m21(matrix._m21) | |
, _m22(matrix._m22) | |
, _dx(matrix._dx) | |
, _dy(matrix._dy) | |
{ | |
} | |
/*! | |
Sets the matrix elements to the specified values, \a m11, \a m12, | |
\a m21, \a m22, \a dx and \a dy. | |
Note that this function replaces the previous values. QMatrix | |
provide the translate(), rotate(), scale() and shear() convenience | |
functions to manipulate the various matrix elements based on the | |
currently defined coordinate system. | |
\sa QMatrix() | |
*/ | |
void QMatrix::setMatrix(qreal m11, qreal m12, qreal m21, qreal m22, qreal dx, qreal dy) | |
{ | |
_m11 = m11; | |
_m12 = m12; | |
_m21 = m21; | |
_m22 = m22; | |
_dx = dx; | |
_dy = dy; | |
} | |
/*! | |
\fn qreal QMatrix::m11() const | |
Returns the horizontal scaling factor. | |
\sa scale(), {QMatrix#Basic Matrix Operations}{Basic Matrix | |
Operations} | |
*/ | |
/*! | |
\fn qreal QMatrix::m12() const | |
Returns the vertical shearing factor. | |
\sa shear(), {QMatrix#Basic Matrix Operations}{Basic Matrix | |
Operations} | |
*/ | |
/*! | |
\fn qreal QMatrix::m21() const | |
Returns the horizontal shearing factor. | |
\sa shear(), {QMatrix#Basic Matrix Operations}{Basic Matrix | |
Operations} | |
*/ | |
/*! | |
\fn qreal QMatrix::m22() const | |
Returns the vertical scaling factor. | |
\sa scale(), {QMatrix#Basic Matrix Operations}{Basic Matrix | |
Operations} | |
*/ | |
/*! | |
\fn qreal QMatrix::dx() const | |
Returns the horizontal translation factor. | |
\sa translate(), {QMatrix#Basic Matrix Operations}{Basic Matrix | |
Operations} | |
*/ | |
/*! | |
\fn qreal QMatrix::dy() const | |
Returns the vertical translation factor. | |
\sa translate(), {QMatrix#Basic Matrix Operations}{Basic Matrix | |
Operations} | |
*/ | |
/*! | |
Maps the given coordinates \a x and \a y into the coordinate | |
system defined by this matrix. The resulting values are put in *\a | |
tx and *\a ty, respectively. | |
The coordinates are transformed using the following formulas: | |
\snippet doc/src/snippets/code/src_gui_painting_qmatrix.cpp 1 | |
The point (x, y) is the original point, and (x', y') is the | |
transformed point. | |
\sa {QMatrix#Basic Matrix Operations}{Basic Matrix Operations} | |
*/ | |
void QMatrix::map(qreal x, qreal y, qreal *tx, qreal *ty) const | |
{ | |
MAPDOUBLE(x, y, *tx, *ty); | |
} | |
/*! | |
\overload | |
Maps the given coordinates \a x and \a y into the coordinate | |
system defined by this matrix. The resulting values are put in *\a | |
tx and *\a ty, respectively. Note that the transformed coordinates | |
are rounded to the nearest integer. | |
*/ | |
void QMatrix::map(int x, int y, int *tx, int *ty) const | |
{ | |
MAPINT(x, y, *tx, *ty); | |
} | |
QRect QMatrix::mapRect(const QRect &rect) const | |
{ | |
QRect result; | |
if (_m12 == 0.0F && _m21 == 0.0F) { | |
int x = qRound(_m11*rect.x() + _dx); | |
int y = qRound(_m22*rect.y() + _dy); | |
int w = qRound(_m11*rect.width()); | |
int h = qRound(_m22*rect.height()); | |
if (w < 0) { | |
w = -w; | |
x -= w; | |
} | |
if (h < 0) { | |
h = -h; | |
y -= h; | |
} | |
result = QRect(x, y, w, h); | |
} else { | |
// see mapToPolygon for explanations of the algorithm. | |
qreal x0, y0; | |
qreal x, y; | |
MAPDOUBLE(rect.left(), rect.top(), x0, y0); | |
qreal xmin = x0; | |
qreal ymin = y0; | |
qreal xmax = x0; | |
qreal ymax = y0; | |
MAPDOUBLE(rect.right() + 1, rect.top(), x, y); | |
xmin = qMin(xmin, x); | |
ymin = qMin(ymin, y); | |
xmax = qMax(xmax, x); | |
ymax = qMax(ymax, y); | |
MAPDOUBLE(rect.right() + 1, rect.bottom() + 1, x, y); | |
xmin = qMin(xmin, x); | |
ymin = qMin(ymin, y); | |
xmax = qMax(xmax, x); | |
ymax = qMax(ymax, y); | |
MAPDOUBLE(rect.left(), rect.bottom() + 1, x, y); | |
xmin = qMin(xmin, x); | |
ymin = qMin(ymin, y); | |
xmax = qMax(xmax, x); | |
ymax = qMax(ymax, y); | |
result = QRect(qRound(xmin), qRound(ymin), qRound(xmax)-qRound(xmin), qRound(ymax)-qRound(ymin)); | |
} | |
return result; | |
} | |
/*! | |
\fn QRectF QMatrix::mapRect(const QRectF &rectangle) const | |
Creates and returns a QRectF object that is a copy of the given \a | |
rectangle, mapped into the coordinate system defined by this | |
matrix. | |
The rectangle's coordinates are transformed using the following | |
formulas: | |
\snippet doc/src/snippets/code/src_gui_painting_qmatrix.cpp 2 | |
If rotation or shearing has been specified, this function returns | |
the \e bounding rectangle. To retrieve the exact region the given | |
\a rectangle maps to, use the mapToPolygon() function instead. | |
\sa mapToPolygon(), {QMatrix#Basic Matrix Operations}{Basic Matrix | |
Operations} | |
*/ | |
QRectF QMatrix::mapRect(const QRectF &rect) const | |
{ | |
QRectF result; | |
if (_m12 == 0.0F && _m21 == 0.0F) { | |
qreal x = _m11*rect.x() + _dx; | |
qreal y = _m22*rect.y() + _dy; | |
qreal w = _m11*rect.width(); | |
qreal h = _m22*rect.height(); | |
if (w < 0) { | |
w = -w; | |
x -= w; | |
} | |
if (h < 0) { | |
h = -h; | |
y -= h; | |
} | |
result = QRectF(x, y, w, h); | |
} else { | |
qreal x0, y0; | |
qreal x, y; | |
MAPDOUBLE(rect.x(), rect.y(), x0, y0); | |
qreal xmin = x0; | |
qreal ymin = y0; | |
qreal xmax = x0; | |
qreal ymax = y0; | |
MAPDOUBLE(rect.x() + rect.width(), rect.y(), x, y); | |
xmin = qMin(xmin, x); | |
ymin = qMin(ymin, y); | |
xmax = qMax(xmax, x); | |
ymax = qMax(ymax, y); | |
MAPDOUBLE(rect.x() + rect.width(), rect.y() + rect.height(), x, y); | |
xmin = qMin(xmin, x); | |
ymin = qMin(ymin, y); | |
xmax = qMax(xmax, x); | |
ymax = qMax(ymax, y); | |
MAPDOUBLE(rect.x(), rect.y() + rect.height(), x, y); | |
xmin = qMin(xmin, x); | |
ymin = qMin(ymin, y); | |
xmax = qMax(xmax, x); | |
ymax = qMax(ymax, y); | |
result = QRectF(xmin, ymin, xmax-xmin, ymax - ymin); | |
} | |
return result; | |
} | |
/*! | |
\fn QRect QMatrix::mapRect(const QRect &rectangle) const | |
\overload | |
Creates and returns a QRect object that is a copy of the given \a | |
rectangle, mapped into the coordinate system defined by this | |
matrix. Note that the transformed coordinates are rounded to the | |
nearest integer. | |
*/ | |
/*! | |
\fn QPoint operator*(const QPoint &point, const QMatrix &matrix) | |
\relates QMatrix | |
This is the same as \a{matrix}.map(\a{point}). | |
\sa QMatrix::map() | |
*/ | |
QPoint QMatrix::map(const QPoint &p) const | |
{ | |
qreal fx = p.x(); | |
qreal fy = p.y(); | |
return QPoint(qRound(_m11*fx + _m21*fy + _dx), | |
qRound(_m12*fx + _m22*fy + _dy)); | |
} | |
/*! | |
\fn QPointF operator*(const QPointF &point, const QMatrix &matrix) | |
\relates QMatrix | |
Same as \a{matrix}.map(\a{point}). | |
\sa QMatrix::map() | |
*/ | |
/*! | |
\overload | |
Creates and returns a QPointF object that is a copy of the given | |
\a point, mapped into the coordinate system defined by this | |
matrix. | |
*/ | |
QPointF QMatrix::map(const QPointF &point) const | |
{ | |
qreal fx = point.x(); | |
qreal fy = point.y(); | |
return QPointF(_m11*fx + _m21*fy + _dx, _m12*fx + _m22*fy + _dy); | |
} | |
/*! | |
\fn QPoint QMatrix::map(const QPoint &point) const | |
\overload | |
Creates and returns a QPoint object that is a copy of the given \a | |
point, mapped into the coordinate system defined by this | |
matrix. Note that the transformed coordinates are rounded to the | |
nearest integer. | |
*/ | |
/*! | |
\fn QLineF operator*(const QLineF &line, const QMatrix &matrix) | |
\relates QMatrix | |
This is the same as \a{matrix}.map(\a{line}). | |
\sa QMatrix::map() | |
*/ | |
/*! | |
\fn QLine operator*(const QLine &line, const QMatrix &matrix) | |
\relates QMatrix | |
This is the same as \a{matrix}.map(\a{line}). | |
\sa QMatrix::map() | |
*/ | |
/*! | |
\overload | |
Creates and returns a QLineF object that is a copy of the given \a | |
line, mapped into the coordinate system defined by this matrix. | |
*/ | |
QLineF QMatrix::map(const QLineF &line) const | |
{ | |
return QLineF(map(line.p1()), map(line.p2())); | |
} | |
/*! | |
\overload | |
Creates and returns a QLine object that is a copy of the given \a | |
line, mapped into the coordinate system defined by this matrix. | |
Note that the transformed coordinates are rounded to the nearest | |
integer. | |
*/ | |
QLine QMatrix::map(const QLine &line) const | |
{ | |
return QLine(map(line.p1()), map(line.p2())); | |
} | |
/*! | |
\fn QPolygonF operator *(const QPolygonF &polygon, const QMatrix &matrix) | |
\relates QMatrix | |
This is the same as \a{matrix}.map(\a{polygon}). | |
\sa QMatrix::map() | |
*/ | |
/*! | |
\fn QPolygon operator*(const QPolygon &polygon, const QMatrix &matrix) | |
\relates QMatrix | |
This is the same as \a{matrix}.map(\a{polygon}). | |
\sa QMatrix::map() | |
*/ | |
QPolygon QMatrix::map(const QPolygon &a) const | |
{ | |
int size = a.size(); | |
int i; | |
QPolygon p(size); | |
const QPoint *da = a.constData(); | |
QPoint *dp = p.data(); | |
for(i = 0; i < size; i++) { | |
MAPINT(da[i].x(), da[i].y(), dp[i].rx(), dp[i].ry()); | |
} | |
return p; | |
} | |
/*! | |
\fn QPolygonF QMatrix::map(const QPolygonF &polygon) const | |
\overload | |
Creates and returns a QPolygonF object that is a copy of the given | |
\a polygon, mapped into the coordinate system defined by this | |
matrix. | |
*/ | |
QPolygonF QMatrix::map(const QPolygonF &a) const | |
{ | |
int size = a.size(); | |
int i; | |
QPolygonF p(size); | |
const QPointF *da = a.constData(); | |
QPointF *dp = p.data(); | |
for(i = 0; i < size; i++) { | |
MAPDOUBLE(da[i].xp, da[i].yp, dp[i].xp, dp[i].yp); | |
} | |
return p; | |
} | |
/*! | |
\fn QPolygon QMatrix::map(const QPolygon &polygon) const | |
\overload | |
Creates and returns a QPolygon object that is a copy of the given | |
\a polygon, mapped into the coordinate system defined by this | |
matrix. Note that the transformed coordinates are rounded to the | |
nearest integer. | |
*/ | |
/*! | |
\fn QRegion operator*(const QRegion ®ion, const QMatrix &matrix) | |
\relates QMatrix | |
This is the same as \a{matrix}.map(\a{region}). | |
\sa QMatrix::map() | |
*/ | |
extern QPainterPath qt_regionToPath(const QRegion ®ion); | |
/*! | |
\fn QRegion QMatrix::map(const QRegion ®ion) const | |
\overload | |
Creates and returns a QRegion object that is a copy of the given | |
\a region, mapped into the coordinate system defined by this matrix. | |
Calling this method can be rather expensive if rotations or | |
shearing are used. | |
*/ | |
QRegion QMatrix::map(const QRegion &r) const | |
{ | |
if (_m11 == 1.0 && _m22 == 1.0 && _m12 == 0.0 && _m21 == 0.0) { // translate or identity | |
if (_dx == 0.0 && _dy == 0.0) // Identity | |
return r; | |
QRegion copy(r); | |
copy.translate(qRound(_dx), qRound(_dy)); | |
return copy; | |
} | |
QPainterPath p = map(qt_regionToPath(r)); | |
return p.toFillPolygon().toPolygon(); | |
} | |
/*! | |
\fn QPainterPath operator *(const QPainterPath &path, const QMatrix &matrix) | |
\relates QMatrix | |
This is the same as \a{matrix}.map(\a{path}). | |
\sa QMatrix::map() | |
*/ | |
/*! | |
\overload | |
Creates and returns a QPainterPath object that is a copy of the | |
given \a path, mapped into the coordinate system defined by this | |
matrix. | |
*/ | |
QPainterPath QMatrix::map(const QPainterPath &path) const | |
{ | |
if (path.isEmpty()) | |
return QPainterPath(); | |
QPainterPath copy = path; | |
// Translate or identity | |
if (_m11 == 1.0 && _m22 == 1.0 && _m12 == 0.0 && _m21 == 0.0) { | |
// Translate | |
if (_dx != 0.0 || _dy != 0.0) { | |
copy.detach(); | |
for (int i=0; i<path.elementCount(); ++i) { | |
QPainterPath::Element &e = copy.d_ptr->elements[i]; | |
e.x += _dx; | |
e.y += _dy; | |
} | |
} | |
// Full xform | |
} else { | |
copy.detach(); | |
for (int i=0; i<path.elementCount(); ++i) { | |
QPainterPath::Element &e = copy.d_ptr->elements[i]; | |
qreal fx = e.x, fy = e.y; | |
e.x = _m11*fx + _m21*fy + _dx; | |
e.y = _m12*fx + _m22*fy + _dy; | |
} | |
} | |
return copy; | |
} | |
/*! | |
\fn QRegion QMatrix::mapToRegion(const QRect &rectangle) const | |
Returns the transformed rectangle \a rectangle as a QRegion | |
object. A rectangle which has been rotated or sheared may result | |
in a non-rectangular region being returned. | |
Use the mapToPolygon() or map() function instead. | |
*/ | |
#ifdef QT3_SUPPORT | |
QRegion QMatrix::mapToRegion(const QRect &rect) const | |
{ | |
QRegion result; | |
if (isIdentity()) { | |
result = rect; | |
} else if (m12() == 0.0F && m21() == 0.0F) { | |
int x = qRound(m11()*rect.x() + dx()); | |
int y = qRound(m22()*rect.y() + dy()); | |
int w = qRound(m11()*rect.width()); | |
int h = qRound(m22()*rect.height()); | |
if (w < 0) { | |
w = -w; | |
x -= w - 1; | |
} | |
if (h < 0) { | |
h = -h; | |
y -= h - 1; | |
} | |
result = QRect(x, y, w, h); | |
} else { | |
result = QRegion(mapToPolygon(rect)); | |
} | |
return result; | |
} | |
#endif | |
/*! | |
\fn QPolygon QMatrix::mapToPolygon(const QRect &rectangle) const | |
Creates and returns a QPolygon representation of the given \a | |
rectangle, mapped into the coordinate system defined by this | |
matrix. | |
The rectangle's coordinates are transformed using the following | |
formulas: | |
\snippet doc/src/snippets/code/src_gui_painting_qmatrix.cpp 3 | |
Polygons and rectangles behave slightly differently when | |
transformed (due to integer rounding), so | |
\c{matrix.map(QPolygon(rectangle))} is not always the same as | |
\c{matrix.mapToPolygon(rectangle)}. | |
\sa mapRect(), {QMatrix#Basic Matrix Operations}{Basic Matrix | |
Operations} | |
*/ | |
QPolygon QMatrix::mapToPolygon(const QRect &rect) const | |
{ | |
QPolygon a(4); | |
qreal x[4], y[4]; | |
if (_m12 == 0.0F && _m21 == 0.0F) { | |
x[0] = _m11*rect.x() + _dx; | |
y[0] = _m22*rect.y() + _dy; | |
qreal w = _m11*rect.width(); | |
qreal h = _m22*rect.height(); | |
if (w < 0) { | |
w = -w; | |
x[0] -= w; | |
} | |
if (h < 0) { | |
h = -h; | |
y[0] -= h; | |
} | |
x[1] = x[0]+w; | |
x[2] = x[1]; | |
x[3] = x[0]; | |
y[1] = y[0]; | |
y[2] = y[0]+h; | |
y[3] = y[2]; | |
} else { | |
qreal right = rect.x() + rect.width(); | |
qreal bottom = rect.y() + rect.height(); | |
MAPDOUBLE(rect.x(), rect.y(), x[0], y[0]); | |
MAPDOUBLE(right, rect.y(), x[1], y[1]); | |
MAPDOUBLE(right, bottom, x[2], y[2]); | |
MAPDOUBLE(rect.x(), bottom, x[3], y[3]); | |
} | |
#if 0 | |
int i; | |
for(i = 0; i< 4; i++) | |
qDebug("coords(%d) = (%f/%f) (%d/%d)", i, x[i], y[i], qRound(x[i]), qRound(y[i])); | |
qDebug("width=%f, height=%f", qSqrt((x[1]-x[0])*(x[1]-x[0]) + (y[1]-y[0])*(y[1]-y[0])), | |
qSqrt((x[0]-x[3])*(x[0]-x[3]) + (y[0]-y[3])*(y[0]-y[3]))); | |
#endif | |
// all coordinates are correctly, tranform to a pointarray | |
// (rounding to the next integer) | |
a.setPoints(4, qRound(x[0]), qRound(y[0]), | |
qRound(x[1]), qRound(y[1]), | |
qRound(x[2]), qRound(y[2]), | |
qRound(x[3]), qRound(y[3])); | |
return a; | |
} | |
/*! | |
Resets the matrix to an identity matrix, i.e. all elements are set | |
to zero, except \c m11 and \c m22 (specifying the scale) which are | |
set to 1. | |
\sa QMatrix(), isIdentity(), {QMatrix#Basic Matrix | |
Operations}{Basic Matrix Operations} | |
*/ | |
void QMatrix::reset() | |
{ | |
_m11 = _m22 = 1.0; | |
_m12 = _m21 = _dx = _dy = 0.0; | |
} | |
/*! | |
\fn bool QMatrix::isIdentity() const | |
Returns true if the matrix is the identity matrix, otherwise | |
returns false. | |
\sa reset() | |
*/ | |
/*! | |
Moves the coordinate system \a dx along the x axis and \a dy along | |
the y axis, and returns a reference to the matrix. | |
\sa setMatrix() | |
*/ | |
QMatrix &QMatrix::translate(qreal dx, qreal dy) | |
{ | |
_dx += dx*_m11 + dy*_m21; | |
_dy += dy*_m22 + dx*_m12; | |
return *this; | |
} | |
/*! | |
\fn QMatrix &QMatrix::scale(qreal sx, qreal sy) | |
Scales the coordinate system by \a sx horizontally and \a sy | |
vertically, and returns a reference to the matrix. | |
\sa setMatrix() | |
*/ | |
QMatrix &QMatrix::scale(qreal sx, qreal sy) | |
{ | |
_m11 *= sx; | |
_m12 *= sx; | |
_m21 *= sy; | |
_m22 *= sy; | |
return *this; | |
} | |
/*! | |
Shears the coordinate system by \a sh horizontally and \a sv | |
vertically, and returns a reference to the matrix. | |
\sa setMatrix() | |
*/ | |
QMatrix &QMatrix::shear(qreal sh, qreal sv) | |
{ | |
qreal tm11 = sv*_m21; | |
qreal tm12 = sv*_m22; | |
qreal tm21 = sh*_m11; | |
qreal tm22 = sh*_m12; | |
_m11 += tm11; | |
_m12 += tm12; | |
_m21 += tm21; | |
_m22 += tm22; | |
return *this; | |
} | |
const qreal deg2rad = qreal(0.017453292519943295769); // pi/180 | |
/*! | |
\fn QMatrix &QMatrix::rotate(qreal degrees) | |
Rotates the coordinate system the given \a degrees | |
counterclockwise. | |
Note that if you apply a QMatrix to a point defined in widget | |
coordinates, the direction of the rotation will be clockwise | |
because the y-axis points downwards. | |
Returns a reference to the matrix. | |
\sa setMatrix() | |
*/ | |
QMatrix &QMatrix::rotate(qreal a) | |
{ | |
qreal sina = 0; | |
qreal cosa = 0; | |
if (a == 90. || a == -270.) | |
sina = 1.; | |
else if (a == 270. || a == -90.) | |
sina = -1.; | |
else if (a == 180.) | |
cosa = -1.; | |
else{ | |
qreal b = deg2rad*a; // convert to radians | |
sina = qSin(b); // fast and convenient | |
cosa = qCos(b); | |
} | |
qreal tm11 = cosa*_m11 + sina*_m21; | |
qreal tm12 = cosa*_m12 + sina*_m22; | |
qreal tm21 = -sina*_m11 + cosa*_m21; | |
qreal tm22 = -sina*_m12 + cosa*_m22; | |
_m11 = tm11; _m12 = tm12; | |
_m21 = tm21; _m22 = tm22; | |
return *this; | |
} | |
/*! | |
\fn bool QMatrix::isInvertible() const | |
Returns true if the matrix is invertible, otherwise returns false. | |
\sa inverted() | |
*/ | |
/*! | |
\obsolete | |
\fn qreal QMatrix::det() const | |
Returns the matrix's determinant. | |
\sa determinant() | |
*/ | |
/*! | |
\since 4.6 | |
\fn qreal QMatrix::determinant() const | |
Returns the matrix's determinant. | |
*/ | |
/*! | |
\fn QMatrix QMatrix::invert(bool *invertible) const | |
Returns an inverted copy of this matrix. | |
Use the inverted() function instead. | |
*/ | |
/*! | |
Returns an inverted copy of this matrix. | |
If the matrix is singular (not invertible), the returned matrix is | |
the identity matrix. If \a invertible is valid (i.e. not 0), its | |
value is set to true if the matrix is invertible, otherwise it is | |
set to false. | |
\sa isInvertible() | |
*/ | |
QMatrix QMatrix::inverted(bool *invertible) const | |
{ | |
qreal dtr = determinant(); | |
if (dtr == 0.0) { | |
if (invertible) | |
*invertible = false; // singular matrix | |
return QMatrix(true); | |
} | |
else { // invertible matrix | |
if (invertible) | |
*invertible = true; | |
qreal dinv = 1.0/dtr; | |
return QMatrix((_m22*dinv), (-_m12*dinv), | |
(-_m21*dinv), (_m11*dinv), | |
((_m21*_dy - _m22*_dx)*dinv), | |
((_m12*_dx - _m11*_dy)*dinv), | |
true); | |
} | |
} | |
/*! | |
\fn bool QMatrix::operator==(const QMatrix &matrix) const | |
Returns true if this matrix is equal to the given \a matrix, | |
otherwise returns false. | |
*/ | |
bool QMatrix::operator==(const QMatrix &m) const | |
{ | |
return _m11 == m._m11 && | |
_m12 == m._m12 && | |
_m21 == m._m21 && | |
_m22 == m._m22 && | |
_dx == m._dx && | |
_dy == m._dy; | |
} | |
/*! | |
\fn bool QMatrix::operator!=(const QMatrix &matrix) const | |
Returns true if this matrix is not equal to the given \a matrix, | |
otherwise returns false. | |
*/ | |
bool QMatrix::operator!=(const QMatrix &m) const | |
{ | |
return _m11 != m._m11 || | |
_m12 != m._m12 || | |
_m21 != m._m21 || | |
_m22 != m._m22 || | |
_dx != m._dx || | |
_dy != m._dy; | |
} | |
/*! | |
\fn QMatrix &QMatrix::operator *=(const QMatrix &matrix) | |
\overload | |
Returns the result of multiplying this matrix by the given \a | |
matrix. | |
*/ | |
QMatrix &QMatrix::operator *=(const QMatrix &m) | |
{ | |
qreal tm11 = _m11*m._m11 + _m12*m._m21; | |
qreal tm12 = _m11*m._m12 + _m12*m._m22; | |
qreal tm21 = _m21*m._m11 + _m22*m._m21; | |
qreal tm22 = _m21*m._m12 + _m22*m._m22; | |
qreal tdx = _dx*m._m11 + _dy*m._m21 + m._dx; | |
qreal tdy = _dx*m._m12 + _dy*m._m22 + m._dy; | |
_m11 = tm11; _m12 = tm12; | |
_m21 = tm21; _m22 = tm22; | |
_dx = tdx; _dy = tdy; | |
return *this; | |
} | |
/*! | |
\fn QMatrix QMatrix::operator *(const QMatrix &matrix) const | |
Returns the result of multiplying this matrix by the given \a | |
matrix. | |
Note that matrix multiplication is not commutative, i.e. a*b != | |
b*a. | |
*/ | |
QMatrix QMatrix::operator *(const QMatrix &m) const | |
{ | |
qreal tm11 = _m11*m._m11 + _m12*m._m21; | |
qreal tm12 = _m11*m._m12 + _m12*m._m22; | |
qreal tm21 = _m21*m._m11 + _m22*m._m21; | |
qreal tm22 = _m21*m._m12 + _m22*m._m22; | |
qreal tdx = _dx*m._m11 + _dy*m._m21 + m._dx; | |
qreal tdy = _dx*m._m12 + _dy*m._m22 + m._dy; | |
return QMatrix(tm11, tm12, tm21, tm22, tdx, tdy, true); | |
} | |
/*! | |
Assigns the given \a matrix's values to this matrix. | |
*/ | |
QMatrix &QMatrix::operator=(const QMatrix &matrix) | |
{ | |
_m11 = matrix._m11; | |
_m12 = matrix._m12; | |
_m21 = matrix._m21; | |
_m22 = matrix._m22; | |
_dx = matrix._dx; | |
_dy = matrix._dy; | |
return *this; | |
} | |
/*! | |
\since 4.2 | |
Returns the matrix as a QVariant. | |
*/ | |
QMatrix::operator QVariant() const | |
{ | |
return QVariant(QVariant::Matrix, this); | |
} | |
Q_GUI_EXPORT QPainterPath operator *(const QPainterPath &p, const QMatrix &m) | |
{ | |
return m.map(p); | |
} | |
/***************************************************************************** | |
QMatrix stream functions | |
*****************************************************************************/ | |
#ifndef QT_NO_DATASTREAM | |
/*! | |
\fn QDataStream &operator<<(QDataStream &stream, const QMatrix &matrix) | |
\relates QMatrix | |
Writes the given \a matrix to the given \a stream and returns a | |
reference to the stream. | |
\sa {Serializing Qt Data Types} | |
*/ | |
QDataStream &operator<<(QDataStream &s, const QMatrix &m) | |
{ | |
if (s.version() == 1) { | |
s << (float)m.m11() << (float)m.m12() << (float)m.m21() | |
<< (float)m.m22() << (float)m.dx() << (float)m.dy(); | |
} else { | |
s << double(m.m11()) | |
<< double(m.m12()) | |
<< double(m.m21()) | |
<< double(m.m22()) | |
<< double(m.dx()) | |
<< double(m.dy()); | |
} | |
return s; | |
} | |
/*! | |
\fn QDataStream &operator>>(QDataStream &stream, QMatrix &matrix) | |
\relates QMatrix | |
Reads the given \a matrix from the given \a stream and returns a | |
reference to the stream. | |
\sa {Serializing Qt Data Types} | |
*/ | |
QDataStream &operator>>(QDataStream &s, QMatrix &m) | |
{ | |
if (s.version() == 1) { | |
float m11, m12, m21, m22, dx, dy; | |
s >> m11; s >> m12; s >> m21; s >> m22; | |
s >> dx; s >> dy; | |
m.setMatrix(m11, m12, m21, m22, dx, dy); | |
} | |
else { | |
double m11, m12, m21, m22, dx, dy; | |
s >> m11; | |
s >> m12; | |
s >> m21; | |
s >> m22; | |
s >> dx; | |
s >> dy; | |
m.setMatrix(m11, m12, m21, m22, dx, dy); | |
} | |
return s; | |
} | |
#endif // QT_NO_DATASTREAM | |
#ifndef QT_NO_DEBUG_STREAM | |
QDebug operator<<(QDebug dbg, const QMatrix &m) | |
{ | |
dbg.nospace() << "QMatrix(" | |
<< "11=" << m.m11() | |
<< " 12=" << m.m12() | |
<< " 21=" << m.m21() | |
<< " 22=" << m.m22() | |
<< " dx=" << m.dx() | |
<< " dy=" << m.dy() | |
<< ')'; | |
return dbg.space(); | |
} | |
#endif | |
/*! | |
\fn QRect QMatrix::map(const QRect &rect) const | |
\compat | |
Creates and returns a QRect object that is a copy of the given | |
rectangle, mapped into the coordinate system defined by this | |
matrix. | |
Use the mapRect() function instead. | |
*/ | |
/*! | |
\fn bool qFuzzyCompare(const QMatrix& m1, const QMatrix& m2) | |
\relates QMatrix | |
\since 4.6 | |
\brief The qFuzzyCompare function is for comparing two matrices | |
using a fuzziness factor. | |
Returns true if \a m1 and \a m2 are equal, allowing for a small | |
fuzziness factor for floating-point comparisons; false otherwise. | |
*/ | |
QT_END_NAMESPACE |