Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/basegfx/source/matrix/b2dhommatrixtools.cxx
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
#include <basegfx/matrix/b2dhommatrixtools.hxx>
21
#include <basegfx/range/b2drange.hxx>
22
23
#include <osl/diagnose.h>
24
25
namespace basegfx::utils
26
{
27
        void createSinCosOrthogonal(double& o_rSin, double& o_rCos, double fRadiant)
28
132k
        {
29
132k
            if( fTools::equalZero( fmod( fRadiant, M_PI_2 ) ) )
30
74.2k
            {
31
                // determine quadrant
32
74.2k
                const sal_Int32 nQuad(
33
74.2k
                    (4 + fround( M_2_PI*fmod( fRadiant, 2 * M_PI ) )) % 4 );
34
74.2k
                switch( nQuad )
35
74.2k
                {
36
0
                    case 0: // -2pi,0,2pi
37
0
                        o_rSin = 0.0;
38
0
                        o_rCos = 1.0;
39
0
                        break;
40
41
31.9k
                    case 1: // -3/2pi,1/2pi
42
31.9k
                        o_rSin = 1.0;
43
31.9k
                        o_rCos = 0.0;
44
31.9k
                        break;
45
46
2.74k
                    case 2: // -pi,pi
47
2.74k
                        o_rSin = 0.0;
48
2.74k
                        o_rCos = -1.0;
49
2.74k
                        break;
50
51
39.5k
                    case 3: // -1/2pi,3/2pi
52
39.5k
                        o_rSin = -1.0;
53
39.5k
                        o_rCos = 0.0;
54
39.5k
                        break;
55
56
0
                    default:
57
0
                        OSL_FAIL( "createSinCos: Impossible case reached" );
58
74.2k
                }
59
74.2k
            }
60
58.4k
            else
61
58.4k
            {
62
                // TODO(P1): Maybe use glibc's sincos here (though
63
                // that's kinda non-portable...)
64
58.4k
                o_rSin = sin(fRadiant);
65
58.4k
                o_rCos = cos(fRadiant);
66
58.4k
            }
67
132k
        }
68
69
        B2DHomMatrix createScaleB2DHomMatrix(double fScaleX, double fScaleY)
70
9.64k
        {
71
9.64k
            B2DHomMatrix aRetval;
72
9.64k
            const double fOne(1.0);
73
74
9.64k
            if(!fTools::equal(fScaleX, fOne))
75
9.38k
            {
76
9.38k
                aRetval.set(0, 0, fScaleX);
77
9.38k
            }
78
79
9.64k
            if(!fTools::equal(fScaleY, fOne))
80
9.42k
            {
81
9.42k
                aRetval.set(1, 1, fScaleY);
82
9.42k
            }
83
84
9.64k
            return aRetval;
85
9.64k
        }
86
87
        B2DHomMatrix createShearXB2DHomMatrix(double fShearX)
88
0
        {
89
0
            B2DHomMatrix aRetval;
90
91
0
            if(!fTools::equalZero(fShearX))
92
0
            {
93
0
                aRetval.set(0, 1, fShearX);
94
0
            }
95
96
0
            return aRetval;
97
0
        }
98
99
        B2DHomMatrix createShearYB2DHomMatrix(double fShearY)
100
0
        {
101
0
            B2DHomMatrix aRetval;
102
103
0
            if(!fTools::equalZero(fShearY))
104
0
            {
105
0
                aRetval.set(1, 0, fShearY);
106
0
            }
107
108
0
            return aRetval;
109
0
        }
110
111
        B2DHomMatrix createRotateB2DHomMatrix(double fRadiant)
112
49.8k
        {
113
49.8k
            B2DHomMatrix aRetval;
114
115
49.8k
            if(!fTools::equalZero(fRadiant))
116
49.8k
            {
117
49.8k
                double fSin(0.0);
118
49.8k
                double fCos(1.0);
119
120
49.8k
                createSinCosOrthogonal(fSin, fCos, fRadiant);
121
49.8k
                aRetval.set(0, 0, fCos);
122
49.8k
                aRetval.set(1, 1, fCos);
123
49.8k
                aRetval.set(1, 0, fSin);
124
49.8k
                aRetval.set(0, 1, -fSin);
125
49.8k
            }
126
127
49.8k
            return aRetval;
128
49.8k
        }
129
130
        B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY)
131
603k
        {
132
603k
            B2DHomMatrix aRetval;
133
134
603k
            if(!(fTools::equalZero(fTranslateX) && fTools::equalZero(fTranslateY)))
135
568k
            {
136
568k
                aRetval.set(0, 2, fTranslateX);
137
568k
                aRetval.set(1, 2, fTranslateY);
138
568k
            }
139
140
603k
            return aRetval;
141
603k
        }
142
143
        B2DHomMatrix createScaleShearXRotateTranslateB2DHomMatrix(
144
            double fScaleX, double fScaleY,
145
            double fShearX,
146
            double fRadiant,
147
            double fTranslateX, double fTranslateY)
148
124k
        {
149
124k
            const double fOne(1.0);
150
151
124k
            if(fTools::equal(fScaleX, fOne) && fTools::equal(fScaleY, fOne))
152
17.7k
            {
153
                /// no scale, take shortcut
154
17.7k
                return createShearXRotateTranslateB2DHomMatrix(fShearX, fRadiant, fTranslateX, fTranslateY);
155
17.7k
            }
156
107k
            else
157
107k
            {
158
                /// scale used
159
107k
                if(fTools::equalZero(fShearX))
160
107k
                {
161
                    /// no shear
162
107k
                    if(fTools::equalZero(fRadiant))
163
103k
                    {
164
                        /// no rotate, take shortcut
165
103k
                        return createScaleTranslateB2DHomMatrix(fScaleX, fScaleY, fTranslateX, fTranslateY);
166
103k
                    }
167
3.17k
                    else
168
3.17k
                    {
169
                        /// rotate and scale used, no shear
170
3.17k
                        double fSin(0.0);
171
3.17k
                        double fCos(1.0);
172
173
3.17k
                        createSinCosOrthogonal(fSin, fCos, fRadiant);
174
175
3.17k
                        B2DHomMatrix aRetval(
176
3.17k
                            /* Row 0, Column 0 */ fCos * fScaleX,
177
3.17k
                            /* Row 0, Column 1 */ fScaleY * -fSin,
178
3.17k
                            /* Row 0, Column 2 */ fTranslateX,
179
3.17k
                            /* Row 1, Column 0 */ fSin * fScaleX,
180
3.17k
                            /* Row 1, Column 1 */ fScaleY * fCos,
181
3.17k
                            /* Row 1, Column 2 */ fTranslateY);
182
183
3.17k
                        return aRetval;
184
3.17k
                    }
185
107k
                }
186
0
                else
187
0
                {
188
                    /// scale and shear used
189
0
                    if(fTools::equalZero(fRadiant))
190
0
                    {
191
                        /// scale and shear, but no rotate
192
0
                        B2DHomMatrix aRetval(
193
0
                            /* Row 0, Column 0 */ fScaleX,
194
0
                            /* Row 0, Column 1 */ fScaleY * fShearX,
195
0
                            /* Row 0, Column 2 */ fTranslateX,
196
0
                            /* Row 1, Column 0 */ 0.0,
197
0
                            /* Row 1, Column 1 */ fScaleY,
198
0
                            /* Row 1, Column 2 */ fTranslateY);
199
200
0
                        return aRetval;
201
0
                    }
202
0
                    else
203
0
                    {
204
                        /// scale, shear and rotate used
205
0
                        double fSin(0.0);
206
0
                        double fCos(1.0);
207
208
0
                        createSinCosOrthogonal(fSin, fCos, fRadiant);
209
210
0
                        B2DHomMatrix aRetval(
211
0
                            /* Row 0, Column 0 */ fCos * fScaleX,
212
0
                            /* Row 0, Column 1 */ fScaleY * ((fCos * fShearX) - fSin),
213
0
                            /* Row 0, Column 2 */ fTranslateX,
214
0
                            /* Row 1, Column 0 */ fSin * fScaleX,
215
0
                            /* Row 1, Column 1 */ fScaleY * ((fSin * fShearX) + fCos),
216
0
                            /* Row 1, Column 2 */ fTranslateY);
217
218
0
                        return aRetval;
219
0
                    }
220
0
                }
221
107k
            }
222
124k
        }
223
224
        B2DHomMatrix createShearXRotateTranslateB2DHomMatrix(
225
            double fShearX,
226
            double fRadiant,
227
            double fTranslateX, double fTranslateY)
228
18.2k
        {
229
18.2k
            if(fTools::equalZero(fShearX))
230
18.2k
            {
231
                /// no shear
232
18.2k
                if(fTools::equalZero(fRadiant))
233
18.1k
                {
234
                    /// no shear, no rotate, take shortcut
235
18.1k
                    return createTranslateB2DHomMatrix(fTranslateX, fTranslateY);
236
18.1k
                }
237
42
                else
238
42
                {
239
                    /// no shear, but rotate used
240
42
                    double fSin(0.0);
241
42
                    double fCos(1.0);
242
243
42
                    createSinCosOrthogonal(fSin, fCos, fRadiant);
244
245
42
                    B2DHomMatrix aRetval(
246
42
                        /* Row 0, Column 0 */ fCos,
247
42
                        /* Row 0, Column 1 */ -fSin,
248
42
                        /* Row 0, Column 2 */ fTranslateX,
249
42
                        /* Row 1, Column 0 */ fSin,
250
42
                        /* Row 1, Column 1 */ fCos,
251
42
                        /* Row 1, Column 2 */ fTranslateY);
252
253
42
                    return aRetval;
254
42
                }
255
18.2k
            }
256
0
            else
257
0
            {
258
                /// shear used
259
0
                if(fTools::equalZero(fRadiant))
260
0
                {
261
                    /// no rotate, but shear used
262
0
                    B2DHomMatrix aRetval(
263
0
                        /* Row 0, Column 0 */ 1.0,
264
0
                        /* Row 0, Column 1 */ fShearX,
265
0
                        /* Row 0, Column 2 */ fTranslateX,
266
0
                        /* Row 1, Column 0 */ 0.0,
267
0
                        /* Row 1, Column 1 */ 1.0,
268
0
                        /* Row 1, Column 2 */ fTranslateY);
269
270
0
                    return aRetval;
271
0
                }
272
0
                else
273
0
                {
274
                    /// shear and rotate used
275
0
                    double fSin(0.0);
276
0
                    double fCos(1.0);
277
278
0
                    createSinCosOrthogonal(fSin, fCos, fRadiant);
279
280
0
                    B2DHomMatrix aRetval(
281
0
                        /* Row 0, Column 0 */ fCos,
282
0
                        /* Row 0, Column 1 */ (fCos * fShearX) - fSin,
283
0
                        /* Row 0, Column 2 */ fTranslateX,
284
0
                        /* Row 1, Column 0 */ fSin,
285
0
                        /* Row 1, Column 1 */ (fSin * fShearX) + fCos,
286
0
                        /* Row 1, Column 2 */ fTranslateY);
287
288
0
                    return aRetval;
289
0
                }
290
0
            }
291
18.2k
        }
292
293
        B2DHomMatrix createScaleTranslateB2DHomMatrix(
294
            double fScaleX, double fScaleY,
295
            double fTranslateX, double fTranslateY)
296
1.03M
        {
297
1.03M
            const double fOne(1.0);
298
299
1.03M
            if(fTools::equal(fScaleX, fOne) && fTools::equal(fScaleY, fOne))
300
1.25k
            {
301
                /// no scale, take shortcut
302
1.25k
                return createTranslateB2DHomMatrix(fTranslateX, fTranslateY);
303
1.25k
            }
304
1.03M
            else
305
1.03M
            {
306
                /// scale used
307
1.03M
                if(fTools::equalZero(fTranslateX) && fTools::equalZero(fTranslateY))
308
100k
                {
309
                    /// no translate, but scale.
310
100k
                    B2DHomMatrix aRetval;
311
312
100k
                    aRetval.set(0, 0, fScaleX);
313
100k
                    aRetval.set(1, 1, fScaleY);
314
315
100k
                    return aRetval;
316
100k
                }
317
931k
                else
318
931k
                {
319
                    /// translate and scale
320
931k
                    B2DHomMatrix aRetval(
321
931k
                        /* Row 0, Column 0 */ fScaleX,
322
931k
                        /* Row 0, Column 1 */ 0.0,
323
931k
                        /* Row 0, Column 2 */ fTranslateX,
324
931k
                        /* Row 1, Column 0 */ 0.0,
325
931k
                        /* Row 1, Column 1 */ fScaleY,
326
931k
                        /* Row 1, Column 2 */ fTranslateY);
327
328
931k
                    return aRetval;
329
931k
                }
330
1.03M
            }
331
1.03M
        }
332
333
        B2DHomMatrix createRotateAroundPoint(
334
            double fPointX, double fPointY,
335
            double fRadiant)
336
15.7k
        {
337
15.7k
            B2DHomMatrix aRetval;
338
339
15.7k
            if(!fTools::equalZero(fRadiant))
340
15.7k
            {
341
15.7k
                double fSin(0.0);
342
15.7k
                double fCos(1.0);
343
344
15.7k
                createSinCosOrthogonal(fSin, fCos, fRadiant);
345
346
15.7k
                aRetval.set3x2(
347
15.7k
                    /* Row 0, Column 0 */ fCos,
348
15.7k
                    /* Row 0, Column 1 */ -fSin,
349
15.7k
                    /* Row 0, Column 2 */ (fPointX * (1.0 - fCos)) + (fSin * fPointY),
350
15.7k
                    /* Row 1, Column 0 */ fSin,
351
15.7k
                    /* Row 1, Column 1 */ fCos,
352
15.7k
                    /* Row 1, Column 2 */ (fPointY * (1.0 - fCos)) - (fSin * fPointX));
353
15.7k
            }
354
355
15.7k
            return aRetval;
356
15.7k
        }
357
358
        B2DHomMatrix createRotateAroundCenterKeepAspectRatioStayInsideRange(
359
            const basegfx::B2DRange& rTargetRange,
360
            double fRotate)
361
0
        {
362
0
            basegfx::B2DHomMatrix aRetval;
363
364
            // RotGrfFlyFrame: Create a transformation that maps the range inside of itself
365
            // so that it fits, takes as much space as possible and keeps the aspect ratio
366
0
            if(0.0 != fRotate)
367
0
            {
368
                // Fit rotated graphic to center of available space, keeping page ratio:
369
                // Adapt scaling ratio of unit object and rotate it
370
0
                aRetval.scale(1.0, rTargetRange.getHeight() / rTargetRange.getWidth());
371
0
                aRetval.rotate(fRotate);
372
373
                // get the range to see where we are in unit coordinates
374
0
                basegfx::B2DRange aFullRange(0.0, 0.0, 1.0, 1.0);
375
0
                aFullRange.transform(aRetval);
376
377
                // detect needed scales in X/Y and choose the smallest for staying inside the
378
                // available space while keeping aspect ratio of the source
379
0
                const double fScaleX(rTargetRange.getWidth() / aFullRange.getWidth());
380
0
                const double fScaleY(rTargetRange.getHeight() / aFullRange.getHeight());
381
0
                const double fScaleMin(std::min(fScaleX, fScaleY));
382
383
                // TopLeft to zero, then scale, then move to center of available space
384
0
                aRetval.translate(-aFullRange.getMinX(), -aFullRange.getMinY());
385
0
                aRetval.scale(fScaleMin, fScaleMin);
386
0
                aRetval.translate(
387
0
                    rTargetRange.getCenterX() - (0.5 * fScaleMin * aFullRange.getWidth()),
388
0
                    rTargetRange.getCenterY() - (0.5 * fScaleMin * aFullRange.getHeight()));
389
0
            }
390
0
            else
391
0
            {
392
                // just scale/translate needed
393
0
                aRetval *= createScaleTranslateB2DHomMatrix(
394
0
                    rTargetRange.getRange(),
395
0
                    rTargetRange.getMinimum());
396
0
            }
397
398
0
            return aRetval;
399
0
        }
400
401
        /// special for the case to map from source range to target range
402
        B2DHomMatrix createSourceRangeTargetRangeTransform(
403
            const B2DRange& rSourceRange,
404
            const B2DRange& rTargetRange)
405
4.84k
        {
406
4.84k
            B2DHomMatrix aRetval;
407
408
4.84k
            if(&rSourceRange == &rTargetRange)
409
140
            {
410
140
                return aRetval;
411
140
            }
412
413
4.70k
            if(!fTools::equalZero(rSourceRange.getMinX()) || !fTools::equalZero(rSourceRange.getMinY()))
414
4.70k
            {
415
4.70k
                aRetval.set(0, 2, -rSourceRange.getMinX());
416
4.70k
                aRetval.set(1, 2, -rSourceRange.getMinY());
417
4.70k
            }
418
419
4.70k
            const double fSourceW(rSourceRange.getWidth());
420
4.70k
            const double fSourceH(rSourceRange.getHeight());
421
4.70k
            const bool bDivX(!fTools::equalZero(fSourceW) && !fTools::equal(fSourceW, 1.0));
422
4.70k
            const bool bDivY(!fTools::equalZero(fSourceH) && !fTools::equal(fSourceH, 1.0));
423
4.70k
            const double fScaleX(bDivX ? rTargetRange.getWidth() / fSourceW : rTargetRange.getWidth());
424
4.70k
            const double fScaleY(bDivY ? rTargetRange.getHeight() / fSourceH : rTargetRange.getHeight());
425
426
4.70k
            if(!fTools::equalZero(fScaleX) || !fTools::equalZero(fScaleY))
427
4.70k
            {
428
4.70k
                aRetval.scale(fScaleX, fScaleY);
429
4.70k
            }
430
431
4.70k
            if(!fTools::equalZero(rTargetRange.getMinX()) || !fTools::equalZero(rTargetRange.getMinY()))
432
1
            {
433
1
                aRetval.translate(
434
1
                    rTargetRange.getMinX(),
435
1
                    rTargetRange.getMinY());
436
1
            }
437
438
4.70k
            return aRetval;
439
4.84k
        }
440
441
        B2DHomMatrix createCoordinateSystemTransform(
442
            const B2DPoint& rOrigin,
443
            const B2DVector& rX,
444
            const B2DVector& rY)
445
0
        {
446
0
            return basegfx::B2DHomMatrix(
447
0
                rX.getX(), rY.getX(), rOrigin.getX(),
448
0
                rX.getY(), rY.getY(), rOrigin.getY());
449
0
        }
450
451
        B2DTuple getColumn(const B2DHomMatrix& rMatrix, sal_uInt16 nCol)
452
0
        {
453
0
            return B2DTuple(rMatrix.get(0, nCol), rMatrix.get(1, nCol));
454
0
        }
455
} // end of namespace
456
457
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */