Coverage Report

Created: 2026-07-10 11:04

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
4.58M
        {
32
4.58M
            if(nRow == nColumn)
33
1.15M
                return 1.0;
34
3.43M
            return 0.0;
35
4.58M
        }
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
9.46M
            {
54
9.46M
                return mfValue[nColumn];
55
9.46M
            }
56
57
            void set(sal_uInt16 nColumn, const double& rValue)
58
4.90M
            {
59
4.90M
                mfValue[nColumn] = rValue;
60
4.90M
            }
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
28.1k
            {
71
140k
                for(sal_uInt16 a(0); a < RowSize; a++)
72
112k
                {
73
112k
                    const double fDefault(implGetDefaultValue((RowSize - 1), a));
74
112k
                    const double fLineValue(maLine[RowSize-1].get(a));
75
76
112k
                    if(fDefault != fLineValue)
77
0
                    {
78
0
                        return false;
79
0
                    }
80
112k
                }
81
28.1k
                return true;
82
28.1k
            }
83
84
            ImplHomMatrixTemplate()
85
186k
            {
86
                // complete initialization with identity matrix, all lines
87
                // were initialized with a trailing 1 followed by 0's.
88
932k
                for(sal_uInt16 a(0); a < RowSize; a++)
89
745k
                {
90
3.72M
                    for(sal_uInt16 b(0); b < RowSize; b++)
91
2.98M
                        maLine[a].set(b, implGetDefaultValue(a, b) );
92
745k
                }
93
186k
            }
94
95
            ImplHomMatrixTemplate(const ImplHomMatrixTemplate& rToBeCopied)
96
89.2k
            {
97
89.2k
                operator=(rToBeCopied);
98
89.2k
            }
99
100
            ImplHomMatrixTemplate& operator=(const ImplHomMatrixTemplate& rToBeCopied)
101
111k
            {
102
111k
                if (this != &rToBeCopied)
103
111k
                {
104
                    // complete initialization using copy
105
558k
                    for(sal_uInt16 a(0); a < RowSize; a++)
106
446k
                    {
107
446k
                        maLine[a] = rToBeCopied.maLine[a];
108
446k
                    }
109
111k
                }
110
111k
                return *this;
111
111k
            }
112
113
22.4k
            static sal_uInt16 getEdgeLength() { return RowSize; }
114
115
            double get(sal_uInt16 nRow, sal_uInt16 nColumn) const
116
9.35M
            {
117
9.35M
                return maLine[nRow].get(nColumn);
118
9.35M
            }
119
120
            void set(sal_uInt16 nRow, sal_uInt16 nColumn, const double& rValue)
121
1.92M
            {
122
1.92M
                maLine[nRow].set(nColumn, rValue);
123
1.92M
            }
124
125
            // Left-upper decomposition
126
            bool ludcmp(sal_uInt16 nIndex[], sal_Int16& nParity)
127
22.4k
            {
128
22.4k
                double fBig, fSum, fDum;
129
22.4k
                double fStorage[RowSize];
130
22.4k
                sal_uInt16 a, b, c;
131
132
                // #i30874# Initialize nAMax (compiler warns)
133
22.4k
                sal_uInt16 nAMax = 0;
134
135
22.4k
                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
112k
                for(a = 0; a < RowSize; a++)
140
89.9k
                {
141
89.9k
                    fBig = 0.0;
142
143
449k
                    for(b = 0; b < RowSize; b++)
144
359k
                    {
145
359k
                        double fTemp(fabs(get(a, b)));
146
147
359k
                        if(::basegfx::fTools::more(fTemp, fBig))
148
95.9k
                        {
149
95.9k
                            fBig = fTemp;
150
95.9k
                        }
151
359k
                    }
152
153
89.9k
                    if(::basegfx::fTools::equalZero(fBig))
154
6
                    {
155
6
                        return false;
156
6
                    }
157
158
89.9k
                    assert(fBig != 0 && "help coverity see it's not zero");
159
89.8k
                    fStorage[a] = 1.0 / fBig;
160
89.8k
                }
161
162
                // start normalizing
163
112k
                for(b = 0; b < RowSize; b++)
164
89.8k
                {
165
224k
                    for(a = 0; a < b; a++)
166
134k
                    {
167
134k
                        fSum = get(a, b);
168
169
224k
                        for(c = 0; c < a; c++)
170
89.8k
                        {
171
89.8k
                            fSum -= get(a, c) * get(c, b);
172
89.8k
                        }
173
174
134k
                        set(a, b, fSum);
175
134k
                    }
176
177
89.8k
                    fBig = 0.0;
178
179
314k
                    for(a = b; a < RowSize; a++)
180
224k
                    {
181
224k
                        fSum = get(a, b);
182
183
449k
                        for(c = 0; c < b; c++)
184
224k
                        {
185
224k
                            fSum -= get(a, c) * get(c, b);
186
224k
                        }
187
188
224k
                        set(a, b, fSum);
189
224k
                        fDum = fStorage[a] * fabs(fSum);
190
191
224k
                        if(::basegfx::fTools::moreOrEqual(fDum, fBig))
192
92.7k
                        {
193
92.7k
                            fBig = fDum;
194
92.7k
                            nAMax = a;
195
92.7k
                        }
196
224k
                    }
197
198
89.8k
                    if(b != nAMax)
199
2.81k
                    {
200
14.0k
                        for(c = 0; c < RowSize; c++)
201
11.2k
                        {
202
11.2k
                            fDum = get(nAMax, c);
203
11.2k
                            set(nAMax, c, get(b, c));
204
11.2k
                            set(b, c, fDum);
205
11.2k
                        }
206
207
2.81k
                        nParity = -nParity;
208
2.81k
                        fStorage[nAMax] = fStorage[b];
209
2.81k
                    }
210
211
89.8k
                    nIndex[b] = nAMax;
212
213
                    // here the failure of precision occurs
214
89.8k
                    const double fValBB(fabs(get(b, b)));
215
216
89.8k
                    if(::basegfx::fTools::equalZero(fValBB))
217
0
                    {
218
0
                        return false;
219
0
                    }
220
221
89.8k
                    if(b != (RowSize - 1))
222
67.4k
                    {
223
67.4k
                        fDum = 1.0 / get(b, b);
224
225
202k
                        for(a = b + 1; a < RowSize; a++)
226
134k
                        {
227
134k
                            set(a, b, get(a, b) * fDum);
228
134k
                        }
229
67.4k
                    }
230
89.8k
                }
231
232
22.4k
                return true;
233
22.4k
            }
234
235
            void lubksb(const sal_uInt16 nIndex[], double fRow[]) const
236
89.8k
            {
237
89.8k
                sal_uInt16 b, ip;
238
89.8k
                sal_Int16 a, a2 = -1;
239
89.8k
                double fSum;
240
241
449k
                for(a = 0; a < RowSize; a++)
242
359k
                {
243
359k
                    ip = nIndex[a];
244
359k
                    fSum = fRow[ip];
245
359k
                    fRow[ip] = fRow[a];
246
247
359k
                    if(a2 >= 0)
248
134k
                    {
249
359k
                        for(b = a2; b < a; b++)
250
224k
                        {
251
224k
                            fSum -= get(a, b) * fRow[b];
252
224k
                        }
253
134k
                    }
254
224k
                    else if(!::basegfx::fTools::equalZero(fSum))
255
89.8k
                    {
256
89.8k
                        a2 = a;
257
89.8k
                    }
258
259
359k
                    fRow[a] = fSum;
260
359k
                }
261
262
449k
                for(a = (RowSize - 1); a >= 0; a--)
263
359k
                {
264
359k
                    fSum = fRow[a];
265
266
898k
                    for(b = a + 1; b < RowSize; b++)
267
539k
                    {
268
539k
                        fSum -= get(a, b) * fRow[b];
269
539k
                    }
270
271
359k
                    const double fValueAA(get(a, a));
272
273
359k
                    if(!::basegfx::fTools::equalZero(fValueAA))
274
359k
                    {
275
359k
                        fRow[a] = fSum / get(a, a);
276
359k
                    }
277
359k
                }
278
89.8k
            }
279
280
            bool isIdentity() const
281
76.0k
            {
282
356k
                for(sal_uInt16 a(0); a < RowSize; a++)
283
286k
                {
284
1.41M
                    for(sal_uInt16 b(0); b < RowSize; b++)
285
1.13M
                    {
286
1.13M
                        const double fDefault(implGetDefaultValue(a, b));
287
1.13M
                        const double fValueAB(get(a, b));
288
289
1.13M
                        if(!::basegfx::fTools::equal(fDefault, fValueAB))
290
5.93k
                        {
291
5.93k
                            return false;
292
5.93k
                        }
293
1.13M
                    }
294
286k
                }
295
296
70.1k
                return true;
297
76.0k
            }
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
22.4k
            {
310
22.4k
                double fArray[RowSize];
311
312
112k
                for(sal_uInt16 a(0); a < RowSize; a++)
313
89.8k
                {
314
                    // prepare line
315
89.8k
                    sal_uInt16 b;
316
449k
                    for( b = 0; b < RowSize; b++)
317
359k
                    {
318
359k
                        fArray[b] = implGetDefaultValue(a, b);
319
359k
                    }
320
321
                    // expand line
322
89.8k
                    rWork.lubksb(nIndex, fArray);
323
324
                    // copy line transposed to this matrix
325
449k
                    for( b = 0; b < RowSize; b++)
326
359k
                    {
327
359k
                        set(b, a, fArray[b]);
328
359k
                    }
329
89.8k
                }
330
22.4k
            }
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
35.0k
            {
375
                // create a copy as source for the original values
376
35.0k
                const ImplHomMatrixTemplate aCopy(*this);
377
378
                // TODO: maybe optimize cases where last line is [0 0 1].
379
380
35.0k
                double fValue(0.0);
381
382
175k
                for(sal_uInt16 a(0); a < RowSize; ++a)
383
140k
                {
384
700k
                    for(sal_uInt16 b(0); b < RowSize; ++b)
385
560k
                    {
386
560k
                        fValue = 0.0;
387
388
2.80M
                        for(sal_uInt16 c(0); c < RowSize; ++c)
389
2.24M
                            fValue += aCopy.get(c, b) * rMat.get(a, c);
390
391
560k
                        set(a, b, fValue);
392
560k
                    }
393
140k
                }
394
35.0k
            }
395
396
            bool isEqual(const ImplHomMatrixTemplate& rMat) const
397
6.45k
            {
398
8.21k
                for(sal_uInt16 a(0); a < RowSize; a++)
399
8.21k
                {
400
24.0k
                    for(sal_uInt16 b(0); b < RowSize; b++)
401
22.3k
                    {
402
22.3k
                        const double fValueA(get(a, b));
403
22.3k
                        const double fValueB(rMat.get(a, b));
404
405
22.3k
                        if(!::basegfx::fTools::equal(fValueA, fValueB))
406
6.45k
                        {
407
6.45k
                            return false;
408
6.45k
                        }
409
22.3k
                    }
410
8.21k
                }
411
412
0
                return true;
413
6.45k
            }
414
        };
415
416
} // namespace basegfx::internal
417
418
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */