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