Coverage Report

Created: 2026-08-14 10:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/drawinglayer/source/geometry/viewinformation3d.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 <drawinglayer/geometry/viewinformation3d.hxx>
21
#include <basegfx/matrix/b3dhommatrix.hxx>
22
#include <com/sun/star/beans/PropertyValue.hpp>
23
#include <com/sun/star/geometry/AffineMatrix3D.hpp>
24
#include <basegfx/utils/canvastools.hxx>
25
#include <com/sun/star/uno/Sequence.hxx>
26
#include <utility>
27
28
29
using namespace com::sun::star;
30
31
32
namespace drawinglayer::geometry
33
{
34
        /** Implementation class for ViewInformation3D
35
        */
36
        class ImpViewInformation3D
37
        {
38
        private:
39
            // ViewInformation3D implementation can change refcount, so we have only
40
            // two memory regions for pairs of ViewInformation3D/ImpViewInformation3D
41
            friend class ::drawinglayer::geometry::ViewInformation3D;
42
43
            // the 3D transformations
44
            // Object to World. This may change and being adapted when entering 3D transformation
45
            // groups
46
            basegfx::B3DHomMatrix                       maObjectTransformation;
47
48
            // World to Camera. This includes VRP, VPN and VUV camera coordinate system
49
            basegfx::B3DHomMatrix                       maOrientation;
50
51
            // Camera to Device with X,Y and Z [-1.0 .. 1.0]. This is the
52
            // 3D to 2D projection which may be parallel or perspective. When it is perspective,
53
            // the last line of the homogen matrix will NOT be unused
54
            basegfx::B3DHomMatrix                       maProjection;
55
56
            // Device to View with X,Y and Z [0.0 .. 1.0]. This converts from -1 to 1 coordinates
57
            // in camera coordinate system to 0 to 1 in unit 2D coordinates. This way it stays
58
            // view-independent. To get discrete coordinates, the 2D transformation of a scene
59
            // as 2D object needs to be involved
60
            basegfx::B3DHomMatrix                       maDeviceToView;
61
62
            // Object to View is the linear combination of all four transformations. It's
63
            // buffered to avoid too much matrix multiplying and created on demand
64
            basegfx::B3DHomMatrix                       maObjectToView;
65
66
            // the point in time
67
            double                                      mfViewTime;
68
69
            // the extra PropertyValues; does not contain the transformations
70
            uno::Sequence< beans::PropertyValue >       mxExtendedInformation;
71
72
            // the local UNO API strings
73
            static constexpr OUString OBJECT_TRANSFORMATION = u"ObjectTransformation"_ustr;
74
            static constexpr OUString ORIENTATION = u"Orientation"_ustr;
75
            static constexpr OUString PROJECTION = u"Projection"_ustr;
76
            static constexpr OUString PROJECTION30 = u"Projection30"_ustr;
77
            static constexpr OUString PROJECTION31 = u"Projection31"_ustr;
78
            static constexpr OUString PROJECTION32 = u"Projection32"_ustr;
79
            static constexpr OUString PROJECTION33 = u"Projection33"_ustr;
80
            static constexpr OUString DEVICE_TO_VIEW = u"DeviceToView"_ustr;
81
            static constexpr OUString TIME = u"Time"_ustr;
82
83
            // a central PropertyValue parsing method to allow transportation of
84
            // all ViewParameters using UNO API
85
            void impInterpretPropertyValues(const uno::Sequence< beans::PropertyValue >& rViewParameters)
86
0
            {
87
0
                if(!rViewParameters.hasElements())
88
0
                    return;
89
90
0
                const sal_Int32 nCount(rViewParameters.getLength());
91
0
                sal_Int32 nExtendedInsert(0);
92
93
                // prepare extended information for filtering. Maximum size is nCount
94
0
                mxExtendedInformation.realloc(nCount);
95
0
                auto pExtendedInformation = mxExtendedInformation.getArray();
96
97
0
                for(sal_Int32 a(0); a < nCount; a++)
98
0
                {
99
0
                    const beans::PropertyValue& rProp = rViewParameters[a];
100
101
0
                    if(rProp.Name == OBJECT_TRANSFORMATION)
102
0
                    {
103
0
                        css::geometry::AffineMatrix3D aAffineMatrix3D;
104
0
                        rProp.Value >>= aAffineMatrix3D;
105
0
                        maObjectTransformation = basegfx::unotools::homMatrixFromAffineMatrix3D(aAffineMatrix3D);
106
0
                    }
107
0
                    else if(rProp.Name == ORIENTATION)
108
0
                    {
109
0
                        css::geometry::AffineMatrix3D aAffineMatrix3D;
110
0
                        rProp.Value >>= aAffineMatrix3D;
111
0
                        maOrientation = basegfx::unotools::homMatrixFromAffineMatrix3D(aAffineMatrix3D);
112
0
                    }
113
0
                    else if(rProp.Name == PROJECTION)
114
0
                    {
115
                        // projection may be defined using a frustum in which case the last line of
116
                        // the 4x4 matrix is not (0,0,0,1). Since AffineMatrix3D does not support that,
117
                        // these four values need to be treated extra
118
0
                        const double f_30(maProjection.get(3, 0));
119
0
                        const double f_31(maProjection.get(3, 1));
120
0
                        const double f_32(maProjection.get(3, 2));
121
0
                        const double f_33(maProjection.get(3, 3));
122
123
0
                        css::geometry::AffineMatrix3D aAffineMatrix3D;
124
0
                        rProp.Value >>= aAffineMatrix3D;
125
0
                        maProjection = basegfx::unotools::homMatrixFromAffineMatrix3D(aAffineMatrix3D);
126
127
0
                        maProjection.set(3, 0, f_30);
128
0
                        maProjection.set(3, 1, f_31);
129
0
                        maProjection.set(3, 2, f_32);
130
0
                        maProjection.set(3, 3, f_33);
131
0
                    }
132
0
                    else if(rProp.Name == PROJECTION30)
133
0
                    {
134
0
                        double f_30(0.0);
135
0
                        rProp.Value >>= f_30;
136
0
                        maProjection.set(3, 0, f_30);
137
0
                    }
138
0
                    else if(rProp.Name == PROJECTION31)
139
0
                    {
140
0
                        double f_31(0.0);
141
0
                        rProp.Value >>= f_31;
142
0
                        maProjection.set(3, 1, f_31);
143
0
                    }
144
0
                    else if(rProp.Name == PROJECTION32)
145
0
                    {
146
0
                        double f_32(0.0);
147
0
                        rProp.Value >>= f_32;
148
0
                        maProjection.set(3, 2, f_32);
149
0
                    }
150
0
                    else if(rProp.Name == PROJECTION33)
151
0
                    {
152
0
                        double f_33(1.0);
153
0
                        rProp.Value >>= f_33;
154
0
                        maProjection.set(3, 3, f_33);
155
0
                    }
156
0
                    else if(rProp.Name == DEVICE_TO_VIEW)
157
0
                    {
158
0
                        css::geometry::AffineMatrix3D aAffineMatrix3D;
159
0
                        rProp.Value >>= aAffineMatrix3D;
160
0
                        maDeviceToView = basegfx::unotools::homMatrixFromAffineMatrix3D(aAffineMatrix3D);
161
0
                    }
162
0
                    else if(rProp.Name == TIME)
163
0
                    {
164
0
                        rProp.Value >>= mfViewTime;
165
0
                    }
166
0
                    else
167
0
                    {
168
                        // extra information; add to filtered information
169
0
                        pExtendedInformation[nExtendedInsert++] = rProp;
170
0
                    }
171
0
                }
172
173
                // extra information size is now known; realloc to final size
174
0
                mxExtendedInformation.realloc(nExtendedInsert);
175
0
            }
176
177
        public:
178
            ImpViewInformation3D(
179
                basegfx::B3DHomMatrix aObjectTransformation,
180
                basegfx::B3DHomMatrix aOrientation,
181
                basegfx::B3DHomMatrix aProjection,
182
                basegfx::B3DHomMatrix aDeviceToView,
183
                double fViewTime,
184
                const uno::Sequence< beans::PropertyValue >& rExtendedParameters)
185
0
            :   maObjectTransformation(std::move(aObjectTransformation)),
186
0
                maOrientation(std::move(aOrientation)),
187
0
                maProjection(std::move(aProjection)),
188
0
                maDeviceToView(std::move(aDeviceToView)),
189
0
                mfViewTime(fViewTime)
190
0
            {
191
0
                impInterpretPropertyValues(rExtendedParameters);
192
0
            }
193
194
            explicit ImpViewInformation3D(const uno::Sequence< beans::PropertyValue >& rViewParameters)
195
            :   mfViewTime()
196
0
            {
197
0
                impInterpretPropertyValues(rViewParameters);
198
0
            }
199
200
            ImpViewInformation3D()
201
            :   mfViewTime()
202
1
            {
203
1
            }
204
205
0
            const basegfx::B3DHomMatrix& getObjectTransformation() const { return maObjectTransformation; }
206
0
            const basegfx::B3DHomMatrix& getOrientation() const { return maOrientation; }
207
0
            const basegfx::B3DHomMatrix& getProjection() const { return maProjection; }
208
0
            const basegfx::B3DHomMatrix& getDeviceToView() const { return maDeviceToView; }
209
0
            double getViewTime() const { return mfViewTime; }
210
211
            const basegfx::B3DHomMatrix& getObjectToView() const
212
0
            {
213
                // on demand WorldToView creation
214
215
0
                if(maObjectToView.isIdentity())
216
0
                {
217
0
                    const_cast< ImpViewInformation3D* >(this)->maObjectToView = maDeviceToView * maProjection * maOrientation * maObjectTransformation;
218
0
                }
219
220
0
                return maObjectToView;
221
0
            }
222
223
            const uno::Sequence< beans::PropertyValue >& getExtendedInformationSequence() const
224
0
            {
225
0
                return mxExtendedInformation;
226
0
            }
227
228
            bool operator==(const ImpViewInformation3D& rCandidate) const
229
0
            {
230
0
                return (maObjectTransformation == rCandidate.maObjectTransformation
231
0
                    && maOrientation == rCandidate.maOrientation
232
0
                    && maProjection == rCandidate.maProjection
233
0
                    && maDeviceToView == rCandidate.maDeviceToView
234
0
                    && mfViewTime == rCandidate.mfViewTime
235
0
                    && mxExtendedInformation == rCandidate.mxExtendedInformation);
236
0
            }
237
        };
238
} // end of namespace drawinglayer::geometry
239
240
241
namespace drawinglayer::geometry
242
{
243
        namespace
244
        {
245
            ViewInformation3D::ImplType& theGlobalDefault()
246
97.7k
            {
247
97.7k
                static ViewInformation3D::ImplType SINGLETON;
248
97.7k
                return SINGLETON;
249
97.7k
            }
250
        }
251
252
        ViewInformation3D::ViewInformation3D(
253
            const basegfx::B3DHomMatrix& rObjectObjectTransformation,
254
            const basegfx::B3DHomMatrix& rOrientation,
255
            const basegfx::B3DHomMatrix& rProjection,
256
            const basegfx::B3DHomMatrix& rDeviceToView,
257
            double fViewTime,
258
            const uno::Sequence< beans::PropertyValue >& rExtendedParameters)
259
0
        :   mpViewInformation3D(ImpViewInformation3D(
260
0
                rObjectObjectTransformation, rOrientation, rProjection,
261
0
                rDeviceToView, fViewTime, rExtendedParameters))
262
0
        {
263
0
        }
264
265
        ViewInformation3D::ViewInformation3D(const uno::Sequence< beans::PropertyValue >& rViewParameters)
266
0
        :   mpViewInformation3D(ImpViewInformation3D(rViewParameters))
267
0
        {
268
0
        }
269
270
        ViewInformation3D::ViewInformation3D()
271
97.7k
        :   mpViewInformation3D(theGlobalDefault())
272
97.7k
        {
273
97.7k
        }
274
275
0
        ViewInformation3D::ViewInformation3D(const ViewInformation3D&) = default;
276
277
0
        ViewInformation3D::ViewInformation3D(ViewInformation3D&&) = default;
278
279
97.7k
        ViewInformation3D::~ViewInformation3D() = default;
280
281
        bool ViewInformation3D::isDefault() const
282
0
        {
283
0
            return mpViewInformation3D.same_object(theGlobalDefault());
284
0
        }
285
286
0
        ViewInformation3D& ViewInformation3D::operator=(const ViewInformation3D&) = default;
287
288
94.4k
        ViewInformation3D& ViewInformation3D::operator=(ViewInformation3D&&) = default;
289
290
        bool ViewInformation3D::operator==(const ViewInformation3D& rCandidate) const
291
0
        {
292
0
            return rCandidate.mpViewInformation3D == mpViewInformation3D;
293
0
        }
294
295
        const basegfx::B3DHomMatrix& ViewInformation3D::getObjectTransformation() const
296
0
        {
297
0
            return mpViewInformation3D->getObjectTransformation();
298
0
        }
299
300
        const basegfx::B3DHomMatrix& ViewInformation3D::getOrientation() const
301
0
        {
302
0
            return mpViewInformation3D->getOrientation();
303
0
        }
304
305
        const basegfx::B3DHomMatrix& ViewInformation3D::getProjection() const
306
0
        {
307
0
            return mpViewInformation3D->getProjection();
308
0
        }
309
310
        const basegfx::B3DHomMatrix& ViewInformation3D::getDeviceToView() const
311
0
        {
312
0
            return mpViewInformation3D->getDeviceToView();
313
0
        }
314
315
        const basegfx::B3DHomMatrix& ViewInformation3D::getObjectToView() const
316
0
        {
317
0
            return mpViewInformation3D->getObjectToView();
318
0
        }
319
320
        double ViewInformation3D::getViewTime() const
321
0
        {
322
0
            return mpViewInformation3D->getViewTime();
323
0
        }
324
325
        const uno::Sequence< beans::PropertyValue >& ViewInformation3D::getExtendedInformationSequence() const
326
0
        {
327
0
            return mpViewInformation3D->getExtendedInformationSequence();
328
0
        }
329
330
} // end of namespace
331
332
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */