Coverage Report

Created: 2025-12-08 09:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/chart2/source/tools/ThreeDHelper.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/numeric/ftools.hxx>
21
#include <ThreeDHelper.hxx>
22
#include <Diagram.hxx>
23
#include <ChartType.hxx>
24
#include <DataSeries.hxx>
25
#include <defines.hxx>
26
27
#include <com/sun/star/drawing/LineStyle.hpp>
28
#include <comphelper/diagnose_ex.hxx>
29
#include <tools/helpers.hxx>
30
#include <rtl/math.hxx>
31
32
namespace chart
33
{
34
using namespace ::com::sun::star;
35
36
using ::com::sun::star::uno::Reference;
37
using ::rtl::math::cos;
38
using ::rtl::math::sin;
39
using ::rtl::math::tan;
40
41
namespace
42
{
43
44
bool lcl_isRightAngledAxesSetAndSupported( const rtl::Reference< Diagram >& xDiagram )
45
0
{
46
0
    if( xDiagram.is() )
47
0
    {
48
0
        bool bRightAngledAxes = false;
49
0
        xDiagram->getPropertyValue( u"RightAngledAxes"_ustr) >>= bRightAngledAxes;
50
0
        if(bRightAngledAxes)
51
0
        {
52
0
            auto xChartType = xDiagram->getChartTypeByIndex(0);
53
0
            if (xChartType.is() ? xChartType->isSupportingRightAngledAxes() : true)
54
0
            {
55
0
                return true;
56
0
            }
57
0
        }
58
0
    }
59
0
    return false;
60
0
}
61
62
} //end anonymous namespace
63
64
drawing::CameraGeometry ThreeDHelper::getDefaultCameraGeometry( bool bPie )
65
0
{
66
    // ViewReferencePoint (Point on the View plane)
67
0
    drawing::Position3D vrp(17634.6218373783, 10271.4823817647, 24594.8639082739);
68
    // ViewPlaneNormal (Normal to the View Plane)
69
0
    drawing::Direction3D vpn(0.416199821709347, 0.173649045905254, 0.892537795986984);
70
    // ViewUpVector (determines the v-axis direction on the view plane as
71
    // projection of VUP parallel to VPN onto th view pane)
72
0
    drawing::Direction3D vup(-0.0733876362771618, 0.984807599917971, -0.157379306090273);
73
74
0
    if( bPie )
75
0
    {
76
0
        vrp = drawing::Position3D( 0.0, 0.0, 87591.2408759124 );//--> 5 percent perspective
77
0
        vpn = drawing::Direction3D( 0.0, 0.0, 1.0 );
78
0
        vup = drawing::Direction3D( 0.0, 1.0, 0.0 );
79
0
    }
80
81
0
    return drawing::CameraGeometry( vrp, vpn, vup );
82
0
}
83
84
namespace
85
{
86
void lcl_ensureIntervalMinus1To1( double& rSinOrCos )
87
0
{
88
0
    if (rSinOrCos < -1.0)
89
0
       rSinOrCos = -1.0;
90
0
    else if (rSinOrCos > 1.0)
91
0
        rSinOrCos = 1.0;
92
0
}
93
94
bool lcl_isSinZero( double fAngleRad )
95
0
{
96
0
    return ::basegfx::fTools::equalZero( sin(fAngleRad), 0.0000001 );
97
0
}
98
bool lcl_isCosZero( double fAngleRad )
99
0
{
100
0
    return ::basegfx::fTools::equalZero( cos(fAngleRad), 0.0000001 );
101
0
}
102
103
}
104
105
void ThreeDHelper::convertElevationRotationDegToXYZAngleRad(
106
    sal_Int32 nElevationDeg, sal_Int32 nRotationDeg,
107
    double& rfXAngleRad, double& rfYAngleRad, double& rfZAngleRad)
108
0
{
109
    // for a description of the algorithm see issue 72994
110
    //https://bz.apache.org/ooo/show_bug.cgi?id=72994
111
    //https://bz.apache.org/ooo/attachment.cgi?id=50608
112
113
0
    nElevationDeg = NormAngle360(nElevationDeg);
114
0
    nRotationDeg = NormAngle360(nRotationDeg);
115
116
0
    double& x = rfXAngleRad;
117
0
    double& y = rfYAngleRad;
118
0
    double& z = rfZAngleRad;
119
120
0
    double E = basegfx::deg2rad(nElevationDeg); //elevation in Rad
121
0
    double R = basegfx::deg2rad(nRotationDeg); //rotation in Rad
122
123
0
    if( (nRotationDeg == 0 || nRotationDeg == 180 )
124
0
        && ( nElevationDeg == 90 || nElevationDeg == 270 ) )
125
0
    {
126
        //sR==0 && cE==0
127
0
        z = 0.0;
128
        //element 23
129
0
        double f23 = cos(R)*sin(E);
130
0
        if(f23>0)
131
0
            x = M_PI_2;
132
0
        else
133
0
            x = -M_PI_2;
134
0
        y = R;
135
0
    }
136
0
    else if( ( nRotationDeg == 90 || nRotationDeg == 270 )
137
0
        && ( nElevationDeg == 90 || nElevationDeg == 270 ) )
138
0
    {
139
        //cR==0 && cE==0
140
0
        z = M_PI_2;
141
0
        if( sin(R)>0 )
142
0
            x = M_PI_2;
143
0
        else
144
0
            x = -M_PI_2;
145
146
0
        if( (sin(R)*sin(E))>0 )
147
0
            y = 0.0;
148
0
        else
149
0
            y = M_PI;
150
0
    }
151
0
    else if( (nRotationDeg == 0 || nRotationDeg == 180 )
152
0
        && ( nElevationDeg == 0 || nElevationDeg == 180 ) )
153
0
    {
154
        //sR==0 && sE==0
155
0
        z = 0.0;
156
0
        y = R;
157
0
        x = E;
158
0
    }
159
0
    else if( ( nRotationDeg == 90 || nRotationDeg == 270 )
160
0
        && ( nElevationDeg == 0 || nElevationDeg == 180 ) )
161
0
    {
162
        //cR==0 && sE==0
163
0
        z = 0.0;
164
165
0
        if( (sin(R)/cos(E))>0 )
166
0
            y = M_PI_2;
167
0
        else
168
0
            y = -M_PI_2;
169
170
0
        if( (cos(E))>0 )
171
0
            x = 0;
172
0
        else
173
0
            x = M_PI;
174
0
    }
175
0
    else if ( nElevationDeg == 0 || nElevationDeg == 180 )
176
0
    {
177
        //sR!=0 cR!=0 sE==0
178
0
        z = 0.0;
179
0
        x = E;
180
0
        y = R;
181
        //use element 13 for sign
182
0
        if((cos(x)*sin(y)*sin(R))<0.0)
183
0
            y *= -1.0;
184
0
    }
185
0
    else if ( nElevationDeg == 90 || nElevationDeg == 270 )
186
0
    {
187
        //sR!=0 cR!=0 cE==0
188
        //element 12 + 22 --> y=0 or M_PI and x=+-M_PI/2
189
        //-->element 13/23:
190
0
        z = atan(sin(R)/(cos(R)*sin(E)));
191
        //use element 13 for sign for x
192
0
        if( (sin(R)*sin(z))>0.0 )
193
0
            x = M_PI_2;
194
0
        else
195
0
            x = -M_PI_2;
196
        //use element 21 for y
197
0
        if( (sin(R)*sin(E)*sin(z))>0.0)
198
0
            y = 0.0;
199
0
        else
200
0
            y = M_PI;
201
0
    }
202
0
    else if ( nRotationDeg == 0 || nRotationDeg == 180 )
203
0
    {
204
        //sE!=0 cE!=0 sR==0
205
0
        z = 0.0;
206
0
        x = E;
207
0
        y = R;
208
0
        double f23 = cos(R)*sin(E);
209
0
        if( (f23 * sin(x)) < 0.0 )
210
0
            x *= -1.0; //todo ??
211
0
    }
212
0
    else if (nRotationDeg == 90 || nRotationDeg == 270)
213
0
    {
214
        //sE!=0 cE!=0 cR==0
215
        //z = +- M_PI/2;
216
        //x = +- M_PI/2;
217
0
        z = M_PI_2;
218
0
        x = M_PI_2;
219
0
        double sR = sin(R);
220
0
        if( sR<0.0 )
221
0
            x *= -1.0; //different signs for x and z
222
223
        //use element 21:
224
0
        double cy = sR*sin(E)/sin(z);
225
0
        lcl_ensureIntervalMinus1To1(cy);
226
0
        y = acos(cy);
227
228
        //use element 22 for sign:
229
0
        if( (sin(x)*sin(y)*sin(z)*cos(E))<0.0)
230
0
            y *= -1.0;
231
0
    }
232
0
    else
233
0
    {
234
0
        z = atan(tan(R) * sin(E));
235
0
        if(cos(z)==0.0)
236
0
        {
237
0
            OSL_FAIL("calculation error in ThreeDHelper::convertElevationRotationDegToXYZAngleRad");
238
0
            return;
239
0
        }
240
0
        double cy = cos(R)/cos(z);
241
0
        lcl_ensureIntervalMinus1To1(cy);
242
0
        y = acos(cy);
243
244
        //element 12 in 23
245
0
        double fDenominator = cos(z)*(1.0-pow(sin(y),2));
246
0
        if(fDenominator==0.0)
247
0
        {
248
0
            OSL_FAIL("calculation error in ThreeDHelper::convertElevationRotationDegToXYZAngleRad");
249
0
            return;
250
0
        }
251
0
        double sx = cos(R)*sin(E)/fDenominator;
252
0
        lcl_ensureIntervalMinus1To1(sx);
253
0
        x = asin( sx );
254
255
        //use element 13 for sign:
256
0
        double f13a = cos(x)*cos(z)*sin(y);
257
0
        double f13b = sin(R)-sx*sin(z);
258
0
        if( (f13b*f13a)<0.0 )
259
0
        {
260
            //change x or y
261
            //use element 22 for further investigations:
262
            //try
263
0
            y *= -1;
264
0
            double f22a = cos(x)*cos(z);
265
0
            double f22b = cos(E)-(sx*sin(y)*sin(z));
266
0
            if( (f22a*f22b)<0.0 )
267
0
            {
268
0
                y *= -1;
269
0
                x=(M_PI-x);
270
0
            }
271
0
        }
272
0
        else
273
0
        {
274
            //change nothing or both
275
            //use element 22 for further investigations:
276
0
            double f22a = cos(x)*cos(z);
277
0
            double f22b = cos(E)-(sx*sin(y)*sin(z));
278
0
            if( (f22a*f22b)<0.0 )
279
0
            {
280
0
                y *= -1;
281
0
                x=(M_PI-x);
282
0
            }
283
0
        }
284
0
    }
285
0
}
286
287
void ThreeDHelper::convertXYZAngleRadToElevationRotationDeg(
288
    sal_Int32& rnElevationDeg, sal_Int32& rnRotationDeg,
289
    double fXRad, double fYRad, double fZRad)
290
0
{
291
    // for a description of the algorithm see issue 72994
292
    //https://bz.apache.org/ooo/show_bug.cgi?id=72994
293
    //https://bz.apache.org/ooo/attachment.cgi?id=50608
294
295
0
    double R = 0.0; //Rotation in Rad
296
0
    double E = 0.0; //Elevation in Rad
297
298
0
    double& x = fXRad;
299
0
    double& y = fYRad;
300
0
    double& z = fZRad;
301
302
0
    double f11 = cos(y)*cos(z);
303
304
0
    if( lcl_isSinZero(y) )
305
0
    {
306
        //siny == 0
307
308
0
        if( lcl_isCosZero(x) )
309
0
        {
310
            //siny == 0 && cosx == 0
311
312
0
            if( lcl_isSinZero(z) )
313
0
            {
314
                //siny == 0 && cosx == 0 && sinz == 0
315
                //example: x=+-90 y=0oder180 z=0(oder180)
316
317
                //element 13+11
318
0
                if( f11 > 0 )
319
0
                    R = 0.0;
320
0
                else
321
0
                    R = M_PI;
322
323
                //element 23
324
0
                double f23 = cos(z)*sin(x) / cos(R);
325
0
                if( f23 > 0 )
326
0
                    E = M_PI_2;
327
0
                else
328
0
                    E = -M_PI_2;
329
0
            }
330
0
            else if( lcl_isCosZero(z) )
331
0
            {
332
                //siny == 0 && cosx == 0 && cosz == 0
333
                //example: x=+-90 y=0oder180 z=+-90
334
335
0
                double f13 = sin(x)*sin(z);
336
                //element 13+11
337
0
                if( f13 > 0 )
338
0
                    R = M_PI_2;
339
0
                else
340
0
                    R = -M_PI_2;
341
342
                //element 21
343
0
                double f21 = cos(y)*sin(z) / sin(R);
344
0
                if( f21 > 0 )
345
0
                    E = M_PI_2;
346
0
                else
347
0
                    E = -M_PI_2;
348
0
            }
349
0
            else
350
0
            {
351
                //siny == 0 && cosx == 0 && cosz != 0 && sinz != 0
352
                //element 11 && 13
353
0
                double f13 = sin(x)*sin(z);
354
0
                R = atan( f13/f11 );
355
356
0
                if(f11<0)
357
0
                    R+=M_PI;
358
359
                //element 23
360
0
                double f23 = cos(z)*sin(x);
361
0
                if( f23/cos(R) > 0 )
362
0
                    E = M_PI_2;
363
0
                else
364
0
                    E = -M_PI_2;
365
0
            }
366
0
        }
367
0
        else if( lcl_isSinZero(x) )
368
0
        {
369
            //sinY==0 sinX==0
370
            //element 13+11
371
0
            if( f11 > 0 )
372
0
                R = 0.0;
373
0
            else
374
0
                R = M_PI;
375
376
0
            double f22 = cos(x)*cos(z);
377
0
            if( f22 > 0 )
378
0
                E = 0.0;
379
0
            else
380
0
                E = M_PI;
381
0
        }
382
0
        else if( lcl_isSinZero(z) )
383
0
        {
384
            //sinY==0 sinZ==0 sinx!=0 cosx!=0
385
            //element 13+11
386
0
            if( f11 > 0 )
387
0
                R = 0.0;
388
0
            else
389
0
                R = M_PI;
390
391
            //element 22 && 23
392
0
            double f22 = cos(x)*cos(z);
393
0
            double f23 = cos(z)*sin(x);
394
0
            E = atan( f23/(f22*cos(R)) );
395
0
            if( (f22*cos(E))<0 )
396
0
                E+=M_PI;
397
0
        }
398
0
        else if( lcl_isCosZero(z) )
399
0
        {
400
            //sinY == 0 && cosZ == 0 && cosx != 0 && sinx != 0
401
0
            double f13 = sin(x)*sin(z);
402
            //element 13+11
403
0
            if( f13 > 0 )
404
0
                R = M_PI_2;
405
0
            else
406
0
                R = -M_PI_2;
407
408
            //element 21+22
409
0
            double f21 = cos(y)*sin(z);
410
0
            if( f21/sin(R) > 0 )
411
0
                E = M_PI_2;
412
0
            else
413
0
                E = -M_PI_2;
414
0
        }
415
0
        else
416
0
        {
417
            //sinY == 0 && all other !=0
418
0
            double f13 = sin(x)*sin(z);
419
0
            R = atan( f13/f11 );
420
0
            if( (f11*cos(R))<0.0 )
421
0
                R+=M_PI;
422
423
0
            double f22 = cos(x)*cos(z);
424
0
            if( !lcl_isCosZero(R) )
425
0
                E = atan( cos(z)*sin(x) /( f22*cos(R) ) );
426
0
            else
427
0
                E = atan( cos(y)*sin(z) /( f22*sin(R) ) );
428
0
            if( (f22*cos(E))<0 )
429
0
                E+=M_PI;
430
0
        }
431
0
    }
432
0
    else if( lcl_isCosZero(y) )
433
0
    {
434
        //cosY==0
435
436
0
        double f13 = sin(x)*sin(z)+cos(x)*cos(z)*sin(y);
437
0
        if( f13 >= 0 )
438
0
            R = M_PI_2;
439
0
        else
440
0
            R = -M_PI_2;
441
442
0
        double f22 = cos(x)*cos(z)+sin(x)*sin(y)*sin(z);
443
0
        if( f22 >= 0 )
444
0
            E = 0.0;
445
0
        else
446
0
            E = M_PI;
447
0
    }
448
0
    else if( lcl_isSinZero(x) )
449
0
    {
450
        //cosY!=0 sinY!=0 sinX=0
451
0
        if( lcl_isSinZero(z) )
452
0
        {
453
            //cosY!=0 sinY!=0 sinX=0 sinZ=0
454
0
            double f13 = cos(x)*cos(z)*sin(y);
455
0
            R = atan( f13/f11 );
456
            //R = asin(f13);
457
0
            if( f11<0 )
458
0
                R+=M_PI;
459
460
0
            double f22 = cos(x)*cos(z);
461
0
            if( f22>0 )
462
0
                E = 0.0;
463
0
            else
464
0
                E = M_PI;
465
0
        }
466
0
        else if( lcl_isCosZero(z) )
467
0
        {
468
            //cosY!=0 sinY!=0 sinX=0 cosZ=0
469
0
            R = x;
470
0
            E = y;//or -y
471
            //use 23 for 'signs'
472
0
            double f23 =  -1.0*cos(x)*sin(y)*sin(z);
473
0
            if( (f23*cos(R)*sin(E))<0.0 )
474
0
            {
475
                //change R or E
476
0
                E = -y;
477
0
            }
478
0
        }
479
0
        else
480
0
        {
481
            //cosY!=0 sinY!=0 sinX=0 sinZ!=0 cosZ!=0
482
0
            double f13 = cos(x)*cos(z)*sin(y);
483
0
            R = atan( f13/f11 );
484
485
0
            if( f11<0 )
486
0
                R+=M_PI;
487
488
0
            double f21 = cos(y)*sin(z);
489
0
            double f22 = cos(x)*cos(z);
490
0
            E = atan(f21/(f22*sin(R)) );
491
492
0
            if( (f22*cos(E))<0.0 )
493
0
                E+=M_PI;
494
0
        }
495
0
    }
496
0
    else if( lcl_isCosZero(x) )
497
0
    {
498
        //cosY!=0 sinY!=0 cosX=0
499
500
0
        if( lcl_isSinZero(z) )
501
0
        {
502
            //cosY!=0 sinY!=0 cosX=0 sinZ=0
503
0
            R=0;//13 -> R=0 or M_PI
504
0
            if( f11<0.0 )
505
0
                R=M_PI;
506
0
            E=M_PI_2;//22 -> E=+-M_PI/2
507
            //use element 11 and 23 for sign
508
0
            double f23 = cos(z)*sin(x);
509
0
            if( (f11*f23*sin(E))<0.0 )
510
0
                E=-M_PI_2;
511
0
        }
512
0
        else if( lcl_isCosZero(z) )
513
0
        {
514
            //cosY!=0 sinY!=0 cosX=0 cosZ=0
515
            //element 11 & 13:
516
0
            if( (sin(x)*sin(z))>0.0 )
517
0
                R=M_PI_2;
518
0
            else
519
0
                R=-M_PI_2;
520
            //element 22:
521
0
            E=acos( sin(x)*sin(y)*sin(z));
522
            //use element 21 for sign:
523
0
            if( (cos(y)*sin(z)*sin(R)*sin(E))<0.0 )
524
0
                E*=-1.0;
525
0
        }
526
0
        else
527
0
        {
528
            //cosY!=0 sinY!=0 cosX=0 sinZ!=0 cosZ!=0
529
            //element 13/11
530
0
            R = atan( sin(x)*sin(z)/(cos(y)*cos(z)) );
531
            //use 13 for 'sign'
532
0
            if( (sin(x)*sin(z))<0.0 )
533
0
                R += M_PI;
534
            //element 22
535
0
            E = acos(sin(x)*sin(y)*sin(z) );
536
            //use 21 for sign
537
0
            if( (cos(y)*sin(z)*sin(R)*sin(E))<0.0 )
538
0
                E*=-1.0;
539
0
        }
540
0
    }
541
0
    else if( lcl_isSinZero(z) )
542
0
    {
543
        //cosY!=0 sinY!=0 sinX!=0 cosX!=0 sinZ=0
544
        //element 11
545
0
        R=y;
546
        //use element 13 for sign
547
0
        if( (cos(x)*cos(z)*sin(y)*sin(R))<0.0 )
548
0
            R*=-1.0;
549
        //element 22
550
0
        E = acos( cos(x)*cos(z) );
551
        //use element 23 for sign
552
0
        if( (cos(z)*sin(x)*cos(R)*sin(E))<0.0 )
553
0
            E*=-1.0;
554
0
    }
555
0
    else if( lcl_isCosZero(z) )
556
0
    {
557
        //cosY!=0 sinY!=0 sinX!=0 cosX!=0 cosZ=0
558
        //element 21/23
559
0
        R=atan(-cos(y)/(cos(x)*sin(y)));
560
        //use element 13 for 'sign'
561
0
        if( (sin(x)*sin(z)*sin(R))<0.0 )
562
0
            R+=M_PI;
563
        //element 21/22
564
0
        E=atan( cos(y)*sin(z)/(sin(R)*sin(x)*sin(y)*sin(z)) );
565
        //use element 23 for 'sign'
566
0
        if( (-cos(x)*sin(y)*sin(z)*cos(R)*sin(E))<0.0 )
567
0
            E+=M_PI;
568
0
    }
569
0
    else
570
0
    {
571
        //cosY!=0 sinY!=0 sinX!=0 cosX!=0 sinZ!=0 cosZ!=0
572
        //13/11:
573
0
        double f13 = sin(x)*sin(z)+cos(x)*cos(z)*sin(y);
574
0
        R = atan( f13/ f11 );
575
0
        if(f11<0.0)
576
0
            R+=M_PI;
577
0
        double f22 = cos(x)*cos(z)+sin(x)*sin(y)*sin(z);
578
0
        double f23 = cos(x)*sin(y)*sin(z)-cos(z)*sin(x);
579
        //23/22:
580
0
        E = atan( -1.0*f23/(f22*cos(R)) );
581
0
        if(f22<0.0)
582
0
            E+=M_PI;
583
0
    }
584
585
0
    rnElevationDeg = basegfx::fround(basegfx::rad2deg(E));
586
0
    rnRotationDeg = basegfx::fround(basegfx::rad2deg(R));
587
0
}
588
589
double ThreeDHelper::getValueClippedToRange( double fAngle, const double& fPositivLimit )
590
0
{
591
0
    if( fAngle<-1*fPositivLimit )
592
0
        fAngle=-1*fPositivLimit;
593
0
    else if( fAngle>fPositivLimit )
594
0
        fAngle=fPositivLimit;
595
0
    return fAngle;
596
0
}
597
598
void ThreeDHelper::adaptRadAnglesForRightAngledAxes( double& rfXAngleRad, double& rfYAngleRad )
599
0
{
600
0
    rfXAngleRad = ThreeDHelper::getValueClippedToRange(rfXAngleRad, basegfx::deg2rad(ThreeDHelper::getXDegreeAngleLimitForRightAngledAxes()) );
601
0
    rfYAngleRad = ThreeDHelper::getValueClippedToRange(rfYAngleRad, basegfx::deg2rad(ThreeDHelper::getYDegreeAngleLimitForRightAngledAxes()) );
602
0
}
603
604
605
void ThreeDHelper::getCameraDistanceRange( double& rfMinimumDistance, double& rfMaximumDistance )
606
0
{
607
0
    rfMinimumDistance = 3.0/4.0*FIXED_SIZE_FOR_3D_CHART_VOLUME;//empiric value
608
0
    rfMaximumDistance = 20.0*FIXED_SIZE_FOR_3D_CHART_VOLUME;//empiric value
609
0
}
610
611
void ThreeDHelper::ensureCameraDistanceRange( double& rfCameraDistance )
612
0
{
613
0
    double fMin, fMax;
614
0
    getCameraDistanceRange( fMin, fMax );
615
0
    if( rfCameraDistance < fMin )
616
0
        rfCameraDistance = fMin;
617
0
    if( rfCameraDistance > fMax )
618
0
        rfCameraDistance = fMax;
619
0
}
620
621
double ThreeDHelper::CameraDistanceToPerspective( double fCameraDistance )
622
0
{
623
0
    double fMin, fMax;
624
0
    ThreeDHelper::getCameraDistanceRange( fMin, fMax );
625
    //fMax <-> 0; fMin <->100
626
    //a/x + b = y
627
0
    double a = 100.0*fMax*fMin/(fMax-fMin);
628
0
    double b = -a/fMax;
629
630
0
    double fRet = a/fCameraDistance + b;
631
632
0
    return fRet;
633
0
}
634
635
double ThreeDHelper::PerspectiveToCameraDistance( double fPerspective )
636
0
{
637
0
    double fMin, fMax;
638
0
    ThreeDHelper::getCameraDistanceRange( fMin, fMax );
639
    //fMax <-> 0; fMin <->100
640
    //a/x + b = y
641
0
    double a = 100.0*fMax*fMin/(fMax-fMin);
642
0
    double b = -a/fMax;
643
644
0
    double fRet = a/(fPerspective - b);
645
646
0
    return fRet;
647
0
}
648
649
void ThreeDHelper::getRoundedEdgesAndObjectLines(
650
            const rtl::Reference< Diagram > & xDiagram
651
            , sal_Int32& rnRoundedEdges, sal_Int32& rnObjectLines )
652
0
{
653
0
    rnRoundedEdges = -1;
654
0
    rnObjectLines = -1;
655
0
    try
656
0
    {
657
0
        bool bDifferentRoundedEdges = false;
658
0
        bool bDifferentObjectLines = false;
659
660
0
        drawing::LineStyle aLineStyle( drawing::LineStyle_SOLID );
661
662
0
        std::vector< rtl::Reference< DataSeries > > aSeriesList =
663
0
            xDiagram->getDataSeries();
664
0
        sal_Int32 nSeriesCount = static_cast<sal_Int32>( aSeriesList.size() );
665
666
0
        OUString aPercentDiagonalPropertyName( u"PercentDiagonal"_ustr );
667
0
        OUString aBorderStylePropertyName( u"BorderStyle"_ustr );
668
669
0
        for( sal_Int32 nS = 0; nS < nSeriesCount; ++nS )
670
0
        {
671
0
            const rtl::Reference< DataSeries >& xSeries( aSeriesList[nS] );
672
0
            if(!nS)
673
0
            {
674
0
                rnRoundedEdges = 0;
675
0
                try
676
0
                {
677
0
                    sal_Int16 nPercentDiagonal = 0;
678
679
0
                    xSeries->getPropertyValue( aPercentDiagonalPropertyName ) >>= nPercentDiagonal;
680
0
                    rnRoundedEdges = static_cast< sal_Int32 >( nPercentDiagonal );
681
682
0
                    if( xSeries->hasAttributedDataPointDifferentValue(
683
0
                            aPercentDiagonalPropertyName, uno::Any(nPercentDiagonal) ) )
684
0
                        bDifferentRoundedEdges = true;
685
0
                }
686
0
                catch( const uno::Exception& )
687
0
                {
688
0
                    TOOLS_WARN_EXCEPTION("chart2", "" );
689
0
                    bDifferentRoundedEdges = true;
690
0
                }
691
0
                try
692
0
                {
693
0
                    xSeries->getPropertyValue( aBorderStylePropertyName ) >>= aLineStyle;
694
695
0
                    if( xSeries->hasAttributedDataPointDifferentValue(
696
0
                            aBorderStylePropertyName, uno::Any(aLineStyle) ) )
697
0
                        bDifferentObjectLines = true;
698
0
                }
699
0
                catch( const uno::Exception& )
700
0
                {
701
0
                    TOOLS_WARN_EXCEPTION("chart2", "" );
702
0
                    bDifferentObjectLines = true;
703
0
                }
704
0
            }
705
0
            else
706
0
            {
707
0
                if( !bDifferentRoundedEdges )
708
0
                {
709
0
                    sal_Int16 nPercentDiagonal = 0;
710
0
                    xSeries->getPropertyValue( aPercentDiagonalPropertyName ) >>= nPercentDiagonal;
711
0
                    sal_Int32 nCurrentRoundedEdges = static_cast< sal_Int32 >( nPercentDiagonal );
712
0
                    if(nCurrentRoundedEdges!=rnRoundedEdges
713
0
                        || xSeries->hasAttributedDataPointDifferentValue(
714
0
                                aPercentDiagonalPropertyName, uno::Any( static_cast< sal_Int16 >(rnRoundedEdges) ) ) )
715
0
                    {
716
0
                        bDifferentRoundedEdges = true;
717
0
                    }
718
0
                }
719
720
0
                if( !bDifferentObjectLines )
721
0
                {
722
0
                    drawing::LineStyle aCurrentLineStyle;
723
0
                    xSeries->getPropertyValue( aBorderStylePropertyName ) >>= aCurrentLineStyle;
724
0
                    if(aCurrentLineStyle!=aLineStyle
725
0
                        || xSeries->hasAttributedDataPointDifferentValue(
726
0
                              aBorderStylePropertyName, uno::Any(aLineStyle) ) )
727
0
                        bDifferentObjectLines = true;
728
0
                }
729
0
            }
730
0
            if( bDifferentRoundedEdges && bDifferentObjectLines )
731
0
                break;
732
0
        }
733
734
        //set rnObjectLines
735
0
        rnObjectLines = 0;
736
0
        if( bDifferentObjectLines )
737
0
            rnObjectLines = -1;
738
0
        else if( aLineStyle == drawing::LineStyle_SOLID )
739
0
            rnObjectLines = 1;
740
0
    }
741
0
    catch( const uno::Exception& )
742
0
    {
743
0
        TOOLS_WARN_EXCEPTION("chart2", "" );
744
0
    }
745
0
}
746
747
void ThreeDHelper::setRoundedEdgesAndObjectLines(
748
            const rtl::Reference< Diagram > & xDiagram
749
            , sal_Int32 nRoundedEdges, sal_Int32 nObjectLines )
750
0
{
751
0
    if( (nRoundedEdges<0||nRoundedEdges>100) && nObjectLines!=0 && nObjectLines!=1 )
752
0
        return;
753
754
0
    drawing::LineStyle aLineStyle( drawing::LineStyle_NONE );
755
0
    if(nObjectLines==1)
756
0
        aLineStyle = drawing::LineStyle_SOLID;
757
758
0
    uno::Any aALineStyle( aLineStyle);
759
0
    uno::Any aARoundedEdges( static_cast< sal_Int16 >( nRoundedEdges ));
760
761
0
    std::vector< rtl::Reference< DataSeries > > aSeriesList =
762
0
        xDiagram->getDataSeries();
763
0
    for( auto const&  xSeries : aSeriesList)
764
0
    {
765
0
        if( nRoundedEdges>=0 && nRoundedEdges<=100 )
766
0
            xSeries->setPropertyAlsoToAllAttributedDataPoints( u"PercentDiagonal"_ustr, aARoundedEdges );
767
768
0
        if( nObjectLines==0 || nObjectLines==1 )
769
0
            xSeries->setPropertyAlsoToAllAttributedDataPoints( u"BorderStyle"_ustr, aALineStyle );
770
0
    }
771
0
}
772
773
CuboidPlanePosition ThreeDHelper::getAutomaticCuboidPlanePositionForStandardLeftWall( const rtl::Reference< ::chart::Diagram >& xDiagram )
774
0
{
775
0
    CuboidPlanePosition eRet(CuboidPlanePosition_Left);
776
777
0
    double fXAngleRad=0.0; double fYAngleRad=0.0; double fZAngleRad=0.0;
778
0
    xDiagram->getRotationAngle( fXAngleRad, fYAngleRad, fZAngleRad );
779
0
    if( lcl_isRightAngledAxesSetAndSupported( xDiagram ) )
780
0
    {
781
0
        ThreeDHelper::adaptRadAnglesForRightAngledAxes( fXAngleRad, fYAngleRad );
782
0
    }
783
0
    if( sin(fYAngleRad)>0.0 )
784
0
        eRet = CuboidPlanePosition_Right;
785
0
    return eRet;
786
0
}
787
788
CuboidPlanePosition ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBackWall( const rtl::Reference< Diagram >& xDiagram )
789
0
{
790
0
    CuboidPlanePosition eRet(CuboidPlanePosition_Back);
791
792
0
    double fXAngleRad=0.0; double fYAngleRad=0.0; double fZAngleRad=0.0;
793
0
    xDiagram->getRotationAngle( fXAngleRad, fYAngleRad, fZAngleRad );
794
0
    if( lcl_isRightAngledAxesSetAndSupported( xDiagram ) )
795
0
    {
796
0
        ThreeDHelper::adaptRadAnglesForRightAngledAxes( fXAngleRad, fYAngleRad );
797
0
    }
798
0
    if( cos(fXAngleRad)*cos(fYAngleRad)<0.0 )
799
0
        eRet = CuboidPlanePosition_Front;
800
0
    return eRet;
801
0
}
802
803
CuboidPlanePosition ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBottom( const rtl::Reference< Diagram >& xDiagram )
804
0
{
805
0
    CuboidPlanePosition eRet(CuboidPlanePosition_Bottom);
806
807
0
    double fXAngleRad=0.0; double fYAngleRad=0.0; double fZAngleRad=0.0;
808
0
    xDiagram->getRotationAngle( fXAngleRad, fYAngleRad, fZAngleRad );
809
0
    if( lcl_isRightAngledAxesSetAndSupported( xDiagram ) )
810
0
    {
811
0
        ThreeDHelper::adaptRadAnglesForRightAngledAxes( fXAngleRad, fYAngleRad );
812
0
    }
813
0
    if( sin(fXAngleRad)*cos(fYAngleRad)<0.0 )
814
0
        eRet = CuboidPlanePosition_Top;
815
0
    return eRet;
816
0
}
817
818
} //namespace chart
819
820
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */