Version 6.4.0.0.beta1, tag libreoffice-6.4.0.0.beta1
[LibreOffice.git] / basegfx / source / inc / hommatrixtemplate.hxx
blob6213d61f2e29b038ccc48b36752860fbe8252b34
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 <cmath>
26 #include <string.h>
28 #include <memory>
30 namespace basegfx
32 namespace internal
35 inline double implGetDefaultValue(sal_uInt16 nRow, sal_uInt16 nColumn)
37 if(nRow == nColumn)
38 return 1.0;
39 return 0.0;
42 template < sal_uInt16 RowSize > class ImplMatLine
44 double mfValue[RowSize];
46 public:
47 ImplMatLine()
51 explicit ImplMatLine(sal_uInt16 nRow, ImplMatLine< RowSize >* pToBeCopied)
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 < sal_uInt16 RowSize > class ImplHomMatrixTemplate
79 ImplMatLine< RowSize > maLine[RowSize - 1];
80 std::unique_ptr<ImplMatLine< RowSize >> mutable mpLine;
82 public:
83 // Is last line used?
84 bool isLastLineDefault() const
86 if(!mpLine)
87 return true;
89 for(sal_uInt16 a(0); a < RowSize; a++)
91 const double fDefault(implGetDefaultValue((RowSize - 1), a));
92 const double fLineValue(mpLine->get(a));
94 if(!::basegfx::fTools::equal(fDefault, fLineValue))
96 return false;
100 // reset last line, it equals default
101 mpLine.reset();
103 return true;
106 ImplHomMatrixTemplate()
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)
119 operator=(rToBeCopied);
122 ImplHomMatrixTemplate& operator=(const ImplHomMatrixTemplate& rToBeCopied)
124 if (this != &rToBeCopied)
126 // complete initialization using copy
127 for(sal_uInt16 a(0); a < (RowSize - 1); a++)
129 memcpy(&maLine[a], &rToBeCopied.maLine[a], sizeof(ImplMatLine< RowSize >));
131 if(rToBeCopied.mpLine)
133 mpLine.reset( new ImplMatLine< RowSize >((RowSize - 1), rToBeCopied.mpLine.get()) );
136 return *this;
139 static sal_uInt16 getEdgeLength() { return RowSize; }
141 double get(sal_uInt16 nRow, sal_uInt16 nColumn) const
143 if(nRow < (RowSize - 1))
145 return maLine[nRow].get(nColumn);
148 if(mpLine)
150 return mpLine->get(nColumn);
153 return implGetDefaultValue((RowSize - 1), nColumn);
156 void set(sal_uInt16 nRow, sal_uInt16 nColumn, const double& rValue)
158 if(nRow < (RowSize - 1))
160 maLine[nRow].set(nColumn, rValue);
162 else if(mpLine)
164 mpLine->set(nColumn, rValue);
166 else
168 const double fDefault(implGetDefaultValue((RowSize - 1), nColumn));
170 if(!::basegfx::fTools::equal(fDefault, rValue))
172 mpLine.reset(new ImplMatLine< RowSize >((RowSize - 1), nullptr));
173 mpLine->set(nColumn, rValue);
178 void testLastLine()
180 if(mpLine)
182 bool bNecessary(false);
184 for(sal_uInt16 a(0);!bNecessary && a < RowSize; a++)
186 const double fDefault(implGetDefaultValue((RowSize - 1), a));
187 const double fLineValue(mpLine->get(a));
189 if(!::basegfx::fTools::equal(fDefault, fLineValue))
191 bNecessary = true;
195 if(!bNecessary)
197 mpLine.reset();
202 // Left-upper decomposition
203 bool ludcmp(sal_uInt16 nIndex[], sal_Int16& nParity)
205 double fBig, fSum, fDum;
206 double fStorage[RowSize];
207 sal_uInt16 a, b, c;
209 // #i30874# Initialize nAMax (compiler warns)
210 sal_uInt16 nAMax = 0;
212 nParity = 1;
214 // Calc the max of each line. If a line is empty,
215 // stop immediately since matrix is not invertible then.
216 for(a = 0; a < RowSize; a++)
218 fBig = 0.0;
220 for(b = 0; b < RowSize; b++)
222 double fTemp(fabs(get(a, b)));
224 if(::basegfx::fTools::more(fTemp, fBig))
226 fBig = fTemp;
230 if(::basegfx::fTools::equalZero(fBig))
232 return false;
235 fStorage[a] = 1.0 / fBig;
238 // start normalizing
239 for(b = 0; b < RowSize; b++)
241 for(a = 0; a < b; a++)
243 fSum = get(a, b);
245 for(c = 0; c < a; c++)
247 fSum -= get(a, c) * get(c, b);
250 set(a, b, fSum);
253 fBig = 0.0;
255 for(a = b; a < RowSize; a++)
257 fSum = get(a, b);
259 for(c = 0; c < b; c++)
261 fSum -= get(a, c) * get(c, b);
264 set(a, b, fSum);
265 fDum = fStorage[a] * fabs(fSum);
267 if(::basegfx::fTools::moreOrEqual(fDum, fBig))
269 fBig = fDum;
270 nAMax = a;
274 if(b != nAMax)
276 for(c = 0; c < RowSize; c++)
278 fDum = get(nAMax, c);
279 set(nAMax, c, get(b, c));
280 set(b, c, fDum);
283 nParity = -nParity;
284 fStorage[nAMax] = fStorage[b];
287 nIndex[b] = nAMax;
289 // here the failure of precision occurs
290 const double fValBB(fabs(get(b, b)));
292 if(::basegfx::fTools::equalZero(fValBB))
294 return false;
297 if(b != (RowSize - 1))
299 fDum = 1.0 / get(b, b);
301 for(a = b + 1; a < RowSize; a++)
303 set(a, b, get(a, b) * fDum);
308 return true;
311 void lubksb(const sal_uInt16 nIndex[], double fRow[]) const
313 sal_uInt16 b, ip;
314 sal_Int16 a, a2 = -1;
315 double fSum;
317 for(a = 0; a < RowSize; a++)
319 ip = nIndex[a];
320 fSum = fRow[ip];
321 fRow[ip] = fRow[a];
323 if(a2 >= 0)
325 for(b = a2; b < a; b++)
327 fSum -= get(a, b) * fRow[b];
330 else if(!::basegfx::fTools::equalZero(fSum))
332 a2 = a;
335 fRow[a] = fSum;
338 for(a = (RowSize - 1); a >= 0; a--)
340 fSum = fRow[a];
342 for(b = a + 1; b < RowSize; b++)
344 fSum -= get(a, b) * fRow[b];
347 const double fValueAA(get(a, a));
349 if(!::basegfx::fTools::equalZero(fValueAA))
351 fRow[a] = fSum / get(a, a);
356 bool isIdentity() const
358 // last line needs no testing if not existing
359 const sal_uInt16 nMaxLine(
360 sal::static_int_cast<sal_uInt16>(mpLine ? RowSize : (RowSize - 1)) );
362 for(sal_uInt16 a(0); a < nMaxLine; a++)
364 for(sal_uInt16 b(0); b < RowSize; b++)
366 const double fDefault(implGetDefaultValue(a, b));
367 const double fValueAB(get(a, b));
369 if(!::basegfx::fTools::equal(fDefault, fValueAB))
371 return false;
376 return true;
379 bool isInvertible() const
381 ImplHomMatrixTemplate aWork(*this);
382 sal_uInt16 nIndex[RowSize];
383 sal_Int16 nParity;
385 return aWork.ludcmp(nIndex, nParity);
388 void doInvert(const ImplHomMatrixTemplate& rWork, const sal_uInt16 nIndex[])
390 double fArray[RowSize];
392 for(sal_uInt16 a(0); a < RowSize; a++)
394 // prepare line
395 sal_uInt16 b;
396 for( b = 0; b < RowSize; b++)
398 fArray[b] = implGetDefaultValue(a, b);
401 // expand line
402 rWork.lubksb(nIndex, fArray);
404 // copy line transposed to this matrix
405 for( b = 0; b < RowSize; b++)
407 set(b, a, fArray[b]);
411 // evtl. get rid of last matrix line
412 testLastLine();
415 double doDeterminant() const
417 ImplHomMatrixTemplate aWork(*this);
418 sal_uInt16 nIndex[RowSize];
419 sal_Int16 nParity;
420 double fRetval(0.0);
422 if(aWork.ludcmp(nIndex, nParity))
424 fRetval = static_cast<double>(nParity);
426 // last line needs no multiply if not existing; default value would be 1.
427 const sal_uInt16 nMaxLine(
428 sal::static_int_cast<sal_uInt16>(aWork.mpLine ? RowSize : (RowSize - 1)) );
430 for(sal_uInt16 a(0); a < nMaxLine; a++)
432 fRetval *= aWork.get(a, a);
436 return fRetval;
439 void doAddMatrix(const ImplHomMatrixTemplate& rMat)
441 for(sal_uInt16 a(0); a < RowSize; a++)
443 for(sal_uInt16 b(0); b < RowSize; b++)
445 set(a, b, get(a, b) + rMat.get(a, b));
449 testLastLine();
452 void doSubMatrix(const ImplHomMatrixTemplate& rMat)
454 for(sal_uInt16 a(0); a < RowSize; a++)
456 for(sal_uInt16 b(0); b < RowSize; b++)
458 set(a, b, get(a, b) - rMat.get(a, b));
462 testLastLine();
465 void doMulMatrix(const double& rfValue)
467 for(sal_uInt16 a(0); a < RowSize; a++)
469 for(sal_uInt16 b(0); b < RowSize; b++)
471 set(a, b, get(a, b) * rfValue);
475 testLastLine();
478 void doMulMatrix(const ImplHomMatrixTemplate& rMat)
480 // create a copy as source for the original values
481 const ImplHomMatrixTemplate aCopy(*this);
483 // TODO: maybe optimize cases where last line is [0 0 1].
485 double fValue(0.0);
487 for(sal_uInt16 a(0); a < RowSize; ++a)
489 for(sal_uInt16 b(0); b < RowSize; ++b)
491 fValue = 0.0;
493 for(sal_uInt16 c(0); c < RowSize; ++c)
494 fValue += aCopy.get(c, b) * rMat.get(a, c);
496 set(a, b, fValue);
500 testLastLine();
503 bool isEqual(const ImplHomMatrixTemplate& rMat) const
505 const sal_uInt16 nMaxLine(
506 sal::static_int_cast<sal_uInt16>((mpLine || rMat.mpLine) ? RowSize : (RowSize - 1)) );
508 for(sal_uInt16 a(0); a < nMaxLine; a++)
510 for(sal_uInt16 b(0); b < RowSize; b++)
512 const double fValueA(get(a, b));
513 const double fValueB(rMat.get(a, b));
515 if(!::basegfx::fTools::equal(fValueA, fValueB))
517 return false;
522 return true;
526 } // namespace internal
527 } // namespace basegfx
529 #endif // INCLUDED_BASEGFX_SOURCE_INC_HOMMATRIXTEMPLATE_HXX
531 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */