/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: */ |