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>
33 inline double implGetDefaultValue(sal_uInt16 nRow
, sal_uInt16 nColumn
)
40 template < sal_uInt16 RowSize
> class ImplMatLine
42 double mfValue
[RowSize
];
49 explicit ImplMatLine(sal_uInt16 nRow
, ImplMatLine
< RowSize
>* pToBeCopied
)
53 memcpy(&mfValue
, pToBeCopied
, sizeof(double) * RowSize
);
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
;
82 bool isLastLineDefault() const
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
))
98 // reset last line, it equals default
99 delete const_cast<ImplHomMatrixTemplate
< RowSize
>*>(this)->mpLine
;
100 const_cast<ImplHomMatrixTemplate
< RowSize
>*>(this)->mpLine
= nullptr;
105 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
)
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()
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
);
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
);
165 mpLine
->set(nColumn
, rValue
);
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
);
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
))
204 // Left-upper decomposition
205 bool ludcmp(sal_uInt16 nIndex
[], sal_Int16
& nParity
)
207 double fBig
, fSum
, fDum
;
208 double fStorage
[RowSize
];
211 // #i30874# Initialize nAMax (compiler warns)
212 sal_uInt16 nAMax
= 0;
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
++)
222 for(b
= 0; b
< RowSize
; b
++)
224 double fTemp(fabs(get(a
, b
)));
226 if(::basegfx::fTools::more(fTemp
, fBig
))
232 if(::basegfx::fTools::equalZero(fBig
))
237 fStorage
[a
] = 1.0 / fBig
;
241 for(b
= 0; b
< RowSize
; b
++)
243 for(a
= 0; a
< b
; a
++)
247 for(c
= 0; c
< a
; c
++)
249 fSum
-= get(a
, c
) * get(c
, b
);
257 for(a
= b
; a
< RowSize
; a
++)
261 for(c
= 0; c
< b
; c
++)
263 fSum
-= get(a
, c
) * get(c
, b
);
267 fDum
= fStorage
[a
] * fabs(fSum
);
269 if(::basegfx::fTools::moreOrEqual(fDum
, fBig
))
278 for(c
= 0; c
< RowSize
; c
++)
280 fDum
= get(nAMax
, c
);
281 set(nAMax
, c
, get(b
, c
));
286 fStorage
[nAMax
] = fStorage
[b
];
291 // here the failure of precision occurs
292 const double fValBB(fabs(get(b
, b
)));
294 if(::basegfx::fTools::equalZero(fValBB
))
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
);
313 void lubksb(const sal_uInt16 nIndex
[], double fRow
[]) const
316 sal_Int16 a
, a2
= -1;
319 for(a
= 0; a
< RowSize
; a
++)
327 for(b
= a2
; b
< a
; b
++)
329 fSum
-= get(a
, b
) * fRow
[b
];
332 else if(!::basegfx::fTools::equalZero(fSum
))
340 for(a
= (RowSize
- 1); a
>= 0; 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
))
381 bool isInvertible() const
383 ImplHomMatrixTemplate
aWork(*this);
384 sal_uInt16 nIndex
[RowSize
];
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
++)
398 for( b
= 0; b
< RowSize
; b
++)
400 fArray
[b
] = implGetDefaultValue(a
, b
);
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
417 double doDeterminant() const
419 ImplHomMatrixTemplate
aWork(*this);
420 sal_uInt16 nIndex
[RowSize
];
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
);
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
));
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
));
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
);
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].
489 for(sal_uInt16
a(0); a
< RowSize
; ++a
)
491 for(sal_uInt16
b(0); b
< RowSize
; ++b
)
495 for(sal_uInt16
c(0); c
< RowSize
; ++c
)
496 fValue
+= aCopy
.get(c
, b
) * rMat
.get(a
, c
);
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
))
528 } // namespace internal
529 } // namespace basegfx
531 #endif // INCLUDED_BASEGFX_SOURCE_INC_HOMMATRIXTEMPLATE_HXX
533 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */