/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_chart2.hxx" #include "ThreeDHelper.hxx" #include "macros.hxx" #include "DiagramHelper.hxx" #include "ChartTypeHelper.hxx" #include "BaseGFXHelper.hxx" #include "DataSeriesHelper.hxx" #include #include #include #include #include //............................................................................. namespace chart { //............................................................................. using namespace ::com::sun::star; using namespace ::com::sun::star::chart2; using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::Sequence; using ::rtl::OUString; using ::rtl::math::cos; using ::rtl::math::sin; using ::rtl::math::tan; #define FIXED_SIZE_FOR_3D_CHART_VOLUME (10000.0) namespace { bool lcl_isRightAngledAxesSetAndSupported( const Reference< beans::XPropertySet >& xSceneProperties ) { sal_Bool bRightAngledAxes = sal_False; if( xSceneProperties.is() ) { xSceneProperties->getPropertyValue( C2U("RightAngledAxes")) >>= bRightAngledAxes; if(bRightAngledAxes) { uno::Reference< chart2::XDiagram > xDiagram( xSceneProperties, uno::UNO_QUERY ); if( ChartTypeHelper::isSupportingRightAngledAxes( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ) ) { return true; } } } return false; } void lcl_RotateLightSource( const Reference< beans::XPropertySet >& xSceneProperties , const OUString& rLightSourceDirection , const OUString& rLightSourceOn , const ::basegfx::B3DHomMatrix& rRotationMatrix ) { if( xSceneProperties.is() ) { sal_Bool bLightOn = sal_False; if( xSceneProperties->getPropertyValue( rLightSourceOn ) >>= bLightOn ) { if( bLightOn ) { drawing::Direction3D aLight; if( xSceneProperties->getPropertyValue( rLightSourceDirection ) >>= aLight ) { ::basegfx::B3DVector aLightVector( BaseGFXHelper::Direction3DToB3DVector( aLight ) ); aLightVector = rRotationMatrix*aLightVector; xSceneProperties->setPropertyValue( rLightSourceDirection , uno::makeAny( BaseGFXHelper::B3DVectorToDirection3D( aLightVector ) ) ); } } } } } void lcl_rotateLights( const ::basegfx::B3DHomMatrix& rLightRottion, const Reference< beans::XPropertySet >& xSceneProperties ) { if(!xSceneProperties.is()) return; ::basegfx::B3DHomMatrix aLightRottion( rLightRottion ); BaseGFXHelper::ReduceToRotationMatrix( aLightRottion ); lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection1"), C2U("D3DSceneLightOn1"), aLightRottion ); lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection2"), C2U("D3DSceneLightOn2"), aLightRottion ); lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection3"), C2U("D3DSceneLightOn3"), aLightRottion ); lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection4"), C2U("D3DSceneLightOn4"), aLightRottion ); lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection5"), C2U("D3DSceneLightOn5"), aLightRottion ); lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection6"), C2U("D3DSceneLightOn6"), aLightRottion ); lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection7"), C2U("D3DSceneLightOn7"), aLightRottion ); lcl_RotateLightSource( xSceneProperties, C2U("D3DSceneLightDirection8"), C2U("D3DSceneLightOn8"), aLightRottion ); } ::basegfx::B3DHomMatrix lcl_getInverseRotationMatrix( const Reference< beans::XPropertySet >& xSceneProperties ) { ::basegfx::B3DHomMatrix aInverseRotation; double fXAngleRad=0.0; double fYAngleRad=0.0; double fZAngleRad=0.0; ThreeDHelper::getRotationAngleFromDiagram( xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad ); aInverseRotation.rotate( 0.0, 0.0, -fZAngleRad ); aInverseRotation.rotate( 0.0, -fYAngleRad, 0.0 ); aInverseRotation.rotate( -fXAngleRad, 0.0, 0.0 ); return aInverseRotation; } ::basegfx::B3DHomMatrix lcl_getCompleteRotationMatrix( const Reference< beans::XPropertySet >& xSceneProperties ) { ::basegfx::B3DHomMatrix aCompleteRotation; double fXAngleRad=0.0; double fYAngleRad=0.0; double fZAngleRad=0.0; ThreeDHelper::getRotationAngleFromDiagram( xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad ); aCompleteRotation.rotate( fXAngleRad, fYAngleRad, fZAngleRad ); return aCompleteRotation; } bool lcl_isEqual( const drawing::Direction3D& rA, const drawing::Direction3D& rB ) { return ::rtl::math::approxEqual(rA.DirectionX, rB.DirectionX) && ::rtl::math::approxEqual(rA.DirectionY, rB.DirectionY) && ::rtl::math::approxEqual(rA.DirectionZ, rB.DirectionZ); } bool lcl_isLightScheme( const uno::Reference< beans::XPropertySet >& xDiagramProps, bool bRealistic ) { if(!xDiagramProps.is()) return false; sal_Bool bIsOn = sal_False; xDiagramProps->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_2 ) ) >>= bIsOn; if(!bIsOn) return false; uno::Reference< chart2::XDiagram > xDiagram( xDiagramProps, uno::UNO_QUERY ); uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); sal_Int32 nColor = 0; xDiagramProps->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_2 ) ) >>= nColor; if( nColor != ::chart::ChartTypeHelper::getDefaultDirectLightColor( !bRealistic, xChartType ) ) return false; sal_Int32 nAmbientColor = 0; xDiagramProps->getPropertyValue( C2U( UNO_NAME_3D_SCENE_AMBIENTCOLOR ) ) >>= nAmbientColor; if( nAmbientColor != ::chart::ChartTypeHelper::getDefaultAmbientLightColor( !bRealistic, xChartType ) ) return false; drawing::Direction3D aDirection(0,0,0); xDiagramProps->getPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_2 ) ) >>= aDirection; drawing::Direction3D aDefaultDirection( bRealistic ? ChartTypeHelper::getDefaultRealisticLightDirection(xChartType) : ChartTypeHelper::getDefaultSimpleLightDirection(xChartType) ); //rotate default light direction when right angled axes are off but supported { sal_Bool bRightAngledAxes = sal_False; xDiagramProps->getPropertyValue( C2U("RightAngledAxes")) >>= bRightAngledAxes; if(!bRightAngledAxes) { if( ChartTypeHelper::isSupportingRightAngledAxes( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ) ) { ::basegfx::B3DHomMatrix aRotation( lcl_getCompleteRotationMatrix( xDiagramProps ) ); BaseGFXHelper::ReduceToRotationMatrix( aRotation ); ::basegfx::B3DVector aLightVector( BaseGFXHelper::Direction3DToB3DVector( aDefaultDirection ) ); aLightVector = aRotation*aLightVector; aDefaultDirection = BaseGFXHelper::B3DVectorToDirection3D( aLightVector ); } } } return lcl_isEqual( aDirection, aDefaultDirection ); } bool lcl_isRealisticLightScheme( const uno::Reference< beans::XPropertySet >& xDiagramProps ) { return lcl_isLightScheme( xDiagramProps, true /*bRealistic*/ ); } bool lcl_isSimpleLightScheme( const uno::Reference< beans::XPropertySet >& xDiagramProps ) { return lcl_isLightScheme( xDiagramProps, false /*bRealistic*/ ); } void lcl_setLightsForScheme( const uno::Reference< beans::XPropertySet >& xDiagramProps, const ThreeDLookScheme& rScheme ) { if(!xDiagramProps.is()) return; if( rScheme == ThreeDLookScheme_Unknown) return; xDiagramProps->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_2 ), uno::makeAny( sal_True ) ); uno::Reference< chart2::XDiagram > xDiagram( xDiagramProps, uno::UNO_QUERY ); uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); uno::Any aADirection( uno::makeAny( rScheme == ThreeDLookScheme_Simple ? ChartTypeHelper::getDefaultSimpleLightDirection(xChartType) : ChartTypeHelper::getDefaultRealisticLightDirection(xChartType) ) ); xDiagramProps->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTDIRECTION_2 ), aADirection ); //rotate light direction when right angled axes are off but supported { sal_Bool bRightAngledAxes = sal_False; xDiagramProps->getPropertyValue( C2U("RightAngledAxes")) >>= bRightAngledAxes; if(!bRightAngledAxes) { if( ChartTypeHelper::isSupportingRightAngledAxes( xChartType ) ) { ::basegfx::B3DHomMatrix aRotation( lcl_getCompleteRotationMatrix( xDiagramProps ) ); BaseGFXHelper::ReduceToRotationMatrix( aRotation ); lcl_RotateLightSource( xDiagramProps, C2U("D3DSceneLightDirection2"), C2U("D3DSceneLightOn2"), aRotation ); } } } sal_Int32 nColor = ::chart::ChartTypeHelper::getDefaultDirectLightColor( rScheme==ThreeDLookScheme_Simple, xChartType ); xDiagramProps->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTCOLOR_2 ), uno::makeAny( nColor ) ); sal_Int32 nAmbientColor = ::chart::ChartTypeHelper::getDefaultAmbientLightColor( rScheme==ThreeDLookScheme_Simple, xChartType ); xDiagramProps->setPropertyValue( C2U( UNO_NAME_3D_SCENE_AMBIENTCOLOR ), uno::makeAny( nAmbientColor ) ); } bool lcl_isRealisticScheme( drawing::ShadeMode aShadeMode , sal_Int32 nRoundedEdges , sal_Int32 nObjectLines ) { if(aShadeMode!=drawing::ShadeMode_SMOOTH) return false; if(nRoundedEdges!=5) return false; if(nObjectLines!=0) return false; return true; } bool lcl_isSimpleScheme( drawing::ShadeMode aShadeMode , sal_Int32 nRoundedEdges , sal_Int32 nObjectLines , const uno::Reference< XDiagram >& xDiagram ) { if(aShadeMode!=drawing::ShadeMode_FLAT) return false; if(nRoundedEdges!=0) return false; if(nObjectLines==0) { uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); return ChartTypeHelper::noBordersForSimpleScheme( xChartType ); } if(nObjectLines!=1) return false; return true; } void lcl_setRealisticScheme( drawing::ShadeMode& rShadeMode , sal_Int32& rnRoundedEdges , sal_Int32& rnObjectLines ) { rShadeMode = drawing::ShadeMode_SMOOTH; rnRoundedEdges = 5; rnObjectLines = 0; } void lcl_setSimpleScheme( drawing::ShadeMode& rShadeMode , sal_Int32& rnRoundedEdges , sal_Int32& rnObjectLines , const uno::Reference< XDiagram >& xDiagram ) { rShadeMode = drawing::ShadeMode_FLAT; rnRoundedEdges = 0; uno::Reference< chart2::XChartType > xChartType( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ); rnObjectLines = ChartTypeHelper::noBordersForSimpleScheme( xChartType ) ? 0 : 1; } } //end anonymous namespace drawing::CameraGeometry ThreeDHelper::getDefaultCameraGeometry( bool bPie ) { // ViewReferencePoint (Point on the View plane) drawing::Position3D vrp(17634.6218373783, 10271.4823817647, 24594.8639082739); // ViewPlaneNormal (Normal to the View Plane) drawing::Direction3D vpn(0.416199821709347, 0.173649045905254, 0.892537795986984); // ViewUpVector (determines the v-axis direction on the view plane as // projection of VUP parallel to VPN onto th view pane) drawing::Direction3D vup(-0.0733876362771618, 0.984807599917971, -0.157379306090273); if( bPie ) { vrp = drawing::Position3D( 0.0, 0.0, 87591.2408759124 );//--> 5 percent perspecitve vpn = drawing::Direction3D( 0.0, 0.0, 1.0 ); vup = drawing::Direction3D( 0.0, 1.0, 0.0 ); } return drawing::CameraGeometry( vrp, vpn, vup ); } namespace { ::basegfx::B3DHomMatrix lcl_getCameraMatrix( const uno::Reference< beans::XPropertySet >& xSceneProperties ) { drawing::HomogenMatrix aCameraMatrix; drawing::CameraGeometry aCG( ThreeDHelper::getDefaultCameraGeometry() ); if( xSceneProperties.is() ) xSceneProperties->getPropertyValue( C2U( "D3DCameraGeometry" ) ) >>= aCG; ::basegfx::B3DVector aVPN( BaseGFXHelper::Direction3DToB3DVector( aCG.vpn ) ); ::basegfx::B3DVector aVUP( BaseGFXHelper::Direction3DToB3DVector( aCG.vup ) ); //normalize vectors: aVPN.normalize(); aVUP.normalize(); ::basegfx::B3DVector aCross = ::basegfx::cross( aVUP, aVPN ); //first line is VUP x VPN aCameraMatrix.Line1.Column1 = aCross[0]; aCameraMatrix.Line1.Column2 = aCross[1]; aCameraMatrix.Line1.Column3 = aCross[2]; aCameraMatrix.Line1.Column4 = 0.0; //second line is VUP aCameraMatrix.Line2.Column1 = aVUP[0]; aCameraMatrix.Line2.Column2 = aVUP[1]; aCameraMatrix.Line2.Column3 = aVUP[2]; aCameraMatrix.Line2.Column4 = 0.0; //third line is VPN aCameraMatrix.Line3.Column1 = aVPN[0]; aCameraMatrix.Line3.Column2 = aVPN[1]; aCameraMatrix.Line3.Column3 = aVPN[2]; aCameraMatrix.Line3.Column4 = 0.0; //fourth line is 0 0 0 1 aCameraMatrix.Line4.Column1 = 0.0; aCameraMatrix.Line4.Column2 = 0.0; aCameraMatrix.Line4.Column3 = 0.0; aCameraMatrix.Line4.Column4 = 1.0; return BaseGFXHelper::HomogenMatrixToB3DHomMatrix( aCameraMatrix ); } double lcl_shiftAngleToIntervalMinusPiToPi( double fAngleRad ) { //valid range: ]-Pi,Pi] while( fAngleRad<=-F_PI ) fAngleRad+=(2*F_PI); while( fAngleRad>F_PI ) fAngleRad-=(2*F_PI); return fAngleRad; } void lcl_shiftAngleToIntervalMinus180To180( sal_Int32& rnAngleDegree ) { //valid range: ]-180,180] while( rnAngleDegree<=-180 ) rnAngleDegree+=360; while( rnAngleDegree>180 ) rnAngleDegree-=360; } void lcl_shiftAngleToIntervalZeroTo360( sal_Int32& rnAngleDegree ) { //valid range: [0,360[ while( rnAngleDegree<0 ) rnAngleDegree+=360; while( rnAngleDegree>=360 ) rnAngleDegree-=360; } void lcl_ensureIntervalMinus1To1( double& rSinOrCos ) { if (rSinOrCos < -1.0) rSinOrCos = -1.0; else if (rSinOrCos > 1.0) rSinOrCos = 1.0; } bool lcl_isSinZero( double fAngleRad ) { return ::basegfx::fTools::equalZero( sin(fAngleRad), 0.0000001 ); } bool lcl_isCosZero( double fAngleRad ) { return ::basegfx::fTools::equalZero( cos(fAngleRad), 0.0000001 ); } } void ThreeDHelper::convertElevationRotationDegToXYZAngleRad( sal_Int32 nElevationDeg, sal_Int32 nRotationDeg, double& rfXAngleRad, double& rfYAngleRad, double& rfZAngleRad) { // for a description of the algorithm see issue 72994 //http://www.openoffice.org/issues/show_bug.cgi?id=72994 //http://www.openoffice.org/nonav/issues/showattachment.cgi/50608/DescriptionCorrected.odt lcl_shiftAngleToIntervalZeroTo360( nElevationDeg ); lcl_shiftAngleToIntervalZeroTo360( nRotationDeg ); double& x = rfXAngleRad; double& y = rfYAngleRad; double& z = rfZAngleRad; double E = F_PI*nElevationDeg/180; //elevation in Rad double R = F_PI*nRotationDeg/180; //rotation in Rad if( (nRotationDeg == 0 || nRotationDeg == 180 ) && ( nElevationDeg == 90 || nElevationDeg == 270 ) ) { //sR==0 && cE==0 z = 0.0; //element 23 double f23 = cos(R)*sin(E); if(f23>0) x = F_PI/2; else x = -F_PI/2; y = R; } else if( ( nRotationDeg == 90 || nRotationDeg == 270 ) && ( nElevationDeg == 90 || nElevationDeg == 270 ) ) { //cR==0 && cE==0 z = F_PI/2; if( sin(R)>0 ) x = F_PI/2.0; else x = -F_PI/2.0; if( (sin(R)*sin(E))>0 ) y = 0.0; else y = F_PI; } else if( (nRotationDeg == 0 || nRotationDeg == 180 ) && ( nElevationDeg == 0 || nElevationDeg == 180 ) ) { //sR==0 && sE==0 z = 0.0; y = R; x = E; } else if( ( nRotationDeg == 90 || nRotationDeg == 270 ) && ( nElevationDeg == 0 || nElevationDeg == 180 ) ) { //cR==0 && sE==0 z = 0.0; if( (sin(R)/cos(E))>0 ) y = F_PI/2; else y = -F_PI/2; if( (cos(E))>0 ) x = 0; else x = F_PI; } else if ( nElevationDeg == 0 || nElevationDeg == 180 ) { //sR!=0 cR!=0 sE==0 z = 0.0; x = E; y = R; //use element 13 for sign if((cos(x)*sin(y)*sin(R))<0.0) y *= -1.0; } else if ( nElevationDeg == 90 || nElevationDeg == 270 ) { //sR!=0 cR!=0 cE==0 //element 12 + 22 --> y=0 or F_PI and x=+-F_PI/2 //-->element 13/23: z = atan(sin(R)/(cos(R)*sin(E))); //use element 13 for sign for x if( (sin(R)*sin(z))>0.0 ) x = F_PI/2; else x = -F_PI/2; //use element 21 for y if( (sin(R)*sin(E)*sin(z))>0.0) y = 0.0; else y = F_PI; } else if ( nRotationDeg == 0 || nRotationDeg == 180 ) { //sE!=0 cE!=0 sR==0 z = 0.0; x = E; y = R; double f23 = cos(R)*sin(E); if( (f23 * sin(x)) < 0.0 ) x *= -1.0; //todo ?? } else if (nRotationDeg == 90 || nRotationDeg == 270) { //sE!=0 cE!=0 cR==0 //z = +- F_PI/2; //x = +- F_PI/2; z = F_PI/2; x = F_PI/2; double sR = sin(R); if( sR<0.0 ) x *= -1.0; //different signs for x and z //use element 21: double cy = sR*sin(E)/sin(z); lcl_ensureIntervalMinus1To1(cy); y = acos(cy); //use element 22 for sign: if( (sin(x)*sin(y)*sin(z)*cos(E))<0.0) y *= -1.0; } else { z = atan(tan(R) * sin(E)); if(cos(z)==0.0) { DBG_ERROR("calculation error in ThreeDHelper::convertElevationRotationDegToXYZAngleRad"); return; } double cy = cos(R)/cos(z); lcl_ensureIntervalMinus1To1(cy); y = acos(cy); //element 12 in 23 double fDenominator = cos(z)*(1.0-pow(sin(y),2)); if(fDenominator==0.0) { DBG_ERROR("calculation error in ThreeDHelper::convertElevationRotationDegToXYZAngleRad"); return; } double sx = cos(R)*sin(E)/fDenominator; lcl_ensureIntervalMinus1To1(sx); x = asin( sx ); //use element 13 for sign: double f13a = cos(x)*cos(z)*sin(y); double f13b = sin(R)-sx*sin(z); if( (f13b*f13a)<0.0 ) { //change x or y //use element 22 for further investigations: //try y *= -1; double f22a = cos(x)*cos(z); double f22b = cos(E)-(sx*sin(y)*sin(z)); if( (f22a*f22b)<0.0 ) { y *= -1; x=(F_PI-x); } } else { //change nothing or both //use element 22 for further investigations: double f22a = cos(x)*cos(z); double f22b = cos(E)-(sx*sin(y)*sin(z)); if( (f22a*f22b)<0.0 ) { y *= -1; x=(F_PI-x); } } } } void ThreeDHelper::convertXYZAngleRadToElevationRotationDeg( sal_Int32& rnElevationDeg, sal_Int32& rnRotationDeg, double fXRad, double fYRad, double fZRad) { // for a description of the algorithm see issue 72994 //http://www.openoffice.org/issues/show_bug.cgi?id=72994 //http://www.openoffice.org/nonav/issues/showattachment.cgi/50608/DescriptionCorrected.odt double R = 0.0; //Rotation in Rad double E = 0.0; //Elevation in Rad double& x = fXRad; double& y = fYRad; double& z = fZRad; double f11 = cos(y)*cos(z); if( lcl_isSinZero(y) ) { //siny == 0 if( lcl_isCosZero(x) ) { //siny == 0 && cosx == 0 if( lcl_isSinZero(z) ) { //siny == 0 && cosx == 0 && sinz == 0 //example: x=+-90 y=0oder180 z=0(oder180) //element 13+11 if( f11 > 0 ) R = 0.0; else R = F_PI; //element 23 double f23 = cos(z)*sin(x) / cos(R); if( f23 > 0 ) E = F_PI/2.0; else E = -F_PI/2.0; } else if( lcl_isCosZero(z) ) { //siny == 0 && cosx == 0 && cosz == 0 //example: x=+-90 y=0oder180 z=+-90 double f13 = sin(x)*sin(z); //element 13+11 if( f13 > 0 ) R = F_PI/2.0; else R = -F_PI/2.0; //element 21 double f21 = cos(y)*sin(z) / sin(R); if( f21 > 0 ) E = F_PI/2.0; else E = -F_PI/2.0; } else { //siny == 0 && cosx == 0 && cosz != 0 && sinz != 0 //element 11 && 13 double f13 = sin(x)*sin(z); R = atan( f13/f11 ); if(f11<0) R+=F_PI; //element 23 double f23 = cos(z)*sin(x); if( f23/cos(R) > 0 ) E = F_PI/2.0; else E = -F_PI/2.0; } } else if( lcl_isSinZero(x) ) { //sinY==0 sinX==0 //element 13+11 if( f11 > 0 ) R = 0.0; else R = F_PI; double f22 = cos(x)*cos(z); if( f22 > 0 ) E = 0.0; else E = F_PI; } else if( lcl_isSinZero(z) ) { //sinY==0 sinZ==0 sinx!=0 cosx!=0 //element 13+11 if( f11 > 0 ) R = 0.0; else R = F_PI; //element 22 && 23 double f22 = cos(x)*cos(z); double f23 = cos(z)*sin(x); E = atan( f23/(f22*cos(R)) ); if( (f22*cos(E))<0 ) E+=F_PI; } else if( lcl_isCosZero(z) ) { //sinY == 0 && cosZ == 0 && cosx != 0 && sinx != 0 double f13 = sin(x)*sin(z); //element 13+11 if( f13 > 0 ) R = F_PI/2.0; else R = -F_PI/2.0; //element 21+22 double f21 = cos(y)*sin(z); if( f21/sin(R) > 0 ) E = F_PI/2.0; else E = -F_PI/2.0; } else { //sinY == 0 && all other !=0 double f13 = sin(x)*sin(z); R = atan( f13/f11 ); if( (f11*cos(R))<0.0 ) R+=F_PI; double f22 = cos(x)*cos(z); if( !lcl_isCosZero(R) ) E = atan( cos(z)*sin(x) /( f22*cos(R) ) ); else E = atan( cos(y)*sin(z) /( f22*sin(R) ) ); if( (f22*cos(E))<0 ) E+=F_PI; } } else if( lcl_isCosZero(y) ) { //cosY==0 double f13 = sin(x)*sin(z)+cos(x)*cos(z)*sin(y); if( f13 >= 0 ) R = F_PI/2.0; else R = -F_PI/2.0; double f22 = cos(x)*cos(z)+sin(x)*sin(y)*sin(z); if( f22 >= 0 ) E = 0.0; else E = F_PI; } else if( lcl_isSinZero(x) ) { //cosY!=0 sinY!=0 sinX=0 if( lcl_isSinZero(z) ) { //cosY!=0 sinY!=0 sinX=0 sinZ=0 double f13 = cos(x)*cos(z)*sin(y); R = atan( f13/f11 ); //R = asin(f13); if( f11<0 ) R+=F_PI; double f22 = cos(x)*cos(z); if( f22>0 ) E = 0.0; else E = F_PI; } else if( lcl_isCosZero(z) ) { //cosY!=0 sinY!=0 sinX=0 cosZ=0 R = x; E = y;//or -y //use 23 for 'signs' double f23 = -1.0*cos(x)*sin(y)*sin(z); if( (f23*cos(R)*sin(E))<0.0 ) { //change R or E E = -y; } } else { //cosY!=0 sinY!=0 sinX=0 sinZ!=0 cosZ!=0 double f13 = cos(x)*cos(z)*sin(y); R = atan( f13/f11 ); if( f11<0 ) R+=F_PI; double f21 = cos(y)*sin(z); double f22 = cos(x)*cos(z); E = atan(f21/(f22*sin(R)) ); if( (f22*cos(E))<0.0 ) E+=F_PI; } } else if( lcl_isCosZero(x) ) { //cosY!=0 sinY!=0 cosX=0 if( lcl_isSinZero(z) ) { //cosY!=0 sinY!=0 cosX=0 sinZ=0 R=0;//13 -> R=0 or F_PI if( f11<0.0 ) R=F_PI; E=F_PI/2;//22 -> E=+-F_PI/2 //use element 11 and 23 for sign double f23 = cos(z)*sin(x); if( (f11*f23*sin(E))<0.0 ) E=-F_PI/2.0; } else if( lcl_isCosZero(z) ) { //cosY!=0 sinY!=0 cosX=0 cosZ=0 //element 11 & 13: if( (sin(x)*sin(z))>0.0 ) R=F_PI/2.0; else R=-F_PI/2.0; //element 22: E=acos( sin(x)*sin(y)*sin(z)); //use element 21 for sign: if( (cos(y)*sin(z)*sin(R)*sin(E))<0.0 ) E*=-1.0; } else { //cosY!=0 sinY!=0 cosX=0 sinZ!=0 cosZ!=0 //element 13/11 R = atan( sin(x)*sin(z)/(cos(y)*cos(z)) ); //use 13 for 'sign' if( (sin(x)*sin(z))<0.0 ) R += F_PI; //element 22 E = acos(sin(x)*sin(y)*sin(z) ); //use 21 for sign if( (cos(y)*sin(z)*sin(R)*sin(E))<0.0 ) E*=-1.0; } } else if( lcl_isSinZero(z) ) { //cosY!=0 sinY!=0 sinX!=0 cosX!=0 sinZ=0 //element 11 R=y; //use elenment 13 for sign if( (cos(x)*cos(z)*sin(y)*sin(R))<0.0 ) R*=-1.0; //element 22 E = acos( cos(x)*cos(z) ); //use element 23 for sign if( (cos(z)*sin(x)*cos(R)*sin(E))<0.0 ) E*=-1.0; } else if( lcl_isCosZero(z) ) { //cosY!=0 sinY!=0 sinX!=0 cosX!=0 cosZ=0 //element 21/23 R=atan(-cos(y)/(cos(x)*sin(y))); //use element 13 for 'sign' if( (sin(x)*sin(z)*sin(R))<0.0 ) R+=F_PI; //element 21/22 E=atan( cos(y)*sin(z)/(sin(R)*sin(x)*sin(y)*sin(z)) ); //use element 23 for 'sign' if( (-cos(x)*sin(y)*sin(z)*cos(R)*sin(E))<0.0 ) E+=F_PI; } else { //cosY!=0 sinY!=0 sinX!=0 cosX!=0 sinZ!=0 cosZ!=0 //13/11: double f13 = sin(x)*sin(z)+cos(x)*cos(z)*sin(y); R = atan( f13/ f11 ); if(f11<0.0) R+=F_PI; double f22 = cos(x)*cos(z)+sin(x)*sin(y)*sin(z); double f23 = cos(x)*sin(y)*sin(z)-cos(z)*sin(x); //23/22: E = atan( -1.0*f23/(f22*cos(R)) ); if(f22<0.0) E+=F_PI; } rnElevationDeg = ::basegfx::fround( BaseGFXHelper::Rad2Deg( E ) ); rnRotationDeg = ::basegfx::fround( BaseGFXHelper::Rad2Deg( R ) ); } double ThreeDHelper::getValueClippedToRange( double fAngle, const double& fPositivLimit ) { if( fAngle<-1*fPositivLimit ) fAngle=-1*fPositivLimit; else if( fAngle>fPositivLimit ) fAngle=fPositivLimit; return fAngle; } double ThreeDHelper::getXDegreeAngleLimitForRightAngledAxes() { return 90.0; } double ThreeDHelper::getYDegreeAngleLimitForRightAngledAxes() { return 45.0; } void ThreeDHelper::adaptRadAnglesForRightAngledAxes( double& rfXAngleRad, double& rfYAngleRad ) { rfXAngleRad = ThreeDHelper::getValueClippedToRange(rfXAngleRad, BaseGFXHelper::Deg2Rad(ThreeDHelper::getXDegreeAngleLimitForRightAngledAxes()) ); rfYAngleRad = ThreeDHelper::getValueClippedToRange(rfYAngleRad, BaseGFXHelper::Deg2Rad(ThreeDHelper::getYDegreeAngleLimitForRightAngledAxes()) ); } void ThreeDHelper::getRotationAngleFromDiagram( const Reference< beans::XPropertySet >& xSceneProperties, double& rfXAngleRad, double& rfYAngleRad, double& rfZAngleRad ) { //takes the camera and the transformation matrix into account rfXAngleRad = rfYAngleRad = rfZAngleRad = 0.0; if( !xSceneProperties.is() ) return; //get camera rotation ::basegfx::B3DHomMatrix aFixCameraRotationMatrix( lcl_getCameraMatrix( xSceneProperties ) ); BaseGFXHelper::ReduceToRotationMatrix( aFixCameraRotationMatrix ); //get scene rotation ::basegfx::B3DHomMatrix aSceneRotation; { drawing::HomogenMatrix aHomMatrix; if( xSceneProperties->getPropertyValue( C2U("D3DTransformMatrix")) >>= aHomMatrix ) { aSceneRotation = BaseGFXHelper::HomogenMatrixToB3DHomMatrix( aHomMatrix ); BaseGFXHelper::ReduceToRotationMatrix( aSceneRotation ); } } ::basegfx::B3DHomMatrix aResultRotation = aFixCameraRotationMatrix * aSceneRotation; ::basegfx::B3DTuple aRotation( BaseGFXHelper::GetRotationFromMatrix( aResultRotation ) ); rfXAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(aRotation.getX()); rfYAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(aRotation.getY()); rfZAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(aRotation.getZ()); if(rfZAngleRad<(-F_PI/2) || rfZAngleRad>(F_PI/2)) { rfZAngleRad-=F_PI; rfXAngleRad-=F_PI; rfYAngleRad=(F_PI-rfYAngleRad); rfXAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(rfXAngleRad); rfYAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(rfYAngleRad); rfZAngleRad = lcl_shiftAngleToIntervalMinusPiToPi(rfZAngleRad); } } void ThreeDHelper::switchRightAngledAxes( const Reference< beans::XPropertySet >& xSceneProperties, sal_Bool bRightAngledAxes, bool bRotateLights ) { try { if( xSceneProperties.is() ) { sal_Bool bOldRightAngledAxes = sal_False; xSceneProperties->getPropertyValue( C2U("RightAngledAxes")) >>= bOldRightAngledAxes; if( bOldRightAngledAxes!=bRightAngledAxes) { xSceneProperties->setPropertyValue( C2U("RightAngledAxes"), uno::makeAny( bRightAngledAxes )); if( bRotateLights ) { if(bRightAngledAxes) { ::basegfx::B3DHomMatrix aInverseRotation( lcl_getInverseRotationMatrix( xSceneProperties ) ); lcl_rotateLights( aInverseRotation, xSceneProperties ); } else { ::basegfx::B3DHomMatrix aCompleteRotation( lcl_getCompleteRotationMatrix( xSceneProperties ) ); lcl_rotateLights( aCompleteRotation, xSceneProperties ); } } } } } catch( const uno::Exception & ex ) { ASSERT_EXCEPTION( ex ); } } void ThreeDHelper::setRotationAngleToDiagram( const Reference< beans::XPropertySet >& xSceneProperties , double fXAngleRad, double fYAngleRad, double fZAngleRad ) { //the rotation of the camera is not touched but taken into account //the rotation difference is applied to the transformation matrix //the light sources will be adapted also if( !xSceneProperties.is() ) return; try { //remind old rotation for adaption of light directions ::basegfx::B3DHomMatrix aInverseOldRotation( lcl_getInverseRotationMatrix( xSceneProperties ) ); ::basegfx::B3DHomMatrix aInverseCameraRotation; { ::basegfx::B3DTuple aR( BaseGFXHelper::GetRotationFromMatrix( lcl_getCameraMatrix( xSceneProperties ) ) ); aInverseCameraRotation.rotate( 0.0, 0.0, -aR.getZ() ); aInverseCameraRotation.rotate( 0.0, -aR.getY(), 0.0 ); aInverseCameraRotation.rotate( -aR.getX(), 0.0, 0.0 ); } ::basegfx::B3DHomMatrix aCumulatedRotation; aCumulatedRotation.rotate( fXAngleRad, fYAngleRad, fZAngleRad ); //calculate new scene matrix ::basegfx::B3DHomMatrix aSceneRotation = aInverseCameraRotation*aCumulatedRotation; BaseGFXHelper::ReduceToRotationMatrix( aSceneRotation ); //set new rotation to transformation matrix xSceneProperties->setPropertyValue( C2U("D3DTransformMatrix"), uno::makeAny( BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aSceneRotation ))); //rotate lights if RightAngledAxes are not set or not supported sal_Bool bRightAngledAxes = sal_False; xSceneProperties->getPropertyValue( C2U("RightAngledAxes")) >>= bRightAngledAxes; uno::Reference< chart2::XDiagram > xDiagram( xSceneProperties, uno::UNO_QUERY ); if(!bRightAngledAxes || !ChartTypeHelper::isSupportingRightAngledAxes( DiagramHelper::getChartTypeByIndex( xDiagram, 0 ) ) ) { ::basegfx::B3DHomMatrix aNewRotation; aNewRotation.rotate( fXAngleRad, fYAngleRad, fZAngleRad ); lcl_rotateLights( aNewRotation*aInverseOldRotation, xSceneProperties ); } } catch( const uno::Exception & ex ) { ASSERT_EXCEPTION( ex ); } } void ThreeDHelper::getRotationFromDiagram( const uno::Reference< beans::XPropertySet >& xSceneProperties , sal_Int32& rnHorizontalAngleDegree, sal_Int32& rnVerticalAngleDegree ) { double fXAngle, fYAngle, fZAngle; ThreeDHelper::getRotationAngleFromDiagram( xSceneProperties, fXAngle, fYAngle, fZAngle ); if( !lcl_isRightAngledAxesSetAndSupported( xSceneProperties ) ) { ThreeDHelper::convertXYZAngleRadToElevationRotationDeg( rnHorizontalAngleDegree, rnVerticalAngleDegree, fXAngle, fYAngle, fZAngle); rnVerticalAngleDegree*=-1; } else { fXAngle = BaseGFXHelper::Rad2Deg( fXAngle ); fYAngle = BaseGFXHelper::Rad2Deg( fYAngle ); fZAngle = BaseGFXHelper::Rad2Deg( fZAngle ); rnHorizontalAngleDegree = ::basegfx::fround(fXAngle); rnVerticalAngleDegree = ::basegfx::fround(-1.0*fYAngle); //nZRotation = ::basegfx::fround(-1.0*fZAngle); } lcl_shiftAngleToIntervalMinus180To180( rnHorizontalAngleDegree ); lcl_shiftAngleToIntervalMinus180To180( rnVerticalAngleDegree ); } void ThreeDHelper::setRotationToDiagram( const uno::Reference< beans::XPropertySet >& xSceneProperties , sal_Int32 nHorizontalAngleDegree, sal_Int32 nVerticalYAngleDegree ) { //todo: x and y is not equal to horz and vert in case of RightAngledAxes==false double fXAngle = BaseGFXHelper::Deg2Rad( nHorizontalAngleDegree ); double fYAngle = BaseGFXHelper::Deg2Rad( -1*nVerticalYAngleDegree ); double fZAngle = 0.0; if( !lcl_isRightAngledAxesSetAndSupported( xSceneProperties ) ) ThreeDHelper::convertElevationRotationDegToXYZAngleRad( nHorizontalAngleDegree, -1*nVerticalYAngleDegree, fXAngle, fYAngle, fZAngle ); ThreeDHelper::setRotationAngleToDiagram( xSceneProperties, fXAngle, fYAngle, fZAngle ); } void ThreeDHelper::getCameraDistanceRange( double& rfMinimumDistance, double& rfMaximumDistance ) { rfMinimumDistance = 3.0/4.0*FIXED_SIZE_FOR_3D_CHART_VOLUME;//empiric value rfMaximumDistance = 20.0*FIXED_SIZE_FOR_3D_CHART_VOLUME;//empiric value } void ThreeDHelper::ensureCameraDistanceRange( double& rfCameraDistance ) { double fMin, fMax; getCameraDistanceRange( fMin, fMax ); if( rfCameraDistance < fMin ) rfCameraDistance = fMin; if( rfCameraDistance > fMax ) rfCameraDistance = fMax; } double ThreeDHelper::getCameraDistance( const Reference< beans::XPropertySet >& xSceneProperties ) { double fCameraDistance = FIXED_SIZE_FOR_3D_CHART_VOLUME; if( !xSceneProperties.is() ) return fCameraDistance; try { drawing::CameraGeometry aCG( ThreeDHelper::getDefaultCameraGeometry() ); xSceneProperties->getPropertyValue( C2U( "D3DCameraGeometry" ) ) >>= aCG; ::basegfx::B3DVector aVRP( BaseGFXHelper::Position3DToB3DVector( aCG.vrp ) ); fCameraDistance = aVRP.getLength(); ensureCameraDistanceRange( fCameraDistance ); } catch( const uno::Exception & ex ) { ASSERT_EXCEPTION( ex ); } return fCameraDistance; } void ThreeDHelper::setCameraDistance( const Reference< beans::XPropertySet >& xSceneProperties, double fCameraDistance ) { if( !xSceneProperties.is() ) return; try { if( fCameraDistance <= 0 ) fCameraDistance = FIXED_SIZE_FOR_3D_CHART_VOLUME; drawing::CameraGeometry aCG( ThreeDHelper::getDefaultCameraGeometry() ); xSceneProperties->getPropertyValue( C2U( "D3DCameraGeometry" ) ) >>= aCG; ::basegfx::B3DVector aVRP( BaseGFXHelper::Position3DToB3DVector( aCG.vrp ) ); if( ::basegfx::fTools::equalZero( aVRP.getLength() ) ) aVRP = ::basegfx::B3DVector(0,0,1); aVRP.setLength(fCameraDistance); aCG.vrp = BaseGFXHelper::B3DVectorToPosition3D( aVRP ); xSceneProperties->setPropertyValue( C2U("D3DCameraGeometry"), uno::makeAny( aCG )); } catch( const uno::Exception & ex ) { ASSERT_EXCEPTION( ex ); } } double ThreeDHelper::CameraDistanceToPerspective( double fCameraDistance ) { double fRet = fCameraDistance; double fMin, fMax; ThreeDHelper::getCameraDistanceRange( fMin, fMax ); //fMax <-> 0; fMin <->100 //a/x + b = y double a = 100.0*fMax*fMin/(fMax-fMin); double b = -a/fMax; fRet = a/fCameraDistance + b; return fRet; } double ThreeDHelper::PerspectiveToCameraDistance( double fPerspective ) { double fRet = fPerspective; double fMin, fMax; ThreeDHelper::getCameraDistanceRange( fMin, fMax ); //fMax <-> 0; fMin <->100 //a/x + b = y double a = 100.0*fMax*fMin/(fMax-fMin); double b = -a/fMax; fRet = a/(fPerspective - b); return fRet; } ThreeDLookScheme ThreeDHelper::detectScheme( const uno::Reference< XDiagram >& xDiagram ) { ThreeDLookScheme aScheme = ThreeDLookScheme_Unknown; sal_Int32 nRoundedEdges; sal_Int32 nObjectLines; ThreeDHelper::getRoundedEdgesAndObjectLines( xDiagram, nRoundedEdges, nObjectLines ); //get shade mode and light settings: drawing::ShadeMode aShadeMode( drawing::ShadeMode_SMOOTH ); uno::Reference< beans::XPropertySet > xDiagramProps( xDiagram, uno::UNO_QUERY ); try { if( xDiagramProps.is() ) xDiagramProps->getPropertyValue( C2U( "D3DSceneShadeMode" ) )>>= aShadeMode; } catch( uno::Exception & ex ) { ASSERT_EXCEPTION( ex ); } if( lcl_isSimpleScheme( aShadeMode, nRoundedEdges, nObjectLines, xDiagram ) ) { if( lcl_isSimpleLightScheme(xDiagramProps) ) aScheme = ThreeDLookScheme_Simple; } else if( lcl_isRealisticScheme( aShadeMode, nRoundedEdges, nObjectLines ) ) { if( lcl_isRealisticLightScheme(xDiagramProps) ) aScheme = ThreeDLookScheme_Realistic; } return aScheme; } void ThreeDHelper::setScheme( const uno::Reference< XDiagram >& xDiagram, ThreeDLookScheme aScheme ) { if( aScheme == ThreeDLookScheme_Unknown ) return; drawing::ShadeMode aShadeMode; sal_Int32 nRoundedEdges; sal_Int32 nObjectLines; if( aScheme == ThreeDLookScheme_Simple ) lcl_setSimpleScheme(aShadeMode,nRoundedEdges,nObjectLines,xDiagram); else lcl_setRealisticScheme(aShadeMode,nRoundedEdges,nObjectLines); try { ThreeDHelper::setRoundedEdgesAndObjectLines( xDiagram, nRoundedEdges, nObjectLines ); uno::Reference< beans::XPropertySet > xProp( xDiagram, uno::UNO_QUERY ); if( xProp.is() ) { drawing::ShadeMode aOldShadeMode; if( ! ( (xProp->getPropertyValue( C2U( "D3DSceneShadeMode" ) )>>=aOldShadeMode) && aOldShadeMode == aShadeMode )) { xProp->setPropertyValue( C2U( "D3DSceneShadeMode" ), uno::makeAny( aShadeMode )); } } lcl_setLightsForScheme( xProp, aScheme ); } catch( uno::Exception & ex ) { ASSERT_EXCEPTION( ex ); } } void ThreeDHelper::set3DSettingsToDefault( const uno::Reference< beans::XPropertySet >& xSceneProperties ) { Reference< beans::XPropertyState > xState( xSceneProperties, uno::UNO_QUERY ); if(xState.is()) { xState->setPropertyToDefault( C2U("D3DSceneDistance")); xState->setPropertyToDefault( C2U("D3DSceneFocalLength")); } ThreeDHelper::setDefaultRotation( xSceneProperties ); ThreeDHelper::setDefaultIllumination( xSceneProperties ); } void ThreeDHelper::setDefaultRotation( const uno::Reference< beans::XPropertySet >& xSceneProperties, bool bPieOrDonut ) { if( !xSceneProperties.is() ) return; drawing::CameraGeometry aCameraGeo( ThreeDHelper::getDefaultCameraGeometry( bPieOrDonut ) ); xSceneProperties->setPropertyValue( C2U("D3DCameraGeometry"), uno::makeAny( aCameraGeo )); ::basegfx::B3DHomMatrix aSceneRotation; if( bPieOrDonut ) aSceneRotation.rotate( -F_PI/3.0, 0, 0 ); xSceneProperties->setPropertyValue( C2U("D3DTransformMatrix"), uno::makeAny( BaseGFXHelper::B3DHomMatrixToHomogenMatrix( aSceneRotation ))); } void ThreeDHelper::setDefaultRotation( const uno::Reference< beans::XPropertySet >& xSceneProperties ) { bool bPieOrDonut( DiagramHelper::isPieOrDonutChart( uno::Reference< XDiagram >(xSceneProperties, uno::UNO_QUERY) ) ); ThreeDHelper::setDefaultRotation( xSceneProperties, bPieOrDonut ); } void ThreeDHelper::setDefaultIllumination( const uno::Reference< beans::XPropertySet >& xSceneProperties ) { if( !xSceneProperties.is() ) return; drawing::ShadeMode aShadeMode( drawing::ShadeMode_SMOOTH ); try { xSceneProperties->getPropertyValue( C2U( "D3DSceneShadeMode" ) )>>= aShadeMode; xSceneProperties->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_1 ), uno::makeAny( sal_False ) ); xSceneProperties->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_3 ), uno::makeAny( sal_False ) ); xSceneProperties->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_4 ), uno::makeAny( sal_False ) ); xSceneProperties->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_5 ), uno::makeAny( sal_False ) ); xSceneProperties->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_6 ), uno::makeAny( sal_False ) ); xSceneProperties->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_7 ), uno::makeAny( sal_False ) ); xSceneProperties->setPropertyValue( C2U( UNO_NAME_3D_SCENE_LIGHTON_8 ), uno::makeAny( sal_False ) ); } catch( uno::Exception & ex ) { ASSERT_EXCEPTION( ex ); } ThreeDLookScheme aScheme = (drawing::ShadeMode_FLAT==aShadeMode) ? ThreeDLookScheme_Simple : ThreeDLookScheme_Realistic; lcl_setLightsForScheme( xSceneProperties, aScheme ); } void ThreeDHelper::getRoundedEdgesAndObjectLines( const uno::Reference< XDiagram > & xDiagram , sal_Int32& rnRoundedEdges, sal_Int32& rnObjectLines ) { rnRoundedEdges = -1; rnObjectLines = -1; try { bool bDifferentRoundedEdges = false; bool bDifferentObjectLines = false; drawing::LineStyle aLineStyle( drawing::LineStyle_SOLID ); ::std::vector< uno::Reference< XDataSeries > > aSeriesList( DiagramHelper::getDataSeriesFromDiagram( xDiagram ) ); sal_Int32 nSeriesCount = static_cast( aSeriesList.size() ); rtl::OUString aPercentDiagonalPropertyName( C2U( "PercentDiagonal" ) ); rtl::OUString aBorderStylePropertyName( C2U( "BorderStyle" ) ); for( sal_Int32 nS = 0; nS < nSeriesCount; ++nS ) { uno::Reference< XDataSeries > xSeries( aSeriesList[nS] ); uno::Reference< beans::XPropertySet > xProp( xSeries, uno::UNO_QUERY ); if(!nS) { rnRoundedEdges = 0; try { sal_Int16 nPercentDiagonal = 0; xProp->getPropertyValue( aPercentDiagonalPropertyName ) >>= nPercentDiagonal; rnRoundedEdges = static_cast< sal_Int32 >( nPercentDiagonal ); if( DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries , aPercentDiagonalPropertyName, uno::makeAny(nPercentDiagonal) ) ) bDifferentRoundedEdges = true; } catch( uno::Exception& e ) { ASSERT_EXCEPTION( e ); bDifferentRoundedEdges = true; } try { xProp->getPropertyValue( aBorderStylePropertyName ) >>= aLineStyle; if( DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries , aBorderStylePropertyName, uno::makeAny(aLineStyle) ) ) bDifferentObjectLines = true; } catch( uno::Exception& e ) { ASSERT_EXCEPTION( e ); bDifferentObjectLines = true; } } else { if( !bDifferentRoundedEdges ) { sal_Int16 nPercentDiagonal = 0; xProp->getPropertyValue( aPercentDiagonalPropertyName ) >>= nPercentDiagonal; sal_Int32 nCurrentRoundedEdges = static_cast< sal_Int32 >( nPercentDiagonal ); if(nCurrentRoundedEdges!=rnRoundedEdges || DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries , aPercentDiagonalPropertyName, uno::makeAny( static_cast< sal_Int16 >(rnRoundedEdges) ) ) ) { bDifferentRoundedEdges = true; nCurrentRoundedEdges = -1; } } if( !bDifferentObjectLines ) { drawing::LineStyle aCurrentLineStyle; xProp->getPropertyValue( aBorderStylePropertyName ) >>= aCurrentLineStyle; if(aCurrentLineStyle!=aLineStyle || DataSeriesHelper::hasAttributedDataPointDifferentValue( xSeries , aBorderStylePropertyName, uno::makeAny(aLineStyle) ) ) bDifferentObjectLines = true; } } if( bDifferentRoundedEdges && bDifferentObjectLines ) break; } //set rnObjectLines rnObjectLines = 0; if( bDifferentObjectLines ) rnObjectLines = -1; else if( aLineStyle == drawing::LineStyle_SOLID ) rnObjectLines = 1; } catch( uno::Exception& e ) { ASSERT_EXCEPTION( e ); } } void ThreeDHelper::setRoundedEdgesAndObjectLines( const uno::Reference< XDiagram > & xDiagram , sal_Int32 nRoundedEdges, sal_Int32 nObjectLines ) { if( (nRoundedEdges<0||nRoundedEdges>100) && nObjectLines!=0 && nObjectLines!=1 ) return; drawing::LineStyle aLineStyle( drawing::LineStyle_NONE ); if(nObjectLines==1) aLineStyle = drawing::LineStyle_SOLID; uno::Any aALineStyle( uno::makeAny(aLineStyle)); uno::Any aARoundedEdges( uno::makeAny( static_cast< sal_Int16 >( nRoundedEdges ))); ::std::vector< uno::Reference< XDataSeries > > aSeriesList( DiagramHelper::getDataSeriesFromDiagram( xDiagram ) ); sal_Int32 nSeriesCount = static_cast( aSeriesList.size() ); for( sal_Int32 nS = 0; nS < nSeriesCount; ++nS ) { uno::Reference< XDataSeries > xSeries( aSeriesList[nS] ); if( nRoundedEdges>=0 && nRoundedEdges<=100 ) DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, C2U( "PercentDiagonal" ), aARoundedEdges ); if( nObjectLines==0 || nObjectLines==1 ) DataSeriesHelper::setPropertyAlsoToAllAttributedDataPoints( xSeries, C2U( "BorderStyle" ), aALineStyle ); } } CuboidPlanePosition ThreeDHelper::getAutomaticCuboidPlanePositionForStandardLeftWall( const Reference< beans::XPropertySet >& xSceneProperties ) { CuboidPlanePosition eRet(CuboidPlanePosition_Left); double fXAngleRad=0.0; double fYAngleRad=0.0; double fZAngleRad=0.0; ThreeDHelper::getRotationAngleFromDiagram( xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad ); if( lcl_isRightAngledAxesSetAndSupported( xSceneProperties ) ) { ThreeDHelper::adaptRadAnglesForRightAngledAxes( fXAngleRad, fYAngleRad ); fZAngleRad=0.0; } if( sin(fYAngleRad)>0.0 ) eRet = CuboidPlanePosition_Right; return eRet; } CuboidPlanePosition ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBackWall( const Reference< beans::XPropertySet >& xSceneProperties ) { CuboidPlanePosition eRet(CuboidPlanePosition_Back); double fXAngleRad=0.0; double fYAngleRad=0.0; double fZAngleRad=0.0; ThreeDHelper::getRotationAngleFromDiagram( xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad ); if( lcl_isRightAngledAxesSetAndSupported( xSceneProperties ) ) { ThreeDHelper::adaptRadAnglesForRightAngledAxes( fXAngleRad, fYAngleRad ); fZAngleRad=0.0; } if( cos(fXAngleRad)*cos(fYAngleRad)<0.0 ) eRet = CuboidPlanePosition_Front; return eRet; } CuboidPlanePosition ThreeDHelper::getAutomaticCuboidPlanePositionForStandardBottom( const Reference< beans::XPropertySet >& xSceneProperties ) { CuboidPlanePosition eRet(CuboidPlanePosition_Bottom); double fXAngleRad=0.0; double fYAngleRad=0.0; double fZAngleRad=0.0; ThreeDHelper::getRotationAngleFromDiagram( xSceneProperties, fXAngleRad, fYAngleRad, fZAngleRad ); if( lcl_isRightAngledAxesSetAndSupported( xSceneProperties ) ) { ThreeDHelper::adaptRadAnglesForRightAngledAxes( fXAngleRad, fYAngleRad ); fZAngleRad=0.0; } if( sin(fXAngleRad)*cos(fYAngleRad)<0.0 ) eRet = CuboidPlanePosition_Top; return eRet; } //............................................................................. } //namespace chart //.............................................................................