update dev300-m58
[ooovba.git] / chart2 / source / tools / ThreeDHelper.cxx
blobd94a28eca5b3a60ce0680f1954a14d99a52cb58f
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: ThreeDHelper.cxx,v $
10 * $Revision: 1.6 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_chart2.hxx"
34 #include "ThreeDHelper.hxx"
35 #include "macros.hxx"
36 #include "DiagramHelper.hxx"
37 #include "ChartTypeHelper.hxx"
38 #include "BaseGFXHelper.hxx"
39 #include "DataSeriesHelper.hxx"
40 #include <svx/unoprnms.hxx>
41 #include <com/sun/star/beans/XPropertyState.hpp>
42 #include <com/sun/star/chart2/XDiagram.hpp>
43 #include <com/sun/star/drawing/LineStyle.hpp>
45 #include <tools/debug.hxx>
47 //.............................................................................
48 namespace chart
50 //.............................................................................
51 using namespace ::com::sun::star;
52 using namespace ::com::sun::star::chart2;
54 using ::com::sun::star::uno::Reference;
55 using ::com::sun::star::uno::Sequence;
56 using ::rtl::OUString;
57 using ::rtl::math::cos;
58 using ::rtl::math::sin;
59 using ::rtl::math::tan;
61 #define FIXED_SIZE_FOR_3D_CHART_VOLUME (10000.0)
63 namespace
66 bool lcl_isRightAngledAxesSetAndSupported( const Reference< beans::XPropertySet >& xSceneProperties )
68 sal_Bool bRightAngledAxes = sal_False;
69 if( xSceneProperties.is() )
71 xSceneProperties->getPropertyValue( C2U("RightAngledAxes")) >>= bRightAngledAxes;
72 if(bRightAngledAxes)
74 uno::Reference< chart2::XDiagram > xDiagram( xSceneProperties, uno::UNO_QUERY );
75 if( ChartTypeHelper::isSupportingRightAngledAxes(
76 DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ) )
78 return true;
82 return false;
85 void lcl_RotateLightSource( const Reference< beans::XPropertySet >& xSceneProperties
86 , const OUString& rLightSourceDirection
87 , const OUString& rLightSourceOn
88 , const ::basegfx::B3DHomMatrix& rRotationMatrix )
90 if( xSceneProperties.is() )
92 sal_Bool bLightOn = sal_False;
93 if( xSceneProperties->getPropertyValue( rLightSourceOn ) >>= bLightOn )
95 if( bLightOn )
97 drawing::Direction3D aLight;
98 if( xSceneProperties->getPropertyValue( rLightSourceDirection ) >>= aLight )
100 ::basegfx::B3DVector aLightVector( BaseGFXHelper::Direction3DToB3DVector( aLight ) );
101 aLightVector = rRotationMatrix*aLightVector;
103 xSceneProperties->setPropertyValue( rLightSourceDirection
104 , uno::makeAny( BaseGFXHelper::B3DVectorToDirection3D( aLightVector ) ) );
111 void lcl_rotateLights( const ::basegfx::B3DHomMatrix& rLightRottion, const Reference< beans::XPropertySet >& xSceneProperties )
113 if(!xSceneProperties.is())
114 return;
116 ::basegfx::B3DHomMatrix aLightRottion( rLightRottion );
117 BaseGFXHelper::ReduceToRotationMatrix( aLightRottion );
119 lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection1"), C2U("D3DSceneLightOn1"), aLightRottion );
120 lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection2"), C2U("D3DSceneLightOn2"), aLightRottion );
121 lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection3"), C2U("D3DSceneLightOn3"), aLightRottion );
122 lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection4"), C2U("D3DSceneLightOn4"), aLightRottion );
123 lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection5"), C2U("D3DSceneLightOn5"), aLightRottion );
124 lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection6"), C2U("D3DSceneLightOn6"), aLightRottion );
125 lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection7"), C2U("D3DSceneLightOn7"), aLightRottion );
126 lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection8"), C2U("D3DSceneLightOn8"), aLightRottion );
129 ::basegfx::B3DHomMatrix lcl_getInverseRotationMatrix( const Reference< beans::XPropertySet >& xSceneProperties )
131 ::basegfx::B3DHomMatrix aInverseRotation;
132 double fXAngleRad=0.0;
133 double fYAngleRad=0.0;
134 double fZAngleRad=0.0;
135 ThreeDHelper::getRotationAngleFromDiagram(
136 xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad );
137 aInverseRotation.rotate( 0.0, 0.0, -fZAngleRad );
138 aInverseRotation.rotate( 0.0, -fYAngleRad, 0.0 );
139 aInverseRotation.rotate( -fXAngleRad, 0.0, 0.0 );
140 return aInverseRotation;
143 ::basegfx::B3DHomMatrix lcl_getCompleteRotationMatrix( const Reference< beans::XPropertySet >& xSceneProperties )
145 ::basegfx::B3DHomMatrix aCompleteRotation;
146 double fXAngleRad=0.0;
147 double fYAngleRad=0.0;
148 double fZAngleRad=0.0;
149 ThreeDHelper::getRotationAngleFromDiagram(
150 xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad );
151 aCompleteRotation.rotate( fXAngleRad, fYAngleRad, fZAngleRad );
152 return aCompleteRotation;
155 bool lcl_isEqual( const drawing::Direction3D& rA, const drawing::Direction3D& rB )
157 return ::rtl::math::approxEqual(rA.DirectionX, rB.DirectionX)
158 && ::rtl::math::approxEqual(rA.DirectionY, rB.DirectionY)
159 && ::rtl::math::approxEqual(rA.DirectionZ, rB.DirectionZ);
162 bool lcl_isLightScheme( const uno::Reference< beans::XPropertySet >& xDiagramProps, bool bRealistic )
164 if(!xDiagramProps.is())
165 return false;
167 sal_Bool bIsOn = sal_False;
168 xDiagramProps->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_2 ) ) >>= bIsOn;
169 if(!bIsOn)
170 return false;
172 uno::Reference< chart2::XDiagram > xDiagram( xDiagramProps, uno::UNO_QUERY );
173 uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) );
175 sal_Int32 nColor = 0;
176 xDiagramProps->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_2 ) ) >>= nColor;
177 if( nColor != ::chart::ChartTypeHelper::getDefaultDirectLightColor( !bRealistic, xChartType ) )
178 return false;
180 sal_Int32 nAmbientColor = 0;
181 xDiagramProps->getPropertyValue( C2U( UNO_NAME_3D_SCENE_AMBIENTCOLOR ) ) >>= nAmbientColor;
182 if( nAmbientColor != ::chart::ChartTypeHelper::getDefaultAmbientLightColor( !bRealistic, xChartType ) )
183 return false;
185 drawing::Direction3D aDirection(0,0,0);
186 xDiagramProps->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_2 ) ) >>= aDirection;
188 drawing::Direction3D aDefaultDirection( bRealistic
189 ? ChartTypeHelper::getDefaultRealisticLightDirection(xChartType)
190 : ChartTypeHelper::getDefaultSimpleLightDirection(xChartType) );
192 //rotate default light direction when right angled axes are off but supported
194 sal_Bool bRightAngledAxes = sal_False;
195 xDiagramProps->getPropertyValue( C2U("RightAngledAxes")) >>= bRightAngledAxes;
196 if(!bRightAngledAxes)
198 if( ChartTypeHelper::isSupportingRightAngledAxes(
199 DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ) )
201 ::basegfx::B3DHomMatrix aRotation( lcl_getCompleteRotationMatrix( xDiagramProps ) );
202 BaseGFXHelper::ReduceToRotationMatrix( aRotation );
203 ::basegfx::B3DVector aLightVector( BaseGFXHelper::Direction3DToB3DVector( aDefaultDirection ) );
204 aLightVector = aRotation*aLightVector;
205 aDefaultDirection = BaseGFXHelper::B3DVectorToDirection3D( aLightVector );
210 return lcl_isEqual( aDirection, aDefaultDirection );
213 bool lcl_isRealisticLightScheme( const uno::Reference< beans::XPropertySet >& xDiagramProps )
215 return lcl_isLightScheme( xDiagramProps, true /*bRealistic*/ );
217 bool lcl_isSimpleLightScheme( const uno::Reference< beans::XPropertySet >& xDiagramProps )
219 return lcl_isLightScheme( xDiagramProps, false /*bRealistic*/ );
221 void lcl_setLightsForScheme( const uno::Reference< beans::XPropertySet >& xDiagramProps, const ThreeDLookScheme& rScheme )
223 if(!xDiagramProps.is())
224 return;
225 if( rScheme == ThreeDLookScheme_Unknown)
226 return;
228 xDiagramProps->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_2 ), uno::makeAny( sal_True ) );
230 uno::Reference< chart2::XDiagram > xDiagram( xDiagramProps, uno::UNO_QUERY );
231 uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) );
232 uno::Any aADirection( uno::makeAny( rScheme == ThreeDLookScheme_Simple
233 ? ChartTypeHelper::getDefaultSimpleLightDirection(xChartType)
234 : ChartTypeHelper::getDefaultRealisticLightDirection(xChartType) ) );
236 xDiagramProps->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_2 ), aADirection );
237 //rotate light direction when right angled axes are off but supported
239 sal_Bool bRightAngledAxes = sal_False;
240 xDiagramProps->getPropertyValue( C2U("RightAngledAxes")) >>= bRightAngledAxes;
241 if(!bRightAngledAxes)
243 if( ChartTypeHelper::isSupportingRightAngledAxes( xChartType ) )
245 ::basegfx::B3DHomMatrix aRotation( lcl_getCompleteRotationMatrix( xDiagramProps ) );
246 BaseGFXHelper::ReduceToRotationMatrix( aRotation );
247 lcl_RotateLightSource( xDiagramProps, C2U("D3DSceneLightDirection2"), C2U("D3DSceneLightOn2"), aRotation );
252 sal_Int32 nColor = ::chart::ChartTypeHelper::getDefaultDirectLightColor( rScheme==ThreeDLookScheme_Simple, xChartType );
253 xDiagramProps->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_2 ), uno::makeAny( nColor ) );
255 sal_Int32 nAmbientColor = ::chart::ChartTypeHelper::getDefaultAmbientLightColor( rScheme==ThreeDLookScheme_Simple, xChartType );
256 xDiagramProps->setPropertyValue( C2U( UNO_NAME_3D_SCENE_AMBIENTCOLOR ), uno::makeAny( nAmbientColor ) );
259 bool lcl_isRealisticScheme( drawing::ShadeMode aShadeMode
260 , sal_Int32 nRoundedEdges
261 , sal_Int32 nObjectLines )
263 if(aShadeMode!=drawing::ShadeMode_SMOOTH)
264 return false;
265 if(nRoundedEdges!=5)
266 return false;
267 if(nObjectLines!=0)
268 return false;
269 return true;
272 bool lcl_isSimpleScheme( drawing::ShadeMode aShadeMode
273 , sal_Int32 nRoundedEdges
274 , sal_Int32 nObjectLines
275 , const uno::Reference< XDiagram >& xDiagram )
277 if(aShadeMode!=drawing::ShadeMode_FLAT)
278 return false;
279 if(nRoundedEdges!=0)
280 return false;
281 if(nObjectLines==0)
283 uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) );
284 return ChartTypeHelper::noBordersForSimpleScheme( xChartType );
286 if(nObjectLines!=1)
287 return false;
288 return true;
291 void lcl_setRealisticScheme( drawing::ShadeMode& rShadeMode
292 , sal_Int32& rnRoundedEdges
293 , sal_Int32& rnObjectLines )
295 rShadeMode = drawing::ShadeMode_SMOOTH;
296 rnRoundedEdges = 5;
297 rnObjectLines = 0;
300 void lcl_setSimpleScheme( drawing::ShadeMode& rShadeMode
301 , sal_Int32& rnRoundedEdges
302 , sal_Int32& rnObjectLines
303 , const uno::Reference< XDiagram >& xDiagram )
305 rShadeMode = drawing::ShadeMode_FLAT;
306 rnRoundedEdges = 0;
308 uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) );
309 rnObjectLines = ChartTypeHelper::noBordersForSimpleScheme( xChartType ) ? 0 : 1;
312 } //end anonymous namespace
315 drawing::CameraGeometry ThreeDHelper::getDefaultCameraGeometry( bool bPie )
317 // ViewReferencePoint (Point on the View plane)
318 drawing::Position3D vrp(17634.6218373783, 10271.4823817647, 24594.8639082739);
319 // ViewPlaneNormal (Normal to the View Plane)
320 drawing::Direction3D vpn(0.416199821709347, 0.173649045905254, 0.892537795986984);
321 // ViewUpVector (determines the v-axis direction on the view plane as
322 // projection of VUP parallel to VPN onto th view pane)
323 drawing::Direction3D vup(-0.0733876362771618, 0.984807599917971, -0.157379306090273);
325 if( bPie )
327 vrp = drawing::Position3D( 0.0, 0.0, 87591.2408759124 );//--> 5 percent perspecitve
328 vpn = drawing::Direction3D( 0.0, 0.0, 1.0 );
329 vup = drawing::Direction3D( 0.0, 1.0, 0.0 );
332 return drawing::CameraGeometry( vrp, vpn, vup );
335 namespace
337 ::basegfx::B3DHomMatrix lcl_getCameraMatrix( const uno::Reference< beans::XPropertySet >& xSceneProperties )
339 drawing::HomogenMatrix aCameraMatrix;
341 drawing::CameraGeometry aCG( ThreeDHelper::getDefaultCameraGeometry() );
342 if( xSceneProperties.is() )
343 xSceneProperties->getPropertyValue( C2U( "D3DCameraGeometry" ) ) >>= aCG;
345 ::basegfx::B3DVector aVPN( BaseGFXHelper::Direction3DToB3DVector( aCG.vpn ) );
346 ::basegfx::B3DVector aVUP( BaseGFXHelper::Direction3DToB3DVector( aCG.vup ) );
348 //normalize vectors:
349 aVPN.normalize();
350 aVUP.normalize();
352 ::basegfx::B3DVector aCross = ::basegfx::cross( aVUP, aVPN );
354 //first line is VUP x VPN
355 aCameraMatrix.Line1.Column1 = aCross[0];
356 aCameraMatrix.Line1.Column2 = aCross[1];
357 aCameraMatrix.Line1.Column3 = aCross[2];
358 aCameraMatrix.Line1.Column4 = 0.0;
360 //second line is VUP
361 aCameraMatrix.Line2.Column1 = aVUP[0];
362 aCameraMatrix.Line2.Column2 = aVUP[1];
363 aCameraMatrix.Line2.Column3 = aVUP[2];
364 aCameraMatrix.Line2.Column4 = 0.0;
366 //third line is VPN
367 aCameraMatrix.Line3.Column1 = aVPN[0];
368 aCameraMatrix.Line3.Column2 = aVPN[1];
369 aCameraMatrix.Line3.Column3 = aVPN[2];
370 aCameraMatrix.Line3.Column4 = 0.0;
372 //fourth line is 0 0 0 1
373 aCameraMatrix.Line4.Column1 = 0.0;
374 aCameraMatrix.Line4.Column2 = 0.0;
375 aCameraMatrix.Line4.Column3 = 0.0;
376 aCameraMatrix.Line4.Column4 = 1.0;
378 return BaseGFXHelper::HomogenMatrixToB3DHomMatrix( aCameraMatrix );
381 double lcl_shiftAngleToIntervalMinusPiToPi( double fAngleRad )
383 //valid range: ]-Pi,Pi]
384 while( fAngleRad<=-F_PI )
385 fAngleRad+=(2*F_PI);
386 while( fAngleRad>F_PI )
387 fAngleRad-=(2*F_PI);
388 return fAngleRad;
391 void lcl_shiftAngleToIntervalMinus180To180( sal_Int32& rnAngleDegree )
393 //valid range: ]-180,180]
394 while( rnAngleDegree<=-180 )
395 rnAngleDegree+=360;
396 while( rnAngleDegree>180 )
397 rnAngleDegree-=360;
400 void lcl_shiftAngleToIntervalZeroTo360( sal_Int32& rnAngleDegree )
402 //valid range: [0,360[
403 while( rnAngleDegree<0 )
404 rnAngleDegree+=360;
405 while( rnAngleDegree>=360 )
406 rnAngleDegree-=360;
409 void lcl_ensureIntervalMinus1To1( double& rSinOrCos )
411 if (rSinOrCos < -1.0)
412 rSinOrCos = -1.0;
413 else if (rSinOrCos > 1.0)
414 rSinOrCos = 1.0;
417 bool lcl_isSinZero( double fAngleRad )
419 return ::basegfx::fTools::equalZero( sin(fAngleRad), 0.0000001 );
421 bool lcl_isCosZero( double fAngleRad )
423 return ::basegfx::fTools::equalZero( cos(fAngleRad), 0.0000001 );
428 void ThreeDHelper::convertElevationRotationDegToXYZAngleRad(
429 sal_Int32 nElevationDeg, sal_Int32 nRotationDeg,
430 double& rfXAngleRad, double& rfYAngleRad, double& rfZAngleRad)
432 // for a description of the algorithm see issue 72994
433 //http://www.openoffice.org/issues/show_bug.cgi?id=72994
434 //http://www.openoffice.org/nonav/issues/showattachment.cgi/50608/DescriptionCorrected.odt
436 lcl_shiftAngleToIntervalZeroTo360( nElevationDeg );
437 lcl_shiftAngleToIntervalZeroTo360( nRotationDeg );
439 double& x = rfXAngleRad;
440 double& y = rfYAngleRad;
441 double& z = rfZAngleRad;
443 double E = F_PI*nElevationDeg/180; //elevation in Rad
444 double R = F_PI*nRotationDeg/180; //rotation in Rad
446 if( (nRotationDeg == 0 || nRotationDeg == 180 )
447 && ( nElevationDeg == 90 || nElevationDeg == 270 ) )
449 //sR==0 && cE==0
450 z = 0.0;
451 //element 23
452 double f23 = cos(R)*sin(E);
453 if(f23>0)
454 x = F_PI/2;
455 else
456 x = -F_PI/2;
457 y = R;
459 else if( ( nRotationDeg == 90 || nRotationDeg == 270 )
460 && ( nElevationDeg == 90 || nElevationDeg == 270 ) )
462 //cR==0 && cE==0
463 z = F_PI/2;
464 if( sin(R)>0 )
465 x = F_PI/2.0;
466 else
467 x = -F_PI/2.0;
469 if( (sin(R)*sin(E))>0 )
470 y = 0.0;
471 else
472 y = F_PI;
474 else if( (nRotationDeg == 0 || nRotationDeg == 180 )
475 && ( nElevationDeg == 0 || nElevationDeg == 180 ) )
477 //sR==0 && sE==0
478 z = 0.0;
479 y = R;
480 x = E;
482 else if( ( nRotationDeg == 90 || nRotationDeg == 270 )
483 && ( nElevationDeg == 0 || nElevationDeg == 180 ) )
485 //cR==0 && sE==0
486 z = 0.0;
488 if( (sin(R)/cos(E))>0 )
489 y = F_PI/2;
490 else
491 y = -F_PI/2;
493 if( (cos(E))>0 )
494 x = 0;
495 else
496 x = F_PI;
498 else if ( nElevationDeg == 0 || nElevationDeg == 180 )
500 //sR!=0 cR!=0 sE==0
501 z = 0.0;
502 x = E;
503 y = R;
504 //use element 13 for sign
505 if((cos(x)*sin(y)*sin(R))<0.0)
506 y *= -1.0;
508 else if ( nElevationDeg == 90 || nElevationDeg == 270 )
510 //sR!=0 cR!=0 cE==0
511 //element 12 + 22 --> y=0 or F_PI and x=+-F_PI/2
512 //-->element 13/23:
513 z = atan(sin(R)/(cos(R)*sin(E)));
514 //use element 13 for sign for x
515 if( (sin(R)*sin(z))>0.0 )
516 x = F_PI/2;
517 else
518 x = -F_PI/2;
519 //use element 21 for y
520 if( (sin(R)*sin(E)*sin(z))>0.0)
521 y = 0.0;
522 else
523 y = F_PI;
525 else if ( nRotationDeg == 0 || nRotationDeg == 180 )
527 //sE!=0 cE!=0 sR==0
528 z = 0.0;
529 x = E;
530 y = R;
531 double f23 = cos(R)*sin(E);
532 if( (f23 * sin(x)) < 0.0 )
533 x *= -1.0; //todo ??
535 else if (nRotationDeg == 90 || nRotationDeg == 270)
537 //sE!=0 cE!=0 cR==0
538 //z = +- F_PI/2;
539 //x = +- F_PI/2;
540 z = F_PI/2;
541 x = F_PI/2;
542 double sR = sin(R);
543 if( sR<0.0 )
544 x *= -1.0; //different signs for x and z
546 //use element 21:
547 double cy = sR*sin(E)/sin(z);
548 lcl_ensureIntervalMinus1To1(cy);
549 y = acos(cy);
551 //use element 22 for sign:
552 if( (sin(x)*sin(y)*sin(z)*cos(E))<0.0)
553 y *= -1.0;
555 else
557 z = atan(tan(R) * sin(E));
558 if(cos(z)==0.0)
560 DBG_ERROR("calculation error in ThreeDHelper::convertElevationRotationDegToXYZAngleRad");
561 return;
563 double cy = cos(R)/cos(z);
564 lcl_ensureIntervalMinus1To1(cy);
565 y = acos(cy);
567 //element 12 in 23
568 double fDenominator = cos(z)*(1.0-pow(sin(y),2));
569 if(fDenominator==0.0)
571 DBG_ERROR("calculation error in ThreeDHelper::convertElevationRotationDegToXYZAngleRad");
572 return;
574 double sx = cos(R)*sin(E)/fDenominator;
575 lcl_ensureIntervalMinus1To1(sx);
576 x = asin( sx );
578 //use element 13 for sign:
579 double f13a = cos(x)*cos(z)*sin(y);
580 double f13b = sin(R)-sx*sin(z);
581 if( (f13b*f13a)<0.0 )
583 //change x or y
584 //use element 22 for further investigations:
585 //try
586 y *= -1;
587 double f22a = cos(x)*cos(z);
588 double f22b = cos(E)-(sx*sin(y)*sin(z));
589 if( (f22a*f22b)<0.0 )
591 y *= -1;
592 x=(F_PI-x);
595 else
597 //change nothing or both
598 //use element 22 for further investigations:
599 double f22a = cos(x)*cos(z);
600 double f22b = cos(E)-(sx*sin(y)*sin(z));
601 if( (f22a*f22b)<0.0 )
603 y *= -1;
604 x=(F_PI-x);
610 void ThreeDHelper::convertXYZAngleRadToElevationRotationDeg(
611 sal_Int32& rnElevationDeg, sal_Int32& rnRotationDeg,
612 double fXRad, double fYRad, double fZRad)
614 // for a description of the algorithm see issue 72994
615 //http://www.openoffice.org/issues/show_bug.cgi?id=72994
616 //http://www.openoffice.org/nonav/issues/showattachment.cgi/50608/DescriptionCorrected.odt
618 double R = 0.0; //Rotation in Rad
619 double E = 0.0; //Elevation in Rad
621 double& x = fXRad;
622 double& y = fYRad;
623 double& z = fZRad;
625 double f11 = cos(y)*cos(z);
627 if( lcl_isSinZero(y) )
629 //siny == 0
631 if( lcl_isCosZero(x) )
633 //siny == 0 && cosx == 0
635 if( lcl_isSinZero(z) )
637 //siny == 0 && cosx == 0 && sinz == 0
638 //example: x=+-90 y=0oder180 z=0(oder180)
640 //element 13+11
641 if( f11 > 0 )
642 R = 0.0;
643 else
644 R = F_PI;
646 //element 23
647 double f23 = cos(z)*sin(x) / cos(R);
648 if( f23 > 0 )
649 E = F_PI/2.0;
650 else
651 E = -F_PI/2.0;
653 else if( lcl_isCosZero(z) )
655 //siny == 0 && cosx == 0 && cosz == 0
656 //example: x=+-90 y=0oder180 z=+-90
658 double f13 = sin(x)*sin(z);
659 //element 13+11
660 if( f13 > 0 )
661 R = F_PI/2.0;
662 else
663 R = -F_PI/2.0;
665 //element 21
666 double f21 = cos(y)*sin(z) / sin(R);
667 if( f21 > 0 )
668 E = F_PI/2.0;
669 else
670 E = -F_PI/2.0;
672 else
674 //siny == 0 && cosx == 0 && cosz != 0 && sinz != 0
675 //element 11 && 13
676 double f13 = sin(x)*sin(z);
677 R = atan( f13/f11 );
679 if(f11<0)
680 R+=F_PI;
682 //element 23
683 double f23 = cos(z)*sin(x);
684 if( f23/cos(R) > 0 )
685 E = F_PI/2.0;
686 else
687 E = -F_PI/2.0;
690 else if( lcl_isSinZero(x) )
692 //sinY==0 sinX==0
693 //element 13+11
694 if( f11 > 0 )
695 R = 0.0;
696 else
697 R = F_PI;
699 double f22 = cos(x)*cos(z);
700 if( f22 > 0 )
701 E = 0.0;
702 else
703 E = F_PI;
705 else if( lcl_isSinZero(z) )
707 //sinY==0 sinZ==0 sinx!=0 cosx!=0
708 //element 13+11
709 if( f11 > 0 )
710 R = 0.0;
711 else
712 R = F_PI;
714 //element 22 && 23
715 double f22 = cos(x)*cos(z);
716 double f23 = cos(z)*sin(x);
717 E = atan( f23/(f22*cos(R)) );
718 if( (f22*cos(E))<0 )
719 E+=F_PI;
721 else if( lcl_isCosZero(z) )
723 //sinY == 0 && cosZ == 0 && cosx != 0 && sinx != 0
724 double f13 = sin(x)*sin(z);
725 //element 13+11
726 if( f13 > 0 )
727 R = F_PI/2.0;
728 else
729 R = -F_PI/2.0;
731 //element 21+22
732 double f21 = cos(y)*sin(z);
733 if( f21/sin(R) > 0 )
734 E = F_PI/2.0;
735 else
736 E = -F_PI/2.0;
738 else
740 //sinY == 0 && all other !=0
741 double f13 = sin(x)*sin(z);
742 R = atan( f13/f11 );
743 if( (f11*cos(R))<0.0 )
744 R+=F_PI;
746 double f22 = cos(x)*cos(z);
747 if( !lcl_isCosZero(R) )
748 E = atan( cos(z)*sin(x) /( f22*cos(R) ) );
749 else
750 E = atan( cos(y)*sin(z) /( f22*sin(R) ) );
751 if( (f22*cos(E))<0 )
752 E+=F_PI;
755 else if( lcl_isCosZero(y) )
757 //cosY==0
759 double f13 = sin(x)*sin(z)+cos(x)*cos(z)*sin(y);
760 if( f13 >= 0 )
761 R = F_PI/2.0;
762 else
763 R = -F_PI/2.0;
765 double f22 = cos(x)*cos(z)+sin(x)*sin(y)*sin(z);
766 if( f22 >= 0 )
767 E = 0.0;
768 else
769 E = F_PI;
771 else if( lcl_isSinZero(x) )
773 //cosY!=0 sinY!=0 sinX=0
774 if( lcl_isSinZero(z) )
776 //cosY!=0 sinY!=0 sinX=0 sinZ=0
777 double f13 = cos(x)*cos(z)*sin(y);
778 R = atan( f13/f11 );
779 //R = asin(f13);
780 if( f11<0 )
781 R+=F_PI;
783 double f22 = cos(x)*cos(z);
784 if( f22>0 )
785 E = 0.0;
786 else
787 E = F_PI;
789 else if( lcl_isCosZero(z) )
791 //cosY!=0 sinY!=0 sinX=0 cosZ=0
792 R = x;
793 E = y;//or -y
794 //use 23 for 'signs'
795 double f23 = -1.0*cos(x)*sin(y)*sin(z);
796 if( (f23*cos(R)*sin(E))<0.0 )
798 //change R or E
799 E = -y;
802 else
804 //cosY!=0 sinY!=0 sinX=0 sinZ!=0 cosZ!=0
805 double f13 = cos(x)*cos(z)*sin(y);
806 R = atan( f13/f11 );
808 if( f11<0 )
809 R+=F_PI;
811 double f21 = cos(y)*sin(z);
812 double f22 = cos(x)*cos(z);
813 E = atan(f21/(f22*sin(R)) );
815 if( (f22*cos(E))<0.0 )
816 E+=F_PI;
819 else if( lcl_isCosZero(x) )
821 //cosY!=0 sinY!=0 cosX=0
823 if( lcl_isSinZero(z) )
825 //cosY!=0 sinY!=0 cosX=0 sinZ=0
826 R=0;//13 -> R=0 or F_PI
827 if( f11<0.0 )
828 R=F_PI;
829 E=F_PI/2;//22 -> E=+-F_PI/2
830 //use element 11 and 23 for sign
831 double f23 = cos(z)*sin(x);
832 if( (f11*f23*sin(E))<0.0 )
833 E=-F_PI/2.0;
835 else if( lcl_isCosZero(z) )
837 //cosY!=0 sinY!=0 cosX=0 cosZ=0
838 //element 11 & 13:
839 if( (sin(x)*sin(z))>0.0 )
840 R=F_PI/2.0;
841 else
842 R=-F_PI/2.0;
843 //element 22:
844 E=acos( sin(x)*sin(y)*sin(z));
845 //use element 21 for sign:
846 if( (cos(y)*sin(z)*sin(R)*sin(E))<0.0 )
847 E*=-1.0;
849 else
851 //cosY!=0 sinY!=0 cosX=0 sinZ!=0 cosZ!=0
852 //element 13/11
853 R = atan( sin(x)*sin(z)/(cos(y)*cos(z)) );
854 //use 13 for 'sign'
855 if( (sin(x)*sin(z))<0.0 )
856 R += F_PI;
857 //element 22
858 E = acos(sin(x)*sin(y)*sin(z) );
859 //use 21 for sign
860 if( (cos(y)*sin(z)*sin(R)*sin(E))<0.0 )
861 E*=-1.0;
864 else if( lcl_isSinZero(z) )
866 //cosY!=0 sinY!=0 sinX!=0 cosX!=0 sinZ=0
867 //element 11
868 R=y;
869 //use elenment 13 for sign
870 if( (cos(x)*cos(z)*sin(y)*sin(R))<0.0 )
871 R*=-1.0;
872 //element 22
873 E = acos( cos(x)*cos(z) );
874 //use element 23 for sign
875 if( (cos(z)*sin(x)*cos(R)*sin(E))<0.0 )
876 E*=-1.0;
878 else if( lcl_isCosZero(z) )
880 //cosY!=0 sinY!=0 sinX!=0 cosX!=0 cosZ=0
881 //element 21/23
882 R=atan(-cos(y)/(cos(x)*sin(y)));
883 //use element 13 for 'sign'
884 if( (sin(x)*sin(z)*sin(R))<0.0 )
885 R+=F_PI;
886 //element 21/22
887 E=atan( cos(y)*sin(z)/(sin(R)*sin(x)*sin(y)*sin(z)) );
888 //use element 23 for 'sign'
889 if( (-cos(x)*sin(y)*sin(z)*cos(R)*sin(E))<0.0 )
890 E+=F_PI;
892 else
894 //cosY!=0 sinY!=0 sinX!=0 cosX!=0 sinZ!=0 cosZ!=0
895 //13/11:
896 double f13 = sin(x)*sin(z)+cos(x)*cos(z)*sin(y);
897 R = atan( f13/ f11 );
898 if(f11<0.0)
899 R+=F_PI;
900 double f22 = cos(x)*cos(z)+sin(x)*sin(y)*sin(z);
901 double f23 = cos(x)*sin(y)*sin(z)-cos(z)*sin(x);
902 //23/22:
903 E = atan( -1.0*f23/(f22*cos(R)) );
904 if(f22<0.0)
905 E+=F_PI;
908 rnElevationDeg = ::basegfx::fround( BaseGFXHelper::Rad2Deg( E ) );
909 rnRotationDeg = ::basegfx::fround( BaseGFXHelper::Rad2Deg( R ) );
912 double ThreeDHelper::getValueClippedToRange( double fAngle, const double& fPositivLimit )
914 if( fAngle<-1*fPositivLimit )
915 fAngle=-1*fPositivLimit;
916 else if( fAngle>fPositivLimit )
917 fAngle=fPositivLimit;
918 return fAngle;
921 double ThreeDHelper::getXDegreeAngleLimitForRightAngledAxes()
923 return 90.0;
926 double ThreeDHelper::getYDegreeAngleLimitForRightAngledAxes()
928 return 45.0;
931 void ThreeDHelper::adaptRadAnglesForRightAngledAxes( double& rfXAngleRad, double& rfYAngleRad )
933 rfXAngleRad = ThreeDHelper::getValueClippedToRange(rfXAngleRad, BaseGFXHelper::Deg2Rad(ThreeDHelper::getXDegreeAngleLimitForRightAngledAxes()) );
934 rfYAngleRad = ThreeDHelper::getValueClippedToRange(rfYAngleRad, BaseGFXHelper::Deg2Rad(ThreeDHelper::getYDegreeAngleLimitForRightAngledAxes()) );
937 void ThreeDHelper::getRotationAngleFromDiagram(
938 const Reference< beans::XPropertySet >& xSceneProperties, double& rfXAngleRad, double& rfYAngleRad, double& rfZAngleRad )
940 //takes the camera and the transformation matrix into account
942 rfXAngleRad = rfYAngleRad = rfZAngleRad = 0.0;
944 if( !xSceneProperties.is() )
945 return;
947 //get camera rotation
948 ::basegfx::B3DHomMatrix aFixCameraRotationMatrix( lcl_getCameraMatrix( xSceneProperties ) );
949 BaseGFXHelper::ReduceToRotationMatrix( aFixCameraRotationMatrix );
951 //get scene rotation
952 ::basegfx::B3DHomMatrix aSceneRotation;
954 drawing::HomogenMatrix aHomMatrix;
955 if( xSceneProperties->getPropertyValue( C2U("D3DTransformMatrix")) >>= aHomMatrix )
957 aSceneRotation = BaseGFXHelper::HomogenMatrixToB3DHomMatrix( aHomMatrix );
958 BaseGFXHelper::ReduceToRotationMatrix( aSceneRotation );
962 ::basegfx::B3DHomMatrix aResultRotation = aFixCameraRotationMatrix * aSceneRotation;
963 ::basegfx::B3DTuple aRotation( BaseGFXHelper::GetRotationFromMatrix( aResultRotation ) );
965 rfXAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(aRotation.getX());
966 rfYAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(aRotation.getY());
967 rfZAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(aRotation.getZ());
969 if(rfZAngleRad<(-F_PI/2) || rfZAngleRad>(F_PI/2))
971 rfZAngleRad-=F_PI;
972 rfXAngleRad-=F_PI;
973 rfYAngleRad=(F_PI-rfYAngleRad);
975 rfXAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(rfXAngleRad);
976 rfYAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(rfYAngleRad);
977 rfZAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(rfZAngleRad);
981 void ThreeDHelper::switchRightAngledAxes( const Reference< beans::XPropertySet >& xSceneProperties, sal_Bool bRightAngledAxes, bool bRotateLights )
985 if( xSceneProperties.is() )
987 sal_Bool bOldRightAngledAxes = sal_False;
988 xSceneProperties->getPropertyValue( C2U("RightAngledAxes")) >>= bOldRightAngledAxes;
989 if( bOldRightAngledAxes!=bRightAngledAxes)
991 xSceneProperties->setPropertyValue( C2U("RightAngledAxes"), uno::makeAny( bRightAngledAxes ));
992 if( bRotateLights )
994 if(bRightAngledAxes)
996 ::basegfx::B3DHomMatrix aInverseRotation( lcl_getInverseRotationMatrix( xSceneProperties ) );
997 lcl_rotateLights( aInverseRotation, xSceneProperties );
999 else
1001 ::basegfx::B3DHomMatrix aCompleteRotation( lcl_getCompleteRotationMatrix( xSceneProperties ) );
1002 lcl_rotateLights( aCompleteRotation, xSceneProperties );
1008 catch( const uno::Exception & ex )
1010 ASSERT_EXCEPTION( ex );
1014 void ThreeDHelper::setRotationAngleToDiagram(
1015 const Reference< beans::XPropertySet >& xSceneProperties
1016 , double fXAngleRad, double fYAngleRad, double fZAngleRad )
1018 //the rotation of the camera is not touched but taken into account
1019 //the rotation difference is applied to the transformation matrix
1021 //the light sources will be adapted also
1023 if( !xSceneProperties.is() )
1024 return;
1028 //remind old rotation for adaption of light directions
1029 ::basegfx::B3DHomMatrix aInverseOldRotation( lcl_getInverseRotationMatrix( xSceneProperties ) );
1031 ::basegfx::B3DHomMatrix aInverseCameraRotation;
1033 ::basegfx::B3DTuple aR( BaseGFXHelper::GetRotationFromMatrix(
1034 lcl_getCameraMatrix( xSceneProperties ) ) );
1035 aInverseCameraRotation.rotate( 0.0, 0.0, -aR.getZ() );
1036 aInverseCameraRotation.rotate( 0.0, -aR.getY(), 0.0 );
1037 aInverseCameraRotation.rotate( -aR.getX(), 0.0, 0.0 );
1040 ::basegfx::B3DHomMatrix aCumulatedRotation;
1041 aCumulatedRotation.rotate( fXAngleRad, fYAngleRad, fZAngleRad );
1043 //calculate new scene matrix
1044 ::basegfx::B3DHomMatrix aSceneRotation = aInverseCameraRotation*aCumulatedRotation;
1045 BaseGFXHelper::ReduceToRotationMatrix( aSceneRotation );
1047 //set new rotation to transformation matrix
1048 xSceneProperties->setPropertyValue(
1049 C2U("D3DTransformMatrix"), uno::makeAny( BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aSceneRotation )));
1051 //rotate lights if RightAngledAxes are not set or not supported
1052 sal_Bool bRightAngledAxes = sal_False;
1053 xSceneProperties->getPropertyValue( C2U("RightAngledAxes")) >>= bRightAngledAxes;
1054 uno::Reference< chart2::XDiagram > xDiagram( xSceneProperties, uno::UNO_QUERY );
1055 if(!bRightAngledAxes || !ChartTypeHelper::isSupportingRightAngledAxes(
1056 DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ) )
1058 ::basegfx::B3DHomMatrix aNewRotation;
1059 aNewRotation.rotate( fXAngleRad, fYAngleRad, fZAngleRad );
1060 lcl_rotateLights( aNewRotation*aInverseOldRotation, xSceneProperties );
1063 catch( const uno::Exception & ex )
1065 ASSERT_EXCEPTION( ex );
1069 void ThreeDHelper::getRotationFromDiagram( const uno::Reference< beans::XPropertySet >& xSceneProperties
1070 , sal_Int32& rnHorizontalAngleDegree, sal_Int32& rnVerticalAngleDegree )
1072 double fXAngle, fYAngle, fZAngle;
1073 ThreeDHelper::getRotationAngleFromDiagram( xSceneProperties, fXAngle, fYAngle, fZAngle );
1075 if( !lcl_isRightAngledAxesSetAndSupported( xSceneProperties ) )
1077 ThreeDHelper::convertXYZAngleRadToElevationRotationDeg(
1078 rnHorizontalAngleDegree, rnVerticalAngleDegree, fXAngle, fYAngle, fZAngle);
1079 rnVerticalAngleDegree*=-1;
1081 else
1083 fXAngle = BaseGFXHelper::Rad2Deg( fXAngle );
1084 fYAngle = BaseGFXHelper::Rad2Deg( fYAngle );
1085 fZAngle = BaseGFXHelper::Rad2Deg( fZAngle );
1087 rnHorizontalAngleDegree = ::basegfx::fround(fXAngle);
1088 rnVerticalAngleDegree = ::basegfx::fround(-1.0*fYAngle);
1089 //nZRotation = ::basegfx::fround(-1.0*fZAngle);
1092 lcl_shiftAngleToIntervalMinus180To180( rnHorizontalAngleDegree );
1093 lcl_shiftAngleToIntervalMinus180To180( rnVerticalAngleDegree );
1096 void ThreeDHelper::setRotationToDiagram( const uno::Reference< beans::XPropertySet >& xSceneProperties
1097 , sal_Int32 nHorizontalAngleDegree, sal_Int32 nVerticalYAngleDegree )
1099 //todo: x and y is not equal to horz and vert in case of RightAngledAxes==false
1100 double fXAngle = BaseGFXHelper::Deg2Rad( nHorizontalAngleDegree );
1101 double fYAngle = BaseGFXHelper::Deg2Rad( -1*nVerticalYAngleDegree );
1102 double fZAngle = 0.0;
1104 if( !lcl_isRightAngledAxesSetAndSupported( xSceneProperties ) )
1105 ThreeDHelper::convertElevationRotationDegToXYZAngleRad(
1106 nHorizontalAngleDegree, -1*nVerticalYAngleDegree, fXAngle, fYAngle, fZAngle );
1108 ThreeDHelper::setRotationAngleToDiagram( xSceneProperties, fXAngle, fYAngle, fZAngle );
1111 void ThreeDHelper::getCameraDistanceRange( double& rfMinimumDistance, double& rfMaximumDistance )
1113 rfMinimumDistance = 3.0/4.0*FIXED_SIZE_FOR_3D_CHART_VOLUME;//empiric value
1114 rfMaximumDistance = 20.0*FIXED_SIZE_FOR_3D_CHART_VOLUME;//empiric value
1117 void ThreeDHelper::ensureCameraDistanceRange( double& rfCameraDistance )
1119 double fMin, fMax;
1120 getCameraDistanceRange( fMin, fMax );
1121 if( rfCameraDistance < fMin )
1122 rfCameraDistance = fMin;
1123 if( rfCameraDistance > fMax )
1124 rfCameraDistance = fMax;
1127 double ThreeDHelper::getCameraDistance(
1128 const Reference< beans::XPropertySet >& xSceneProperties )
1130 double fCameraDistance = FIXED_SIZE_FOR_3D_CHART_VOLUME;
1132 if( !xSceneProperties.is() )
1133 return fCameraDistance;
1137 drawing::CameraGeometry aCG( ThreeDHelper::getDefaultCameraGeometry() );
1138 xSceneProperties->getPropertyValue( C2U( "D3DCameraGeometry" ) ) >>= aCG;
1139 ::basegfx::B3DVector aVRP( BaseGFXHelper::Position3DToB3DVector( aCG.vrp ) );
1140 fCameraDistance = aVRP.getLength();
1142 ensureCameraDistanceRange( fCameraDistance );
1144 catch( const uno::Exception & ex )
1146 ASSERT_EXCEPTION( ex );
1148 return fCameraDistance;
1151 void ThreeDHelper::setCameraDistance(
1152 const Reference< beans::XPropertySet >& xSceneProperties, double fCameraDistance )
1154 if( !xSceneProperties.is() )
1155 return;
1159 if( fCameraDistance <= 0 )
1160 fCameraDistance = FIXED_SIZE_FOR_3D_CHART_VOLUME;
1162 drawing::CameraGeometry aCG( ThreeDHelper::getDefaultCameraGeometry() );
1163 xSceneProperties->getPropertyValue( C2U( "D3DCameraGeometry" ) ) >>= aCG;
1164 ::basegfx::B3DVector aVRP( BaseGFXHelper::Position3DToB3DVector( aCG.vrp ) );
1165 if( ::basegfx::fTools::equalZero( aVRP.getLength() ) )
1166 aVRP = ::basegfx::B3DVector(0,0,1);
1167 aVRP.setLength(fCameraDistance);
1168 aCG.vrp = BaseGFXHelper::B3DVectorToPosition3D( aVRP );
1170 xSceneProperties->setPropertyValue( C2U("D3DCameraGeometry"), uno::makeAny( aCG ));
1172 catch( const uno::Exception & ex )
1174 ASSERT_EXCEPTION( ex );
1178 //static
1179 double ThreeDHelper::CameraDistanceToPerspective( double fCameraDistance )
1181 double fRet = fCameraDistance;
1182 double fMin, fMax;
1183 ThreeDHelper::getCameraDistanceRange( fMin, fMax );
1184 //fMax <-> 0; fMin <->100
1185 //a/x + b = y
1186 double a = 100.0*fMax*fMin/(fMax-fMin);
1187 double b = -a/fMax;
1189 fRet = a/fCameraDistance + b;
1191 return fRet;
1194 //static
1195 double ThreeDHelper::PerspectiveToCameraDistance( double fPerspective )
1197 double fRet = fPerspective;
1198 double fMin, fMax;
1199 ThreeDHelper::getCameraDistanceRange( fMin, fMax );
1200 //fMax <-> 0; fMin <->100
1201 //a/x + b = y
1202 double a = 100.0*fMax*fMin/(fMax-fMin);
1203 double b = -a/fMax;
1205 fRet = a/(fPerspective - b);
1207 return fRet;
1210 //static
1211 ThreeDLookScheme ThreeDHelper::detectScheme( const uno::Reference< XDiagram >& xDiagram )
1213 ThreeDLookScheme aScheme = ThreeDLookScheme_Unknown;
1215 sal_Int32 nRoundedEdges;
1216 sal_Int32 nObjectLines;
1217 ThreeDHelper::getRoundedEdgesAndObjectLines( xDiagram, nRoundedEdges, nObjectLines );
1219 //get shade mode and light settings:
1220 drawing::ShadeMode aShadeMode( drawing::ShadeMode_SMOOTH );
1221 uno::Reference< beans::XPropertySet > xDiagramProps( xDiagram, uno::UNO_QUERY );
1224 if( xDiagramProps.is() )
1225 xDiagramProps->getPropertyValue( C2U( "D3DSceneShadeMode" ) )>>= aShadeMode;
1227 catch( uno::Exception & ex )
1229 ASSERT_EXCEPTION( ex );
1232 if( lcl_isSimpleScheme( aShadeMode, nRoundedEdges, nObjectLines, xDiagram ) )
1234 if( lcl_isSimpleLightScheme(xDiagramProps) )
1235 aScheme = ThreeDLookScheme_Simple;
1237 else if( lcl_isRealisticScheme( aShadeMode, nRoundedEdges, nObjectLines ) )
1239 if( lcl_isRealisticLightScheme(xDiagramProps) )
1240 aScheme = ThreeDLookScheme_Realistic;
1243 return aScheme;
1246 void ThreeDHelper::setScheme( const uno::Reference< XDiagram >& xDiagram, ThreeDLookScheme aScheme )
1248 if( aScheme == ThreeDLookScheme_Unknown )
1249 return;
1251 drawing::ShadeMode aShadeMode;
1252 sal_Int32 nRoundedEdges;
1253 sal_Int32 nObjectLines;
1255 if( aScheme == ThreeDLookScheme_Simple )
1256 lcl_setSimpleScheme(aShadeMode,nRoundedEdges,nObjectLines,xDiagram);
1257 else
1258 lcl_setRealisticScheme(aShadeMode,nRoundedEdges,nObjectLines);
1262 ThreeDHelper::setRoundedEdgesAndObjectLines( xDiagram, nRoundedEdges, nObjectLines );
1264 uno::Reference< beans::XPropertySet > xProp( xDiagram, uno::UNO_QUERY );
1265 if( xProp.is() )
1267 drawing::ShadeMode aOldShadeMode;
1268 if( ! ( (xProp->getPropertyValue( C2U( "D3DSceneShadeMode" ) )>>=aOldShadeMode) &&
1269 aOldShadeMode == aShadeMode ))
1271 xProp->setPropertyValue( C2U( "D3DSceneShadeMode" ), uno::makeAny( aShadeMode ));
1275 lcl_setLightsForScheme( xProp, aScheme );
1277 catch( uno::Exception & ex )
1279 ASSERT_EXCEPTION( ex );
1284 //static
1285 void ThreeDHelper::set3DSettingsToDefault( const uno::Reference< beans::XPropertySet >& xSceneProperties )
1287 Reference< beans::XPropertyState > xState( xSceneProperties, uno::UNO_QUERY );
1288 if(xState.is())
1290 xState->setPropertyToDefault( C2U("D3DSceneDistance"));
1291 xState->setPropertyToDefault( C2U("D3DSceneFocalLength"));
1293 ThreeDHelper::setDefaultRotation( xSceneProperties );
1294 ThreeDHelper::setDefaultIllumination( xSceneProperties );
1297 //static
1298 void ThreeDHelper::setDefaultRotation( const uno::Reference< beans::XPropertySet >& xSceneProperties, bool bPieOrDonut )
1300 if( !xSceneProperties.is() )
1301 return;
1303 drawing::CameraGeometry aCameraGeo( ThreeDHelper::getDefaultCameraGeometry( bPieOrDonut ) );
1304 xSceneProperties->setPropertyValue( C2U("D3DCameraGeometry"), uno::makeAny( aCameraGeo ));
1306 ::basegfx::B3DHomMatrix aSceneRotation;
1307 if( bPieOrDonut )
1308 aSceneRotation.rotate( -F_PI/3.0, 0, 0 );
1309 xSceneProperties->setPropertyValue( C2U("D3DTransformMatrix"),
1310 uno::makeAny( BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aSceneRotation )));
1313 //static
1314 void ThreeDHelper::setDefaultRotation( const uno::Reference< beans::XPropertySet >& xSceneProperties )
1316 bool bPieOrDonut( DiagramHelper::isPieOrDonutChart( uno::Reference< XDiagram >(xSceneProperties, uno::UNO_QUERY) ) );
1317 ThreeDHelper::setDefaultRotation( xSceneProperties, bPieOrDonut );
1320 //static
1321 void ThreeDHelper::setDefaultIllumination( const uno::Reference< beans::XPropertySet >& xSceneProperties )
1323 if( !xSceneProperties.is() )
1324 return;
1326 drawing::ShadeMode aShadeMode( drawing::ShadeMode_SMOOTH );
1329 xSceneProperties->getPropertyValue( C2U( "D3DSceneShadeMode" ) )>>= aShadeMode;
1330 xSceneProperties->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_1 ), uno::makeAny( sal_False ) );
1331 xSceneProperties->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_3 ), uno::makeAny( sal_False ) );
1332 xSceneProperties->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_4 ), uno::makeAny( sal_False ) );
1333 xSceneProperties->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_5 ), uno::makeAny( sal_False ) );
1334 xSceneProperties->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_6 ), uno::makeAny( sal_False ) );
1335 xSceneProperties->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_7 ), uno::makeAny( sal_False ) );
1336 xSceneProperties->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_8 ), uno::makeAny( sal_False ) );
1338 catch( uno::Exception & ex )
1340 ASSERT_EXCEPTION( ex );
1343 ThreeDLookScheme aScheme = (drawing::ShadeMode_FLAT==aShadeMode) ? ThreeDLookScheme_Simple : ThreeDLookScheme_Realistic;
1344 lcl_setLightsForScheme( xSceneProperties, aScheme );
1347 //static
1348 void ThreeDHelper::getRoundedEdgesAndObjectLines(
1349 const uno::Reference< XDiagram > & xDiagram
1350 , sal_Int32& rnRoundedEdges, sal_Int32& rnObjectLines )
1352 rnRoundedEdges = -1;
1353 rnObjectLines = -1;
1356 bool bDifferentRoundedEdges = false;
1357 bool bDifferentObjectLines = false;
1359 drawing::LineStyle aLineStyle( drawing::LineStyle_SOLID );
1361 ::std::vector< uno::Reference< XDataSeries > > aSeriesList(
1362 DiagramHelper::getDataSeriesFromDiagram( xDiagram ) );
1363 sal_Int32 nSeriesCount = static_cast<sal_Int32>( aSeriesList.size() );
1365 rtl::OUString aPercentDiagonalPropertyName( C2U( "PercentDiagonal" ) );
1366 rtl::OUString aBorderStylePropertyName( C2U( "BorderStyle" ) );
1368 for( sal_Int32 nS = 0; nS < nSeriesCount; ++nS )
1370 uno::Reference< XDataSeries > xSeries( aSeriesList[nS] );
1371 uno::Reference< beans::XPropertySet > xProp( xSeries, uno::UNO_QUERY );
1372 if(!nS)
1374 rnRoundedEdges = 0;
1377 sal_Int16 nPercentDiagonal = 0;
1379 xProp->getPropertyValue( aPercentDiagonalPropertyName ) >>= nPercentDiagonal;
1380 rnRoundedEdges = static_cast< sal_Int32 >( nPercentDiagonal );
1382 if( DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries
1383 , aPercentDiagonalPropertyName, uno::makeAny(nPercentDiagonal) ) )
1384 bDifferentRoundedEdges = true;
1386 catch( uno::Exception& e )
1388 ASSERT_EXCEPTION( e );
1389 bDifferentRoundedEdges = true;
1393 xProp->getPropertyValue( aBorderStylePropertyName ) >>= aLineStyle;
1395 if( DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries
1396 , aBorderStylePropertyName, uno::makeAny(aLineStyle) ) )
1397 bDifferentObjectLines = true;
1399 catch( uno::Exception& e )
1401 ASSERT_EXCEPTION( e );
1402 bDifferentObjectLines = true;
1405 else
1407 if( !bDifferentRoundedEdges )
1409 sal_Int16 nPercentDiagonal = 0;
1410 xProp->getPropertyValue( aPercentDiagonalPropertyName ) >>= nPercentDiagonal;
1411 sal_Int32 nCurrentRoundedEdges = static_cast< sal_Int32 >( nPercentDiagonal );
1412 if(nCurrentRoundedEdges!=rnRoundedEdges
1413 || DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries
1414 , aPercentDiagonalPropertyName, uno::makeAny( static_cast< sal_Int16 >(rnRoundedEdges) ) ) )
1416 bDifferentRoundedEdges = true;
1417 nCurrentRoundedEdges = -1;
1421 if( !bDifferentObjectLines )
1423 drawing::LineStyle aCurrentLineStyle;
1424 xProp->getPropertyValue( aBorderStylePropertyName ) >>= aCurrentLineStyle;
1425 if(aCurrentLineStyle!=aLineStyle
1426 || DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries
1427 , aBorderStylePropertyName, uno::makeAny(aLineStyle) ) )
1428 bDifferentObjectLines = true;
1431 if( bDifferentRoundedEdges && bDifferentObjectLines )
1432 break;
1435 //set rnObjectLines
1436 rnObjectLines = 0;
1437 if( bDifferentObjectLines )
1438 rnObjectLines = -1;
1439 else if( aLineStyle == drawing::LineStyle_SOLID )
1440 rnObjectLines = 1;
1442 catch( uno::Exception& e )
1444 ASSERT_EXCEPTION( e );
1447 //static
1448 void ThreeDHelper::setRoundedEdgesAndObjectLines(
1449 const uno::Reference< XDiagram > & xDiagram
1450 , sal_Int32 nRoundedEdges, sal_Int32 nObjectLines )
1452 if( (nRoundedEdges<0||nRoundedEdges>100) && nObjectLines!=0 && nObjectLines!=1 )
1453 return;
1455 drawing::LineStyle aLineStyle( drawing::LineStyle_NONE );
1456 if(nObjectLines==1)
1457 aLineStyle = drawing::LineStyle_SOLID;
1459 uno::Any aALineStyle( uno::makeAny(aLineStyle));
1460 uno::Any aARoundedEdges( uno::makeAny( static_cast< sal_Int16 >( nRoundedEdges )));
1462 ::std::vector< uno::Reference< XDataSeries > > aSeriesList(
1463 DiagramHelper::getDataSeriesFromDiagram( xDiagram ) );
1464 sal_Int32 nSeriesCount = static_cast<sal_Int32>( aSeriesList.size() );
1465 for( sal_Int32 nS = 0; nS < nSeriesCount; ++nS )
1467 uno::Reference< XDataSeries > xSeries( aSeriesList[nS] );
1469 if( nRoundedEdges>=0 && nRoundedEdges<=100 )
1470 DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, C2U( "PercentDiagonal" ), aARoundedEdges );
1472 if( nObjectLines==0 || nObjectLines==1 )
1473 DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, C2U( "BorderStyle" ), aALineStyle );
1477 //static
1478 CuboidPlanePosition ThreeDHelper::getAutomaticCuboidPlanePositionForStandardLeftWall( const Reference< beans::XPropertySet >& xSceneProperties )
1480 CuboidPlanePosition eRet(CuboidPlanePosition_Left);
1482 double fXAngleRad=0.0; double fYAngleRad=0.0; double fZAngleRad=0.0;
1483 ThreeDHelper::getRotationAngleFromDiagram( xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad );
1484 if( lcl_isRightAngledAxesSetAndSupported( xSceneProperties ) )
1486 ThreeDHelper::adaptRadAnglesForRightAngledAxes( fXAngleRad, fYAngleRad );
1487 fZAngleRad=0.0;
1489 if( sin(fYAngleRad)>0.0 )
1490 eRet = CuboidPlanePosition_Right;
1491 return eRet;
1494 //static
1495 CuboidPlanePosition ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBackWall( const Reference< beans::XPropertySet >& xSceneProperties )
1497 CuboidPlanePosition eRet(CuboidPlanePosition_Back);
1499 double fXAngleRad=0.0; double fYAngleRad=0.0; double fZAngleRad=0.0;
1500 ThreeDHelper::getRotationAngleFromDiagram( xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad );
1501 if( lcl_isRightAngledAxesSetAndSupported( xSceneProperties ) )
1503 ThreeDHelper::adaptRadAnglesForRightAngledAxes( fXAngleRad, fYAngleRad );
1504 fZAngleRad=0.0;
1506 if( cos(fXAngleRad)*cos(fYAngleRad)<0.0 )
1507 eRet = CuboidPlanePosition_Front;
1508 return eRet;
1511 //static
1512 CuboidPlanePosition ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBottom( const Reference< beans::XPropertySet >& xSceneProperties )
1514 CuboidPlanePosition eRet(CuboidPlanePosition_Bottom);
1516 double fXAngleRad=0.0; double fYAngleRad=0.0; double fZAngleRad=0.0;
1517 ThreeDHelper::getRotationAngleFromDiagram( xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad );
1518 if( lcl_isRightAngledAxesSetAndSupported( xSceneProperties ) )
1520 ThreeDHelper::adaptRadAnglesForRightAngledAxes( fXAngleRad, fYAngleRad );
1521 fZAngleRad=0.0;
1523 if( sin(fXAngleRad)*cos(fYAngleRad)<0.0 )
1524 eRet = CuboidPlanePosition_Top;
1525 return eRet;
1528 //.............................................................................
1529 } //namespace chart
1530 //.............................................................................