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