merged tag ooo/OOO330_m14
[LibreOffice.git] / chart2 / source / tools / ThreeDHelper.cxx
blob44ed73eade43a2ebc41f9176344739e8aec1bc05
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2000, 2010 Oracle and/or its affiliates.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * This file is part of OpenOffice.org.
11 * OpenOffice.org is free software: you can redistribute it and/or modify
12 * it under the terms of the GNU Lesser General Public License version 3
13 * only, as published by the Free Software Foundation.
15 * OpenOffice.org is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License version 3 for more details
19 * (a copy is included in the LICENSE file that accompanied this code).
21 * You should have received a copy of the GNU Lesser General Public License
22 * version 3 along with OpenOffice.org. If not, see
23 * <http://www.openoffice.org/license.html>
24 * for a copy of the LGPLv3 License.
26 ************************************************************************/
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_chart2.hxx"
31 #include "ThreeDHelper.hxx"
32 #include "macros.hxx"
33 #include "DiagramHelper.hxx"
34 #include "ChartTypeHelper.hxx"
35 #include "BaseGFXHelper.hxx"
36 #include "DataSeriesHelper.hxx"
37 #include <editeng/unoprnms.hxx>
38 #include <com/sun/star/beans/XPropertyState.hpp>
39 #include <com/sun/star/chart2/XDiagram.hpp>
40 #include <com/sun/star/drawing/LineStyle.hpp>
42 #include <tools/debug.hxx>
44 //.............................................................................
45 namespace chart
47 //.............................................................................
48 using namespace ::com::sun::star;
49 using namespace ::com::sun::star::chart2;
51 using ::com::sun::star::uno::Reference;
52 using ::com::sun::star::uno::Sequence;
53 using ::rtl::OUString;
54 using ::rtl::math::cos;
55 using ::rtl::math::sin;
56 using ::rtl::math::tan;
58 #define FIXED_SIZE_FOR_3D_CHART_VOLUME (10000.0)
60 namespace
63 bool lcl_isRightAngledAxesSetAndSupported( const Reference< beans::XPropertySet >& xSceneProperties )
65 sal_Bool bRightAngledAxes = sal_False;
66 if( xSceneProperties.is() )
68 xSceneProperties->getPropertyValue( C2U("RightAngledAxes")) >>= bRightAngledAxes;
69 if(bRightAngledAxes)
71 uno::Reference< chart2::XDiagram > xDiagram( xSceneProperties, uno::UNO_QUERY );
72 if( ChartTypeHelper::isSupportingRightAngledAxes(
73 DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ) )
75 return true;
79 return false;
82 void lcl_RotateLightSource( const Reference< beans::XPropertySet >& xSceneProperties
83 , const OUString& rLightSourceDirection
84 , const OUString& rLightSourceOn
85 , const ::basegfx::B3DHomMatrix& rRotationMatrix )
87 if( xSceneProperties.is() )
89 sal_Bool bLightOn = sal_False;
90 if( xSceneProperties->getPropertyValue( rLightSourceOn ) >>= bLightOn )
92 if( bLightOn )
94 drawing::Direction3D aLight;
95 if( xSceneProperties->getPropertyValue( rLightSourceDirection ) >>= aLight )
97 ::basegfx::B3DVector aLightVector( BaseGFXHelper::Direction3DToB3DVector( aLight ) );
98 aLightVector = rRotationMatrix*aLightVector;
100 xSceneProperties->setPropertyValue( rLightSourceDirection
101 , uno::makeAny( BaseGFXHelper::B3DVectorToDirection3D( aLightVector ) ) );
108 void lcl_rotateLights( const ::basegfx::B3DHomMatrix& rLightRottion, const Reference< beans::XPropertySet >& xSceneProperties )
110 if(!xSceneProperties.is())
111 return;
113 ::basegfx::B3DHomMatrix aLightRottion( rLightRottion );
114 BaseGFXHelper::ReduceToRotationMatrix( aLightRottion );
116 lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection1"), C2U("D3DSceneLightOn1"), aLightRottion );
117 lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection2"), C2U("D3DSceneLightOn2"), aLightRottion );
118 lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection3"), C2U("D3DSceneLightOn3"), aLightRottion );
119 lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection4"), C2U("D3DSceneLightOn4"), aLightRottion );
120 lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection5"), C2U("D3DSceneLightOn5"), aLightRottion );
121 lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection6"), C2U("D3DSceneLightOn6"), aLightRottion );
122 lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection7"), C2U("D3DSceneLightOn7"), aLightRottion );
123 lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection8"), C2U("D3DSceneLightOn8"), aLightRottion );
126 ::basegfx::B3DHomMatrix lcl_getInverseRotationMatrix( const Reference< beans::XPropertySet >& xSceneProperties )
128 ::basegfx::B3DHomMatrix aInverseRotation;
129 double fXAngleRad=0.0;
130 double fYAngleRad=0.0;
131 double fZAngleRad=0.0;
132 ThreeDHelper::getRotationAngleFromDiagram(
133 xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad );
134 aInverseRotation.rotate( 0.0, 0.0, -fZAngleRad );
135 aInverseRotation.rotate( 0.0, -fYAngleRad, 0.0 );
136 aInverseRotation.rotate( -fXAngleRad, 0.0, 0.0 );
137 return aInverseRotation;
140 ::basegfx::B3DHomMatrix lcl_getCompleteRotationMatrix( const Reference< beans::XPropertySet >& xSceneProperties )
142 ::basegfx::B3DHomMatrix aCompleteRotation;
143 double fXAngleRad=0.0;
144 double fYAngleRad=0.0;
145 double fZAngleRad=0.0;
146 ThreeDHelper::getRotationAngleFromDiagram(
147 xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad );
148 aCompleteRotation.rotate( fXAngleRad, fYAngleRad, fZAngleRad );
149 return aCompleteRotation;
152 bool lcl_isEqual( const drawing::Direction3D& rA, const drawing::Direction3D& rB )
154 return ::rtl::math::approxEqual(rA.DirectionX, rB.DirectionX)
155 && ::rtl::math::approxEqual(rA.DirectionY, rB.DirectionY)
156 && ::rtl::math::approxEqual(rA.DirectionZ, rB.DirectionZ);
159 bool lcl_isLightScheme( const uno::Reference< beans::XPropertySet >& xDiagramProps, bool bRealistic )
161 if(!xDiagramProps.is())
162 return false;
164 sal_Bool bIsOn = sal_False;
165 xDiagramProps->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_2 ) ) >>= bIsOn;
166 if(!bIsOn)
167 return false;
169 uno::Reference< chart2::XDiagram > xDiagram( xDiagramProps, uno::UNO_QUERY );
170 uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) );
172 sal_Int32 nColor = 0;
173 xDiagramProps->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_2 ) ) >>= nColor;
174 if( nColor != ::chart::ChartTypeHelper::getDefaultDirectLightColor( !bRealistic, xChartType ) )
175 return false;
177 sal_Int32 nAmbientColor = 0;
178 xDiagramProps->getPropertyValue( C2U( UNO_NAME_3D_SCENE_AMBIENTCOLOR ) ) >>= nAmbientColor;
179 if( nAmbientColor != ::chart::ChartTypeHelper::getDefaultAmbientLightColor( !bRealistic, xChartType ) )
180 return false;
182 drawing::Direction3D aDirection(0,0,0);
183 xDiagramProps->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_2 ) ) >>= aDirection;
185 drawing::Direction3D aDefaultDirection( bRealistic
186 ? ChartTypeHelper::getDefaultRealisticLightDirection(xChartType)
187 : ChartTypeHelper::getDefaultSimpleLightDirection(xChartType) );
189 //rotate default light direction when right angled axes are off but supported
191 sal_Bool bRightAngledAxes = sal_False;
192 xDiagramProps->getPropertyValue( C2U("RightAngledAxes")) >>= bRightAngledAxes;
193 if(!bRightAngledAxes)
195 if( ChartTypeHelper::isSupportingRightAngledAxes(
196 DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ) )
198 ::basegfx::B3DHomMatrix aRotation( lcl_getCompleteRotationMatrix( xDiagramProps ) );
199 BaseGFXHelper::ReduceToRotationMatrix( aRotation );
200 ::basegfx::B3DVector aLightVector( BaseGFXHelper::Direction3DToB3DVector( aDefaultDirection ) );
201 aLightVector = aRotation*aLightVector;
202 aDefaultDirection = BaseGFXHelper::B3DVectorToDirection3D( aLightVector );
207 return lcl_isEqual( aDirection, aDefaultDirection );
210 bool lcl_isRealisticLightScheme( const uno::Reference< beans::XPropertySet >& xDiagramProps )
212 return lcl_isLightScheme( xDiagramProps, true /*bRealistic*/ );
214 bool lcl_isSimpleLightScheme( const uno::Reference< beans::XPropertySet >& xDiagramProps )
216 return lcl_isLightScheme( xDiagramProps, false /*bRealistic*/ );
218 void lcl_setLightsForScheme( const uno::Reference< beans::XPropertySet >& xDiagramProps, const ThreeDLookScheme& rScheme )
220 if(!xDiagramProps.is())
221 return;
222 if( rScheme == ThreeDLookScheme_Unknown)
223 return;
225 xDiagramProps->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_2 ), uno::makeAny( sal_True ) );
227 uno::Reference< chart2::XDiagram > xDiagram( xDiagramProps, uno::UNO_QUERY );
228 uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) );
229 uno::Any aADirection( uno::makeAny( rScheme == ThreeDLookScheme_Simple
230 ? ChartTypeHelper::getDefaultSimpleLightDirection(xChartType)
231 : ChartTypeHelper::getDefaultRealisticLightDirection(xChartType) ) );
233 xDiagramProps->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_2 ), aADirection );
234 //rotate light direction when right angled axes are off but supported
236 sal_Bool bRightAngledAxes = sal_False;
237 xDiagramProps->getPropertyValue( C2U("RightAngledAxes")) >>= bRightAngledAxes;
238 if(!bRightAngledAxes)
240 if( ChartTypeHelper::isSupportingRightAngledAxes( xChartType ) )
242 ::basegfx::B3DHomMatrix aRotation( lcl_getCompleteRotationMatrix( xDiagramProps ) );
243 BaseGFXHelper::ReduceToRotationMatrix( aRotation );
244 lcl_RotateLightSource( xDiagramProps, C2U("D3DSceneLightDirection2"), C2U("D3DSceneLightOn2"), aRotation );
249 sal_Int32 nColor = ::chart::ChartTypeHelper::getDefaultDirectLightColor( rScheme==ThreeDLookScheme_Simple, xChartType );
250 xDiagramProps->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_2 ), uno::makeAny( nColor ) );
252 sal_Int32 nAmbientColor = ::chart::ChartTypeHelper::getDefaultAmbientLightColor( rScheme==ThreeDLookScheme_Simple, xChartType );
253 xDiagramProps->setPropertyValue( C2U( UNO_NAME_3D_SCENE_AMBIENTCOLOR ), uno::makeAny( nAmbientColor ) );
256 bool lcl_isRealisticScheme( drawing::ShadeMode aShadeMode
257 , sal_Int32 nRoundedEdges
258 , sal_Int32 nObjectLines )
260 if(aShadeMode!=drawing::ShadeMode_SMOOTH)
261 return false;
262 if(nRoundedEdges!=5)
263 return false;
264 if(nObjectLines!=0)
265 return false;
266 return true;
269 bool lcl_isSimpleScheme( drawing::ShadeMode aShadeMode
270 , sal_Int32 nRoundedEdges
271 , sal_Int32 nObjectLines
272 , const uno::Reference< XDiagram >& xDiagram )
274 if(aShadeMode!=drawing::ShadeMode_FLAT)
275 return false;
276 if(nRoundedEdges!=0)
277 return false;
278 if(nObjectLines==0)
280 uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) );
281 return ChartTypeHelper::noBordersForSimpleScheme( xChartType );
283 if(nObjectLines!=1)
284 return false;
285 return true;
288 void lcl_setRealisticScheme( drawing::ShadeMode& rShadeMode
289 , sal_Int32& rnRoundedEdges
290 , sal_Int32& rnObjectLines )
292 rShadeMode = drawing::ShadeMode_SMOOTH;
293 rnRoundedEdges = 5;
294 rnObjectLines = 0;
297 void lcl_setSimpleScheme( drawing::ShadeMode& rShadeMode
298 , sal_Int32& rnRoundedEdges
299 , sal_Int32& rnObjectLines
300 , const uno::Reference< XDiagram >& xDiagram )
302 rShadeMode = drawing::ShadeMode_FLAT;
303 rnRoundedEdges = 0;
305 uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) );
306 rnObjectLines = ChartTypeHelper::noBordersForSimpleScheme( xChartType ) ? 0 : 1;
309 } //end anonymous namespace
312 drawing::CameraGeometry ThreeDHelper::getDefaultCameraGeometry( bool bPie )
314 // ViewReferencePoint (Point on the View plane)
315 drawing::Position3D vrp(17634.6218373783, 10271.4823817647, 24594.8639082739);
316 // ViewPlaneNormal (Normal to the View Plane)
317 drawing::Direction3D vpn(0.416199821709347, 0.173649045905254, 0.892537795986984);
318 // ViewUpVector (determines the v-axis direction on the view plane as
319 // projection of VUP parallel to VPN onto th view pane)
320 drawing::Direction3D vup(-0.0733876362771618, 0.984807599917971, -0.157379306090273);
322 if( bPie )
324 vrp = drawing::Position3D( 0.0, 0.0, 87591.2408759124 );//--> 5 percent perspecitve
325 vpn = drawing::Direction3D( 0.0, 0.0, 1.0 );
326 vup = drawing::Direction3D( 0.0, 1.0, 0.0 );
329 return drawing::CameraGeometry( vrp, vpn, vup );
332 namespace
334 ::basegfx::B3DHomMatrix lcl_getCameraMatrix( const uno::Reference< beans::XPropertySet >& xSceneProperties )
336 drawing::HomogenMatrix aCameraMatrix;
338 drawing::CameraGeometry aCG( ThreeDHelper::getDefaultCameraGeometry() );
339 if( xSceneProperties.is() )
340 xSceneProperties->getPropertyValue( C2U( "D3DCameraGeometry" ) ) >>= aCG;
342 ::basegfx::B3DVector aVPN( BaseGFXHelper::Direction3DToB3DVector( aCG.vpn ) );
343 ::basegfx::B3DVector aVUP( BaseGFXHelper::Direction3DToB3DVector( aCG.vup ) );
345 //normalize vectors:
346 aVPN.normalize();
347 aVUP.normalize();
349 ::basegfx::B3DVector aCross = ::basegfx::cross( aVUP, aVPN );
351 //first line is VUP x VPN
352 aCameraMatrix.Line1.Column1 = aCross[0];
353 aCameraMatrix.Line1.Column2 = aCross[1];
354 aCameraMatrix.Line1.Column3 = aCross[2];
355 aCameraMatrix.Line1.Column4 = 0.0;
357 //second line is VUP
358 aCameraMatrix.Line2.Column1 = aVUP[0];
359 aCameraMatrix.Line2.Column2 = aVUP[1];
360 aCameraMatrix.Line2.Column3 = aVUP[2];
361 aCameraMatrix.Line2.Column4 = 0.0;
363 //third line is VPN
364 aCameraMatrix.Line3.Column1 = aVPN[0];
365 aCameraMatrix.Line3.Column2 = aVPN[1];
366 aCameraMatrix.Line3.Column3 = aVPN[2];
367 aCameraMatrix.Line3.Column4 = 0.0;
369 //fourth line is 0 0 0 1
370 aCameraMatrix.Line4.Column1 = 0.0;
371 aCameraMatrix.Line4.Column2 = 0.0;
372 aCameraMatrix.Line4.Column3 = 0.0;
373 aCameraMatrix.Line4.Column4 = 1.0;
375 return BaseGFXHelper::HomogenMatrixToB3DHomMatrix( aCameraMatrix );
378 double lcl_shiftAngleToIntervalMinusPiToPi( double fAngleRad )
380 //valid range: ]-Pi,Pi]
381 while( fAngleRad<=-F_PI )
382 fAngleRad+=(2*F_PI);
383 while( fAngleRad>F_PI )
384 fAngleRad-=(2*F_PI);
385 return fAngleRad;
388 void lcl_shiftAngleToIntervalMinus180To180( sal_Int32& rnAngleDegree )
390 //valid range: ]-180,180]
391 while( rnAngleDegree<=-180 )
392 rnAngleDegree+=360;
393 while( rnAngleDegree>180 )
394 rnAngleDegree-=360;
397 void lcl_shiftAngleToIntervalZeroTo360( sal_Int32& rnAngleDegree )
399 //valid range: [0,360[
400 while( rnAngleDegree<0 )
401 rnAngleDegree+=360;
402 while( rnAngleDegree>=360 )
403 rnAngleDegree-=360;
406 void lcl_ensureIntervalMinus1To1( double& rSinOrCos )
408 if (rSinOrCos < -1.0)
409 rSinOrCos = -1.0;
410 else if (rSinOrCos > 1.0)
411 rSinOrCos = 1.0;
414 bool lcl_isSinZero( double fAngleRad )
416 return ::basegfx::fTools::equalZero( sin(fAngleRad), 0.0000001 );
418 bool lcl_isCosZero( double fAngleRad )
420 return ::basegfx::fTools::equalZero( cos(fAngleRad), 0.0000001 );
425 void ThreeDHelper::convertElevationRotationDegToXYZAngleRad(
426 sal_Int32 nElevationDeg, sal_Int32 nRotationDeg,
427 double& rfXAngleRad, double& rfYAngleRad, double& rfZAngleRad)
429 // for a description of the algorithm see issue 72994
430 //http://www.openoffice.org/issues/show_bug.cgi?id=72994
431 //http://www.openoffice.org/nonav/issues/showattachment.cgi/50608/DescriptionCorrected.odt
433 lcl_shiftAngleToIntervalZeroTo360( nElevationDeg );
434 lcl_shiftAngleToIntervalZeroTo360( nRotationDeg );
436 double& x = rfXAngleRad;
437 double& y = rfYAngleRad;
438 double& z = rfZAngleRad;
440 double E = F_PI*nElevationDeg/180; //elevation in Rad
441 double R = F_PI*nRotationDeg/180; //rotation in Rad
443 if( (nRotationDeg == 0 || nRotationDeg == 180 )
444 && ( nElevationDeg == 90 || nElevationDeg == 270 ) )
446 //sR==0 && cE==0
447 z = 0.0;
448 //element 23
449 double f23 = cos(R)*sin(E);
450 if(f23>0)
451 x = F_PI/2;
452 else
453 x = -F_PI/2;
454 y = R;
456 else if( ( nRotationDeg == 90 || nRotationDeg == 270 )
457 && ( nElevationDeg == 90 || nElevationDeg == 270 ) )
459 //cR==0 && cE==0
460 z = F_PI/2;
461 if( sin(R)>0 )
462 x = F_PI/2.0;
463 else
464 x = -F_PI/2.0;
466 if( (sin(R)*sin(E))>0 )
467 y = 0.0;
468 else
469 y = F_PI;
471 else if( (nRotationDeg == 0 || nRotationDeg == 180 )
472 && ( nElevationDeg == 0 || nElevationDeg == 180 ) )
474 //sR==0 && sE==0
475 z = 0.0;
476 y = R;
477 x = E;
479 else if( ( nRotationDeg == 90 || nRotationDeg == 270 )
480 && ( nElevationDeg == 0 || nElevationDeg == 180 ) )
482 //cR==0 && sE==0
483 z = 0.0;
485 if( (sin(R)/cos(E))>0 )
486 y = F_PI/2;
487 else
488 y = -F_PI/2;
490 if( (cos(E))>0 )
491 x = 0;
492 else
493 x = F_PI;
495 else if ( nElevationDeg == 0 || nElevationDeg == 180 )
497 //sR!=0 cR!=0 sE==0
498 z = 0.0;
499 x = E;
500 y = R;
501 //use element 13 for sign
502 if((cos(x)*sin(y)*sin(R))<0.0)
503 y *= -1.0;
505 else if ( nElevationDeg == 90 || nElevationDeg == 270 )
507 //sR!=0 cR!=0 cE==0
508 //element 12 + 22 --> y=0 or F_PI and x=+-F_PI/2
509 //-->element 13/23:
510 z = atan(sin(R)/(cos(R)*sin(E)));
511 //use element 13 for sign for x
512 if( (sin(R)*sin(z))>0.0 )
513 x = F_PI/2;
514 else
515 x = -F_PI/2;
516 //use element 21 for y
517 if( (sin(R)*sin(E)*sin(z))>0.0)
518 y = 0.0;
519 else
520 y = F_PI;
522 else if ( nRotationDeg == 0 || nRotationDeg == 180 )
524 //sE!=0 cE!=0 sR==0
525 z = 0.0;
526 x = E;
527 y = R;
528 double f23 = cos(R)*sin(E);
529 if( (f23 * sin(x)) < 0.0 )
530 x *= -1.0; //todo ??
532 else if (nRotationDeg == 90 || nRotationDeg == 270)
534 //sE!=0 cE!=0 cR==0
535 //z = +- F_PI/2;
536 //x = +- F_PI/2;
537 z = F_PI/2;
538 x = F_PI/2;
539 double sR = sin(R);
540 if( sR<0.0 )
541 x *= -1.0; //different signs for x and z
543 //use element 21:
544 double cy = sR*sin(E)/sin(z);
545 lcl_ensureIntervalMinus1To1(cy);
546 y = acos(cy);
548 //use element 22 for sign:
549 if( (sin(x)*sin(y)*sin(z)*cos(E))<0.0)
550 y *= -1.0;
552 else
554 z = atan(tan(R) * sin(E));
555 if(cos(z)==0.0)
557 DBG_ERROR("calculation error in ThreeDHelper::convertElevationRotationDegToXYZAngleRad");
558 return;
560 double cy = cos(R)/cos(z);
561 lcl_ensureIntervalMinus1To1(cy);
562 y = acos(cy);
564 //element 12 in 23
565 double fDenominator = cos(z)*(1.0-pow(sin(y),2));
566 if(fDenominator==0.0)
568 DBG_ERROR("calculation error in ThreeDHelper::convertElevationRotationDegToXYZAngleRad");
569 return;
571 double sx = cos(R)*sin(E)/fDenominator;
572 lcl_ensureIntervalMinus1To1(sx);
573 x = asin( sx );
575 //use element 13 for sign:
576 double f13a = cos(x)*cos(z)*sin(y);
577 double f13b = sin(R)-sx*sin(z);
578 if( (f13b*f13a)<0.0 )
580 //change x or y
581 //use element 22 for further investigations:
582 //try
583 y *= -1;
584 double f22a = cos(x)*cos(z);
585 double f22b = cos(E)-(sx*sin(y)*sin(z));
586 if( (f22a*f22b)<0.0 )
588 y *= -1;
589 x=(F_PI-x);
592 else
594 //change nothing or both
595 //use element 22 for further investigations:
596 double f22a = cos(x)*cos(z);
597 double f22b = cos(E)-(sx*sin(y)*sin(z));
598 if( (f22a*f22b)<0.0 )
600 y *= -1;
601 x=(F_PI-x);
607 void ThreeDHelper::convertXYZAngleRadToElevationRotationDeg(
608 sal_Int32& rnElevationDeg, sal_Int32& rnRotationDeg,
609 double fXRad, double fYRad, double fZRad)
611 // for a description of the algorithm see issue 72994
612 //http://www.openoffice.org/issues/show_bug.cgi?id=72994
613 //http://www.openoffice.org/nonav/issues/showattachment.cgi/50608/DescriptionCorrected.odt
615 double R = 0.0; //Rotation in Rad
616 double E = 0.0; //Elevation in Rad
618 double& x = fXRad;
619 double& y = fYRad;
620 double& z = fZRad;
622 double f11 = cos(y)*cos(z);
624 if( lcl_isSinZero(y) )
626 //siny == 0
628 if( lcl_isCosZero(x) )
630 //siny == 0 && cosx == 0
632 if( lcl_isSinZero(z) )
634 //siny == 0 && cosx == 0 && sinz == 0
635 //example: x=+-90 y=0oder180 z=0(oder180)
637 //element 13+11
638 if( f11 > 0 )
639 R = 0.0;
640 else
641 R = F_PI;
643 //element 23
644 double f23 = cos(z)*sin(x) / cos(R);
645 if( f23 > 0 )
646 E = F_PI/2.0;
647 else
648 E = -F_PI/2.0;
650 else if( lcl_isCosZero(z) )
652 //siny == 0 && cosx == 0 && cosz == 0
653 //example: x=+-90 y=0oder180 z=+-90
655 double f13 = sin(x)*sin(z);
656 //element 13+11
657 if( f13 > 0 )
658 R = F_PI/2.0;
659 else
660 R = -F_PI/2.0;
662 //element 21
663 double f21 = cos(y)*sin(z) / sin(R);
664 if( f21 > 0 )
665 E = F_PI/2.0;
666 else
667 E = -F_PI/2.0;
669 else
671 //siny == 0 && cosx == 0 && cosz != 0 && sinz != 0
672 //element 11 && 13
673 double f13 = sin(x)*sin(z);
674 R = atan( f13/f11 );
676 if(f11<0)
677 R+=F_PI;
679 //element 23
680 double f23 = cos(z)*sin(x);
681 if( f23/cos(R) > 0 )
682 E = F_PI/2.0;
683 else
684 E = -F_PI/2.0;
687 else if( lcl_isSinZero(x) )
689 //sinY==0 sinX==0
690 //element 13+11
691 if( f11 > 0 )
692 R = 0.0;
693 else
694 R = F_PI;
696 double f22 = cos(x)*cos(z);
697 if( f22 > 0 )
698 E = 0.0;
699 else
700 E = F_PI;
702 else if( lcl_isSinZero(z) )
704 //sinY==0 sinZ==0 sinx!=0 cosx!=0
705 //element 13+11
706 if( f11 > 0 )
707 R = 0.0;
708 else
709 R = F_PI;
711 //element 22 && 23
712 double f22 = cos(x)*cos(z);
713 double f23 = cos(z)*sin(x);
714 E = atan( f23/(f22*cos(R)) );
715 if( (f22*cos(E))<0 )
716 E+=F_PI;
718 else if( lcl_isCosZero(z) )
720 //sinY == 0 && cosZ == 0 && cosx != 0 && sinx != 0
721 double f13 = sin(x)*sin(z);
722 //element 13+11
723 if( f13 > 0 )
724 R = F_PI/2.0;
725 else
726 R = -F_PI/2.0;
728 //element 21+22
729 double f21 = cos(y)*sin(z);
730 if( f21/sin(R) > 0 )
731 E = F_PI/2.0;
732 else
733 E = -F_PI/2.0;
735 else
737 //sinY == 0 && all other !=0
738 double f13 = sin(x)*sin(z);
739 R = atan( f13/f11 );
740 if( (f11*cos(R))<0.0 )
741 R+=F_PI;
743 double f22 = cos(x)*cos(z);
744 if( !lcl_isCosZero(R) )
745 E = atan( cos(z)*sin(x) /( f22*cos(R) ) );
746 else
747 E = atan( cos(y)*sin(z) /( f22*sin(R) ) );
748 if( (f22*cos(E))<0 )
749 E+=F_PI;
752 else if( lcl_isCosZero(y) )
754 //cosY==0
756 double f13 = sin(x)*sin(z)+cos(x)*cos(z)*sin(y);
757 if( f13 >= 0 )
758 R = F_PI/2.0;
759 else
760 R = -F_PI/2.0;
762 double f22 = cos(x)*cos(z)+sin(x)*sin(y)*sin(z);
763 if( f22 >= 0 )
764 E = 0.0;
765 else
766 E = F_PI;
768 else if( lcl_isSinZero(x) )
770 //cosY!=0 sinY!=0 sinX=0
771 if( lcl_isSinZero(z) )
773 //cosY!=0 sinY!=0 sinX=0 sinZ=0
774 double f13 = cos(x)*cos(z)*sin(y);
775 R = atan( f13/f11 );
776 //R = asin(f13);
777 if( f11<0 )
778 R+=F_PI;
780 double f22 = cos(x)*cos(z);
781 if( f22>0 )
782 E = 0.0;
783 else
784 E = F_PI;
786 else if( lcl_isCosZero(z) )
788 //cosY!=0 sinY!=0 sinX=0 cosZ=0
789 R = x;
790 E = y;//or -y
791 //use 23 for 'signs'
792 double f23 = -1.0*cos(x)*sin(y)*sin(z);
793 if( (f23*cos(R)*sin(E))<0.0 )
795 //change R or E
796 E = -y;
799 else
801 //cosY!=0 sinY!=0 sinX=0 sinZ!=0 cosZ!=0
802 double f13 = cos(x)*cos(z)*sin(y);
803 R = atan( f13/f11 );
805 if( f11<0 )
806 R+=F_PI;
808 double f21 = cos(y)*sin(z);
809 double f22 = cos(x)*cos(z);
810 E = atan(f21/(f22*sin(R)) );
812 if( (f22*cos(E))<0.0 )
813 E+=F_PI;
816 else if( lcl_isCosZero(x) )
818 //cosY!=0 sinY!=0 cosX=0
820 if( lcl_isSinZero(z) )
822 //cosY!=0 sinY!=0 cosX=0 sinZ=0
823 R=0;//13 -> R=0 or F_PI
824 if( f11<0.0 )
825 R=F_PI;
826 E=F_PI/2;//22 -> E=+-F_PI/2
827 //use element 11 and 23 for sign
828 double f23 = cos(z)*sin(x);
829 if( (f11*f23*sin(E))<0.0 )
830 E=-F_PI/2.0;
832 else if( lcl_isCosZero(z) )
834 //cosY!=0 sinY!=0 cosX=0 cosZ=0
835 //element 11 & 13:
836 if( (sin(x)*sin(z))>0.0 )
837 R=F_PI/2.0;
838 else
839 R=-F_PI/2.0;
840 //element 22:
841 E=acos( sin(x)*sin(y)*sin(z));
842 //use element 21 for sign:
843 if( (cos(y)*sin(z)*sin(R)*sin(E))<0.0 )
844 E*=-1.0;
846 else
848 //cosY!=0 sinY!=0 cosX=0 sinZ!=0 cosZ!=0
849 //element 13/11
850 R = atan( sin(x)*sin(z)/(cos(y)*cos(z)) );
851 //use 13 for 'sign'
852 if( (sin(x)*sin(z))<0.0 )
853 R += F_PI;
854 //element 22
855 E = acos(sin(x)*sin(y)*sin(z) );
856 //use 21 for sign
857 if( (cos(y)*sin(z)*sin(R)*sin(E))<0.0 )
858 E*=-1.0;
861 else if( lcl_isSinZero(z) )
863 //cosY!=0 sinY!=0 sinX!=0 cosX!=0 sinZ=0
864 //element 11
865 R=y;
866 //use elenment 13 for sign
867 if( (cos(x)*cos(z)*sin(y)*sin(R))<0.0 )
868 R*=-1.0;
869 //element 22
870 E = acos( cos(x)*cos(z) );
871 //use element 23 for sign
872 if( (cos(z)*sin(x)*cos(R)*sin(E))<0.0 )
873 E*=-1.0;
875 else if( lcl_isCosZero(z) )
877 //cosY!=0 sinY!=0 sinX!=0 cosX!=0 cosZ=0
878 //element 21/23
879 R=atan(-cos(y)/(cos(x)*sin(y)));
880 //use element 13 for 'sign'
881 if( (sin(x)*sin(z)*sin(R))<0.0 )
882 R+=F_PI;
883 //element 21/22
884 E=atan( cos(y)*sin(z)/(sin(R)*sin(x)*sin(y)*sin(z)) );
885 //use element 23 for 'sign'
886 if( (-cos(x)*sin(y)*sin(z)*cos(R)*sin(E))<0.0 )
887 E+=F_PI;
889 else
891 //cosY!=0 sinY!=0 sinX!=0 cosX!=0 sinZ!=0 cosZ!=0
892 //13/11:
893 double f13 = sin(x)*sin(z)+cos(x)*cos(z)*sin(y);
894 R = atan( f13/ f11 );
895 if(f11<0.0)
896 R+=F_PI;
897 double f22 = cos(x)*cos(z)+sin(x)*sin(y)*sin(z);
898 double f23 = cos(x)*sin(y)*sin(z)-cos(z)*sin(x);
899 //23/22:
900 E = atan( -1.0*f23/(f22*cos(R)) );
901 if(f22<0.0)
902 E+=F_PI;
905 rnElevationDeg = ::basegfx::fround( BaseGFXHelper::Rad2Deg( E ) );
906 rnRotationDeg = ::basegfx::fround( BaseGFXHelper::Rad2Deg( R ) );
909 double ThreeDHelper::getValueClippedToRange( double fAngle, const double& fPositivLimit )
911 if( fAngle<-1*fPositivLimit )
912 fAngle=-1*fPositivLimit;
913 else if( fAngle>fPositivLimit )
914 fAngle=fPositivLimit;
915 return fAngle;
918 double ThreeDHelper::getXDegreeAngleLimitForRightAngledAxes()
920 return 90.0;
923 double ThreeDHelper::getYDegreeAngleLimitForRightAngledAxes()
925 return 45.0;
928 void ThreeDHelper::adaptRadAnglesForRightAngledAxes( double& rfXAngleRad, double& rfYAngleRad )
930 rfXAngleRad = ThreeDHelper::getValueClippedToRange(rfXAngleRad, BaseGFXHelper::Deg2Rad(ThreeDHelper::getXDegreeAngleLimitForRightAngledAxes()) );
931 rfYAngleRad = ThreeDHelper::getValueClippedToRange(rfYAngleRad, BaseGFXHelper::Deg2Rad(ThreeDHelper::getYDegreeAngleLimitForRightAngledAxes()) );
934 void ThreeDHelper::getRotationAngleFromDiagram(
935 const Reference< beans::XPropertySet >& xSceneProperties, double& rfXAngleRad, double& rfYAngleRad, double& rfZAngleRad )
937 //takes the camera and the transformation matrix into account
939 rfXAngleRad = rfYAngleRad = rfZAngleRad = 0.0;
941 if( !xSceneProperties.is() )
942 return;
944 //get camera rotation
945 ::basegfx::B3DHomMatrix aFixCameraRotationMatrix( lcl_getCameraMatrix( xSceneProperties ) );
946 BaseGFXHelper::ReduceToRotationMatrix( aFixCameraRotationMatrix );
948 //get scene rotation
949 ::basegfx::B3DHomMatrix aSceneRotation;
951 drawing::HomogenMatrix aHomMatrix;
952 if( xSceneProperties->getPropertyValue( C2U("D3DTransformMatrix")) >>= aHomMatrix )
954 aSceneRotation = BaseGFXHelper::HomogenMatrixToB3DHomMatrix( aHomMatrix );
955 BaseGFXHelper::ReduceToRotationMatrix( aSceneRotation );
959 ::basegfx::B3DHomMatrix aResultRotation = aFixCameraRotationMatrix * aSceneRotation;
960 ::basegfx::B3DTuple aRotation( BaseGFXHelper::GetRotationFromMatrix( aResultRotation ) );
962 rfXAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(aRotation.getX());
963 rfYAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(aRotation.getY());
964 rfZAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(aRotation.getZ());
966 if(rfZAngleRad<(-F_PI/2) || rfZAngleRad>(F_PI/2))
968 rfZAngleRad-=F_PI;
969 rfXAngleRad-=F_PI;
970 rfYAngleRad=(F_PI-rfYAngleRad);
972 rfXAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(rfXAngleRad);
973 rfYAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(rfYAngleRad);
974 rfZAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(rfZAngleRad);
978 void ThreeDHelper::switchRightAngledAxes( const Reference< beans::XPropertySet >& xSceneProperties, sal_Bool bRightAngledAxes, bool bRotateLights )
982 if( xSceneProperties.is() )
984 sal_Bool bOldRightAngledAxes = sal_False;
985 xSceneProperties->getPropertyValue( C2U("RightAngledAxes")) >>= bOldRightAngledAxes;
986 if( bOldRightAngledAxes!=bRightAngledAxes)
988 xSceneProperties->setPropertyValue( C2U("RightAngledAxes"), uno::makeAny( bRightAngledAxes ));
989 if( bRotateLights )
991 if(bRightAngledAxes)
993 ::basegfx::B3DHomMatrix aInverseRotation( lcl_getInverseRotationMatrix( xSceneProperties ) );
994 lcl_rotateLights( aInverseRotation, xSceneProperties );
996 else
998 ::basegfx::B3DHomMatrix aCompleteRotation( lcl_getCompleteRotationMatrix( xSceneProperties ) );
999 lcl_rotateLights( aCompleteRotation, xSceneProperties );
1005 catch( const uno::Exception & ex )
1007 ASSERT_EXCEPTION( ex );
1011 void ThreeDHelper::setRotationAngleToDiagram(
1012 const Reference< beans::XPropertySet >& xSceneProperties
1013 , double fXAngleRad, double fYAngleRad, double fZAngleRad )
1015 //the rotation of the camera is not touched but taken into account
1016 //the rotation difference is applied to the transformation matrix
1018 //the light sources will be adapted also
1020 if( !xSceneProperties.is() )
1021 return;
1025 //remind old rotation for adaption of light directions
1026 ::basegfx::B3DHomMatrix aInverseOldRotation( lcl_getInverseRotationMatrix( xSceneProperties ) );
1028 ::basegfx::B3DHomMatrix aInverseCameraRotation;
1030 ::basegfx::B3DTuple aR( BaseGFXHelper::GetRotationFromMatrix(
1031 lcl_getCameraMatrix( xSceneProperties ) ) );
1032 aInverseCameraRotation.rotate( 0.0, 0.0, -aR.getZ() );
1033 aInverseCameraRotation.rotate( 0.0, -aR.getY(), 0.0 );
1034 aInverseCameraRotation.rotate( -aR.getX(), 0.0, 0.0 );
1037 ::basegfx::B3DHomMatrix aCumulatedRotation;
1038 aCumulatedRotation.rotate( fXAngleRad, fYAngleRad, fZAngleRad );
1040 //calculate new scene matrix
1041 ::basegfx::B3DHomMatrix aSceneRotation = aInverseCameraRotation*aCumulatedRotation;
1042 BaseGFXHelper::ReduceToRotationMatrix( aSceneRotation );
1044 //set new rotation to transformation matrix
1045 xSceneProperties->setPropertyValue(
1046 C2U("D3DTransformMatrix"), uno::makeAny( BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aSceneRotation )));
1048 //rotate lights if RightAngledAxes are not set or not supported
1049 sal_Bool bRightAngledAxes = sal_False;
1050 xSceneProperties->getPropertyValue( C2U("RightAngledAxes")) >>= bRightAngledAxes;
1051 uno::Reference< chart2::XDiagram > xDiagram( xSceneProperties, uno::UNO_QUERY );
1052 if(!bRightAngledAxes || !ChartTypeHelper::isSupportingRightAngledAxes(
1053 DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ) )
1055 ::basegfx::B3DHomMatrix aNewRotation;
1056 aNewRotation.rotate( fXAngleRad, fYAngleRad, fZAngleRad );
1057 lcl_rotateLights( aNewRotation*aInverseOldRotation, xSceneProperties );
1060 catch( const uno::Exception & ex )
1062 ASSERT_EXCEPTION( ex );
1066 void ThreeDHelper::getRotationFromDiagram( const uno::Reference< beans::XPropertySet >& xSceneProperties
1067 , sal_Int32& rnHorizontalAngleDegree, sal_Int32& rnVerticalAngleDegree )
1069 double fXAngle, fYAngle, fZAngle;
1070 ThreeDHelper::getRotationAngleFromDiagram( xSceneProperties, fXAngle, fYAngle, fZAngle );
1072 if( !lcl_isRightAngledAxesSetAndSupported( xSceneProperties ) )
1074 ThreeDHelper::convertXYZAngleRadToElevationRotationDeg(
1075 rnHorizontalAngleDegree, rnVerticalAngleDegree, fXAngle, fYAngle, fZAngle);
1076 rnVerticalAngleDegree*=-1;
1078 else
1080 fXAngle = BaseGFXHelper::Rad2Deg( fXAngle );
1081 fYAngle = BaseGFXHelper::Rad2Deg( fYAngle );
1082 fZAngle = BaseGFXHelper::Rad2Deg( fZAngle );
1084 rnHorizontalAngleDegree = ::basegfx::fround(fXAngle);
1085 rnVerticalAngleDegree = ::basegfx::fround(-1.0*fYAngle);
1086 //nZRotation = ::basegfx::fround(-1.0*fZAngle);
1089 lcl_shiftAngleToIntervalMinus180To180( rnHorizontalAngleDegree );
1090 lcl_shiftAngleToIntervalMinus180To180( rnVerticalAngleDegree );
1093 void ThreeDHelper::setRotationToDiagram( const uno::Reference< beans::XPropertySet >& xSceneProperties
1094 , sal_Int32 nHorizontalAngleDegree, sal_Int32 nVerticalYAngleDegree )
1096 //todo: x and y is not equal to horz and vert in case of RightAngledAxes==false
1097 double fXAngle = BaseGFXHelper::Deg2Rad( nHorizontalAngleDegree );
1098 double fYAngle = BaseGFXHelper::Deg2Rad( -1*nVerticalYAngleDegree );
1099 double fZAngle = 0.0;
1101 if( !lcl_isRightAngledAxesSetAndSupported( xSceneProperties ) )
1102 ThreeDHelper::convertElevationRotationDegToXYZAngleRad(
1103 nHorizontalAngleDegree, -1*nVerticalYAngleDegree, fXAngle, fYAngle, fZAngle );
1105 ThreeDHelper::setRotationAngleToDiagram( xSceneProperties, fXAngle, fYAngle, fZAngle );
1108 void ThreeDHelper::getCameraDistanceRange( double& rfMinimumDistance, double& rfMaximumDistance )
1110 rfMinimumDistance = 3.0/4.0*FIXED_SIZE_FOR_3D_CHART_VOLUME;//empiric value
1111 rfMaximumDistance = 20.0*FIXED_SIZE_FOR_3D_CHART_VOLUME;//empiric value
1114 void ThreeDHelper::ensureCameraDistanceRange( double& rfCameraDistance )
1116 double fMin, fMax;
1117 getCameraDistanceRange( fMin, fMax );
1118 if( rfCameraDistance < fMin )
1119 rfCameraDistance = fMin;
1120 if( rfCameraDistance > fMax )
1121 rfCameraDistance = fMax;
1124 double ThreeDHelper::getCameraDistance(
1125 const Reference< beans::XPropertySet >& xSceneProperties )
1127 double fCameraDistance = FIXED_SIZE_FOR_3D_CHART_VOLUME;
1129 if( !xSceneProperties.is() )
1130 return fCameraDistance;
1134 drawing::CameraGeometry aCG( ThreeDHelper::getDefaultCameraGeometry() );
1135 xSceneProperties->getPropertyValue( C2U( "D3DCameraGeometry" ) ) >>= aCG;
1136 ::basegfx::B3DVector aVRP( BaseGFXHelper::Position3DToB3DVector( aCG.vrp ) );
1137 fCameraDistance = aVRP.getLength();
1139 ensureCameraDistanceRange( fCameraDistance );
1141 catch( const uno::Exception & ex )
1143 ASSERT_EXCEPTION( ex );
1145 return fCameraDistance;
1148 void ThreeDHelper::setCameraDistance(
1149 const Reference< beans::XPropertySet >& xSceneProperties, double fCameraDistance )
1151 if( !xSceneProperties.is() )
1152 return;
1156 if( fCameraDistance <= 0 )
1157 fCameraDistance = FIXED_SIZE_FOR_3D_CHART_VOLUME;
1159 drawing::CameraGeometry aCG( ThreeDHelper::getDefaultCameraGeometry() );
1160 xSceneProperties->getPropertyValue( C2U( "D3DCameraGeometry" ) ) >>= aCG;
1161 ::basegfx::B3DVector aVRP( BaseGFXHelper::Position3DToB3DVector( aCG.vrp ) );
1162 if( ::basegfx::fTools::equalZero( aVRP.getLength() ) )
1163 aVRP = ::basegfx::B3DVector(0,0,1);
1164 aVRP.setLength(fCameraDistance);
1165 aCG.vrp = BaseGFXHelper::B3DVectorToPosition3D( aVRP );
1167 xSceneProperties->setPropertyValue( C2U("D3DCameraGeometry"), uno::makeAny( aCG ));
1169 catch( const uno::Exception & ex )
1171 ASSERT_EXCEPTION( ex );
1175 //static
1176 double ThreeDHelper::CameraDistanceToPerspective( double fCameraDistance )
1178 double fRet = fCameraDistance;
1179 double fMin, fMax;
1180 ThreeDHelper::getCameraDistanceRange( fMin, fMax );
1181 //fMax <-> 0; fMin <->100
1182 //a/x + b = y
1183 double a = 100.0*fMax*fMin/(fMax-fMin);
1184 double b = -a/fMax;
1186 fRet = a/fCameraDistance + b;
1188 return fRet;
1191 //static
1192 double ThreeDHelper::PerspectiveToCameraDistance( double fPerspective )
1194 double fRet = fPerspective;
1195 double fMin, fMax;
1196 ThreeDHelper::getCameraDistanceRange( fMin, fMax );
1197 //fMax <-> 0; fMin <->100
1198 //a/x + b = y
1199 double a = 100.0*fMax*fMin/(fMax-fMin);
1200 double b = -a/fMax;
1202 fRet = a/(fPerspective - b);
1204 return fRet;
1207 //static
1208 ThreeDLookScheme ThreeDHelper::detectScheme( const uno::Reference< XDiagram >& xDiagram )
1210 ThreeDLookScheme aScheme = ThreeDLookScheme_Unknown;
1212 sal_Int32 nRoundedEdges;
1213 sal_Int32 nObjectLines;
1214 ThreeDHelper::getRoundedEdgesAndObjectLines( xDiagram, nRoundedEdges, nObjectLines );
1216 //get shade mode and light settings:
1217 drawing::ShadeMode aShadeMode( drawing::ShadeMode_SMOOTH );
1218 uno::Reference< beans::XPropertySet > xDiagramProps( xDiagram, uno::UNO_QUERY );
1221 if( xDiagramProps.is() )
1222 xDiagramProps->getPropertyValue( C2U( "D3DSceneShadeMode" ) )>>= aShadeMode;
1224 catch( uno::Exception & ex )
1226 ASSERT_EXCEPTION( ex );
1229 if( lcl_isSimpleScheme( aShadeMode, nRoundedEdges, nObjectLines, xDiagram ) )
1231 if( lcl_isSimpleLightScheme(xDiagramProps) )
1232 aScheme = ThreeDLookScheme_Simple;
1234 else if( lcl_isRealisticScheme( aShadeMode, nRoundedEdges, nObjectLines ) )
1236 if( lcl_isRealisticLightScheme(xDiagramProps) )
1237 aScheme = ThreeDLookScheme_Realistic;
1240 return aScheme;
1243 void ThreeDHelper::setScheme( const uno::Reference< XDiagram >& xDiagram, ThreeDLookScheme aScheme )
1245 if( aScheme == ThreeDLookScheme_Unknown )
1246 return;
1248 drawing::ShadeMode aShadeMode;
1249 sal_Int32 nRoundedEdges;
1250 sal_Int32 nObjectLines;
1252 if( aScheme == ThreeDLookScheme_Simple )
1253 lcl_setSimpleScheme(aShadeMode,nRoundedEdges,nObjectLines,xDiagram);
1254 else
1255 lcl_setRealisticScheme(aShadeMode,nRoundedEdges,nObjectLines);
1259 ThreeDHelper::setRoundedEdgesAndObjectLines( xDiagram, nRoundedEdges, nObjectLines );
1261 uno::Reference< beans::XPropertySet > xProp( xDiagram, uno::UNO_QUERY );
1262 if( xProp.is() )
1264 drawing::ShadeMode aOldShadeMode;
1265 if( ! ( (xProp->getPropertyValue( C2U( "D3DSceneShadeMode" ) )>>=aOldShadeMode) &&
1266 aOldShadeMode == aShadeMode ))
1268 xProp->setPropertyValue( C2U( "D3DSceneShadeMode" ), uno::makeAny( aShadeMode ));
1272 lcl_setLightsForScheme( xProp, aScheme );
1274 catch( uno::Exception & ex )
1276 ASSERT_EXCEPTION( ex );
1281 //static
1282 void ThreeDHelper::set3DSettingsToDefault( const uno::Reference< beans::XPropertySet >& xSceneProperties )
1284 Reference< beans::XPropertyState > xState( xSceneProperties, uno::UNO_QUERY );
1285 if(xState.is())
1287 xState->setPropertyToDefault( C2U("D3DSceneDistance"));
1288 xState->setPropertyToDefault( C2U("D3DSceneFocalLength"));
1290 ThreeDHelper::setDefaultRotation( xSceneProperties );
1291 ThreeDHelper::setDefaultIllumination( xSceneProperties );
1294 //static
1295 void ThreeDHelper::setDefaultRotation( const uno::Reference< beans::XPropertySet >& xSceneProperties, bool bPieOrDonut )
1297 if( !xSceneProperties.is() )
1298 return;
1300 drawing::CameraGeometry aCameraGeo( ThreeDHelper::getDefaultCameraGeometry( bPieOrDonut ) );
1301 xSceneProperties->setPropertyValue( C2U("D3DCameraGeometry"), uno::makeAny( aCameraGeo ));
1303 ::basegfx::B3DHomMatrix aSceneRotation;
1304 if( bPieOrDonut )
1305 aSceneRotation.rotate( -F_PI/3.0, 0, 0 );
1306 xSceneProperties->setPropertyValue( C2U("D3DTransformMatrix"),
1307 uno::makeAny( BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aSceneRotation )));
1310 //static
1311 void ThreeDHelper::setDefaultRotation( const uno::Reference< beans::XPropertySet >& xSceneProperties )
1313 bool bPieOrDonut( DiagramHelper::isPieOrDonutChart( uno::Reference< XDiagram >(xSceneProperties, uno::UNO_QUERY) ) );
1314 ThreeDHelper::setDefaultRotation( xSceneProperties, bPieOrDonut );
1317 //static
1318 void ThreeDHelper::setDefaultIllumination( const uno::Reference< beans::XPropertySet >& xSceneProperties )
1320 if( !xSceneProperties.is() )
1321 return;
1323 drawing::ShadeMode aShadeMode( drawing::ShadeMode_SMOOTH );
1326 xSceneProperties->getPropertyValue( C2U( "D3DSceneShadeMode" ) )>>= aShadeMode;
1327 xSceneProperties->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_1 ), uno::makeAny( sal_False ) );
1328 xSceneProperties->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_3 ), uno::makeAny( sal_False ) );
1329 xSceneProperties->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_4 ), uno::makeAny( sal_False ) );
1330 xSceneProperties->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_5 ), uno::makeAny( sal_False ) );
1331 xSceneProperties->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_6 ), uno::makeAny( sal_False ) );
1332 xSceneProperties->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_7 ), uno::makeAny( sal_False ) );
1333 xSceneProperties->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_8 ), uno::makeAny( sal_False ) );
1335 catch( uno::Exception & ex )
1337 ASSERT_EXCEPTION( ex );
1340 ThreeDLookScheme aScheme = (drawing::ShadeMode_FLAT==aShadeMode) ? ThreeDLookScheme_Simple : ThreeDLookScheme_Realistic;
1341 lcl_setLightsForScheme( xSceneProperties, aScheme );
1344 //static
1345 void ThreeDHelper::getRoundedEdgesAndObjectLines(
1346 const uno::Reference< XDiagram > & xDiagram
1347 , sal_Int32& rnRoundedEdges, sal_Int32& rnObjectLines )
1349 rnRoundedEdges = -1;
1350 rnObjectLines = -1;
1353 bool bDifferentRoundedEdges = false;
1354 bool bDifferentObjectLines = false;
1356 drawing::LineStyle aLineStyle( drawing::LineStyle_SOLID );
1358 ::std::vector< uno::Reference< XDataSeries > > aSeriesList(
1359 DiagramHelper::getDataSeriesFromDiagram( xDiagram ) );
1360 sal_Int32 nSeriesCount = static_cast<sal_Int32>( aSeriesList.size() );
1362 rtl::OUString aPercentDiagonalPropertyName( C2U( "PercentDiagonal" ) );
1363 rtl::OUString aBorderStylePropertyName( C2U( "BorderStyle" ) );
1365 for( sal_Int32 nS = 0; nS < nSeriesCount; ++nS )
1367 uno::Reference< XDataSeries > xSeries( aSeriesList[nS] );
1368 uno::Reference< beans::XPropertySet > xProp( xSeries, uno::UNO_QUERY );
1369 if(!nS)
1371 rnRoundedEdges = 0;
1374 sal_Int16 nPercentDiagonal = 0;
1376 xProp->getPropertyValue( aPercentDiagonalPropertyName ) >>= nPercentDiagonal;
1377 rnRoundedEdges = static_cast< sal_Int32 >( nPercentDiagonal );
1379 if( DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries
1380 , aPercentDiagonalPropertyName, uno::makeAny(nPercentDiagonal) ) )
1381 bDifferentRoundedEdges = true;
1383 catch( uno::Exception& e )
1385 ASSERT_EXCEPTION( e );
1386 bDifferentRoundedEdges = true;
1390 xProp->getPropertyValue( aBorderStylePropertyName ) >>= aLineStyle;
1392 if( DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries
1393 , aBorderStylePropertyName, uno::makeAny(aLineStyle) ) )
1394 bDifferentObjectLines = true;
1396 catch( uno::Exception& e )
1398 ASSERT_EXCEPTION( e );
1399 bDifferentObjectLines = true;
1402 else
1404 if( !bDifferentRoundedEdges )
1406 sal_Int16 nPercentDiagonal = 0;
1407 xProp->getPropertyValue( aPercentDiagonalPropertyName ) >>= nPercentDiagonal;
1408 sal_Int32 nCurrentRoundedEdges = static_cast< sal_Int32 >( nPercentDiagonal );
1409 if(nCurrentRoundedEdges!=rnRoundedEdges
1410 || DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries
1411 , aPercentDiagonalPropertyName, uno::makeAny( static_cast< sal_Int16 >(rnRoundedEdges) ) ) )
1413 bDifferentRoundedEdges = true;
1414 nCurrentRoundedEdges = -1;
1418 if( !bDifferentObjectLines )
1420 drawing::LineStyle aCurrentLineStyle;
1421 xProp->getPropertyValue( aBorderStylePropertyName ) >>= aCurrentLineStyle;
1422 if(aCurrentLineStyle!=aLineStyle
1423 || DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries
1424 , aBorderStylePropertyName, uno::makeAny(aLineStyle) ) )
1425 bDifferentObjectLines = true;
1428 if( bDifferentRoundedEdges && bDifferentObjectLines )
1429 break;
1432 //set rnObjectLines
1433 rnObjectLines = 0;
1434 if( bDifferentObjectLines )
1435 rnObjectLines = -1;
1436 else if( aLineStyle == drawing::LineStyle_SOLID )
1437 rnObjectLines = 1;
1439 catch( uno::Exception& e )
1441 ASSERT_EXCEPTION( e );
1444 //static
1445 void ThreeDHelper::setRoundedEdgesAndObjectLines(
1446 const uno::Reference< XDiagram > & xDiagram
1447 , sal_Int32 nRoundedEdges, sal_Int32 nObjectLines )
1449 if( (nRoundedEdges<0||nRoundedEdges>100) && nObjectLines!=0 && nObjectLines!=1 )
1450 return;
1452 drawing::LineStyle aLineStyle( drawing::LineStyle_NONE );
1453 if(nObjectLines==1)
1454 aLineStyle = drawing::LineStyle_SOLID;
1456 uno::Any aALineStyle( uno::makeAny(aLineStyle));
1457 uno::Any aARoundedEdges( uno::makeAny( static_cast< sal_Int16 >( nRoundedEdges )));
1459 ::std::vector< uno::Reference< XDataSeries > > aSeriesList(
1460 DiagramHelper::getDataSeriesFromDiagram( xDiagram ) );
1461 sal_Int32 nSeriesCount = static_cast<sal_Int32>( aSeriesList.size() );
1462 for( sal_Int32 nS = 0; nS < nSeriesCount; ++nS )
1464 uno::Reference< XDataSeries > xSeries( aSeriesList[nS] );
1466 if( nRoundedEdges>=0 && nRoundedEdges<=100 )
1467 DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, C2U( "PercentDiagonal" ), aARoundedEdges );
1469 if( nObjectLines==0 || nObjectLines==1 )
1470 DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, C2U( "BorderStyle" ), aALineStyle );
1474 //static
1475 CuboidPlanePosition ThreeDHelper::getAutomaticCuboidPlanePositionForStandardLeftWall( const Reference< beans::XPropertySet >& xSceneProperties )
1477 CuboidPlanePosition eRet(CuboidPlanePosition_Left);
1479 double fXAngleRad=0.0; double fYAngleRad=0.0; double fZAngleRad=0.0;
1480 ThreeDHelper::getRotationAngleFromDiagram( xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad );
1481 if( lcl_isRightAngledAxesSetAndSupported( xSceneProperties ) )
1483 ThreeDHelper::adaptRadAnglesForRightAngledAxes( fXAngleRad, fYAngleRad );
1484 fZAngleRad=0.0;
1486 if( sin(fYAngleRad)>0.0 )
1487 eRet = CuboidPlanePosition_Right;
1488 return eRet;
1491 //static
1492 CuboidPlanePosition ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBackWall( const Reference< beans::XPropertySet >& xSceneProperties )
1494 CuboidPlanePosition eRet(CuboidPlanePosition_Back);
1496 double fXAngleRad=0.0; double fYAngleRad=0.0; double fZAngleRad=0.0;
1497 ThreeDHelper::getRotationAngleFromDiagram( xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad );
1498 if( lcl_isRightAngledAxesSetAndSupported( xSceneProperties ) )
1500 ThreeDHelper::adaptRadAnglesForRightAngledAxes( fXAngleRad, fYAngleRad );
1501 fZAngleRad=0.0;
1503 if( cos(fXAngleRad)*cos(fYAngleRad)<0.0 )
1504 eRet = CuboidPlanePosition_Front;
1505 return eRet;
1508 //static
1509 CuboidPlanePosition ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBottom( const Reference< beans::XPropertySet >& xSceneProperties )
1511 CuboidPlanePosition eRet(CuboidPlanePosition_Bottom);
1513 double fXAngleRad=0.0; double fYAngleRad=0.0; double fZAngleRad=0.0;
1514 ThreeDHelper::getRotationAngleFromDiagram( xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad );
1515 if( lcl_isRightAngledAxesSetAndSupported( xSceneProperties ) )
1517 ThreeDHelper::adaptRadAnglesForRightAngledAxes( fXAngleRad, fYAngleRad );
1518 fZAngleRad=0.0;
1520 if( sin(fXAngleRad)*cos(fYAngleRad)<0.0 )
1521 eRet = CuboidPlanePosition_Top;
1522 return eRet;
1525 //.............................................................................
1526 } //namespace chart
1527 //.............................................................................