Coverage Report

Created: 2026-11-06 11:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/tools/source/generic/b3dtrans.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 <tools/b3dtrans.hxx>
21
22
#include <osl/diagnose.h>
23
24
    // Near and far clipping planes
25
constexpr double gfNearBound = 0.001;
26
constexpr double gfFarBound = 1.001;
27
28
29
// B3dTransformationSet --------------------------------------------------------
30
// Transformations for all 3D output
31
32
B3dTransformationSet::B3dTransformationSet()
33
3.52k
{
34
3.52k
    Reset();
35
3.52k
}
36
37
B3dTransformationSet::~B3dTransformationSet()
38
3.52k
{
39
3.52k
}
40
41
void B3dTransformationSet::Orientation(basegfx::B3DHomMatrix& rTarget, const basegfx::B3DPoint& aVRP, basegfx::B3DVector aVPN, basegfx::B3DVector aVUP)
42
21.1k
{
43
21.1k
    rTarget.translate( -aVRP.getX(), -aVRP.getY(), -aVRP.getZ());
44
21.1k
    aVUP.normalize();
45
21.1k
    aVPN.normalize();
46
21.1k
    basegfx::B3DVector aRx(aVUP);
47
21.1k
    basegfx::B3DVector aRy(aVPN);
48
21.1k
    aRx = aRx.getPerpendicular(aRy);
49
21.1k
    aRx.normalize();
50
21.1k
    aRy = aRy.getPerpendicular(aRx);
51
21.1k
    aRy.normalize();
52
21.1k
    basegfx::B3DHomMatrix aTemp;
53
21.1k
    aTemp.set(0, 0, aRx.getX());
54
21.1k
    aTemp.set(0, 1, aRx.getY());
55
21.1k
    aTemp.set(0, 2, aRx.getZ());
56
21.1k
    aTemp.set(1, 0, aRy.getX());
57
21.1k
    aTemp.set(1, 1, aRy.getY());
58
21.1k
    aTemp.set(1, 2, aRy.getZ());
59
21.1k
    aTemp.set(2, 0, aVPN.getX());
60
21.1k
    aTemp.set(2, 1, aVPN.getY());
61
21.1k
    aTemp.set(2, 2, aVPN.getZ());
62
21.1k
    rTarget *= aTemp;
63
21.1k
}
64
65
void B3dTransformationSet::Frustum(basegfx::B3DHomMatrix& rTarget, double fLeft, double fRight, double fBottom, double fTop, double fNear, double fFar)
66
3.52k
{
67
3.52k
    if(!(fNear > 0.0))
68
0
    {
69
0
        fNear = 0.001;
70
0
    }
71
3.52k
    if(!(fFar > 0.0))
72
0
    {
73
0
        fFar = 1.0;
74
0
    }
75
3.52k
    if(fNear == fFar)
76
0
    {
77
0
        fFar = fNear + 1.0;
78
0
    }
79
3.52k
    if(fLeft == fRight)
80
0
    {
81
0
        fLeft -= 1.0;
82
0
        fRight += 1.0;
83
0
    }
84
3.52k
    if(fTop == fBottom)
85
0
    {
86
0
        fBottom -= 1.0;
87
0
        fTop += 1.0;
88
0
    }
89
3.52k
    basegfx::B3DHomMatrix aTemp;
90
91
3.52k
    aTemp.set(0, 0, 2.0 * fNear / (fRight - fLeft));
92
3.52k
    aTemp.set(1, 1, 2.0 * fNear / (fTop - fBottom));
93
3.52k
    aTemp.set(0, 2, (fRight + fLeft) / (fRight - fLeft));
94
3.52k
    aTemp.set(1, 2, (fTop + fBottom) / (fTop - fBottom));
95
3.52k
    aTemp.set(2, 2, -1.0 * ((fFar + fNear) / (fFar - fNear)));
96
3.52k
    aTemp.set(3, 2, -1.0);
97
3.52k
    aTemp.set(2, 3, -1.0 * ((2.0 * fFar * fNear) / (fFar - fNear)));
98
3.52k
    aTemp.set(3, 3, 0.0);
99
100
3.52k
    rTarget *= aTemp;
101
3.52k
}
102
103
void B3dTransformationSet::Ortho(basegfx::B3DHomMatrix& rTarget,
104
                                 double fLeft, double fRight, double fBottom, double fTop,
105
                                 double fNear, double fFar)
106
0
{
107
0
    if(fNear == fFar)
108
0
    {
109
0
        OSL_FAIL("Near and far clipping plane in Ortho definition are identical");
110
0
        fFar = fNear + 1.0;
111
0
    }
112
0
    if(fLeft == fRight)
113
0
    {
114
0
        OSL_FAIL("Left and right in Ortho definition are identical");
115
0
        fLeft -= 1.0;
116
0
        fRight += 1.0;
117
0
    }
118
0
    if(fTop == fBottom)
119
0
    {
120
0
        OSL_FAIL("Top and bottom in Ortho definition are identical");
121
0
        fBottom -= 1.0;
122
0
        fTop += 1.0;
123
0
    }
124
0
    basegfx::B3DHomMatrix aTemp;
125
126
0
    aTemp.set(0, 0, 2.0 / (fRight - fLeft));
127
0
    aTemp.set(1, 1, 2.0 / (fTop - fBottom));
128
0
    aTemp.set(2, 2, -1.0 * (2.0 / (fFar - fNear)));
129
0
    aTemp.set(0, 3, -1.0 * ((fRight + fLeft) / (fRight - fLeft)));
130
0
    aTemp.set(1, 3, -1.0 * ((fTop + fBottom) / (fTop - fBottom)));
131
0
    aTemp.set(2, 3, -1.0 * ((fFar + fNear) / (fFar - fNear)));
132
133
0
    rTarget *= aTemp;
134
0
}
135
136
/// reset values
137
void B3dTransformationSet::Reset()
138
3.52k
{
139
    // Reset matrices to identity matrices
140
3.52k
    maObjectTrans.identity();
141
3.52k
    PostSetObjectTrans();
142
143
3.52k
    Orientation(maOrientation);
144
3.52k
    PostSetOrientation();
145
146
3.52k
    maTexture.identity();
147
148
3.52k
    mfLeftBound = mfBottomBound = -1.0;
149
3.52k
    mfRightBound = mfTopBound = 1.0;
150
151
3.52k
    mfRatio = 0.0;
152
153
3.52k
    maViewportRectangle = tools::Rectangle(-1, -1, 2, 2);
154
3.52k
    maVisibleRectangle = maViewportRectangle;
155
156
3.52k
    mbPerspective = true;
157
158
3.52k
    mbProjectionValid = false;
159
160
3.52k
    CalcViewport();
161
3.52k
}
162
163
/// Object transformation
164
void B3dTransformationSet::PostSetObjectTrans()
165
3.52k
{
166
    // Assign and compute inverse
167
3.52k
    maInvObjectTrans = maObjectTrans;
168
3.52k
    maInvObjectTrans.invert();
169
3.52k
}
170
171
void B3dTransformationSet::SetOrientation(const basegfx::B3DPoint& rVRP, const basegfx::B3DVector& rVPN, const basegfx::B3DVector& rVUP)
172
17.6k
{
173
17.6k
    maOrientation.identity();
174
17.6k
    Orientation(maOrientation, rVRP, rVPN, rVUP);
175
176
17.6k
    PostSetOrientation();
177
17.6k
}
178
179
void B3dTransformationSet::PostSetOrientation()
180
21.1k
{
181
    // Assign and compute inverse
182
21.1k
    maInvOrientation = maOrientation;
183
21.1k
    maInvOrientation.invert();
184
21.1k
}
185
186
/// Projections for transformations
187
void B3dTransformationSet::SetProjection(const basegfx::B3DHomMatrix& mProject)
188
3.52k
{
189
3.52k
    maProjection = mProject;
190
3.52k
    PostSetProjection();
191
3.52k
}
192
193
const basegfx::B3DHomMatrix& B3dTransformationSet::GetProjection()
194
3.52k
{
195
3.52k
    if(!mbProjectionValid)
196
0
        CalcViewport();
197
3.52k
    return maProjection;
198
3.52k
}
199
200
void B3dTransformationSet::PostSetProjection()
201
3.52k
{
202
    // Assign and compute inverse
203
3.52k
    maInvProjection = GetProjection();
204
3.52k
    maInvProjection.invert();
205
3.52k
}
206
207
/// Transformations for viewport
208
void B3dTransformationSet::CalcViewport()
209
3.52k
{
210
    // Parameters for projection
211
3.52k
    double fLeft(mfLeftBound);
212
3.52k
    double fRight(mfRightBound);
213
3.52k
    double fBottom(mfBottomBound);
214
3.52k
    double fTop(mfTopBound);
215
216
    // Adjust projection to aspect ratio, if set
217
3.52k
    if(GetRatio() != 0.0)
218
0
    {
219
        // Compute current aspect ratio of boundaries
220
0
        double fBoundWidth = static_cast<double>(maViewportRectangle.GetWidth() + 1);
221
0
        double fBoundHeight = static_cast<double>(maViewportRectangle.GetHeight() + 1);
222
0
        double fActRatio = 1;
223
0
        double fFactor;
224
225
0
        if(fBoundWidth != 0.0)
226
0
            fActRatio = fBoundHeight / fBoundWidth;
227
        // FIXME   else in this case has a lot of problems,  should this return.
228
229
        // scale down larger part
230
0
        if(fActRatio > mfRatio)
231
0
        {
232
            // scale down Y
233
0
            fFactor = fActRatio;
234
0
            fTop *= fFactor;
235
0
            fBottom *= fFactor;
236
0
        }
237
0
        else
238
0
        {
239
            // scale down X
240
0
            fFactor = 1.0 / fActRatio;
241
0
            fRight  *= fFactor;
242
0
            fLeft *= fFactor;
243
0
        }
244
0
    }
245
246
    // Do projection and object areas overlap?
247
3.52k
    maSetBound = maViewportRectangle;
248
249
    // Reset projection with new values
250
3.52k
    basegfx::B3DHomMatrix aNewProjection;
251
252
    // #i36281#
253
    // OpenGL needs a little more rough additional size to not let
254
    // the front face vanish. Changed from SMALL_DVALUE to 0.000001,
255
    // which is 1/10000th, compared with 1/tenth of a million from SMALL_DVALUE.
256
3.52k
    const double fDistPart((gfFarBound - gfNearBound) * 0.0001);
257
258
    // To avoid critical clipping, set Near & Far generously
259
3.52k
    if(mbPerspective)
260
3.52k
    {
261
3.52k
        Frustum(aNewProjection, fLeft, fRight, fBottom, fTop, gfNearBound - fDistPart, gfFarBound + fDistPart);
262
3.52k
    }
263
0
    else
264
0
    {
265
0
        Ortho(aNewProjection, fLeft, fRight, fBottom, fTop, gfNearBound - fDistPart, gfFarBound + fDistPart);
266
0
    }
267
268
    // Set to true to guarantee loop termination
269
3.52k
    mbProjectionValid = true;
270
271
    // set new projection
272
3.52k
    SetProjection(aNewProjection);
273
274
    // fill parameters for ViewportTransformation
275
    // Translation
276
3.52k
    maTranslate.setX(static_cast<double>(maSetBound.Left()) + ((maSetBound.GetWidth() - 1) / 2.0));
277
3.52k
    maTranslate.setY(static_cast<double>(maSetBound.Top()) + ((maSetBound.GetHeight() - 1) / 2.0));
278
3.52k
    maTranslate.setZ(ZBUFFER_DEPTH_RANGE / 2.0);
279
280
    // Scaling
281
3.52k
    maScale.setX((maSetBound.GetWidth() - 1) / 2.0);
282
3.52k
    maScale.setY((maSetBound.GetHeight() - 1) / -2.0);
283
3.52k
    maScale.setZ(ZBUFFER_DEPTH_RANGE / 2.0);
284
3.52k
}
285
286
void B3dTransformationSet::SetRatio(double fNew)
287
7.05k
{
288
7.05k
    if(mfRatio != fNew)
289
0
    {
290
0
        mfRatio = fNew;
291
0
        mbProjectionValid = false;
292
0
    }
293
7.05k
}
294
295
void B3dTransformationSet::SetDeviceRectangle(double fL, double fR, double fB, double fT)
296
3.52k
{
297
3.52k
    if(fL != mfLeftBound || fR != mfRightBound || fB != mfBottomBound || fT != mfTopBound)
298
3.52k
    {
299
3.52k
        mfLeftBound = fL;
300
3.52k
        mfRightBound = fR;
301
3.52k
        mfBottomBound = fB;
302
3.52k
        mfTopBound = fT;
303
304
3.52k
        mbProjectionValid = false;
305
306
        // Broadcast changes
307
3.52k
        DeviceRectangleChange();
308
3.52k
    }
309
3.52k
}
310
311
void B3dTransformationSet::DeviceRectangleChange()
312
3.52k
{
313
3.52k
}
314
315
void B3dTransformationSet::SetPerspective(bool bNew)
316
7.05k
{
317
7.05k
    if(mbPerspective != bNew)
318
3.18k
    {
319
3.18k
        mbPerspective = bNew;
320
3.18k
        mbProjectionValid = false;
321
3.18k
    }
322
7.05k
}
323
324
void B3dTransformationSet::SetViewportRectangle(tools::Rectangle const & rRect, tools::Rectangle const & rVisible)
325
17.6k
{
326
17.6k
    if(rRect != maViewportRectangle || rVisible != maVisibleRectangle)
327
14.1k
    {
328
14.1k
        maViewportRectangle = rRect;
329
14.1k
        maVisibleRectangle = rVisible;
330
331
14.1k
        mbProjectionValid = false;
332
14.1k
    }
333
17.6k
}
334
335
// direct access to various transformations
336
337
basegfx::B3DPoint B3dTransformationSet::WorldToEyeCoor(const basegfx::B3DPoint& rVec)
338
7.05k
{
339
7.05k
    basegfx::B3DPoint aVec(rVec);
340
7.05k
    aVec *= maOrientation;
341
7.05k
    return aVec;
342
7.05k
}
343
344
basegfx::B3DPoint B3dTransformationSet::EyeToWorldCoor(const basegfx::B3DPoint& rVec)
345
0
{
346
0
    basegfx::B3DPoint aVec(rVec);
347
0
    aVec *= maInvOrientation;
348
0
    return aVec;
349
0
}
350
351
// B3dViewport -----------------------------------------------------------------
352
353
B3dViewport::B3dViewport()
354
3.52k
:   aVRP(0, 0, 0),
355
3.52k
    aVPN(0, 0, 1),
356
3.52k
    aVUV(0, 1, 0)
357
3.52k
{
358
3.52k
    CalcOrientation();
359
3.52k
}
360
361
B3dViewport::~B3dViewport()
362
{
363
}
364
365
void B3dViewport::SetVUV(const basegfx::B3DVector& rNewVUV)
366
0
{
367
0
    aVUV = rNewVUV;
368
0
    CalcOrientation();
369
0
}
370
371
void B3dViewport::SetViewportValues(
372
    const basegfx::B3DPoint& rNewVRP,
373
    const basegfx::B3DVector& rNewVPN,
374
    const basegfx::B3DVector& rNewVUV)
375
14.1k
{
376
14.1k
    aVRP = rNewVRP;
377
14.1k
    aVPN = rNewVPN;
378
14.1k
    aVUV = rNewVUV;
379
14.1k
    CalcOrientation();
380
14.1k
}
381
382
void B3dViewport::CalcOrientation()
383
17.6k
{
384
17.6k
    SetOrientation(aVRP, aVPN, aVUV);
385
17.6k
}
386
387
// B3dCamera -------------------------------------------------------------------
388
389
B3dCamera::B3dCamera(
390
    const basegfx::B3DPoint& rPos, const basegfx::B3DVector& rLkAt,
391
    double fFocLen, double fBnkAng)
392
3.52k
:   aPosition(rPos),
393
3.52k
    aLookAt(rLkAt),
394
3.52k
    fFocalLength(fFocLen),
395
3.52k
    fBankAngle(fBnkAng)
396
3.52k
{
397
3.52k
    CalcNewViewportValues();
398
3.52k
}
399
400
B3dCamera::~B3dCamera()
401
{
402
}
403
404
void B3dCamera::DeviceRectangleChange()
405
3.52k
{
406
    // call parent
407
3.52k
    B3dViewport::DeviceRectangleChange();
408
409
    // react to changes
410
3.52k
    CalcNewViewportValues();
411
3.52k
}
412
413
void B3dCamera::CalcNewViewportValues()
414
7.05k
{
415
7.05k
    basegfx::B3DVector aNewVPN(aPosition - aLookAt);
416
417
7.05k
    basegfx::B3DVector aNewVUV(0.0, 1.0, 0.0);
418
7.05k
    if(aNewVPN.getLength() < aNewVPN.getY())
419
0
        aNewVUV.setX(0.5);
420
421
7.05k
    aNewVUV.normalize();
422
7.05k
    aNewVPN.normalize();
423
424
7.05k
    basegfx::B3DVector aNewToTheRight = aNewVPN.getPerpendicular(aNewVUV);
425
7.05k
    aNewToTheRight.normalize();
426
7.05k
    aNewVUV = aNewToTheRight.getPerpendicular(aNewVPN);
427
7.05k
    aNewVUV.normalize();
428
429
7.05k
    SetViewportValues(aPosition, aNewVPN, aNewVUV);
430
7.05k
    CalcFocalLength();
431
432
7.05k
    if(fBankAngle != 0.0)
433
0
    {
434
0
        basegfx::B3DHomMatrix aRotMat;
435
0
        aRotMat.rotate(0.0, 0.0, fBankAngle);
436
0
        basegfx::B3DVector aUp(0.0, 1.0, 0.0);
437
0
        aUp *= aRotMat;
438
0
        aUp = EyeToWorldCoor(aUp);
439
0
        aUp.normalize();
440
0
        SetVUV(aUp);
441
0
    }
442
7.05k
}
443
444
void B3dCamera::CalcFocalLength()
445
7.05k
{
446
7.05k
    double fWidth = GetDeviceRectangleWidth();
447
448
    // Adjust focal length based on given position
449
7.05k
    basegfx::B3DPoint aOldPosition = WorldToEyeCoor({});
450
7.05k
    if(fWidth != 0.0)
451
7.05k
        fFocalLength = aOldPosition.getZ() / fWidth * 35.0;
452
7.05k
    if(fFocalLength < 5.0)
453
7.05k
        fFocalLength = 5.0;
454
7.05k
}
455
456
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */