summaryrefslogtreecommitdiffstats
path: root/src/gui/painting/qtransform.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/painting/qtransform.cpp')
-rw-r--r--src/gui/painting/qtransform.cpp363
1 files changed, 243 insertions, 120 deletions
diff --git a/src/gui/painting/qtransform.cpp b/src/gui/painting/qtransform.cpp
index 1a0d3d7..859767b 100644
--- a/src/gui/painting/qtransform.cpp
+++ b/src/gui/painting/qtransform.cpp
@@ -48,11 +48,15 @@
#include "qvariant.h"
#include <qmath.h>
+#include <private/qbezier_p.h>
+
QT_BEGIN_NAMESPACE
#define Q_NEAR_CLIP 0.000001
-
+#ifdef MAP
+# undef MAP
+#endif
#define MAP(x, y, nx, ny) \
do { \
qreal FX_ = x; \
@@ -76,7 +80,9 @@ QT_BEGIN_NAMESPACE
nx = affine._m11 * FX_ + affine._m21 * FY_ + affine._dx; \
ny = affine._m12 * FX_ + affine._m22 * FY_ + affine._dy; \
if (t == TxProject) { \
- qreal w = 1./(m_13 * FX_ + m_23 * FY_ + m_33); \
+ qreal w = (m_13 * FX_ + m_23 * FY_ + m_33); \
+ if (w < qreal(Q_NEAR_CLIP)) w = qreal(Q_NEAR_CLIP); \
+ w = 1./w; \
nx *= w; \
ny *= w; \
} \
@@ -87,7 +93,7 @@ QT_BEGIN_NAMESPACE
\class QTransform
\brief The QTransform class specifies 2D transformations of a coordinate system.
\since 4.3
- \ingroup multimedia
+ \ingroup painting
A transformation specifies how to translate, scale, shear, rotate
or project the coordinate system, and is typically used when
@@ -97,7 +103,7 @@ QT_BEGIN_NAMESPACE
allowing perspective transformations. QTransform's toAffine()
method allows casting QTransform to QMatrix. If a perspective
transformation has been specified on the matrix, then the
- conversion to an affine QMatrix will cause loss of data.
+ conversion will cause loss of data.
QTransform is the recommended transformation class in Qt.
@@ -121,11 +127,13 @@ QT_BEGIN_NAMESPACE
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, QTransform provides the det() function
- returning the matrix's determinant.
+ matrix), and adjoint() returns the matrix's classical adjoint.
+ In addition, QTransform provides the determinant() function which
+ returns the matrix's determinant.
- Finally, the QTransform class supports matrix multiplication, and
- objects of the class can be streamed as well as compared.
+ Finally, the QTransform class supports matrix multiplication, addition
+ and subtraction, and objects of the class can be streamed as well
+ as compared.
\tableofcontents
@@ -187,7 +195,7 @@ QT_BEGIN_NAMESPACE
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
+ shear() convenience functions. The currently set values can be
retrieved using the m11(), m12(), m13(), m21(), m22(), m23(),
m31(), m32(), m33(), dx() and dy() functions.
@@ -200,9 +208,9 @@ QT_BEGIN_NAMESPACE
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. Perspective transformation is achieved by carefully setting
- both the projection factors and the scaling factors.
+ setting both the shearing factors and the scaling factors. Perspective
+ transformation is achieved by setting both the projection factors and
+ the scaling factors.
Here's the combined transformations example using basic matrix
operations:
@@ -230,6 +238,11 @@ QT_BEGIN_NAMESPACE
*/
/*!
+ \fn QTransform::QTransform(Qt::Initialization)
+ \internal
+*/
+
+/*!
Constructs an identity matrix.
All elements are set to zero except \c m11 and \c m22 (specifying
@@ -238,11 +251,11 @@ QT_BEGIN_NAMESPACE
\sa reset()
*/
QTransform::QTransform()
- : m_13(0), m_23(0), m_33(1)
+ : affine(true)
+ , m_13(0), m_23(0), m_33(1)
, m_type(TxNone)
, m_dirty(TxNone)
{
-
}
/*!
@@ -256,12 +269,11 @@ QTransform::QTransform()
QTransform::QTransform(qreal h11, qreal h12, qreal h13,
qreal h21, qreal h22, qreal h23,
qreal h31, qreal h32, qreal h33)
- : affine(h11, h12, h21, h22, h31, h32),
- m_13(h13), m_23(h23), m_33(h33)
+ : affine(h11, h12, h21, h22, h31, h32, true)
+ , m_13(h13), m_23(h23), m_33(h33)
, m_type(TxNone)
, m_dirty(TxProject)
{
-
}
/*!
@@ -273,12 +285,11 @@ QTransform::QTransform(qreal h11, qreal h12, qreal h13,
*/
QTransform::QTransform(qreal h11, qreal h12, qreal h21,
qreal h22, qreal dx, qreal dy)
- : affine(h11, h12, h21, h22, dx, dy),
- m_13(0), m_23(0), m_33(1)
+ : affine(h11, h12, h21, h22, dx, dy, true)
+ , m_13(0), m_23(0), m_33(1)
, m_type(TxNone)
, m_dirty(TxShear)
{
-
}
/*!
@@ -289,12 +300,11 @@ QTransform::QTransform(qreal h11, qreal h12, qreal h21,
and 1 respectively.
*/
QTransform::QTransform(const QMatrix &mtx)
- : affine(mtx),
+ : affine(mtx._m11, mtx._m12, mtx._m21, mtx._m22, mtx._dx, mtx._dy, true),
m_13(0), m_23(0), m_33(1)
, m_type(TxNone)
, m_dirty(TxShear)
{
-
}
/*!
@@ -317,7 +327,7 @@ QTransform QTransform::adjoint() const
return QTransform(h11, h12, h13,
h21, h22, h23,
- h31, h32, h33);
+ h31, h32, h33, true);
}
/*!
@@ -327,7 +337,7 @@ QTransform QTransform::transposed() const
{
QTransform t(affine._m11, affine._m21, affine._dx,
affine._m12, affine._m22, affine._dy,
- m_13, m_23, m_33);
+ m_13, m_23, m_33, true);
t.m_type = m_type;
t.m_dirty = m_dirty;
return t;
@@ -345,11 +355,10 @@ QTransform QTransform::transposed() const
*/
QTransform QTransform::inverted(bool *invertible) const
{
- QTransform invert;
+ QTransform invert(true);
bool inv = true;
- qreal det;
- switch(type()) {
+ switch(inline_type()) {
case TxNone:
break;
case TxTranslate:
@@ -357,11 +366,11 @@ QTransform QTransform::inverted(bool *invertible) const
invert.affine._dy = -affine._dy;
break;
case TxScale:
- inv = !qFuzzyCompare(affine._m11 + 1, 1);
- inv &= !qFuzzyCompare(affine._m22 + 1, 1);
+ inv = !qFuzzyIsNull(affine._m11);
+ inv &= !qFuzzyIsNull(affine._m22);
if (inv) {
- invert.affine._m11 = 1 / affine._m11;
- invert.affine._m22 = 1 / affine._m22;
+ invert.affine._m11 = 1. / affine._m11;
+ invert.affine._m22 = 1. / affine._m22;
invert.affine._dx = -affine._dx * invert.affine._m11;
invert.affine._dy = -affine._dy * invert.affine._m22;
}
@@ -372,8 +381,8 @@ QTransform QTransform::inverted(bool *invertible) const
break;
default:
// general case
- det = determinant();
- inv = !qFuzzyCompare(det + 1, 1);
+ qreal det = determinant();
+ inv = !qFuzzyIsNull(det);
if (inv)
invert = adjoint() / det;
break;
@@ -397,12 +406,12 @@ QTransform QTransform::inverted(bool *invertible) const
\sa setMatrix()
*/
-QTransform & QTransform::translate(qreal dx, qreal dy)
+QTransform &QTransform::translate(qreal dx, qreal dy)
{
if (dx == 0 && dy == 0)
return *this;
- switch(type()) {
+ switch(inline_type()) {
case TxNone:
affine._dx = dx;
affine._dy = dy;
@@ -424,7 +433,8 @@ QTransform & QTransform::translate(qreal dx, qreal dy)
affine._dy += dy*affine._m22 + dx*affine._m12;
break;
}
- m_dirty |= TxTranslate;
+ if (m_dirty < TxTranslate)
+ m_dirty = TxTranslate;
return *this;
}
@@ -437,11 +447,12 @@ QTransform & QTransform::translate(qreal dx, qreal dy)
*/
QTransform QTransform::fromTranslate(qreal dx, qreal dy)
{
- QTransform transform(1, 0, 0, 1, dx, dy);
+ QTransform transform(1, 0, 0, 0, 1, 0, dx, dy, 1, true);
if (dx == 0 && dy == 0)
- transform.m_dirty = TxNone;
+ transform.m_type = TxNone;
else
- transform.m_dirty = TxTranslate;
+ transform.m_type = TxTranslate;
+ transform.m_dirty = TxNone;
return transform;
}
@@ -456,7 +467,7 @@ QTransform & QTransform::scale(qreal sx, qreal sy)
if (sx == 1 && sy == 1)
return *this;
- switch(type()) {
+ switch(inline_type()) {
case TxNone:
case TxTranslate:
affine._m11 = sx;
@@ -476,7 +487,8 @@ QTransform & QTransform::scale(qreal sx, qreal sy)
affine._m22 *= sy;
break;
}
- m_dirty |= TxScale;
+ if (m_dirty < TxScale)
+ m_dirty = TxScale;
return *this;
}
@@ -489,11 +501,12 @@ QTransform & QTransform::scale(qreal sx, qreal sy)
*/
QTransform QTransform::fromScale(qreal sx, qreal sy)
{
- QTransform transform(sx, 0, 0, sy, 0, 0);
- if (sx == 1 && sy == 1)
- transform.m_dirty = TxNone;
+ QTransform transform(sx, 0, 0, 0, sy, 0, 0, 0, 1, true);
+ if (sx == 1. && sy == 1.)
+ transform.m_type = TxNone;
else
- transform.m_dirty = TxScale;
+ transform.m_type = TxScale;
+ transform.m_dirty = TxNone;
return transform;
}
@@ -505,7 +518,10 @@ QTransform QTransform::fromScale(qreal sx, qreal sy)
*/
QTransform & QTransform::shear(qreal sh, qreal sv)
{
- switch(type()) {
+ if (sh == 0 && sv == 0)
+ return *this;
+
+ switch(inline_type()) {
case TxNone:
case TxTranslate:
affine._m12 = sv;
@@ -533,7 +549,8 @@ QTransform & QTransform::shear(qreal sh, qreal sv)
break;
}
}
- m_dirty |= TxShear;
+ if (m_dirty < TxShear)
+ m_dirty = TxShear;
return *this;
}
@@ -574,7 +591,7 @@ QTransform & QTransform::rotate(qreal a, Qt::Axis axis)
}
if (axis == Qt::ZAxis) {
- switch(type()) {
+ switch(inline_type()) {
case TxNone:
case TxTranslate:
affine._m11 = cosa;
@@ -609,7 +626,8 @@ QTransform & QTransform::rotate(qreal a, Qt::Axis axis)
break;
}
}
- m_dirty |= TxRotate;
+ if (m_dirty < TxRotate)
+ m_dirty = TxRotate;
} else {
QTransform result;
if (axis == Qt::YAxis) {
@@ -646,7 +664,7 @@ QTransform & QTransform::rotateRadians(qreal a, Qt::Axis axis)
qreal cosa = qCos(a);
if (axis == Qt::ZAxis) {
- switch(type()) {
+ switch(inline_type()) {
case TxNone:
case TxTranslate:
affine._m11 = cosa;
@@ -681,7 +699,8 @@ QTransform & QTransform::rotateRadians(qreal a, Qt::Axis axis)
break;
}
}
- m_dirty |= TxRotate;
+ if (m_dirty < TxRotate)
+ m_dirty = TxRotate;
} else {
QTransform result;
if (axis == Qt::YAxis) {
@@ -704,11 +723,15 @@ QTransform & QTransform::rotateRadians(qreal a, Qt::Axis axis)
*/
bool QTransform::operator==(const QTransform &o) const
{
-#define qFZ qFuzzyCompare
- return qFZ(affine._m11, o.affine._m11) && qFZ(affine._m12, o.affine._m12) && qFZ(m_13, o.m_13)
- && qFZ(affine._m21, o.affine._m21) && qFZ(affine._m22, o.affine._m22) && qFZ(m_23, o.m_23)
- && qFZ(affine._dx, o.affine._dx) && qFZ(affine._dy, o.affine._dy) && qFZ(m_33, o.m_33);
-#undef qFZ
+ return affine._m11 == o.affine._m11 &&
+ affine._m12 == o.affine._m12 &&
+ affine._m21 == o.affine._m21 &&
+ affine._m22 == o.affine._m22 &&
+ affine._dx == o.affine._dx &&
+ affine._dy == o.affine._dy &&
+ m_13 == o.m_13 &&
+ m_23 == o.m_23 &&
+ m_33 == o.m_33;
}
/*!
@@ -730,11 +753,11 @@ bool QTransform::operator!=(const QTransform &o) const
*/
QTransform & QTransform::operator*=(const QTransform &o)
{
- const TransformationType otherType = o.type();
+ const TransformationType otherType = o.inline_type();
if (otherType == TxNone)
return *this;
- const TransformationType thisType = type();
+ const TransformationType thisType = inline_type();
if (thisType == TxNone)
return operator=(o);
@@ -812,9 +835,77 @@ QTransform & QTransform::operator*=(const QTransform &o)
*/
QTransform QTransform::operator*(const QTransform &m) const
{
- QTransform result = *this;
- result *= m;
- return result;
+ const TransformationType otherType = m.inline_type();
+ if (otherType == TxNone)
+ return *this;
+
+ const TransformationType thisType = inline_type();
+ if (thisType == TxNone)
+ return m;
+
+ QTransform t(true);
+ TransformationType type = qMax(thisType, otherType);
+ switch(type) {
+ case TxNone:
+ break;
+ case TxTranslate:
+ t.affine._dx = affine._dx + m.affine._dx;
+ t.affine._dy += affine._dy + m.affine._dy;
+ break;
+ case TxScale:
+ {
+ qreal m11 = affine._m11*m.affine._m11;
+ qreal m22 = affine._m22*m.affine._m22;
+
+ qreal m31 = affine._dx*m.affine._m11 + m.affine._dx;
+ qreal m32 = affine._dy*m.affine._m22 + m.affine._dy;
+
+ t.affine._m11 = m11;
+ t.affine._m22 = m22;
+ t.affine._dx = m31; t.affine._dy = m32;
+ break;
+ }
+ case TxRotate:
+ case TxShear:
+ {
+ qreal m11 = affine._m11*m.affine._m11 + affine._m12*m.affine._m21;
+ qreal m12 = affine._m11*m.affine._m12 + affine._m12*m.affine._m22;
+
+ qreal m21 = affine._m21*m.affine._m11 + affine._m22*m.affine._m21;
+ qreal m22 = affine._m21*m.affine._m12 + affine._m22*m.affine._m22;
+
+ qreal m31 = affine._dx*m.affine._m11 + affine._dy*m.affine._m21 + m.affine._dx;
+ qreal m32 = affine._dx*m.affine._m12 + affine._dy*m.affine._m22 + m.affine._dy;
+
+ t.affine._m11 = m11; t.affine._m12 = m12;
+ t.affine._m21 = m21; t.affine._m22 = m22;
+ t.affine._dx = m31; t.affine._dy = m32;
+ break;
+ }
+ case TxProject:
+ {
+ qreal m11 = affine._m11*m.affine._m11 + affine._m12*m.affine._m21 + m_13*m.affine._dx;
+ qreal m12 = affine._m11*m.affine._m12 + affine._m12*m.affine._m22 + m_13*m.affine._dy;
+ qreal m13 = affine._m11*m.m_13 + affine._m12*m.m_23 + m_13*m.m_33;
+
+ qreal m21 = affine._m21*m.affine._m11 + affine._m22*m.affine._m21 + m_23*m.affine._dx;
+ qreal m22 = affine._m21*m.affine._m12 + affine._m22*m.affine._m22 + m_23*m.affine._dy;
+ qreal m23 = affine._m21*m.m_13 + affine._m22*m.m_23 + m_23*m.m_33;
+
+ qreal m31 = affine._dx*m.affine._m11 + affine._dy*m.affine._m21 + m_33*m.affine._dx;
+ qreal m32 = affine._dx*m.affine._m12 + affine._dy*m.affine._m22 + m_33*m.affine._dy;
+ qreal m33 = affine._dx*m.m_13 + affine._dy*m.m_23 + m_33*m.m_33;
+
+ t.affine._m11 = m11; t.affine._m12 = m12; t.m_13 = m13;
+ t.affine._m21 = m21; t.affine._m22 = m22; t.m_23 = m23;
+ t.affine._dx = m31; t.affine._dy = m32; t.m_33 = m33;
+ }
+ }
+
+ t.m_dirty = type;
+ t.m_type = type;
+
+ return t;
}
/*!
@@ -871,8 +962,8 @@ QTransform & QTransform::operator=(const QTransform &matrix)
/*!
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.
+ to zero, except \c m11 and \c m22 (specifying the scale) and \c m33
+ which are set to 1.
\sa QTransform(), isIdentity(), {QTransform#Basic Matrix
Operations}{Basic Matrix Operations}
@@ -956,7 +1047,7 @@ QDebug operator<<(QDebug dbg, const QTransform &m)
<< " 31=" << m.m31()
<< " 32=" << m.m32()
<< " 33=" << m.m33()
- << ")";
+ << ')';
return dbg.space();
}
#endif
@@ -976,7 +1067,7 @@ QPoint QTransform::map(const QPoint &p) const
qreal x = 0, y = 0;
- TransformationType t = type();
+ TransformationType t = inline_type();
switch(t) {
case TxNone:
x = fx;
@@ -1027,7 +1118,7 @@ QPointF QTransform::map(const QPointF &p) const
qreal x = 0, y = 0;
- TransformationType t = type();
+ TransformationType t = inline_type();
switch(t) {
case TxNone:
x = fx;
@@ -1098,7 +1189,7 @@ QLine QTransform::map(const QLine &l) const
qreal x1 = 0, y1 = 0, x2 = 0, y2 = 0;
- TransformationType t = type();
+ TransformationType t = inline_type();
switch(t) {
case TxNone:
x1 = fx1;
@@ -1157,7 +1248,7 @@ QLineF QTransform::map(const QLineF &l) const
qreal x1 = 0, y1 = 0, x2 = 0, y2 = 0;
- TransformationType t = type();
+ TransformationType t = inline_type();
switch(t) {
case TxNone:
x1 = fx1;
@@ -1245,7 +1336,10 @@ static QPolygonF mapProjective(const QTransform &transform, const QPolygonF &pol
*/
QPolygonF QTransform::map(const QPolygonF &a) const
{
- TransformationType t = type();
+ TransformationType t = inline_type();
+ if (t <= TxTranslate)
+ return a.translated(affine._dx, affine._dy);
+
if (t >= QTransform::TxProject)
return mapProjective(*this, a);
@@ -1272,7 +1366,10 @@ QPolygonF QTransform::map(const QPolygonF &a) const
*/
QPolygon QTransform::map(const QPolygon &a) const
{
- TransformationType t = type();
+ TransformationType t = inline_type();
+ if (t <= TxTranslate)
+ return a.translated(qRound(affine._dx), qRound(affine._dy));
+
if (t >= QTransform::TxProject)
return mapProjective(*this, QPolygonF(a)).toPolygon();
@@ -1314,7 +1411,7 @@ extern QPainterPath qt_regionToPath(const QRegion &region);
*/
QRegion QTransform::map(const QRegion &r) const
{
- TransformationType t = type();
+ TransformationType t = inline_type();
if (t == TxNone)
return r;
@@ -1341,7 +1438,7 @@ struct QHomogeneousCoordinate
QHomogeneousCoordinate(qreal x_, qreal y_, qreal w_) : x(x_), y(y_), w(w_) {}
const QPointF toPoint() const {
- qreal iw = 1 / w;
+ qreal iw = 1. / w;
return QPointF(x * iw, y * iw);
}
};
@@ -1397,27 +1494,12 @@ static inline bool lineTo_clipped(QPainterPath &path, const QTransform &transfor
static inline bool cubicTo_clipped(QPainterPath &path, const QTransform &transform, const QPointF &a, const QPointF &b, const QPointF &c, const QPointF &d, bool needsMoveTo)
{
- const QHomogeneousCoordinate ha = mapHomogeneous(transform, a);
- const QHomogeneousCoordinate hb = mapHomogeneous(transform, b);
- const QHomogeneousCoordinate hc = mapHomogeneous(transform, c);
- const QHomogeneousCoordinate hd = mapHomogeneous(transform, d);
-
- if (ha.w < Q_NEAR_CLIP && hb.w < Q_NEAR_CLIP && hc.w < Q_NEAR_CLIP && hd.w < Q_NEAR_CLIP)
- return false;
-
- if (ha.w >= Q_NEAR_CLIP && hb.w >= Q_NEAR_CLIP && hc.w >= Q_NEAR_CLIP && hd.w >= Q_NEAR_CLIP) {
- if (needsMoveTo)
- path.moveTo(ha.toPoint());
+ // Convert projective xformed curves to line
+ // segments so they can be transformed more accurately
+ QPolygonF segment = QBezier::fromPoints(a, b, c, d).toPolygon();
- path.cubicTo(hb.toPoint(), hc.toPoint(), hd.toPoint());
- return true;
- }
-
- if (lineTo_clipped(path, transform, a, b, needsMoveTo))
- needsMoveTo = false;
- if (lineTo_clipped(path, transform, b, c, needsMoveTo))
- needsMoveTo = false;
- if (lineTo_clipped(path, transform, c, d, needsMoveTo))
+ for (int i = 0; i < segment.size() - 1; ++i)
+ if (lineTo_clipped(path, transform, segment.at(i), segment.at(i+1), needsMoveTo))
needsMoveTo = false;
return !needsMoveTo;
@@ -1482,7 +1564,7 @@ static QPainterPath mapProjective(const QTransform &transform, const QPainterPat
*/
QPainterPath QTransform::map(const QPainterPath &path) const
{
- TransformationType t = type();
+ TransformationType t = inline_type();
if (t == TxNone || path.isEmpty())
return path;
@@ -1490,15 +1572,11 @@ QPainterPath QTransform::map(const QPainterPath &path) const
return mapProjective(*this, path);
QPainterPath copy = path;
- copy.detach();
if (t == TxTranslate) {
- for (int i=0; i<path.elementCount(); ++i) {
- QPainterPath::Element &e = copy.d_ptr->elements[i];
- e.x += affine._dx;
- e.y += affine._dy;
- }
+ copy.translate(affine._dx, affine._dy);
} else {
+ copy.detach();
// Full xform
for (int i=0; i<path.elementCount(); ++i) {
QPainterPath::Element &e = copy.d_ptr->elements[i];
@@ -1531,7 +1609,7 @@ QPainterPath QTransform::map(const QPainterPath &path) const
*/
QPolygon QTransform::mapToPolygon(const QRect &rect) const
{
- TransformationType t = type();
+ TransformationType t = inline_type();
QPolygon a(4);
qreal x[4] = { 0, 0, 0, 0 }, y[4] = { 0, 0, 0, 0 };
@@ -1685,7 +1763,7 @@ bool QTransform::quadToQuad(const QPolygonF &one,
Sets the matrix elements to the specified values, \a m11,
\a m12, \a m13 \a m21, \a m22, \a m23 \a m31, \a m32 and
\a m33. Note that this function replaces the previous values.
- QMatrix provides the translate(), rotate(), scale() and shear()
+ QTransform provides the translate(), rotate(), scale() and shear()
convenience functions to manipulate the various matrix elements
based on the currently defined coordinate system.
@@ -1703,9 +1781,20 @@ void QTransform::setMatrix(qreal m11, qreal m12, qreal m13,
m_dirty = TxProject;
}
+static inline bool needsPerspectiveClipping(const QRectF &rect, const QTransform &transform)
+{
+ const qreal wx = qMin(transform.m13() * rect.left(), transform.m13() * rect.right());
+ const qreal wy = qMin(transform.m23() * rect.top(), transform.m23() * rect.bottom());
+
+ return wx + wy + transform.m33() < Q_NEAR_CLIP;
+}
+
QRect QTransform::mapRect(const QRect &rect) const
{
- TransformationType t = type();
+ TransformationType t = inline_type();
+ if (t <= TxTranslate)
+ return rect.translated(qRound(affine._dx), qRound(affine._dy));
+
if (t <= TxScale) {
int x = qRound(affine._m11*rect.x() + affine._dx);
int y = qRound(affine._m22*rect.y() + affine._dy);
@@ -1720,7 +1809,7 @@ QRect QTransform::mapRect(const QRect &rect) const
y -= h;
}
return QRect(x, y, w, h);
- } else if (t < TxProject) {
+ } else if (t < TxProject || !needsPerspectiveClipping(rect, *this)) {
// see mapToPolygon for explanations of the algorithm.
qreal x = 0, y = 0;
MAP(rect.left(), rect.top(), x, y);
@@ -1772,7 +1861,10 @@ QRect QTransform::mapRect(const QRect &rect) const
*/
QRectF QTransform::mapRect(const QRectF &rect) const
{
- TransformationType t = type();
+ TransformationType t = inline_type();
+ if (t <= TxTranslate)
+ return rect.translated(affine._dx, affine._dy);
+
if (t <= TxScale) {
qreal x = affine._m11*rect.x() + affine._dx;
qreal y = affine._m22*rect.y() + affine._dy;
@@ -1787,7 +1879,7 @@ QRectF QTransform::mapRect(const QRectF &rect) const
y -= h;
}
return QRectF(x, y, w, h);
- } else if (t < TxProject) {
+ } else if (t < TxProject || !needsPerspectiveClipping(rect, *this)) {
qreal x = 0, y = 0;
MAP(rect.x(), rect.y(), x, y);
qreal xmin = x;
@@ -1843,7 +1935,7 @@ QRectF QTransform::mapRect(const QRectF &rect) const
*/
void QTransform::map(qreal x, qreal y, qreal *tx, qreal *ty) const
{
- TransformationType t = type();
+ TransformationType t = inline_type();
MAP(x, y, *tx, *ty);
}
@@ -1857,7 +1949,7 @@ void QTransform::map(qreal x, qreal y, qreal *tx, qreal *ty) const
*/
void QTransform::map(int x, int y, int *tx, int *ty) const
{
- TransformationType t = type();
+ TransformationType t = inline_type();
qreal fx = 0, fy = 0;
MAP(x, y, fx, fy);
*tx = qRound(fx);
@@ -1865,8 +1957,11 @@ void QTransform::map(int x, int y, int *tx, int *ty) const
}
/*!
- Returns the QTransform cast to a QMatrix.
- */
+ Returns the QTransform as an affine matrix.
+
+ \warning If a perspective transformation has been specified,
+ then the conversion will cause loss of data.
+*/
const QMatrix &QTransform::toAffine() const
{
return affine;
@@ -1886,25 +1981,41 @@ const QMatrix &QTransform::toAffine() const
*/
QTransform::TransformationType QTransform::type() const
{
- if (m_dirty >= m_type) {
- if (m_dirty > TxShear && (!qFuzzyCompare(m_13 + 1, 1) || !qFuzzyCompare(m_23 + 1, 1) || !qFuzzyCompare(m_33, 1)))
+ if(m_dirty == TxNone || m_dirty < m_type)
+ return static_cast<TransformationType>(m_type);
+
+ switch (static_cast<TransformationType>(m_dirty)) {
+ case TxProject:
+ if (!qFuzzyIsNull(m_13) || !qFuzzyIsNull(m_23) || !qFuzzyIsNull(m_33 - 1)) {
m_type = TxProject;
- else if (m_dirty > TxScale && (!qFuzzyCompare(affine._m12 + 1, 1) || !qFuzzyCompare(affine._m21 + 1, 1))) {
+ break;
+ }
+ case TxShear:
+ case TxRotate:
+ if (!qFuzzyIsNull(affine._m12) || !qFuzzyIsNull(affine._m21)) {
const qreal dot = affine._m11 * affine._m12 + affine._m21 * affine._m22;
- if (qFuzzyCompare(dot + 1, 1))
+ if (qFuzzyIsNull(dot))
m_type = TxRotate;
else
m_type = TxShear;
- } else if (m_dirty > TxTranslate && (!qFuzzyCompare(affine._m11, 1) || !qFuzzyCompare(affine._m22, 1)))
+ break;
+ }
+ case TxScale:
+ if (!qFuzzyIsNull(affine._m11 - 1) || !qFuzzyIsNull(affine._m22 - 1)) {
m_type = TxScale;
- else if (m_dirty > TxNone && (!qFuzzyCompare(affine._dx + 1, 1) || !qFuzzyCompare(affine._dy + 1, 1)))
+ break;
+ }
+ case TxTranslate:
+ if (!qFuzzyIsNull(affine._dx) || !qFuzzyIsNull(affine._dy)) {
m_type = TxTranslate;
- else
- m_type = TxNone;
-
- m_dirty = TxNone;
+ break;
+ }
+ case TxNone:
+ m_type = TxNone;
+ break;
}
+ m_dirty = TxNone;
return static_cast<TransformationType>(m_type);
}
@@ -1928,8 +2039,9 @@ QTransform::operator QVariant() const
/*!
\fn qreal QTransform::det() const
+ \obsolete
- Returns the matrix's determinant.
+ Returns the matrix's determinant. Use determinant() instead.
*/
@@ -2083,6 +2195,17 @@ QTransform::operator QVariant() const
\sa reset()
*/
+/*!
+ \fn bool qFuzzyCompare(const QTransform& t1, const QTransform& t2)
+
+ \relates QTransform
+ \since 4.6
+
+ Returns true if \a t1 and \a t2 are equal, allowing for a small
+ fuzziness factor for floating-point comparisons; false otherwise.
+*/
+
+
// returns true if the transform is uniformly scaling
// (same scale in x and y direction)
// scale is set to the max of x and y scaling factors