Coverage Report

Created: 2026-11-06 11:29

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