Line data Source code
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 "ThreeDHelper.hxx"
21 : #include "macros.hxx"
22 : #include "DiagramHelper.hxx"
23 : #include "ChartTypeHelper.hxx"
24 : #include "BaseGFXHelper.hxx"
25 : #include "DataSeriesHelper.hxx"
26 : #include "defines.hxx"
27 :
28 : #include <editeng/unoprnms.hxx>
29 : #include <com/sun/star/beans/XPropertyState.hpp>
30 : #include <com/sun/star/chart2/XDiagram.hpp>
31 : #include <com/sun/star/drawing/LineStyle.hpp>
32 :
33 : namespace chart
34 : {
35 : using namespace ::com::sun::star;
36 : using namespace ::com::sun::star::chart2;
37 :
38 : using ::com::sun::star::uno::Reference;
39 : using ::com::sun::star::uno::Sequence;
40 : using ::rtl::math::cos;
41 : using ::rtl::math::sin;
42 : using ::rtl::math::tan;
43 :
44 : namespace
45 : {
46 :
47 554 : bool lcl_isRightAngledAxesSetAndSupported( const Reference< beans::XPropertySet >& xSceneProperties )
48 : {
49 554 : bool bRightAngledAxes = false;
50 554 : if( xSceneProperties.is() )
51 : {
52 554 : xSceneProperties->getPropertyValue( "RightAngledAxes") >>= bRightAngledAxes;
53 554 : if(bRightAngledAxes)
54 : {
55 372 : uno::Reference< chart2::XDiagram > xDiagram( xSceneProperties, uno::UNO_QUERY );
56 744 : if( ChartTypeHelper::isSupportingRightAngledAxes(
57 744 : DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ) )
58 : {
59 372 : return true;
60 0 : }
61 : }
62 : }
63 182 : return false;
64 : }
65 :
66 192 : void lcl_RotateLightSource( const Reference< beans::XPropertySet >& xSceneProperties
67 : , const OUString& rLightSourceDirection
68 : , const OUString& rLightSourceOn
69 : , const ::basegfx::B3DHomMatrix& rRotationMatrix )
70 : {
71 192 : if( xSceneProperties.is() )
72 : {
73 192 : bool bLightOn = false;
74 192 : if( xSceneProperties->getPropertyValue( rLightSourceOn ) >>= bLightOn )
75 : {
76 192 : if( bLightOn )
77 : {
78 24 : drawing::Direction3D aLight;
79 24 : if( xSceneProperties->getPropertyValue( rLightSourceDirection ) >>= aLight )
80 : {
81 24 : ::basegfx::B3DVector aLightVector( BaseGFXHelper::Direction3DToB3DVector( aLight ) );
82 24 : aLightVector = rRotationMatrix*aLightVector;
83 :
84 24 : xSceneProperties->setPropertyValue( rLightSourceDirection
85 24 : , uno::makeAny( BaseGFXHelper::B3DVectorToDirection3D( aLightVector ) ) );
86 : }
87 : }
88 : }
89 : }
90 192 : }
91 :
92 24 : void lcl_rotateLights( const ::basegfx::B3DHomMatrix& rLightRottion, const Reference< beans::XPropertySet >& xSceneProperties )
93 : {
94 24 : if(!xSceneProperties.is())
95 24 : return;
96 :
97 24 : ::basegfx::B3DHomMatrix aLightRottion( rLightRottion );
98 24 : BaseGFXHelper::ReduceToRotationMatrix( aLightRottion );
99 :
100 24 : lcl_RotateLightSource( xSceneProperties, "D3DSceneLightDirection1", "D3DSceneLightOn1", aLightRottion );
101 24 : lcl_RotateLightSource( xSceneProperties, "D3DSceneLightDirection2", "D3DSceneLightOn2", aLightRottion );
102 24 : lcl_RotateLightSource( xSceneProperties, "D3DSceneLightDirection3", "D3DSceneLightOn3", aLightRottion );
103 24 : lcl_RotateLightSource( xSceneProperties, "D3DSceneLightDirection4", "D3DSceneLightOn4", aLightRottion );
104 24 : lcl_RotateLightSource( xSceneProperties, "D3DSceneLightDirection5", "D3DSceneLightOn5", aLightRottion );
105 24 : lcl_RotateLightSource( xSceneProperties, "D3DSceneLightDirection6", "D3DSceneLightOn6", aLightRottion );
106 24 : lcl_RotateLightSource( xSceneProperties, "D3DSceneLightDirection7", "D3DSceneLightOn7", aLightRottion );
107 24 : lcl_RotateLightSource( xSceneProperties, "D3DSceneLightDirection8", "D3DSceneLightOn8", aLightRottion );
108 : }
109 :
110 140 : ::basegfx::B3DHomMatrix lcl_getInverseRotationMatrix( const Reference< beans::XPropertySet >& xSceneProperties )
111 : {
112 140 : ::basegfx::B3DHomMatrix aInverseRotation;
113 140 : double fXAngleRad=0.0;
114 140 : double fYAngleRad=0.0;
115 140 : double fZAngleRad=0.0;
116 : ThreeDHelper::getRotationAngleFromDiagram(
117 140 : xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad );
118 140 : aInverseRotation.rotate( 0.0, 0.0, -fZAngleRad );
119 140 : aInverseRotation.rotate( 0.0, -fYAngleRad, 0.0 );
120 140 : aInverseRotation.rotate( -fXAngleRad, 0.0, 0.0 );
121 140 : return aInverseRotation;
122 : }
123 :
124 0 : ::basegfx::B3DHomMatrix lcl_getCompleteRotationMatrix( const Reference< beans::XPropertySet >& xSceneProperties )
125 : {
126 0 : ::basegfx::B3DHomMatrix aCompleteRotation;
127 0 : double fXAngleRad=0.0;
128 0 : double fYAngleRad=0.0;
129 0 : double fZAngleRad=0.0;
130 : ThreeDHelper::getRotationAngleFromDiagram(
131 0 : xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad );
132 0 : aCompleteRotation.rotate( fXAngleRad, fYAngleRad, fZAngleRad );
133 0 : return aCompleteRotation;
134 : }
135 :
136 6 : bool lcl_isEqual( const drawing::Direction3D& rA, const drawing::Direction3D& rB )
137 : {
138 6 : return ::rtl::math::approxEqual(rA.DirectionX, rB.DirectionX)
139 6 : && ::rtl::math::approxEqual(rA.DirectionY, rB.DirectionY)
140 12 : && ::rtl::math::approxEqual(rA.DirectionZ, rB.DirectionZ);
141 : }
142 :
143 6 : bool lcl_isLightScheme( const uno::Reference< beans::XPropertySet >& xDiagramProps, bool bRealistic )
144 : {
145 6 : if(!xDiagramProps.is())
146 0 : return false;
147 :
148 6 : bool bIsOn = false;
149 6 : xDiagramProps->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_2 ) >>= bIsOn;
150 6 : if(!bIsOn)
151 0 : return false;
152 :
153 6 : uno::Reference< chart2::XDiagram > xDiagram( xDiagramProps, uno::UNO_QUERY );
154 12 : uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) );
155 :
156 6 : sal_Int32 nColor = 0;
157 6 : xDiagramProps->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_2 ) >>= nColor;
158 6 : if( nColor != ::chart::ChartTypeHelper::getDefaultDirectLightColor( !bRealistic, xChartType ) )
159 0 : return false;
160 :
161 6 : sal_Int32 nAmbientColor = 0;
162 6 : xDiagramProps->getPropertyValue( UNO_NAME_3D_SCENE_AMBIENTCOLOR ) >>= nAmbientColor;
163 6 : if( nAmbientColor != ::chart::ChartTypeHelper::getDefaultAmbientLightColor( !bRealistic, xChartType ) )
164 0 : return false;
165 :
166 6 : drawing::Direction3D aDirection(0,0,0);
167 6 : xDiagramProps->getPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_2 ) >>= aDirection;
168 :
169 : drawing::Direction3D aDefaultDirection( bRealistic
170 : ? ChartTypeHelper::getDefaultRealisticLightDirection(xChartType)
171 6 : : ChartTypeHelper::getDefaultSimpleLightDirection(xChartType) );
172 :
173 : //rotate default light direction when right angled axes are off but supported
174 : {
175 6 : bool bRightAngledAxes = false;
176 6 : xDiagramProps->getPropertyValue( "RightAngledAxes") >>= bRightAngledAxes;
177 6 : if(!bRightAngledAxes)
178 : {
179 0 : if( ChartTypeHelper::isSupportingRightAngledAxes(
180 0 : DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ) )
181 : {
182 0 : ::basegfx::B3DHomMatrix aRotation( lcl_getCompleteRotationMatrix( xDiagramProps ) );
183 0 : BaseGFXHelper::ReduceToRotationMatrix( aRotation );
184 0 : ::basegfx::B3DVector aLightVector( BaseGFXHelper::Direction3DToB3DVector( aDefaultDirection ) );
185 0 : aLightVector = aRotation*aLightVector;
186 0 : aDefaultDirection = BaseGFXHelper::B3DVectorToDirection3D( aLightVector );
187 : }
188 : }
189 : }
190 :
191 12 : return lcl_isEqual( aDirection, aDefaultDirection );
192 : }
193 :
194 6 : bool lcl_isRealisticLightScheme( const uno::Reference< beans::XPropertySet >& xDiagramProps )
195 : {
196 6 : return lcl_isLightScheme( xDiagramProps, true /*bRealistic*/ );
197 : }
198 0 : bool lcl_isSimpleLightScheme( const uno::Reference< beans::XPropertySet >& xDiagramProps )
199 : {
200 0 : return lcl_isLightScheme( xDiagramProps, false /*bRealistic*/ );
201 : }
202 34 : void lcl_setLightsForScheme( const uno::Reference< beans::XPropertySet >& xDiagramProps, const ThreeDLookScheme& rScheme )
203 : {
204 34 : if(!xDiagramProps.is())
205 0 : return;
206 34 : if( rScheme == ThreeDLookScheme_Unknown)
207 0 : return;
208 :
209 34 : xDiagramProps->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_2, uno::makeAny( sal_True ) );
210 :
211 34 : uno::Reference< chart2::XDiagram > xDiagram( xDiagramProps, uno::UNO_QUERY );
212 68 : uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) );
213 34 : uno::Any aADirection( uno::makeAny( rScheme == ThreeDLookScheme_Simple
214 : ? ChartTypeHelper::getDefaultSimpleLightDirection(xChartType)
215 68 : : ChartTypeHelper::getDefaultRealisticLightDirection(xChartType) ) );
216 :
217 34 : xDiagramProps->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTDIRECTION_2, aADirection );
218 : //rotate light direction when right angled axes are off but supported
219 : {
220 34 : bool bRightAngledAxes = false;
221 34 : xDiagramProps->getPropertyValue( "RightAngledAxes") >>= bRightAngledAxes;
222 34 : if(!bRightAngledAxes)
223 : {
224 0 : if( ChartTypeHelper::isSupportingRightAngledAxes( xChartType ) )
225 : {
226 0 : ::basegfx::B3DHomMatrix aRotation( lcl_getCompleteRotationMatrix( xDiagramProps ) );
227 0 : BaseGFXHelper::ReduceToRotationMatrix( aRotation );
228 0 : lcl_RotateLightSource( xDiagramProps, "D3DSceneLightDirection2", "D3DSceneLightOn2", aRotation );
229 : }
230 : }
231 : }
232 :
233 34 : sal_Int32 nColor = ::chart::ChartTypeHelper::getDefaultDirectLightColor( rScheme==ThreeDLookScheme_Simple, xChartType );
234 34 : xDiagramProps->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTCOLOR_2, uno::makeAny( nColor ) );
235 :
236 34 : sal_Int32 nAmbientColor = ::chart::ChartTypeHelper::getDefaultAmbientLightColor( rScheme==ThreeDLookScheme_Simple, xChartType );
237 68 : xDiagramProps->setPropertyValue( UNO_NAME_3D_SCENE_AMBIENTCOLOR, uno::makeAny( nAmbientColor ) );
238 : }
239 :
240 26 : bool lcl_isRealisticScheme( drawing::ShadeMode aShadeMode
241 : , sal_Int32 nRoundedEdges
242 : , sal_Int32 nObjectLines )
243 : {
244 26 : if(aShadeMode!=drawing::ShadeMode_SMOOTH)
245 0 : return false;
246 26 : if(nRoundedEdges!=5)
247 20 : return false;
248 6 : if(nObjectLines!=0)
249 0 : return false;
250 6 : return true;
251 : }
252 :
253 26 : bool lcl_isSimpleScheme( drawing::ShadeMode aShadeMode
254 : , sal_Int32 nRoundedEdges
255 : , sal_Int32 nObjectLines
256 : , const uno::Reference< XDiagram >& xDiagram )
257 : {
258 26 : if(aShadeMode!=drawing::ShadeMode_FLAT)
259 26 : return false;
260 0 : if(nRoundedEdges!=0)
261 0 : return false;
262 0 : if(nObjectLines==0)
263 : {
264 0 : uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) );
265 0 : return ChartTypeHelper::noBordersForSimpleScheme( xChartType );
266 : }
267 0 : if(nObjectLines!=1)
268 0 : return false;
269 0 : return true;
270 : }
271 :
272 34 : void lcl_setRealisticScheme( drawing::ShadeMode& rShadeMode
273 : , sal_Int32& rnRoundedEdges
274 : , sal_Int32& rnObjectLines )
275 : {
276 34 : rShadeMode = drawing::ShadeMode_SMOOTH;
277 34 : rnRoundedEdges = 5;
278 34 : rnObjectLines = 0;
279 34 : }
280 :
281 0 : void lcl_setSimpleScheme( drawing::ShadeMode& rShadeMode
282 : , sal_Int32& rnRoundedEdges
283 : , sal_Int32& rnObjectLines
284 : , const uno::Reference< XDiagram >& xDiagram )
285 : {
286 0 : rShadeMode = drawing::ShadeMode_FLAT;
287 0 : rnRoundedEdges = 0;
288 :
289 0 : uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) );
290 0 : rnObjectLines = ChartTypeHelper::noBordersForSimpleScheme( xChartType ) ? 0 : 1;
291 0 : }
292 :
293 : } //end anonymous namespace
294 :
295 1494 : drawing::CameraGeometry ThreeDHelper::getDefaultCameraGeometry( bool bPie )
296 : {
297 : // ViewReferencePoint (Point on the View plane)
298 1494 : drawing::Position3D vrp(17634.6218373783, 10271.4823817647, 24594.8639082739);
299 : // ViewPlaneNormal (Normal to the View Plane)
300 1494 : drawing::Direction3D vpn(0.416199821709347, 0.173649045905254, 0.892537795986984);
301 : // ViewUpVector (determines the v-axis direction on the view plane as
302 : // projection of VUP parallel to VPN onto th view pane)
303 1494 : drawing::Direction3D vup(-0.0733876362771618, 0.984807599917971, -0.157379306090273);
304 :
305 1494 : if( bPie )
306 : {
307 32 : vrp = drawing::Position3D( 0.0, 0.0, 87591.2408759124 );//--> 5 percent perspecitve
308 32 : vpn = drawing::Direction3D( 0.0, 0.0, 1.0 );
309 32 : vup = drawing::Direction3D( 0.0, 1.0, 0.0 );
310 : }
311 :
312 1494 : return drawing::CameraGeometry( vrp, vpn, vup );
313 : }
314 :
315 : namespace
316 : {
317 731 : ::basegfx::B3DHomMatrix lcl_getCameraMatrix( const uno::Reference< beans::XPropertySet >& xSceneProperties )
318 : {
319 731 : drawing::HomogenMatrix aCameraMatrix;
320 :
321 731 : drawing::CameraGeometry aCG( ThreeDHelper::getDefaultCameraGeometry() );
322 731 : if( xSceneProperties.is() )
323 731 : xSceneProperties->getPropertyValue( "D3DCameraGeometry" ) >>= aCG;
324 :
325 731 : ::basegfx::B3DVector aVPN( BaseGFXHelper::Direction3DToB3DVector( aCG.vpn ) );
326 1462 : ::basegfx::B3DVector aVUP( BaseGFXHelper::Direction3DToB3DVector( aCG.vup ) );
327 :
328 : //normalize vectors:
329 731 : aVPN.normalize();
330 731 : aVUP.normalize();
331 :
332 1462 : ::basegfx::B3DVector aCross = ::basegfx::cross( aVUP, aVPN );
333 :
334 : //first line is VUP x VPN
335 731 : aCameraMatrix.Line1.Column1 = aCross[0];
336 731 : aCameraMatrix.Line1.Column2 = aCross[1];
337 731 : aCameraMatrix.Line1.Column3 = aCross[2];
338 731 : aCameraMatrix.Line1.Column4 = 0.0;
339 :
340 : //second line is VUP
341 731 : aCameraMatrix.Line2.Column1 = aVUP[0];
342 731 : aCameraMatrix.Line2.Column2 = aVUP[1];
343 731 : aCameraMatrix.Line2.Column3 = aVUP[2];
344 731 : aCameraMatrix.Line2.Column4 = 0.0;
345 :
346 : //third line is VPN
347 731 : aCameraMatrix.Line3.Column1 = aVPN[0];
348 731 : aCameraMatrix.Line3.Column2 = aVPN[1];
349 731 : aCameraMatrix.Line3.Column3 = aVPN[2];
350 731 : aCameraMatrix.Line3.Column4 = 0.0;
351 :
352 : //fourth line is 0 0 0 1
353 731 : aCameraMatrix.Line4.Column1 = 0.0;
354 731 : aCameraMatrix.Line4.Column2 = 0.0;
355 731 : aCameraMatrix.Line4.Column3 = 0.0;
356 731 : aCameraMatrix.Line4.Column4 = 1.0;
357 :
358 1462 : return BaseGFXHelper::HomogenMatrixToB3DHomMatrix( aCameraMatrix );
359 : }
360 :
361 1773 : double lcl_shiftAngleToIntervalMinusPiToPi( double fAngleRad )
362 : {
363 : //valid range: ]-Pi,Pi]
364 3546 : while( fAngleRad<=-F_PI )
365 0 : fAngleRad+=(2*F_PI);
366 3546 : while( fAngleRad>F_PI )
367 0 : fAngleRad-=(2*F_PI);
368 1773 : return fAngleRad;
369 : }
370 :
371 384 : void lcl_shiftAngleToIntervalMinus180To180( sal_Int32& rnAngleDegree )
372 : {
373 : //valid range: ]-180,180]
374 768 : while( rnAngleDegree<=-180 )
375 0 : rnAngleDegree+=360;
376 768 : while( rnAngleDegree>180 )
377 0 : rnAngleDegree-=360;
378 384 : }
379 :
380 48 : void lcl_shiftAngleToIntervalZeroTo360( sal_Int32& rnAngleDegree )
381 : {
382 : //valid range: [0,360[
383 108 : while( rnAngleDegree<0 )
384 12 : rnAngleDegree+=360;
385 96 : while( rnAngleDegree>=360 )
386 0 : rnAngleDegree-=360;
387 48 : }
388 :
389 0 : void lcl_ensureIntervalMinus1To1( double& rSinOrCos )
390 : {
391 0 : if (rSinOrCos < -1.0)
392 0 : rSinOrCos = -1.0;
393 0 : else if (rSinOrCos > 1.0)
394 0 : rSinOrCos = 1.0;
395 0 : }
396 :
397 96 : bool lcl_isSinZero( double fAngleRad )
398 : {
399 96 : return ::basegfx::fTools::equalZero( sin(fAngleRad), 0.0000001 );
400 : }
401 56 : bool lcl_isCosZero( double fAngleRad )
402 : {
403 56 : return ::basegfx::fTools::equalZero( cos(fAngleRad), 0.0000001 );
404 : }
405 :
406 : }
407 :
408 24 : void ThreeDHelper::convertElevationRotationDegToXYZAngleRad(
409 : sal_Int32 nElevationDeg, sal_Int32 nRotationDeg,
410 : double& rfXAngleRad, double& rfYAngleRad, double& rfZAngleRad)
411 : {
412 : // for a description of the algorithm see issue 72994
413 : //http://www.openoffice.org/issues/show_bug.cgi?id=72994
414 : //http://www.openoffice.org/nonav/issues/showattachment.cgi/50608/DescriptionCorrected.odt
415 :
416 24 : lcl_shiftAngleToIntervalZeroTo360( nElevationDeg );
417 24 : lcl_shiftAngleToIntervalZeroTo360( nRotationDeg );
418 :
419 24 : double& x = rfXAngleRad;
420 24 : double& y = rfYAngleRad;
421 24 : double& z = rfZAngleRad;
422 :
423 24 : double E = F_PI*nElevationDeg/180; //elevation in Rad
424 24 : double R = F_PI*nRotationDeg/180; //rotation in Rad
425 :
426 24 : if( (nRotationDeg == 0 || nRotationDeg == 180 )
427 24 : && ( nElevationDeg == 90 || nElevationDeg == 270 ) )
428 : {
429 : //sR==0 && cE==0
430 0 : z = 0.0;
431 : //element 23
432 0 : double f23 = cos(R)*sin(E);
433 0 : if(f23>0)
434 0 : x = F_PI/2;
435 : else
436 0 : x = -F_PI/2;
437 0 : y = R;
438 : }
439 24 : else if( ( nRotationDeg == 90 || nRotationDeg == 270 )
440 0 : && ( nElevationDeg == 90 || nElevationDeg == 270 ) )
441 : {
442 : //cR==0 && cE==0
443 0 : z = F_PI/2;
444 0 : if( sin(R)>0 )
445 0 : x = F_PI/2.0;
446 : else
447 0 : x = -F_PI/2.0;
448 :
449 0 : if( (sin(R)*sin(E))>0 )
450 0 : y = 0.0;
451 : else
452 0 : y = F_PI;
453 : }
454 24 : else if( (nRotationDeg == 0 || nRotationDeg == 180 )
455 24 : && ( nElevationDeg == 0 || nElevationDeg == 180 ) )
456 : {
457 : //sR==0 && sE==0
458 0 : z = 0.0;
459 0 : y = R;
460 0 : x = E;
461 : }
462 24 : else if( ( nRotationDeg == 90 || nRotationDeg == 270 )
463 0 : && ( nElevationDeg == 0 || nElevationDeg == 180 ) )
464 : {
465 : //cR==0 && sE==0
466 0 : z = 0.0;
467 :
468 0 : if( (sin(R)/cos(E))>0 )
469 0 : y = F_PI/2;
470 : else
471 0 : y = -F_PI/2;
472 :
473 0 : if( (cos(E))>0 )
474 0 : x = 0;
475 : else
476 0 : x = F_PI;
477 : }
478 24 : else if ( nElevationDeg == 0 || nElevationDeg == 180 )
479 : {
480 : //sR!=0 cR!=0 sE==0
481 0 : z = 0.0;
482 0 : x = E;
483 0 : y = R;
484 : //use element 13 for sign
485 0 : if((cos(x)*sin(y)*sin(R))<0.0)
486 0 : y *= -1.0;
487 : }
488 24 : else if ( nElevationDeg == 90 || nElevationDeg == 270 )
489 : {
490 : //sR!=0 cR!=0 cE==0
491 : //element 12 + 22 --> y=0 or F_PI and x=+-F_PI/2
492 : //-->element 13/23:
493 0 : z = atan(sin(R)/(cos(R)*sin(E)));
494 : //use element 13 for sign for x
495 0 : if( (sin(R)*sin(z))>0.0 )
496 0 : x = F_PI/2;
497 : else
498 0 : x = -F_PI/2;
499 : //use element 21 for y
500 0 : if( (sin(R)*sin(E)*sin(z))>0.0)
501 0 : y = 0.0;
502 : else
503 0 : y = F_PI;
504 : }
505 24 : else if ( nRotationDeg == 0 || nRotationDeg == 180 )
506 : {
507 : //sE!=0 cE!=0 sR==0
508 24 : z = 0.0;
509 24 : x = E;
510 24 : y = R;
511 24 : double f23 = cos(R)*sin(E);
512 24 : if( (f23 * sin(x)) < 0.0 )
513 0 : x *= -1.0; //todo ??
514 : }
515 0 : else if (nRotationDeg == 90 || nRotationDeg == 270)
516 : {
517 : //sE!=0 cE!=0 cR==0
518 : //z = +- F_PI/2;
519 : //x = +- F_PI/2;
520 0 : z = F_PI/2;
521 0 : x = F_PI/2;
522 0 : double sR = sin(R);
523 0 : if( sR<0.0 )
524 0 : x *= -1.0; //different signs for x and z
525 :
526 : //use element 21:
527 0 : double cy = sR*sin(E)/sin(z);
528 0 : lcl_ensureIntervalMinus1To1(cy);
529 0 : y = acos(cy);
530 :
531 : //use element 22 for sign:
532 0 : if( (sin(x)*sin(y)*sin(z)*cos(E))<0.0)
533 0 : y *= -1.0;
534 : }
535 : else
536 : {
537 0 : z = atan(tan(R) * sin(E));
538 0 : if(cos(z)==0.0)
539 : {
540 : OSL_FAIL("calculation error in ThreeDHelper::convertElevationRotationDegToXYZAngleRad");
541 0 : return;
542 : }
543 0 : double cy = cos(R)/cos(z);
544 0 : lcl_ensureIntervalMinus1To1(cy);
545 0 : y = acos(cy);
546 :
547 : //element 12 in 23
548 0 : double fDenominator = cos(z)*(1.0-pow(sin(y),2));
549 0 : if(fDenominator==0.0)
550 : {
551 : OSL_FAIL("calculation error in ThreeDHelper::convertElevationRotationDegToXYZAngleRad");
552 0 : return;
553 : }
554 0 : double sx = cos(R)*sin(E)/fDenominator;
555 0 : lcl_ensureIntervalMinus1To1(sx);
556 0 : x = asin( sx );
557 :
558 : //use element 13 for sign:
559 0 : double f13a = cos(x)*cos(z)*sin(y);
560 0 : double f13b = sin(R)-sx*sin(z);
561 0 : if( (f13b*f13a)<0.0 )
562 : {
563 : //change x or y
564 : //use element 22 for further investigations:
565 : //try
566 0 : y *= -1;
567 0 : double f22a = cos(x)*cos(z);
568 0 : double f22b = cos(E)-(sx*sin(y)*sin(z));
569 0 : if( (f22a*f22b)<0.0 )
570 : {
571 0 : y *= -1;
572 0 : x=(F_PI-x);
573 : }
574 : }
575 : else
576 : {
577 : //change nothing or both
578 : //use element 22 for further investigations:
579 0 : double f22a = cos(x)*cos(z);
580 0 : double f22b = cos(E)-(sx*sin(y)*sin(z));
581 0 : if( (f22a*f22b)<0.0 )
582 : {
583 0 : y *= -1;
584 0 : x=(F_PI-x);
585 : }
586 : }
587 : }
588 : }
589 :
590 32 : void ThreeDHelper::convertXYZAngleRadToElevationRotationDeg(
591 : sal_Int32& rnElevationDeg, sal_Int32& rnRotationDeg,
592 : double fXRad, double fYRad, double fZRad)
593 : {
594 : // for a description of the algorithm see issue 72994
595 : //http://www.openoffice.org/issues/show_bug.cgi?id=72994
596 : //http://www.openoffice.org/nonav/issues/showattachment.cgi/50608/DescriptionCorrected.odt
597 :
598 32 : double R = 0.0; //Rotation in Rad
599 32 : double E = 0.0; //Elevation in Rad
600 :
601 32 : double& x = fXRad;
602 32 : double& y = fYRad;
603 32 : double& z = fZRad;
604 :
605 32 : double f11 = cos(y)*cos(z);
606 :
607 32 : if( lcl_isSinZero(y) )
608 : {
609 : //siny == 0
610 :
611 20 : if( lcl_isCosZero(x) )
612 : {
613 : //siny == 0 && cosx == 0
614 :
615 0 : if( lcl_isSinZero(z) )
616 : {
617 : //siny == 0 && cosx == 0 && sinz == 0
618 : //example: x=+-90 y=0oder180 z=0(oder180)
619 :
620 : //element 13+11
621 0 : if( f11 > 0 )
622 0 : R = 0.0;
623 : else
624 0 : R = F_PI;
625 :
626 : //element 23
627 0 : double f23 = cos(z)*sin(x) / cos(R);
628 0 : if( f23 > 0 )
629 0 : E = F_PI/2.0;
630 : else
631 0 : E = -F_PI/2.0;
632 : }
633 0 : else if( lcl_isCosZero(z) )
634 : {
635 : //siny == 0 && cosx == 0 && cosz == 0
636 : //example: x=+-90 y=0oder180 z=+-90
637 :
638 0 : double f13 = sin(x)*sin(z);
639 : //element 13+11
640 0 : if( f13 > 0 )
641 0 : R = F_PI/2.0;
642 : else
643 0 : R = -F_PI/2.0;
644 :
645 : //element 21
646 0 : double f21 = cos(y)*sin(z) / sin(R);
647 0 : if( f21 > 0 )
648 0 : E = F_PI/2.0;
649 : else
650 0 : E = -F_PI/2.0;
651 : }
652 : else
653 : {
654 : //siny == 0 && cosx == 0 && cosz != 0 && sinz != 0
655 : //element 11 && 13
656 0 : double f13 = sin(x)*sin(z);
657 0 : R = atan( f13/f11 );
658 :
659 0 : if(f11<0)
660 0 : R+=F_PI;
661 :
662 : //element 23
663 0 : double f23 = cos(z)*sin(x);
664 0 : if( f23/cos(R) > 0 )
665 0 : E = F_PI/2.0;
666 : else
667 0 : E = -F_PI/2.0;
668 : }
669 : }
670 20 : else if( lcl_isSinZero(x) )
671 : {
672 : //sinY==0 sinX==0
673 : //element 13+11
674 0 : if( f11 > 0 )
675 0 : R = 0.0;
676 : else
677 0 : R = F_PI;
678 :
679 0 : double f22 = cos(x)*cos(z);
680 0 : if( f22 > 0 )
681 0 : E = 0.0;
682 : else
683 0 : E = F_PI;
684 : }
685 20 : else if( lcl_isSinZero(z) )
686 : {
687 : //sinY==0 sinZ==0 sinx!=0 cosx!=0
688 : //element 13+11
689 20 : if( f11 > 0 )
690 20 : R = 0.0;
691 : else
692 0 : R = F_PI;
693 :
694 : //element 22 && 23
695 20 : double f22 = cos(x)*cos(z);
696 20 : double f23 = cos(z)*sin(x);
697 20 : E = atan( f23/(f22*cos(R)) );
698 20 : if( (f22*cos(E))<0 )
699 0 : E+=F_PI;
700 : }
701 0 : else if( lcl_isCosZero(z) )
702 : {
703 : //sinY == 0 && cosZ == 0 && cosx != 0 && sinx != 0
704 0 : double f13 = sin(x)*sin(z);
705 : //element 13+11
706 0 : if( f13 > 0 )
707 0 : R = F_PI/2.0;
708 : else
709 0 : R = -F_PI/2.0;
710 :
711 : //element 21+22
712 0 : double f21 = cos(y)*sin(z);
713 0 : if( f21/sin(R) > 0 )
714 0 : E = F_PI/2.0;
715 : else
716 0 : E = -F_PI/2.0;
717 : }
718 : else
719 : {
720 : //sinY == 0 && all other !=0
721 0 : double f13 = sin(x)*sin(z);
722 0 : R = atan( f13/f11 );
723 0 : if( (f11*cos(R))<0.0 )
724 0 : R+=F_PI;
725 :
726 0 : double f22 = cos(x)*cos(z);
727 0 : if( !lcl_isCosZero(R) )
728 0 : E = atan( cos(z)*sin(x) /( f22*cos(R) ) );
729 : else
730 0 : E = atan( cos(y)*sin(z) /( f22*sin(R) ) );
731 0 : if( (f22*cos(E))<0 )
732 0 : E+=F_PI;
733 : }
734 : }
735 12 : else if( lcl_isCosZero(y) )
736 : {
737 : //cosY==0
738 :
739 0 : double f13 = sin(x)*sin(z)+cos(x)*cos(z)*sin(y);
740 0 : if( f13 >= 0 )
741 0 : R = F_PI/2.0;
742 : else
743 0 : R = -F_PI/2.0;
744 :
745 0 : double f22 = cos(x)*cos(z)+sin(x)*sin(y)*sin(z);
746 0 : if( f22 >= 0 )
747 0 : E = 0.0;
748 : else
749 0 : E = F_PI;
750 : }
751 12 : else if( lcl_isSinZero(x) )
752 : {
753 : //cosY!=0 sinY!=0 sinX=0
754 0 : if( lcl_isSinZero(z) )
755 : {
756 : //cosY!=0 sinY!=0 sinX=0 sinZ=0
757 0 : double f13 = cos(x)*cos(z)*sin(y);
758 0 : R = atan( f13/f11 );
759 : //R = asin(f13);
760 0 : if( f11<0 )
761 0 : R+=F_PI;
762 :
763 0 : double f22 = cos(x)*cos(z);
764 0 : if( f22>0 )
765 0 : E = 0.0;
766 : else
767 0 : E = F_PI;
768 : }
769 0 : else if( lcl_isCosZero(z) )
770 : {
771 : //cosY!=0 sinY!=0 sinX=0 cosZ=0
772 0 : R = x;
773 0 : E = y;//or -y
774 : //use 23 for 'signs'
775 0 : double f23 = -1.0*cos(x)*sin(y)*sin(z);
776 0 : if( (f23*cos(R)*sin(E))<0.0 )
777 : {
778 : //change R or E
779 0 : E = -y;
780 : }
781 : }
782 : else
783 : {
784 : //cosY!=0 sinY!=0 sinX=0 sinZ!=0 cosZ!=0
785 0 : double f13 = cos(x)*cos(z)*sin(y);
786 0 : R = atan( f13/f11 );
787 :
788 0 : if( f11<0 )
789 0 : R+=F_PI;
790 :
791 0 : double f21 = cos(y)*sin(z);
792 0 : double f22 = cos(x)*cos(z);
793 0 : E = atan(f21/(f22*sin(R)) );
794 :
795 0 : if( (f22*cos(E))<0.0 )
796 0 : E+=F_PI;
797 : }
798 : }
799 12 : else if( lcl_isCosZero(x) )
800 : {
801 : //cosY!=0 sinY!=0 cosX=0
802 :
803 0 : if( lcl_isSinZero(z) )
804 : {
805 : //cosY!=0 sinY!=0 cosX=0 sinZ=0
806 0 : R=0;//13 -> R=0 or F_PI
807 0 : if( f11<0.0 )
808 0 : R=F_PI;
809 0 : E=F_PI/2;//22 -> E=+-F_PI/2
810 : //use element 11 and 23 for sign
811 0 : double f23 = cos(z)*sin(x);
812 0 : if( (f11*f23*sin(E))<0.0 )
813 0 : E=-F_PI/2.0;
814 : }
815 0 : else if( lcl_isCosZero(z) )
816 : {
817 : //cosY!=0 sinY!=0 cosX=0 cosZ=0
818 : //element 11 & 13:
819 0 : if( (sin(x)*sin(z))>0.0 )
820 0 : R=F_PI/2.0;
821 : else
822 0 : R=-F_PI/2.0;
823 : //element 22:
824 0 : E=acos( sin(x)*sin(y)*sin(z));
825 : //use element 21 for sign:
826 0 : if( (cos(y)*sin(z)*sin(R)*sin(E))<0.0 )
827 0 : E*=-1.0;
828 : }
829 : else
830 : {
831 : //cosY!=0 sinY!=0 cosX=0 sinZ!=0 cosZ!=0
832 : //element 13/11
833 0 : R = atan( sin(x)*sin(z)/(cos(y)*cos(z)) );
834 : //use 13 for 'sign'
835 0 : if( (sin(x)*sin(z))<0.0 )
836 0 : R += F_PI;
837 : //element 22
838 0 : E = acos(sin(x)*sin(y)*sin(z) );
839 : //use 21 for sign
840 0 : if( (cos(y)*sin(z)*sin(R)*sin(E))<0.0 )
841 0 : E*=-1.0;
842 : }
843 : }
844 12 : else if( lcl_isSinZero(z) )
845 : {
846 : //cosY!=0 sinY!=0 sinX!=0 cosX!=0 sinZ=0
847 : //element 11
848 0 : R=y;
849 : //use elenment 13 for sign
850 0 : if( (cos(x)*cos(z)*sin(y)*sin(R))<0.0 )
851 0 : R*=-1.0;
852 : //element 22
853 0 : E = acos( cos(x)*cos(z) );
854 : //use element 23 for sign
855 0 : if( (cos(z)*sin(x)*cos(R)*sin(E))<0.0 )
856 0 : E*=-1.0;
857 : }
858 12 : else if( lcl_isCosZero(z) )
859 : {
860 : //cosY!=0 sinY!=0 sinX!=0 cosX!=0 cosZ=0
861 : //element 21/23
862 0 : R=atan(-cos(y)/(cos(x)*sin(y)));
863 : //use element 13 for 'sign'
864 0 : if( (sin(x)*sin(z)*sin(R))<0.0 )
865 0 : R+=F_PI;
866 : //element 21/22
867 0 : E=atan( cos(y)*sin(z)/(sin(R)*sin(x)*sin(y)*sin(z)) );
868 : //use element 23 for 'sign'
869 0 : if( (-cos(x)*sin(y)*sin(z)*cos(R)*sin(E))<0.0 )
870 0 : E+=F_PI;
871 : }
872 : else
873 : {
874 : //cosY!=0 sinY!=0 sinX!=0 cosX!=0 sinZ!=0 cosZ!=0
875 : //13/11:
876 12 : double f13 = sin(x)*sin(z)+cos(x)*cos(z)*sin(y);
877 12 : R = atan( f13/ f11 );
878 12 : if(f11<0.0)
879 0 : R+=F_PI;
880 12 : double f22 = cos(x)*cos(z)+sin(x)*sin(y)*sin(z);
881 12 : double f23 = cos(x)*sin(y)*sin(z)-cos(z)*sin(x);
882 : //23/22:
883 12 : E = atan( -1.0*f23/(f22*cos(R)) );
884 12 : if(f22<0.0)
885 0 : E+=F_PI;
886 : }
887 :
888 32 : rnElevationDeg = ::basegfx::fround( BaseGFXHelper::Rad2Deg( E ) );
889 32 : rnRotationDeg = ::basegfx::fround( BaseGFXHelper::Rad2Deg( R ) );
890 32 : }
891 :
892 224 : double ThreeDHelper::getValueClippedToRange( double fAngle, const double& fPositivLimit )
893 : {
894 224 : if( fAngle<-1*fPositivLimit )
895 14 : fAngle=-1*fPositivLimit;
896 210 : else if( fAngle>fPositivLimit )
897 0 : fAngle=fPositivLimit;
898 224 : return fAngle;
899 : }
900 :
901 112 : double ThreeDHelper::getXDegreeAngleLimitForRightAngledAxes()
902 : {
903 112 : return 90.0;
904 : }
905 :
906 112 : double ThreeDHelper::getYDegreeAngleLimitForRightAngledAxes()
907 : {
908 112 : return 45.0;
909 : }
910 :
911 112 : void ThreeDHelper::adaptRadAnglesForRightAngledAxes( double& rfXAngleRad, double& rfYAngleRad )
912 : {
913 112 : rfXAngleRad = ThreeDHelper::getValueClippedToRange(rfXAngleRad, BaseGFXHelper::Deg2Rad(ThreeDHelper::getXDegreeAngleLimitForRightAngledAxes()) );
914 112 : rfYAngleRad = ThreeDHelper::getValueClippedToRange(rfYAngleRad, BaseGFXHelper::Deg2Rad(ThreeDHelper::getYDegreeAngleLimitForRightAngledAxes()) );
915 112 : }
916 :
917 591 : void ThreeDHelper::getRotationAngleFromDiagram(
918 : const Reference< beans::XPropertySet >& xSceneProperties, double& rfXAngleRad, double& rfYAngleRad, double& rfZAngleRad )
919 : {
920 : //takes the camera and the transformation matrix into account
921 :
922 591 : rfXAngleRad = rfYAngleRad = rfZAngleRad = 0.0;
923 :
924 591 : if( !xSceneProperties.is() )
925 591 : return;
926 :
927 : //get camera rotation
928 591 : ::basegfx::B3DHomMatrix aFixCameraRotationMatrix( lcl_getCameraMatrix( xSceneProperties ) );
929 591 : BaseGFXHelper::ReduceToRotationMatrix( aFixCameraRotationMatrix );
930 :
931 : //get scene rotation
932 1182 : ::basegfx::B3DHomMatrix aSceneRotation;
933 : {
934 591 : drawing::HomogenMatrix aHomMatrix;
935 591 : if( xSceneProperties->getPropertyValue( "D3DTransformMatrix") >>= aHomMatrix )
936 : {
937 591 : aSceneRotation = BaseGFXHelper::HomogenMatrixToB3DHomMatrix( aHomMatrix );
938 591 : BaseGFXHelper::ReduceToRotationMatrix( aSceneRotation );
939 : }
940 : }
941 :
942 1182 : ::basegfx::B3DHomMatrix aResultRotation = aFixCameraRotationMatrix * aSceneRotation;
943 1182 : ::basegfx::B3DTuple aRotation( BaseGFXHelper::GetRotationFromMatrix( aResultRotation ) );
944 :
945 591 : rfXAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(aRotation.getX());
946 591 : rfYAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(aRotation.getY());
947 591 : rfZAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(aRotation.getZ());
948 :
949 591 : if(rfZAngleRad<(-F_PI/2) || rfZAngleRad>(F_PI/2))
950 : {
951 0 : rfZAngleRad-=F_PI;
952 0 : rfXAngleRad-=F_PI;
953 0 : rfYAngleRad=(F_PI-rfYAngleRad);
954 :
955 0 : rfXAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(rfXAngleRad);
956 0 : rfYAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(rfYAngleRad);
957 0 : rfZAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(rfZAngleRad);
958 591 : }
959 : }
960 :
961 0 : void ThreeDHelper::switchRightAngledAxes( const Reference< beans::XPropertySet >& xSceneProperties, bool bRightAngledAxes, bool bRotateLights )
962 : {
963 : try
964 : {
965 0 : if( xSceneProperties.is() )
966 : {
967 0 : bool bOldRightAngledAxes = false;
968 0 : xSceneProperties->getPropertyValue( "RightAngledAxes") >>= bOldRightAngledAxes;
969 0 : if( bOldRightAngledAxes!=bRightAngledAxes)
970 : {
971 0 : xSceneProperties->setPropertyValue( "RightAngledAxes", uno::makeAny( bRightAngledAxes ));
972 0 : if( bRotateLights )
973 : {
974 0 : if(bRightAngledAxes)
975 : {
976 0 : ::basegfx::B3DHomMatrix aInverseRotation( lcl_getInverseRotationMatrix( xSceneProperties ) );
977 0 : lcl_rotateLights( aInverseRotation, xSceneProperties );
978 : }
979 : else
980 : {
981 0 : ::basegfx::B3DHomMatrix aCompleteRotation( lcl_getCompleteRotationMatrix( xSceneProperties ) );
982 0 : lcl_rotateLights( aCompleteRotation, xSceneProperties );
983 : }
984 : }
985 : }
986 : }
987 : }
988 0 : catch( const uno::Exception & ex )
989 : {
990 : ASSERT_EXCEPTION( ex );
991 : }
992 0 : }
993 :
994 140 : void ThreeDHelper::setRotationAngleToDiagram(
995 : const Reference< beans::XPropertySet >& xSceneProperties
996 : , double fXAngleRad, double fYAngleRad, double fZAngleRad )
997 : {
998 : //the rotation of the camera is not touched but taken into account
999 : //the rotation difference is applied to the transformation matrix
1000 :
1001 : //the light sources will be adapted also
1002 :
1003 140 : if( !xSceneProperties.is() )
1004 140 : return;
1005 :
1006 : try
1007 : {
1008 : //remind old rotation for adaption of light directions
1009 140 : ::basegfx::B3DHomMatrix aInverseOldRotation( lcl_getInverseRotationMatrix( xSceneProperties ) );
1010 :
1011 280 : ::basegfx::B3DHomMatrix aInverseCameraRotation;
1012 : {
1013 : ::basegfx::B3DTuple aR( BaseGFXHelper::GetRotationFromMatrix(
1014 140 : lcl_getCameraMatrix( xSceneProperties ) ) );
1015 140 : aInverseCameraRotation.rotate( 0.0, 0.0, -aR.getZ() );
1016 140 : aInverseCameraRotation.rotate( 0.0, -aR.getY(), 0.0 );
1017 140 : aInverseCameraRotation.rotate( -aR.getX(), 0.0, 0.0 );
1018 : }
1019 :
1020 280 : ::basegfx::B3DHomMatrix aCumulatedRotation;
1021 140 : aCumulatedRotation.rotate( fXAngleRad, fYAngleRad, fZAngleRad );
1022 :
1023 : //calculate new scene matrix
1024 280 : ::basegfx::B3DHomMatrix aSceneRotation = aInverseCameraRotation*aCumulatedRotation;
1025 140 : BaseGFXHelper::ReduceToRotationMatrix( aSceneRotation );
1026 :
1027 : //set new rotation to transformation matrix
1028 140 : xSceneProperties->setPropertyValue(
1029 140 : "D3DTransformMatrix", uno::makeAny( BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aSceneRotation )));
1030 :
1031 : //rotate lights if RightAngledAxes are not set or not supported
1032 140 : bool bRightAngledAxes = false;
1033 140 : xSceneProperties->getPropertyValue( "RightAngledAxes") >>= bRightAngledAxes;
1034 280 : uno::Reference< chart2::XDiagram > xDiagram( xSceneProperties, uno::UNO_QUERY );
1035 536 : if(!bRightAngledAxes || !ChartTypeHelper::isSupportingRightAngledAxes(
1036 488 : DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ) )
1037 : {
1038 24 : ::basegfx::B3DHomMatrix aNewRotation;
1039 24 : aNewRotation.rotate( fXAngleRad, fYAngleRad, fZAngleRad );
1040 24 : lcl_rotateLights( aNewRotation*aInverseOldRotation, xSceneProperties );
1041 140 : }
1042 : }
1043 0 : catch( const uno::Exception & ex )
1044 : {
1045 : ASSERT_EXCEPTION( ex );
1046 : }
1047 : }
1048 :
1049 192 : void ThreeDHelper::getRotationFromDiagram( const uno::Reference< beans::XPropertySet >& xSceneProperties
1050 : , sal_Int32& rnHorizontalAngleDegree, sal_Int32& rnVerticalAngleDegree )
1051 : {
1052 : double fXAngle, fYAngle, fZAngle;
1053 192 : ThreeDHelper::getRotationAngleFromDiagram( xSceneProperties, fXAngle, fYAngle, fZAngle );
1054 :
1055 192 : if( !lcl_isRightAngledAxesSetAndSupported( xSceneProperties ) )
1056 : {
1057 : ThreeDHelper::convertXYZAngleRadToElevationRotationDeg(
1058 32 : rnHorizontalAngleDegree, rnVerticalAngleDegree, fXAngle, fYAngle, fZAngle);
1059 32 : rnVerticalAngleDegree*=-1;
1060 : }
1061 : else
1062 : {
1063 160 : fXAngle = BaseGFXHelper::Rad2Deg( fXAngle );
1064 160 : fYAngle = BaseGFXHelper::Rad2Deg( fYAngle );
1065 160 : fZAngle = BaseGFXHelper::Rad2Deg( fZAngle );
1066 :
1067 160 : rnHorizontalAngleDegree = ::basegfx::fround(fXAngle);
1068 160 : rnVerticalAngleDegree = ::basegfx::fround(-1.0*fYAngle);
1069 : //nZRotation = ::basegfx::fround(-1.0*fZAngle);
1070 : }
1071 :
1072 192 : lcl_shiftAngleToIntervalMinus180To180( rnHorizontalAngleDegree );
1073 192 : lcl_shiftAngleToIntervalMinus180To180( rnVerticalAngleDegree );
1074 192 : }
1075 :
1076 140 : void ThreeDHelper::setRotationToDiagram( const uno::Reference< beans::XPropertySet >& xSceneProperties
1077 : , sal_Int32 nHorizontalAngleDegree, sal_Int32 nVerticalYAngleDegree )
1078 : {
1079 : //todo: x and y is not equal to horz and vert in case of RightAngledAxes==false
1080 140 : double fXAngle = BaseGFXHelper::Deg2Rad( nHorizontalAngleDegree );
1081 140 : double fYAngle = BaseGFXHelper::Deg2Rad( -1*nVerticalYAngleDegree );
1082 140 : double fZAngle = 0.0;
1083 :
1084 140 : if( !lcl_isRightAngledAxesSetAndSupported( xSceneProperties ) )
1085 : ThreeDHelper::convertElevationRotationDegToXYZAngleRad(
1086 24 : nHorizontalAngleDegree, -1*nVerticalYAngleDegree, fXAngle, fYAngle, fZAngle );
1087 :
1088 140 : ThreeDHelper::setRotationAngleToDiagram( xSceneProperties, fXAngle, fYAngle, fZAngle );
1089 140 : }
1090 :
1091 159 : void ThreeDHelper::getCameraDistanceRange( double& rfMinimumDistance, double& rfMaximumDistance )
1092 : {
1093 159 : rfMinimumDistance = 3.0/4.0*FIXED_SIZE_FOR_3D_CHART_VOLUME;//empiric value
1094 159 : rfMaximumDistance = 20.0*FIXED_SIZE_FOR_3D_CHART_VOLUME;//empiric value
1095 159 : }
1096 :
1097 63 : void ThreeDHelper::ensureCameraDistanceRange( double& rfCameraDistance )
1098 : {
1099 : double fMin, fMax;
1100 63 : getCameraDistanceRange( fMin, fMax );
1101 63 : if( rfCameraDistance < fMin )
1102 0 : rfCameraDistance = fMin;
1103 63 : if( rfCameraDistance > fMax )
1104 0 : rfCameraDistance = fMax;
1105 63 : }
1106 :
1107 63 : double ThreeDHelper::getCameraDistance(
1108 : const Reference< beans::XPropertySet >& xSceneProperties )
1109 : {
1110 63 : double fCameraDistance = FIXED_SIZE_FOR_3D_CHART_VOLUME;
1111 :
1112 63 : if( !xSceneProperties.is() )
1113 0 : return fCameraDistance;
1114 :
1115 : try
1116 : {
1117 63 : drawing::CameraGeometry aCG( ThreeDHelper::getDefaultCameraGeometry() );
1118 63 : xSceneProperties->getPropertyValue( "D3DCameraGeometry" ) >>= aCG;
1119 63 : ::basegfx::B3DVector aVRP( BaseGFXHelper::Position3DToB3DVector( aCG.vrp ) );
1120 63 : fCameraDistance = aVRP.getLength();
1121 :
1122 63 : ensureCameraDistanceRange( fCameraDistance );
1123 : }
1124 0 : catch( const uno::Exception & ex )
1125 : {
1126 : ASSERT_EXCEPTION( ex );
1127 : }
1128 63 : return fCameraDistance;
1129 : }
1130 :
1131 70 : void ThreeDHelper::setCameraDistance(
1132 : const Reference< beans::XPropertySet >& xSceneProperties, double fCameraDistance )
1133 : {
1134 70 : if( !xSceneProperties.is() )
1135 70 : return;
1136 :
1137 : try
1138 : {
1139 70 : if( fCameraDistance <= 0 )
1140 0 : fCameraDistance = FIXED_SIZE_FOR_3D_CHART_VOLUME;
1141 :
1142 70 : drawing::CameraGeometry aCG( ThreeDHelper::getDefaultCameraGeometry() );
1143 70 : xSceneProperties->getPropertyValue( "D3DCameraGeometry" ) >>= aCG;
1144 70 : ::basegfx::B3DVector aVRP( BaseGFXHelper::Position3DToB3DVector( aCG.vrp ) );
1145 70 : if( ::basegfx::fTools::equalZero( aVRP.getLength() ) )
1146 0 : aVRP = ::basegfx::B3DVector(0,0,1);
1147 70 : aVRP.setLength(fCameraDistance);
1148 70 : aCG.vrp = BaseGFXHelper::B3DVectorToPosition3D( aVRP );
1149 :
1150 70 : xSceneProperties->setPropertyValue( "D3DCameraGeometry", uno::makeAny( aCG ));
1151 : }
1152 0 : catch( const uno::Exception & ex )
1153 : {
1154 : ASSERT_EXCEPTION( ex );
1155 : }
1156 : }
1157 :
1158 26 : double ThreeDHelper::CameraDistanceToPerspective( double fCameraDistance )
1159 : {
1160 : double fMin, fMax;
1161 26 : ThreeDHelper::getCameraDistanceRange( fMin, fMax );
1162 : //fMax <-> 0; fMin <->100
1163 : //a/x + b = y
1164 26 : double a = 100.0*fMax*fMin/(fMax-fMin);
1165 26 : double b = -a/fMax;
1166 :
1167 26 : double fRet = a/fCameraDistance + b;
1168 :
1169 26 : return fRet;
1170 : }
1171 :
1172 70 : double ThreeDHelper::PerspectiveToCameraDistance( double fPerspective )
1173 : {
1174 : double fMin, fMax;
1175 70 : ThreeDHelper::getCameraDistanceRange( fMin, fMax );
1176 : //fMax <-> 0; fMin <->100
1177 : //a/x + b = y
1178 70 : double a = 100.0*fMax*fMin/(fMax-fMin);
1179 70 : double b = -a/fMax;
1180 :
1181 70 : double fRet = a/(fPerspective - b);
1182 :
1183 70 : return fRet;
1184 : }
1185 :
1186 26 : ThreeDLookScheme ThreeDHelper::detectScheme( const uno::Reference< XDiagram >& xDiagram )
1187 : {
1188 26 : ThreeDLookScheme aScheme = ThreeDLookScheme_Unknown;
1189 :
1190 : sal_Int32 nRoundedEdges;
1191 : sal_Int32 nObjectLines;
1192 26 : ThreeDHelper::getRoundedEdgesAndObjectLines( xDiagram, nRoundedEdges, nObjectLines );
1193 :
1194 : //get shade mode and light settings:
1195 26 : drawing::ShadeMode aShadeMode( drawing::ShadeMode_SMOOTH );
1196 26 : uno::Reference< beans::XPropertySet > xDiagramProps( xDiagram, uno::UNO_QUERY );
1197 : try
1198 : {
1199 26 : if( xDiagramProps.is() )
1200 26 : xDiagramProps->getPropertyValue( "D3DSceneShadeMode" )>>= aShadeMode;
1201 : }
1202 0 : catch( const uno::Exception & ex )
1203 : {
1204 : ASSERT_EXCEPTION( ex );
1205 : }
1206 :
1207 26 : if( lcl_isSimpleScheme( aShadeMode, nRoundedEdges, nObjectLines, xDiagram ) )
1208 : {
1209 0 : if( lcl_isSimpleLightScheme(xDiagramProps) )
1210 0 : aScheme = ThreeDLookScheme_Simple;
1211 : }
1212 26 : else if( lcl_isRealisticScheme( aShadeMode, nRoundedEdges, nObjectLines ) )
1213 : {
1214 6 : if( lcl_isRealisticLightScheme(xDiagramProps) )
1215 6 : aScheme = ThreeDLookScheme_Realistic;
1216 : }
1217 :
1218 26 : return aScheme;
1219 : }
1220 :
1221 54 : void ThreeDHelper::setScheme( const uno::Reference< XDiagram >& xDiagram, ThreeDLookScheme aScheme )
1222 : {
1223 54 : if( aScheme == ThreeDLookScheme_Unknown )
1224 74 : return;
1225 :
1226 : drawing::ShadeMode aShadeMode;
1227 : sal_Int32 nRoundedEdges;
1228 : sal_Int32 nObjectLines;
1229 :
1230 34 : if( aScheme == ThreeDLookScheme_Simple )
1231 0 : lcl_setSimpleScheme(aShadeMode,nRoundedEdges,nObjectLines,xDiagram);
1232 : else
1233 34 : lcl_setRealisticScheme(aShadeMode,nRoundedEdges,nObjectLines);
1234 :
1235 : try
1236 : {
1237 34 : ThreeDHelper::setRoundedEdgesAndObjectLines( xDiagram, nRoundedEdges, nObjectLines );
1238 :
1239 34 : uno::Reference< beans::XPropertySet > xProp( xDiagram, uno::UNO_QUERY );
1240 34 : if( xProp.is() )
1241 : {
1242 : drawing::ShadeMode aOldShadeMode;
1243 102 : if( ! ( (xProp->getPropertyValue( "D3DSceneShadeMode" )>>=aOldShadeMode) &&
1244 102 : aOldShadeMode == aShadeMode ))
1245 : {
1246 0 : xProp->setPropertyValue( "D3DSceneShadeMode", uno::makeAny( aShadeMode ));
1247 : }
1248 : }
1249 :
1250 34 : lcl_setLightsForScheme( xProp, aScheme );
1251 : }
1252 0 : catch( const uno::Exception & ex )
1253 : {
1254 : ASSERT_EXCEPTION( ex );
1255 : }
1256 :
1257 : }
1258 :
1259 0 : void ThreeDHelper::set3DSettingsToDefault( const uno::Reference< beans::XPropertySet >& xSceneProperties )
1260 : {
1261 0 : Reference< beans::XPropertyState > xState( xSceneProperties, uno::UNO_QUERY );
1262 0 : if(xState.is())
1263 : {
1264 0 : xState->setPropertyToDefault( "D3DSceneDistance");
1265 0 : xState->setPropertyToDefault( "D3DSceneFocalLength");
1266 : }
1267 0 : ThreeDHelper::setDefaultRotation( xSceneProperties );
1268 0 : ThreeDHelper::setDefaultIllumination( xSceneProperties );
1269 0 : }
1270 :
1271 32 : void ThreeDHelper::setDefaultRotation( const uno::Reference< beans::XPropertySet >& xSceneProperties, bool bPieOrDonut )
1272 : {
1273 32 : if( !xSceneProperties.is() )
1274 32 : return;
1275 :
1276 32 : drawing::CameraGeometry aCameraGeo( ThreeDHelper::getDefaultCameraGeometry( bPieOrDonut ) );
1277 32 : xSceneProperties->setPropertyValue( "D3DCameraGeometry", uno::makeAny( aCameraGeo ));
1278 :
1279 32 : ::basegfx::B3DHomMatrix aSceneRotation;
1280 32 : if( bPieOrDonut )
1281 32 : aSceneRotation.rotate( -F_PI/3.0, 0, 0 );
1282 32 : xSceneProperties->setPropertyValue( "D3DTransformMatrix",
1283 32 : uno::makeAny( BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aSceneRotation )));
1284 : }
1285 :
1286 0 : void ThreeDHelper::setDefaultRotation( const uno::Reference< beans::XPropertySet >& xSceneProperties )
1287 : {
1288 0 : bool bPieOrDonut( DiagramHelper::isPieOrDonutChart( uno::Reference< XDiagram >(xSceneProperties, uno::UNO_QUERY) ) );
1289 0 : ThreeDHelper::setDefaultRotation( xSceneProperties, bPieOrDonut );
1290 0 : }
1291 :
1292 0 : void ThreeDHelper::setDefaultIllumination( const uno::Reference< beans::XPropertySet >& xSceneProperties )
1293 : {
1294 0 : if( !xSceneProperties.is() )
1295 0 : return;
1296 :
1297 0 : drawing::ShadeMode aShadeMode( drawing::ShadeMode_SMOOTH );
1298 : try
1299 : {
1300 0 : xSceneProperties->getPropertyValue( "D3DSceneShadeMode" )>>= aShadeMode;
1301 0 : xSceneProperties->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_1, uno::makeAny( sal_False ) );
1302 0 : xSceneProperties->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_3, uno::makeAny( sal_False ) );
1303 0 : xSceneProperties->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_4, uno::makeAny( sal_False ) );
1304 0 : xSceneProperties->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_5, uno::makeAny( sal_False ) );
1305 0 : xSceneProperties->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_6, uno::makeAny( sal_False ) );
1306 0 : xSceneProperties->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_7, uno::makeAny( sal_False ) );
1307 0 : xSceneProperties->setPropertyValue( UNO_NAME_3D_SCENE_LIGHTON_8, uno::makeAny( sal_False ) );
1308 : }
1309 0 : catch( const uno::Exception & ex )
1310 : {
1311 : ASSERT_EXCEPTION( ex );
1312 : }
1313 :
1314 0 : ThreeDLookScheme aScheme = (drawing::ShadeMode_FLAT==aShadeMode) ? ThreeDLookScheme_Simple : ThreeDLookScheme_Realistic;
1315 0 : lcl_setLightsForScheme( xSceneProperties, aScheme );
1316 : }
1317 :
1318 26 : void ThreeDHelper::getRoundedEdgesAndObjectLines(
1319 : const uno::Reference< XDiagram > & xDiagram
1320 : , sal_Int32& rnRoundedEdges, sal_Int32& rnObjectLines )
1321 : {
1322 26 : rnRoundedEdges = -1;
1323 26 : rnObjectLines = -1;
1324 : try
1325 : {
1326 26 : bool bDifferentRoundedEdges = false;
1327 26 : bool bDifferentObjectLines = false;
1328 :
1329 26 : drawing::LineStyle aLineStyle( drawing::LineStyle_SOLID );
1330 :
1331 : ::std::vector< uno::Reference< XDataSeries > > aSeriesList(
1332 26 : DiagramHelper::getDataSeriesFromDiagram( xDiagram ) );
1333 26 : sal_Int32 nSeriesCount = static_cast<sal_Int32>( aSeriesList.size() );
1334 :
1335 52 : OUString aPercentDiagonalPropertyName( "PercentDiagonal" );
1336 52 : OUString aBorderStylePropertyName( "BorderStyle" );
1337 :
1338 232 : for( sal_Int32 nS = 0; nS < nSeriesCount; ++nS )
1339 : {
1340 206 : uno::Reference< XDataSeries > xSeries( aSeriesList[nS] );
1341 412 : uno::Reference< beans::XPropertySet > xProp( xSeries, uno::UNO_QUERY );
1342 206 : if(!nS)
1343 : {
1344 26 : rnRoundedEdges = 0;
1345 : try
1346 : {
1347 26 : sal_Int16 nPercentDiagonal = 0;
1348 :
1349 26 : xProp->getPropertyValue( aPercentDiagonalPropertyName ) >>= nPercentDiagonal;
1350 26 : rnRoundedEdges = static_cast< sal_Int32 >( nPercentDiagonal );
1351 :
1352 52 : if( DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries
1353 52 : , aPercentDiagonalPropertyName, uno::makeAny(nPercentDiagonal) ) )
1354 0 : bDifferentRoundedEdges = true;
1355 : }
1356 0 : catch( const uno::Exception& e )
1357 : {
1358 : ASSERT_EXCEPTION( e );
1359 0 : bDifferentRoundedEdges = true;
1360 : }
1361 : try
1362 : {
1363 26 : xProp->getPropertyValue( aBorderStylePropertyName ) >>= aLineStyle;
1364 :
1365 52 : if( DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries
1366 52 : , aBorderStylePropertyName, uno::makeAny(aLineStyle) ) )
1367 0 : bDifferentObjectLines = true;
1368 : }
1369 0 : catch( const uno::Exception& e )
1370 : {
1371 : ASSERT_EXCEPTION( e );
1372 0 : bDifferentObjectLines = true;
1373 : }
1374 : }
1375 : else
1376 : {
1377 180 : if( !bDifferentRoundedEdges )
1378 : {
1379 180 : sal_Int16 nPercentDiagonal = 0;
1380 180 : xProp->getPropertyValue( aPercentDiagonalPropertyName ) >>= nPercentDiagonal;
1381 180 : sal_Int32 nCurrentRoundedEdges = static_cast< sal_Int32 >( nPercentDiagonal );
1382 540 : if(nCurrentRoundedEdges!=rnRoundedEdges
1383 720 : || DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries
1384 720 : , aPercentDiagonalPropertyName, uno::makeAny( static_cast< sal_Int16 >(rnRoundedEdges) ) ) )
1385 : {
1386 0 : bDifferentRoundedEdges = true;
1387 0 : nCurrentRoundedEdges = -1;
1388 : }
1389 : }
1390 :
1391 180 : if( !bDifferentObjectLines )
1392 : {
1393 : drawing::LineStyle aCurrentLineStyle;
1394 180 : xProp->getPropertyValue( aBorderStylePropertyName ) >>= aCurrentLineStyle;
1395 540 : if(aCurrentLineStyle!=aLineStyle
1396 720 : || DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries
1397 720 : , aBorderStylePropertyName, uno::makeAny(aLineStyle) ) )
1398 0 : bDifferentObjectLines = true;
1399 : }
1400 : }
1401 206 : if( bDifferentRoundedEdges && bDifferentObjectLines )
1402 0 : break;
1403 206 : }
1404 :
1405 : //set rnObjectLines
1406 26 : rnObjectLines = 0;
1407 26 : if( bDifferentObjectLines )
1408 0 : rnObjectLines = -1;
1409 26 : else if( aLineStyle == drawing::LineStyle_SOLID )
1410 38 : rnObjectLines = 1;
1411 : }
1412 0 : catch( const uno::Exception& e )
1413 : {
1414 : ASSERT_EXCEPTION( e );
1415 : }
1416 26 : }
1417 :
1418 34 : void ThreeDHelper::setRoundedEdgesAndObjectLines(
1419 : const uno::Reference< XDiagram > & xDiagram
1420 : , sal_Int32 nRoundedEdges, sal_Int32 nObjectLines )
1421 : {
1422 34 : if( (nRoundedEdges<0||nRoundedEdges>100) && nObjectLines!=0 && nObjectLines!=1 )
1423 34 : return;
1424 :
1425 34 : drawing::LineStyle aLineStyle( drawing::LineStyle_NONE );
1426 34 : if(nObjectLines==1)
1427 0 : aLineStyle = drawing::LineStyle_SOLID;
1428 :
1429 34 : uno::Any aALineStyle( uno::makeAny(aLineStyle));
1430 68 : uno::Any aARoundedEdges( uno::makeAny( static_cast< sal_Int16 >( nRoundedEdges )));
1431 :
1432 : ::std::vector< uno::Reference< XDataSeries > > aSeriesList(
1433 68 : DiagramHelper::getDataSeriesFromDiagram( xDiagram ) );
1434 34 : sal_Int32 nSeriesCount = static_cast<sal_Int32>( aSeriesList.size() );
1435 136 : for( sal_Int32 nS = 0; nS < nSeriesCount; ++nS )
1436 : {
1437 102 : uno::Reference< XDataSeries > xSeries( aSeriesList[nS] );
1438 :
1439 102 : if( nRoundedEdges>=0 && nRoundedEdges<=100 )
1440 102 : DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, "PercentDiagonal", aARoundedEdges );
1441 :
1442 102 : if( nObjectLines==0 || nObjectLines==1 )
1443 102 : DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, "BorderStyle", aALineStyle );
1444 136 : }
1445 : }
1446 :
1447 74 : CuboidPlanePosition ThreeDHelper::getAutomaticCuboidPlanePositionForStandardLeftWall( const Reference< beans::XPropertySet >& xSceneProperties )
1448 : {
1449 74 : CuboidPlanePosition eRet(CuboidPlanePosition_Left);
1450 :
1451 74 : double fXAngleRad=0.0; double fYAngleRad=0.0; double fZAngleRad=0.0;
1452 74 : ThreeDHelper::getRotationAngleFromDiagram( xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad );
1453 74 : if( lcl_isRightAngledAxesSetAndSupported( xSceneProperties ) )
1454 : {
1455 32 : ThreeDHelper::adaptRadAnglesForRightAngledAxes( fXAngleRad, fYAngleRad );
1456 32 : fZAngleRad=0.0;
1457 : }
1458 74 : if( sin(fYAngleRad)>0.0 )
1459 0 : eRet = CuboidPlanePosition_Right;
1460 74 : return eRet;
1461 : }
1462 :
1463 74 : CuboidPlanePosition ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBackWall( const Reference< beans::XPropertySet >& xSceneProperties )
1464 : {
1465 74 : CuboidPlanePosition eRet(CuboidPlanePosition_Back);
1466 :
1467 74 : double fXAngleRad=0.0; double fYAngleRad=0.0; double fZAngleRad=0.0;
1468 74 : ThreeDHelper::getRotationAngleFromDiagram( xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad );
1469 74 : if( lcl_isRightAngledAxesSetAndSupported( xSceneProperties ) )
1470 : {
1471 32 : ThreeDHelper::adaptRadAnglesForRightAngledAxes( fXAngleRad, fYAngleRad );
1472 32 : fZAngleRad=0.0;
1473 : }
1474 74 : if( cos(fXAngleRad)*cos(fYAngleRad)<0.0 )
1475 0 : eRet = CuboidPlanePosition_Front;
1476 74 : return eRet;
1477 : }
1478 :
1479 74 : CuboidPlanePosition ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBottom( const Reference< beans::XPropertySet >& xSceneProperties )
1480 : {
1481 74 : CuboidPlanePosition eRet(CuboidPlanePosition_Bottom);
1482 :
1483 74 : double fXAngleRad=0.0; double fYAngleRad=0.0; double fZAngleRad=0.0;
1484 74 : ThreeDHelper::getRotationAngleFromDiagram( xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad );
1485 74 : if( lcl_isRightAngledAxesSetAndSupported( xSceneProperties ) )
1486 : {
1487 32 : ThreeDHelper::adaptRadAnglesForRightAngledAxes( fXAngleRad, fYAngleRad );
1488 32 : fZAngleRad=0.0;
1489 : }
1490 74 : if( sin(fXAngleRad)*cos(fYAngleRad)<0.0 )
1491 4 : eRet = CuboidPlanePosition_Top;
1492 74 : return eRet;
1493 : }
1494 :
1495 108 : } //namespace chart
1496 :
1497 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|