diff options
Diffstat (limited to 'tqtinterface/qt4/src/kernel/tqwmatrix.cpp~')
| -rw-r--r-- | tqtinterface/qt4/src/kernel/tqwmatrix.cpp~ | 1204 | 
1 files changed, 1204 insertions, 0 deletions
| diff --git a/tqtinterface/qt4/src/kernel/tqwmatrix.cpp~ b/tqtinterface/qt4/src/kernel/tqwmatrix.cpp~ new file mode 100644 index 0000000..f95b660 --- /dev/null +++ b/tqtinterface/qt4/src/kernel/tqwmatrix.cpp~ @@ -0,0 +1,1204 @@ +/**************************************************************************** +** +** Implementation of TQWMatrix class +** +** Created : 941020 +** +** Copyright (C) 2010 Timothy Pearson and (C) 1992-2008 Trolltech ASA. +** +** This file is part of the kernel module of the TQt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free TQt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.TQPL +** included in the packaging of this file.  Licensees holding valid TQt +** Commercial licenses may use this file in accordance with the TQt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "tqwmatrix.h" +#include "tqdatastream.h" +#include "tqregion.h" +#if defined(TQ_WS_X11) +double qsincos( double, bool calcCos );		// defined in qpainter_x11.cpp +#else +#include <math.h> +#endif + +#include <limits.h> + +#ifndef TQT_NO_WMATRIX + +#ifdef USE_QT4 + +// some defines to inline some code +#define MAPDOUBLE( x, y, nx, ny ) \ +{ \ +    double fx = x; \ +    double fy = y; \ +    nx = m11()*fx + m21()*fy + dx(); \ +    ny = m12()*fx + m22()*fy + dy(); \ +} + +#define MAPINT( x, y, nx, ny ) \ +{ \ +    double fx = x; \ +    double fy = y; \ +    nx = tqRound(m11()*fx + m21()*fy + dx()); \ +    ny = tqRound(m12()*fx + m22()*fy + dy()); \ +} + +struct TQWMDoublePoint { +    double x; +    double y; +}; + +bool qt_old_transformations = TRUE; + +// TQWMatrix TQWMatrix::invert(bool *invertible=0) { +// 	return convertFromQMatrix(inverted(invertible)); +// } + +/*! +    Sets the transformation mode that TQWMatrix and painter +    transformations use to \a m. + +    \sa TQWMatrix::TransformationMode +*/ +void TQWMatrix::setTransformationMode( TQWMatrix::TransformationMode m ) +{ +	printf("[WARNING] TQWMatrix::setTransformationMode has no effect!\n\r"); + +	if ( m == TQWMatrix::Points ) +		qt_old_transformations = TRUE; +	else +		qt_old_transformations = FALSE; +} + + +/*! +    Returns the current transformation mode. + +    \sa TQWMatrix::TransformationMode +*/ +TQWMatrix::TransformationMode TQWMatrix::transformationMode() +{ +	return (qt_old_transformations ? TQWMatrix::Points : TQWMatrix::Areas ); +} + +/*! +  \internal +*/ +TQPointArray TQWMatrix::operator *( const TQPointArray &a ) const +{ +    if( qt_old_transformations ) { +	TQPointArray result = a.copy(); +	int x, y; +	for ( int i=0; i<(int)result.size(); i++ ) { +	    result.point( i, &x, &y ); +	    MAPINT( x, y, x, y ); +	    result.setPoint( i, x, y ); +	} +	return result; +    } else { +	int size = a.size(); +	int i; +	TQMemArray<TQWMDoublePoint> p( size ); +	TQPoint *da = TQT_TQPOINT_CONST(a.data()); +	TQWMDoublePoint *dp = p.data(); +	double xmin = INT_MAX; +	double ymin = xmin; +	double xmax = INT_MIN; +	double ymax = xmax; +	int xminp = 0; +	int yminp = 0; +	for( i = 0; i < size; i++ ) { +	    dp[i].x = da[i].x(); +	    dp[i].y = da[i].y(); +	    if ( dp[i].x < xmin ) { +		xmin = dp[i].x; +		xminp = i; +	    } +	    if ( dp[i].y < ymin ) { +		ymin = dp[i].y; +		yminp = i; +	    } +	    xmax = TQMAX( xmax, dp[i].x ); +	    ymax = TQMAX( ymax, dp[i].y ); +	} +	double w = TQMAX( xmax - xmin, 1 ); +	double h = TQMAX( ymax - ymin, 1 ); +	for( i = 0; i < size; i++ ) { +	    dp[i].x += (dp[i].x - xmin)/w; +	    dp[i].y += (dp[i].y - ymin)/h; +	    MAPDOUBLE( dp[i].x, dp[i].y, dp[i].x, dp[i].y ); +	} + +	// now apply correction back for transformed values... +	xmin = INT_MAX; +	ymin = xmin; +	xmax = INT_MIN; +	ymax = xmax; +	for( i = 0; i < size; i++ ) { +	    xmin = TQMIN( xmin, dp[i].x ); +	    ymin = TQMIN( ymin, dp[i].y ); +	    xmax = TQMAX( xmax, dp[i].x ); +	    ymax = TQMAX( ymax, dp[i].y ); +	} +	w = TQMAX( xmax - xmin, 1 ); +	h = TQMAX( ymax - ymin, 1 ); + +	TQPointArray result( size ); +	TQPoint *dr = TQT_TQPOINT(result.data()); +	for( i = 0; i < size; i++ ) { +	    dr[i].setX( tqRound( dp[i].x - (dp[i].x - dp[xminp].x)/w ) ); +	    dr[i].setY( tqRound( dp[i].y - (dp[i].y - dp[yminp].y)/h ) ); +	} +	return result; +    } +} + +/*! +    Returns the result of multiplying this matrix by matrix \a m. +*/ + +TQWMatrix &TQWMatrix::operator*=( const TQWMatrix &m ) +{ +    double tm11 = m11()*m.m11() + m12()*m.m21(); +    double tm12 = m11()*m.m12() + m12()*m.m22(); +    double tm21 = m21()*m.m11() + m22()*m.m21(); +    double tm22 = m21()*m.m12() + m22()*m.m22(); + +    double tdx  = dx()*m.m11()  + dy()*m.m21() + m.dx(); +    double tdy =  dx()*m.m12()  + dy()*m.m22() + m.dy(); + +    *this = TQWMatrix(tm11, tm12, tm21, tm22, tdx, tdy); + +    return *this; +} + +/*! +    \overload +    \relates TQWMatrix +    Returns the product of \a m1 * \a m2. + +    Note that matrix multiplication is not commutative, i.e. a*b != +    b*a. +*/ + +TQWMatrix operator*( const TQWMatrix &m1, const TQWMatrix &m2 ) +{ +    TQWMatrix result = m1; +    result *= m2; +    return result; +} + +#else // USE_QT4 + +/*! +    \class TQWMatrix tqwmatrix.h +    \brief The TQWMatrix class specifies 2D transformations of a +    coordinate system. + +    \ingroup graphics +    \ingroup images + +    The standard coordinate system of a \link TQPaintDevice paint +    tqdevice\endlink has the origin located at the top-left position. X +    values increase to the right; Y values increase downward. + +    This coordinate system is the default for the TQPainter, which +    renders graphics in a paint tqdevice. A user-defined coordinate +    system can be specified by setting a TQWMatrix for the painter. + +    Example: +    \code +	MyWidget::paintEvent( TQPaintEvent * ) +	{ +            TQPainter p;                      // our painter +            TQWMatrix m;                      // our transformation matrix +            m.rotate( 22.5 );                // rotated coordinate system +            p.begin( this );                 // start painting +            p.setWorldMatrix( m );           // use rotated coordinate system +            p.drawText( 30,20, "detator" );  // draw rotated text at 30,20 +            p.end();                         // painting done +	} +    \endcode + +    A matrix specifies how to translate, scale, shear or rotate the +    graphics; the actual transformation is performed by the drawing +    routines in TQPainter and by TQPixmap::xForm(). + +    The TQWMatrix class tqcontains a 3x3 matrix of the form: +    <table align=center border=1 cellpadding=1 cellspacing=0> +    <tr align=center><td>m11</td><td>m12</td><td> 0 </td></tr> +    <tr align=center><td>m21</td><td>m22</td><td> 0 </td></tr> +    <tr align=center><td>dx</td> <td>dy</td> <td> 1 </td></tr> +    </table> + +    A matrix transforms a point in the plane to another point: +    \code +	x' = m11*x + m21*y + dx +	y' = m22*y + m12*x + dy +    \endcode + +    The point \e (x, y) is the original point, and \e (x', y') is the +    transformed point. \e (x', y') can be transformed back to \e (x, +    y) by performing the same operation on the \link +    TQWMatrix::invert() inverted matrix\endlink. + +    The elements \e dx and \e dy specify horizontal and vertical +    translation. The elements \e m11 and \e m22 specify horizontal and +    vertical scaling. The elements \e m12 and \e m21 specify +    horizontal and vertical shearing. + +    The identity matrix has \e m11 and \e m22 set to 1; all others are +    set to 0. This matrix maps a point to itself. + +    Translation is the simplest transformation. Setting \e dx and \e +    dy will move the coordinate system \e dx units along the X axis +    and \e dy units along the Y axis. + +    Scaling can be done by setting \e m11 and \e m22. For example, +    setting \e m11 to 2 and \e m22 to 1.5 will double the height and +    increase the width by 50%. + +    Shearing is controlled by \e m12 and \e m21. Setting these +    elements to values different from zero will twist the coordinate +    system. + +    Rotation is achieved by carefully setting both the shearing +    factors and the scaling factors. The TQWMatrix also has a function +    that sets \link rotate() rotation \endlink directly. + +    TQWMatrix lets you combine transformations like this: +    \code +	TQWMatrix m;           // identity matrix +	m.translate(10, -20); // first translate (10,-20) +	m.rotate(25);         // then rotate 25 degrees +	m.scale(1.2, 0.7);    // finally scale it +    \endcode + +    Here's the same example using basic matrix operations: +    \code +	double a    = pi/180 * 25;         // convert 25 to radians +	double sina = sin(a); +	double cosa = cos(a); +	TQWMatrix m1(1, 0, 0, 1, 10, -20);  // translation matrix +	TQWMatrix m2( cosa, sina,           // rotation matrix +		    -sina, cosa, 0, 0 ); +	TQWMatrix m3(1.2, 0, 0, 0.7, 0, 0); // scaling matrix +	TQWMatrix m; +	m = m3 * m2 * m1;                  // combine all transformations +    \endcode + +    \l TQPainter has functions to translate, scale, shear and rotate the +    coordinate system without using a TQWMatrix. Although these +    functions are very convenient, it can be more efficient to build a +    TQWMatrix and call TQPainter::setWorldMatrix() if you want to perform +    more than a single transform operation. + +    \sa TQPainter::setWorldMatrix(), TQPixmap::xForm() +*/ + +bool qt_old_transformations = TRUE; + +/*! +    \enum TQWMatrix::TransformationMode + +    \keyword transformation matrix + +    TQWMatrix offers two transformation modes. Calculations can either +    be done in terms of points (Points mode, the default), or in +    terms of area (Area mode). + +    In Points mode the transformation is applied to the points that +    mark out the tqshape's bounding line. In Areas mode the +    transformation is applied in such a way that the area of the +    contained region is correctly transformed under the matrix. + +    \value Points transformations are applied to the tqshape's points. +    \value Areas transformations are applied (e.g. to the width and +    height) so that the area is transformed. + +    Example: + +    Suppose we have a rectangle, +    \c{TQRect( 10, 20, 30, 40 )} and a transformation matrix +    \c{TQWMatrix( 2, 0, 0, 2, 0, 0 )} to double the rectangle's size. + +    In Points mode, the matrix will transform the top-left (10,20) and +    the bottom-right (39,59) points producing a rectangle with its +    top-left point at (20,40) and its bottom-right point at (78,118), +    i.e. with a width of 59 and a height of 79. + +    In Areas mode, the matrix will transform the top-left point in +    the same way as in Points mode to (20/40), and double the width +    and height, so the bottom-right will become (69,99), i.e. a width +    of 60 and a height of 80. + +    Because integer arithmetic is used (for speed), rounding +    differences mean that the modes will produce slightly different +    results given the same tqshape and the same transformation, +    especially when scaling up. This also means that some operations +    are not commutative. + +    Under Points mode, \c{matrix * ( region1 | region2 )} is not equal to +    \c{matrix * region1 | matrix * region2}. Under Area mode, \c{matrix * +    (pointarray[i])} is not neccesarily equal to +    \c{(matrix * pointarry)[i]}. + +    \img xform.png Comparison of Points and Areas TransformationModes +*/ + +/*! +    Sets the transformation mode that TQWMatrix and painter +    transformations use to \a m. + +    \sa TQWMatrix::TransformationMode +*/ +void TQWMatrix::setTransformationMode( TQWMatrix::TransformationMode m ) +{ +    if ( m == TQWMatrix::Points ) +	qt_old_transformations = TRUE; +    else +	qt_old_transformations = FALSE; +} + + +/*! +    Returns the current transformation mode. + +    \sa TQWMatrix::TransformationMode +*/ +TQWMatrix::TransformationMode TQWMatrix::transformationMode() +{ +    return (qt_old_transformations ? TQWMatrix::Points : TQWMatrix::Areas ); +} + + +// some defines to inline some code +#define MAPDOUBLE( x, y, nx, ny ) \ +{ \ +    double fx = x; \ +    double fy = y; \ +    nx = _m11*fx + _m21*fy + _dx; \ +    ny = _m12*fx + _m22*fy + _dy; \ +} + +#define MAPINT( x, y, nx, ny ) \ +{ \ +    double fx = x; \ +    double fy = y; \ +    nx = tqRound(_m11*fx + _m21*fy + _dx); \ +    ny = tqRound(_m12*fx + _m22*fy + _dy); \ +} + +/***************************************************************************** +  TQWMatrix member functions + *****************************************************************************/ + +/*! +    Constructs an identity matrix. All elements are set to zero except +    \e m11 and \e m22 (scaling), which are set to 1. +*/ + +TQWMatrix::TQWMatrix() +{ +    _m11 = _m22 = 1.0; +    _m12 = _m21 = _dx = _dy = 0.0; +} + +/*! +    Constructs a matrix with the elements, \a m11, \a m12, \a m21, \a +    m22, \a dx and \a dy. +*/ + +TQWMatrix::TQWMatrix( double m11, double m12, double m21, double m22, +		    double dx, double dy ) +{ +    _m11 = m11;	 _m12 = m12; +    _m21 = m21;	 _m22 = m22; +    _dx	 = dx;	 _dy  = dy; +} + + +/*! +    Sets the matrix elements to the specified values, \a m11, \a m12, +    \a m21, \a m22, \a dx and \a dy. +*/ + +void TQWMatrix::setMatrix( double m11, double m12, double m21, double m22, +			  double dx, double dy ) +{ +    _m11 = m11;	 _m12 = m12; +    _m21 = m21;	 _m22 = m22; +    _dx	 = dx;	 _dy  = dy; +} + + +/*! +    \fn double TQWMatrix::m11() const + +    Returns the X scaling factor. +*/ + +/*! +    \fn double TQWMatrix::m12() const + +    Returns the vertical shearing factor. +*/ + +/*! +    \fn double TQWMatrix::m21() const + +    Returns the horizontal shearing factor. +*/ + +/*! +    \fn double TQWMatrix::m22() const + +    Returns the Y scaling factor. +*/ + +/*! +    \fn double TQWMatrix::dx() const + +    Returns the horizontal translation. +*/ + +/*! +    \fn double TQWMatrix::dy() const + +    Returns the vertical translation. +*/ + + +/*! +    \overload + +    Transforms ( \a x, \a y ) to ( \a *tx, \a *ty ) using the +    following formulae: + +    \code +	*tx = m11*x + m21*y + dx +	*ty = m22*y + m12*x + dy +    \endcode +*/ + +void TQWMatrix::map( double x, double y, double *tx, double *ty ) const +{ +    MAPDOUBLE( x, y, *tx, *ty ); +} + +/*! +    Transforms ( \a x, \a y ) to ( \a *tx, \a *ty ) using the formulae: + +    \code +	*tx = m11*x + m21*y + dx  (rounded to the nearest integer) +	*ty = m22*y + m12*x + dy  (rounded to the nearest integer) +    \endcode +*/ + +void TQWMatrix::map( int x, int y, int *tx, int *ty ) const +{ +    MAPINT( x, y, *tx, *ty ); +} + +/*! +    \fn TQPoint TQWMatrix::map( const TQPoint &p ) const + +    \overload + +    Transforms \a p to using the formulae: + +    \code +	retx = m11*px + m21*py + dx  (rounded to the nearest integer) +	rety = m22*py + m12*px + dy  (rounded to the nearest integer) +    \endcode +*/ + +/*! +  \fn TQRect TQWMatrix::map( const TQRect &r ) const + +  \obsolete + +  Please use \l TQWMatrix::mapRect() instead. + +  Note that this method does return the bounding rectangle of the \a r, when +  shearing or rotations are used. +*/ + +/*! +    \fn TQPointArray TQWMatrix::map( const TQPointArray &a ) const + +    \overload + +    Returns the point array \a a transformed by calling map for each point. +*/ + + +/*! +    \fn TQRegion TQWMatrix::map( const TQRegion &r ) const + +    \overload + +    Transforms the region \a r. + +    Calling this method can be rather expensive, if rotations or +    shearing are used. +*/ + +/*! +    \fn TQRegion TQWMatrix::mapToRegion( const TQRect &rect ) const + +    Returns the transformed rectangle \a rect. + +    A rectangle which has been rotated or sheared may result in a +    non-rectangular region being returned. + +    Calling this method can be expensive, if rotations or shearing are +    used. If you just need to know the bounding rectangle of the +    returned region, use mapRect() which is a lot faster than this +    function. + +    \sa TQWMatrix::mapRect() +*/ + + +/*! +    Returns the transformed rectangle \a rect. + +    The bounding rectangle is returned if rotation or shearing has +    been specified. + +    If you need to know the exact region \a rect maps to use \l +    operator*(). + +    \sa operator*() +*/ + +TQRect TQWMatrix::mapRect( const TQRect &rect ) const +{ +    TQRect result; +    if( qt_old_transformations ) { +	if ( _m12 == 0.0F && _m21 == 0.0F ) { +	    result = TQRect( map(rect.topLeft()), map(rect.bottomRight()) ).normalize(); +	} else { +	    TQPointArray a( rect ); +	    a = map( a ); +	    result = a.boundingRect(); +	} +    } else { +	if ( _m12 == 0.0F && _m21 == 0.0F ) { +	    int x = tqRound( _m11*rect.x() + _dx ); +	    int y = tqRound( _m22*rect.y() + _dy ); +	    int w = tqRound( _m11*rect.width() ); +	    int h = tqRound( _m22*rect.height() ); +	    if ( w < 0 ) { +		w = -w; +		x -= w-1; +	    } +	    if ( h < 0 ) { +		h = -h; +		y -= h-1; +	    } +	    result = TQRect( x, y, w, h ); +	} else { + +	    // see mapToPolygon for explanations of the algorithm. +	    double x0, y0; +	    double x, y; +	    MAPDOUBLE( rect.left(), rect.top(), x0, y0 ); +	    double xmin = x0; +	    double ymin = y0; +	    double xmax = x0; +	    double ymax = y0; +	    MAPDOUBLE( rect.right() + 1, rect.top(), x, y ); +	    xmin = TQMIN( xmin, x ); +	    ymin = TQMIN( ymin, y ); +	    xmax = TQMAX( xmax, x ); +	    ymax = TQMAX( ymax, y ); +	    MAPDOUBLE( rect.right() + 1, rect.bottom() + 1, x, y ); +	    xmin = TQMIN( xmin, x ); +	    ymin = TQMIN( ymin, y ); +	    xmax = TQMAX( xmax, x ); +	    ymax = TQMAX( ymax, y ); +	    MAPDOUBLE( rect.left(), rect.bottom() + 1, x, y ); +	    xmin = TQMIN( xmin, x ); +	    ymin = TQMIN( ymin, y ); +	    xmax = TQMAX( xmax, x ); +	    ymax = TQMAX( ymax, y ); +	    double w = xmax - xmin; +	    double h = ymax - ymin; +	    xmin -= ( xmin - x0 ) / w; +	    ymin -= ( ymin - y0 ) / h; +	    xmax -= ( xmax - x0 ) / w; +	    ymax -= ( ymax - y0 ) / h; +	    result = TQRect( tqRound(xmin), tqRound(ymin), tqRound(xmax)-tqRound(xmin)+1, tqRound(ymax)-tqRound(ymin)+1 ); +	} +    } +    return result; +} + + +/*! +  \internal +*/ +TQPoint TQWMatrix::operator *( const TQPoint &p ) const +{ +    double fx = p.x(); +    double fy = p.y(); +    return TQPoint( tqRound(_m11*fx + _m21*fy + _dx), +		   tqRound(_m12*fx + _m22*fy + _dy) ); +} + + +struct TQWMDoublePoint { +    double x; +    double y; +}; + +/*! +  \internal +*/ +TQPointArray TQWMatrix::operator *( const TQPointArray &a ) const +{ +    if( qt_old_transformations ) { +	TQPointArray result = a.copy(); +	int x, y; +	for ( int i=0; i<(int)result.size(); i++ ) { +	    result.point( i, &x, &y ); +	    MAPINT( x, y, x, y ); +	    result.setPoint( i, x, y ); +	} +	return result; +    } else { +	int size = a.size(); +	int i; +	TQMemArray<TQWMDoublePoint> p( size ); +	TQPoint *da = a.data(); +	TQWMDoublePoint *dp = p.data(); +	double xmin = INT_MAX; +	double ymin = xmin; +	double xmax = INT_MIN; +	double ymax = xmax; +	int xminp = 0; +	int yminp = 0; +	for( i = 0; i < size; i++ ) { +	    dp[i].x = da[i].x(); +	    dp[i].y = da[i].y(); +	    if ( dp[i].x < xmin ) { +		xmin = dp[i].x; +		xminp = i; +	    } +	    if ( dp[i].y < ymin ) { +		ymin = dp[i].y; +		yminp = i; +	    } +	    xmax = TQMAX( xmax, dp[i].x ); +	    ymax = TQMAX( ymax, dp[i].y ); +	} +	double w = TQMAX( xmax - xmin, 1 ); +	double h = TQMAX( ymax - ymin, 1 ); +	for( i = 0; i < size; i++ ) { +	    dp[i].x += (dp[i].x - xmin)/w; +	    dp[i].y += (dp[i].y - ymin)/h; +	    MAPDOUBLE( dp[i].x, dp[i].y, dp[i].x, dp[i].y ); +	} + +	// now apply correction back for transformed values... +	xmin = INT_MAX; +	ymin = xmin; +	xmax = INT_MIN; +	ymax = xmax; +	for( i = 0; i < size; i++ ) { +	    xmin = TQMIN( xmin, dp[i].x ); +	    ymin = TQMIN( ymin, dp[i].y ); +	    xmax = TQMAX( xmax, dp[i].x ); +	    ymax = TQMAX( ymax, dp[i].y ); +	} +	w = TQMAX( xmax - xmin, 1 ); +	h = TQMAX( ymax - ymin, 1 ); + +	TQPointArray result( size ); +	TQPoint *dr = result.data(); +	for( i = 0; i < size; i++ ) { +	    dr[i].setX( tqRound( dp[i].x - (dp[i].x - dp[xminp].x)/w ) ); +	    dr[i].setY( tqRound( dp[i].y - (dp[i].y - dp[yminp].y)/h ) ); +	} +	return result; +    } +} + +/*! +\internal +*/ +TQRegion TQWMatrix::operator * (const TQRect &rect ) const +{ +    TQRegion result; +    if ( isIdentity() ) { +	result = rect; +    } else if ( _m12 == 0.0F && _m21 == 0.0F ) { +	if( qt_old_transformations ) { +	    result = TQRect( map(rect.topLeft()), map(rect.bottomRight()) ).normalize(); +	} else { +	    int x = tqRound( _m11*rect.x() + _dx ); +	    int y = tqRound( _m22*rect.y() + _dy ); +	    int w = tqRound( _m11*rect.width() ); +	    int h = tqRound( _m22*rect.height() ); +	    if ( w < 0 ) { +		w = -w; +		x -= w - 1; +	    } +	    if ( h < 0 ) { +		h = -h; +		y -= h - 1; +	    } +	    result = TQRect( x, y, w, h ); +	} +    } else { +	result = TQRegion( mapToPolygon( rect ) ); +    } +    return result; + +} + +/*! +    Returns the transformed rectangle \a rect as a polygon. + +    Polygons and rectangles behave slightly differently +    when transformed (due to integer rounding), so +    \c{matrix.map( TQPointArray( rect ) )} is not always the same as +    \c{matrix.mapToPolygon( rect )}. +*/ +TQPointArray TQWMatrix::mapToPolygon( const TQRect &rect ) const +{ +    TQPointArray a( 4 ); +    if ( qt_old_transformations ) { +	a = TQPointArray( rect ); +	return operator *( a ); +    } +    double x[4], y[4]; +    if ( _m12 == 0.0F && _m21 == 0.0F ) { +	x[0] = tqRound( _m11*rect.x() + _dx ); +        y[0] = tqRound( _m22*rect.y() + _dy ); +	double w = tqRound( _m11*rect.width() ); +	double h = tqRound( _m22*rect.height() ); +	if ( w < 0 ) { +	    w = -w; +	    x[0] -= w - 1.; +	} +	if ( h < 0 ) { +	    h = -h; +	    y[0] -= h - 1.; +	} +	x[1] = x[0]+w-1; +	x[2] = x[1]; +	x[3] = x[0]; +	y[1] = y[0]; +	y[2] = y[0]+h-1; +	y[3] = y[2]; +    } else { +	MAPINT( rect.left(), rect.top(), x[0], y[0] ); +	MAPINT( rect.right() + 1, rect.top(), x[1], y[1] ); +	MAPINT( rect.right() + 1, rect.bottom() + 1, x[2], y[2] ); +	MAPINT( rect.left(), rect.bottom() + 1, x[3], y[3] ); + +	/* +	Including rectangles as we have are evil. + +        We now have a rectangle that is one pixel to wide and one to +        high. the tranformed position of the top-left corner is +        correct. All other points need some adjustments. + +	Doing this mathematically exact would force us to calculate some square roots, +	something we don't want for the sake of speed. + +        Instead we use an approximation, that converts to the correct +        answer when m12 -> 0 and m21 -> 0, and accept smaller +        errors in the general transformation case. + +        The solution is to calculate the width and height of the +        bounding rect, and scale the points 1/2/3 by (xp-x0)/xw pixel direction +        to point 0. +        */ + +	double xmin = x[0]; +	double ymin = y[0]; +	double xmax = x[0]; +	double ymax = y[0]; +	int i; +	for( i = 1; i< 4; i++ ) { +	    xmin = TQMIN( xmin, x[i] ); +	    ymin = TQMIN( ymin, y[i] ); +	    xmax = TQMAX( xmax, x[i] ); +	    ymax = TQMAX( ymax, y[i] ); +	} +	double w = xmax - xmin; +	double h = ymax - ymin; + +	for( i = 1; i < 4; i++ ) { +	    x[i] -= (x[i] - x[0])/w; +	    y[i] -= (y[i] - y[0])/h; +	} +    } +#if 0 +    int i; +    for( i = 0; i< 4; i++ ) +	qDebug("coords(%d) = (%f/%f) (%d/%d)", i, x[i], y[i], tqRound(x[i]), tqRound(y[i]) ); +    qDebug( "width=%f, height=%f", sqrt( (x[1]-x[0])*(x[1]-x[0]) + (y[1]-y[0])*(y[1]-y[0]) ), +	    sqrt( (x[0]-x[3])*(x[0]-x[3]) + (y[0]-y[3])*(y[0]-y[3]) ) ); +#endif +    // all coordinates are correctly, tranform to a pointarray +    // (rounding to the next integer) +    a.setPoints( 4, tqRound( x[0] ), tqRound( y[0] ), +		 tqRound( x[1] ), tqRound( y[1] ), +		 tqRound( x[2] ), tqRound( y[2] ), +		 tqRound( x[3] ), tqRound( y[3] ) ); +    return a; +} + +/*! +\internal +*/ +TQRegion TQWMatrix::operator * (const TQRegion &r ) const +{ +    if ( isIdentity() ) +	return r; +    TQMemArray<TQRect> rects = r.rects(); +    TQRegion result; +    register TQRect *rect = rects.data(); +    register int i = rects.size(); +    if ( _m12 == 0.0F && _m21 == 0.0F && _m11 > 1.0F && _m22 > 1.0F ) { +	// simple case, no rotation +	while ( i ) { +	    int x = tqRound( _m11*rect->x() + _dx ); +	    int y = tqRound( _m22*rect->y() + _dy ); +	    int w = tqRound( _m11*rect->width() ); +	    int h = tqRound( _m22*rect->height() ); +	    if ( w < 0 ) { +		w = -w; +		x -= w-1; +	    } +	    if ( h < 0 ) { +		h = -h; +		y -= h-1; +	    } +	    *rect = TQRect( x, y, w, h ); +	    rect++; +	    i--; +	} +	result.setRects( rects.data(), rects.size() ); +    } else { +	while ( i ) { +	    result |= operator *( *rect ); +	    rect++; +	    i--; +	} +    } +    return result; +} + +/*! +    Resets the matrix to an identity matrix. + +    All elements are set to zero, except \e m11 and \e m22 (scaling) +    which are set to 1. + +    \sa isIdentity() +*/ + +void TQWMatrix::reset() +{ +    _m11 = _m22 = 1.0; +    _m12 = _m21 = _dx = _dy = 0.0; +} + +/*! +    Returns TRUE if the matrix is the identity matrix; otherwise returns FALSE. + +    \sa reset() +*/ +bool TQWMatrix::isIdentity() const +{ +    return _m11 == 1.0 && _m22 == 1.0 && _m12 == 0.0 && _m21 == 0.0 +	&& _dx == 0.0 && _dy == 0.0; +} + +/*! +    Moves the coordinate system \a dx along the X-axis and \a dy along +    the Y-axis. + +    Returns a reference to the matrix. + +    \sa scale(), shear(), rotate() +*/ + +TQWMatrix &TQWMatrix::translate( double dx, double dy ) +{ +    _dx += dx*_m11 + dy*_m21; +    _dy += dy*_m22 + dx*_m12; +    return *this; +} + +/*! +    Scales the coordinate system unit by \a sx horizontally and \a sy +    vertically. + +    Returns a reference to the matrix. + +    \sa translate(), shear(), rotate() +*/ + +TQWMatrix &TQWMatrix::scale( double sx, double sy ) +{ +    _m11 *= sx; +    _m12 *= sx; +    _m21 *= sy; +    _m22 *= sy; +    return *this; +} + +/*! +    Shears the coordinate system by \a sh horizontally and \a sv +    vertically. + +    Returns a reference to the matrix. + +    \sa translate(), scale(), rotate() +*/ + +TQWMatrix &TQWMatrix::shear( double sh, double sv ) +{ +    double tm11 = sv*_m21; +    double tm12 = sv*_m22; +    double tm21 = sh*_m11; +    double tm22 = sh*_m12; +    _m11 += tm11; +    _m12 += tm12; +    _m21 += tm21; +    _m22 += tm22; +    return *this; +} + +const double deg2rad = 0.017453292519943295769;	// pi/180 + +/*! +    Rotates the coordinate system \a a degrees counterclockwise. + +    Returns a reference to the matrix. + +    \sa translate(), scale(), shear() +*/ + +TQWMatrix &TQWMatrix::rotate( double a ) +{ +    double b = deg2rad*a;			// convert to radians +#if defined(TQ_WS_X11) +    double sina = qsincos(b,FALSE);		// fast and convenient +    double cosa = qsincos(b,TRUE); +#else +    double sina = sin(b); +    double cosa = cos(b); +#endif +    double tm11 = cosa*_m11 + sina*_m21; +    double tm12 = cosa*_m12 + sina*_m22; +    double tm21 = -sina*_m11 + cosa*_m21; +    double tm22 = -sina*_m12 + cosa*_m22; +    _m11 = tm11; _m12 = tm12; +    _m21 = tm21; _m22 = tm22; +    return *this; +} + +/*! +    \fn bool TQWMatrix::isInvertible() const + +    Returns TRUE if the matrix is invertible; otherwise returns FALSE. + +    \sa invert() +*/ + +/*! +    \fn double TQWMatrix::det() const + +    Returns the matrix's determinant. +*/ + + +/*! +    Returns the inverted matrix. + +    If the matrix is singular (not invertible), the identity matrix is +    returned. + +    If \a invertible is not 0: the value of \a *invertible is set +    to TRUE if the matrix is invertible; otherwise \a *invertible is +    set to FALSE. + +    \sa isInvertible() +*/ + +TQWMatrix TQWMatrix::invert( bool *invertible ) const +{ +    double determinant = det(); +    if ( determinant == 0.0 ) { +	if ( invertible ) +	    *invertible = FALSE;		// singular matrix +	TQWMatrix defaultMatrix; +	return defaultMatrix; +    } +    else {					// invertible matrix +	if ( invertible ) +	    *invertible = TRUE; +	double dinv = 1.0/determinant; +	TQWMatrix imatrix( (_m22*dinv),	(-_m12*dinv), +			  (-_m21*dinv), ( _m11*dinv), +			  ((_m21*_dy - _m22*_dx)*dinv), +			  ((_m12*_dx - _m11*_dy)*dinv) ); +	return imatrix; +    } +} + + +/*! +    Returns TRUE if this matrix is equal to \a m; otherwise returns FALSE. +*/ + +bool TQWMatrix::operator==( const TQWMatrix &m ) const +{ +    return _m11 == m._m11 && +	   _m12 == m._m12 && +	   _m21 == m._m21 && +	   _m22 == m._m22 && +	   _dx == m._dx && +	   _dy == m._dy; +} + +/*! +    Returns TRUE if this matrix is not equal to \a m; otherwise returns FALSE. +*/ + +bool TQWMatrix::operator!=( const TQWMatrix &m ) const +{ +    return _m11 != m._m11 || +	   _m12 != m._m12 || +	   _m21 != m._m21 || +	   _m22 != m._m22 || +	   _dx != m._dx || +	   _dy != m._dy; +} + +/*! +    Returns the result of multiplying this matrix by matrix \a m. +*/ + +TQWMatrix &TQWMatrix::operator*=( const TQWMatrix &m ) +{ +    double tm11 = _m11*m._m11 + _m12*m._m21; +    double tm12 = _m11*m._m12 + _m12*m._m22; +    double tm21 = _m21*m._m11 + _m22*m._m21; +    double tm22 = _m21*m._m12 + _m22*m._m22; + +    double tdx  = _dx*m._m11  + _dy*m._m21 + m._dx; +    double tdy =  _dx*m._m12  + _dy*m._m22 + m._dy; + +    _m11 = tm11; _m12 = tm12; +    _m21 = tm21; _m22 = tm22; +    _dx = tdx; _dy = tdy; +    return *this; +} + +/*! +    \overload +    \relates TQWMatrix +    Returns the product of \a m1 * \a m2. + +    Note that matrix multiplication is not commutative, i.e. a*b != +    b*a. +*/ + +TQWMatrix operator*( const TQWMatrix &m1, const TQWMatrix &m2 ) +{ +    TQWMatrix result = m1; +    result *= m2; +    return result; +} + +/***************************************************************************** +  TQWMatrix stream functions + *****************************************************************************/ +#ifndef TQT_NO_DATASTREAM +/*! +    \relates TQWMatrix + +    Writes the matrix \a m to the stream \a s and returns a reference +    to the stream. + +    \sa \link datastreamformat.html Format of the TQDataStream operators \endlink +*/ + +TQDataStream &operator<<( TQDataStream &s, const TQWMatrix &m ) +{ +    if ( s.version() == 1 ) +	s << (float)m.m11() << (float)m.m12() << (float)m.m21() +	  << (float)m.m22() << (float)m.dx()  << (float)m.dy(); +    else +	s << m.m11() << m.m12() << m.m21() << m.m22() +	  << m.dx() << m.dy(); +    return s; +} + +/*! +    \relates TQWMatrix + +    Reads the matrix \a m from the stream \a s and returns a reference +    to the stream. + +    \sa \link datastreamformat.html Format of the TQDataStream operators \endlink +*/ + +TQDataStream &operator>>( TQDataStream &s, TQWMatrix &m ) +{ +    if ( s.version() == 1 ) { +	float m11, m12, m21, m22, dx, dy; +	s >> m11;  s >> m12;  s >> m21;  s >> m22; +	s >> dx;   s >> dy; +	m.setMatrix( m11, m12, m21, m22, dx, dy ); +    } +    else { +	double m11, m12, m21, m22, dx, dy; +	s >> m11;  s >> m12;  s >> m21;  s >> m22; +	s >> dx;   s >> dy; +	m.setMatrix( m11, m12, m21, m22, dx, dy ); +    } +    return s; +} +#endif // TQT_NO_DATASTREAM + +#endif // USE_QT4 + +#endif // TQT_NO_WMATRIX + | 
