Version 6.1.0.2, tag libreoffice-6.1.0.2
[LibreOffice.git] / basegfx / source / inc / hommatrixtemplate.hxx
blob4e00fdf2119c25fb3557479ae0960f2791feca24
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 INCLUDED_BASEGFX_SOURCE_INC_HOMMATRIXTEMPLATE_HXX
21 #define INCLUDED_BASEGFX_SOURCE_INC_HOMMATRIXTEMPLATE_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 < sal_uInt16 RowSize > class ImplMatLine
42 double mfValue[RowSize];
44 public:
45 ImplMatLine()
49 explicit ImplMatLine(sal_uInt16 nRow, ImplMatLine< RowSize >* pToBeCopied)
51 if(pToBeCopied)
53 memcpy(&mfValue, pToBeCopied, sizeof(double) * RowSize);
55 else
57 for(sal_uInt16 a(0); a < RowSize; a++)
59 mfValue[a] = implGetDefaultValue(nRow, a);
64 double get(sal_uInt16 nColumn) const
66 return mfValue[nColumn];
69 void set(sal_uInt16 nColumn, const double& rValue)
71 mfValue[nColumn] = rValue;
75 template < sal_uInt16 RowSize > class ImplHomMatrixTemplate
77 ImplMatLine< RowSize > maLine[RowSize - 1];
78 ImplMatLine< RowSize >* mpLine;
80 public:
81 // Is last line used?
82 bool isLastLineDefault() const
84 if(!mpLine)
85 return true;
87 for(sal_uInt16 a(0); a < RowSize; a++)
89 const double fDefault(implGetDefaultValue((RowSize - 1), a));
90 const double fLineValue(mpLine->get(a));
92 if(!::basegfx::fTools::equal(fDefault, fLineValue))
94 return false;
98 // reset last line, it equals default
99 delete const_cast<ImplHomMatrixTemplate< RowSize >*>(this)->mpLine;
100 const_cast<ImplHomMatrixTemplate< RowSize >*>(this)->mpLine = nullptr;
102 return true;
105 ImplHomMatrixTemplate()
106 : mpLine(nullptr)
108 // complete initialization with identity matrix, all lines
109 // were initialized with a trailing 1 followed by 0's.
110 for(sal_uInt16 a(0); a < RowSize-1; a++)
112 for(sal_uInt16 b(0); b < RowSize; b++)
113 maLine[a].set(b, implGetDefaultValue(a, b) );
117 ImplHomMatrixTemplate(const ImplHomMatrixTemplate& rToBeCopied)
118 : mpLine(nullptr)
120 // complete initialization using copy
121 for(sal_uInt16 a(0); a < (RowSize - 1); a++)
123 memcpy(&maLine[a], &rToBeCopied.maLine[a], sizeof(ImplMatLine< RowSize >));
126 if(rToBeCopied.mpLine)
128 mpLine = new ImplMatLine< RowSize >((RowSize - 1), rToBeCopied.mpLine);
132 ~ImplHomMatrixTemplate()
134 if(mpLine)
136 delete mpLine;
140 static sal_uInt16 getEdgeLength() { return RowSize; }
142 double get(sal_uInt16 nRow, sal_uInt16 nColumn) const
144 if(nRow < (RowSize - 1))
146 return maLine[nRow].get(nColumn);
149 if(mpLine)
151 return mpLine->get(nColumn);
154 return implGetDefaultValue((RowSize - 1), nColumn);
157 void set(sal_uInt16 nRow, sal_uInt16 nColumn, const double& rValue)
159 if(nRow < (RowSize - 1))
161 maLine[nRow].set(nColumn, rValue);
163 else if(mpLine)
165 mpLine->set(nColumn, rValue);
167 else
169 const double fDefault(implGetDefaultValue((RowSize - 1), nColumn));
171 if(!::basegfx::fTools::equal(fDefault, rValue))
173 mpLine = new ImplMatLine< RowSize >((RowSize - 1), nullptr);
174 mpLine->set(nColumn, rValue);
179 void testLastLine()
181 if(mpLine)
183 bool bNecessary(false);
185 for(sal_uInt16 a(0);!bNecessary && a < RowSize; a++)
187 const double fDefault(implGetDefaultValue((RowSize - 1), a));
188 const double fLineValue(mpLine->get(a));
190 if(!::basegfx::fTools::equal(fDefault, fLineValue))
192 bNecessary = true;
196 if(!bNecessary)
198 delete mpLine;
199 mpLine = nullptr;
204 // Left-upper decomposition
205 bool ludcmp(sal_uInt16 nIndex[], sal_Int16& nParity)
207 double fBig, fSum, fDum;
208 double fStorage[RowSize];
209 sal_uInt16 a, b, c;
211 // #i30874# Initialize nAMax (compiler warns)
212 sal_uInt16 nAMax = 0;
214 nParity = 1;
216 // Calc the max of each line. If a line is empty,
217 // stop immediately since matrix is not invertible then.
218 for(a = 0; a < RowSize; a++)
220 fBig = 0.0;
222 for(b = 0; b < RowSize; b++)
224 double fTemp(fabs(get(a, b)));
226 if(::basegfx::fTools::more(fTemp, fBig))
228 fBig = fTemp;
232 if(::basegfx::fTools::equalZero(fBig))
234 return false;
237 fStorage[a] = 1.0 / fBig;
240 // start normalizing
241 for(b = 0; b < RowSize; b++)
243 for(a = 0; a < b; a++)
245 fSum = get(a, b);
247 for(c = 0; c < a; c++)
249 fSum -= get(a, c) * get(c, b);
252 set(a, b, fSum);
255 fBig = 0.0;
257 for(a = b; a < RowSize; a++)
259 fSum = get(a, b);
261 for(c = 0; c < b; c++)
263 fSum -= get(a, c) * get(c, b);
266 set(a, b, fSum);
267 fDum = fStorage[a] * fabs(fSum);
269 if(::basegfx::fTools::moreOrEqual(fDum, fBig))
271 fBig = fDum;
272 nAMax = a;
276 if(b != nAMax)
278 for(c = 0; c < RowSize; c++)
280 fDum = get(nAMax, c);
281 set(nAMax, c, get(b, c));
282 set(b, c, fDum);
285 nParity = -nParity;
286 fStorage[nAMax] = fStorage[b];
289 nIndex[b] = nAMax;
291 // here the failure of precision occurs
292 const double fValBB(fabs(get(b, b)));
294 if(::basegfx::fTools::equalZero(fValBB))
296 return false;
299 if(b != (RowSize - 1))
301 fDum = 1.0 / get(b, b);
303 for(a = b + 1; a < RowSize; a++)
305 set(a, b, get(a, b) * fDum);
310 return true;
313 void lubksb(const sal_uInt16 nIndex[], double fRow[]) const
315 sal_uInt16 b, ip;
316 sal_Int16 a, a2 = -1;
317 double fSum;
319 for(a = 0; a < RowSize; a++)
321 ip = nIndex[a];
322 fSum = fRow[ip];
323 fRow[ip] = fRow[a];
325 if(a2 >= 0)
327 for(b = a2; b < a; b++)
329 fSum -= get(a, b) * fRow[b];
332 else if(!::basegfx::fTools::equalZero(fSum))
334 a2 = a;
337 fRow[a] = fSum;
340 for(a = (RowSize - 1); a >= 0; a--)
342 fSum = fRow[a];
344 for(b = a + 1; b < RowSize; b++)
346 fSum -= get(a, b) * fRow[b];
349 const double fValueAA(get(a, a));
351 if(!::basegfx::fTools::equalZero(fValueAA))
353 fRow[a] = fSum / get(a, a);
358 bool isIdentity() const
360 // last line needs no testing if not existing
361 const sal_uInt16 nMaxLine(
362 sal::static_int_cast<sal_uInt16>(mpLine ? RowSize : (RowSize - 1)) );
364 for(sal_uInt16 a(0); a < nMaxLine; a++)
366 for(sal_uInt16 b(0); b < RowSize; b++)
368 const double fDefault(implGetDefaultValue(a, b));
369 const double fValueAB(get(a, b));
371 if(!::basegfx::fTools::equal(fDefault, fValueAB))
373 return false;
378 return true;
381 bool isInvertible() const
383 ImplHomMatrixTemplate aWork(*this);
384 sal_uInt16 nIndex[RowSize];
385 sal_Int16 nParity;
387 return aWork.ludcmp(nIndex, nParity);
390 void doInvert(const ImplHomMatrixTemplate& rWork, const sal_uInt16 nIndex[])
392 double fArray[RowSize];
394 for(sal_uInt16 a(0); a < RowSize; a++)
396 // prepare line
397 sal_uInt16 b;
398 for( b = 0; b < RowSize; b++)
400 fArray[b] = implGetDefaultValue(a, b);
403 // expand line
404 rWork.lubksb(nIndex, fArray);
406 // copy line transposed to this matrix
407 for( b = 0; b < RowSize; b++)
409 set(b, a, fArray[b]);
413 // evtl. get rid of last matrix line
414 testLastLine();
417 double doDeterminant() const
419 ImplHomMatrixTemplate aWork(*this);
420 sal_uInt16 nIndex[RowSize];
421 sal_Int16 nParity;
422 double fRetval(0.0);
424 if(aWork.ludcmp(nIndex, nParity))
426 fRetval = static_cast<double>(nParity);
428 // last line needs no multiply if not existing; default value would be 1.
429 const sal_uInt16 nMaxLine(
430 sal::static_int_cast<sal_uInt16>(aWork.mpLine ? RowSize : (RowSize - 1)) );
432 for(sal_uInt16 a(0); a < nMaxLine; a++)
434 fRetval *= aWork.get(a, a);
438 return fRetval;
441 void doAddMatrix(const ImplHomMatrixTemplate& rMat)
443 for(sal_uInt16 a(0); a < RowSize; a++)
445 for(sal_uInt16 b(0); b < RowSize; b++)
447 set(a, b, get(a, b) + rMat.get(a, b));
451 testLastLine();
454 void doSubMatrix(const ImplHomMatrixTemplate& rMat)
456 for(sal_uInt16 a(0); a < RowSize; a++)
458 for(sal_uInt16 b(0); b < RowSize; b++)
460 set(a, b, get(a, b) - rMat.get(a, b));
464 testLastLine();
467 void doMulMatrix(const double& rfValue)
469 for(sal_uInt16 a(0); a < RowSize; a++)
471 for(sal_uInt16 b(0); b < RowSize; b++)
473 set(a, b, get(a, b) * rfValue);
477 testLastLine();
480 void doMulMatrix(const ImplHomMatrixTemplate& rMat)
482 // create a copy as source for the original values
483 const ImplHomMatrixTemplate aCopy(*this);
485 // TODO: maybe optimize cases where last line is [0 0 1].
487 double fValue(0.0);
489 for(sal_uInt16 a(0); a < RowSize; ++a)
491 for(sal_uInt16 b(0); b < RowSize; ++b)
493 fValue = 0.0;
495 for(sal_uInt16 c(0); c < RowSize; ++c)
496 fValue += aCopy.get(c, b) * rMat.get(a, c);
498 set(a, b, fValue);
502 testLastLine();
505 bool isEqual(const ImplHomMatrixTemplate& rMat) const
507 const sal_uInt16 nMaxLine(
508 sal::static_int_cast<sal_uInt16>((mpLine || rMat.mpLine) ? RowSize : (RowSize - 1)) );
510 for(sal_uInt16 a(0); a < nMaxLine; a++)
512 for(sal_uInt16 b(0); b < RowSize; b++)
514 const double fValueA(get(a, b));
515 const double fValueB(rMat.get(a, b));
517 if(!::basegfx::fTools::equal(fValueA, fValueB))
519 return false;
524 return true;
528 } // namespace internal
529 } // namespace basegfx
531 #endif // INCLUDED_BASEGFX_SOURCE_INC_HOMMATRIXTEMPLATE_HXX
533 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */