1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 #ifndef _HOMMATRIX_TEMPLATE_HXX
29 #define _HOMMATRIX_TEMPLATE_HXX
31 #include <sal/types.h>
32 #include <basegfx/numeric/ftools.hxx>
41 inline double implGetDefaultValue(sal_uInt16 nRow
, sal_uInt16 nColumn
)
48 template < unsigned int _RowSize
> class ImplMatLine
50 enum { RowSize
= _RowSize
};
52 double mfValue
[RowSize
];
59 ImplMatLine(sal_uInt16 nRow
, ImplMatLine
< RowSize
>* pToBeCopied
= 0L)
63 memcpy(&mfValue
, pToBeCopied
, sizeof(double) * RowSize
);
67 for(sal_uInt16
a(0); a
< RowSize
; a
++)
69 mfValue
[a
] = implGetDefaultValue(nRow
, a
);
74 double get(sal_uInt16 nColumn
) const
76 return mfValue
[nColumn
];
79 void set(sal_uInt16 nColumn
, const double& rValue
)
81 mfValue
[nColumn
] = rValue
;
85 template < unsigned int _RowSize
> class ImplHomMatrixTemplate
87 enum { RowSize
= _RowSize
};
89 ImplMatLine
< RowSize
> maLine
[RowSize
- 1];
90 ImplMatLine
< RowSize
>* mpLine
;
94 bool isLastLineDefault() const
99 for(sal_uInt16
a(0); a
< RowSize
; a
++)
101 const double fDefault(implGetDefaultValue((RowSize
- 1), a
));
102 const double fLineValue(mpLine
->get(a
));
104 if(!::basegfx::fTools::equal(fDefault
, fLineValue
))
110 // reset last line, it equals default
111 delete ((ImplHomMatrixTemplate
< RowSize
>*)this)->mpLine
;
112 ((ImplHomMatrixTemplate
< RowSize
>*)this)->mpLine
= 0L;
117 ImplHomMatrixTemplate()
120 // complete initialization with identity matrix, all lines
121 // were initialized with a trailing 1 followed by 0's.
122 for(sal_uInt16
a(0); a
< RowSize
-1; a
++)
124 for(sal_uInt16
b(0); b
< RowSize
; b
++)
125 maLine
[a
].set(b
, implGetDefaultValue(a
, b
) );
129 ImplHomMatrixTemplate(const ImplHomMatrixTemplate
& rToBeCopied
)
132 // complete initialization using copy
133 for(sal_uInt16
a(0); a
< (RowSize
- 1); a
++)
135 memcpy(&maLine
[a
], &rToBeCopied
.maLine
[a
], sizeof(ImplMatLine
< RowSize
>));
138 if(rToBeCopied
.mpLine
)
140 mpLine
= new ImplMatLine
< RowSize
>((RowSize
- 1), rToBeCopied
.mpLine
);
144 ~ImplHomMatrixTemplate()
152 sal_uInt16
getEdgeLength() const { return RowSize
; }
154 double get(sal_uInt16 nRow
, sal_uInt16 nColumn
) const
156 if(nRow
< (RowSize
- 1))
158 return maLine
[nRow
].get(nColumn
);
163 return mpLine
->get(nColumn
);
166 return implGetDefaultValue((RowSize
- 1), nColumn
);
169 void set(sal_uInt16 nRow
, sal_uInt16 nColumn
, const double& rValue
)
171 if(nRow
< (RowSize
- 1))
173 maLine
[nRow
].set(nColumn
, rValue
);
177 mpLine
->set(nColumn
, rValue
);
181 const double fDefault(implGetDefaultValue((RowSize
- 1), nColumn
));
183 if(!::basegfx::fTools::equal(fDefault
, rValue
))
185 mpLine
= new ImplMatLine
< RowSize
>((RowSize
- 1), 0L);
186 mpLine
->set(nColumn
, rValue
);
195 bool bNecessary(false);
197 for(sal_uInt16
a(0);!bNecessary
&& a
< RowSize
; a
++)
199 const double fDefault(implGetDefaultValue((RowSize
- 1), a
));
200 const double fLineValue(mpLine
->get(a
));
202 if(!::basegfx::fTools::equal(fDefault
, fLineValue
))
216 // Left-upper decompositon
217 bool ludcmp(sal_uInt16 nIndex
[], sal_Int16
& nParity
)
219 double fBig
, fSum
, fDum
;
220 double fStorage
[RowSize
];
223 // #i30874# Initialize nAMax (compiler warns)
224 sal_uInt16 nAMax
= 0;
228 // Calc the max of each line. If a line is empty,
229 // stop immediately since matrix is not invertible then.
230 for(a
= 0; a
< RowSize
; a
++)
234 for(b
= 0; b
< RowSize
; b
++)
236 double fTemp(fabs(get(a
, b
)));
238 if(::basegfx::fTools::more(fTemp
, fBig
))
244 if(::basegfx::fTools::equalZero(fBig
))
249 fStorage
[a
] = 1.0 / fBig
;
253 for(b
= 0; b
< RowSize
; b
++)
255 for(a
= 0; a
< b
; a
++)
259 for(c
= 0; c
< a
; c
++)
261 fSum
-= get(a
, c
) * get(c
, b
);
269 for(a
= b
; a
< RowSize
; a
++)
273 for(c
= 0; c
< b
; c
++)
275 fSum
-= get(a
, c
) * get(c
, b
);
279 fDum
= fStorage
[a
] * fabs(fSum
);
281 if(::basegfx::fTools::moreOrEqual(fDum
, fBig
))
290 for(c
= 0; c
< RowSize
; c
++)
292 fDum
= get(nAMax
, c
);
293 set(nAMax
, c
, get(b
, c
));
298 fStorage
[nAMax
] = fStorage
[b
];
303 // here the failure of precision occurs
304 const double fValBB(fabs(get(b
, b
)));
306 if(::basegfx::fTools::equalZero(fValBB
))
311 if(b
!= (RowSize
- 1))
313 fDum
= 1.0 / get(b
, b
);
315 for(a
= b
+ 1; a
< RowSize
; a
++)
317 set(a
, b
, get(a
, b
) * fDum
);
325 void lubksb(const sal_uInt16 nIndex
[], double fRow
[]) const
328 sal_Int16 a
, a2
= -1;
331 for(a
= 0; a
< RowSize
; a
++)
339 for(b
= a2
; b
< a
; b
++)
341 fSum
-= get(a
, b
) * fRow
[b
];
344 else if(!::basegfx::fTools::equalZero(fSum
))
352 for(a
= (RowSize
- 1); a
>= 0; a
--)
356 for(b
= a
+ 1; b
< RowSize
; b
++)
358 fSum
-= get(a
, b
) * fRow
[b
];
361 const double fValueAA(get(a
, a
));
363 if(!::basegfx::fTools::equalZero(fValueAA
))
365 fRow
[a
] = fSum
/ get(a
, a
);
370 bool isIdentity() const
372 // last line needs no testing if not existing
373 const sal_uInt16
nMaxLine(
374 sal::static_int_cast
<sal_uInt16
>(mpLine
? RowSize
: (RowSize
- 1)) );
376 for(sal_uInt16
a(0); a
< nMaxLine
; a
++)
378 for(sal_uInt16
b(0); b
< RowSize
; b
++)
380 const double fDefault(implGetDefaultValue(a
, b
));
381 const double fValueAB(get(a
, b
));
383 if(!::basegfx::fTools::equal(fDefault
, fValueAB
))
393 bool isInvertible() const
395 ImplHomMatrixTemplate
aWork(*this);
396 sal_uInt16 nIndex
[RowSize
];
399 return aWork
.ludcmp(nIndex
, nParity
);
402 bool isNormalized() const
407 const double fHomValue(get((RowSize
- 1), (RowSize
- 1)));
409 if(::basegfx::fTools::equalZero(fHomValue
))
414 const double fOne(1.0);
416 if(::basegfx::fTools::equal(fOne
, fHomValue
))
424 void doInvert(const ImplHomMatrixTemplate
& rWork
, const sal_uInt16 nIndex
[])
426 double fArray
[RowSize
];
428 for(sal_uInt16
a(0); a
< RowSize
; a
++)
432 for( b
= 0; b
< RowSize
; b
++)
434 fArray
[b
] = implGetDefaultValue(a
, b
);
438 rWork
.lubksb(nIndex
, fArray
);
440 // copy line transposed to this matrix
441 for( b
= 0; b
< RowSize
; b
++)
443 set(b
, a
, fArray
[b
]);
447 // evtl. get rid of last matrix line
455 const double fHomValue(get((RowSize
- 1), (RowSize
- 1)));
457 for(sal_uInt16
a(0); a
< RowSize
; a
++)
459 for(sal_uInt16
b(0); b
< RowSize
; b
++)
461 set(a
, b
, get(a
, b
) / fHomValue
);
465 // evtl. get rid of last matrix line
470 double doDeterminant() const
472 ImplHomMatrixTemplate
aWork(*this);
473 sal_uInt16 nIndex
[RowSize
];
477 if(aWork
.ludcmp(nIndex
, nParity
))
479 fRetval
= (double)nParity
;
481 // last line needs no multiply if not existing; default value would be 1.
482 const sal_uInt16
nMaxLine(
483 sal::static_int_cast
<sal_uInt16
>(aWork
.mpLine
? RowSize
: (RowSize
- 1)) );
485 for(sal_uInt16
a(0); a
< nMaxLine
; a
++)
487 fRetval
*= aWork
.get(a
, a
);
494 double doTrace() const
496 double fTrace
= (mpLine
) ? 0.0 : 1.0;
497 const sal_uInt16
nMaxLine(
498 sal::static_int_cast
<sal_uInt16
>(mpLine
? RowSize
: (RowSize
- 1)) );
500 for(sal_uInt16
a(0); a
< nMaxLine
; a
++)
510 for(sal_uInt16
a(0); a
< (RowSize
- 1); a
++)
512 for(sal_uInt16
b(a
+ 1); b
< RowSize
; b
++)
514 const double fTemp(get(a
, b
));
515 set(a
, b
, get(b
, a
));
523 void doAddMatrix(const ImplHomMatrixTemplate
& rMat
)
525 for(sal_uInt16
a(0); a
< RowSize
; a
++)
527 for(sal_uInt16
b(0); b
< RowSize
; b
++)
529 set(a
, b
, get(a
, b
) + rMat
.get(a
, b
));
536 void doSubMatrix(const ImplHomMatrixTemplate
& rMat
)
538 for(sal_uInt16
a(0); a
< RowSize
; a
++)
540 for(sal_uInt16
b(0); b
< RowSize
; b
++)
542 set(a
, b
, get(a
, b
) - rMat
.get(a
, b
));
549 void doMulMatrix(const double& rfValue
)
551 for(sal_uInt16
a(0); a
< RowSize
; a
++)
553 for(sal_uInt16
b(0); b
< RowSize
; b
++)
555 set(a
, b
, get(a
, b
) * rfValue
);
562 void doMulMatrix(const ImplHomMatrixTemplate
& rMat
)
564 // create a copy as source for the original values
565 const ImplHomMatrixTemplate
aCopy(*this);
567 // TODO: maybe optimize cases where last line is [0 0 1].
571 for(sal_uInt16
a(0); a
< RowSize
; ++a
)
573 for(sal_uInt16
b(0); b
< RowSize
; ++b
)
577 for(sal_uInt16
c(0); c
< RowSize
; ++c
)
578 fValue
+= aCopy
.get(c
, b
) * rMat
.get(a
, c
);
587 bool isEqual(const ImplHomMatrixTemplate
& rMat
) const
589 const sal_uInt16
nMaxLine(
590 sal::static_int_cast
<sal_uInt16
>((mpLine
|| rMat
.mpLine
) ? RowSize
: (RowSize
- 1)) );
592 for(sal_uInt16
a(0); a
< nMaxLine
; a
++)
594 for(sal_uInt16
b(0); b
< RowSize
; b
++)
596 const double fValueA(get(a
, b
));
597 const double fValueB(rMat
.get(a
, b
));
599 if(!::basegfx::fTools::equal(fValueA
, fValueB
))
610 } // namespace internal
611 } // namespace basegfx
613 #endif /* _HOMMATRIX_TEMPLATE_HXX */