LibreOffice Module basegfx (master) 1
hommatrixtemplate.hxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#pragma once
21
22#include <sal/types.h>
24#include <cmath>
25#include <string.h>
26
27#include <memory>
28
29namespace basegfx::internal
30 {
31
32 inline constexpr double implGetDefaultValue(sal_uInt16 nRow, sal_uInt16 nColumn)
33 {
34 if(nRow == nColumn)
35 return 1.0;
36 return 0.0;
37 }
38
39 template < sal_uInt16 RowSize > class ImplMatLine
40 {
42
43 public:
44 ImplMatLine() = default;
45
46 explicit ImplMatLine(sal_uInt16 nRow)
47 {
48 for(sal_uInt16 a(0); a < RowSize; a++)
49 {
51 }
52 }
53
54 double get(sal_uInt16 nColumn) const
55 {
56 return mfValue[nColumn];
57 }
58
59 void set(sal_uInt16 nColumn, const double& rValue)
60 {
61 mfValue[nColumn] = rValue;
62 }
63 };
64
65 template < sal_uInt16 RowSize > class ImplHomMatrixTemplate
66 {
68
69 public:
70 // Is last line used?
71 bool isLastLineDefault() const
72 {
73 for(sal_uInt16 a(0); a < RowSize; a++)
74 {
75 const double fDefault(implGetDefaultValue((RowSize - 1), a));
76 const double fLineValue(maLine[RowSize-1].get(a));
77
78 if(fDefault != fLineValue)
79 {
80 return false;
81 }
82 }
83 return true;
84 }
85
87 {
88 // complete initialization with identity matrix, all lines
89 // were initialized with a trailing 1 followed by 0's.
90 for(sal_uInt16 a(0); a < RowSize; a++)
91 {
92 for(sal_uInt16 b(0); b < RowSize; b++)
94 }
95 }
96
98 {
99 operator=(rToBeCopied);
100 }
101
103 {
104 if (this != &rToBeCopied)
105 {
106 // complete initialization using copy
107 for(sal_uInt16 a(0); a < RowSize; a++)
108 {
109 maLine[a] = rToBeCopied.maLine[a];
110 }
111 }
112 return *this;
113 }
114
115 static sal_uInt16 getEdgeLength() { return RowSize; }
116
117 double get(sal_uInt16 nRow, sal_uInt16 nColumn) const
118 {
119 return maLine[nRow].get(nColumn);
120 }
121
122 void set(sal_uInt16 nRow, sal_uInt16 nColumn, const double& rValue)
123 {
124 maLine[nRow].set(nColumn, rValue);
125 }
126
127 // Left-upper decomposition
128 bool ludcmp(sal_uInt16 nIndex[], sal_Int16& nParity)
129 {
130 double fBig, fSum, fDum;
131 double fStorage[RowSize];
132 sal_uInt16 a, b, c;
133
134 // #i30874# Initialize nAMax (compiler warns)
135 sal_uInt16 nAMax = 0;
136
137 nParity = 1;
138
139 // Calc the max of each line. If a line is empty,
140 // stop immediately since matrix is not invertible then.
141 for(a = 0; a < RowSize; a++)
142 {
143 fBig = 0.0;
144
145 for(b = 0; b < RowSize; b++)
146 {
147 double fTemp(fabs(get(a, b)));
148
149 if(::basegfx::fTools::more(fTemp, fBig))
150 {
151 fBig = fTemp;
152 }
153 }
154
156 {
157 return false;
158 }
159
160 fStorage[a] = 1.0 / fBig;
161 }
162
163 // start normalizing
164 for(b = 0; b < RowSize; b++)
165 {
166 for(a = 0; a < b; a++)
167 {
168 fSum = get(a, b);
169
170 for(c = 0; c < a; c++)
171 {
172 fSum -= get(a, c) * get(c, b);
173 }
174
175 set(a, b, fSum);
176 }
177
178 fBig = 0.0;
179
180 for(a = b; a < RowSize; a++)
181 {
182 fSum = get(a, b);
183
184 for(c = 0; c < b; c++)
185 {
186 fSum -= get(a, c) * get(c, b);
187 }
188
189 set(a, b, fSum);
190 fDum = fStorage[a] * fabs(fSum);
191
192 if(::basegfx::fTools::moreOrEqual(fDum, fBig))
193 {
194 fBig = fDum;
195 nAMax = a;
196 }
197 }
198
199 if(b != nAMax)
200 {
201 for(c = 0; c < RowSize; c++)
202 {
203 fDum = get(nAMax, c);
204 set(nAMax, c, get(b, c));
205 set(b, c, fDum);
206 }
207
208 nParity = -nParity;
209 fStorage[nAMax] = fStorage[b];
210 }
211
212 nIndex[b] = nAMax;
213
214 // here the failure of precision occurs
215 const double fValBB(fabs(get(b, b)));
216
218 {
219 return false;
220 }
221
222 if(b != (RowSize - 1))
223 {
224 fDum = 1.0 / get(b, b);
225
226 for(a = b + 1; a < RowSize; a++)
227 {
228 set(a, b, get(a, b) * fDum);
229 }
230 }
231 }
232
233 return true;
234 }
235
236 void lubksb(const sal_uInt16 nIndex[], double fRow[]) const
237 {
238 sal_uInt16 b, ip;
239 sal_Int16 a, a2 = -1;
240 double fSum;
241
242 for(a = 0; a < RowSize; a++)
243 {
244 ip = nIndex[a];
245 fSum = fRow[ip];
246 fRow[ip] = fRow[a];
247
248 if(a2 >= 0)
249 {
250 for(b = a2; b < a; b++)
251 {
252 fSum -= get(a, b) * fRow[b];
253 }
254 }
255 else if(!::basegfx::fTools::equalZero(fSum))
256 {
257 a2 = a;
258 }
259
260 fRow[a] = fSum;
261 }
262
263 for(a = (RowSize - 1); a >= 0; a--)
264 {
265 fSum = fRow[a];
266
267 for(b = a + 1; b < RowSize; b++)
268 {
269 fSum -= get(a, b) * fRow[b];
270 }
271
272 const double fValueAA(get(a, a));
273
274 if(!::basegfx::fTools::equalZero(fValueAA))
275 {
276 fRow[a] = fSum / get(a, a);
277 }
278 }
279 }
280
281 bool isIdentity() const
282 {
283 for(sal_uInt16 a(0); a < RowSize; a++)
284 {
285 for(sal_uInt16 b(0); b < RowSize; b++)
286 {
287 const double fDefault(implGetDefaultValue(a, b));
288 const double fValueAB(get(a, b));
289
290 if(!::basegfx::fTools::equal(fDefault, fValueAB))
291 {
292 return false;
293 }
294 }
295 }
296
297 return true;
298 }
299
300 bool isInvertible() const
301 {
302 ImplHomMatrixTemplate aWork(*this);
303 sal_uInt16 nIndex[RowSize];
304 sal_Int16 nParity;
305
306 return aWork.ludcmp(nIndex, nParity);
307 }
308
309 void doInvert(const ImplHomMatrixTemplate& rWork, const sal_uInt16 nIndex[])
310 {
311 double fArray[RowSize];
312
313 for(sal_uInt16 a(0); a < RowSize; a++)
314 {
315 // prepare line
316 sal_uInt16 b;
317 for( b = 0; b < RowSize; b++)
318 {
319 fArray[b] = implGetDefaultValue(a, b);
320 }
321
322 // expand line
323 rWork.lubksb(nIndex, fArray);
324
325 // copy line transposed to this matrix
326 for( b = 0; b < RowSize; b++)
327 {
328 set(b, a, fArray[b]);
329 }
330 }
331 }
332
333 double doDeterminant() const
334 {
335 ImplHomMatrixTemplate aWork(*this);
336 sal_uInt16 nIndex[RowSize];
337 sal_Int16 nParity;
338 double fRetval(0.0);
339
340 if(aWork.ludcmp(nIndex, nParity))
341 {
342 fRetval = static_cast<double>(nParity);
343 for(sal_uInt16 a(0); a < RowSize; a++)
344 {
345 fRetval *= aWork.get(a, a);
346 }
347 }
348
349 return fRetval;
350 }
351
353 {
354 for(sal_uInt16 a(0); a < RowSize; a++)
355 {
356 for(sal_uInt16 b(0); b < RowSize; b++)
357 {
358 set(a, b, get(a, b) + rMat.get(a, b));
359 }
360 }
361 }
362
364 {
365 for(sal_uInt16 a(0); a < RowSize; a++)
366 {
367 for(sal_uInt16 b(0); b < RowSize; b++)
368 {
369 set(a, b, get(a, b) - rMat.get(a, b));
370 }
371 }
372 }
373
374 void doMulMatrix(const double& rfValue)
375 {
376 for(sal_uInt16 a(0); a < RowSize; a++)
377 {
378 for(sal_uInt16 b(0); b < RowSize; b++)
379 {
380 set(a, b, get(a, b) * rfValue);
381 }
382 }
383 }
384
386 {
387 // create a copy as source for the original values
388 const ImplHomMatrixTemplate aCopy(*this);
389
390 // TODO: maybe optimize cases where last line is [0 0 1].
391
392 double fValue(0.0);
393
394 for(sal_uInt16 a(0); a < RowSize; ++a)
395 {
396 for(sal_uInt16 b(0); b < RowSize; ++b)
397 {
398 fValue = 0.0;
399
400 for(sal_uInt16 c(0); c < RowSize; ++c)
401 fValue += aCopy.get(c, b) * rMat.get(a, c);
402
403 set(a, b, fValue);
404 }
405 }
406 }
407
408 bool isEqual(const ImplHomMatrixTemplate& rMat) const
409 {
410 for(sal_uInt16 a(0); a < RowSize; a++)
411 {
412 for(sal_uInt16 b(0); b < RowSize; b++)
413 {
414 const double fValueA(get(a, b));
415 const double fValueB(rMat.get(a, b));
416
417 if(!::basegfx::fTools::equal(fValueA, fValueB))
418 {
419 return false;
420 }
421 }
422 }
423
424 return true;
425 }
426 };
427
428} // namespace basegfx::internal
429
430/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
ImplHomMatrixTemplate(const ImplHomMatrixTemplate &rToBeCopied)
void doSubMatrix(const ImplHomMatrixTemplate &rMat)
ImplHomMatrixTemplate & operator=(const ImplHomMatrixTemplate &rToBeCopied)
void doAddMatrix(const ImplHomMatrixTemplate &rMat)
void lubksb(const sal_uInt16 nIndex[], double fRow[]) const
double get(sal_uInt16 nRow, sal_uInt16 nColumn) const
void doInvert(const ImplHomMatrixTemplate &rWork, const sal_uInt16 nIndex[])
ImplMatLine< RowSize > maLine[RowSize]
void doMulMatrix(const ImplHomMatrixTemplate &rMat)
bool isEqual(const ImplHomMatrixTemplate &rMat) const
void set(sal_uInt16 nRow, sal_uInt16 nColumn, const double &rValue)
bool ludcmp(sal_uInt16 nIndex[], sal_Int16 &nParity)
void set(sal_uInt16 nColumn, const double &rValue)
double get(sal_uInt16 nColumn) const
sal_Int32 nIndex
uno_Any a
bool more(const T &rfValA, const T &rfValB)
Definition: ftools.hxx:194
bool equalZero(const T &rfVal)
Compare against small value.
Definition: ftools.hxx:156
bool moreOrEqual(const T &rfValA, const T &rfValB)
Definition: ftools.hxx:200
constexpr double implGetDefaultValue(sal_uInt16 nRow, sal_uInt16 nColumn)
constexpr int RowSize