src/gui/graphicsview/qgraphicstransform.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 /*!
       
    43     \class QGraphicsTransform
       
    44     \brief The QGraphicsTransform class is an abstract base class for building
       
    45     advanced transformations on QGraphicsItems.
       
    46     \since 4.6
       
    47     \ingroup graphicsview-api
       
    48 
       
    49     As an alternative to QGraphicsItem::transform, QGraphicsTransform lets you
       
    50     create and control advanced transformations that can be configured
       
    51     independently using specialized properties.
       
    52 
       
    53     QGraphicsItem allows you to assign any number of QGraphicsTransform
       
    54     instances to one QGraphicsItem. Each QGraphicsTransform is applied in
       
    55     order, one at a time, to the QGraphicsItem it's assigned to.
       
    56 
       
    57     QGraphicsTransform is particularily useful for animations. Whereas
       
    58     QGraphicsItem::setTransform() lets you assign any transform directly to an
       
    59     item, there is no direct way to interpolate between two different
       
    60     transformations (e.g., when transitioning between two states, each for
       
    61     which the item has a different arbitrary transform assigned). Using
       
    62     QGraphicsTransform you can interpolate the property values of each
       
    63     independent transformation. The resulting operation is then combined into a
       
    64     single transform which is applied to QGraphicsItem.
       
    65 
       
    66     Transformations are computed in true 3D space using QMatrix4x4.
       
    67     When the transformation is applied to a QGraphicsItem, it will be
       
    68     projected back to a 2D QTransform.  When multiple QGraphicsTransform
       
    69     objects are applied to a QGraphicsItem, all of the transformations
       
    70     are computed in true 3D space, with the projection back to 2D
       
    71     only occurring after the last QGraphicsTransform is applied.
       
    72 
       
    73     If you want to create your own configurable transformation, you can create
       
    74     a subclass of QGraphicsTransform (or any or the existing subclasses), and
       
    75     reimplement the pure virtual applyTo() function, which takes a pointer to a
       
    76     QMatrix4x4. Each operation you would like to apply should be exposed as
       
    77     properties (e.g., customTransform->setVerticalShear(2.5)). Inside you
       
    78     reimplementation of applyTo(), you can modify the provided transform
       
    79     respectively.
       
    80 
       
    81     QGraphicsTransform can be used together with QGraphicsItem::setTransform(),
       
    82     QGraphicsItem::setRotation(), and QGraphicsItem::setScale().
       
    83 
       
    84     \sa QGraphicsItem::transform(), QGraphicsScale, QGraphicsRotation
       
    85 */
       
    86 
       
    87 #include "qgraphicstransform.h"
       
    88 #include "qgraphicsitem_p.h"
       
    89 #include "qgraphicstransform_p.h"
       
    90 #include <QDebug>
       
    91 #include <QtCore/qmath.h>
       
    92 
       
    93 QT_BEGIN_NAMESPACE
       
    94 
       
    95 void QGraphicsTransformPrivate::setItem(QGraphicsItem *i)
       
    96 {
       
    97     if (item == i)
       
    98         return;
       
    99 
       
   100     if (item) {
       
   101         Q_Q(QGraphicsTransform);
       
   102         QGraphicsItemPrivate *d_ptr = item->d_ptr.data();
       
   103 
       
   104         item->prepareGeometryChange();
       
   105         Q_ASSERT(d_ptr->transformData);
       
   106         d_ptr->transformData->graphicsTransforms.removeAll(q);
       
   107         d_ptr->dirtySceneTransform = 1;
       
   108         item = 0;
       
   109     }
       
   110 
       
   111     item = i;
       
   112 }
       
   113 
       
   114 void QGraphicsTransformPrivate::updateItem(QGraphicsItem *item)
       
   115 {
       
   116     item->prepareGeometryChange();
       
   117     item->d_ptr->dirtySceneTransform = 1;
       
   118 }
       
   119 
       
   120 /*!
       
   121     Constructs a new QGraphicsTransform with the given \a parent.
       
   122 */
       
   123 QGraphicsTransform::QGraphicsTransform(QObject *parent)
       
   124     : QObject(*new QGraphicsTransformPrivate, parent)
       
   125 {
       
   126 }
       
   127 
       
   128 /*!
       
   129     Destroys the graphics transform.
       
   130 */
       
   131 QGraphicsTransform::~QGraphicsTransform()
       
   132 {
       
   133     Q_D(QGraphicsTransform);
       
   134     d->setItem(0);
       
   135 }
       
   136 
       
   137 /*!
       
   138     \internal
       
   139 */
       
   140 QGraphicsTransform::QGraphicsTransform(QGraphicsTransformPrivate &p, QObject *parent)
       
   141     : QObject(p, parent)
       
   142 {
       
   143 }
       
   144 
       
   145 /*!
       
   146     \fn void QGraphicsTransform::applyTo(QMatrix4x4 *matrix) const
       
   147 
       
   148     This pure virtual method has to be reimplemented in derived classes.
       
   149 
       
   150     It applies this transformation to \a matrix.
       
   151 
       
   152     \sa QGraphicsItem::transform(), QMatrix4x4::toTransform()
       
   153 */
       
   154 
       
   155 /*!
       
   156     Notifies that this transform operation has changed its parameters in such a
       
   157     way that applyTo() will return a different result than before.
       
   158 
       
   159     When implementing you own custom graphics transform, you must call this
       
   160     function every time you change a parameter, to let QGraphicsItem know that
       
   161     its transformation needs to be updated.
       
   162 
       
   163     \sa applyTo()
       
   164 */
       
   165 void QGraphicsTransform::update()
       
   166 {
       
   167     Q_D(QGraphicsTransform);
       
   168     if (d->item)
       
   169         d->updateItem(d->item);
       
   170 }
       
   171 
       
   172 /*!
       
   173   \class QGraphicsScale
       
   174   \brief The QGraphicsScale class provides a scale transformation.
       
   175   \since 4.6
       
   176 
       
   177   QGraphicsScene provides certain parameters to help control how the scale
       
   178   should be applied.
       
   179 
       
   180   The origin is the point that the item is scaled from (i.e., it stays fixed
       
   181   relative to the parent as the rest of the item grows). By default the
       
   182   origin is QPointF(0, 0).
       
   183 
       
   184   The parameters xScale, yScale, and zScale describe the scale factors to
       
   185   apply in horizontal, vertical, and depth directions. They can take on any
       
   186   value, including 0 (to collapse the item to a point) or negative value.
       
   187   A negative xScale value will mirror the item horizontally. A negative yScale
       
   188   value will flip the item vertically. A negative zScale will flip the
       
   189   item end for end.
       
   190 
       
   191   \sa QGraphicsTransform, QGraphicsItem::setScale(), QTransform::scale()
       
   192 */
       
   193 
       
   194 class QGraphicsScalePrivate : public QGraphicsTransformPrivate
       
   195 {
       
   196 public:
       
   197     QGraphicsScalePrivate()
       
   198         : xScale(1), yScale(1), zScale(1) {}
       
   199     QVector3D origin;
       
   200     qreal xScale;
       
   201     qreal yScale;
       
   202     qreal zScale;
       
   203 };
       
   204 
       
   205 /*!
       
   206     Constructs an empty QGraphicsScale object with the given \a parent.
       
   207 */
       
   208 QGraphicsScale::QGraphicsScale(QObject *parent)
       
   209     : QGraphicsTransform(*new QGraphicsScalePrivate, parent)
       
   210 {
       
   211 }
       
   212 
       
   213 /*!
       
   214     Destroys the graphics scale.
       
   215 */
       
   216 QGraphicsScale::~QGraphicsScale()
       
   217 {
       
   218 }
       
   219 
       
   220 /*!
       
   221     \property QGraphicsScale::origin
       
   222     \brief the origin of the scale in 3D space.
       
   223 
       
   224     All scaling will be done relative to this point (i.e., this point
       
   225     will stay fixed, relative to the parent, when the item is scaled).
       
   226 
       
   227     \sa xScale, yScale, zScale
       
   228 */
       
   229 QVector3D QGraphicsScale::origin() const
       
   230 {
       
   231     Q_D(const QGraphicsScale);
       
   232     return d->origin;
       
   233 }
       
   234 void QGraphicsScale::setOrigin(const QVector3D &point)
       
   235 {
       
   236     Q_D(QGraphicsScale);
       
   237     if (d->origin == point)
       
   238         return;
       
   239     d->origin = point;
       
   240     update();
       
   241     emit originChanged();
       
   242 }
       
   243 
       
   244 /*!
       
   245     \property QGraphicsScale::xScale
       
   246     \brief the horizontal scale factor.
       
   247 
       
   248     The scale factor can be any real number; the default value is 1.0. If you
       
   249     set the factor to 0.0, the item will be collapsed to a single point. If you
       
   250     provide a negative value, the item will be mirrored horizontally around its
       
   251     origin.
       
   252 
       
   253     \sa yScale, zScale, origin
       
   254 */
       
   255 qreal QGraphicsScale::xScale() const
       
   256 {
       
   257     Q_D(const QGraphicsScale);
       
   258     return d->xScale;
       
   259 }
       
   260 void QGraphicsScale::setXScale(qreal scale)
       
   261 {
       
   262     Q_D(QGraphicsScale);
       
   263     if (d->xScale == scale)
       
   264         return;
       
   265     d->xScale = scale;
       
   266     update();
       
   267     emit scaleChanged();
       
   268 }
       
   269 
       
   270 /*!
       
   271     \property QGraphicsScale::yScale
       
   272     \brief the vertical scale factor.
       
   273 
       
   274     The scale factor can be any real number; the default value is 1.0. If you
       
   275     set the factor to 0.0, the item will be collapsed to a single point. If you
       
   276     provide a negative value, the item will be flipped vertically around its
       
   277     origin.
       
   278 
       
   279     \sa xScale, zScale, origin
       
   280 */
       
   281 qreal QGraphicsScale::yScale() const
       
   282 {
       
   283     Q_D(const QGraphicsScale);
       
   284     return d->yScale;
       
   285 }
       
   286 void QGraphicsScale::setYScale(qreal scale)
       
   287 {
       
   288     Q_D(QGraphicsScale);
       
   289     if (d->yScale == scale)
       
   290         return;
       
   291     d->yScale = scale;
       
   292     update();
       
   293     emit scaleChanged();
       
   294 }
       
   295 
       
   296 /*!
       
   297     \property QGraphicsScale::zScale
       
   298     \brief the depth scale factor.
       
   299 
       
   300     The scale factor can be any real number; the default value is 1.0. If you
       
   301     set the factor to 0.0, the item will be collapsed to a single point. If you
       
   302     provide a negative value, the item will be flipped end for end around its
       
   303     origin.
       
   304 
       
   305     \sa xScale, yScale, origin
       
   306 */
       
   307 qreal QGraphicsScale::zScale() const
       
   308 {
       
   309     Q_D(const QGraphicsScale);
       
   310     return d->zScale;
       
   311 }
       
   312 void QGraphicsScale::setZScale(qreal scale)
       
   313 {
       
   314     Q_D(QGraphicsScale);
       
   315     if (d->zScale == scale)
       
   316         return;
       
   317     d->zScale = scale;
       
   318     update();
       
   319     emit scaleChanged();
       
   320 }
       
   321 
       
   322 /*!
       
   323     \reimp
       
   324 */
       
   325 void QGraphicsScale::applyTo(QMatrix4x4 *matrix) const
       
   326 {
       
   327     Q_D(const QGraphicsScale);
       
   328     matrix->translate(d->origin);
       
   329     matrix->scale(d->xScale, d->yScale, d->zScale);
       
   330     matrix->translate(-d->origin);
       
   331 }
       
   332 
       
   333 /*!
       
   334     \fn QGraphicsScale::originChanged()
       
   335 
       
   336     QGraphicsScale emits this signal when its origin changes.
       
   337 
       
   338     \sa QGraphicsScale::origin
       
   339 */
       
   340 
       
   341 /*!
       
   342     \fn QGraphicsScale::scaleChanged()
       
   343 
       
   344     This signal is emitted whenever the xScale, yScale, or zScale
       
   345     of the object changes.
       
   346 
       
   347     \sa QGraphicsScale::xScale, QGraphicsScale::yScale
       
   348     \sa QGraphicsScale::zScale
       
   349 */
       
   350 
       
   351 /*!
       
   352     \class QGraphicsRotation
       
   353     \brief The QGraphicsRotation class provides a rotation transformation around
       
   354     a given axis.
       
   355     \since 4.6
       
   356 
       
   357     You can provide the desired axis by assigning a QVector3D to the axis property
       
   358     or by passing a member if Qt::Axis to the setAxis convenience function.
       
   359     By default the axis is (0, 0, 1) i.e., rotation around the Z axis.
       
   360 
       
   361     The angle property, which is provided by QGraphicsRotation, now
       
   362     describes the number of degrees to rotate around this axis.
       
   363 
       
   364     QGraphicsRotation provides certain parameters to help control how the
       
   365     rotation should be applied.
       
   366 
       
   367     The origin is the point that the item is rotated around (i.e., it stays
       
   368     fixed relative to the parent as the rest of the item is rotated). By
       
   369     default the origin is QPointF(0, 0).
       
   370 
       
   371     The angle property provides the number of degrees to rotate the item
       
   372     clockwise around the origin. This value also be negative, indicating a
       
   373     counter-clockwise rotation. For animation purposes it may also be useful to
       
   374     provide rotation angles exceeding (-360, 360) degrees, for instance to
       
   375     animate how an item rotates several times.
       
   376 
       
   377     Note: the final rotation is the combined effect of a rotation in
       
   378     3D space followed by a projection back to 2D.  If several rotations
       
   379     are performed in succession, they will not behave as expected unless
       
   380     they were all around the Z axis.
       
   381 
       
   382     \sa QGraphicsTransform, QGraphicsItem::setRotation(), QTransform::rotate()
       
   383 */
       
   384 
       
   385 class QGraphicsRotationPrivate : public QGraphicsTransformPrivate
       
   386 {
       
   387 public:
       
   388     QGraphicsRotationPrivate()
       
   389         : angle(0), axis(0, 0, 1) {}
       
   390     QVector3D origin;
       
   391     qreal angle;
       
   392     QVector3D axis;
       
   393 };
       
   394 
       
   395 /*!
       
   396     Constructs a new QGraphicsRotation with the given \a parent.
       
   397 */
       
   398 QGraphicsRotation::QGraphicsRotation(QObject *parent)
       
   399     : QGraphicsTransform(*new QGraphicsRotationPrivate, parent)
       
   400 {
       
   401 }
       
   402 
       
   403 /*!
       
   404     Destroys the graphics rotation.
       
   405 */
       
   406 QGraphicsRotation::~QGraphicsRotation()
       
   407 {
       
   408 }
       
   409 
       
   410 /*!
       
   411     \property QGraphicsRotation::origin
       
   412     \brief the origin of the rotation in 3D space.
       
   413 
       
   414     All rotations will be done relative to this point (i.e., this point
       
   415     will stay fixed, relative to the parent, when the item is rotated).
       
   416 
       
   417     \sa angle
       
   418 */
       
   419 QVector3D QGraphicsRotation::origin() const
       
   420 {
       
   421     Q_D(const QGraphicsRotation);
       
   422     return d->origin;
       
   423 }
       
   424 void QGraphicsRotation::setOrigin(const QVector3D &point)
       
   425 {
       
   426     Q_D(QGraphicsRotation);
       
   427     if (d->origin == point)
       
   428         return;
       
   429     d->origin = point;
       
   430     update();
       
   431     emit originChanged();
       
   432 }
       
   433 
       
   434 /*!
       
   435     \property QGraphicsRotation::angle
       
   436     \brief the angle for clockwise rotation, in degrees.
       
   437 
       
   438     The angle can be any real number; the default value is 0.0. A value of 180
       
   439     will rotate 180 degrees, clockwise. If you provide a negative number, the
       
   440     item will be rotated counter-clockwise. Normally the rotation angle will be
       
   441     in the range (-360, 360), but you can also provide numbers outside of this
       
   442     range (e.g., a angle of 370 degrees gives the same result as 10 degrees).
       
   443 
       
   444     \sa origin
       
   445 */
       
   446 qreal QGraphicsRotation::angle() const
       
   447 {
       
   448     Q_D(const QGraphicsRotation);
       
   449     return d->angle;
       
   450 }
       
   451 void QGraphicsRotation::setAngle(qreal angle)
       
   452 {
       
   453     Q_D(QGraphicsRotation);
       
   454     if (d->angle == angle)
       
   455         return;
       
   456     d->angle = angle;
       
   457     update();
       
   458     emit angleChanged();
       
   459 }
       
   460 
       
   461 /*!
       
   462     \fn QGraphicsRotation::originChanged()
       
   463 
       
   464     This signal is emitted whenever the origin has changed.
       
   465 
       
   466     \sa QGraphicsRotation::origin
       
   467 */
       
   468 
       
   469 /*!
       
   470     \fn void QGraphicsRotation::angleChanged()
       
   471 
       
   472     This signal is emitted whenever the angle has changed.
       
   473 
       
   474     \sa QGraphicsRotation::angle
       
   475 */
       
   476 
       
   477 /*!
       
   478     \property QGraphicsRotation::axis
       
   479     \brief a rotation axis, specified by a vector in 3D space.
       
   480 
       
   481     This can be any axis in 3D space. By default the axis is (0, 0, 1),
       
   482     which is aligned with the Z axis. If you provide another axis,
       
   483     QGraphicsRotation will provide a transformation that rotates
       
   484     around this axis. For example, if you would like to rotate an item
       
   485     around its X axis, you could pass (1, 0, 0) as the axis.
       
   486 
       
   487     \sa QTransform, QGraphicsRotation::angle
       
   488 */
       
   489 QVector3D QGraphicsRotation::axis() const
       
   490 {
       
   491     Q_D(const QGraphicsRotation);
       
   492     return d->axis;
       
   493 }
       
   494 void QGraphicsRotation::setAxis(const QVector3D &axis)
       
   495 {
       
   496     Q_D(QGraphicsRotation);
       
   497     if (d->axis == axis)
       
   498          return;
       
   499     d->axis = axis;
       
   500     update();
       
   501     emit axisChanged();
       
   502 }
       
   503 
       
   504 /*!
       
   505     \fn void QGraphicsRotation::setAxis(Qt::Axis axis)
       
   506 
       
   507     Convenience function to set the axis to \a axis.
       
   508 
       
   509     Note: the Qt::YAxis rotation for QTransform is inverted from the
       
   510     correct mathematical rotation in 3D space.  The QGraphicsRotation
       
   511     class implements a correct mathematical rotation.  The following
       
   512     two sequences of code will perform the same transformation:
       
   513 
       
   514     \code
       
   515     QTransform t;
       
   516     t.rotate(45, Qt::YAxis);
       
   517 
       
   518     QGraphicsRotation r;
       
   519     r.setAxis(Qt::YAxis);
       
   520     r.setAngle(-45);
       
   521     \endcode
       
   522 */
       
   523 void QGraphicsRotation::setAxis(Qt::Axis axis)
       
   524 {
       
   525     switch (axis)
       
   526     {
       
   527     case Qt::XAxis:
       
   528         setAxis(QVector3D(1, 0, 0));
       
   529         break;
       
   530     case Qt::YAxis:
       
   531         setAxis(QVector3D(0, 1, 0));
       
   532         break;
       
   533     case Qt::ZAxis:
       
   534         setAxis(QVector3D(0, 0, 1));
       
   535         break;
       
   536     }
       
   537 }
       
   538 
       
   539 /*!
       
   540     \reimp
       
   541 */
       
   542 void QGraphicsRotation::applyTo(QMatrix4x4 *matrix) const
       
   543 {
       
   544     Q_D(const QGraphicsRotation);
       
   545 
       
   546     if (d->angle == 0. || d->axis.isNull())
       
   547         return;
       
   548 
       
   549     matrix->translate(d->origin);
       
   550     QMatrix4x4 m;
       
   551     m.rotate(d->angle, d->axis.x(), d->axis.y(), d->axis.z());
       
   552     *matrix *= m.toTransform();
       
   553     matrix->translate(-d->origin);
       
   554 }
       
   555 
       
   556 /*!
       
   557     \fn void QGraphicsRotation::axisChanged()
       
   558 
       
   559     This signal is emitted whenever the axis of the object changes.
       
   560 
       
   561     \sa QGraphicsRotation::axis
       
   562 */
       
   563 
       
   564 #include "moc_qgraphicstransform.cpp"
       
   565 
       
   566 QT_END_NAMESPACE