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 .
22 #include <sal/types.h>
23 #include <basegfx/numeric/ftools.hxx>
26 namespace basegfx::internal
29 inline constexpr double implGetDefaultValue(sal_uInt16 nRow
, sal_uInt16 nColumn
)
36 template < sal_uInt16 RowSize
> class ImplMatLine
38 double mfValue
[RowSize
];
41 ImplMatLine() = default;
43 explicit ImplMatLine(sal_uInt16 nRow
)
45 for(sal_uInt16
a(0); a
< RowSize
; a
++)
47 mfValue
[a
] = implGetDefaultValue(nRow
, a
);
51 double get(sal_uInt16 nColumn
) const
53 return mfValue
[nColumn
];
56 void set(sal_uInt16 nColumn
, const double& rValue
)
58 mfValue
[nColumn
] = rValue
;
62 template < sal_uInt16 RowSize
> class ImplHomMatrixTemplate
64 ImplMatLine
< RowSize
> maLine
[RowSize
];
68 bool isLastLineDefault() const
70 for(sal_uInt16
a(0); a
< RowSize
; a
++)
72 const double fDefault(implGetDefaultValue((RowSize
- 1), a
));
73 const double fLineValue(maLine
[RowSize
-1].get(a
));
75 if(fDefault
!= fLineValue
)
83 ImplHomMatrixTemplate()
85 // complete initialization with identity matrix, all lines
86 // were initialized with a trailing 1 followed by 0's.
87 for(sal_uInt16
a(0); a
< RowSize
; a
++)
89 for(sal_uInt16
b(0); b
< RowSize
; b
++)
90 maLine
[a
].set(b
, implGetDefaultValue(a
, b
) );
94 ImplHomMatrixTemplate(const ImplHomMatrixTemplate
& rToBeCopied
)
96 operator=(rToBeCopied
);
99 ImplHomMatrixTemplate
& operator=(const ImplHomMatrixTemplate
& rToBeCopied
)
101 if (this != &rToBeCopied
)
103 // complete initialization using copy
104 for(sal_uInt16
a(0); a
< RowSize
; a
++)
106 maLine
[a
] = rToBeCopied
.maLine
[a
];
112 static sal_uInt16
getEdgeLength() { return RowSize
; }
114 double get(sal_uInt16 nRow
, sal_uInt16 nColumn
) const
116 return maLine
[nRow
].get(nColumn
);
119 void set(sal_uInt16 nRow
, sal_uInt16 nColumn
, const double& rValue
)
121 maLine
[nRow
].set(nColumn
, rValue
);
124 // Left-upper decomposition
125 bool ludcmp(sal_uInt16 nIndex
[], sal_Int16
& nParity
)
127 double fBig
, fSum
, fDum
;
128 double fStorage
[RowSize
];
131 // #i30874# Initialize nAMax (compiler warns)
132 sal_uInt16 nAMax
= 0;
136 // Calc the max of each line. If a line is empty,
137 // stop immediately since matrix is not invertible then.
138 for(a
= 0; a
< RowSize
; a
++)
142 for(b
= 0; b
< RowSize
; b
++)
144 double fTemp(fabs(get(a
, b
)));
146 if(::basegfx::fTools::more(fTemp
, fBig
))
152 if(::basegfx::fTools::equalZero(fBig
))
157 fStorage
[a
] = 1.0 / fBig
;
161 for(b
= 0; b
< RowSize
; b
++)
163 for(a
= 0; a
< b
; a
++)
167 for(c
= 0; c
< a
; c
++)
169 fSum
-= get(a
, c
) * get(c
, b
);
177 for(a
= b
; a
< RowSize
; a
++)
181 for(c
= 0; c
< b
; c
++)
183 fSum
-= get(a
, c
) * get(c
, b
);
187 fDum
= fStorage
[a
] * fabs(fSum
);
189 if(::basegfx::fTools::moreOrEqual(fDum
, fBig
))
198 for(c
= 0; c
< RowSize
; c
++)
200 fDum
= get(nAMax
, c
);
201 set(nAMax
, c
, get(b
, c
));
206 fStorage
[nAMax
] = fStorage
[b
];
211 // here the failure of precision occurs
212 const double fValBB(fabs(get(b
, b
)));
214 if(::basegfx::fTools::equalZero(fValBB
))
219 if(b
!= (RowSize
- 1))
221 fDum
= 1.0 / get(b
, b
);
223 for(a
= b
+ 1; a
< RowSize
; a
++)
225 set(a
, b
, get(a
, b
) * fDum
);
233 void lubksb(const sal_uInt16 nIndex
[], double fRow
[]) const
236 sal_Int16 a
, a2
= -1;
239 for(a
= 0; a
< RowSize
; a
++)
247 for(b
= a2
; b
< a
; b
++)
249 fSum
-= get(a
, b
) * fRow
[b
];
252 else if(!::basegfx::fTools::equalZero(fSum
))
260 for(a
= (RowSize
- 1); a
>= 0; a
--)
264 for(b
= a
+ 1; b
< RowSize
; b
++)
266 fSum
-= get(a
, b
) * fRow
[b
];
269 const double fValueAA(get(a
, a
));
271 if(!::basegfx::fTools::equalZero(fValueAA
))
273 fRow
[a
] = fSum
/ get(a
, a
);
278 bool isIdentity() const
280 for(sal_uInt16
a(0); a
< RowSize
; a
++)
282 for(sal_uInt16
b(0); b
< RowSize
; b
++)
284 const double fDefault(implGetDefaultValue(a
, b
));
285 const double fValueAB(get(a
, b
));
287 if(!::basegfx::fTools::equal(fDefault
, fValueAB
))
297 bool isInvertible() const
299 ImplHomMatrixTemplate
aWork(*this);
300 sal_uInt16 nIndex
[RowSize
];
303 return aWork
.ludcmp(nIndex
, nParity
);
306 void doInvert(const ImplHomMatrixTemplate
& rWork
, const sal_uInt16 nIndex
[])
308 double fArray
[RowSize
];
310 for(sal_uInt16
a(0); a
< RowSize
; a
++)
314 for( b
= 0; b
< RowSize
; b
++)
316 fArray
[b
] = implGetDefaultValue(a
, b
);
320 rWork
.lubksb(nIndex
, fArray
);
322 // copy line transposed to this matrix
323 for( b
= 0; b
< RowSize
; b
++)
325 set(b
, a
, fArray
[b
]);
330 double doDeterminant() const
332 ImplHomMatrixTemplate
aWork(*this);
333 sal_uInt16 nIndex
[RowSize
];
337 if(aWork
.ludcmp(nIndex
, nParity
))
339 fRetval
= static_cast<double>(nParity
);
340 for(sal_uInt16
a(0); a
< RowSize
; a
++)
342 fRetval
*= aWork
.get(a
, a
);
349 void doAddMatrix(const ImplHomMatrixTemplate
& rMat
)
351 for(sal_uInt16
a(0); a
< RowSize
; a
++)
353 for(sal_uInt16
b(0); b
< RowSize
; b
++)
355 set(a
, b
, get(a
, b
) + rMat
.get(a
, b
));
360 void doSubMatrix(const ImplHomMatrixTemplate
& rMat
)
362 for(sal_uInt16
a(0); a
< RowSize
; a
++)
364 for(sal_uInt16
b(0); b
< RowSize
; b
++)
366 set(a
, b
, get(a
, b
) - rMat
.get(a
, b
));
371 void doMulMatrix(const double& rfValue
)
373 for(sal_uInt16
a(0); a
< RowSize
; a
++)
375 for(sal_uInt16
b(0); b
< RowSize
; b
++)
377 set(a
, b
, get(a
, b
) * rfValue
);
382 void doMulMatrix(const ImplHomMatrixTemplate
& rMat
)
384 // create a copy as source for the original values
385 const ImplHomMatrixTemplate
aCopy(*this);
387 // TODO: maybe optimize cases where last line is [0 0 1].
391 for(sal_uInt16
a(0); a
< RowSize
; ++a
)
393 for(sal_uInt16
b(0); b
< RowSize
; ++b
)
397 for(sal_uInt16
c(0); c
< RowSize
; ++c
)
398 fValue
+= aCopy
.get(c
, b
) * rMat
.get(a
, c
);
405 bool isEqual(const ImplHomMatrixTemplate
& rMat
) const
407 for(sal_uInt16
a(0); a
< RowSize
; a
++)
409 for(sal_uInt16
b(0); b
< RowSize
; b
++)
411 const double fValueA(get(a
, b
));
412 const double fValueB(rMat
.get(a
, b
));
414 if(!::basegfx::fTools::equal(fValueA
, fValueB
))
425 } // namespace basegfx::internal
427 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */