merge the formfield patch from ooo-build
[ooovba.git] / basegfx / source / inc / hommatrixtemplate.hxx
blob5a1251919501bf4c29bea86a2ef7faa06685746c
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: hommatrixtemplate.hxx,v $
10 * $Revision: 1.18.12.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #ifndef _HOMMATRIX_TEMPLATE_HXX
32 #define _HOMMATRIX_TEMPLATE_HXX
34 #include <sal/types.h>
35 #include <basegfx/numeric/ftools.hxx>
36 #include <math.h>
37 #include <string.h>
39 namespace basegfx
41 namespace internal
44 inline double implGetDefaultValue(sal_uInt16 nRow, sal_uInt16 nColumn)
46 if(nRow == nColumn)
47 return 1.0;
48 return 0.0;
51 template < unsigned int _RowSize > class ImplMatLine
53 enum { RowSize = _RowSize };
55 double mfValue[RowSize];
57 public:
58 ImplMatLine()
62 ImplMatLine(sal_uInt16 nRow, ImplMatLine< RowSize >* pToBeCopied = 0L)
64 if(pToBeCopied)
66 memcpy(&mfValue, pToBeCopied, sizeof(double) * RowSize);
68 else
70 for(sal_uInt16 a(0); a < RowSize; a++)
72 mfValue[a] = implGetDefaultValue(nRow, a);
77 double get(sal_uInt16 nColumn) const
79 return mfValue[nColumn];
82 void set(sal_uInt16 nColumn, const double& rValue)
84 mfValue[nColumn] = rValue;
88 template < unsigned int _RowSize > class ImplHomMatrixTemplate
90 enum { RowSize = _RowSize };
92 ImplMatLine< RowSize > maLine[RowSize - 1];
93 ImplMatLine< RowSize >* mpLine;
95 public:
96 // Is last line used?
97 bool isLastLineDefault() const
99 if(!mpLine)
100 return true;
102 for(sal_uInt16 a(0); a < RowSize; a++)
104 const double fDefault(implGetDefaultValue((RowSize - 1), a));
105 const double fLineValue(mpLine->get(a));
107 if(!::basegfx::fTools::equal(fDefault, fLineValue))
109 return false;
113 // reset last line, it equals default
114 delete ((ImplHomMatrixTemplate< RowSize >*)this)->mpLine;
115 ((ImplHomMatrixTemplate< RowSize >*)this)->mpLine = 0L;
117 return true;
120 ImplHomMatrixTemplate()
121 : mpLine(0L)
123 // complete initialization with identity matrix, all lines
124 // were initialized with a trailing 1 followed by 0's.
125 for(sal_uInt16 a(0); a < RowSize-1; a++)
127 for(sal_uInt16 b(0); b < RowSize; b++)
128 maLine[a].set(b, implGetDefaultValue(a, b) );
132 ImplHomMatrixTemplate(const ImplHomMatrixTemplate& rToBeCopied)
133 : mpLine(0L)
135 // complete initialization using copy
136 for(sal_uInt16 a(0); a < (RowSize - 1); a++)
138 memcpy(&maLine[a], &rToBeCopied.maLine[a], sizeof(ImplMatLine< RowSize >));
141 if(rToBeCopied.mpLine)
143 mpLine = new ImplMatLine< RowSize >((RowSize - 1), rToBeCopied.mpLine);
147 ~ImplHomMatrixTemplate()
149 if(mpLine)
151 delete mpLine;
155 sal_uInt16 getEdgeLength() const { return RowSize; }
157 double get(sal_uInt16 nRow, sal_uInt16 nColumn) const
159 if(nRow < (RowSize - 1))
161 return maLine[nRow].get(nColumn);
164 if(mpLine)
166 return mpLine->get(nColumn);
169 return implGetDefaultValue((RowSize - 1), nColumn);
172 void set(sal_uInt16 nRow, sal_uInt16 nColumn, const double& rValue)
174 if(nRow < (RowSize - 1))
176 maLine[nRow].set(nColumn, rValue);
178 else if(mpLine)
180 mpLine->set(nColumn, rValue);
182 else
184 const double fDefault(implGetDefaultValue((RowSize - 1), nColumn));
186 if(!::basegfx::fTools::equal(fDefault, rValue))
188 mpLine = new ImplMatLine< RowSize >((RowSize - 1), 0L);
189 mpLine->set(nColumn, rValue);
194 void testLastLine()
196 if(mpLine)
198 bool bNecessary(false);
200 for(sal_uInt16 a(0);!bNecessary && a < RowSize; a++)
202 const double fDefault(implGetDefaultValue((RowSize - 1), a));
203 const double fLineValue(mpLine->get(a));
205 if(!::basegfx::fTools::equal(fDefault, fLineValue))
207 bNecessary = true;
211 if(!bNecessary)
213 delete mpLine;
214 mpLine = 0L;
219 // Left-upper decompositon
220 bool ludcmp(sal_uInt16 nIndex[], sal_Int16& nParity)
222 double fBig, fSum, fDum;
223 double fStorage[RowSize];
224 sal_uInt16 a, b, c;
226 // #i30874# Initialize nAMax (compiler warns)
227 sal_uInt16 nAMax = 0;
229 nParity = 1;
231 // Calc the max of each line. If a line is empty,
232 // stop immediately since matrix is not invertible then.
233 for(a = 0; a < RowSize; a++)
235 fBig = 0.0;
237 for(b = 0; b < RowSize; b++)
239 double fTemp(fabs(get(a, b)));
241 if(::basegfx::fTools::more(fTemp, fBig))
243 fBig = fTemp;
247 if(::basegfx::fTools::equalZero(fBig))
249 return false;
252 fStorage[a] = 1.0 / fBig;
255 // start normalizing
256 for(b = 0; b < RowSize; b++)
258 for(a = 0; a < b; a++)
260 fSum = get(a, b);
262 for(c = 0; c < a; c++)
264 fSum -= get(a, c) * get(c, b);
267 set(a, b, fSum);
270 fBig = 0.0;
272 for(a = b; a < RowSize; a++)
274 fSum = get(a, b);
276 for(c = 0; c < b; c++)
278 fSum -= get(a, c) * get(c, b);
281 set(a, b, fSum);
282 fDum = fStorage[a] * fabs(fSum);
284 if(::basegfx::fTools::moreOrEqual(fDum, fBig))
286 fBig = fDum;
287 nAMax = a;
291 if(b != nAMax)
293 for(c = 0; c < RowSize; c++)
295 fDum = get(nAMax, c);
296 set(nAMax, c, get(b, c));
297 set(b, c, fDum);
300 nParity = -nParity;
301 fStorage[nAMax] = fStorage[b];
304 nIndex[b] = nAMax;
306 // here the failure of precision occurs
307 const double fValBB(fabs(get(b, b)));
309 if(::basegfx::fTools::equalZero(fValBB))
311 return false;
314 if(b != (RowSize - 1))
316 fDum = 1.0 / get(b, b);
318 for(a = b + 1; a < RowSize; a++)
320 set(a, b, get(a, b) * fDum);
325 return true;
328 void lubksb(const sal_uInt16 nIndex[], double fRow[]) const
330 sal_uInt16 b, ip;
331 sal_Int16 a, a2 = -1;
332 double fSum;
334 for(a = 0; a < RowSize; a++)
336 ip = nIndex[a];
337 fSum = fRow[ip];
338 fRow[ip] = fRow[a];
340 if(a2 >= 0)
342 for(b = a2; b < a; b++)
344 fSum -= get(a, b) * fRow[b];
347 else if(!::basegfx::fTools::equalZero(fSum))
349 a2 = a;
352 fRow[a] = fSum;
355 for(a = (RowSize - 1); a >= 0; a--)
357 fSum = fRow[a];
359 for(b = a + 1; b < RowSize; b++)
361 fSum -= get(a, b) * fRow[b];
364 const double fValueAA(get(a, a));
366 if(!::basegfx::fTools::equalZero(fValueAA))
368 fRow[a] = fSum / get(a, a);
373 bool isIdentity() const
375 // last line needs no testing if not existing
376 const sal_uInt16 nMaxLine(
377 sal::static_int_cast<sal_uInt16>(mpLine ? RowSize : (RowSize - 1)) );
379 for(sal_uInt16 a(0); a < nMaxLine; a++)
381 for(sal_uInt16 b(0); b < RowSize; b++)
383 const double fDefault(implGetDefaultValue(a, b));
384 const double fValueAB(get(a, b));
386 if(!::basegfx::fTools::equal(fDefault, fValueAB))
388 return false;
393 return true;
396 bool isInvertible() const
398 ImplHomMatrixTemplate aWork(*this);
399 sal_uInt16 nIndex[RowSize];
400 sal_Int16 nParity;
402 return aWork.ludcmp(nIndex, nParity);
405 bool isNormalized() const
407 if(!mpLine)
408 return true;
410 const double fHomValue(get((RowSize - 1), (RowSize - 1)));
412 if(::basegfx::fTools::equalZero(fHomValue))
414 return true;
417 const double fOne(1.0);
419 if(::basegfx::fTools::equal(fOne, fHomValue))
421 return true;
424 return false;
427 void doInvert(const ImplHomMatrixTemplate& rWork, const sal_uInt16 nIndex[])
429 double fArray[RowSize];
431 for(sal_uInt16 a(0); a < RowSize; a++)
433 // prepare line
434 sal_uInt16 b;
435 for( b = 0; b < RowSize; b++)
437 fArray[b] = implGetDefaultValue(a, b);
440 // expand line
441 rWork.lubksb(nIndex, fArray);
443 // copy line transposed to this matrix
444 for( b = 0; b < RowSize; b++)
446 set(b, a, fArray[b]);
450 // evtl. get rid of last matrix line
451 testLastLine();
454 void doNormalize()
456 if(mpLine)
458 const double fHomValue(get((RowSize - 1), (RowSize - 1)));
460 for(sal_uInt16 a(0); a < RowSize; a++)
462 for(sal_uInt16 b(0); b < RowSize; b++)
464 set(a, b, get(a, b) / fHomValue);
468 // evtl. get rid of last matrix line
469 testLastLine();
473 double doDeterminant() const
475 ImplHomMatrixTemplate aWork(*this);
476 sal_uInt16 nIndex[RowSize];
477 sal_Int16 nParity;
478 double fRetval(0.0);
480 if(aWork.ludcmp(nIndex, nParity))
482 fRetval = (double)nParity;
484 // last line needs no multiply if not existing; default value would be 1.
485 const sal_uInt16 nMaxLine(
486 sal::static_int_cast<sal_uInt16>(aWork.mpLine ? RowSize : (RowSize - 1)) );
488 for(sal_uInt16 a(0); a < nMaxLine; a++)
490 fRetval *= aWork.get(a, a);
494 return fRetval;
497 double doTrace() const
499 double fTrace = (mpLine) ? 0.0 : 1.0;
500 const sal_uInt16 nMaxLine(
501 sal::static_int_cast<sal_uInt16>(mpLine ? RowSize : (RowSize - 1)) );
503 for(sal_uInt16 a(0); a < nMaxLine; a++)
505 fTrace += get(a, a);
508 return fTrace;
511 void doTranspose()
513 for(sal_uInt16 a(0); a < (RowSize - 1); a++)
515 for(sal_uInt16 b(a + 1); b < RowSize; b++)
517 const double fTemp(get(a, b));
518 set(a, b, get(b, a));
519 set(b, a, fTemp);
523 testLastLine();
526 void doAddMatrix(const ImplHomMatrixTemplate& rMat)
528 for(sal_uInt16 a(0); a < RowSize; a++)
530 for(sal_uInt16 b(0); b < RowSize; b++)
532 set(a, b, get(a, b) + rMat.get(a, b));
536 testLastLine();
539 void doSubMatrix(const ImplHomMatrixTemplate& rMat)
541 for(sal_uInt16 a(0); a < RowSize; a++)
543 for(sal_uInt16 b(0); b < RowSize; b++)
545 set(a, b, get(a, b) - rMat.get(a, b));
549 testLastLine();
552 void doMulMatrix(const double& rfValue)
554 for(sal_uInt16 a(0); a < RowSize; a++)
556 for(sal_uInt16 b(0); b < RowSize; b++)
558 set(a, b, get(a, b) * rfValue);
562 testLastLine();
565 void doMulMatrix(const ImplHomMatrixTemplate& rMat)
567 // create a copy as source for the original values
568 const ImplHomMatrixTemplate aCopy(*this);
570 // TODO: maybe optimize cases where last line is [0 0 1].
572 double fValue(0.0);
574 for(sal_uInt16 a(0); a < RowSize; ++a)
576 for(sal_uInt16 b(0); b < RowSize; ++b)
578 fValue = 0.0;
580 for(sal_uInt16 c(0); c < RowSize; ++c)
581 fValue += aCopy.get(c, b) * rMat.get(a, c);
583 set(a, b, fValue);
587 testLastLine();
590 bool isEqual(const ImplHomMatrixTemplate& rMat) const
592 const sal_uInt16 nMaxLine(
593 sal::static_int_cast<sal_uInt16>((mpLine || rMat.mpLine) ? RowSize : (RowSize - 1)) );
595 for(sal_uInt16 a(0); a < nMaxLine; a++)
597 for(sal_uInt16 b(0); b < RowSize; b++)
599 const double fValueA(get(a, b));
600 const double fValueB(rMat.get(a, b));
602 if(!::basegfx::fTools::equal(fValueA, fValueB))
604 return false;
609 return true;
613 } // namespace internal
614 } // namespace basegfx
616 #endif /* _HOMMATRIX_TEMPLATE_HXX */