source: trunk/src/gui/graphicsview/qgraphicstransform.cpp@ 651

Last change on this file since 651 was 651, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.2 sources.

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