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