1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: hommatrixtemplate.hxx,v $
10 * $Revision: 1.18.12.2 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #ifndef _HOMMATRIX_TEMPLATE_HXX
32 #define _HOMMATRIX_TEMPLATE_HXX
34 #include <sal/types.h>
35 #include <basegfx/numeric/ftools.hxx>
44 inline double implGetDefaultValue(sal_uInt16 nRow
, sal_uInt16 nColumn
)
51 template < unsigned int _RowSize
> class ImplMatLine
53 enum { RowSize
= _RowSize
};
55 double mfValue
[RowSize
];
62 ImplMatLine(sal_uInt16 nRow
, ImplMatLine
< RowSize
>* pToBeCopied
= 0L)
66 memcpy(&mfValue
, pToBeCopied
, sizeof(double) * RowSize
);
70 for(sal_uInt16
a(0); a
< RowSize
; a
++)
72 mfValue
[a
] = implGetDefaultValue(nRow
, a
);
77 double get(sal_uInt16 nColumn
) const
79 return mfValue
[nColumn
];
82 void set(sal_uInt16 nColumn
, const double& rValue
)
84 mfValue
[nColumn
] = rValue
;
88 template < unsigned int _RowSize
> class ImplHomMatrixTemplate
90 enum { RowSize
= _RowSize
};
92 ImplMatLine
< RowSize
> maLine
[RowSize
- 1];
93 ImplMatLine
< RowSize
>* mpLine
;
97 bool isLastLineDefault() const
102 for(sal_uInt16
a(0); a
< RowSize
; a
++)
104 const double fDefault(implGetDefaultValue((RowSize
- 1), a
));
105 const double fLineValue(mpLine
->get(a
));
107 if(!::basegfx::fTools::equal(fDefault
, fLineValue
))
113 // reset last line, it equals default
114 delete ((ImplHomMatrixTemplate
< RowSize
>*)this)->mpLine
;
115 ((ImplHomMatrixTemplate
< RowSize
>*)this)->mpLine
= 0L;
120 ImplHomMatrixTemplate()
123 // complete initialization with identity matrix, all lines
124 // were initialized with a trailing 1 followed by 0's.
125 for(sal_uInt16
a(0); a
< RowSize
-1; a
++)
127 for(sal_uInt16
b(0); b
< RowSize
; b
++)
128 maLine
[a
].set(b
, implGetDefaultValue(a
, b
) );
132 ImplHomMatrixTemplate(const ImplHomMatrixTemplate
& rToBeCopied
)
135 // complete initialization using copy
136 for(sal_uInt16
a(0); a
< (RowSize
- 1); a
++)
138 memcpy(&maLine
[a
], &rToBeCopied
.maLine
[a
], sizeof(ImplMatLine
< RowSize
>));
141 if(rToBeCopied
.mpLine
)
143 mpLine
= new ImplMatLine
< RowSize
>((RowSize
- 1), rToBeCopied
.mpLine
);
147 ~ImplHomMatrixTemplate()
155 sal_uInt16
getEdgeLength() const { return RowSize
; }
157 double get(sal_uInt16 nRow
, sal_uInt16 nColumn
) const
159 if(nRow
< (RowSize
- 1))
161 return maLine
[nRow
].get(nColumn
);
166 return mpLine
->get(nColumn
);
169 return implGetDefaultValue((RowSize
- 1), nColumn
);
172 void set(sal_uInt16 nRow
, sal_uInt16 nColumn
, const double& rValue
)
174 if(nRow
< (RowSize
- 1))
176 maLine
[nRow
].set(nColumn
, rValue
);
180 mpLine
->set(nColumn
, rValue
);
184 const double fDefault(implGetDefaultValue((RowSize
- 1), nColumn
));
186 if(!::basegfx::fTools::equal(fDefault
, rValue
))
188 mpLine
= new ImplMatLine
< RowSize
>((RowSize
- 1), 0L);
189 mpLine
->set(nColumn
, rValue
);
198 bool bNecessary(false);
200 for(sal_uInt16
a(0);!bNecessary
&& a
< RowSize
; a
++)
202 const double fDefault(implGetDefaultValue((RowSize
- 1), a
));
203 const double fLineValue(mpLine
->get(a
));
205 if(!::basegfx::fTools::equal(fDefault
, fLineValue
))
219 // Left-upper decompositon
220 bool ludcmp(sal_uInt16 nIndex
[], sal_Int16
& nParity
)
222 double fBig
, fSum
, fDum
;
223 double fStorage
[RowSize
];
226 // #i30874# Initialize nAMax (compiler warns)
227 sal_uInt16 nAMax
= 0;
231 // Calc the max of each line. If a line is empty,
232 // stop immediately since matrix is not invertible then.
233 for(a
= 0; a
< RowSize
; a
++)
237 for(b
= 0; b
< RowSize
; b
++)
239 double fTemp(fabs(get(a
, b
)));
241 if(::basegfx::fTools::more(fTemp
, fBig
))
247 if(::basegfx::fTools::equalZero(fBig
))
252 fStorage
[a
] = 1.0 / fBig
;
256 for(b
= 0; b
< RowSize
; b
++)
258 for(a
= 0; a
< b
; a
++)
262 for(c
= 0; c
< a
; c
++)
264 fSum
-= get(a
, c
) * get(c
, b
);
272 for(a
= b
; a
< RowSize
; a
++)
276 for(c
= 0; c
< b
; c
++)
278 fSum
-= get(a
, c
) * get(c
, b
);
282 fDum
= fStorage
[a
] * fabs(fSum
);
284 if(::basegfx::fTools::moreOrEqual(fDum
, fBig
))
293 for(c
= 0; c
< RowSize
; c
++)
295 fDum
= get(nAMax
, c
);
296 set(nAMax
, c
, get(b
, c
));
301 fStorage
[nAMax
] = fStorage
[b
];
306 // here the failure of precision occurs
307 const double fValBB(fabs(get(b
, b
)));
309 if(::basegfx::fTools::equalZero(fValBB
))
314 if(b
!= (RowSize
- 1))
316 fDum
= 1.0 / get(b
, b
);
318 for(a
= b
+ 1; a
< RowSize
; a
++)
320 set(a
, b
, get(a
, b
) * fDum
);
328 void lubksb(const sal_uInt16 nIndex
[], double fRow
[]) const
331 sal_Int16 a
, a2
= -1;
334 for(a
= 0; a
< RowSize
; a
++)
342 for(b
= a2
; b
< a
; b
++)
344 fSum
-= get(a
, b
) * fRow
[b
];
347 else if(!::basegfx::fTools::equalZero(fSum
))
355 for(a
= (RowSize
- 1); a
>= 0; a
--)
359 for(b
= a
+ 1; b
< RowSize
; b
++)
361 fSum
-= get(a
, b
) * fRow
[b
];
364 const double fValueAA(get(a
, a
));
366 if(!::basegfx::fTools::equalZero(fValueAA
))
368 fRow
[a
] = fSum
/ get(a
, a
);
373 bool isIdentity() const
375 // last line needs no testing if not existing
376 const sal_uInt16
nMaxLine(
377 sal::static_int_cast
<sal_uInt16
>(mpLine
? RowSize
: (RowSize
- 1)) );
379 for(sal_uInt16
a(0); a
< nMaxLine
; a
++)
381 for(sal_uInt16
b(0); b
< RowSize
; b
++)
383 const double fDefault(implGetDefaultValue(a
, b
));
384 const double fValueAB(get(a
, b
));
386 if(!::basegfx::fTools::equal(fDefault
, fValueAB
))
396 bool isInvertible() const
398 ImplHomMatrixTemplate
aWork(*this);
399 sal_uInt16 nIndex
[RowSize
];
402 return aWork
.ludcmp(nIndex
, nParity
);
405 bool isNormalized() const
410 const double fHomValue(get((RowSize
- 1), (RowSize
- 1)));
412 if(::basegfx::fTools::equalZero(fHomValue
))
417 const double fOne(1.0);
419 if(::basegfx::fTools::equal(fOne
, fHomValue
))
427 void doInvert(const ImplHomMatrixTemplate
& rWork
, const sal_uInt16 nIndex
[])
429 double fArray
[RowSize
];
431 for(sal_uInt16
a(0); a
< RowSize
; a
++)
435 for( b
= 0; b
< RowSize
; b
++)
437 fArray
[b
] = implGetDefaultValue(a
, b
);
441 rWork
.lubksb(nIndex
, fArray
);
443 // copy line transposed to this matrix
444 for( b
= 0; b
< RowSize
; b
++)
446 set(b
, a
, fArray
[b
]);
450 // evtl. get rid of last matrix line
458 const double fHomValue(get((RowSize
- 1), (RowSize
- 1)));
460 for(sal_uInt16
a(0); a
< RowSize
; a
++)
462 for(sal_uInt16
b(0); b
< RowSize
; b
++)
464 set(a
, b
, get(a
, b
) / fHomValue
);
468 // evtl. get rid of last matrix line
473 double doDeterminant() const
475 ImplHomMatrixTemplate
aWork(*this);
476 sal_uInt16 nIndex
[RowSize
];
480 if(aWork
.ludcmp(nIndex
, nParity
))
482 fRetval
= (double)nParity
;
484 // last line needs no multiply if not existing; default value would be 1.
485 const sal_uInt16
nMaxLine(
486 sal::static_int_cast
<sal_uInt16
>(aWork
.mpLine
? RowSize
: (RowSize
- 1)) );
488 for(sal_uInt16
a(0); a
< nMaxLine
; a
++)
490 fRetval
*= aWork
.get(a
, a
);
497 double doTrace() const
499 double fTrace
= (mpLine
) ? 0.0 : 1.0;
500 const sal_uInt16
nMaxLine(
501 sal::static_int_cast
<sal_uInt16
>(mpLine
? RowSize
: (RowSize
- 1)) );
503 for(sal_uInt16
a(0); a
< nMaxLine
; a
++)
513 for(sal_uInt16
a(0); a
< (RowSize
- 1); a
++)
515 for(sal_uInt16
b(a
+ 1); b
< RowSize
; b
++)
517 const double fTemp(get(a
, b
));
518 set(a
, b
, get(b
, a
));
526 void doAddMatrix(const ImplHomMatrixTemplate
& rMat
)
528 for(sal_uInt16
a(0); a
< RowSize
; a
++)
530 for(sal_uInt16
b(0); b
< RowSize
; b
++)
532 set(a
, b
, get(a
, b
) + rMat
.get(a
, b
));
539 void doSubMatrix(const ImplHomMatrixTemplate
& rMat
)
541 for(sal_uInt16
a(0); a
< RowSize
; a
++)
543 for(sal_uInt16
b(0); b
< RowSize
; b
++)
545 set(a
, b
, get(a
, b
) - rMat
.get(a
, b
));
552 void doMulMatrix(const double& rfValue
)
554 for(sal_uInt16
a(0); a
< RowSize
; a
++)
556 for(sal_uInt16
b(0); b
< RowSize
; b
++)
558 set(a
, b
, get(a
, b
) * rfValue
);
565 void doMulMatrix(const ImplHomMatrixTemplate
& rMat
)
567 // create a copy as source for the original values
568 const ImplHomMatrixTemplate
aCopy(*this);
570 // TODO: maybe optimize cases where last line is [0 0 1].
574 for(sal_uInt16
a(0); a
< RowSize
; ++a
)
576 for(sal_uInt16
b(0); b
< RowSize
; ++b
)
580 for(sal_uInt16
c(0); c
< RowSize
; ++c
)
581 fValue
+= aCopy
.get(c
, b
) * rMat
.get(a
, c
);
590 bool isEqual(const ImplHomMatrixTemplate
& rMat
) const
592 const sal_uInt16
nMaxLine(
593 sal::static_int_cast
<sal_uInt16
>((mpLine
|| rMat
.mpLine
) ? RowSize
: (RowSize
- 1)) );
595 for(sal_uInt16
a(0); a
< nMaxLine
; a
++)
597 for(sal_uInt16
b(0); b
< RowSize
; b
++)
599 const double fValueA(get(a
, b
));
600 const double fValueB(rMat
.get(a
, b
));
602 if(!::basegfx::fTools::equal(fValueA
, fValueB
))
613 } // namespace internal
614 } // namespace basegfx
616 #endif /* _HOMMATRIX_TEMPLATE_HXX */