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

Last change on this file since 858 was 846, checked in by Dmitry A. Kuminov, 14 years ago

trunk: Merged in qt 4.7.2 sources from branches/vendor/nokia/qt.

  • Property svn:eol-style set to native
File size: 16.7 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 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 particularly 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 xScaleChanged();
271 emit scaleChanged();
272}
273
274/*!
275 \property QGraphicsScale::yScale
276 \brief the vertical scale factor.
277
278 The scale factor can be any real number; the default value is 1.0. If you
279 set the factor to 0.0, the item will be collapsed to a single point. If you
280 provide a negative value, the item will be flipped vertically around its
281 origin.
282
283 \sa xScale, zScale, origin
284*/
285qreal QGraphicsScale::yScale() const
286{
287 Q_D(const QGraphicsScale);
288 return d->yScale;
289}
290void QGraphicsScale::setYScale(qreal scale)
291{
292 Q_D(QGraphicsScale);
293 if (d->yScale == scale)
294 return;
295 d->yScale = scale;
296 update();
297 emit yScaleChanged();
298 emit scaleChanged();
299}
300
301/*!
302 \property QGraphicsScale::zScale
303 \brief the depth scale factor.
304
305 The scale factor can be any real number; the default value is 1.0. If you
306 set the factor to 0.0, the item will be collapsed to a single point. If you
307 provide a negative value, the item will be flipped end for end around its
308 origin.
309
310 \sa xScale, yScale, origin
311*/
312qreal QGraphicsScale::zScale() const
313{
314 Q_D(const QGraphicsScale);
315 return d->zScale;
316}
317void QGraphicsScale::setZScale(qreal scale)
318{
319 Q_D(QGraphicsScale);
320 if (d->zScale == scale)
321 return;
322 d->zScale = scale;
323 update();
324 emit zScaleChanged();
325 emit scaleChanged();
326}
327
328/*!
329 \reimp
330*/
331void QGraphicsScale::applyTo(QMatrix4x4 *matrix) const
332{
333 Q_D(const QGraphicsScale);
334 matrix->translate(d->origin);
335 matrix->scale(d->xScale, d->yScale, d->zScale);
336 matrix->translate(-d->origin);
337}
338
339/*!
340 \fn QGraphicsScale::originChanged()
341
342 QGraphicsScale emits this signal when its origin changes.
343
344 \sa QGraphicsScale::origin
345*/
346
347/*!
348 \fn QGraphicsScale::xScaleChanged()
349 \since 4.7
350
351 This signal is emitted whenever the \l xScale property changes.
352*/
353
354/*!
355 \fn QGraphicsScale::yScaleChanged()
356 \since 4.7
357
358 This signal is emitted whenever the \l yScale property changes.
359*/
360
361/*!
362 \fn QGraphicsScale::zScaleChanged()
363 \since 4.7
364
365 This signal is emitted whenever the \l zScale property changes.
366*/
367
368/*!
369 \fn QGraphicsScale::scaleChanged()
370
371 This signal is emitted whenever the xScale, yScale, or zScale
372 of the object changes.
373
374 \sa QGraphicsScale::xScale, QGraphicsScale::yScale
375 \sa QGraphicsScale::zScale
376*/
377
378/*!
379 \class QGraphicsRotation
380 \brief The QGraphicsRotation class provides a rotation transformation around
381 a given axis.
382 \since 4.6
383
384 You can provide the desired axis by assigning a QVector3D to the axis property
385 or by passing a member if Qt::Axis to the setAxis convenience function.
386 By default the axis is (0, 0, 1) i.e., rotation around the Z axis.
387
388 The angle property, which is provided by QGraphicsRotation, now
389 describes the number of degrees to rotate around this axis.
390
391 QGraphicsRotation provides certain parameters to help control how the
392 rotation should be applied.
393
394 The origin is the point that the item is rotated around (i.e., it stays
395 fixed relative to the parent as the rest of the item is rotated). By
396 default the origin is QPointF(0, 0).
397
398 The angle property provides the number of degrees to rotate the item
399 clockwise around the origin. This value also be negative, indicating a
400 counter-clockwise rotation. For animation purposes it may also be useful to
401 provide rotation angles exceeding (-360, 360) degrees, for instance to
402 animate how an item rotates several times.
403
404 Note: the final rotation is the combined effect of a rotation in
405 3D space followed by a projection back to 2D. If several rotations
406 are performed in succession, they will not behave as expected unless
407 they were all around the Z axis.
408
409 \sa QGraphicsTransform, QGraphicsItem::setRotation(), QTransform::rotate()
410*/
411
412class QGraphicsRotationPrivate : public QGraphicsTransformPrivate
413{
414public:
415 QGraphicsRotationPrivate()
416 : angle(0), axis(0, 0, 1) {}
417 QVector3D origin;
418 qreal angle;
419 QVector3D axis;
420};
421
422/*!
423 Constructs a new QGraphicsRotation with the given \a parent.
424*/
425QGraphicsRotation::QGraphicsRotation(QObject *parent)
426 : QGraphicsTransform(*new QGraphicsRotationPrivate, parent)
427{
428}
429
430/*!
431 Destroys the graphics rotation.
432*/
433QGraphicsRotation::~QGraphicsRotation()
434{
435}
436
437/*!
438 \property QGraphicsRotation::origin
439 \brief the origin of the rotation in 3D space.
440
441 All rotations will be done relative to this point (i.e., this point
442 will stay fixed, relative to the parent, when the item is rotated).
443
444 \sa angle
445*/
446QVector3D QGraphicsRotation::origin() const
447{
448 Q_D(const QGraphicsRotation);
449 return d->origin;
450}
451void QGraphicsRotation::setOrigin(const QVector3D &point)
452{
453 Q_D(QGraphicsRotation);
454 if (d->origin == point)
455 return;
456 d->origin = point;
457 update();
458 emit originChanged();
459}
460
461/*!
462 \property QGraphicsRotation::angle
463 \brief the angle for clockwise rotation, in degrees.
464
465 The angle can be any real number; the default value is 0.0. A value of 180
466 will rotate 180 degrees, clockwise. If you provide a negative number, the
467 item will be rotated counter-clockwise. Normally the rotation angle will be
468 in the range (-360, 360), but you can also provide numbers outside of this
469 range (e.g., a angle of 370 degrees gives the same result as 10 degrees).
470
471 \sa origin
472*/
473qreal QGraphicsRotation::angle() const
474{
475 Q_D(const QGraphicsRotation);
476 return d->angle;
477}
478void QGraphicsRotation::setAngle(qreal angle)
479{
480 Q_D(QGraphicsRotation);
481 if (d->angle == angle)
482 return;
483 d->angle = angle;
484 update();
485 emit angleChanged();
486}
487
488/*!
489 \fn QGraphicsRotation::originChanged()
490
491 This signal is emitted whenever the origin has changed.
492
493 \sa QGraphicsRotation::origin
494*/
495
496/*!
497 \fn void QGraphicsRotation::angleChanged()
498
499 This signal is emitted whenever the angle has changed.
500
501 \sa QGraphicsRotation::angle
502*/
503
504/*!
505 \property QGraphicsRotation::axis
506 \brief a rotation axis, specified by a vector in 3D space.
507
508 This can be any axis in 3D space. By default the axis is (0, 0, 1),
509 which is aligned with the Z axis. If you provide another axis,
510 QGraphicsRotation will provide a transformation that rotates
511 around this axis. For example, if you would like to rotate an item
512 around its X axis, you could pass (1, 0, 0) as the axis.
513
514 \sa QTransform, QGraphicsRotation::angle
515*/
516QVector3D QGraphicsRotation::axis() const
517{
518 Q_D(const QGraphicsRotation);
519 return d->axis;
520}
521void QGraphicsRotation::setAxis(const QVector3D &axis)
522{
523 Q_D(QGraphicsRotation);
524 if (d->axis == axis)
525 return;
526 d->axis = axis;
527 update();
528 emit axisChanged();
529}
530
531/*!
532 \fn void QGraphicsRotation::setAxis(Qt::Axis axis)
533
534 Convenience function to set the axis to \a axis.
535
536 Note: the Qt::YAxis rotation for QTransform is inverted from the
537 correct mathematical rotation in 3D space. The QGraphicsRotation
538 class implements a correct mathematical rotation. The following
539 two sequences of code will perform the same transformation:
540
541 \code
542 QTransform t;
543 t.rotate(45, Qt::YAxis);
544
545 QGraphicsRotation r;
546 r.setAxis(Qt::YAxis);
547 r.setAngle(-45);
548 \endcode
549*/
550void QGraphicsRotation::setAxis(Qt::Axis axis)
551{
552 switch (axis)
553 {
554 case Qt::XAxis:
555 setAxis(QVector3D(1, 0, 0));
556 break;
557 case Qt::YAxis:
558 setAxis(QVector3D(0, 1, 0));
559 break;
560 case Qt::ZAxis:
561 setAxis(QVector3D(0, 0, 1));
562 break;
563 }
564}
565
566/*!
567 \reimp
568*/
569void QGraphicsRotation::applyTo(QMatrix4x4 *matrix) const
570{
571 Q_D(const QGraphicsRotation);
572
573 if (d->angle == 0. || d->axis.isNull())
574 return;
575
576 matrix->translate(d->origin);
577 matrix->projectedRotate(d->angle, d->axis.x(), d->axis.y(), d->axis.z());
578 matrix->translate(-d->origin);
579}
580
581/*!
582 \fn void QGraphicsRotation::axisChanged()
583
584 This signal is emitted whenever the axis of the object changes.
585
586 \sa QGraphicsRotation::axis
587*/
588
589#include "moc_qgraphicstransform.cpp"
590
591QT_END_NAMESPACE
592#endif //QT_NO_GRAPHICSVIEW
Note: See TracBrowser for help on using the repository browser.