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 _HOMMATRIX_TEMPLATE_HXX
21 #define _HOMMATRIX_TEMPLATE_HXX
23 #include <sal/types.h>
24 #include <basegfx/numeric/ftools.hxx>
33 inline double implGetDefaultValue(sal_uInt16 nRow
, sal_uInt16 nColumn
)
40 template < unsigned int _RowSize
> class ImplMatLine
42 enum { RowSize
= _RowSize
};
44 double mfValue
[RowSize
];
51 explicit ImplMatLine(sal_uInt16 nRow
, ImplMatLine
< RowSize
>* pToBeCopied
= 0L)
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 < unsigned int _RowSize
> class ImplHomMatrixTemplate
79 enum { RowSize
= _RowSize
};
81 ImplMatLine
< RowSize
> maLine
[RowSize
- 1];
82 ImplMatLine
< RowSize
>* mpLine
;
86 bool isLastLineDefault() const
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
))
102 // reset last line, it equals default
103 delete ((ImplHomMatrixTemplate
< RowSize
>*)this)->mpLine
;
104 ((ImplHomMatrixTemplate
< RowSize
>*)this)->mpLine
= 0L;
109 ImplHomMatrixTemplate()
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
)
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()
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
);
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
);
169 mpLine
->set(nColumn
, rValue
);
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
);
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
))
208 // Left-upper decompositon
209 bool ludcmp(sal_uInt16 nIndex
[], sal_Int16
& nParity
)
211 double fBig
, fSum
, fDum
;
212 double fStorage
[RowSize
];
215 // #i30874# Initialize nAMax (compiler warns)
216 sal_uInt16 nAMax
= 0;
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
++)
226 for(b
= 0; b
< RowSize
; b
++)
228 double fTemp(fabs(get(a
, b
)));
230 if(::basegfx::fTools::more(fTemp
, fBig
))
236 if(::basegfx::fTools::equalZero(fBig
))
241 fStorage
[a
] = 1.0 / fBig
;
245 for(b
= 0; b
< RowSize
; b
++)
247 for(a
= 0; a
< b
; a
++)
251 for(c
= 0; c
< a
; c
++)
253 fSum
-= get(a
, c
) * get(c
, b
);
261 for(a
= b
; a
< RowSize
; a
++)
265 for(c
= 0; c
< b
; c
++)
267 fSum
-= get(a
, c
) * get(c
, b
);
271 fDum
= fStorage
[a
] * fabs(fSum
);
273 if(::basegfx::fTools::moreOrEqual(fDum
, fBig
))
282 for(c
= 0; c
< RowSize
; c
++)
284 fDum
= get(nAMax
, c
);
285 set(nAMax
, c
, get(b
, c
));
290 fStorage
[nAMax
] = fStorage
[b
];
295 // here the failure of precision occurs
296 const double fValBB(fabs(get(b
, b
)));
298 if(::basegfx::fTools::equalZero(fValBB
))
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
);
317 void lubksb(const sal_uInt16 nIndex
[], double fRow
[]) const
320 sal_Int16 a
, a2
= -1;
323 for(a
= 0; a
< RowSize
; a
++)
331 for(b
= a2
; b
< a
; b
++)
333 fSum
-= get(a
, b
) * fRow
[b
];
336 else if(!::basegfx::fTools::equalZero(fSum
))
344 for(a
= (RowSize
- 1); a
>= 0; 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
))
385 bool isInvertible() const
387 ImplHomMatrixTemplate
aWork(*this);
388 sal_uInt16 nIndex
[RowSize
];
391 return aWork
.ludcmp(nIndex
, nParity
);
394 bool isNormalized() const
399 const double fHomValue(get((RowSize
- 1), (RowSize
- 1)));
401 if(::basegfx::fTools::equalZero(fHomValue
))
406 const double fOne(1.0);
408 if(::basegfx::fTools::equal(fOne
, fHomValue
))
416 void doInvert(const ImplHomMatrixTemplate
& rWork
, const sal_uInt16 nIndex
[])
418 double fArray
[RowSize
];
420 for(sal_uInt16
a(0); a
< RowSize
; a
++)
424 for( b
= 0; b
< RowSize
; b
++)
426 fArray
[b
] = implGetDefaultValue(a
, b
);
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
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
462 double doDeterminant() const
464 ImplHomMatrixTemplate
aWork(*this);
465 sal_uInt16 nIndex
[RowSize
];
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
);
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
++)
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
));
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
));
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
));
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
);
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].
563 for(sal_uInt16
a(0); a
< RowSize
; ++a
)
565 for(sal_uInt16
b(0); b
< RowSize
; ++b
)
569 for(sal_uInt16
c(0); c
< RowSize
; ++c
)
570 fValue
+= aCopy
.get(c
, b
) * rMat
.get(a
, c
);
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
))
602 } // namespace internal
603 } // namespace basegfx
605 #endif /* _HOMMATRIX_TEMPLATE_HXX */
607 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */