diff options
author | Rhys Weatherley <rhys.weatherley@nokia.com> | 2009-08-19 03:25:38 (GMT) |
---|---|---|
committer | Rhys Weatherley <rhys.weatherley@nokia.com> | 2009-08-19 03:25:38 (GMT) |
commit | 9e8ff32da0eeaa9dfe03b5ffc123bd6390951494 (patch) | |
tree | 0106b57e45688f273aaed07b761876684a3b4a23 /tests/auto | |
parent | f7af55e67711270286a1addf6a28399982647a62 (diff) | |
download | Qt-9e8ff32da0eeaa9dfe03b5ffc123bd6390951494.zip Qt-9e8ff32da0eeaa9dfe03b5ffc123bd6390951494.tar.gz Qt-9e8ff32da0eeaa9dfe03b5ffc123bd6390951494.tar.bz2 |
Re-implement QGraphicsTransform to use QMatrix4x4
QTransform-based transformations create problems when performing
X and Y axis rotations because they aren't using true 3D. This
change modifies QGraphicsTransform and its sub-classes to use
QMatrix4x4 as the standard transformation matrix, with a project()
function to project back to 2D when required.
Reviewed-by: trustme
Diffstat (limited to 'tests/auto')
-rw-r--r-- | tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp | 141 |
1 files changed, 109 insertions, 32 deletions
diff --git a/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp b/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp index bfd346b..029c182 100644 --- a/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp +++ b/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp @@ -84,60 +84,131 @@ void tst_QGraphicsTransform::cleanup() { } +static QTransform transform2D(const QGraphicsTransform& t) +{ + QMatrix4x4 m; + t.applyTo(&m); + return QGraphicsTransform::project(m); +} void tst_QGraphicsTransform::scale() { QGraphicsScale scale; - scale.setOrigin(QPointF(10, 10)); - QTransform t; + // check initial conditions + QCOMPARE(scale.xScale(), qreal(1)); + QCOMPARE(scale.yScale(), qreal(1)); + QCOMPARE(scale.zScale(), qreal(1)); + QCOMPARE(scale.origin(), QVector3D(0, 0, 0)); + + scale.setOrigin(QVector3D(10, 10, 0)); + + QCOMPARE(scale.xScale(), qreal(1)); + QCOMPARE(scale.yScale(), qreal(1)); + QCOMPARE(scale.zScale(), qreal(1)); + QCOMPARE(scale.origin(), QVector3D(10, 10, 0)); + + QMatrix4x4 t; scale.applyTo(&t); - QCOMPARE(t, QTransform()); - QCOMPARE(scale.transform(), QTransform()); + QCOMPARE(t, QMatrix4x4()); + QCOMPARE(transform2D(scale), QTransform()); scale.setXScale(10); - scale.setOrigin(QPointF(0, 0)); + scale.setOrigin(QVector3D(0, 0, 0)); + + QCOMPARE(scale.xScale(), qreal(10)); + QCOMPARE(scale.yScale(), qreal(1)); + QCOMPARE(scale.zScale(), qreal(1)); + QCOMPARE(scale.origin(), QVector3D(0, 0, 0)); QTransform res; res.scale(10, 1); - QCOMPARE(scale.transform(), res); - QCOMPARE(scale.transform().map(QPointF(10, 10)), QPointF(100, 10)); + QCOMPARE(transform2D(scale), res); + QCOMPARE(transform2D(scale).map(QPointF(10, 10)), QPointF(100, 10)); + + scale.setOrigin(QVector3D(10, 10, 0)); + QCOMPARE(transform2D(scale).map(QPointF(10, 10)), QPointF(10, 10)); + QCOMPARE(transform2D(scale).map(QPointF(11, 10)), QPointF(20, 10)); + + scale.setYScale(2); + scale.setZScale(4.5); + scale.setOrigin(QVector3D(1, 2, 3)); + + QCOMPARE(scale.xScale(), qreal(10)); + QCOMPARE(scale.yScale(), qreal(2)); + QCOMPARE(scale.zScale(), qreal(4.5)); + QCOMPARE(scale.origin(), QVector3D(1, 2, 3)); + + QMatrix4x4 t2; + scale.applyTo(&t2); - scale.setOrigin(QPointF(10, 10)); - QCOMPARE(scale.transform().map(QPointF(10, 10)), QPointF(10, 10)); - QCOMPARE(scale.transform().map(QPointF(11, 10)), QPointF(20, 10)); + QCOMPARE(t2.map(QVector3D(4, 5, 6)), QVector3D(31, 8, 16.5)); + + // Because the origin has a non-zero z, mapping (4, 5) in 2D + // will introduce a projective component into the result. + QTransform t3 = QGraphicsTransform::project(t2); + QCOMPARE(t3.map(QPointF(4, 5)), QPointF(31 / t3.m33(), 8 / t3.m33())); +} + +// QMatrix4x4 uses float internally, whereas QTransform uses qreal. +// This can lead to issues with qFuzzyCompare() where it uses double +// precision to compare values that have no more than float precision +// after conversion from QMatrix4x4 to QTransform. The following +// definitions correct for the difference. +static inline bool fuzzyCompare(qreal p1, qreal p2) +{ + return (qAbs(p1 - p2) <= 0.00001f * qMin(qAbs(p1), qAbs(p2))); +} +static bool fuzzyCompare(const QTransform& t1, const QTransform& t2) +{ + return fuzzyCompare(t1.m11(), t2.m11()) && + fuzzyCompare(t1.m12(), t2.m12()) && + fuzzyCompare(t1.m13(), t2.m13()) && + fuzzyCompare(t1.m21(), t2.m21()) && + fuzzyCompare(t1.m22(), t2.m22()) && + fuzzyCompare(t1.m23(), t2.m23()) && + fuzzyCompare(t1.m31(), t2.m31()) && + fuzzyCompare(t1.m32(), t2.m32()) && + fuzzyCompare(t1.m33(), t2.m33()); } void tst_QGraphicsTransform::rotation() { QGraphicsRotation rotation; - QCOMPARE(rotation.axis().x(), (qreal)0); - QCOMPARE(rotation.axis().y(), (qreal)0); - QCOMPARE(rotation.axis().z(), (qreal)1); + QCOMPARE(rotation.axis(), QVector3D(0, 0, 1)); + QCOMPARE(rotation.origin(), QVector3D(0, 0, 0)); QCOMPARE(rotation.angle(), (qreal)0); - rotation.setOrigin(QPointF(10, 10)); + rotation.setOrigin(QVector3D(10, 10, 0)); + + QCOMPARE(rotation.axis(), QVector3D(0, 0, 1)); + QCOMPARE(rotation.origin(), QVector3D(10, 10, 0)); + QCOMPARE(rotation.angle(), (qreal)0); - QTransform t; + QMatrix4x4 t; rotation.applyTo(&t); - QCOMPARE(t, QTransform()); - QCOMPARE(rotation.transform(), QTransform()); + QCOMPARE(t, QMatrix4x4()); + QCOMPARE(transform2D(rotation), QTransform()); rotation.setAngle(40); - rotation.setOrigin(QPointF(0, 0)); + rotation.setOrigin(QVector3D(0, 0, 0)); + + QCOMPARE(rotation.axis(), QVector3D(0, 0, 1)); + QCOMPARE(rotation.origin(), QVector3D(0, 0, 0)); + QCOMPARE(rotation.angle(), (qreal)40); QTransform res; res.rotate(40); - QCOMPARE(rotation.transform(), res); + QVERIFY(fuzzyCompare(transform2D(rotation), res)); - rotation.setOrigin(QPointF(10, 10)); + rotation.setOrigin(QVector3D(10, 10, 0)); rotation.setAngle(90); - QCOMPARE(rotation.transform().map(QPointF(10, 10)), QPointF(10, 10)); - QCOMPARE(rotation.transform().map(QPointF(20, 10)), QPointF(10, 20)); + QCOMPARE(transform2D(rotation).map(QPointF(10, 10)), QPointF(10, 10)); + QCOMPARE(transform2D(rotation).map(QPointF(20, 10)), QPointF(10, 20)); } Q_DECLARE_METATYPE(Qt::Axis); @@ -161,38 +232,44 @@ void tst_QGraphicsTransform::rotation3d() QGraphicsRotation rotation; rotation.setAxis(axis); - QTransform t; + QMatrix4x4 t; rotation.applyTo(&t); QVERIFY(t.isIdentity()); - QVERIFY(rotation.transform().isIdentity()); + QVERIFY(transform2D(rotation).isIdentity()); rotation.setAngle(angle); + // QGraphicsRotation uses a correct mathematical rotation in 3D. + // QTransform's Qt::YAxis rotation is inverted from the mathematical + // version of rotation. We correct for that here. QTransform expected; - expected.rotate(angle, axis); + if (axis == Qt::YAxis && angle != 180.) + expected.rotate(-angle, axis); + else + expected.rotate(angle, axis); - QVERIFY(qFuzzyCompare(rotation.transform(), expected)); + QVERIFY(fuzzyCompare(transform2D(rotation), expected)); //now let's check that a null vector will not change the transform rotation.setAxis(QVector3D(0, 0, 0)); - rotation.setOrigin(QPointF(10, 10)); + rotation.setOrigin(QVector3D(10, 10, 0)); - t.reset(); + t.setIdentity(); rotation.applyTo(&t); QVERIFY(t.isIdentity()); - QVERIFY(rotation.transform().isIdentity()); + QVERIFY(transform2D(rotation).isIdentity()); rotation.setAngle(angle); QVERIFY(t.isIdentity()); - QVERIFY(rotation.transform().isIdentity()); + QVERIFY(transform2D(rotation).isIdentity()); - rotation.setOrigin(QPointF(0, 0)); + rotation.setOrigin(QVector3D(0, 0, 0)); QVERIFY(t.isIdentity()); - QVERIFY(rotation.transform().isIdentity()); + QVERIFY(transform2D(rotation).isIdentity()); } |