Version 4.2.0.1, tag libreoffice-4.2.0.1
[LibreOffice.git] / basegfx / source / inc / hommatrixtemplate.hxx
blob6342677c5216cd2cb0bfc9addecbe1d8bd0a9393
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #ifndef _HOMMATRIX_TEMPLATE_HXX
21 #define _HOMMATRIX_TEMPLATE_HXX
23 #include <sal/types.h>
24 #include <basegfx/numeric/ftools.hxx>
25 #include <math.h>
26 #include <string.h>
28 namespace basegfx
30 namespace internal
33 inline double implGetDefaultValue(sal_uInt16 nRow, sal_uInt16 nColumn)
35 if(nRow == nColumn)
36 return 1.0;
37 return 0.0;
40 template < unsigned int _RowSize > class ImplMatLine
42 enum { RowSize = _RowSize };
44 double mfValue[RowSize];
46 public:
47 ImplMatLine()
51 explicit ImplMatLine(sal_uInt16 nRow, ImplMatLine< RowSize >* pToBeCopied = 0L)
53 if(pToBeCopied)
55 memcpy(&mfValue, pToBeCopied, sizeof(double) * RowSize);
57 else
59 for(sal_uInt16 a(0); a < RowSize; a++)
61 mfValue[a] = implGetDefaultValue(nRow, a);
66 double get(sal_uInt16 nColumn) const
68 return mfValue[nColumn];
71 void set(sal_uInt16 nColumn, const double& rValue)
73 mfValue[nColumn] = rValue;
77 template < unsigned int _RowSize > class ImplHomMatrixTemplate
79 enum { RowSize = _RowSize };
81 ImplMatLine< RowSize > maLine[RowSize - 1];
82 ImplMatLine< RowSize >* mpLine;
84 public:
85 // Is last line used?
86 bool isLastLineDefault() const
88 if(!mpLine)
89 return true;
91 for(sal_uInt16 a(0); a < RowSize; a++)
93 const double fDefault(implGetDefaultValue((RowSize - 1), a));
94 const double fLineValue(mpLine->get(a));
96 if(!::basegfx::fTools::equal(fDefault, fLineValue))
98 return false;
102 // reset last line, it equals default
103 delete ((ImplHomMatrixTemplate< RowSize >*)this)->mpLine;
104 ((ImplHomMatrixTemplate< RowSize >*)this)->mpLine = 0L;
106 return true;
109 ImplHomMatrixTemplate()
110 : mpLine(0L)
112 // complete initialization with identity matrix, all lines
113 // were initialized with a trailing 1 followed by 0's.
114 for(sal_uInt16 a(0); a < RowSize-1; a++)
116 for(sal_uInt16 b(0); b < RowSize; b++)
117 maLine[a].set(b, implGetDefaultValue(a, b) );
121 ImplHomMatrixTemplate(const ImplHomMatrixTemplate& rToBeCopied)
122 : mpLine(0L)
124 // complete initialization using copy
125 for(sal_uInt16 a(0); a < (RowSize - 1); a++)
127 memcpy(&maLine[a], &rToBeCopied.maLine[a], sizeof(ImplMatLine< RowSize >));
130 if(rToBeCopied.mpLine)
132 mpLine = new ImplMatLine< RowSize >((RowSize - 1), rToBeCopied.mpLine);
136 ~ImplHomMatrixTemplate()
138 if(mpLine)
140 delete mpLine;
144 sal_uInt16 getEdgeLength() const { return RowSize; }
146 double get(sal_uInt16 nRow, sal_uInt16 nColumn) const
148 if(nRow < (RowSize - 1))
150 return maLine[nRow].get(nColumn);
153 if(mpLine)
155 return mpLine->get(nColumn);
158 return implGetDefaultValue((RowSize - 1), nColumn);
161 void set(sal_uInt16 nRow, sal_uInt16 nColumn, const double& rValue)
163 if(nRow < (RowSize - 1))
165 maLine[nRow].set(nColumn, rValue);
167 else if(mpLine)
169 mpLine->set(nColumn, rValue);
171 else
173 const double fDefault(implGetDefaultValue((RowSize - 1), nColumn));
175 if(!::basegfx::fTools::equal(fDefault, rValue))
177 mpLine = new ImplMatLine< RowSize >((RowSize - 1), 0L);
178 mpLine->set(nColumn, rValue);
183 void testLastLine()
185 if(mpLine)
187 bool bNecessary(false);
189 for(sal_uInt16 a(0);!bNecessary && a < RowSize; a++)
191 const double fDefault(implGetDefaultValue((RowSize - 1), a));
192 const double fLineValue(mpLine->get(a));
194 if(!::basegfx::fTools::equal(fDefault, fLineValue))
196 bNecessary = true;
200 if(!bNecessary)
202 delete mpLine;
203 mpLine = 0L;
208 // Left-upper decompositon
209 bool ludcmp(sal_uInt16 nIndex[], sal_Int16& nParity)
211 double fBig, fSum, fDum;
212 double fStorage[RowSize];
213 sal_uInt16 a, b, c;
215 // #i30874# Initialize nAMax (compiler warns)
216 sal_uInt16 nAMax = 0;
218 nParity = 1;
220 // Calc the max of each line. If a line is empty,
221 // stop immediately since matrix is not invertible then.
222 for(a = 0; a < RowSize; a++)
224 fBig = 0.0;
226 for(b = 0; b < RowSize; b++)
228 double fTemp(fabs(get(a, b)));
230 if(::basegfx::fTools::more(fTemp, fBig))
232 fBig = fTemp;
236 if(::basegfx::fTools::equalZero(fBig))
238 return false;
241 fStorage[a] = 1.0 / fBig;
244 // start normalizing
245 for(b = 0; b < RowSize; b++)
247 for(a = 0; a < b; a++)
249 fSum = get(a, b);
251 for(c = 0; c < a; c++)
253 fSum -= get(a, c) * get(c, b);
256 set(a, b, fSum);
259 fBig = 0.0;
261 for(a = b; a < RowSize; a++)
263 fSum = get(a, b);
265 for(c = 0; c < b; c++)
267 fSum -= get(a, c) * get(c, b);
270 set(a, b, fSum);
271 fDum = fStorage[a] * fabs(fSum);
273 if(::basegfx::fTools::moreOrEqual(fDum, fBig))
275 fBig = fDum;
276 nAMax = a;
280 if(b != nAMax)
282 for(c = 0; c < RowSize; c++)
284 fDum = get(nAMax, c);
285 set(nAMax, c, get(b, c));
286 set(b, c, fDum);
289 nParity = -nParity;
290 fStorage[nAMax] = fStorage[b];
293 nIndex[b] = nAMax;
295 // here the failure of precision occurs
296 const double fValBB(fabs(get(b, b)));
298 if(::basegfx::fTools::equalZero(fValBB))
300 return false;
303 if(b != (RowSize - 1))
305 fDum = 1.0 / get(b, b);
307 for(a = b + 1; a < RowSize; a++)
309 set(a, b, get(a, b) * fDum);
314 return true;
317 void lubksb(const sal_uInt16 nIndex[], double fRow[]) const
319 sal_uInt16 b, ip;
320 sal_Int16 a, a2 = -1;
321 double fSum;
323 for(a = 0; a < RowSize; a++)
325 ip = nIndex[a];
326 fSum = fRow[ip];
327 fRow[ip] = fRow[a];
329 if(a2 >= 0)
331 for(b = a2; b < a; b++)
333 fSum -= get(a, b) * fRow[b];
336 else if(!::basegfx::fTools::equalZero(fSum))
338 a2 = a;
341 fRow[a] = fSum;
344 for(a = (RowSize - 1); a >= 0; a--)
346 fSum = fRow[a];
348 for(b = a + 1; b < RowSize; b++)
350 fSum -= get(a, b) * fRow[b];
353 const double fValueAA(get(a, a));
355 if(!::basegfx::fTools::equalZero(fValueAA))
357 fRow[a] = fSum / get(a, a);
362 bool isIdentity() const
364 // last line needs no testing if not existing
365 const sal_uInt16 nMaxLine(
366 sal::static_int_cast<sal_uInt16>(mpLine ? RowSize : (RowSize - 1)) );
368 for(sal_uInt16 a(0); a < nMaxLine; a++)
370 for(sal_uInt16 b(0); b < RowSize; b++)
372 const double fDefault(implGetDefaultValue(a, b));
373 const double fValueAB(get(a, b));
375 if(!::basegfx::fTools::equal(fDefault, fValueAB))
377 return false;
382 return true;
385 bool isInvertible() const
387 ImplHomMatrixTemplate aWork(*this);
388 sal_uInt16 nIndex[RowSize];
389 sal_Int16 nParity;
391 return aWork.ludcmp(nIndex, nParity);
394 bool isNormalized() const
396 if(!mpLine)
397 return true;
399 const double fHomValue(get((RowSize - 1), (RowSize - 1)));
401 if(::basegfx::fTools::equalZero(fHomValue))
403 return true;
406 const double fOne(1.0);
408 if(::basegfx::fTools::equal(fOne, fHomValue))
410 return true;
413 return false;
416 void doInvert(const ImplHomMatrixTemplate& rWork, const sal_uInt16 nIndex[])
418 double fArray[RowSize];
420 for(sal_uInt16 a(0); a < RowSize; a++)
422 // prepare line
423 sal_uInt16 b;
424 for( b = 0; b < RowSize; b++)
426 fArray[b] = implGetDefaultValue(a, b);
429 // expand line
430 rWork.lubksb(nIndex, fArray);
432 // copy line transposed to this matrix
433 for( b = 0; b < RowSize; b++)
435 set(b, a, fArray[b]);
439 // evtl. get rid of last matrix line
440 testLastLine();
443 void doNormalize()
445 if(mpLine)
447 const double fHomValue(get((RowSize - 1), (RowSize - 1)));
449 for(sal_uInt16 a(0); a < RowSize; a++)
451 for(sal_uInt16 b(0); b < RowSize; b++)
453 set(a, b, get(a, b) / fHomValue);
457 // evtl. get rid of last matrix line
458 testLastLine();
462 double doDeterminant() const
464 ImplHomMatrixTemplate aWork(*this);
465 sal_uInt16 nIndex[RowSize];
466 sal_Int16 nParity;
467 double fRetval(0.0);
469 if(aWork.ludcmp(nIndex, nParity))
471 fRetval = (double)nParity;
473 // last line needs no multiply if not existing; default value would be 1.
474 const sal_uInt16 nMaxLine(
475 sal::static_int_cast<sal_uInt16>(aWork.mpLine ? RowSize : (RowSize - 1)) );
477 for(sal_uInt16 a(0); a < nMaxLine; a++)
479 fRetval *= aWork.get(a, a);
483 return fRetval;
486 double doTrace() const
488 double fTrace = (mpLine) ? 0.0 : 1.0;
489 const sal_uInt16 nMaxLine(
490 sal::static_int_cast<sal_uInt16>(mpLine ? RowSize : (RowSize - 1)) );
492 for(sal_uInt16 a(0); a < nMaxLine; a++)
494 fTrace += get(a, a);
497 return fTrace;
500 void doTranspose()
502 for(sal_uInt16 a(0); a < (RowSize - 1); a++)
504 for(sal_uInt16 b(a + 1); b < RowSize; b++)
506 const double fTemp(get(a, b));
507 set(a, b, get(b, a));
508 set(b, a, fTemp);
512 testLastLine();
515 void doAddMatrix(const ImplHomMatrixTemplate& rMat)
517 for(sal_uInt16 a(0); a < RowSize; a++)
519 for(sal_uInt16 b(0); b < RowSize; b++)
521 set(a, b, get(a, b) + rMat.get(a, b));
525 testLastLine();
528 void doSubMatrix(const ImplHomMatrixTemplate& rMat)
530 for(sal_uInt16 a(0); a < RowSize; a++)
532 for(sal_uInt16 b(0); b < RowSize; b++)
534 set(a, b, get(a, b) - rMat.get(a, b));
538 testLastLine();
541 void doMulMatrix(const double& rfValue)
543 for(sal_uInt16 a(0); a < RowSize; a++)
545 for(sal_uInt16 b(0); b < RowSize; b++)
547 set(a, b, get(a, b) * rfValue);
551 testLastLine();
554 void doMulMatrix(const ImplHomMatrixTemplate& rMat)
556 // create a copy as source for the original values
557 const ImplHomMatrixTemplate aCopy(*this);
559 // TODO: maybe optimize cases where last line is [0 0 1].
561 double fValue(0.0);
563 for(sal_uInt16 a(0); a < RowSize; ++a)
565 for(sal_uInt16 b(0); b < RowSize; ++b)
567 fValue = 0.0;
569 for(sal_uInt16 c(0); c < RowSize; ++c)
570 fValue += aCopy.get(c, b) * rMat.get(a, c);
572 set(a, b, fValue);
576 testLastLine();
579 bool isEqual(const ImplHomMatrixTemplate& rMat) const
581 const sal_uInt16 nMaxLine(
582 sal::static_int_cast<sal_uInt16>((mpLine || rMat.mpLine) ? RowSize : (RowSize - 1)) );
584 for(sal_uInt16 a(0); a < nMaxLine; a++)
586 for(sal_uInt16 b(0); b < RowSize; b++)
588 const double fValueA(get(a, b));
589 const double fValueB(rMat.get(a, b));
591 if(!::basegfx::fTools::equal(fValueA, fValueB))
593 return false;
598 return true;
602 } // namespace internal
603 } // namespace basegfx
605 #endif /* _HOMMATRIX_TEMPLATE_HXX */
607 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */