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 }