1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
35 inline double implGetDefaultValue(sal_uInt16 nRow
, sal_uInt16 nColumn
)
42 template < sal_uInt16 RowSize
> class ImplMatLine
44 double mfValue
[RowSize
];
51 explicit ImplMatLine(sal_uInt16 nRow
, ImplMatLine
< RowSize
>* pToBeCopied
)
55 memcpy(&mfValue
, pToBeCopied
, sizeof(double) * RowSize
);
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
;
84 bool isLastLineDefault() const
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
))
100 // reset last line, it equals default
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()) );
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
);
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
);
164 mpLine
->set(nColumn
, rValue
);
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
);
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
))
202 // Left-upper decomposition
203 bool ludcmp(sal_uInt16 nIndex
[], sal_Int16
& nParity
)
205 double fBig
, fSum
, fDum
;
206 double fStorage
[RowSize
];
209 // #i30874# Initialize nAMax (compiler warns)
210 sal_uInt16 nAMax
= 0;
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
++)
220 for(b
= 0; b
< RowSize
; b
++)
222 double fTemp(fabs(get(a
, b
)));
224 if(::basegfx::fTools::more(fTemp
, fBig
))
230 if(::basegfx::fTools::equalZero(fBig
))
235 fStorage
[a
] = 1.0 / fBig
;
239 for(b
= 0; b
< RowSize
; b
++)
241 for(a
= 0; a
< b
; a
++)
245 for(c
= 0; c
< a
; c
++)
247 fSum
-= get(a
, c
) * get(c
, b
);
255 for(a
= b
; a
< RowSize
; a
++)
259 for(c
= 0; c
< b
; c
++)
261 fSum
-= get(a
, c
) * get(c
, b
);
265 fDum
= fStorage
[a
] * fabs(fSum
);
267 if(::basegfx::fTools::moreOrEqual(fDum
, fBig
))
276 for(c
= 0; c
< RowSize
; c
++)
278 fDum
= get(nAMax
, c
);
279 set(nAMax
, c
, get(b
, c
));
284 fStorage
[nAMax
] = fStorage
[b
];
289 // here the failure of precision occurs
290 const double fValBB(fabs(get(b
, b
)));
292 if(::basegfx::fTools::equalZero(fValBB
))
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
);
311 void lubksb(const sal_uInt16 nIndex
[], double fRow
[]) const
314 sal_Int16 a
, a2
= -1;
317 for(a
= 0; a
< RowSize
; a
++)
325 for(b
= a2
; b
< a
; b
++)
327 fSum
-= get(a
, b
) * fRow
[b
];
330 else if(!::basegfx::fTools::equalZero(fSum
))
338 for(a
= (RowSize
- 1); a
>= 0; 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
))
379 bool isInvertible() const
381 ImplHomMatrixTemplate
aWork(*this);
382 sal_uInt16 nIndex
[RowSize
];
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
++)
396 for( b
= 0; b
< RowSize
; b
++)
398 fArray
[b
] = implGetDefaultValue(a
, b
);
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
415 double doDeterminant() const
417 ImplHomMatrixTemplate
aWork(*this);
418 sal_uInt16 nIndex
[RowSize
];
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
);
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
));
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
));
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
);
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].
487 for(sal_uInt16
a(0); a
< RowSize
; ++a
)
489 for(sal_uInt16
b(0); b
< RowSize
; ++b
)
493 for(sal_uInt16
c(0); c
< RowSize
; ++c
)
494 fValue
+= aCopy
.get(c
, b
) * rMat
.get(a
, c
);
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
))
526 } // namespace internal
527 } // namespace basegfx
529 #endif // INCLUDED_BASEGFX_SOURCE_INC_HOMMATRIXTEMPLATE_HXX
531 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */