summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--demos/sub-attaq/submarine.cpp2
-rw-r--r--demos/sub-attaq/submarine.h4
-rw-r--r--demos/sub-attaq/submarine_p.h5
-rw-r--r--src/gui/graphicsview/qgraphicstransform.cpp182
-rw-r--r--src/gui/graphicsview/qgraphicstransform.h31
-rw-r--r--tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp59
6 files changed, 138 insertions, 145 deletions
diff --git a/demos/sub-attaq/submarine.cpp b/demos/sub-attaq/submarine.cpp
index 857b009..383005d 100644
--- a/demos/sub-attaq/submarine.cpp
+++ b/demos/sub-attaq/submarine.cpp
@@ -111,7 +111,7 @@ SubMarine::SubMarine(int type, const QString &name, int points, QGraphicsItem *
resize(pixmapItem->boundingRect().width(),pixmapItem->boundingRect().height());
setTransformOriginPoint(boundingRect().center());
- graphicsRotation = new QGraphicsRotation3D(this);
+ graphicsRotation = new QGraphicsRotation(this);
graphicsRotation->setAxis(QVector3D(0, 1, 0));
graphicsRotation->setOrigin(QPointF(size().width()/2, size().height()/2));
QList<QGraphicsTransform *> r;
diff --git a/demos/sub-attaq/submarine.h b/demos/sub-attaq/submarine.h
index 0e4d074..1e33ba0 100644
--- a/demos/sub-attaq/submarine.h
+++ b/demos/sub-attaq/submarine.h
@@ -76,7 +76,7 @@ public:
virtual int type() const;
- QGraphicsRotation3D *rotation3d() const { return graphicsRotation; }
+ QGraphicsRotation *rotation() const { return graphicsRotation; }
signals:
void subMarineDestroyed();
@@ -90,7 +90,7 @@ private:
int speed;
Movement direction;
PixmapItem *pixmapItem;
- QGraphicsRotation3D *graphicsRotation;
+ QGraphicsRotation *graphicsRotation;
};
#endif //__SUBMARINE__H__
diff --git a/demos/sub-attaq/submarine_p.h b/demos/sub-attaq/submarine_p.h
index 1af820f..520fe2f 100644
--- a/demos/sub-attaq/submarine_p.h
+++ b/demos/sub-attaq/submarine_p.h
@@ -109,7 +109,8 @@ class ReturnState : public QAnimationState
public:
ReturnState(SubMarine *submarine, QState *parent = 0) : QAnimationState(parent)
{
- returnAnimation = new QPropertyAnimation(submarine->rotation3d(), "angle");
+ returnAnimation = new QPropertyAnimation(submarine->rotation(), "angle");
+ returnAnimation->setDuration(500);
AnimationManager::self()->registerAnimation(returnAnimation);
setAnimation(returnAnimation);
this->submarine = submarine;
@@ -119,9 +120,7 @@ protected:
void onEntry(QEvent *e)
{
returnAnimation->stop();
- returnAnimation->setStartValue(submarine->rotation3d()->angle());
returnAnimation->setEndValue(submarine->currentDirection() == SubMarine::Right ? 360. : 180.);
- returnAnimation->setDuration(500);
QAnimationState::onEntry(e);
}
diff --git a/src/gui/graphicsview/qgraphicstransform.cpp b/src/gui/graphicsview/qgraphicstransform.cpp
index 8f04850..95f137d 100644
--- a/src/gui/graphicsview/qgraphicstransform.cpp
+++ b/src/gui/graphicsview/qgraphicstransform.cpp
@@ -73,7 +73,7 @@
QGraphicsTransform can be used together with QGraphicsItem::setTransform(),
QGraphicsItem::setRotation(), and QGraphicsItem::setScale().
- \sa QGraphicsItem::transform(), QGraphicsScale, QGraphicsRotation, QGraphicsRotation3D
+ \sa QGraphicsItem::transform(), QGraphicsScale, QGraphicsRotation
*/
#include "qgraphicstransform.h"
@@ -326,9 +326,17 @@ void QGraphicsScale::applyTo(QTransform *transform) const
/*!
\class QGraphicsRotation
- \brief The QGraphicsRotation class provides a rotation transformation.
+ \brief The QGraphicsRotation class provides a rotation transformation around
+ a given axis.
\since 4.6
+ You can provide the desired axis by assigning a QVector3D to the axis property
+ or by passing a member if Qt::Axis to the setAxis convenience function.
+ By default the axis is (0, 0, 1) i.e., rotation around the Z axis.
+
+ The angle property, which is provided by QGraphicsRotation, now
+ describes the number of degrees to rotate around this axis.
+
QGraphicsRotation provides certain parameters to help control how the
rotation should be applied.
@@ -342,16 +350,28 @@ void QGraphicsScale::applyTo(QTransform *transform) const
provide rotation angles exceeding (-360, 360) degrees, for instance to
animate how an item rotates several times.
+ Note: the final rotation is the combined effect of a rotation in
+ 3D space followed by a projection back to 2D. If several rotations
+ are performed in succession, they will not behave as expected unless
+ they were all around the Z axis.
+
\sa QGraphicsTransform, QGraphicsItem::setRotation(), QTransform::rotate()
*/
+#define VECTOR_FOR_AXIS_X QVector3D(1, 0, 0)
+#define VECTOR_FOR_AXIS_Y QVector3D(0, 1, 0)
+#define VECTOR_FOR_AXIS_Z QVector3D(0, 0, 1)
+
+
class QGraphicsRotationPrivate : public QGraphicsTransformPrivate
{
public:
QGraphicsRotationPrivate()
- : angle(0) {}
+ : angle(0), axis(VECTOR_FOR_AXIS_Z), simpleAxis(Qt::ZAxis) {}
QPointF origin;
qreal angle;
+ QVector3D axis;
+ int simpleAxis;
};
/*!
@@ -363,14 +383,6 @@ QGraphicsRotation::QGraphicsRotation(QObject *parent)
}
/*!
- \internal
-*/
-QGraphicsRotation::QGraphicsRotation(QGraphicsRotationPrivate &p, QObject *parent)
- : QGraphicsTransform(p, parent)
-{
-}
-
-/*!
Destroys the graphics rotation.
*/
QGraphicsRotation::~QGraphicsRotation()
@@ -427,19 +439,6 @@ void QGraphicsRotation::setAngle(qreal angle)
}
/*!
- \reimp
-*/
-void QGraphicsRotation::applyTo(QTransform *t) const
-{
- Q_D(const QGraphicsRotation);
- if (d->angle) {
- t->translate(d->origin.x(), d->origin.y());
- t->rotate(d->angle);
- t->translate(-d->origin.x(), -d->origin.y());
- }
-}
-
-/*!
\fn QGraphicsRotation::originChanged()
This signal is emitted whenever the origin has changed.
@@ -456,93 +455,92 @@ void QGraphicsRotation::applyTo(QTransform *t) const
*/
/*!
- \class QGraphicsRotation3D
- \brief The QGraphicsRotation3D class provides rotation in 3 dimensions.
- \since 4.6
-
- QGraphicsRotation3D extends QGraphicsRotation with the ability to rotate
- around a given axis.
-
- You can provide the desired axis by assigning a QVector3D to the axis
- property. The angle property, which is provided by QGraphicsRotation, now
- describes the number of degrees to rotate around this axis.
-
- By default the axis is (0, 0, 1), giving QGraphicsRotation3D the same
- default behavior as QGraphicsRotation (i.e., rotation around the Z axis).
-
- Note: the final rotation is the combined effect of a rotation in
- 3D space followed by a projection back to 2D. If several rotations
- are performed in succession, they will not behave as expected unless
- they were all around the Z axis.
-
- \sa QGraphicsTransform, QGraphicsItem::setRotation(), QTransform::rotate()
-*/
-
-class QGraphicsRotation3DPrivate : public QGraphicsRotationPrivate
-{
-public:
- QGraphicsRotation3DPrivate() : axis(0, 0, 1) {}
-
- QVector3D axis;
-};
-
-/*!
- Constructs a new QGraphicsRotation3D with the given \a parent.
-*/
-QGraphicsRotation3D::QGraphicsRotation3D(QObject *parent)
- : QGraphicsRotation(*new QGraphicsRotation3DPrivate, parent)
-{
-}
-
-/*!
- Destroys the 3D graphics rotation.
-*/
-QGraphicsRotation3D::~QGraphicsRotation3D()
-{
-}
-
-/*!
- \property QGraphicsRotation3D::axis
+ \property QGraphicsRotation::axis
\brief a rotation axis, specified by a vector in 3D space.
This can be any axis in 3D space. By default the axis is (0, 0, 1),
- which is aligned with the Z axis and provides the same behavior
- for the rotation angle as QGraphicsRotation. If you provide another
- axis, QGraphicsRotation3D will provide a transformation that rotates
+ which is aligned with the Z axis. If you provide another axis,
+ QGraphicsRotation will provide a transformation that rotates
around this axis. For example, if you would like to rotate an item
around its X axis, you could pass (1, 0, 0) as the axis.
\sa QTransform, QGraphicsRotation::angle
*/
-QVector3D QGraphicsRotation3D::axis()
+QVector3D QGraphicsRotation::axis() const
{
- Q_D(QGraphicsRotation3D);
+ Q_D(const QGraphicsRotation);
return d->axis;
}
-void QGraphicsRotation3D::setAxis(const QVector3D &axis)
+void QGraphicsRotation::setAxis(const QVector3D &axis)
{
- Q_D(QGraphicsRotation3D);
- if (d->axis == axis)
- return;
- d->axis = axis;
+ Q_D(QGraphicsRotation);
+ if (d->axis == axis)
+ return;
+ d->axis = axis;
+ if (axis == VECTOR_FOR_AXIS_X) {
+ d->simpleAxis = Qt::XAxis;
+ } else if (axis == VECTOR_FOR_AXIS_Y) {
+ d->simpleAxis = Qt::YAxis;
+ } else if (axis == VECTOR_FOR_AXIS_Z) {
+ d->simpleAxis = Qt::ZAxis;
+ } else {
+ d->simpleAxis = -1; // no predefined axis
+ }
update();
emit axisChanged();
}
+/*!
+ \fn void QGraphicsRotation::setAxis(Qt::Axis axis)
+
+ Convenience function to set the axis to \a axis.
+*/
+
+void QGraphicsRotation::setAxis(Qt::Axis axis)
+{
+ switch (axis)
+ {
+ case Qt::XAxis:
+ setAxis(VECTOR_FOR_AXIS_X);
+ break;
+ case Qt::YAxis:
+ setAxis(VECTOR_FOR_AXIS_Y);
+ break;
+ case Qt::ZAxis:
+ setAxis(VECTOR_FOR_AXIS_Z);
+ break;
+ }
+}
+
+
const qreal deg2rad = qreal(0.017453292519943295769); // pi/180
static const qreal inv_dist_to_plane = 1. / 1024.;
/*!
\reimp
*/
-void QGraphicsRotation3D::applyTo(QTransform *t) const
+void QGraphicsRotation::applyTo(QTransform *t) const
{
- Q_D(const QGraphicsRotation3D);
+ Q_D(const QGraphicsRotation);
qreal a = d->angle;
- if (a == 0. ||
- (d->axis.z() == 0. && d->axis.y() == 0 && d->axis.x() == 0))
+ if (a == 0.)
+ return;
+
+ if (d->simpleAxis != -1) {
+ //that's an optimization for simple axis
+ t->translate(d->origin.x(), d->origin.y());
+ t->rotate(a, Qt::Axis(d->simpleAxis));
+ t->translate(-d->origin.x(), -d->origin.y());
+ return;
+ }
+
+ qreal x = d->axis.x();
+ qreal y = d->axis.y();
+ qreal z = d->axis.z();
+
+ if (x == 0. && y == 0 && z == 0)
return;
qreal c, s;
@@ -561,27 +559,23 @@ void QGraphicsRotation3D::applyTo(QTransform *t) const
c = qCos(b);
}
- qreal x = d->axis.x();
- qreal y = d->axis.y();
- qreal z = d->axis.z();
-
qreal len = x * x + y * y + z * z;
if (len != 1.) {
- len = 1./::sqrt(len);
+ len = 1. / qSqrt(len);
x *= len;
y *= len;
z *= len;
}
t->translate(d->origin.x(), d->origin.y());
- *t = QTransform(x*x*(1-c)+c, x*y*(1-c)-z*s, x*z*(1-c)+y*s*inv_dist_to_plane,
- y*x*(1-c)+z*s, y*y*(1-c)+c, y*z*(1-c)-x*s*inv_dist_to_plane,
- 0, 0, 1) * *t;
+ *t = QTransform(x*x*(1-c)+c, x*y*(1-c)+z*s, x*z*(1-c)-y*s*inv_dist_to_plane,
+ y*x*(1-c)-z*s, y*y*(1-c)+c, y*z*(1-c)-x*s*inv_dist_to_plane,
+ 0, 0, 1) * *t;
t->translate(-d->origin.x(), -d->origin.y());
}
/*!
- \fn void QGraphicsRotation3D::axisChanged()
+ \fn void QGraphicsRotation::axisChanged()
This signal is emitted whenever the axis of the object changes.
*/
diff --git a/src/gui/graphicsview/qgraphicstransform.h b/src/gui/graphicsview/qgraphicstransform.h
index 2e0d511..8ccc258 100644
--- a/src/gui/graphicsview/qgraphicstransform.h
+++ b/src/gui/graphicsview/qgraphicstransform.h
@@ -117,6 +117,7 @@ class Q_GUI_EXPORT QGraphicsRotation : public QGraphicsTransform
Q_PROPERTY(QPointF origin READ origin WRITE setOrigin NOTIFY originChanged)
Q_PROPERTY(qreal angle READ angle WRITE setAngle NOTIFY angleChanged)
+ Q_PROPERTY(QVector3D axis READ axis WRITE setAxis NOTIFY axisChanged)
public:
QGraphicsRotation(QObject *parent = 0);
~QGraphicsRotation();
@@ -127,39 +128,19 @@ public:
qreal angle() const;
void setAngle(qreal);
- void applyTo(QTransform *transform) const;
-
-Q_SIGNALS:
- void originChanged();
- void angleChanged();
-
-protected:
- QGraphicsRotation(QGraphicsRotationPrivate &p, QObject *parent);
-private:
- Q_DECLARE_PRIVATE(QGraphicsRotation)
-};
-
-class QGraphicsRotation3DPrivate;
-
-class Q_GUI_EXPORT QGraphicsRotation3D : public QGraphicsRotation
-{
- Q_OBJECT
-
- Q_PROPERTY(QVector3D axis READ axis WRITE setAxis NOTIFY axisChanged)
-public:
- QGraphicsRotation3D(QObject *parent = 0);
- ~QGraphicsRotation3D();
-
- QVector3D axis();
+ QVector3D axis() const;
void setAxis(const QVector3D &axis);
+ void setAxis(Qt::Axis axis);
void applyTo(QTransform *transform) const;
Q_SIGNALS:
+ void originChanged();
+ void angleChanged();
void axisChanged();
private:
- Q_DECLARE_PRIVATE(QGraphicsRotation3D)
+ Q_DECLARE_PRIVATE(QGraphicsRotation)
};
QT_END_NAMESPACE
diff --git a/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp b/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp
index 932062f..bfd346b 100644
--- a/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp
+++ b/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp
@@ -57,6 +57,7 @@ public slots:
private slots:
void scale();
void rotation();
+ void rotation3d_data();
void rotation3d();
};
@@ -112,6 +113,11 @@ void tst_QGraphicsTransform::scale()
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.angle(), (qreal)0);
+
rotation.setOrigin(QPointF(10, 10));
QTransform t;
@@ -134,46 +140,59 @@ void tst_QGraphicsTransform::rotation()
QCOMPARE(rotation.transform().map(QPointF(20, 10)), QPointF(10, 20));
}
+Q_DECLARE_METATYPE(Qt::Axis);
+void tst_QGraphicsTransform::rotation3d_data()
+{
+ QTest::addColumn<Qt::Axis>("axis");
+ QTest::addColumn<qreal>("angle");
+
+ for (int angle = 0; angle <= 360; angle++) {
+ QTest::newRow("test rotation on X") << Qt::XAxis << qreal(angle);
+ QTest::newRow("test rotation on Y") << Qt::YAxis << qreal(angle);
+ QTest::newRow("test rotation on Z") << Qt::ZAxis << qreal(angle);
+ }
+}
+
void tst_QGraphicsTransform::rotation3d()
{
- QGraphicsRotation3D rotation;
- QCOMPARE(rotation.axis().x(), (qreal)0);
- QCOMPARE(rotation.axis().y(), (qreal)0);
- QCOMPARE(rotation.axis().z(), (qreal)1);
- QCOMPARE(rotation.angle(), (qreal)0);
+ QFETCH(Qt::Axis, axis);
+ QFETCH(qreal, angle);
+
+ QGraphicsRotation rotation;
+ rotation.setAxis(axis);
QTransform t;
rotation.applyTo(&t);
- QCOMPARE(t, QTransform());
- QCOMPARE(rotation.transform(), QTransform());
+ QVERIFY(t.isIdentity());
+ QVERIFY(rotation.transform().isIdentity());
- rotation.setAngle(180);
+ rotation.setAngle(angle);
- QTransform t180;
- t180.rotate(180.0f);
+ QTransform expected;
+ expected.rotate(angle, axis);
- QCOMPARE(t, QTransform());
- QVERIFY(qFuzzyCompare(rotation.transform(), t180));
+ QVERIFY(qFuzzyCompare(rotation.transform(), 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));
- t = QTransform();
+ t.reset();
rotation.applyTo(&t);
- QCOMPARE(t, QTransform());
- QCOMPARE(rotation.transform(), QTransform());
+ QVERIFY(t.isIdentity());
+ QVERIFY(rotation.transform().isIdentity());
- rotation.setAngle(180);
+ rotation.setAngle(angle);
- QCOMPARE(t, QTransform());
- QCOMPARE(rotation.transform(), QTransform());
+ QVERIFY(t.isIdentity());
+ QVERIFY(rotation.transform().isIdentity());
rotation.setOrigin(QPointF(0, 0));
- QCOMPARE(t, QTransform());
- QCOMPARE(rotation.transform(), QTransform());
+ QVERIFY(t.isIdentity());
+ QVERIFY(rotation.transform().isIdentity());
}