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