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