matrix.cpp

Go to the documentation of this file.
00001 // $Id: matrix.cpp 1282 2006-06-09 09:46:49Z alex $
00002 /* @@tag:xara-cn@@ DO NOT MODIFY THIS LINE
00003 ================================XARAHEADERSTART===========================
00004  
00005                Xara LX, a vector drawing and manipulation program.
00006                     Copyright (C) 1993-2006 Xara Group Ltd.
00007        Copyright on certain contributions may be held in joint with their
00008               respective authors. See AUTHORS file for details.
00009 
00010 LICENSE TO USE AND MODIFY SOFTWARE
00011 ----------------------------------
00012 
00013 This file is part of Xara LX.
00014 
00015 Xara LX is free software; you can redistribute it and/or modify it
00016 under the terms of the GNU General Public License version 2 as published
00017 by the Free Software Foundation.
00018 
00019 Xara LX and its component source files are distributed in the hope
00020 that it will be useful, but WITHOUT ANY WARRANTY; without even the
00021 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00022 See the GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License along
00025 with Xara LX (see the file GPL in the root directory of the
00026 distribution); if not, write to the Free Software Foundation, Inc., 51
00027 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
00028 
00029 
00030 ADDITIONAL RIGHTS
00031 -----------------
00032 
00033 Conditional upon your continuing compliance with the GNU General Public
00034 License described above, Xara Group Ltd grants to you certain additional
00035 rights. 
00036 
00037 The additional rights are to use, modify, and distribute the software
00038 together with the wxWidgets library, the wxXtra library, and the "CDraw"
00039 library and any other such library that any version of Xara LX relased
00040 by Xara Group Ltd requires in order to compile and execute, including
00041 the static linking of that library to XaraLX. In the case of the
00042 "CDraw" library, you may satisfy obligation under the GNU General Public
00043 License to provide source code by providing a binary copy of the library
00044 concerned and a copy of the license accompanying it.
00045 
00046 Nothing in this section restricts any of the rights you have under
00047 the GNU General Public License.
00048 
00049 
00050 SCOPE OF LICENSE
00051 ----------------
00052 
00053 This license applies to this program (XaraLX) and its constituent source
00054 files only, and does not necessarily apply to other Xara products which may
00055 in part share the same code base, and are subject to their own licensing
00056 terms.
00057 
00058 This license does not apply to files in the wxXtra directory, which
00059 are built into a separate library, and are subject to the wxWindows
00060 license contained within that directory in the file "WXXTRA-LICENSE".
00061 
00062 This license does not apply to the binary libraries (if any) within
00063 the "libs" directory, which are subject to a separate license contained
00064 within that directory in the file "LIBS-LICENSE".
00065 
00066 
00067 ARRANGEMENTS FOR CONTRIBUTION OF MODIFICATIONS
00068 ----------------------------------------------
00069 
00070 Subject to the terms of the GNU Public License (see above), you are
00071 free to do whatever you like with your modifications. However, you may
00072 (at your option) wish contribute them to Xara's source tree. You can
00073 find details of how to do this at:
00074   http://www.xaraxtreme.org/developers/
00075 
00076 Prior to contributing your modifications, you will need to complete our
00077 contributor agreement. This can be found at:
00078   http://www.xaraxtreme.org/developers/contribute/
00079 
00080 Please note that Xara will not accept modifications which modify any of
00081 the text between the start and end of this header (marked
00082 XARAHEADERSTART and XARAHEADEREND).
00083 
00084 
00085 MARKS
00086 -----
00087 
00088 Xara, Xara LX, Xara X, Xara X/Xtreme, Xara Xtreme, the Xtreme and Xara
00089 designs are registered or unregistered trademarks, design-marks, and/or
00090 service marks of Xara Group Ltd. All rights in these marks are reserved.
00091 
00092 
00093       Xara Group Ltd, Gaddesden Place, Hemel Hempstead, HP2 6EX, UK.
00094                         http://www.xara.com/
00095 
00096 =================================XARAHEADEREND============================
00097  */
00098 
00099 
00100 #include "camtypes.h"
00101 // camconfig.h must be included immediately after camtypes.h
00102 //#include "camconfig.h"
00103 //#include "errors.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00104 //#include "ensure.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00105 //#include "matrix.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00106 //#include "docrect.h" - in camtypes.h [AUTOMATICALLY REMOVED]
00107 //#include "xadrwold.h"
00108 #include "macros.h"
00109 //#include "grndrgn.h"
00110 
00111 DECLARE_SOURCE("$Revision: 1282 $");
00112 
00113 #define TORADIANS(x)    ((x)/180.0*PI)
00114 
00115 /********************************************************************************************
00116 
00117 >   Matrix::Matrix () 
00118 
00119     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00120     Created:    14/5/93
00121     Inputs:     None
00122     Outputs:    None
00123     Returns:    None.
00124     Purpose:    Default initialisation - sets up the identity matrix.
00125     Errors:     None.
00126 
00127 ********************************************************************************************/
00128 /*
00129 Technical notes:
00130 
00131 ********************************************************************************************/
00132 
00133 Matrix::Matrix()
00134 {
00135     a = (FIXED16)1;
00136     b = (FIXED16)0;
00137     c = (FIXED16)0;
00138     d = (FIXED16)1;
00139     e = 0;
00140     f = 0;
00141     
00142     Type = TRANS_IDENTITY;
00143     Angle = (ANGLE)0;
00144 }
00145     
00146 /********************************************************************************************
00147 
00148 >   Matrix::Matrix (const FIXED16& xScale, const FIXED16& yScale) 
00149 
00150     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00151     Created:    14/5/93
00152     Inputs:     Two fixed16s representing the x and y scale factors.
00153     Outputs:    None
00154     Returns:    None.
00155     Purpose:    Default initialisation - sets up the scale matrix.
00156     Errors:     None.
00157 
00158 ********************************************************************************************/
00159 /*
00160 Technical notes:
00161 
00162 ********************************************************************************************/
00163 
00164 Matrix::Matrix(const FIXED16& xScale, const FIXED16& yScale)  
00165 {
00166     a = xScale;
00167     b = (FIXED16)0;
00168     c = (FIXED16)0;
00169     d = yScale;
00170     e = 0;
00171     f = 0;
00172     
00173     Type = TRANS_SCALE;
00174     Angle = (ANGLE)0;
00175 }
00176 
00177 /********************************************************************************************
00178 
00179 >   Matrix::Matrix (const ANGLE& theta) 
00180 
00181     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00182     Created:    14/5/93
00183     Inputs:     An angle representing the degree of rotation.
00184     Outputs:    None
00185     Returns:    None.
00186     Purpose:    Default initialisation - sets up the rotation matrix.
00187     Errors:     None.
00188 
00189 ********************************************************************************************/
00190 /*
00191 Technical notes:
00192 
00193 ********************************************************************************************/
00194 
00195 Matrix::Matrix(const ANGLE& theta) 
00196 {
00197 #if 0
00198     a = b = c = d = theta;
00199     
00200     a.Cos();
00201     b.Sin();
00202     c = -(c.Sin());
00203     d.Cos(); 
00204 #else
00205 
00206     double thetaradians = TORADIANS(theta.MakeDouble());
00207     FIXED16 costheta = cos(thetaradians);
00208     FIXED16 sintheta = sin(thetaradians);
00209     
00210     a = d = costheta;
00211     b = sintheta;
00212     c = -sintheta;
00213 #endif
00214 
00215     e = 0;
00216     f = 0;
00217     
00218     Type = TRANS_ROTATION;
00219     Angle = theta;
00220 }
00221 
00222 /********************************************************************************************
00223 
00224 >   Matrix::Matrix (const Coord& disp) 
00225 
00226     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00227     Created:    14/5/93
00228     Inputs:     Displacement of translation.
00229     Outputs:    None
00230     Returns:    None.
00231     Purpose:    Default initialisation - Sets up a translate matrix.
00232     Errors:     None.
00233 
00234 ********************************************************************************************/
00235 /*
00236 Technical notes:
00237 
00238 ********************************************************************************************/
00239 
00240 Matrix::Matrix(const Coord& disp) 
00241 {
00242     a = (FIXED16)1;
00243     b = (FIXED16)0;
00244     c = (FIXED16)0;
00245     d = (FIXED16)1;
00246     e = disp.x;
00247     f = disp.y;
00248     
00249     Type = TRANS_TRANSLATION;
00250     Angle = (ANGLE)0;
00251 }
00252 
00253 
00254 /********************************************************************************************
00255 
00256 >   Matrix::Matrix (const INT32 x, const INT32 y)
00257 
00258     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
00259     Created:    30/5/93
00260     Inputs:     Displacement of translation.
00261     Outputs:    None
00262     Returns:    None.
00263     Purpose:    Default initialisation - Sets up a translate matrix.
00264     Errors:     None.
00265 
00266 ********************************************************************************************/
00267 /*
00268 Technical notes:
00269 
00270 ********************************************************************************************/
00271 
00272 Matrix::Matrix(const INT32 x, const INT32 y)
00273 {
00274     a = (FIXED16)1;
00275     b = (FIXED16)0;
00276     c = (FIXED16)0;
00277     d = (FIXED16)1;
00278     e = x;
00279     f = y;
00280     
00281     Type = TRANS_TRANSLATION;
00282     Angle = (ANGLE)0;
00283 }
00284     
00285 /********************************************************************************************
00286 
00287 >   Matrix::Matrix (const FIXED16& ca,
00288                     const FIXED16& cb,
00289                     const FIXED16& cc,
00290                     const FIXED16& cd,
00291                     const INT32     ce,
00292                     const INT32     cf
00293                     ) 
00294 
00295     Author:     Phil_Martin (Xara Group Ltd) <camelotdev@xara.com>
00296     Created:    21/7/93
00297     Inputs:     All six parameters which make up a matrix
00298     Outputs:    None
00299     Returns:    None.
00300     Purpose:    Initialise a while matrix.
00301     Errors:     None.
00302 
00303 ********************************************************************************************/
00304 
00305 Matrix::Matrix( const FIXED16& ca,
00306                 const FIXED16& cb,
00307                 const FIXED16& cc,
00308                 const FIXED16& cd,
00309                 const INT32     ce,
00310                 const INT32     cf
00311                 ) 
00312 {
00313     a = ca;
00314     b = cb;
00315     c = cc;
00316     d = cd;
00317     e = ce;
00318     f = cf;
00319     
00320     Type = TRANS_COMPLEX;
00321     Angle = (ANGLE)0;
00322 }
00323     
00324 
00325 /*******************************************************************************************
00326 
00327 >   Matrix::Matrix(const DocRect& Source, const DocRect& Destin)
00328 
00329     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
00330     Created:    13/12/93
00331     Inputs:     Source = source rectangle 
00332                 Destin = destination rectangle
00333     Returns:    a matrix whose domain is the source rectangle and range is the destination
00334                 rectangle.
00335     Purpose:    Matrix constructor taking two document rectangles.
00336                 Creates a matrix which can be used to transform coordinates within the
00337                 source rectangle into coordinates in the second rectangle
00338 
00339 ********************************************************************************************/
00340 
00341 Matrix::Matrix(const DocRect& Source, const DocRect& Destin)
00342 {
00343     double Sx0 = Source.lo.x;
00344     double Sy0 = Source.lo.y;
00345     double Sx1 = Source.hi.x;
00346     double Sy1 = Source.hi.y;
00347     double Dx0 = Destin.lo.x;   
00348     double Dy0 = Destin.lo.y;
00349     double Dx1 = Destin.hi.x;   
00350     double Dy1 = Destin.hi.y;
00351     double t0,t1;
00352     
00353     (Sx1==Sx0) ? t0=1 : t0=(Dx1-Dx0)/(Sx1-Sx0);
00354     (Sy1==Sy0) ? t1=1 : t1=(Dy1-Dy0)/(Sy1-Sy0);
00355 
00356     a = (FIXED16)t0;
00357     b = (FIXED16)0;
00358     c = (FIXED16)0;
00359     d = (FIXED16)t1;
00360     e = (INT32)(Dx0-Sx0*t0);
00361     f = (INT32)(Dy0-Sy0*t1);
00362 
00363     Type = TRANS_COMPLEX;
00364     Angle = (ANGLE)0;
00365 }
00366 
00367 
00368 
00369 
00370 
00371 /********************************************************************************************
00372 
00373 >   void Matrix::transform(Coord pts[], UINT32 count) 
00374 
00375     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00376     Created:    14/5/93
00377     Inputs:     result - points to be translated.
00378                 count - number of points.
00379     Outputs:    None
00380     Returns:    None.
00381     Purpose:    Transforms a list of points.
00382     Errors:     None.
00383 
00384 ********************************************************************************************/
00385 /*
00386 Technical notes:
00387 
00388 ********************************************************************************************/
00389 
00390 void Matrix::transform(Coord pts[], UINT32 count ) const
00391 {                    
00392     if ( Type == TRANS_TRANSLATION )
00393     {
00394         for (UINT32 i = 0; i < count; i++)
00395         {
00396             pts[i].x += e;
00397             pts[i].y += f;
00398         }
00399     }
00400     else
00401     {
00402 #ifdef OLD_MATRIX_TRANSFORMATIONS
00403         INT32 tx;        // Holds INPUT value of pts[i].x for use in second MatrixCalc
00404 
00405         for (UINT32 i = 0; i < count; i++)
00406         {
00407             tx = pts[i].x;
00408             pts[i].x = MatrixCalc(a, tx, c, pts[i].y) + e;
00409             pts[i].y = MatrixCalc(b, tx, d, pts[i].y) + f;
00410         }
00411 #else
00412         // We use GDraw to transform the path
00413         // Alex asserts it is unimportant to switch contexts here as path transformations are not context
00414         // dependent; thus we call GDraw directly
00415 
00416         GMATRIX gmat;
00417         gmat.AX = a.GetShifted16();
00418         gmat.AY = b.GetShifted16();
00419         gmat.BX = c.GetShifted16();
00420         gmat.BY = d.GetShifted16();
00421         gmat.CX.SetHighLow(e>>16, e<<16);
00422         gmat.CY.SetHighLow(f>>16, f<<16);
00423         // Alex promises we don't need a context to do this op
00424 //      XaDrawOld_TransformPath( (LPPOINT)pts, (LPPOINT)pts, count, &gmat );
00425         GRenderRegion::GetStaticDrawContext()->TransformPath( (LPPOINT)pts, (LPPOINT)pts, count, &gmat );
00426 #endif
00427     }
00428 
00429 }
00430 
00431 /********************************************************************************************
00432 
00433 >   void Matrix::transform(Coord pts[], const Coord input[], UINT32 count)
00434 
00435     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00436     Created:    14/5/93
00437     Inputs:     input - points to be translated.
00438                 count - number of points.
00439     Outputs:    result points translated.
00440     Returns:    None.
00441     Purpose:    Transforms a list of points.
00442     Errors:     None.
00443 
00444 ********************************************************************************************/
00445 /*
00446 Technical notes:
00447 
00448 ********************************************************************************************/
00449 
00450 void Matrix::transform(Coord pts[], const Coord input[], UINT32 count) const
00451 {
00452     if ( Type == TRANS_TRANSLATION )
00453     {
00454         for (UINT32 i = 0; i < count; i++)
00455         {
00456             pts[i].x = input[i].x + e;
00457             pts[i].y = input[i].y + f;
00458         }
00459     }
00460     else
00461     {
00462 #ifdef OLD_MATRIX_TRANSFORMATIONS
00463         for (UINT32 i = 0; i < count; i++)
00464         {
00465             pts[i].x = MatrixCalc(a, input[i].x, c, input[i].y);  
00466             pts[i].x += e;
00467             pts[i].y = MatrixCalc(b, input[i].x, d, input[i].y);
00468             pts[i].y += f;
00469         }
00470 #else
00471         // We use GDraw to transform the path
00472         // Alex asserts it is unimportant to switch contexts here as path transformations are not context
00473         // dependent; thus we call GDraw directly
00474 
00475         GMATRIX gmat;
00476         gmat.AX = a.GetShifted16();
00477         gmat.AY = b.GetShifted16();
00478         gmat.BX = c.GetShifted16();
00479         gmat.BY = d.GetShifted16();
00480         gmat.CX.SetHighLow(e>>16, e<<16);
00481         gmat.CY.SetHighLow(f>>16, f<<16);
00482         // Alex promises we don't need a context to do this op
00483 //      XaDrawOld_TransformPath( (LPPOINT)input, (LPPOINT)pts, count, &gmat );
00484         GRenderRegion::GetStaticDrawContext()->TransformPath( (LPPOINT)input, (LPPOINT)pts, count, &gmat );
00485 #endif
00486     }
00487 }
00488 
00489 /********************************************************************************************
00490 
00491 >   void Matrix::transform(Coord* pt) 
00492 
00493     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00494     Created:    19/5/93
00495     Inputs:     Coordinate to be transformed.
00496     Outputs:    Coordinate is overwritten with new values
00497     Returns:    None.
00498     Purpose:    Transforms a single point.
00499     Errors:     None.
00500 
00501 ********************************************************************************************/
00502 /*
00503 Technical notes:
00504 
00505 ********************************************************************************************/
00506 
00507 void Matrix::transform(Coord* pt) const
00508 {
00509     INT32 tx;        // Holds INPUT value of pt.x for use in second MatrixCalc!
00510 
00511     if ( Type == TRANS_TRANSLATION )
00512     {
00513         pt->x += e;
00514         pt->y += f;
00515     }
00516     else
00517     {
00518         tx = pt->x;
00519         pt->x = MatrixCalc(a, tx, c, pt->y) + e;
00520         pt->y = MatrixCalc(b, tx, d, pt->y) + f;
00521     }
00522 }
00523 
00524 /********************************************************************************************
00525 
00526 >   Matrix& Matrix::operator=(const Matrix& rhs) 
00527 
00528     Author:     Mario_Shamtani (Xara Group Ltd) <camelotdev@xara.com>
00529     Created:    14/5/93
00530     Inputs:     rhs - matrix to be assigned.
00531     Outputs:    None.
00532     Returns:    None.
00533     Purpose:    Matrix assignment.
00534     Errors:     None.
00535 
00536 ********************************************************************************************/
00537 Matrix& Matrix::operator=(const Matrix& rhs) 
00538 {
00539     this->a = rhs.a;
00540     this->b = rhs.b;
00541     this->c = rhs.c;
00542     this->d = rhs.d;
00543     this->e = rhs.e;
00544     this->f = rhs.f;
00545     
00546     this->Type = rhs.Type;
00547     this->Angle = rhs.Angle;
00548                  
00549     return *this;
00550 }                
00551                  
00552 
00553 /********************************************************************************************
00554 
00555 >   BOOL Matrix::operator==(const Matrix&) 
00556 
00557     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
00558     Created:    26/01/97
00559     Inputs:     rhs:    The right-hand side of the equality.
00560     Returns:    TRUE if this Matrix is equal to rhs
00561     Purpose:    Test for Matrix equality
00562 
00563 ********************************************************************************************/
00564 BOOL Matrix::operator==(const Matrix& rhs) const
00565 {
00566     return (a == rhs.a && b == rhs.b && c == rhs.c && d == rhs.d &&
00567             e == rhs.e && f == rhs.f);
00568 }
00569 
00570 
00571 /********************************************************************************************
00572 >   Matrix Matrix::operator*(const Matrix& operand1, const Matrix& operand2) 
00573 
00574     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00575     Created:    5/2/96
00576     Inputs:     Two matrices to be multiplied.
00577     Returns:    result of multiplication.
00578     Purpose:    Matrix multiplication.
00579 ********************************************************************************************/
00580 
00581 Matrix operator*(const Matrix& op1, const Matrix& op2) 
00582 {
00583     static Matrix t;
00584 
00585     t = op1;
00586     t *= op2;   // no point in duplicating code, just call *= operator
00587 
00588     return t;
00589 }
00590 
00591 
00592 /********************************************************************************************
00593 >   Matrix& Matrix::operator*=(const Matrix& op) 
00594 
00595     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00596     Created:    5/2/96
00597     Inputs:     Matrix to be multiplied by.
00598     Returns:    result of multiplication.
00599     Purpose:    optimized *= operator for matrices
00600     Note:       e,f are not optimised as MatrixCalc() has different round from explicit operations
00601                 however, it does have optimisations for 0 an 1
00602 ********************************************************************************************/
00603 
00604 Matrix& Matrix::operator*=(const Matrix& op) 
00605 {
00606     if (op.b==0 && op.c==0)
00607     {
00608         // it's just an x or y scaling ...
00609         if (op.a!=1)
00610         {
00611             a *= op.a;
00612             c *= op.a;
00613         }
00614         if (op.d!=1)
00615         {
00616             b *= op.d;
00617             d *= op.d;
00618         }
00619     }
00620     else
00621     {
00622         // it's the complex case ...
00623         FIXED16 t;
00624         t = a*op.a + b*op.c;
00625         b = a*op.b + b*op.d;
00626         a = t;
00627         t = c*op.a + d*op.c;
00628         d = c*op.b + d*op.d;
00629         c = t;
00630     }
00631 
00632     // either case requires these bits
00633     INT32 u;
00634     u = MatrixCalc(op.a, e, op.c, f) + op.e;
00635     f = MatrixCalc(op.b, e, op.d, f) + op.f;
00636     e = u;
00637 
00638     Type  = TRANS_COMPLEX;
00639     Angle = (ANGLE)0;
00640 
00641     return *this;
00642 }
00643 
00644 
00645 
00646 
00647 /********************************************************************************************
00648 
00649 >   Matrix Matrix::Inverse() const
00650 
00651     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
00652     Created:    2/11/93
00653     Returns:    The Inverse of this matrix
00654     Purpose:    Inverts the 'this' matrix and returns the result. 'this' matrix is not
00655                 effected
00656 
00657 ********************************************************************************************/
00658 
00659 Matrix Matrix::Inverse() const
00660 {
00661     Matrix Temp;
00662 
00663     // Inverting a general matrix is quite an expensive operation, so we will try and
00664     // avoid having to do all the maths (esp as it can fail - some matrices do not have
00665     // an inverse! eg Scale by a factor of zero)
00666 
00667     switch ( Type )
00668     {
00669         case TRANS_IDENTITY:
00670             // Inverse is the same as this
00671             ENSURE(a==FIXED16(1), "Matrix inconsistency!");
00672             ENSURE(b==FIXED16(0), "Matrix inconsistency!");
00673             ENSURE(c==FIXED16(0), "Matrix inconsistency!");
00674             ENSURE(d==FIXED16(1), "Matrix inconsistency!");
00675             ENSURE(e==0, "Matrix inconsistency!");
00676             ENSURE(f==0, "Matrix inconsistency!");
00677 
00678             return Temp;
00679             break;
00680 
00681         case TRANS_TRANSLATION :
00682             // Translation matrix - The inverse of this requires negating the x and y 
00683             // components of the translation
00684             ENSURE(a==FIXED16(1), "Matrix inconsistency!");
00685             ENSURE(b==FIXED16(0), "Matrix inconsistency!");
00686             ENSURE(c==FIXED16(0), "Matrix inconsistency!");
00687             ENSURE(d==FIXED16(1), "Matrix inconsistency!");
00688 
00689             Temp.a     =  this->a;
00690             Temp.b     =  this->b;
00691             Temp.c     =  this->c;
00692             Temp.d     =  this->d;
00693             Temp.e     = -this->e;
00694             Temp.f     = -this->f;
00695             Temp.Type  =  this->Type;
00696             Temp.Angle =  this->Angle;
00697             break;
00698 
00699         case TRANS_ROTATION:
00700             // The inverse of a rotation matrix is the Transpose of this matrix
00701             // ie components b and c are swapped
00702             ENSURE(e==0, "Matrix inconsistency!");
00703             ENSURE(f==0, "Matrix inconsistency!");
00704 
00705             Temp.a     = this->a;
00706             Temp.b     = this->c;
00707             Temp.c     = this->b;
00708             Temp.d     = this->d;
00709             Temp.e     = this->e;
00710             Temp.f     = this->f;
00711             Temp.Type  = this->Type;
00712             Temp.Angle = -this->Angle;
00713             break;
00714 
00715         case TRANS_SCALE:
00716             // This can fail if one of the scale factors is 0. This will cause an ENSURE to fail
00717             // The inverse of a scale involves finding the inverse of the scale factors
00718 //          ENSURE( this->a != 0, "Matrix Inversion failed - X scale factor was zero!" );
00719 //          ENSURE( this->d != 0, "Matrix Inversion failed - Y scale factor was zero!" );
00720             if ((this->a==0) || (this->d==0))
00721             {
00722                 TRACE( _T("Matrix Inversion failed!\n"));
00723                 // There is no inversion of this matrix
00724                 // return the identity matrix
00725                 return Temp;
00726             }
00727             ENSURE(e==0, "Matrix inconsistency!");
00728             ENSURE(f==0, "Matrix inconsistency!");
00729 
00730             Temp.a     = 1/this->a;
00731             Temp.b     = this->b;
00732             Temp.c     = this->c;
00733             Temp.d     = 1/this->d;
00734             Temp.e     = this->e;
00735             Temp.f     = this->f;
00736             Temp.Type  = this->Type;
00737             Temp.Angle = this->Angle;
00738             break;
00739 
00740         case TRANS_SHEAR:
00741         case TRANS_COMPLEX:
00742         default:
00743             // This is the general case. It may be possible for this to fail.
00744             // I got the general idea for this from Graphics Gems page 766.
00745             // It did take 4 pages of c code in there, but it was a slightly
00746             // more complex solution.
00747 
00748             // Find the determinent of the Adjoint matrix - Luckily we can calculate
00749             // this before we calculate the Adjoint matrix as we know that the
00750             // right hand edge of the matrix is 0 0 1
00751             double Det = a.MakeDouble()*d.MakeDouble() - b.MakeDouble()*c.MakeDouble();
00752 
00753             if (Det==0.0)
00754             {
00755                 // There is no inversion of this matrix
00756                 // return the identity matrix
00757 //              ENSURE( FALSE, "Matrix Inversion Failed - Tried to Invert a non-invertable matrix" );
00758                 TRACE( _T("Matrix Inversion failed!\n"));
00759                 return Temp;
00760             }
00761 
00762             // this section calculates the inverse of the matrix. As it takes into
00763             // account that our 3x3 matrix always has 0,0,1 down its right hand side
00764             // it has been greatly simplified. The operations combine the calculation
00765             // of the adjoint matrix and scaling it by the Determinent with a matrix
00766             // transpose (the inverse is the transpose of the adjoint scaled by the 
00767             // determinent)
00768             Temp.a     = (FIXED16)(d.MakeDouble() / Det);
00769             Temp.b     = (FIXED16)(-b.MakeDouble() / Det);
00770             Temp.c     = (FIXED16)(-c.MakeDouble() / Det);
00771             Temp.d     = (FIXED16)(a.MakeDouble() / Det);
00772             Temp.e     = (INT32)( ((c.MakeDouble()*f)-(e*d.MakeDouble()))/Det );
00773             Temp.f     = (INT32)( -(((a.MakeDouble()*f) - (e*b.MakeDouble()))/Det));
00774             Temp.Type  = TRANS_COMPLEX;
00775             Temp.Angle = 0;
00776 
00777             break;
00778     }
00779 
00780     // return the inverted matrix back
00781     return Temp;
00782 }
00783 
00784 
00785 /********************************************************************************************
00786 
00787 >   void Matrix::GetComponents( FIXED16 *abcd, INT32 *ef ) const
00788 
00789     Author:     Andy_Pennell (Xara Group Ltd) <camelotdev@xara.com>
00790     Created:    24/5/94
00791     Inputs:     -
00792     Outputs:    abcd should point to FIXED16[4] which will get loaded with the a,b,c,d
00793                 values from the matrix. Similarly ef should point to INT32[2] which will get
00794                 loaded with the e and f values. If either pointer is NULL then nothing will
00795                 get written for that type.
00796     Returns:    -
00797     Purpose:    Allows code to get to the elements in the matrix without having to be a friend
00798                 of the class. Should be used very sparingly indeed.
00799 
00800 ********************************************************************************************/
00801 
00802 void Matrix::GetComponents( FIXED16 *abcd, INT32 *ef) const
00803 {
00804     if (abcd)
00805     {
00806         abcd[0] = a;
00807         abcd[1] = b;
00808         abcd[2] = c;
00809         abcd[3] = d;
00810     }
00811 
00812     if (ef)
00813     {
00814         ef[0] = e;
00815         ef[1] = f;
00816     }
00817 }
00818 
00819 #ifdef _DEBUG
00820 void Matrix::Dump() const
00821 {
00822     // Display a matrix
00823     /*TRACE( _T("| %+5.3f %+5.3f %+5.3f |\n"), a.MakeDouble(), b.MakeDouble(), 0.0 );
00824     TRACE( _T("| %+5.3f %+5.3f %+5.3f |\n"), c.MakeDouble(), d.MakeDouble(), 0.0 );
00825     TRACE( _T("| %+5.3f %+5.3f %+5.3f |\n\n"), (double)e, (double)f, 1.0 );*/
00826     TRACE( _T("| %f %f %f |\n"), a.MakeDouble(), b.MakeDouble(), 0.0 );
00827     TRACE( _T("| %f %f %f |\n"), c.MakeDouble(), d.MakeDouble(), 0.0 );
00828     TRACE( _T("| %f %f %f |\n\n"), (double)e, (double)f, 1.0 );
00829 }
00830 #endif
00831 
00832 /********************************************************************************************
00833 >   void Matrix::translate(const INT32 TransX, const INT32 TransY);
00834 
00835     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00836     Created:    17/4/95
00837     Inputs:     TransX, TransY - translations to apply
00838     Purpose:    QUICKLY add a translation to a matrix!
00839 ********************************************************************************************/
00840 
00841 void Matrix::translate(const INT32 TransX, const INT32 TransY)
00842 {
00843     e+=TransX;
00844     f+=TransY;
00845 }
00846 
00847 
00848 void Matrix::GetTranslation(DocCoord& coord) const
00849 {
00850     coord.x = e;
00851     coord.y = f;    
00852 }
00853 
00854 void Matrix::GetTranslation(INT32& xlate,INT32& ylate) const
00855 {
00856     xlate=e;
00857     ylate=f;
00858 }
00859 
00860 void Matrix::SetTranslation(const DocCoord& coord)
00861 {
00862     e = coord.x;
00863     f = coord.y;
00864 
00865     if (Type!=TRANS_TRANSLATION)
00866         Type = TRANS_COMPLEX;
00867 }
00868 
00869 void Matrix::SetTranslation(const INT32& xlate, const INT32& ylate)
00870 {
00871     e = xlate;
00872     f = ylate;
00873 
00874     if (Type!=TRANS_TRANSLATION)
00875         Type = TRANS_COMPLEX;
00876 }
00877 
00878 
00879 
00880 
00881 /********************************************************************************************
00882 >   virtual BOOL Matrix::Decompose(FIXED16* pScale=NULL, FIXED16* pAspect=NULL,
00883                                    ANGLE* pRotation=NULL, ANGLE* pShear=NULL,
00884                                    Coord* pTranslate=NULL, FIXED16* pScaleY=NULL);
00885 
00886     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00887     Created:    7/4/95
00888     Outputs:    pScale     - if not NULL, outputs scale (-ve indicates mirror Y)
00889                 pAspect    - if not NULL, outputs aspect
00890                 pRotation  - if not NULL, outputs rotation (-PI..PI)
00891                 pShear     - if not NULL, outputs sheer (-PI/2..PI/2)
00892                 pTranslate - if not NULL, outputs translation
00893     Returns:    FALSE if falis
00894     Purpose:    Decompose a matrix into its component transforms
00895 ********************************************************************************************/
00896 
00897 BOOL Matrix::Decompose(FIXED16* pScale, FIXED16* pAspect, ANGLE* pRotation,
00898                        ANGLE* pShear, Coord* pTranslate, FIXED16* pScaleY)
00899 {
00900     // unit square decomposition of matrix ...
00901     // A={a,c}, B={b,d}, Q=angle between vectors (ie PI/2-shear angle)!
00902     // |A|=sqrt(aa+cc)
00903     // |B|=sqrt(bb+dd)
00904     // AxB=|A||B|sinQ=ad-bc=(new area of unit square)
00905     // A.B=|A||B|cosQ=ab+cd
00906     // so ...
00907     // ScaleX   = |A|
00908     // ScaleY   = |B|
00909     // Scale    = ScaleY*cos(PI/2-Q) = ScaleY*sinQ = AxB/|A|
00910     // AbsScale = abs(Scale) // effectively remove any mirror
00911     // Aspect   = ScaleX/abs(Scale)
00912     // Shear    = PI/2-Q = PI/2-acos((A.B)/(|A||B|))
00913     // Rotate   = RotateX = atan2(c,a)
00914 
00915     double a=this->a.MakeDouble();
00916     double b=this->c.MakeDouble();  // 'cos I think of coords as column vectors not rows!
00917     double c=this->b.MakeDouble();
00918     double d=this->d.MakeDouble();
00919 
00920     // get cross product (determinant), modulus (length) of A and scale
00921     double AxB      = a*d-b*c;
00922     double ModA     = sqrt(a*a+c*c);
00923     double ModB     = sqrt(b*b+d*d);
00924     double Scale    = AxB/ModA;
00925 
00926     // set output values where required
00927     if (pTranslate) *pTranslate = Coord(this->e,this->f);
00928     if (pScale)     *pScale     = Scale;
00929     if (pAspect)
00930         if (Scale==0)
00931             *pAspect    = (FIXED16)1;
00932         else
00933             *pAspect    = ModA/fabs(Scale);
00934     if (pRotation)  *pRotation  = (ANGLE)atan2(c,a);
00935     if (pShear)
00936     {
00937         double AdotB = a*b+c*d;
00938         *pShear = (ANGLE)(PI/2-acos(AdotB/(ModB*ModA)));
00939     }
00940     if (pScaleY)    *pScaleY = ModB;
00941 
00942 //  TRACE( _T("\n"));
00943 //  TRACE( _T("Scale  = %f\n"),Scale);
00944 //  TRACE( _T("Aspect = %f\n"),ModA/fabs(Scale));
00945 //  TRACE( _T("Rotate = %f\n"),atan2(c,a)/PI*180);
00946 //  double AdotB = a*b+c*d;
00947 //  double ModB  = sqrt(b*b+d*d);
00948 //  TRACE( _T("Shear  = %f\n"),(PI/2-acos(AdotB/(ModB*ModA)))/PI*180);
00949 
00950     return TRUE;
00951 }
00952 
00953 
00954 /********************************************************************************************
00955 >   virtual BOOL Matrix::Compose(FIXED16 Scale=1.0, FIXED16 Aspect=1.0,
00956                                  ANGLE Rotation=0, ANGLE Shear=0,
00957                                  Coord Translation=Coord(0,0));
00958 
00959     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00960     Created:    7/4/95
00961     Inputs:     Scale       - 
00962                 Aspect      - 
00963                 Rotation    - 
00964                 Shear       - 
00965                 Translation - 
00966     Returns:    FALSE if falis
00967     Purpose:    Compose a matrix from its components
00968 ********************************************************************************************/
00969 
00970 BOOL Matrix::Compose(FIXED16 Scale, FIXED16 Aspect, ANGLE Rotation, ANGLE Shear, Coord Translation)
00971 {
00972     // do scale, aspect and shear
00973     FIXED16 AbsScale = (Scale<0) ? -Scale : Scale;
00974     *this=Matrix(AbsScale*Aspect,0,Scale*tan(Shear.MakeDouble()),Scale,0,0);
00975 
00976     // do rotate
00977     *this*=Matrix((Rotation*180)/PI);       // god damned amatuers using degrees!
00978 
00979     // translate
00980     this->translate(Translation.x,Translation.y);
00981 
00982     return TRUE;
00983 }
00984 
00985 
00986 /********************************************************************************************
00987 >   BOOL Matrix::TransformBounds(DocRect* pRect) const
00988 
00989     Author:     Ed_Cornes (Xara Group Ltd) <camelotdev@xara.com>
00990     Created:    23/4/95
00991     Inputs:     pRect - rect to transform
00992     Outputs:    pRect - transformed rect
00993     Returns:    FALSE if fails
00994     Purpose:    Given a rect, find its bounds when transformed
00995 ********************************************************************************************/
00996 
00997 BOOL Matrix::TransformBounds(DocRect* pRect) const
00998 {
00999     ERROR2IF(pRect==NULL,FALSE,"Matrix::Transform() - pRect==NULL");
01000 
01001     static DocCoord coords[4];
01002     coords[0] = pRect->lo;
01003     coords[1] = DocCoord(pRect->hi.x,pRect->lo.y);
01004     coords[2] = pRect->hi;
01005     coords[3] = DocCoord(pRect->lo.x,pRect->hi.y);
01006 
01007     this->transform((Coord*)&coords,4);
01008 
01009     *pRect = DocRect(coords[0],coords[0]);
01010     pRect->IncludePoint(coords[1]);
01011     pRect->IncludePoint(coords[2]);
01012     pRect->IncludePoint(coords[3]);
01013 
01014     return TRUE;
01015 }
01016     
01017 
01018 /********************************************************************************************
01019 
01020 >   Matrix::Matrix(const Coord& CentreOfRotation, const ANGLE& Rotation)
01021 
01022     Author:     Rik_Heywood (Xara Group Ltd) <camelotdev@xara.com>
01023     Created:    7/3/94
01024     Inputs:     CentreOfRot - The centre of rotation
01025                 RotateBy    - The angle of the rotation that this transform object will perform
01026     Purpose:    Creates a Matrix transform object that will perform a rotation about the
01027                 given point by the given number of degrees.
01028 
01029 ********************************************************************************************/
01030 
01031 Matrix::Matrix(const Coord& CentreOfRotation, const ANGLE& Rotation)
01032 {
01033     // need to translate the centre of rotation to the origin
01034     *this = Matrix(-CentreOfRotation.x, -CentreOfRotation.y);
01035 
01036     // rotate about the origin
01037     *this *= Matrix(Rotation);
01038 
01039     // translate back to the centre of rotation
01040     this->translate(CentreOfRotation.x, CentreOfRotation.y);
01041     
01042     Type  = TRANS_COMPLEX;
01043     Angle = (ANGLE)0;
01044 }
01045 
01046 
01047 
01048 /********************************************************************************************
01049 
01050 >   BOOL Matrix::IsTranslation(double epsilon=0.0) const
01051 
01052     Author:     Mike_Kenny (Xara Group Ltd) <camelotdev@xara.com>
01053     Created:    11/01/96
01054     Inputs:     epsilon - an error threshold to use against the scaling components
01055     Returns:    TRUE if this matrix is a translation matrix
01056                 FALSE if not
01057     Purpose:    Examine this matrix and determin whether it is a translation matrix or not.
01058                 This function is needed as within the code there are areas where complex
01059                 matricees are built which are really translation matricees. The function
01060                 will return immediately with TRUE if the matrix type is Translation otherwise
01061                 the function will actually check the matrix values for translation type
01062     See also:   IsRotation(), IsReflection().
01063 
01064 ********************************************************************************************/
01065 BOOL Matrix::IsTranslation(const double epsilon) const
01066 {
01067     if (Type==TRANS_TRANSLATION)
01068         return TRUE;
01069 
01070     if (epsilon==0.0)
01071     {
01072         FIXED16 c0,c1,c2,c3;
01073         c0 = (FIXED16)1;
01074         c1 = (FIXED16)0;
01075         c2 = (FIXED16)0;
01076         c3 = (FIXED16)1;
01077         return  ((a==c0) && (b==c1) && (c==c2) && (d==c3));
01078     }
01079 
01080     double c0,c1,c2,c3;
01081     
01082     c0=a.MakeDouble();
01083     c1=b.MakeDouble();
01084     c2=c.MakeDouble();
01085     c3=d.MakeDouble();
01086 
01087     return ( (fabs(c0-1.0)<epsilon) && (fabs(c1-0.0)<epsilon) && (fabs(c2-0.0)<epsilon) && (fabs(c3-1.0)<epsilon) );
01088 }
01089 
01090 
01091 
01092 /********************************************************************************************
01093 
01094 >   BOOL Matrix::IsRotation(const double epsilon = 0.0) const
01095 
01096     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01097     Created:    16/11/2000
01098     Inputs:     epsilon     optional error threshold to use in our calculations.
01099 
01100     Returns:    TRUE if we're a rotation matrix,
01101                 FALSE otherwise.
01102 
01103     Purpose:    Determine whether this matrix is a rotation matrix or not.
01104 
01105     See also:   IsTranslation(), IsReflection().
01106 
01107 ********************************************************************************************/
01108 BOOL Matrix::IsRotation(const double epsilon) const
01109 {
01110     if (Type == TRANS_ROTATION)
01111         return TRUE;
01112 
01113     // Note: Camelot matrices swap the b & c components, so the form is:
01114     //
01115     //  (a c) , instead of the more familiar (a b) .
01116     //  (b d)                                (c d)
01117     //
01118     // So tests for rotation are:
01119     //  1. a = d
01120     //  2. b = -c
01121     //  3. |(a b)| = |(c d)| = 1.
01122 
01123     if (epsilon == 0.0)
01124     {
01125         if (a == d && b == -c)
01126         {
01127             FIXED16 aa = (a * a);
01128             FIXED16 bb = (b * b);
01129             FIXED16 ab = aa + bb;
01130             if (ab == FIXED16(1))
01131                 return TRUE;
01132         }
01133     }
01134 
01135     else
01136     {
01137         double c0,c1,c2,c3;
01138 
01139         c0 = a.MakeDouble();
01140         c1 = b.MakeDouble();
01141         c2 = c.MakeDouble();
01142         c3 = d.MakeDouble();
01143 
01144         if (fabs(c0 - c3) < epsilon && fabs(c1 + c2) < epsilon)
01145         {
01146             double ab = (c0 * c0) + (c1 * c1);
01147             if (fabs(ab - 1.0) < epsilon)
01148                 return TRUE;
01149         }
01150     }
01151 
01152     return FALSE;
01153 }
01154 
01155 
01156 
01157 /********************************************************************************************
01158 
01159 >   BOOL Matrix::IsReflection(const double epsilon = 0.0) const
01160 
01161     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01162     Created:    16/11/2000
01163     Inputs:     epsilon     optional error threshold to use in our calculations.
01164 
01165     Returns:    TRUE if we're a reflection matrix,
01166                 FALSE otherwise.
01167 
01168     Purpose:    Determine whether this matrix is a reflection matrix or not.
01169 
01170     Notes:      In the interests of speed, this test is INCOMPLETE - we're *only*
01171                 testing for x- or y- axis reflections (no, not both together either).
01172 
01173                 Feel free to modify this method to test for all reflections, but first make
01174                 sure you won't break any code which uses it (at time of writing, you're ok).
01175 
01176     See also:   IsTranslation(), IsRotation().
01177 
01178 ********************************************************************************************/
01179 BOOL Matrix::IsReflection(const double epsilon) const
01180 {
01181     // A Camelot matrix of the form: (a c) , is an x- or y- reflection if:
01182     //                               (b d)
01183     //  1. b = c = 0.
01184     //  2. a = -d.
01185     //  3. |a| = 1.
01186 
01187     if (epsilon == 0.0)
01188     {
01189         if (b == c && c == FIXED16(0) &&
01190             a == -d &&
01191             (a == FIXED16(1) || a == FIXED16(-1)) )
01192             return TRUE;
01193     }
01194 
01195     else
01196     {
01197         double c0,c1,c2,c3;
01198 
01199         c0 = a.MakeDouble();
01200         c1 = b.MakeDouble();
01201         c2 = c.MakeDouble();
01202         c3 = d.MakeDouble();
01203 
01204         if (fabs(c1) < epsilon && fabs(c2) < epsilon &&
01205             fabs(c0 + c3) < epsilon &&
01206             (fabs(c0 - 1.0) < epsilon || fabs(c0 + 1.0) < epsilon) )
01207             return TRUE;
01208     }
01209 
01210     return FALSE;
01211 }
01212 
01213 
01214 
01215 /********************************************************************************************
01216 
01217 >   BOOL IsNear(const T& x, const T& value, const T& Tolerance)
01218                         
01219     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
01220     Created:    28/08/96
01221     Inputs:     x1:         The first of the two values to compare
01222                 x2:         The second of the two values to compare
01223                 Tolerance:  The value within which x1 is considered to be near to x2
01224     Returns:    TRUE if the two values have an absolute difference greater than or equal to
01225                 the given Tolerance
01226                 FALSE otherwise
01227     Purpose:    Support function for IsIsometric
01228                 Determines whether two values are near enough to each other to be considered
01229                 equal.
01230     Notes:      This is a templated function with <class T>
01231 
01232 ********************************************************************************************/
01233 /*
01234 template <class T>
01235 inline BOOL IsNear(const T& x1, const T& x2, const T& Tolerance)
01236 {
01237     return (ABS(x1 - x2) <= Tolerance) ? TRUE : FALSE;
01238 }
01239 */
01240 
01241 /********************************************************************************************
01242 
01243 >   BOOL Matrix::IsIdentity(DOUBLEPARAM epsilon) const
01244 
01245     Author:     Colin_Barfoot (Xara Group Ltd) <camelotdev@xara.com>
01246     Created:    26/01/97
01247     Returns:    TRUE if this matrix is an identity matrix
01248                 FALSE if not
01249     Purpose:    Determines whether or not this matrix is an identity matrix.
01250                 Used by the MOA interface, XMOAFhMtx::FHIMtxIsUnity.
01251 
01252 ********************************************************************************************/
01253 BOOL Matrix::IsIdentity(/*DOUBLEPARAM epsilon*/) const
01254 {
01255     BOOL bIsIdentity = FALSE;
01256 
01257     if (Type == TRANS_IDENTITY)
01258     {
01259         bIsIdentity = TRUE;
01260     }
01261 
01262     if (Type != TRANS_IDENTITY) // && epsilon == 0.0)
01263     {
01264         const FIXED16 c0 = FIXED16(0);
01265         const FIXED16 c1 = FIXED16(1);
01266 
01267         bIsIdentity = ( (a == c1) && (b == c0) && (c == c0) && (d == c1) &&
01268                         (e == 0) && (f == 0));
01269     }
01270 /*
01271     if (Type != TRANS_IDENTITY && epsilon != 0.0)
01272     {
01273         const double ca = a.MakeDouble();
01274         const double cb = b.MakeDouble();
01275         const double cc = c.MakeDouble();
01276         const double cd = d.MakeDouble();
01277         const double ce = e.MakeDouble();
01278         const double cf = f.MakeDouble();
01279 
01280         bIsIdentity = ( IsNear(ca, 1.0, epsilon) && IsNear(cb, 1.0, epsilon) && 
01281                         IsNear(cc, 1.0, epsilon) && IsNear(cd, 1.0, epsilon) && 
01282                         IsNear(ce, 1.0, epsilon) && IsNear(cf, 1.0, epsilon))
01283     }*/
01284     return bIsIdentity;
01285 }
01286 
01287 
01288 
01289 /********************************************************************************************
01290 
01291 >   static Matrix Matrix::CreateTransMatrix(const Coord& dcTrans)
01292 
01293     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01294     Created:    23-07-2000
01295     Inputs:     dcTrans     the translation to perform.
01296     Returns:    A translation matrix.
01297     Purpose:    Factory method - maps directly onto the translation Matrix constructor.
01298 
01299 ********************************************************************************************/
01300 Matrix Matrix::CreateTransMatrix(const Coord& dcTrans)
01301 {
01302     return Matrix(dcTrans);
01303 }
01304 
01305 
01306 
01307 /********************************************************************************************
01308 
01309 >   static Matrix Matrix::CreateScaleMatrix(const double& xScale, const double& yScale)
01310 
01311     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01312     Created:    23-07-2000
01313     Inputs:     xScale      the x-scaling to perform.
01314                 yScale      the y-scaling to perform.
01315     Returns:    A scaling matrix.
01316     Purpose:    Factory method - maps directly onto the scaling Matrix constructor.
01317 
01318 ********************************************************************************************/
01319 Matrix Matrix::CreateScaleMatrix(const double& xScale, const double& yScale)
01320 {
01321     return Matrix(FIXED16(xScale), FIXED16(yScale));
01322 }
01323 
01324 
01325 
01326 /********************************************************************************************
01327 
01328 >   static Matrix Matrix::CreateScaleMatrix(const double& ScaleFactor)
01329 
01330     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01331     Created:    23-07-2000
01332     Inputs:     ScaleFactor     the uniform scaling to perform.
01333     Returns:    A scaling matrix.
01334     Purpose:    Factory method - maps directly onto the scaling Matrix constructor.
01335 
01336 ********************************************************************************************/
01337 Matrix Matrix::CreateScaleMatrix(const double& ScaleFactor)
01338 {
01339     return Matrix(FIXED16(ScaleFactor), FIXED16(ScaleFactor));
01340 }
01341 
01342 
01343 
01344 /********************************************************************************************
01345 
01346 >   static Matrix Matrix::CreateShearMatrix(const double& ShearAngle)
01347 
01348     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01349     Created:    23-07-2000
01350     Inputs:     ShearAngle      the angle clockwise from vertical to shear by, in radians.
01351     Returns:    A shearing matrix.
01352     Purpose:    Factory method - maps directly onto the 'complex' Matrix constructor.
01353 
01354 ********************************************************************************************/
01355 Matrix Matrix::CreateShearMatrix(const double& ShearAngle)
01356 {
01357     FIXED16 one  = FIXED16(1);
01358     FIXED16 zero = FIXED16(0);
01359     FIXED16 shear = FIXED16(tan(ShearAngle));
01360     return Matrix(  one,    zero,
01361                     shear,  one,
01362                     0,      0   );
01363 }
01364 
01365 
01366 
01367 /********************************************************************************************
01368 
01369 >   static Matrix Matrix::CreateRotateMatrix(const double& RotateAngle)
01370 
01371     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01372     Created:    23-07-2000
01373     Inputs:     RotateAngle     the angle to rotate anti-clockwise by, in radians.
01374     Returns:    A rotation matrix.
01375     Purpose:    Factory method - maps directly onto the rotation Matrix constructor.
01376 
01377     Notes:      Karim 06/09/2001
01378                 Method now in use & fixed bug so input is processed as radians, not degrees.
01379 
01380 ********************************************************************************************/
01381 Matrix Matrix::CreateRotateMatrix(const double& RotateAngle)
01382 {
01383     return Matrix(FIXED16(DDegrees(RotateAngle)));
01384 }
01385 
01386 
01387 
01388 /********************************************************************************************
01389 
01390 >   double Matrix::Trace() const
01391 
01392     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01393     Created:    04 September 2000
01394     Returns:    The trace of this matrix (the sum of the elements on its leading diagonal).
01395 
01396     Notes:      Trace(Rotation matrix) = 2cos(theta), where theta is the angle of rotation.
01397                 (Usually 1+2cos(theta), but these are 3x2 matrices).
01398 
01399 ********************************************************************************************/
01400 double Matrix::Trace() const
01401 {
01402     return (a.MakeDouble() + d.MakeDouble());
01403 }
01404 
01405 
01406 
01407 /********************************************************************************************
01408 
01409 >   double Matrix::Det() const
01410 
01411     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01412     Created:    04 September 2000
01413     Returns:    The determinant of this matrix: (ad - bc) if matrix is ((a b),(c d)).
01414 
01415     Notes:      Det(Matrix) = area scale factor on application of the matrix.
01416 
01417 ********************************************************************************************/
01418 double Matrix::Det() const
01419 {
01420     return ( (a.MakeDouble() * d.MakeDouble()) - (b.MakeDouble() * c.MakeDouble()) );
01421 }
01422 
01423 /********************************************************************************************
01424 
01425 >   void Matrix::RatioMatrix (const double ratio)
01426 
01427     Author:     Chris_Snook (Xara Group Ltd) <camelotdev@xara.com>
01428     Created:    ????
01429     Returns:    This routine ratios *this* matrix.  For example, if we have a scaling matrix
01430                 and ratio is 0.5, then we get a scaling matrix that has half the effect of
01431                 the original matrix.
01432 
01433                 Do NOT go changing this routine !!!!!!  It is fundamental to the entire
01434                 animation system - and an error will break everything !!!!!!!
01435 
01436                 You should get CGS to change this routine if needs be ....
01437 
01438                 This routine cannot be used to ratio a rotation matrix. This is because the
01439                 elements in a rotation matrix are cos & sin of the quantity which must be
01440                 interpolated (the angle), and these are non-linear functions.
01441 
01442 ********************************************************************************************/
01443 void Matrix::RatioMatrix (const double ratio)
01444 {
01445     static Matrix Identity;
01446     *this = Identity.Interpolate(*this, ratio);
01447 }
01448 
01449 
01450 
01451 /********************************************************************************************
01452 
01453 >   Matrix Matrix::Interpolate(const Matrix& op, const double ratio) const
01454 
01455     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01456     Created:    25/09/2001
01457 
01458     Inputs:     op      other matrix to interpolate to.
01459                 ratio   interpolation ratio.
01460 
01461     Returns:    Interpolated matrix.
01462 
01463     Purpose:    Interpolate between this and another matrix.
01464 
01465 ********************************************************************************************/
01466 Matrix Matrix::Interpolate(const Matrix& op, const double ratio) const
01467 {
01468     // Essential: 0 <= ratio <= 1.
01469 
01470     if (ratio < 0 || ratio > 1 || Type == TRANS_ROTATION || op.Type == TRANS_ROTATION)
01471     {
01472         ERROR3("Interpolate() requires 0 <= ratio <= 1 and no rotation matrices.");
01473         return Matrix();
01474     }
01475 
01476     else if (ratio == 0)
01477         return *this;
01478 
01479     else if (ratio == 1)
01480         return op;
01481 
01482     else
01483     {
01484         const FIXED16 f16Ratio (ratio);
01485         const FIXED16 f16InvRatio (1 - ratio);
01486 
01487         Matrix temp;
01488 
01489         temp.a = a * f16InvRatio + op.a * f16Ratio;
01490         temp.b = b * f16InvRatio + op.b * f16Ratio;
01491         temp.c = c * f16InvRatio + op.c * f16Ratio;
01492         temp.d = d * f16InvRatio + op.d * f16Ratio;
01493 
01494         temp.e = e * (INT32)((1 - ratio) + op.e * ratio);
01495         temp.f = f * (INT32)((1 - ratio) + op.f * ratio);
01496 
01497         temp.Type   = TRANS_COMPLEX;
01498         temp.Angle  = 0;
01499 
01500         return temp;
01501     }
01502 }
01503 
01504 
01505 
01506 /********************************************************************************************
01507 
01508 >   Matrix Matrix::PostRotate(DocCoord dcCentre, const ANGLE& Angle) const
01509 
01510     Author:     Karim_MacDonald (Xara Group Ltd) <camelotdev@xara.com>
01511     Created:    04/10/2001
01512 
01513     Inputs:     dcCentre    centre of rotation *before* it is transformed by this matrix.
01514                 Angle       angle of rotation, anti-clockwise in degrees.
01515 
01516     Returns:    A matrix which will apply this transformation followed by a rotation of Angle
01517                 around the transformed centre.
01518 
01519     Purpose:    Allows you to transform an object, then rotate it about some point relative
01520                 to its original self, which has now been transformed.
01521 
01522                 eg: squash an object, then rotate it around its centre. You can't
01523                     rotate-then-squash, as you will lose the right-angles. Nor should you
01524                     rotate about its new centre, as this may be different to the transformed
01525                     version of its old centre.
01526 
01527 ********************************************************************************************/
01528 Matrix Matrix::PostRotate(DocCoord dcCentre, const ANGLE& Angle) const
01529 {
01530     transform(&dcCentre);
01531     return (*this) * Matrix(dcCentre, Angle);
01532 }

Generated on Sat Nov 10 03:45:41 2007 for Camelot by  doxygen 1.4.4