merged tag ooo/OOO330_m14
[LibreOffice.git] / basegfx / source / inc / hommatrixtemplate.hxx
blobfe58ed2602912d469378f0a78534bb1442ded021
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 #ifndef _HOMMATRIX_TEMPLATE_HXX
29 #define _HOMMATRIX_TEMPLATE_HXX
31 #include <sal/types.h>
32 #include <basegfx/numeric/ftools.hxx>
33 #include <math.h>
34 #include <string.h>
36 namespace basegfx
38 namespace internal
41 inline double implGetDefaultValue(sal_uInt16 nRow, sal_uInt16 nColumn)
43 if(nRow == nColumn)
44 return 1.0;
45 return 0.0;
48 template < unsigned int _RowSize > class ImplMatLine
50 enum { RowSize = _RowSize };
52 double mfValue[RowSize];
54 public:
55 ImplMatLine()
59 ImplMatLine(sal_uInt16 nRow, ImplMatLine< RowSize >* pToBeCopied = 0L)
61 if(pToBeCopied)
63 memcpy(&mfValue, pToBeCopied, sizeof(double) * RowSize);
65 else
67 for(sal_uInt16 a(0); a < RowSize; a++)
69 mfValue[a] = implGetDefaultValue(nRow, a);
74 double get(sal_uInt16 nColumn) const
76 return mfValue[nColumn];
79 void set(sal_uInt16 nColumn, const double& rValue)
81 mfValue[nColumn] = rValue;
85 template < unsigned int _RowSize > class ImplHomMatrixTemplate
87 enum { RowSize = _RowSize };
89 ImplMatLine< RowSize > maLine[RowSize - 1];
90 ImplMatLine< RowSize >* mpLine;
92 public:
93 // Is last line used?
94 bool isLastLineDefault() const
96 if(!mpLine)
97 return true;
99 for(sal_uInt16 a(0); a < RowSize; a++)
101 const double fDefault(implGetDefaultValue((RowSize - 1), a));
102 const double fLineValue(mpLine->get(a));
104 if(!::basegfx::fTools::equal(fDefault, fLineValue))
106 return false;
110 // reset last line, it equals default
111 delete ((ImplHomMatrixTemplate< RowSize >*)this)->mpLine;
112 ((ImplHomMatrixTemplate< RowSize >*)this)->mpLine = 0L;
114 return true;
117 ImplHomMatrixTemplate()
118 : mpLine(0L)
120 // complete initialization with identity matrix, all lines
121 // were initialized with a trailing 1 followed by 0's.
122 for(sal_uInt16 a(0); a < RowSize-1; a++)
124 for(sal_uInt16 b(0); b < RowSize; b++)
125 maLine[a].set(b, implGetDefaultValue(a, b) );
129 ImplHomMatrixTemplate(const ImplHomMatrixTemplate& rToBeCopied)
130 : mpLine(0L)
132 // complete initialization using copy
133 for(sal_uInt16 a(0); a < (RowSize - 1); a++)
135 memcpy(&maLine[a], &rToBeCopied.maLine[a], sizeof(ImplMatLine< RowSize >));
138 if(rToBeCopied.mpLine)
140 mpLine = new ImplMatLine< RowSize >((RowSize - 1), rToBeCopied.mpLine);
144 ~ImplHomMatrixTemplate()
146 if(mpLine)
148 delete mpLine;
152 sal_uInt16 getEdgeLength() const { return RowSize; }
154 double get(sal_uInt16 nRow, sal_uInt16 nColumn) const
156 if(nRow < (RowSize - 1))
158 return maLine[nRow].get(nColumn);
161 if(mpLine)
163 return mpLine->get(nColumn);
166 return implGetDefaultValue((RowSize - 1), nColumn);
169 void set(sal_uInt16 nRow, sal_uInt16 nColumn, const double& rValue)
171 if(nRow < (RowSize - 1))
173 maLine[nRow].set(nColumn, rValue);
175 else if(mpLine)
177 mpLine->set(nColumn, rValue);
179 else
181 const double fDefault(implGetDefaultValue((RowSize - 1), nColumn));
183 if(!::basegfx::fTools::equal(fDefault, rValue))
185 mpLine = new ImplMatLine< RowSize >((RowSize - 1), 0L);
186 mpLine->set(nColumn, rValue);
191 void testLastLine()
193 if(mpLine)
195 bool bNecessary(false);
197 for(sal_uInt16 a(0);!bNecessary && a < RowSize; a++)
199 const double fDefault(implGetDefaultValue((RowSize - 1), a));
200 const double fLineValue(mpLine->get(a));
202 if(!::basegfx::fTools::equal(fDefault, fLineValue))
204 bNecessary = true;
208 if(!bNecessary)
210 delete mpLine;
211 mpLine = 0L;
216 // Left-upper decompositon
217 bool ludcmp(sal_uInt16 nIndex[], sal_Int16& nParity)
219 double fBig, fSum, fDum;
220 double fStorage[RowSize];
221 sal_uInt16 a, b, c;
223 // #i30874# Initialize nAMax (compiler warns)
224 sal_uInt16 nAMax = 0;
226 nParity = 1;
228 // Calc the max of each line. If a line is empty,
229 // stop immediately since matrix is not invertible then.
230 for(a = 0; a < RowSize; a++)
232 fBig = 0.0;
234 for(b = 0; b < RowSize; b++)
236 double fTemp(fabs(get(a, b)));
238 if(::basegfx::fTools::more(fTemp, fBig))
240 fBig = fTemp;
244 if(::basegfx::fTools::equalZero(fBig))
246 return false;
249 fStorage[a] = 1.0 / fBig;
252 // start normalizing
253 for(b = 0; b < RowSize; b++)
255 for(a = 0; a < b; a++)
257 fSum = get(a, b);
259 for(c = 0; c < a; c++)
261 fSum -= get(a, c) * get(c, b);
264 set(a, b, fSum);
267 fBig = 0.0;
269 for(a = b; a < RowSize; a++)
271 fSum = get(a, b);
273 for(c = 0; c < b; c++)
275 fSum -= get(a, c) * get(c, b);
278 set(a, b, fSum);
279 fDum = fStorage[a] * fabs(fSum);
281 if(::basegfx::fTools::moreOrEqual(fDum, fBig))
283 fBig = fDum;
284 nAMax = a;
288 if(b != nAMax)
290 for(c = 0; c < RowSize; c++)
292 fDum = get(nAMax, c);
293 set(nAMax, c, get(b, c));
294 set(b, c, fDum);
297 nParity = -nParity;
298 fStorage[nAMax] = fStorage[b];
301 nIndex[b] = nAMax;
303 // here the failure of precision occurs
304 const double fValBB(fabs(get(b, b)));
306 if(::basegfx::fTools::equalZero(fValBB))
308 return false;
311 if(b != (RowSize - 1))
313 fDum = 1.0 / get(b, b);
315 for(a = b + 1; a < RowSize; a++)
317 set(a, b, get(a, b) * fDum);
322 return true;
325 void lubksb(const sal_uInt16 nIndex[], double fRow[]) const
327 sal_uInt16 b, ip;
328 sal_Int16 a, a2 = -1;
329 double fSum;
331 for(a = 0; a < RowSize; a++)
333 ip = nIndex[a];
334 fSum = fRow[ip];
335 fRow[ip] = fRow[a];
337 if(a2 >= 0)
339 for(b = a2; b < a; b++)
341 fSum -= get(a, b) * fRow[b];
344 else if(!::basegfx::fTools::equalZero(fSum))
346 a2 = a;
349 fRow[a] = fSum;
352 for(a = (RowSize - 1); a >= 0; a--)
354 fSum = fRow[a];
356 for(b = a + 1; b < RowSize; b++)
358 fSum -= get(a, b) * fRow[b];
361 const double fValueAA(get(a, a));
363 if(!::basegfx::fTools::equalZero(fValueAA))
365 fRow[a] = fSum / get(a, a);
370 bool isIdentity() const
372 // last line needs no testing if not existing
373 const sal_uInt16 nMaxLine(
374 sal::static_int_cast<sal_uInt16>(mpLine ? RowSize : (RowSize - 1)) );
376 for(sal_uInt16 a(0); a < nMaxLine; a++)
378 for(sal_uInt16 b(0); b < RowSize; b++)
380 const double fDefault(implGetDefaultValue(a, b));
381 const double fValueAB(get(a, b));
383 if(!::basegfx::fTools::equal(fDefault, fValueAB))
385 return false;
390 return true;
393 bool isInvertible() const
395 ImplHomMatrixTemplate aWork(*this);
396 sal_uInt16 nIndex[RowSize];
397 sal_Int16 nParity;
399 return aWork.ludcmp(nIndex, nParity);
402 bool isNormalized() const
404 if(!mpLine)
405 return true;
407 const double fHomValue(get((RowSize - 1), (RowSize - 1)));
409 if(::basegfx::fTools::equalZero(fHomValue))
411 return true;
414 const double fOne(1.0);
416 if(::basegfx::fTools::equal(fOne, fHomValue))
418 return true;
421 return false;
424 void doInvert(const ImplHomMatrixTemplate& rWork, const sal_uInt16 nIndex[])
426 double fArray[RowSize];
428 for(sal_uInt16 a(0); a < RowSize; a++)
430 // prepare line
431 sal_uInt16 b;
432 for( b = 0; b < RowSize; b++)
434 fArray[b] = implGetDefaultValue(a, b);
437 // expand line
438 rWork.lubksb(nIndex, fArray);
440 // copy line transposed to this matrix
441 for( b = 0; b < RowSize; b++)
443 set(b, a, fArray[b]);
447 // evtl. get rid of last matrix line
448 testLastLine();
451 void doNormalize()
453 if(mpLine)
455 const double fHomValue(get((RowSize - 1), (RowSize - 1)));
457 for(sal_uInt16 a(0); a < RowSize; a++)
459 for(sal_uInt16 b(0); b < RowSize; b++)
461 set(a, b, get(a, b) / fHomValue);
465 // evtl. get rid of last matrix line
466 testLastLine();
470 double doDeterminant() const
472 ImplHomMatrixTemplate aWork(*this);
473 sal_uInt16 nIndex[RowSize];
474 sal_Int16 nParity;
475 double fRetval(0.0);
477 if(aWork.ludcmp(nIndex, nParity))
479 fRetval = (double)nParity;
481 // last line needs no multiply if not existing; default value would be 1.
482 const sal_uInt16 nMaxLine(
483 sal::static_int_cast<sal_uInt16>(aWork.mpLine ? RowSize : (RowSize - 1)) );
485 for(sal_uInt16 a(0); a < nMaxLine; a++)
487 fRetval *= aWork.get(a, a);
491 return fRetval;
494 double doTrace() const
496 double fTrace = (mpLine) ? 0.0 : 1.0;
497 const sal_uInt16 nMaxLine(
498 sal::static_int_cast<sal_uInt16>(mpLine ? RowSize : (RowSize - 1)) );
500 for(sal_uInt16 a(0); a < nMaxLine; a++)
502 fTrace += get(a, a);
505 return fTrace;
508 void doTranspose()
510 for(sal_uInt16 a(0); a < (RowSize - 1); a++)
512 for(sal_uInt16 b(a + 1); b < RowSize; b++)
514 const double fTemp(get(a, b));
515 set(a, b, get(b, a));
516 set(b, a, fTemp);
520 testLastLine();
523 void doAddMatrix(const ImplHomMatrixTemplate& rMat)
525 for(sal_uInt16 a(0); a < RowSize; a++)
527 for(sal_uInt16 b(0); b < RowSize; b++)
529 set(a, b, get(a, b) + rMat.get(a, b));
533 testLastLine();
536 void doSubMatrix(const ImplHomMatrixTemplate& rMat)
538 for(sal_uInt16 a(0); a < RowSize; a++)
540 for(sal_uInt16 b(0); b < RowSize; b++)
542 set(a, b, get(a, b) - rMat.get(a, b));
546 testLastLine();
549 void doMulMatrix(const double& rfValue)
551 for(sal_uInt16 a(0); a < RowSize; a++)
553 for(sal_uInt16 b(0); b < RowSize; b++)
555 set(a, b, get(a, b) * rfValue);
559 testLastLine();
562 void doMulMatrix(const ImplHomMatrixTemplate& rMat)
564 // create a copy as source for the original values
565 const ImplHomMatrixTemplate aCopy(*this);
567 // TODO: maybe optimize cases where last line is [0 0 1].
569 double fValue(0.0);
571 for(sal_uInt16 a(0); a < RowSize; ++a)
573 for(sal_uInt16 b(0); b < RowSize; ++b)
575 fValue = 0.0;
577 for(sal_uInt16 c(0); c < RowSize; ++c)
578 fValue += aCopy.get(c, b) * rMat.get(a, c);
580 set(a, b, fValue);
584 testLastLine();
587 bool isEqual(const ImplHomMatrixTemplate& rMat) const
589 const sal_uInt16 nMaxLine(
590 sal::static_int_cast<sal_uInt16>((mpLine || rMat.mpLine) ? RowSize : (RowSize - 1)) );
592 for(sal_uInt16 a(0); a < nMaxLine; a++)
594 for(sal_uInt16 b(0); b < RowSize; b++)
596 const double fValueA(get(a, b));
597 const double fValueB(rMat.get(a, b));
599 if(!::basegfx::fTools::equal(fValueA, fValueB))
601 return false;
606 return true;
610 } // namespace internal
611 } // namespace basegfx
613 #endif /* _HOMMATRIX_TEMPLATE_HXX */