svgtopt/gfx2d/src/GfxGeom/GfxAffineTransform.cpp
author hgs
Wed, 03 Nov 2010 18:56:10 +0200
changeset 46 88edb906c587
permissions -rw-r--r--
201044

/*
* Copyright (c) 2002 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:  Graphics Extension Library source file
*
*/


#include "GfxAffineTransform.h"

#include "GfxGeneralPath.h"
#include "Gfxtrignometric.h"

#include "e32debug.h"

// ==========================================================================
// Notes:
//
//    [ x']   [  m00  m01  m02  ] [ x ]   [ m00x + m01y + m02 ]
//    [ y'] = [  m10  m11  m12  ] [ y ] = [ m10x + m11y + m12 ]
//    [ 1 ]   [   0    0    1   ] [ 1 ]   [         1         ]
//
// ==========================================================================

// ==========================================================================
// Constructor
// ==========================================================================
// --------------------------------------------------------------------------
//  TGfxAffineTransform::TGfxAffineTransform()
// ---------------------------------------------------------------------------
 TGfxAffineTransform::TGfxAffineTransform()
   :iM00(KFloatFixOne),
    iM10(KFloatFixZero),
    iM01(KFloatFixZero),
    iM11(KFloatFixOne),
    iM02(KFloatFixZero),
    iM12(KFloatFixZero)
	{
    iTransType = KTransformIdentity;
    }


// ==========================================================================
// Constructor with elements
// ==========================================================================
// --------------------------------------------------------------------------
//  TGfxAffineTransform::TGfxAffineTransform( TReal32 aM00,
// ---------------------------------------------------------------------------
 TGfxAffineTransform::TGfxAffineTransform( TReal32 aM00,
                                                   TReal32 aM10,
                                                   TReal32 aM01,
                                                   TReal32 aM11,
                                                   TReal32 aM02,
                                                   TReal32 aM12 )
    {
    SetTransform( aM00, aM10, aM01, aM11, aM02, aM12 );
    }

// --------------------------------------------------------------------------
// TGfxAffineTransform::TGfxAffineTransform( TReal32 aM00,
// ---------------------------------------------------------------------------
TGfxAffineTransform::TGfxAffineTransform( TReal32 aM00,
                                          TReal32 aM10,
                                          TReal32 aM01,
                                          TReal32 aM11,
                                          TReal32 aM02,
                                          TReal32 aM12,
                                          TGfxTransformType aType )
										  :iM00(aM00),
										  iM10(aM10),
										  iM01(aM01),
										  iM11(aM11),
										  iM02(aM02),
										  iM12(aM12)
	{
    iTransType = aType;
    }

// ==========================================================================
// Generally used instance creation: Rotation matrix
// ==========================================================================
// --------------------------------------------------------------------------
//  TGfxAffineTransform TGfxAffineTransform::GetRotateInstance( TReal32 aTheta )
// ---------------------------------------------------------------------------
 TGfxAffineTransform TGfxAffineTransform::GetRotateInstance( TReal32 aTheta )
    {
    TGfxAffineTransform tmp;
    tmp.SetToRotate( aTheta );
    return tmp;
    }

// ==========================================================================
// Generally used instance creation: another Rotation matrix
// ==========================================================================
// --------------------------------------------------------------------------
//  TGfxAffineTransform TGfxAffineTransform::GetRotateInstance( TReal32 aTheta,
// ---------------------------------------------------------------------------
 TGfxAffineTransform TGfxAffineTransform::GetRotateInstance( TReal32 aTheta,
                                                                     const TFloatFixPt& aX,
                                                                     const TFloatFixPt& aY )
    {
    TGfxAffineTransform tmp;
    tmp.SetToRotate( aTheta );

    TFloatFixPt x = aX;
    TFloatFixPt y = aY;
    TFloatFixPt KOne( KFloatFixOne );
    tmp.iM02 = x * ( KOne - tmp.iM00 ) + y * tmp.iM10;
    tmp.iM12 = y * ( KOne - tmp.iM00 ) - x * tmp.iM10;
    tmp.iTransType |= KTransformTranslate;
    return tmp;
    }

// ==========================================================================
// Added Zoom Instance for better calculation
// ==========================================================================
// --------------------------------------------------------------------------
//  TGfxAffineTransform TGfxAffineTransform::GetZoomInstance( sf,ax,ay);
// ---------------------------------------------------------------------------
 TGfxAffineTransform TGfxAffineTransform::GetZoomInstance( TReal32 aScaleFactor,
                                                                     const TFloatFixPt& aX,
                                                                     const TFloatFixPt& aY )
    {
    TFloatFixPt KOne( KFloatFixOne );
    TGfxAffineTransform tmp;
    tmp.iM00 = aScaleFactor;
    tmp.iM11 = aScaleFactor;

    TMatrixElType x = ( TMatrixElType ) aX;
    TMatrixElType y = ( TMatrixElType ) aY;
    tmp.iM02 = x * ( KOne - tmp.iM00 ); 
    tmp.iM12 = y * ( KOne - tmp.iM11 ); 
    tmp.iTransType |= KTransformTranslate | KTransformScale;
    return tmp;
    }

// --------------------------------------------------------------------------
// void TGfxAffineTransform::SetToRotate( TReal32 aTheta )
// ---------------------------------------------------------------------------
void TGfxAffineTransform::SetToRotate( TReal32 aTheta )
    {
    TFloatFixPt KZero;
	#ifdef SVG_FLOAT_BUILD
	TFloatFixPt cs = TFloatFixPt::CosFloatDouble( aTheta ); //(GfxMath::svgScalarCos((TInt32)(aTheta * TReal(0x10000))));
	TFloatFixPt sn = TFloatFixPt::SinFloatDouble( aTheta ); //(GfxMath::svgScalarSin((TInt32)(aTheta * TReal(0x10000))));
	#else
	TFloatFixPt cs (GfxMath::svgScalarCos((TInt32)(aTheta * TReal(0x10000))), ETrue);
	TFloatFixPt sn (GfxMath::svgScalarSin((TInt32)(aTheta * TReal(0x10000))), ETrue);
	#endif
    iM00 =  cs;
    iM10 =  sn;
    iM01 = KZero - sn;
    iM11 =  cs;

    iM02 = KZero;
    iM12 = KZero;
    iTransType = KTransformShear | KTransformScale;
    }

// ==========================================================================
// Generally used instance creation: Scale matrix
// ==========================================================================
// --------------------------------------------------------------------------
//  TGfxAffineTransform TGfxAffineTransform::GetScaleInstance( TReal32 aSx,
// ---------------------------------------------------------------------------
 TGfxAffineTransform TGfxAffineTransform::GetScaleInstance( TReal32 aSx,
                                                                    TReal32 aSy )
    {
    return TGfxAffineTransform( ( TReal32 ) aSx,
                                0.0f,
                                0.0f,
                                ( TReal32 ) aSy,
                                0.0f,
                                0.0f,
                                KTransformScale );
    }

// ==========================================================================
// Generally used instance creation: Shear matrix
// ==========================================================================
// --------------------------------------------------------------------------
//  TGfxAffineTransform TGfxAffineTransform::GetShearInstance( TReal32 aShx,
// ---------------------------------------------------------------------------
 TGfxAffineTransform TGfxAffineTransform::GetShearInstance( TReal32 aShx,
                                                                    TReal32 aShy )
    {
	#ifdef SVG_FLOAT_BUILD
	TFloatFixPt tnshx = TFloatFixPt::TanFloatDouble( aShx ); //(GfxMath::svgScalarTan(TInt(aShx*0x10000)));
	TFloatFixPt tnshy = TFloatFixPt::TanFloatDouble( aShy ); //(GfxMath::svgScalarTan(TInt(aShy*0x10000)));
	#else
	TFloatFixPt tnshx(GfxMath::svgScalarTan(TInt(aShx*0x10000)), ETrue);
	TFloatFixPt tnshy(GfxMath::svgScalarTan(TInt(aShy*0x10000)), ETrue);
	#endif

    return TGfxAffineTransform( 1.0f,
                                TReal32(tnshy),
                                TReal32(tnshx),
                                1.0f,
                                0.0f,
                                0.0f,
                                KTransformShear );
    }


// ==========================================================================
// Generally used instance creation: Translate matrix
// ==========================================================================
// --------------------------------------------------------------------------
//  TGfxAffineTransform TGfxAffineTransform::GetTranslateInstance( const TFixPt& aTx,
// ---------------------------------------------------------------------------
 TGfxAffineTransform TGfxAffineTransform::GetTranslateInstance( const TFloatFixPt& aTx,
                                                                        const TFloatFixPt& aTy )
    {
    return TGfxAffineTransform( 1.0f,
                                0.0f,
                                0.0f,
                                1.0f,
                                ( TReal32 ) aTx,
                                ( TReal32 ) aTy,
                                KTransformTranslate );
    }

// --------------------------------------------------------------------------
//  TReal32 TGfxAffineTransform::Determinant() const
// ---------------------------------------------------------------------------
 TReal32 TGfxAffineTransform::Determinant() const
    {
    return iM00 * iM11 - iM10 * iM01;
    }

// --------------------------------------------------------------------------
//  TBool TGfxAffineTransform::IsIdentity() const
// ---------------------------------------------------------------------------
 TBool TGfxAffineTransform::IsIdentity() const
    {
    return  ( (int)iTransType == KTransformIdentity );
    }

// --------------------------------------------------------------------------
//  TReal32 TGfxAffineTransform::ScaleX() const
// ---------------------------------------------------------------------------
 TReal32 TGfxAffineTransform::ScaleX() const
    {
    return iM00;
    }

// --------------------------------------------------------------------------
//  TReal32 TGfxAffineTransform::ScaleY() const
// ---------------------------------------------------------------------------
 TReal32 TGfxAffineTransform::ScaleY() const
    {
    return iM11;
    }

// --------------------------------------------------------------------------
//  TReal32 TGfxAffineTransform::ShearX() const
// ---------------------------------------------------------------------------
 TReal32 TGfxAffineTransform::ShearX() const
    {
    return iM01;
    }

// --------------------------------------------------------------------------
//  TReal32 TGfxAffineTransform::ShearY() const
// ---------------------------------------------------------------------------
 TReal32 TGfxAffineTransform::ShearY() const
    {
    return iM10;
    }

// --------------------------------------------------------------------------
//  TReal32 TGfxAffineTransform::TranslateX() const
// ---------------------------------------------------------------------------
 TReal32 TGfxAffineTransform::TranslateX() const
    {
    return iM02;
    }

// --------------------------------------------------------------------------
//  TReal32 TGfxAffineTransform::TranslateY() const
// ---------------------------------------------------------------------------
 TReal32 TGfxAffineTransform::TranslateY() const
    {
    return iM12;
    }


// --------------------------------------------------------------------------
//  void TGfxAffineTransform::Concatenate( const TGfxAffineTransform& aTransform )
// ---------------------------------------------------------------------------
 void TGfxAffineTransform::Concatenate( const TGfxAffineTransform& aTransform )
    {

    if ( IsIdentity() )
        {
        iM00 = aTransform.iM00;
        iM01 = aTransform.iM01;
        iM02 = aTransform.iM02;
        iM11 = aTransform.iM11;
        iM10 = aTransform.iM10;
        iM12 = aTransform.iM12;
        iTransType = aTransform.iTransType;
        }
    else if ( aTransform.IsIdentity() )
        {
        // Do nothing
        }
    else
        {
        TFloatFixPt m0, m1;
        m0 = iM00;
        m1 = iM01;
        iM00 = aTransform.iM00 * m0 + aTransform.iM10 * m1;
        iM01 = aTransform.iM01 * m0 + aTransform.iM11 * m1;
        iM02 += aTransform.iM02 * m0 + aTransform.iM12 * m1;
        m0 = iM10;
        m1 = iM11;
        iM11 = aTransform.iM01 * m0 + aTransform.iM11 * m1;
        iM10 = aTransform.iM00 * m0 + aTransform.iM10 * m1;
        iM12 += aTransform.iM02 * m0 + aTransform.iM12 * m1;
        iTransType |= aTransform.iTransType;
        }
    }

// --------------------------------------------------------------------------
//  TGfxAffineTransform TGfxAffineTransform::CreateInverse()
// ---------------------------------------------------------------------------
 TGfxAffineTransform TGfxAffineTransform::CreateInverse()
    {
    TFloatFixPt KZero;
    TFloatFixPt det = iM00* iM11 - iM01* iM10;
    if ( det == KZero )
        return TGfxAffineTransform();
    else
		{
	#ifdef SVG_FLOAT_BUILD	
		TFloatFixPt idet = TFloatFixPt(1.0f) / det;
	#else	
		TFloatFixPt idet = TFloatFixPt(0x10000,ETrue)/ det;

	#endif
    return TGfxAffineTransform( iM11 * idet,
                                    KZero - iM10 * idet,
                                    KZero - iM01 * idet,
                                    iM00 * idet,
                                    ( iM01 * iM12 - iM11 * iM02 ) * idet,
                                    ( iM10 * iM02 - iM00 * iM12 ) * idet );
		}
    }

// --------------------------------------------------------------------------
//  void TGfxAffineTransform::Rotate( TReal32 aTheta )
// ---------------------------------------------------------------------------
 void TGfxAffineTransform::Rotate( TReal32 aTheta )
    {
    Concatenate( GetRotateInstance( aTheta ) );
    iTransType |= ( KTransformShear | KTransformScale );
    }

// --------------------------------------------------------------------------
//  void TGfxAffineTransform::Rotate( TReal32 aTheta,
// ---------------------------------------------------------------------------
 void TGfxAffineTransform::Rotate( TReal32 aTheta,
                                           const TFloatFixPt& aX,
                                           const TFloatFixPt& aY )
    {
    Concatenate( GetRotateInstance( aTheta, aX, aY ) );
    iTransType |= ( KTransformShear | KTransformScale | KTransformTranslate );
    }

// --------------------------------------------------------------------------
//  void TGfxAffineTransform::Scale( TReal32 aSx, TReal32 aSy )
// ---------------------------------------------------------------------------
 void TGfxAffineTransform::Scale( TReal32 aSx, TReal32 aSy )
    {
    Concatenate( GetScaleInstance( aSx, aSy ) );
    iTransType |= KTransformScale;
    }

// --------------------------------------------------------------------------
//  void TGfxAffineTransform::Translate( const TFixPt& aTx,
// ---------------------------------------------------------------------------
 void TGfxAffineTransform::Translate( const TFloatFixPt& aTx,
                                              const TFloatFixPt& aTy )
    {
    Concatenate( GetTranslateInstance( aTx, aTy ) );
    iTransType |= KTransformTranslate;
    }

// --------------------------------------------------------------------------
//  void TGfxAffineTransform::Shear( TReal32 aShX, TReal32 aShY )
// ---------------------------------------------------------------------------
 void TGfxAffineTransform::Shear( TReal32 aShX, TReal32 aShY )
    {
    Concatenate( GetShearInstance( aShX, aShY ) );
    iTransType |= KTransformShear;
    }

// --------------------------------------------------------------------------
//  void TGfxAffineTransform::SetTransform( TReal32 aM00,
// ---------------------------------------------------------------------------
 void TGfxAffineTransform::SetTransform( TReal32 aM00,
                                                 TReal32 aM10,
                                                 TReal32 aM01,
                                                 TReal32 aM11,
                                                 TReal32 aM02,
                                                 TReal32 aM12 )
    {
    iM00 = aM00;
    iM01 = aM01;
    iM02 = aM02;
    iM10 = aM10;
    iM11 = aM11;
    iM12 = aM12;
    UpdateState();
    }

// --------------------------------------------------------------------------
//  void TGfxAffineTransform::Transform( TGfxPoint2D* aSrcPts,
// ---------------------------------------------------------------------------
 void TGfxAffineTransform::Transform( TGfxPoint2D* aSrcPts,
                                              TGfxPoint2D* aDstPts,
                                              TInt32 aNumPts ) const
    {

    if ( (int)iTransType == KTransformIdentity )
        {
        if ( aSrcPts != aDstPts )
            {
            for ( TInt32 i = 0; i < aNumPts; i++ )
                {
                aDstPts[i] = aSrcPts[i];
                }
            }
        return;
        }

    if ( (int)iTransType == KTransformScale )
        {
        for ( TInt32 i = 0; i < aNumPts; i++ )
            {
            aDstPts[i].iX = aSrcPts[i].iX * iM00;
            aDstPts[i].iY = aSrcPts[i].iY * iM11;
            }
        }
    else if ( (int)iTransType == KTransformTranslate )
        {
        for ( TInt32 i = 0; i < aNumPts; i++ )
            {
            aDstPts[i].iX = aSrcPts[i].iX + iM02;
            aDstPts[i].iY = aSrcPts[i].iY + iM12;
            }
        }
    else if ( (int)iTransType == ( KTransformScale | KTransformTranslate ) )
        {
        for ( TInt32 i = 0; i < aNumPts; i++ )
            {
            aDstPts[i].iX = ( aSrcPts[i].iX * iM00 ) + iM02;
            aDstPts[i].iY = ( aSrcPts[i].iY * iM11 ) + iM12;
            }
        }
    else
        {
        TFloatFixPt x, y;

        for ( TInt32 i = 0; i < aNumPts; i++ )
            {
            x = aSrcPts[i].iX;
            y = aSrcPts[i].iY;
            aDstPts[i].iX = ( iM00 * x ) + ( iM01 * y ) + iM02;
            aDstPts[i].iY = ( iM10 * x ) + ( iM11 * y ) + iM12;
            }
        }
    }

// --------------------------------------------------------------------------
//  void TGfxAffineTransform::Transform( TFixPt* aSrcPts,
// ---------------------------------------------------------------------------
 void TGfxAffineTransform::Transform( TFloatFixPt* aSrcPts,
                                              TFloatFixPt* aDstPts,
                                              TInt32 aNumPts ) const
    {
    aNumPts <<= 1;

    if ( (int)iTransType == KTransformIdentity )
        {
        if ( aSrcPts != aDstPts )
            {
            for ( TInt32 i = 0; i < aNumPts; i++ )
                {
                *aDstPts++ = *aSrcPts++;
                *aDstPts++ = *aSrcPts++;
                }
            }
        return;
        }

    if ( (int)iTransType == KTransformScale )
        {
        for ( TInt32 i = 0; i < aNumPts; i += 2 )
            {
            *aDstPts++ = *aSrcPts++ * iM00;
            *aDstPts++ = *aSrcPts++ * iM11;
            }
        }
    else if ( (int)iTransType == KTransformTranslate )
        {
        for ( TInt32 i = 0; i < aNumPts; i += 2 )
            {
            *aDstPts++ = *aSrcPts++ + iM02;
            *aDstPts++ = *aSrcPts++ + iM12;
            }
        }
    else if ( (int)iTransType == ( KTransformScale | KTransformTranslate ) )
        {
        for ( TInt32 i = 0; i < aNumPts; i += 2 )
            {
            *aDstPts++ = ( *aSrcPts++ * iM00 ) + iM02;
            *aDstPts++ = ( *aSrcPts++ * iM11 ) + iM12;
            }
        }
    else
        {
        TFloatFixPt x, y;

        for ( TInt32 i = 0; i < aNumPts; i += 2 )
            {
            x = *aSrcPts++;
            y = *aSrcPts++;
            *aDstPts++ = ( iM00 * x ) + ( iM01 * y ) + iM02;
            *aDstPts++ = ( iM10 * x ) + ( iM11 * y ) + iM12;
            }
        }
    }

// --------------------------------------------------------------------------
//  void TGfxAffineTransform::Transform( TFixPt* aSrcDstPts,
// ---------------------------------------------------------------------------
 void TGfxAffineTransform::Transform( TFloatFixPt* aSrcDstPts,
                                              TInt32 aNumPts ) const
    {
    if ( (int)iTransType == KTransformIdentity )
        return;

    aNumPts <<= 1;

    if ( (int)iTransType == KTransformScale )
        {
        for ( TInt32 i = 0; i < aNumPts; i += 2 )
            {
            *aSrcDstPts++ *= iM00;
            *aSrcDstPts++ *= iM11;
            }
        }
    else if ( (int)iTransType == KTransformTranslate )
        {
        for ( TInt32 i = 0; i < aNumPts; i += 2 )
            {
            *aSrcDstPts++ += iM02;
            *aSrcDstPts++ += iM12;
            }
        }
    else if ( (int)iTransType == ( KTransformScale | KTransformTranslate ) )
        {
        for ( TInt32 i = 0; i < aNumPts; i += 2 )
            {
            *aSrcDstPts *= iM00;
            *aSrcDstPts++ += iM02;
            *aSrcDstPts *= iM11;
            *aSrcDstPts++ += iM12;
            }
        }
    else
        {
        TFloatFixPt x, y;

        for ( TInt32 i = 0; i < aNumPts; i += 2 )
            {
            x = *aSrcDstPts;
            y = *( aSrcDstPts + 1 );
            *aSrcDstPts++ = ( iM00 * x ) + ( iM01 * y ) + iM02;
            *aSrcDstPts++ = ( iM10 * x ) + ( iM11 * y ) + iM12;
            }
        }
    }

// --------------------------------------------------------------------------
// void TGfxAffineTransform::UpdateState()
// ---------------------------------------------------------------------------
void TGfxAffineTransform::UpdateState()
    {
    TFloatFixPt KZero;
    TFloatFixPt KOne( KFloatFixOne );
    iTransType = KTransformIdentity;

    if ( iM02 != KZero || iM12 != KZero )
        iTransType |= KTransformTranslate;

    if ( iM00 != KZero || iM11 != KZero )
        iTransType |= KTransformScale;

    if ( iM01 != KZero || iM10 != KZero )
        iTransType |= KTransformShear;

    if ( (int)iTransType == KTransformScale && iM00 == KOne && iM11 == KOne )
         iTransType = KTransformIdentity;
    }

// --------------------------------------------------------------------------
// TUint32 TGfxAffineTransform::TransformType()
// ---------------------------------------------------------------------------
TUint32 TGfxAffineTransform::TransformType()
    {
    return iTransType;
    }

// --------------------------------------------------------------------------
// void TGfxAffineTransform::Print()
// prints out the matrix
// ---------------------------------------------------------------------------
 void TGfxAffineTransform::Print()
{
		RDebug::Printf("a=%f b=%f c=%f d=%f e=%f f=%f", (TReal32)iM00, (TReal32)iM10, (TReal32)iM01, (TReal32)iM11, (TReal32)iM02, (TReal32)iM12);
}

// --------------------------------------------------------------------------
// Get the scaling factor set in this transform.  This function returns correctly
// for a uniform scaling in both directions only.
// ---------------------------------------------------------------------------
 TFloatFixPt TGfxAffineTransform::ScalingFactor() const
{
    TGfxPoint2D ep( 1, 0 ), org( 2, 0 );
    Transform( &ep, & ep, 1 );
    Transform( &org, & org, 1 );
    ep.iX -= org.iX;
    ep.iY -= org.iY;
    return TFloatFixPt::Sqrt( ep.iX * ep.iX + ep.iY * ep.iY );
}



// --------------------------------------------------------------------------
//
//  Appends this transform with the existing transform
//  Multiply in reverse order
//  For Ex:  In cases of zoom, rotate and pan of already transformed content.
// If T is the existing transform and zoom operation has to be applied to it
// the resultant transform would be Z*T.
//
//  void TGfxAffineTransform::AppendTransform( const TGfxAffineTransform& aTransform )
// ---------------------------------------------------------------------------
 void TGfxAffineTransform::AppendTransform( const TGfxAffineTransform& aTransform )
    {

    if ( IsIdentity() )
        {
        iM00 = aTransform.iM00;
        iM01 = aTransform.iM01;
        iM02 = aTransform.iM02;
        iM11 = aTransform.iM11;
        iM10 = aTransform.iM10;
        iM12 = aTransform.iM12;
        iTransType = aTransform.iTransType;
        }
    else if ( aTransform.IsIdentity() )
        {
        // Do nothing
        }
    else
        {
        TMatrixElType m00, m01,m02,m10,m11,m12;
        m00 = iM00;
        m01 = iM01;
        m02 = iM02;
        m10 = iM10;
        m11 = iM11;
        m12 = iM12;
        iM00 = aTransform.iM00 * m00 + aTransform.iM01 * m10;
        iM01 = aTransform.iM00 * m01 + aTransform.iM01 * m11;
        iM02 = aTransform.iM00 * m02 + aTransform.iM01 * m12 + aTransform.iM02;

        iM10 = aTransform.iM10 * m00 + aTransform.iM11 * m10;
        iM11 = aTransform.iM10 * m01 + aTransform.iM11 * m11;
        iM12 = aTransform.iM10 * m02 + aTransform.iM11 * m12 + aTransform.iM12;
        
        iTransType |= aTransform.iTransType;
        }
    }

// --------------------------------------------------------------------------
//  void TGfxAffineTransform::UserRoatate( TReal32 aTheta,
// ---------------------------------------------------------------------------
 void TGfxAffineTransform::UserRotate( TReal32 aTheta,
                                           const TFloatFixPt& aX,
                                           const TFloatFixPt& aY )
    {
    AppendTransform( GetRotateInstance( aTheta, aX, aY ) );
    iTransType |= ( KTransformShear | KTransformScale | KTransformTranslate );
    }
    
// --------------------------------------------------------------------------
//  void TGfxAffineTransform::UserZoom( TReal32 aScaleFactor,
// ---------------------------------------------------------------------------
 void TGfxAffineTransform::UserZoom( TReal32 aScaleFactor,
                                           const TFloatFixPt& aX,
                                           const TFloatFixPt& aY )
    {
    AppendTransform( GetZoomInstance( aScaleFactor, aX, aY ) );
    iTransType |= ( KTransformScale | KTransformTranslate );
    }

// --------------------------------------------------------------------------
//  void TGfxAffineTransform::UserPan( const TFloatFixPt& aTx,
// ---------------------------------------------------------------------------
 void TGfxAffineTransform::UserPan( const TFloatFixPt& aTx,
                                              const TFloatFixPt& aTy )
    {
    AppendTransform( GetTranslateInstance( aTx, aTy ) );
    iTransType |= KTransformTranslate;
    }
    

//