source: vendor/trolltech/current/src/kernel/qwmatrix.cpp

Last change on this file was 2, checked in by dmik, 20 years ago

Imported xplatform parts of the official release 3.3.1 from Trolltech

  • Property svn:keywords set to Id
File size: 27.1 KB
Line 
1/****************************************************************************
2** $Id: qwmatrix.cpp 2 2005-11-16 15:49:26Z dmik $
3**
4** Implementation of QWMatrix class
5**
6** Created : 941020
7**
8** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qwmatrix.h"
39#include "qdatastream.h"
40#include "qregion.h"
41#if defined(Q_WS_X11)
42double qsincos( double, bool calcCos ); // defined in qpainter_x11.cpp
43#else
44#include <math.h>
45#endif
46
47#include <limits.h>
48
49#ifndef QT_NO_WMATRIX
50
51/*!
52 \class QWMatrix qwmatrix.h
53 \brief The QWMatrix class specifies 2D transformations of a
54 coordinate system.
55
56 \ingroup graphics
57 \ingroup images
58
59 The standard coordinate system of a \link QPaintDevice paint
60 device\endlink has the origin located at the top-left position. X
61 values increase to the right; Y values increase downward.
62
63 This coordinate system is the default for the QPainter, which
64 renders graphics in a paint device. A user-defined coordinate
65 system can be specified by setting a QWMatrix for the painter.
66
67 Example:
68 \code
69 MyWidget::paintEvent( QPaintEvent * )
70 {
71 QPainter p; // our painter
72 QWMatrix m; // our transformation matrix
73 m.rotate( 22.5 ); // rotated coordinate system
74 p.begin( this ); // start painting
75 p.setWorldMatrix( m ); // use rotated coordinate system
76 p.drawText( 30,20, "detator" ); // draw rotated text at 30,20
77 p.end(); // painting done
78 }
79 \endcode
80
81 A matrix specifies how to translate, scale, shear or rotate the
82 graphics; the actual transformation is performed by the drawing
83 routines in QPainter and by QPixmap::xForm().
84
85 The QWMatrix class contains a 3x3 matrix of the form:
86 <table align=center border=1 cellpadding=1 cellspacing=0>
87 <tr align=center><td>m11</td><td>m12</td><td>&nbsp;0 </td></tr>
88 <tr align=center><td>m21</td><td>m22</td><td>&nbsp;0 </td></tr>
89 <tr align=center><td>dx</td> <td>dy</td> <td>&nbsp;1 </td></tr>
90 </table>
91
92 A matrix transforms a point in the plane to another point:
93 \code
94 x' = m11*x + m21*y + dx
95 y' = m22*y + m12*x + dy
96 \endcode
97
98 The point \e (x, y) is the original point, and \e (x', y') is the
99 transformed point. \e (x', y') can be transformed back to \e (x,
100 y) by performing the same operation on the \link
101 QWMatrix::invert() inverted matrix\endlink.
102
103 The elements \e dx and \e dy specify horizontal and vertical
104 translation. The elements \e m11 and \e m22 specify horizontal and
105 vertical scaling. The elements \e m12 and \e m21 specify
106 horizontal and vertical shearing.
107
108 The identity matrix has \e m11 and \e m22 set to 1; all others are
109 set to 0. This matrix maps a point to itself.
110
111 Translation is the simplest transformation. Setting \e dx and \e
112 dy will move the coordinate system \e dx units along the X axis
113 and \e dy units along the Y axis.
114
115 Scaling can be done by setting \e m11 and \e m22. For example,
116 setting \e m11 to 2 and \e m22 to 1.5 will double the height and
117 increase the width by 50%.
118
119 Shearing is controlled by \e m12 and \e m21. Setting these
120 elements to values different from zero will twist the coordinate
121 system.
122
123 Rotation is achieved by carefully setting both the shearing
124 factors and the scaling factors. The QWMatrix also has a function
125 that sets \link rotate() rotation \endlink directly.
126
127 QWMatrix lets you combine transformations like this:
128 \code
129 QWMatrix m; // identity matrix
130 m.translate(10, -20); // first translate (10,-20)
131 m.rotate(25); // then rotate 25 degrees
132 m.scale(1.2, 0.7); // finally scale it
133 \endcode
134
135 Here's the same example using basic matrix operations:
136 \code
137 double a = pi/180 * 25; // convert 25 to radians
138 double sina = sin(a);
139 double cosa = cos(a);
140 QWMatrix m1(1, 0, 0, 1, 10, -20); // translation matrix
141 QWMatrix m2( cosa, sina, // rotation matrix
142 -sina, cosa, 0, 0 );
143 QWMatrix m3(1.2, 0, 0, 0.7, 0, 0); // scaling matrix
144 QWMatrix m;
145 m = m3 * m2 * m1; // combine all transformations
146 \endcode
147
148 \l QPainter has functions to translate, scale, shear and rotate the
149 coordinate system without using a QWMatrix. Although these
150 functions are very convenient, it can be more efficient to build a
151 QWMatrix and call QPainter::setWorldMatrix() if you want to perform
152 more than a single transform operation.
153
154 \sa QPainter::setWorldMatrix(), QPixmap::xForm()
155*/
156
157bool qt_old_transformations = TRUE;
158
159/*!
160 \enum QWMatrix::TransformationMode
161
162 \keyword transformation matrix
163
164 QWMatrix offers two transformation modes. Calculations can either
165 be done in terms of points (Points mode, the default), or in
166 terms of area (Area mode).
167
168 In Points mode the transformation is applied to the points that
169 mark out the shape's bounding line. In Areas mode the
170 transformation is applied in such a way that the area of the
171 contained region is correctly transformed under the matrix.
172
173 \value Points transformations are applied to the shape's points.
174 \value Areas transformations are applied (e.g. to the width and
175 height) so that the area is transformed.
176
177 Example:
178
179 Suppose we have a rectangle,
180 \c{QRect( 10, 20, 30, 40 )} and a transformation matrix
181 \c{QWMatrix( 2, 0, 0, 2, 0, 0 )} to double the rectangle's size.
182
183 In Points mode, the matrix will transform the top-left (10,20) and
184 the bottom-right (39,59) points producing a rectangle with its
185 top-left point at (20,40) and its bottom-right point at (78,118),
186 i.e. with a width of 59 and a height of 79.
187
188 In Areas mode, the matrix will transform the top-left point in
189 the same way as in Points mode to (20/40), and double the width
190 and height, so the bottom-right will become (69,99), i.e. a width
191 of 60 and a height of 80.
192
193 Because integer arithmetic is used (for speed), rounding
194 differences mean that the modes will produce slightly different
195 results given the same shape and the same transformation,
196 especially when scaling up. This also means that some operations
197 are not commutative.
198
199 Under Points mode, \c{matrix * ( region1 | region2 )} is not equal to
200 \c{matrix * region1 | matrix * region2}. Under Area mode, \c{matrix *
201 (pointarray[i])} is not neccesarily equal to
202 \c{(matrix * pointarry)[i]}.
203
204 \img xform.png Comparison of Points and Areas TransformationModes
205*/
206
207/*!
208 Sets the transformation mode that QWMatrix and painter
209 transformations use to \a m.
210
211 \sa QWMatrix::TransformationMode
212*/
213void QWMatrix::setTransformationMode( QWMatrix::TransformationMode m )
214{
215 if ( m == QWMatrix::Points )
216 qt_old_transformations = TRUE;
217 else
218 qt_old_transformations = FALSE;
219}
220
221
222/*!
223 Returns the current transformation mode.
224
225 \sa QWMatrix::TransformationMode
226*/
227QWMatrix::TransformationMode QWMatrix::transformationMode()
228{
229 return (qt_old_transformations ? QWMatrix::Points : QWMatrix::Areas );
230}
231
232
233// some defines to inline some code
234#define MAPDOUBLE( x, y, nx, ny ) \
235{ \
236 double fx = x; \
237 double fy = y; \
238 nx = _m11*fx + _m21*fy + _dx; \
239 ny = _m12*fx + _m22*fy + _dy; \
240}
241
242#define MAPINT( x, y, nx, ny ) \
243{ \
244 double fx = x; \
245 double fy = y; \
246 nx = qRound(_m11*fx + _m21*fy + _dx); \
247 ny = qRound(_m12*fx + _m22*fy + _dy); \
248}
249
250/*****************************************************************************
251 QWMatrix member functions
252 *****************************************************************************/
253
254/*!
255 Constructs an identity matrix. All elements are set to zero except
256 \e m11 and \e m22 (scaling), which are set to 1.
257*/
258
259QWMatrix::QWMatrix()
260{
261 _m11 = _m22 = 1.0;
262 _m12 = _m21 = _dx = _dy = 0.0;
263}
264
265/*!
266 Constructs a matrix with the elements, \a m11, \a m12, \a m21, \a
267 m22, \a dx and \a dy.
268*/
269
270QWMatrix::QWMatrix( double m11, double m12, double m21, double m22,
271 double dx, double dy )
272{
273 _m11 = m11; _m12 = m12;
274 _m21 = m21; _m22 = m22;
275 _dx = dx; _dy = dy;
276}
277
278
279/*!
280 Sets the matrix elements to the specified values, \a m11, \a m12,
281 \a m21, \a m22, \a dx and \a dy.
282*/
283
284void QWMatrix::setMatrix( double m11, double m12, double m21, double m22,
285 double dx, double dy )
286{
287 _m11 = m11; _m12 = m12;
288 _m21 = m21; _m22 = m22;
289 _dx = dx; _dy = dy;
290}
291
292
293/*!
294 \fn double QWMatrix::m11() const
295
296 Returns the X scaling factor.
297*/
298
299/*!
300 \fn double QWMatrix::m12() const
301
302 Returns the vertical shearing factor.
303*/
304
305/*!
306 \fn double QWMatrix::m21() const
307
308 Returns the horizontal shearing factor.
309*/
310
311/*!
312 \fn double QWMatrix::m22() const
313
314 Returns the Y scaling factor.
315*/
316
317/*!
318 \fn double QWMatrix::dx() const
319
320 Returns the horizontal translation.
321*/
322
323/*!
324 \fn double QWMatrix::dy() const
325
326 Returns the vertical translation.
327*/
328
329
330/*!
331 \overload
332
333 Transforms ( \a x, \a y ) to ( \a *tx, \a *ty ) using the
334 following formulae:
335
336 \code
337 *tx = m11*x + m21*y + dx
338 *ty = m22*y + m12*x + dy
339 \endcode
340*/
341
342void QWMatrix::map( double x, double y, double *tx, double *ty ) const
343{
344 MAPDOUBLE( x, y, *tx, *ty );
345}
346
347/*!
348 Transforms ( \a x, \a y ) to ( \a *tx, \a *ty ) using the formulae:
349
350 \code
351 *tx = m11*x + m21*y + dx (rounded to the nearest integer)
352 *ty = m22*y + m12*x + dy (rounded to the nearest integer)
353 \endcode
354*/
355
356void QWMatrix::map( int x, int y, int *tx, int *ty ) const
357{
358 MAPINT( x, y, *tx, *ty );
359}
360
361/*!
362 \fn QPoint QWMatrix::map( const QPoint &p ) const
363
364 \overload
365
366 Transforms \a p to using the formulae:
367
368 \code
369 retx = m11*px + m21*py + dx (rounded to the nearest integer)
370 rety = m22*py + m12*px + dy (rounded to the nearest integer)
371 \endcode
372*/
373
374/*!
375 \fn QRect QWMatrix::map( const QRect &r ) const
376
377 \obsolete
378
379 Please use \l QWMatrix::mapRect() instead.
380
381 Note that this method does return the bounding rectangle of the \a r, when
382 shearing or rotations are used.
383*/
384
385/*!
386 \fn QPointArray QWMatrix::map( const QPointArray &a ) const
387
388 \overload
389
390 Returns the point array \a a transformed by calling map for each point.
391*/
392
393
394/*!
395 \fn QRegion QWMatrix::map( const QRegion &r ) const
396
397 \overload
398
399 Transforms the region \a r.
400
401 Calling this method can be rather expensive, if rotations or
402 shearing are used.
403*/
404
405/*!
406 \fn QRegion QWMatrix::mapToRegion( const QRect &rect ) const
407
408 Returns the transformed rectangle \a rect.
409
410 A rectangle which has been rotated or sheared may result in a
411 non-rectangular region being returned.
412
413 Calling this method can be expensive, if rotations or shearing are
414 used. If you just need to know the bounding rectangle of the
415 returned region, use mapRect() which is a lot faster than this
416 function.
417
418 \sa QWMatrix::mapRect()
419*/
420
421
422/*!
423 Returns the transformed rectangle \a rect.
424
425 The bounding rectangle is returned if rotation or shearing has
426 been specified.
427
428 If you need to know the exact region \a rect maps to use \l
429 operator*().
430
431 \sa operator*()
432*/
433
434QRect QWMatrix::mapRect( const QRect &rect ) const
435{
436 QRect result;
437 if( qt_old_transformations ) {
438 if ( _m12 == 0.0F && _m21 == 0.0F ) {
439 result = QRect( map(rect.topLeft()), map(rect.bottomRight()) ).normalize();
440 } else {
441 QPointArray a( rect );
442 a = map( a );
443 result = a.boundingRect();
444 }
445 } else {
446 if ( _m12 == 0.0F && _m21 == 0.0F ) {
447 int x = qRound( _m11*rect.x() + _dx );
448 int y = qRound( _m22*rect.y() + _dy );
449 int w = qRound( _m11*rect.width() );
450 int h = qRound( _m22*rect.height() );
451 if ( w < 0 ) {
452 w = -w;
453 x -= w-1;
454 }
455 if ( h < 0 ) {
456 h = -h;
457 y -= h-1;
458 }
459 result = QRect( x, y, w, h );
460 } else {
461
462 // see mapToPolygon for explanations of the algorithm.
463 double x0, y0;
464 double x, y;
465 MAPDOUBLE( rect.left(), rect.top(), x0, y0 );
466 double xmin = x0;
467 double ymin = y0;
468 double xmax = x0;
469 double ymax = y0;
470 MAPDOUBLE( rect.right() + 1, rect.top(), x, y );
471 xmin = QMIN( xmin, x );
472 ymin = QMIN( ymin, y );
473 xmax = QMAX( xmax, x );
474 ymax = QMAX( ymax, y );
475 MAPDOUBLE( rect.right() + 1, rect.bottom() + 1, x, y );
476 xmin = QMIN( xmin, x );
477 ymin = QMIN( ymin, y );
478 xmax = QMAX( xmax, x );
479 ymax = QMAX( ymax, y );
480 MAPDOUBLE( rect.left(), rect.bottom() + 1, x, y );
481 xmin = QMIN( xmin, x );
482 ymin = QMIN( ymin, y );
483 xmax = QMAX( xmax, x );
484 ymax = QMAX( ymax, y );
485 double w = xmax - xmin;
486 double h = ymax - ymin;
487 xmin -= ( xmin - x0 ) / w;
488 ymin -= ( ymin - y0 ) / h;
489 xmax -= ( xmax - x0 ) / w;
490 ymax -= ( ymax - y0 ) / h;
491 result = QRect( qRound(xmin), qRound(ymin), qRound(xmax)-qRound(xmin)+1, qRound(ymax)-qRound(ymin)+1 );
492 }
493 }
494 return result;
495}
496
497
498/*!
499 \internal
500*/
501QPoint QWMatrix::operator *( const QPoint &p ) const
502{
503 double fx = p.x();
504 double fy = p.y();
505 return QPoint( qRound(_m11*fx + _m21*fy + _dx),
506 qRound(_m12*fx + _m22*fy + _dy) );
507}
508
509
510struct QWMDoublePoint {
511 double x;
512 double y;
513};
514
515/*!
516 \internal
517*/
518QPointArray QWMatrix::operator *( const QPointArray &a ) const
519{
520 if( qt_old_transformations ) {
521 QPointArray result = a.copy();
522 int x, y;
523 for ( int i=0; i<(int)result.size(); i++ ) {
524 result.point( i, &x, &y );
525 MAPINT( x, y, x, y );
526 result.setPoint( i, x, y );
527 }
528 return result;
529 } else {
530 int size = a.size();
531 int i;
532 QMemArray<QWMDoublePoint> p( size );
533 QPoint *da = a.data();
534 QWMDoublePoint *dp = p.data();
535 double xmin = INT_MAX;
536 double ymin = xmin;
537 double xmax = INT_MIN;
538 double ymax = xmax;
539 int xminp = 0;
540 int yminp = 0;
541 for( i = 0; i < size; i++ ) {
542 dp[i].x = da[i].x();
543 dp[i].y = da[i].y();
544 if ( dp[i].x < xmin ) {
545 xmin = dp[i].x;
546 xminp = i;
547 }
548 if ( dp[i].y < ymin ) {
549 ymin = dp[i].y;
550 yminp = i;
551 }
552 xmax = QMAX( xmax, dp[i].x );
553 ymax = QMAX( ymax, dp[i].y );
554 }
555 double w = QMAX( xmax - xmin, 1 );
556 double h = QMAX( ymax - ymin, 1 );
557 for( i = 0; i < size; i++ ) {
558 dp[i].x += (dp[i].x - xmin)/w;
559 dp[i].y += (dp[i].y - ymin)/h;
560 MAPDOUBLE( dp[i].x, dp[i].y, dp[i].x, dp[i].y );
561 }
562
563 // now apply correction back for transformed values...
564 xmin = INT_MAX;
565 ymin = xmin;
566 xmax = INT_MIN;
567 ymax = xmax;
568 for( i = 0; i < size; i++ ) {
569 xmin = QMIN( xmin, dp[i].x );
570 ymin = QMIN( ymin, dp[i].y );
571 xmax = QMAX( xmax, dp[i].x );
572 ymax = QMAX( ymax, dp[i].y );
573 }
574 w = QMAX( xmax - xmin, 1 );
575 h = QMAX( ymax - ymin, 1 );
576
577 QPointArray result( size );
578 QPoint *dr = result.data();
579 for( i = 0; i < size; i++ ) {
580 dr[i].setX( qRound( dp[i].x - (dp[i].x - dp[xminp].x)/w ) );
581 dr[i].setY( qRound( dp[i].y - (dp[i].y - dp[yminp].y)/h ) );
582 }
583 return result;
584 }
585}
586
587/*!
588\internal
589*/
590QRegion QWMatrix::operator * (const QRect &rect ) const
591{
592 QRegion result;
593 if ( isIdentity() ) {
594 result = rect;
595 } else if ( _m12 == 0.0F && _m21 == 0.0F ) {
596 if( qt_old_transformations ) {
597 result = QRect( map(rect.topLeft()), map(rect.bottomRight()) ).normalize();
598 } else {
599 int x = qRound( _m11*rect.x() + _dx );
600 int y = qRound( _m22*rect.y() + _dy );
601 int w = qRound( _m11*rect.width() );
602 int h = qRound( _m22*rect.height() );
603 if ( w < 0 ) {
604 w = -w;
605 x -= w - 1;
606 }
607 if ( h < 0 ) {
608 h = -h;
609 y -= h - 1;
610 }
611 result = QRect( x, y, w, h );
612 }
613 } else {
614 result = QRegion( mapToPolygon( rect ) );
615 }
616 return result;
617
618}
619
620/*!
621 Returns the transformed rectangle \a rect as a polygon.
622
623 Polygons and rectangles behave slightly differently
624 when transformed (due to integer rounding), so
625 \c{matrix.map( QPointArray( rect ) )} is not always the same as
626 \c{matrix.mapToPolygon( rect )}.
627*/
628QPointArray QWMatrix::mapToPolygon( const QRect &rect ) const
629{
630 QPointArray a( 4 );
631 if ( qt_old_transformations ) {
632 a = QPointArray( rect );
633 return operator *( a );
634 }
635 double x[4], y[4];
636 if ( _m12 == 0.0F && _m21 == 0.0F ) {
637 x[0] = qRound( _m11*rect.x() + _dx );
638 y[0] = qRound( _m22*rect.y() + _dy );
639 double w = qRound( _m11*rect.width() );
640 double h = qRound( _m22*rect.height() );
641 if ( w < 0 ) {
642 w = -w;
643 x[0] -= w - 1.;
644 }
645 if ( h < 0 ) {
646 h = -h;
647 y[0] -= h - 1.;
648 }
649 x[1] = x[0]+w-1;
650 x[2] = x[1];
651 x[3] = x[0];
652 y[1] = y[0];
653 y[2] = y[0]+h-1;
654 y[3] = y[2];
655 } else {
656 MAPINT( rect.left(), rect.top(), x[0], y[0] );
657 MAPINT( rect.right() + 1, rect.top(), x[1], y[1] );
658 MAPINT( rect.right() + 1, rect.bottom() + 1, x[2], y[2] );
659 MAPINT( rect.left(), rect.bottom() + 1, x[3], y[3] );
660
661 /*
662 Including rectangles as we have are evil.
663
664 We now have a rectangle that is one pixel to wide and one to
665 high. the tranformed position of the top-left corner is
666 correct. All other points need some adjustments.
667
668 Doing this mathematically exact would force us to calculate some square roots,
669 something we don't want for the sake of speed.
670
671 Instead we use an approximation, that converts to the correct
672 answer when m12 -> 0 and m21 -> 0, and accept smaller
673 errors in the general transformation case.
674
675 The solution is to calculate the width and height of the
676 bounding rect, and scale the points 1/2/3 by (xp-x0)/xw pixel direction
677 to point 0.
678 */
679
680 double xmin = x[0];
681 double ymin = y[0];
682 double xmax = x[0];
683 double ymax = y[0];
684 int i;
685 for( i = 1; i< 4; i++ ) {
686 xmin = QMIN( xmin, x[i] );
687 ymin = QMIN( ymin, y[i] );
688 xmax = QMAX( xmax, x[i] );
689 ymax = QMAX( ymax, y[i] );
690 }
691 double w = xmax - xmin;
692 double h = ymax - ymin;
693
694 for( i = 1; i < 4; i++ ) {
695 x[i] -= (x[i] - x[0])/w;
696 y[i] -= (y[i] - y[0])/h;
697 }
698 }
699#if 0
700 int i;
701 for( i = 0; i< 4; i++ )
702 qDebug("coords(%d) = (%f/%f) (%d/%d)", i, x[i], y[i], qRound(x[i]), qRound(y[i]) );
703 qDebug( "width=%f, height=%f", sqrt( (x[1]-x[0])*(x[1]-x[0]) + (y[1]-y[0])*(y[1]-y[0]) ),
704 sqrt( (x[0]-x[3])*(x[0]-x[3]) + (y[0]-y[3])*(y[0]-y[3]) ) );
705#endif
706 // all coordinates are correctly, tranform to a pointarray
707 // (rounding to the next integer)
708 a.setPoints( 4, qRound( x[0] ), qRound( y[0] ),
709 qRound( x[1] ), qRound( y[1] ),
710 qRound( x[2] ), qRound( y[2] ),
711 qRound( x[3] ), qRound( y[3] ) );
712 return a;
713}
714
715/*!
716\internal
717*/
718QRegion QWMatrix::operator * (const QRegion &r ) const
719{
720 if ( isIdentity() )
721 return r;
722 QMemArray<QRect> rects = r.rects();
723 QRegion result;
724 register QRect *rect = rects.data();
725 register int i = rects.size();
726 if ( _m12 == 0.0F && _m21 == 0.0F ) {
727 // simple case, no rotation
728 while ( i ) {
729 int x = qRound( _m11*rect->x() + _dx );
730 int y = qRound( _m22*rect->y() + _dy );
731 int w = qRound( _m11*rect->width() );
732 int h = qRound( _m22*rect->height() );
733 if ( w < 0 ) {
734 w = -w;
735 x -= w-1;
736 }
737 if ( h < 0 ) {
738 h = -h;
739 y -= h-1;
740 }
741 *rect = QRect( x, y, w, h );
742 rect++;
743 i--;
744 }
745 result.setRects( rects.data(), rects.size() );
746 } else {
747 while ( i ) {
748 result |= operator *( *rect );
749 rect++;
750 i--;
751 }
752 }
753 return result;
754}
755
756/*!
757 Resets the matrix to an identity matrix.
758
759 All elements are set to zero, except \e m11 and \e m22 (scaling)
760 which are set to 1.
761
762 \sa isIdentity()
763*/
764
765void QWMatrix::reset()
766{
767 _m11 = _m22 = 1.0;
768 _m12 = _m21 = _dx = _dy = 0.0;
769}
770
771/*!
772 Returns TRUE if the matrix is the identity matrix; otherwise returns FALSE.
773
774 \sa reset()
775*/
776bool QWMatrix::isIdentity() const
777{
778 return _m11 == 1.0 && _m22 == 1.0 && _m12 == 0.0 && _m21 == 0.0
779 && _dx == 0.0 && _dy == 0.0;
780}
781
782/*!
783 Moves the coordinate system \a dx along the X-axis and \a dy along
784 the Y-axis.
785
786 Returns a reference to the matrix.
787
788 \sa scale(), shear(), rotate()
789*/
790
791QWMatrix &QWMatrix::translate( double dx, double dy )
792{
793 _dx += dx*_m11 + dy*_m21;
794 _dy += dy*_m22 + dx*_m12;
795 return *this;
796}
797
798/*!
799 Scales the coordinate system unit by \a sx horizontally and \a sy
800 vertically.
801
802 Returns a reference to the matrix.
803
804 \sa translate(), shear(), rotate()
805*/
806
807QWMatrix &QWMatrix::scale( double sx, double sy )
808{
809 _m11 *= sx;
810 _m12 *= sx;
811 _m21 *= sy;
812 _m22 *= sy;
813 return *this;
814}
815
816/*!
817 Shears the coordinate system by \a sh horizontally and \a sv
818 vertically.
819
820 Returns a reference to the matrix.
821
822 \sa translate(), scale(), rotate()
823*/
824
825QWMatrix &QWMatrix::shear( double sh, double sv )
826{
827 double tm11 = sv*_m21;
828 double tm12 = sv*_m22;
829 double tm21 = sh*_m11;
830 double tm22 = sh*_m12;
831 _m11 += tm11;
832 _m12 += tm12;
833 _m21 += tm21;
834 _m22 += tm22;
835 return *this;
836}
837
838const double deg2rad = 0.017453292519943295769; // pi/180
839
840/*!
841 Rotates the coordinate system \a a degrees counterclockwise.
842
843 Returns a reference to the matrix.
844
845 \sa translate(), scale(), shear()
846*/
847
848QWMatrix &QWMatrix::rotate( double a )
849{
850 double b = deg2rad*a; // convert to radians
851#if defined(Q_WS_X11)
852 double sina = qsincos(b,FALSE); // fast and convenient
853 double cosa = qsincos(b,TRUE);
854#else
855 double sina = sin(b);
856 double cosa = cos(b);
857#endif
858 double tm11 = cosa*_m11 + sina*_m21;
859 double tm12 = cosa*_m12 + sina*_m22;
860 double tm21 = -sina*_m11 + cosa*_m21;
861 double tm22 = -sina*_m12 + cosa*_m22;
862 _m11 = tm11; _m12 = tm12;
863 _m21 = tm21; _m22 = tm22;
864 return *this;
865}
866
867/*!
868 \fn bool QWMatrix::isInvertible() const
869
870 Returns TRUE if the matrix is invertible; otherwise returns FALSE.
871
872 \sa invert()
873*/
874
875/*!
876 \fn double QWMatrix::det() const
877
878 Returns the matrix's determinant.
879*/
880
881
882/*!
883 Returns the inverted matrix.
884
885 If the matrix is singular (not invertible), the identity matrix is
886 returned.
887
888 If \a invertible is not 0: the value of \a *invertible is set
889 to TRUE if the matrix is invertible; otherwise \a *invertible is
890 set to FALSE.
891
892 \sa isInvertible()
893*/
894
895QWMatrix QWMatrix::invert( bool *invertible ) const
896{
897 double determinant = det();
898 if ( determinant == 0.0 ) {
899 if ( invertible )
900 *invertible = FALSE; // singular matrix
901 QWMatrix defaultMatrix;
902 return defaultMatrix;
903 }
904 else { // invertible matrix
905 if ( invertible )
906 *invertible = TRUE;
907 double dinv = 1.0/determinant;
908 QWMatrix imatrix( (_m22*dinv), (-_m12*dinv),
909 (-_m21*dinv), ( _m11*dinv),
910 ((_m21*_dy - _m22*_dx)*dinv),
911 ((_m12*_dx - _m11*_dy)*dinv) );
912 return imatrix;
913 }
914}
915
916
917/*!
918 Returns TRUE if this matrix is equal to \a m; otherwise returns FALSE.
919*/
920
921bool QWMatrix::operator==( const QWMatrix &m ) const
922{
923 return _m11 == m._m11 &&
924 _m12 == m._m12 &&
925 _m21 == m._m21 &&
926 _m22 == m._m22 &&
927 _dx == m._dx &&
928 _dy == m._dy;
929}
930
931/*!
932 Returns TRUE if this matrix is not equal to \a m; otherwise returns FALSE.
933*/
934
935bool QWMatrix::operator!=( const QWMatrix &m ) const
936{
937 return _m11 != m._m11 ||
938 _m12 != m._m12 ||
939 _m21 != m._m21 ||
940 _m22 != m._m22 ||
941 _dx != m._dx ||
942 _dy != m._dy;
943}
944
945/*!
946 Returns the result of multiplying this matrix by matrix \a m.
947*/
948
949QWMatrix &QWMatrix::operator*=( const QWMatrix &m )
950{
951 double tm11 = _m11*m._m11 + _m12*m._m21;
952 double tm12 = _m11*m._m12 + _m12*m._m22;
953 double tm21 = _m21*m._m11 + _m22*m._m21;
954 double tm22 = _m21*m._m12 + _m22*m._m22;
955
956 double tdx = _dx*m._m11 + _dy*m._m21 + m._dx;
957 double tdy = _dx*m._m12 + _dy*m._m22 + m._dy;
958
959 _m11 = tm11; _m12 = tm12;
960 _m21 = tm21; _m22 = tm22;
961 _dx = tdx; _dy = tdy;
962 return *this;
963}
964
965/*!
966 \overload
967 \relates QWMatrix
968 Returns the product of \a m1 * \a m2.
969
970 Note that matrix multiplication is not commutative, i.e. a*b !=
971 b*a.
972*/
973
974QWMatrix operator*( const QWMatrix &m1, const QWMatrix &m2 )
975{
976 QWMatrix result = m1;
977 result *= m2;
978 return result;
979}
980
981/*****************************************************************************
982 QWMatrix stream functions
983 *****************************************************************************/
984#ifndef QT_NO_DATASTREAM
985/*!
986 \relates QWMatrix
987
988 Writes the matrix \a m to the stream \a s and returns a reference
989 to the stream.
990
991 \sa \link datastreamformat.html Format of the QDataStream operators \endlink
992*/
993
994QDataStream &operator<<( QDataStream &s, const QWMatrix &m )
995{
996 if ( s.version() == 1 )
997 s << (float)m.m11() << (float)m.m12() << (float)m.m21()
998 << (float)m.m22() << (float)m.dx() << (float)m.dy();
999 else
1000 s << m.m11() << m.m12() << m.m21() << m.m22()
1001 << m.dx() << m.dy();
1002 return s;
1003}
1004
1005/*!
1006 \relates QWMatrix
1007
1008 Reads the matrix \a m from the stream \a s and returns a reference
1009 to the stream.
1010
1011 \sa \link datastreamformat.html Format of the QDataStream operators \endlink
1012*/
1013
1014QDataStream &operator>>( QDataStream &s, QWMatrix &m )
1015{
1016 if ( s.version() == 1 ) {
1017 float m11, m12, m21, m22, dx, dy;
1018 s >> m11; s >> m12; s >> m21; s >> m22;
1019 s >> dx; s >> dy;
1020 m.setMatrix( m11, m12, m21, m22, dx, dy );
1021 }
1022 else {
1023 double m11, m12, m21, m22, dx, dy;
1024 s >> m11; s >> m12; s >> m21; s >> m22;
1025 s >> dx; s >> dy;
1026 m.setMatrix( m11, m12, m21, m22, dx, dy );
1027 }
1028 return s;
1029}
1030#endif // QT_NO_DATASTREAM
1031
1032#endif // QT_NO_WMATRIX
1033
Note: See TracBrowser for help on using the repository browser.