LCOV - code coverage report
Current view: top level - chart2/source/view/charttypes - PieChart.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 176 433 40.6 %
Date: 2012-08-25 Functions: 23 32 71.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 134 654 20.5 %

           Branch data     Line data    Source code
       1                 :            : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2                 :            : /*
       3                 :            :  * This file is part of the LibreOffice project.
       4                 :            :  *
       5                 :            :  * This Source Code Form is subject to the terms of the Mozilla Public
       6                 :            :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7                 :            :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8                 :            :  *
       9                 :            :  * This file incorporates work covered by the following license notice:
      10                 :            :  *
      11                 :            :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12                 :            :  *   contributor license agreements. See the NOTICE file distributed
      13                 :            :  *   with this work for additional information regarding copyright
      14                 :            :  *   ownership. The ASF licenses this file to you under the Apache
      15                 :            :  *   License, Version 2.0 (the "License"); you may not use this file
      16                 :            :  *   except in compliance with the License. You may obtain a copy of
      17                 :            :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18                 :            :  */
      19                 :            : 
      20                 :            : #include "PieChart.hxx"
      21                 :            : #include "PlottingPositionHelper.hxx"
      22                 :            : #include "ShapeFactory.hxx"
      23                 :            : #include "PolarLabelPositionHelper.hxx"
      24                 :            : #include "macros.hxx"
      25                 :            : #include "CommonConverters.hxx"
      26                 :            : #include "ViewDefines.hxx"
      27                 :            : #include "ObjectIdentifier.hxx"
      28                 :            : 
      29                 :            : #include <com/sun/star/chart/DataLabelPlacement.hpp>
      30                 :            : #include <com/sun/star/chart2/XColorScheme.hpp>
      31                 :            : 
      32                 :            : #include <com/sun/star/container/XChild.hpp>
      33                 :            : #include <rtl/math.hxx>
      34                 :            : 
      35                 :            : #include <boost/scoped_ptr.hpp>
      36                 :            : 
      37                 :            : //.............................................................................
      38                 :            : namespace chart
      39                 :            : {
      40                 :            : //.............................................................................
      41                 :            : using namespace ::com::sun::star;
      42                 :            : using namespace ::com::sun::star::chart2;
      43                 :            : 
      44                 :            : class PiePositionHelper : public PolarPlottingPositionHelper
      45                 :            : {
      46                 :            : public:
      47                 :            :     PiePositionHelper( NormalAxis eNormalAxis, double fAngleDegreeOffset );
      48                 :            :     virtual ~PiePositionHelper();
      49                 :            : 
      50                 :            :     bool    getInnerAndOuterRadius( double fCategoryX, double& fLogicInnerRadius, double& fLogicOuterRadius, bool bUseRings, double fMaxOffset ) const;
      51                 :            : 
      52                 :            : public:
      53                 :            :     //Distance between different category rings, seen relative to width of a ring:
      54                 :            :     double  m_fRingDistance; //>=0 m_fRingDistance=1 --> distance == width
      55                 :            : };
      56                 :            : 
      57                 :         19 : PiePositionHelper::PiePositionHelper( NormalAxis eNormalAxis, double fAngleDegreeOffset )
      58                 :            :         : PolarPlottingPositionHelper(eNormalAxis)
      59                 :         19 :         , m_fRingDistance(0.0)
      60                 :            : {
      61                 :         19 :     m_fRadiusOffset = 0.0;
      62                 :         19 :     m_fAngleDegreeOffset = fAngleDegreeOffset;
      63                 :         19 : }
      64                 :            : 
      65                 :         19 : PiePositionHelper::~PiePositionHelper()
      66                 :            : {
      67         [ -  + ]:         38 : }
      68                 :            : 
      69                 :        152 : bool PiePositionHelper::getInnerAndOuterRadius( double fCategoryX
      70                 :            :                                                , double& fLogicInnerRadius, double& fLogicOuterRadius
      71                 :            :                                                , bool bUseRings, double fMaxOffset ) const
      72                 :            : {
      73         [ +  - ]:        152 :     if( !bUseRings )
      74                 :        152 :         fCategoryX = 1.0;
      75                 :            : 
      76                 :        152 :     bool bIsVisible = true;
      77                 :        152 :     double fLogicInner = fCategoryX -0.5+m_fRingDistance/2.0;
      78                 :        152 :     double fLogicOuter = fCategoryX +0.5-m_fRingDistance/2.0;
      79                 :            : 
      80         [ +  - ]:        152 :     if( !isMathematicalOrientationRadius() )
      81                 :            :     {
      82                 :            :         //in this case the given getMaximumX() was not corrcect instead the minimum should have been smaller by fMaxOffset
      83                 :            :         //but during getMaximumX and getMimumX we do not know the axis orientation
      84                 :        152 :         fLogicInner += fMaxOffset;
      85                 :        152 :         fLogicOuter += fMaxOffset;
      86                 :            :     }
      87                 :            : 
      88         [ -  + ]:        152 :     if( fLogicInner >= getLogicMaxX() )
      89                 :          0 :         return false;
      90         [ -  + ]:        152 :     if( fLogicOuter <= getLogicMinX() )
      91                 :          0 :         return false;
      92                 :            : 
      93         [ -  + ]:        152 :     if( fLogicInner < getLogicMinX() )
      94                 :          0 :         fLogicInner = getLogicMinX();
      95         [ -  + ]:        152 :     if( fLogicOuter > getLogicMaxX() )
      96                 :          0 :         fLogicOuter = getLogicMaxX();
      97                 :            : 
      98                 :        152 :     fLogicInnerRadius = fLogicInner;
      99                 :        152 :     fLogicOuterRadius = fLogicOuter;
     100         [ +  - ]:        152 :     if( !isMathematicalOrientationRadius() )
     101                 :        152 :         std::swap(fLogicInnerRadius,fLogicOuterRadius);
     102                 :        152 :     return bIsVisible;
     103                 :            : }
     104                 :            : 
     105                 :            : //-----------------------------------------------------------------------------
     106                 :            : //-----------------------------------------------------------------------------
     107                 :            : //-----------------------------------------------------------------------------
     108                 :            : 
     109                 :         19 : PieChart::PieChart( const uno::Reference<XChartType>& xChartTypeModel
     110                 :            :                    , sal_Int32 nDimensionCount
     111                 :            :                    , bool bExcludingPositioning )
     112                 :            :         : VSeriesPlotter( xChartTypeModel, nDimensionCount )
     113 [ -  + ][ +  - ]:         19 :         , m_pPosHelper( new PiePositionHelper( NormalAxis_Z, (m_nDimension==3)?0.0:90.0 ) )
     114                 :            :         , m_bUseRings(false)
     115 [ +  - ][ +  - ]:         38 :         , m_bSizeExcludesLabelsAndExplodedSegments(bExcludingPositioning)
     116                 :            : {
     117                 :         19 :     ::rtl::math::setNan(&m_fMaxOffset);
     118                 :            : 
     119                 :         19 :     PlotterBase::m_pPosHelper = m_pPosHelper;
     120                 :         19 :     VSeriesPlotter::m_pMainPosHelper = m_pPosHelper;
     121                 :         19 :     m_pPosHelper->m_fRadiusOffset = 0.0;
     122                 :         19 :     m_pPosHelper->m_fRingDistance = 0.0;
     123                 :            : 
     124         [ +  - ]:         19 :     uno::Reference< beans::XPropertySet > xChartTypeProps( xChartTypeModel, uno::UNO_QUERY );
     125         [ +  - ]:         19 :     if( xChartTypeProps.is() ) try
     126                 :            :     {
     127 [ +  - ][ +  - ]:         19 :         xChartTypeProps->getPropertyValue( C2U( "UseRings" )) >>= m_bUseRings;
         [ +  - ][ #  # ]
     128         [ -  + ]:         19 :         if( m_bUseRings )
     129                 :            :         {
     130                 :          0 :             m_pPosHelper->m_fRadiusOffset = 1.0;
     131         [ #  # ]:          0 :             if( nDimensionCount==3 )
     132                 :          0 :                 m_pPosHelper->m_fRingDistance = 0.1;
     133                 :            :         }
     134                 :            :     }
     135         [ #  # ]:          0 :     catch( const uno::Exception& e )
     136                 :            :     {
     137                 :            :         ASSERT_EXCEPTION( e );
     138                 :         19 :     }
     139                 :         19 : }
     140                 :            : 
     141                 :         19 : PieChart::~PieChart()
     142                 :            : {
     143 [ +  - ][ +  - ]:         19 :     delete m_pPosHelper;
     144         [ -  + ]:         38 : }
     145                 :            : 
     146                 :            : //-----------------------------------------------------------------
     147                 :            : 
     148                 :         19 : void PieChart::setScales( const std::vector< ExplicitScaleData >& rScales, bool /* bSwapXAndYAxis */ )
     149                 :            : {
     150                 :            :     OSL_ENSURE(m_nDimension<=static_cast<sal_Int32>(rScales.size()),"Dimension of Plotter does not fit two dimension of given scale sequence");
     151                 :         19 :     m_pPosHelper->setScales( rScales, true );
     152                 :         19 : }
     153                 :            : 
     154                 :            : //-----------------------------------------------------------------
     155                 :            : 
     156                 :         19 : drawing::Direction3D PieChart::getPreferredDiagramAspectRatio() const
     157                 :            : {
     158         [ -  + ]:         19 :     if( m_nDimension == 3 )
     159                 :          0 :         return drawing::Direction3D(1,1,0.25);
     160                 :         19 :     return drawing::Direction3D(1,1,1);
     161                 :            : }
     162                 :            : 
     163                 :          0 : bool PieChart::keepAspectRatio() const
     164                 :            : {
     165         [ #  # ]:          0 :     if( m_nDimension == 3 )
     166                 :          0 :         return false;
     167                 :          0 :     return true;
     168                 :            : }
     169                 :            : 
     170                 :         19 : bool PieChart::shouldSnapRectToUsedArea()
     171                 :            : {
     172                 :         19 :     return true;
     173                 :            : }
     174                 :            : 
     175                 :        152 : uno::Reference< drawing::XShape > PieChart::createDataPoint(
     176                 :            :           const uno::Reference< drawing::XShapes >& xTarget
     177                 :            :         , const uno::Reference< beans::XPropertySet >& xObjectProperties
     178                 :            :         , double fUnitCircleStartAngleDegree, double fUnitCircleWidthAngleDegree
     179                 :            :         , double fUnitCircleInnerRadius, double fUnitCircleOuterRadius
     180                 :            :         , double fLogicZ, double fDepth, double fExplodePercentage
     181                 :            :         , tPropertyNameValueMap* pOverwritePropertiesMap )
     182                 :            : {
     183                 :            :     //---------------------------
     184                 :            :     //transform position:
     185                 :        152 :     drawing::Direction3D aOffset;
     186         [ -  + ]:        152 :     if( !::rtl::math::approxEqual( fExplodePercentage, 0.0 ) )
     187                 :            :     {
     188                 :          0 :         double fAngle  = fUnitCircleStartAngleDegree + fUnitCircleWidthAngleDegree/2.0;
     189                 :          0 :         double fRadius = (fUnitCircleOuterRadius-fUnitCircleInnerRadius)*fExplodePercentage;
     190         [ #  # ]:          0 :         drawing::Position3D aOrigin = m_pPosHelper->transformUnitCircleToScene( 0, 0, fLogicZ );
     191         [ #  # ]:          0 :         drawing::Position3D aNewOrigin = m_pPosHelper->transformUnitCircleToScene( fAngle, fRadius, fLogicZ );
     192         [ #  # ]:          0 :         aOffset = aNewOrigin - aOrigin;
     193                 :            :     }
     194                 :            : 
     195                 :            :     //---------------------------
     196                 :            :     //create point
     197         [ +  - ]:        152 :     uno::Reference< drawing::XShape > xShape(0);
     198         [ -  + ]:        152 :     if(m_nDimension==3)
     199                 :            :     {
     200                 :            :         xShape = m_pShapeFactory->createPieSegment( xTarget
     201                 :            :             , fUnitCircleStartAngleDegree, fUnitCircleWidthAngleDegree
     202                 :            :             , fUnitCircleInnerRadius, fUnitCircleOuterRadius
     203   [ #  #  #  # ]:          0 :             , aOffset, B3DHomMatrixToHomogenMatrix( m_pPosHelper->getUnitCartesianToScene() )
     204 [ #  # ][ #  # ]:          0 :             , fDepth );
                 [ #  # ]
     205                 :            :     }
     206                 :            :     else
     207                 :            :     {
     208                 :            :         xShape = m_pShapeFactory->createPieSegment2D( xTarget
     209                 :            :             , fUnitCircleStartAngleDegree, fUnitCircleWidthAngleDegree
     210                 :            :             , fUnitCircleInnerRadius, fUnitCircleOuterRadius
     211 [ +  - ][ +  - ]:        152 :             , aOffset, B3DHomMatrixToHomogenMatrix( m_pPosHelper->getUnitCartesianToScene() ) );
         [ +  - ][ +  - ]
                 [ +  - ]
     212                 :            :     }
     213 [ +  - ][ +  - ]:        152 :     this->setMappedProperties( xShape, xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties(), pOverwritePropertiesMap );
     214                 :        152 :     return xShape;
     215                 :            : }
     216                 :            : 
     217                 :         57 : void PieChart::addSeries( VDataSeries* pSeries, sal_Int32 /* zSlot */, sal_Int32 /* xSlot */, sal_Int32 /* ySlot */ )
     218                 :            : {
     219                 :         57 :     VSeriesPlotter::addSeries( pSeries, 0, -1, 0 );
     220                 :         57 : }
     221                 :            : 
     222                 :         19 : double PieChart::getMinimumX()
     223                 :            : {
     224                 :         19 :     return 0.5;
     225                 :            : }
     226                 :        171 : double PieChart::getMaxOffset()
     227                 :            : {
     228         [ +  + ]:        171 :     if (!::rtl::math::isNan(m_fMaxOffset))
     229                 :            :         // Value already cached.  Use it.
     230                 :        114 :         return m_fMaxOffset;
     231                 :            : 
     232                 :         57 :     m_fMaxOffset = 0.0;
     233         [ -  + ]:         57 :     if( m_aZSlots.size()<=0 )
     234                 :          0 :         return m_fMaxOffset;
     235         [ -  + ]:         57 :     if( m_aZSlots[0].size()<=0 )
     236                 :          0 :         return m_fMaxOffset;
     237                 :            : 
     238                 :         57 :     const ::std::vector< VDataSeries* >& rSeriesList( m_aZSlots[0][0].m_aSeriesVector );
     239         [ -  + ]:         57 :     if( rSeriesList.size()<=0 )
     240                 :          0 :         return m_fMaxOffset;
     241                 :            : 
     242                 :         57 :     VDataSeries* pSeries = rSeriesList[0];
     243         [ +  - ]:         57 :     uno::Reference< beans::XPropertySet > xSeriesProp( pSeries->getPropertiesOfSeries() );
     244         [ -  + ]:         57 :     if( !xSeriesProp.is() )
     245                 :          0 :         return m_fMaxOffset;
     246                 :            : 
     247                 :         57 :     double fExplodePercentage=0.0;
     248 [ +  - ][ +  - ]:         57 :     xSeriesProp->getPropertyValue( C2U( "Offset" )) >>= fExplodePercentage;
                 [ +  - ]
     249         [ -  + ]:         57 :     if(fExplodePercentage>m_fMaxOffset)
     250                 :          0 :         m_fMaxOffset=fExplodePercentage;
     251                 :            : 
     252         [ +  - ]:         57 :     if(!m_bSizeExcludesLabelsAndExplodedSegments)
     253                 :            :     {
     254         [ +  - ]:         57 :         uno::Sequence< sal_Int32 > aAttributedDataPointIndexList;
     255 [ +  - ][ +  - ]:         57 :         if( xSeriesProp->getPropertyValue( C2U( "AttributedDataPoints" ) ) >>= aAttributedDataPointIndexList )
         [ +  - ][ +  - ]
                 [ +  - ]
     256                 :            :         {
     257         [ -  + ]:         57 :             for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;)
     258                 :            :             {
     259 [ #  # ][ #  # ]:          0 :                 uno::Reference< beans::XPropertySet > xPointProp( pSeries->getPropertiesOfPoint(aAttributedDataPointIndexList[nN]) );
     260         [ #  # ]:          0 :                 if(xPointProp.is())
     261                 :            :                 {
     262                 :          0 :                     fExplodePercentage=0.0;
     263 [ #  # ][ #  # ]:          0 :                     xPointProp->getPropertyValue( C2U( "Offset" )) >>= fExplodePercentage;
                 [ #  # ]
     264         [ #  # ]:          0 :                     if(fExplodePercentage>m_fMaxOffset)
     265                 :          0 :                         m_fMaxOffset=fExplodePercentage;
     266                 :            :                 }
     267                 :          0 :             }
     268         [ +  - ]:         57 :         }
     269                 :            :     }
     270                 :        171 :     return m_fMaxOffset;
     271                 :            : }
     272                 :         19 : double PieChart::getMaximumX()
     273                 :            : {
     274                 :         19 :     double fMaxOffset = getMaxOffset();
     275 [ -  + ][ -  + ]:         19 :     if( m_aZSlots.size()>0 && m_bUseRings)
                 [ +  - ]
     276                 :          0 :         return m_aZSlots[0].size()+0.5+fMaxOffset;
     277                 :         19 :     return 1.5+fMaxOffset;
     278                 :            : }
     279                 :         19 : double PieChart::getMinimumYInRange( double /* fMinimumX */, double /* fMaximumX */, sal_Int32 /* nAxisIndex */ )
     280                 :            : {
     281                 :         19 :     return 0.0;
     282                 :            : }
     283                 :            : 
     284                 :         19 : double PieChart::getMaximumYInRange( double /* fMinimumX */, double /* fMaximumX */, sal_Int32 /* nAxisIndex */ )
     285                 :            : {
     286                 :         19 :     return 1.0;
     287                 :            : }
     288                 :            : 
     289                 :         38 : bool PieChart::isExpandBorderToIncrementRhythm( sal_Int32 /* nDimensionIndex */ )
     290                 :            : {
     291                 :         38 :     return false;
     292                 :            : }
     293                 :            : 
     294                 :         38 : bool PieChart::isExpandIfValuesCloseToBorder( sal_Int32 /* nDimensionIndex */ )
     295                 :            : {
     296                 :         38 :     return false;
     297                 :            : }
     298                 :            : 
     299                 :         38 : bool PieChart::isExpandWideValuesToZero( sal_Int32 /* nDimensionIndex */ )
     300                 :            : {
     301                 :         38 :     return false;
     302                 :            : }
     303                 :            : 
     304                 :         38 : bool PieChart::isExpandNarrowValuesTowardZero( sal_Int32 /* nDimensionIndex */ )
     305                 :            : {
     306                 :         38 :     return false;
     307                 :            : }
     308                 :            : 
     309                 :          0 : bool PieChart::isSeperateStackingForDifferentSigns( sal_Int32 /* nDimensionIndex */ )
     310                 :            : {
     311                 :          0 :     return false;
     312                 :            : }
     313                 :            : 
     314                 :         38 : void PieChart::createShapes()
     315                 :            : {
     316 [ +  - ][ +  - ]:         38 :     if( m_aZSlots.begin() == m_aZSlots.end() ) //no series
     317                 :            :         return;
     318                 :            : 
     319                 :            :     OSL_ENSURE(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is(),"PieChart is not proper initialized");
     320 [ +  - ][ +  - ]:         38 :     if(!(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is()))
         [ -  + ][ +  - ]
     321                 :            :         return;
     322                 :            : 
     323                 :            :     //the text labels should be always on top of the other series shapes
     324                 :            :     //therefore create an own group for the texts to move them to front
     325                 :            :     //(because the text group is created after the series group the texts are displayed on top)
     326                 :            :     uno::Reference< drawing::XShapes > xSeriesTarget(
     327         [ +  - ]:         38 :         createGroupShape( m_xLogicTarget,rtl::OUString() ));
     328                 :            :     uno::Reference< drawing::XShapes > xTextTarget(
     329         [ +  - ]:         38 :         m_pShapeFactory->createGroup2D( m_xFinalTarget,rtl::OUString() ));
     330                 :            :     //---------------------------------------------
     331                 :            :     //check necessary here that different Y axis can not be stacked in the same group? ... hm?
     332                 :            : 
     333                 :            : //=============================================================================
     334                 :         38 :     ::std::vector< VDataSeriesGroup >::iterator             aXSlotIter = m_aZSlots[0].begin();
     335         [ +  - ]:         38 :     const ::std::vector< VDataSeriesGroup >::const_iterator aXSlotEnd = m_aZSlots[0].end();
     336                 :            : 
     337                 :         38 :     ::std::vector< VDataSeriesGroup >::size_type nExplodeableSlot = 0;
     338 [ +  - ][ -  + ]:         38 :     if( m_pPosHelper->isMathematicalOrientationRadius() && m_bUseRings )
         [ #  # ][ -  + ]
     339                 :          0 :         nExplodeableSlot = m_aZSlots[0].size()-1;
     340                 :            : 
     341                 :         38 :     m_aLabelInfoList.clear();
     342                 :         38 :     ::rtl::math::setNan(&m_fMaxOffset);
     343                 :            : 
     344                 :            : //=============================================================================
     345 [ +  - ][ +  - ]:         76 :     for( double fSlotX=0; aXSlotIter != aXSlotEnd && (m_bUseRings||fSlotX<0.5 ); ++aXSlotIter, fSlotX+=1.0 )
         [ +  - ][ +  + ]
                 [ +  + ]
     346                 :            :     {
     347                 :         38 :         ::std::vector< VDataSeries* >* pSeriesList = &(aXSlotIter->m_aSeriesVector);
     348         [ -  + ]:         38 :         if( pSeriesList->size()<=0 )//there should be only one series in each x slot
     349                 :          0 :             continue;
     350                 :         38 :         VDataSeries* pSeries = (*pSeriesList)[0];
     351         [ -  + ]:         38 :         if(!pSeries)
     352                 :          0 :             continue;
     353                 :            : 
     354         [ +  - ]:         38 :         m_pPosHelper->m_fAngleDegreeOffset = pSeries->getStartingAngle();
     355                 :            : 
     356                 :         38 :         double fLogicYSum = 0.0;
     357                 :            :         //iterate through all points to get the sum
     358                 :         38 :         sal_Int32 nPointIndex=0;
     359         [ +  - ]:         38 :         sal_Int32 nPointCount=pSeries->getTotalPointCount();
     360         [ +  + ]:        190 :         for( nPointIndex = 0; nPointIndex < nPointCount; nPointIndex++ )
     361                 :            :         {
     362         [ +  - ]:        152 :             double fY = pSeries->getYValue( nPointIndex );
     363                 :            :             if(fY<0.0)
     364                 :            :             {
     365                 :            :                 //@todo warn somehow that negative values are treated as positive
     366                 :            :             }
     367         [ -  + ]:        152 :             if( ::rtl::math::isNan(fY) )
     368                 :          0 :                 continue;
     369                 :        152 :             fLogicYSum += fabs(fY);
     370                 :            :         }
     371         [ -  + ]:         38 :         if(fLogicYSum==0.0)
     372                 :          0 :             continue;
     373                 :         38 :         double fLogicYForNextPoint = 0.0;
     374                 :            :         //iterate through all points to create shapes
     375         [ +  + ]:        190 :         for( nPointIndex = 0; nPointIndex < nPointCount; nPointIndex++ )
     376                 :            :         {
     377                 :            :             double fLogicInnerRadius, fLogicOuterRadius;
     378         [ +  - ]:        152 :             double fOffset = getMaxOffset();
     379         [ +  - ]:        152 :             bool bIsVisible = m_pPosHelper->getInnerAndOuterRadius( fSlotX+1.0, fLogicInnerRadius, fLogicOuterRadius, m_bUseRings, fOffset );
     380         [ -  + ]:        152 :             if( !bIsVisible )
     381                 :          0 :                 continue;
     382                 :            : 
     383         [ +  - ]:        152 :             double fDepth  = this->getTransformedDepth();
     384                 :            : 
     385         [ +  - ]:        152 :             uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes = getSeriesGroupShape(pSeries, xSeriesTarget);
     386                 :            :             //collect data point information (logic coordinates, style ):
     387         [ +  - ]:        152 :             double fLogicYValue = fabs(pSeries->getYValue( nPointIndex ));
     388         [ -  + ]:        152 :             if( ::rtl::math::isNan(fLogicYValue) )
     389                 :          0 :                 continue;
     390         [ -  + ]:        152 :             if(fLogicYValue==0.0)//@todo: continue also if the resolution to small
     391                 :          0 :                 continue;
     392                 :        152 :             double fLogicYPos = fLogicYForNextPoint;
     393                 :        152 :             fLogicYForNextPoint += fLogicYValue;
     394                 :            : 
     395         [ +  - ]:        152 :             uno::Reference< beans::XPropertySet > xPointProperties = pSeries->getPropertiesOfPoint( nPointIndex );
     396                 :            : 
     397                 :            :             //iterate through all subsystems to create partial points
     398                 :            :             {
     399                 :            :                 //logic values on angle axis:
     400                 :        152 :                 double fLogicStartAngleValue = fLogicYPos/fLogicYSum;
     401                 :        152 :                 double fLogicEndAngleValue = (fLogicYPos+fLogicYValue)/fLogicYSum;
     402                 :            : 
     403                 :        152 :                 double fExplodePercentage=0.0;
     404                 :        152 :                 bool bDoExplode = ( nExplodeableSlot == static_cast< ::std::vector< VDataSeriesGroup >::size_type >(fSlotX) );
     405         [ +  - ]:        152 :                 if(bDoExplode) try
     406                 :            :                 {
     407 [ +  - ][ +  - ]:        152 :                     xPointProperties->getPropertyValue( C2U( "Offset" )) >>= fExplodePercentage;
         [ +  - ][ #  # ]
     408                 :            :                 }
     409         [ #  # ]:          0 :                 catch( const uno::Exception& e )
     410                 :            :                 {
     411                 :            :                     ASSERT_EXCEPTION( e );
     412                 :            :                 }
     413                 :            : 
     414                 :            :                 //---------------------------
     415                 :            :                 //transforme to unit circle:
     416         [ +  - ]:        152 :                 double fUnitCircleWidthAngleDegree = m_pPosHelper->getWidthAngleDegree( fLogicStartAngleValue, fLogicEndAngleValue );
     417         [ +  - ]:        152 :                 double fUnitCircleStartAngleDegree = m_pPosHelper->transformToAngleDegree( fLogicStartAngleValue );
     418         [ +  - ]:        152 :                 double fUnitCircleInnerRadius = m_pPosHelper->transformToRadius( fLogicInnerRadius );
     419         [ +  - ]:        152 :                 double fUnitCircleOuterRadius = m_pPosHelper->transformToRadius( fLogicOuterRadius );
     420                 :            : 
     421                 :            :                 //---------------------------
     422                 :            :                 //point color:
     423                 :        152 :                 boost::scoped_ptr< tPropertyNameValueMap > apOverwritePropertiesMap(NULL);
     424                 :            :                 {
     425 [ +  - ][ +  - ]:        152 :                     if(!pSeries->hasPointOwnColor(nPointIndex) && m_xColorScheme.is())
         [ +  - ][ +  - ]
     426                 :            :                     {
     427 [ +  - ][ +  - ]:        152 :                         apOverwritePropertiesMap.reset( new tPropertyNameValueMap() );
                 [ +  - ]
     428 [ +  - ][ +  - ]:        304 :                         (*apOverwritePropertiesMap)[C2U("FillColor")] = uno::makeAny(
     429 [ +  - ][ +  - ]:        456 :                             m_xColorScheme->getColorByIndex( nPointIndex ));
                 [ +  - ]
     430                 :            :                     }
     431                 :            :                 }
     432                 :            : 
     433                 :            :                 //create data point
     434                 :        152 :                 double fLogicZ = -0.5;//as defined
     435                 :            :                 uno::Reference<drawing::XShape> xPointShape(
     436                 :            :                     createDataPoint( xSeriesGroupShape_Shapes, xPointProperties
     437                 :            :                                     , fUnitCircleStartAngleDegree, fUnitCircleWidthAngleDegree
     438                 :            :                                     , fUnitCircleInnerRadius, fUnitCircleOuterRadius
     439         [ +  - ]:        152 :                                     , fLogicZ, fDepth, fExplodePercentage, apOverwritePropertiesMap.get() ) );
     440                 :            : 
     441                 :            :                 //create label
     442 [ +  - ][ -  + ]:        152 :                 if( pSeries->getDataPointLabelIfLabel(nPointIndex) )
     443                 :            :                 {
     444         [ #  # ]:          0 :                     if( !::rtl::math::approxEqual( fExplodePercentage, 0.0 ) )
     445                 :            :                     {
     446                 :          0 :                         double fExplodeOffset = (fUnitCircleOuterRadius-fUnitCircleInnerRadius)*fExplodePercentage;
     447                 :          0 :                         fUnitCircleInnerRadius += fExplodeOffset;
     448                 :          0 :                         fUnitCircleOuterRadius += fExplodeOffset;
     449                 :            :                     }
     450                 :            : 
     451         [ #  # ]:          0 :                     sal_Int32 nLabelPlacement = pSeries->getLabelPlacement( nPointIndex, m_xChartTypeModel, m_nDimension, m_pPosHelper->isSwapXAndY() );
     452                 :          0 :                     bool bMovementAllowed = ( nLabelPlacement == ::com::sun::star::chart::DataLabelPlacement::AVOID_OVERLAP );
     453         [ #  # ]:          0 :                     if( bMovementAllowed )
     454                 :          0 :                         nLabelPlacement = ::com::sun::star::chart::DataLabelPlacement::OUTSIDE;
     455                 :            : 
     456                 :          0 :                     LabelAlignment eAlignment(LABEL_ALIGN_CENTER);
     457                 :          0 :                     sal_Int32 nScreenValueOffsetInRadiusDirection = 0 ;
     458         [ #  # ]:          0 :                     if( nLabelPlacement == ::com::sun::star::chart::DataLabelPlacement::OUTSIDE )
     459         [ #  # ]:          0 :                         nScreenValueOffsetInRadiusDirection = (3!=m_nDimension) ? 150 : 0;//todo maybe calculate this font height dependent
     460         [ #  # ]:          0 :                     else if( nLabelPlacement == ::com::sun::star::chart::DataLabelPlacement::INSIDE )
     461         [ #  # ]:          0 :                         nScreenValueOffsetInRadiusDirection = (3!=m_nDimension) ? -150 : 0;//todo maybe calculate this font height dependent
     462         [ #  # ]:          0 :                     PolarLabelPositionHelper aPolarPosHelper(m_pPosHelper,m_nDimension,m_xLogicTarget,m_pShapeFactory);
     463                 :            :                     awt::Point aScreenPosition2D(
     464                 :            :                         aPolarPosHelper.getLabelScreenPositionAndAlignmentForUnitCircleValues(eAlignment, nLabelPlacement
     465                 :            :                         , fUnitCircleStartAngleDegree, fUnitCircleWidthAngleDegree
     466         [ #  # ]:          0 :                         , fUnitCircleInnerRadius, fUnitCircleOuterRadius, fLogicZ+0.5, 0 ));
     467                 :            : 
     468         [ #  # ]:          0 :                     PieLabelInfo aPieLabelInfo;
     469         [ #  # ]:          0 :                     aPieLabelInfo.aFirstPosition = basegfx::B2IVector( aScreenPosition2D.X, aScreenPosition2D.Y );
     470 [ #  # ][ #  # ]:          0 :                     awt::Point aOrigin( aPolarPosHelper.transformSceneToScreenPosition( m_pPosHelper->transformUnitCircleToScene( 0.0, 0.0, fLogicZ+1.0 ) ) );
     471         [ #  # ]:          0 :                     aPieLabelInfo.aOrigin = basegfx::B2IVector( aOrigin.X, aOrigin.Y );
     472                 :            : 
     473                 :            :                     //add a scaling independent Offset if requested
     474         [ #  # ]:          0 :                     if( nScreenValueOffsetInRadiusDirection != 0)
     475                 :            :                     {
     476                 :          0 :                         basegfx::B2IVector aDirection( aScreenPosition2D.X- aOrigin.X, aScreenPosition2D.Y- aOrigin.Y );
     477         [ #  # ]:          0 :                         aDirection.setLength(nScreenValueOffsetInRadiusDirection);
     478                 :          0 :                         aScreenPosition2D.X += aDirection.getX();
     479                 :          0 :                         aScreenPosition2D.Y += aDirection.getY();
     480                 :            :                     }
     481                 :            : 
     482                 :            :                     aPieLabelInfo.xTextShape = this->createDataLabel( xTextTarget, *pSeries, nPointIndex
     483 [ #  # ][ #  # ]:          0 :                                     , fLogicYValue, fLogicYSum, aScreenPosition2D, eAlignment );
     484                 :            : 
     485         [ #  # ]:          0 :                     uno::Reference< container::XChild > xChild( aPieLabelInfo.xTextShape, uno::UNO_QUERY );
     486         [ #  # ]:          0 :                     if( xChild.is() )
     487 [ #  # ][ #  # ]:          0 :                         aPieLabelInfo.xLabelGroupShape = uno::Reference<drawing::XShape>( xChild->getParent(), uno::UNO_QUERY );
         [ #  # ][ #  # ]
     488                 :          0 :                     aPieLabelInfo.fValue = fLogicYValue;
     489                 :          0 :                     aPieLabelInfo.bMovementAllowed = bMovementAllowed;
     490                 :          0 :                     aPieLabelInfo.bMoved= false;
     491         [ #  # ]:          0 :                     aPieLabelInfo.xTextTarget = xTextTarget;
     492 [ #  # ][ #  # ]:          0 :                     m_aLabelInfoList.push_back(aPieLabelInfo);
                 [ #  # ]
     493                 :            :                 }
     494                 :            : 
     495         [ -  + ]:        152 :                 if(!bDoExplode)
     496                 :            :                 {
     497                 :            :                     ShapeFactory::setShapeName( xPointShape
     498 [ #  # ][ #  # ]:          0 :                                 , ObjectIdentifier::createPointCID( pSeries->getPointCID_Stub(), nPointIndex ) );
                 [ #  # ]
     499                 :            :                 }
     500                 :            :                 else try
     501                 :            :                 {
     502                 :            :                     //enable dragging of outer segments
     503                 :            : 
     504                 :        152 :                     double fAngle  = fUnitCircleStartAngleDegree + fUnitCircleWidthAngleDegree/2.0;
     505                 :        152 :                     double fMaxDeltaRadius = fUnitCircleOuterRadius-fUnitCircleInnerRadius;
     506         [ +  - ]:        152 :                     drawing::Position3D aOrigin = m_pPosHelper->transformUnitCircleToScene( fAngle, fUnitCircleOuterRadius, fLogicZ );
     507         [ +  - ]:        152 :                     drawing::Position3D aNewOrigin = m_pPosHelper->transformUnitCircleToScene( fAngle, fUnitCircleOuterRadius + fMaxDeltaRadius, fLogicZ );
     508                 :            : 
     509                 :        152 :                     sal_Int32 nOffsetPercent( static_cast<sal_Int32>(fExplodePercentage * 100.0) );
     510                 :            : 
     511                 :            :                     awt::Point aMinimumPosition( PlottingPositionHelper::transformSceneToScreenPosition(
     512         [ +  - ]:        152 :                         aOrigin, m_xLogicTarget, m_pShapeFactory, m_nDimension ) );
     513                 :            :                     awt::Point aMaximumPosition( PlottingPositionHelper::transformSceneToScreenPosition(
     514         [ +  - ]:        152 :                         aNewOrigin, m_xLogicTarget, m_pShapeFactory, m_nDimension ) );
     515                 :            : 
     516                 :            :                     //enable draging of piesegments
     517                 :            :                     rtl::OUString aPointCIDStub( ObjectIdentifier::createSeriesSubObjectStub( OBJECTTYPE_DATA_POINT
     518                 :            :                         , pSeries->getSeriesParticle()
     519         [ +  - ]:        152 :                         , ObjectIdentifier::getPieSegmentDragMethodServiceName()
     520                 :            :                         , ObjectIdentifier::createPieSegmentDragParameterString(
     521                 :            :                             nOffsetPercent, aMinimumPosition, aMaximumPosition )
     522 [ +  - ][ +  - ]:        304 :                         ) );
                 [ +  - ]
     523                 :            : 
     524                 :            :                     ShapeFactory::setShapeName( xPointShape
     525 [ +  - ][ #  # ]:        152 :                                 , ObjectIdentifier::createPointCID( aPointCIDStub, nPointIndex ) );
                 [ +  - ]
     526                 :            :                 }
     527         [ #  # ]:          0 :                 catch( const uno::Exception& e )
     528                 :            :                 {
     529                 :            :                     ASSERT_EXCEPTION( e );
     530         [ +  - ]:        152 :                 }
     531                 :            :             }//next series in x slot (next y slot)
     532         [ +  - ]:        152 :         }//next category
     533                 :         38 :     }//next x slot
     534                 :            : //=============================================================================
     535                 :            : //=============================================================================
     536                 :            : //=============================================================================
     537                 :            :     /* @todo remove series shapes if empty
     538                 :            :     //remove and delete point-group-shape if empty
     539                 :            :     if(!xSeriesGroupShape_Shapes->getCount())
     540                 :            :     {
     541                 :            :         (*aSeriesIter)->m_xShape.set(NULL);
     542                 :            :         m_xLogicTarget->remove(xSeriesGroupShape_Shape);
     543                 :            :     }
     544                 :            :     */
     545                 :            : 
     546                 :            :     //remove and delete series-group-shape if empty
     547                 :            : 
     548                 :            :     //... todo
     549                 :            : }
     550                 :            : 
     551                 :            : namespace
     552                 :            : {
     553                 :            : 
     554                 :          0 : ::basegfx::B2IRectangle lcl_getRect( const uno::Reference< drawing::XShape >& xShape )
     555                 :            : {
     556                 :          0 :     ::basegfx::B2IRectangle aRect;
     557         [ #  # ]:          0 :     if( xShape.is() )
     558 [ #  # ][ #  # ]:          0 :         aRect = BaseGFXHelper::makeRectangle(xShape->getPosition(),xShape->getSize() );
                 [ #  # ]
     559                 :          0 :     return aRect;
     560                 :            : }
     561                 :            : 
     562                 :          0 : bool lcl_isInsidePage( const awt::Point& rPos, const awt::Size& rSize, const awt::Size& rPageSize )
     563                 :            : {
     564 [ #  # ][ #  # ]:          0 :     if( rPos.X < 0  || rPos.Y < 0 )
     565                 :          0 :         return false;
     566         [ #  # ]:          0 :     if( (rPos.X + rSize.Width) > rPageSize.Width  )
     567                 :          0 :         return false;
     568         [ #  # ]:          0 :     if( (rPos.Y + rSize.Height) > rPageSize.Height )
     569                 :          0 :         return false;
     570                 :          0 :     return true;
     571                 :            : }
     572                 :            : 
     573                 :            : }//end anonymous namespace
     574                 :            : 
     575                 :          0 : PieChart::PieLabelInfo::PieLabelInfo()
     576                 :            :     : xTextShape(0), xLabelGroupShape(0), aFirstPosition(), aOrigin(), fValue(0.0)
     577 [ #  # ][ #  # ]:          0 :     , bMovementAllowed(false), bMoved(false), xTextTarget(0), pPrevious(0),pNext(0)
     578                 :            : {
     579                 :          0 : }
     580                 :            : 
     581                 :          0 : bool PieChart::PieLabelInfo::moveAwayFrom( const PieChart::PieLabelInfo* pFix, const awt::Size& rPageSize, bool bMoveHalfWay, bool bMoveClockwise, bool bAlternativeMoveDirection )
     582                 :            : {
     583                 :            :     //return true if the move was successful
     584         [ #  # ]:          0 :     if(!this->bMovementAllowed)
     585                 :          0 :         return false;
     586                 :            : 
     587                 :          0 :     const sal_Int32 nLabelDistanceX = rPageSize.Width/50;
     588                 :          0 :     const sal_Int32 nLabelDistanceY = rPageSize.Height/50;
     589                 :            : 
     590         [ #  # ]:          0 :     ::basegfx::B2IRectangle aOverlap( lcl_getRect( this->xLabelGroupShape ) );
     591 [ #  # ][ #  # ]:          0 :     aOverlap.intersect( lcl_getRect( pFix->xLabelGroupShape ) );
     592 [ #  # ][ #  # ]:          0 :     if( !aOverlap.isEmpty() )
     593                 :            :     {
     594                 :            :         (void)bAlternativeMoveDirection;//todo
     595                 :            : 
     596         [ #  # ]:          0 :         basegfx::B2IVector aRadiusDirection = this->aFirstPosition - this->aOrigin;
     597         [ #  # ]:          0 :         aRadiusDirection.setLength(1.0);
     598                 :          0 :         basegfx::B2IVector aTangentialDirection( -aRadiusDirection.getY(), aRadiusDirection.getX() );
     599                 :          0 :         bool bShiftHorizontal = abs(aTangentialDirection.getX()) > abs(aTangentialDirection.getY());
     600                 :            : 
     601 [ #  # ][ #  # ]:          0 :         sal_Int32 nShift = bShiftHorizontal ? static_cast<sal_Int32>(aOverlap.getWidth()) : static_cast<sal_Int32>(aOverlap.getHeight());
                 [ #  # ]
     602         [ #  # ]:          0 :         nShift += (bShiftHorizontal ? nLabelDistanceX : nLabelDistanceY);
     603         [ #  # ]:          0 :         if( bMoveHalfWay )
     604                 :          0 :             nShift/=2;
     605         [ #  # ]:          0 :         if(!bMoveClockwise)
     606                 :          0 :             nShift*=-1;
     607 [ #  # ][ #  # ]:          0 :         awt::Point aOldPos( this->xLabelGroupShape->getPosition() );
     608 [ #  # ][ #  # ]:          0 :         basegfx::B2IVector aNewPos = basegfx::B2IVector( aOldPos.X, aOldPos.Y ) + nShift*aTangentialDirection;
     609                 :            : 
     610                 :            :         //check whether the new position is ok
     611                 :          0 :         awt::Point aNewAWTPos( aNewPos.getX(), aNewPos.getY() );
     612 [ #  # ][ #  # ]:          0 :         if( !lcl_isInsidePage( aNewAWTPos, this->xLabelGroupShape->getSize(), rPageSize ) )
                 [ #  # ]
     613                 :          0 :             return false;
     614                 :            : 
     615 [ #  # ][ #  # ]:          0 :         this->xLabelGroupShape->setPosition( aNewAWTPos );
     616 [ #  # ][ #  # ]:          0 :         this->bMoved = true;
                 [ #  # ]
     617                 :            :     }
     618                 :          0 :     return true;
     619                 :            : }
     620                 :            : 
     621                 :          0 : void PieChart::resetLabelPositionsToPreviousState()
     622                 :            : {
     623                 :          0 :     std::vector< PieLabelInfo >::iterator aIt = m_aLabelInfoList.begin();
     624         [ #  # ]:          0 :     std::vector< PieLabelInfo >::const_iterator aEnd = m_aLabelInfoList.end();
     625 [ #  # ][ #  # ]:          0 :     for( ;aIt!=aEnd; ++aIt )
     626 [ #  # ][ #  # ]:          0 :         aIt->xLabelGroupShape->setPosition(aIt->aPreviousPosition);
     627                 :          0 : }
     628                 :            : 
     629                 :          0 : bool PieChart::detectLabelOverlapsAndMove( const awt::Size& rPageSize )
     630                 :            : {
     631                 :            :     //returns true when there might be more to do
     632                 :            : 
     633                 :            :     //find borders of a group of overlapping labels
     634                 :          0 :     bool bOverlapFound = false;
     635         [ #  # ]:          0 :     PieLabelInfo* pStart = &(*(m_aLabelInfoList.rbegin()));
     636                 :          0 :     PieLabelInfo* pFirstBorder = 0;
     637                 :          0 :     PieLabelInfo* pSecondBorder = 0;
     638                 :          0 :     PieLabelInfo* pCurrent = pStart;
     639         [ #  # ]:          0 :     do
     640                 :            :     {
     641         [ #  # ]:          0 :         ::basegfx::B2IRectangle aPreviousOverlap( lcl_getRect( pCurrent->xLabelGroupShape ) );
     642                 :          0 :         ::basegfx::B2IRectangle aNextOverlap( aPreviousOverlap );
     643 [ #  # ][ #  # ]:          0 :         aPreviousOverlap.intersect( lcl_getRect( pCurrent->pPrevious->xLabelGroupShape ) );
     644 [ #  # ][ #  # ]:          0 :         aNextOverlap.intersect( lcl_getRect( pCurrent->pNext->xLabelGroupShape ) );
     645                 :            : 
     646         [ #  # ]:          0 :         bool bPreviousOverlap = !aPreviousOverlap.isEmpty();
     647         [ #  # ]:          0 :         bool bNextOverlap = !aNextOverlap.isEmpty();
     648 [ #  # ][ #  # ]:          0 :         if( bPreviousOverlap || bNextOverlap )
     649                 :          0 :             bOverlapFound = true;
     650 [ #  # ][ #  # ]:          0 :         if( !bPreviousOverlap && bNextOverlap )
     651                 :            :         {
     652                 :          0 :             pFirstBorder = pCurrent;
     653                 :            :             break;
     654                 :            :         }
     655                 :          0 :         pCurrent = pCurrent->pNext;
     656                 :            :     }
     657                 :            :     while( pCurrent != pStart );
     658                 :            : 
     659         [ #  # ]:          0 :     if( !bOverlapFound )
     660                 :          0 :         return false;
     661                 :            : 
     662         [ #  # ]:          0 :     if( pFirstBorder )
     663                 :            :     {
     664                 :          0 :         pCurrent = pFirstBorder;
     665         [ #  # ]:          0 :         do
     666                 :            :         {
     667         [ #  # ]:          0 :             ::basegfx::B2IRectangle aPreviousOverlap( lcl_getRect( pCurrent->xLabelGroupShape ) );
     668                 :          0 :             ::basegfx::B2IRectangle aNextOverlap( aPreviousOverlap );
     669 [ #  # ][ #  # ]:          0 :             aPreviousOverlap.intersect( lcl_getRect( pCurrent->pPrevious->xLabelGroupShape ) );
     670 [ #  # ][ #  # ]:          0 :             aNextOverlap.intersect( lcl_getRect( pCurrent->pNext->xLabelGroupShape ) );
     671                 :            : 
     672 [ #  # ][ #  # ]:          0 :             if( !aPreviousOverlap.isEmpty() && aNextOverlap.isEmpty() )
         [ #  # ][ #  # ]
                 [ #  # ]
     673                 :            :             {
     674                 :          0 :                 pSecondBorder = pCurrent;
     675                 :            :                 break;
     676                 :            :             }
     677                 :          0 :             pCurrent = pCurrent->pNext;
     678                 :            :         }
     679                 :            :         while( pCurrent != pFirstBorder );
     680                 :            :     }
     681                 :            : 
     682 [ #  # ][ #  # ]:          0 :     if( !pFirstBorder || !pSecondBorder )
     683                 :            :     {
     684         [ #  # ]:          0 :         pFirstBorder = &(*(m_aLabelInfoList.rbegin()));
     685                 :          0 :         pSecondBorder = &(*(m_aLabelInfoList.begin()));
     686                 :            :     }
     687                 :            : 
     688                 :            :     //find center
     689                 :          0 :     PieLabelInfo* pCenter = pFirstBorder;
     690                 :          0 :     sal_Int32 nOverlapGroupCount = 1;
     691         [ #  # ]:          0 :     for( pCurrent = pFirstBorder ;pCurrent != pSecondBorder; pCurrent = pCurrent->pNext )
     692                 :          0 :         nOverlapGroupCount++;
     693                 :          0 :     sal_Int32 nCenterPos = nOverlapGroupCount/2;
     694                 :          0 :     bool bSingleCenter = nOverlapGroupCount%2 != 0;
     695         [ #  # ]:          0 :     if( bSingleCenter )
     696                 :          0 :         nCenterPos++;
     697         [ #  # ]:          0 :     if(nCenterPos>1)
     698                 :            :     {
     699                 :          0 :         pCurrent = pFirstBorder;
     700         [ #  # ]:          0 :         while( --nCenterPos )
     701                 :          0 :             pCurrent = pCurrent->pNext;
     702                 :          0 :         pCenter = pCurrent;
     703                 :            :     }
     704                 :            : 
     705                 :            :     //remind current positions
     706                 :          0 :     pCurrent = pStart;
     707         [ #  # ]:          0 :     do
     708                 :            :     {
     709 [ #  # ][ #  # ]:          0 :         pCurrent->aPreviousPosition = pCurrent->xLabelGroupShape->getPosition();
     710                 :          0 :         pCurrent = pCurrent->pNext;
     711                 :            :     }
     712                 :            :     while( pCurrent != pStart );
     713                 :            : 
     714                 :            :     //
     715                 :          0 :     bool bAlternativeMoveDirection = false;
     716 [ #  # ][ #  # ]:          0 :     if( !tryMoveLabels( pFirstBorder, pSecondBorder, pCenter, bSingleCenter, bAlternativeMoveDirection, rPageSize ) )
     717         [ #  # ]:          0 :         tryMoveLabels( pFirstBorder, pSecondBorder, pCenter, bSingleCenter, bAlternativeMoveDirection, rPageSize );
     718                 :          0 :     return true;
     719                 :            : }
     720                 :            : 
     721                 :          0 : bool PieChart::tryMoveLabels( PieLabelInfo* pFirstBorder, PieLabelInfo* pSecondBorder
     722                 :            :                              , PieLabelInfo* pCenter
     723                 :            :                              , bool bSingleCenter, bool& rbAlternativeMoveDirection, const awt::Size& rPageSize )
     724                 :            : {
     725         [ #  # ]:          0 :     PieLabelInfo* p1 = bSingleCenter ? pCenter->pPrevious : pCenter;
     726                 :          0 :     PieLabelInfo* p2 = pCenter->pNext;
     727                 :            :     //return true when successful
     728                 :            : 
     729                 :          0 :     bool bLabelOrderIsAntiClockWise = m_pPosHelper->isMathematicalOrientationAngle();
     730                 :            : 
     731                 :          0 :     PieLabelInfo* pCurrent = 0;
     732         [ #  # ]:          0 :     for( pCurrent = p2 ;pCurrent->pPrevious != pSecondBorder; pCurrent = pCurrent->pNext )
     733                 :            :     {
     734                 :          0 :         PieLabelInfo* pFix = 0;
     735         [ #  # ]:          0 :         for( pFix = p2->pPrevious ;pFix != pCurrent; pFix = pFix->pNext )
     736                 :            :         {
     737 [ #  # ][ #  # ]:          0 :             if( !pCurrent->moveAwayFrom( pFix, rPageSize, !bSingleCenter && pCurrent == p2, !bLabelOrderIsAntiClockWise, rbAlternativeMoveDirection ) )
                 [ #  # ]
     738                 :            :             {
     739         [ #  # ]:          0 :                 if( !rbAlternativeMoveDirection )
     740                 :            :                 {
     741                 :          0 :                     rbAlternativeMoveDirection = true;
     742                 :          0 :                     resetLabelPositionsToPreviousState();
     743                 :          0 :                     return false;
     744                 :            :                 }
     745                 :            :             }
     746                 :            :         }
     747                 :            :     }
     748         [ #  # ]:          0 :     for( pCurrent = p1 ;pCurrent->pNext != pFirstBorder; pCurrent = pCurrent->pPrevious )
     749                 :            :     {
     750                 :          0 :         PieLabelInfo* pFix = 0;
     751         [ #  # ]:          0 :         for( pFix = p2->pNext ;pFix != pCurrent; pFix = pFix->pPrevious )
     752                 :            :         {
     753         [ #  # ]:          0 :             if( !pCurrent->moveAwayFrom( pFix, rPageSize, false, bLabelOrderIsAntiClockWise, rbAlternativeMoveDirection ) )
     754                 :            :             {
     755         [ #  # ]:          0 :                 if( !rbAlternativeMoveDirection )
     756                 :            :                 {
     757                 :          0 :                     rbAlternativeMoveDirection = true;
     758                 :          0 :                     resetLabelPositionsToPreviousState();
     759                 :          0 :                     return false;
     760                 :            :                 }
     761                 :            :             }
     762                 :            :         }
     763                 :            :     }
     764                 :          0 :     return true;
     765                 :            : }
     766                 :            : 
     767                 :         19 : void PieChart::rearrangeLabelToAvoidOverlapIfRequested( const awt::Size& rPageSize )
     768                 :            : {
     769                 :            :     //------------------------------------------------------------------
     770                 :            :     //check whether there are any labels that should be moved
     771                 :         19 :     std::vector< PieLabelInfo >::iterator aIt1 = m_aLabelInfoList.begin();
     772         [ +  - ]:         19 :     std::vector< PieLabelInfo >::const_iterator aEnd = m_aLabelInfoList.end();
     773                 :         19 :     bool bMoveableFound = false;
     774 [ +  - ][ -  + ]:         19 :     for( ;aIt1!=aEnd; ++aIt1 )
     775                 :            :     {
     776         [ #  # ]:          0 :         if(aIt1->bMovementAllowed)
     777                 :            :         {
     778                 :          0 :             bMoveableFound = true;
     779                 :          0 :             break;
     780                 :            :         }
     781                 :            :     }
     782         [ -  + ]:         19 :     if(!bMoveableFound)
     783                 :            :         return;
     784                 :            : 
     785                 :          0 :     double fPageDiagonaleLength = sqrt( double( rPageSize.Width*rPageSize.Width + rPageSize.Height*rPageSize.Height) );
     786         [ #  # ]:          0 :     if( ::rtl::math::approxEqual( fPageDiagonaleLength, 0.0 ) )
     787                 :            :         return;
     788                 :            : 
     789                 :            :     //------------------------------------------------------------------
     790                 :            :     //init next and previous
     791                 :          0 :     aIt1 = m_aLabelInfoList.begin();
     792                 :          0 :     std::vector< PieLabelInfo >::iterator aIt2 = aIt1;
     793 [ #  # ][ #  # ]:          0 :     if( aIt1==aEnd )//no need to do anything when we only have one label
     794                 :            :         return;
     795         [ #  # ]:          0 :     aIt1->pPrevious = &(*(m_aLabelInfoList.rbegin()));
     796                 :          0 :     ++aIt2;
     797 [ #  # ][ #  # ]:          0 :     for( ;aIt2!=aEnd; ++aIt1, ++aIt2 )
     798                 :            :     {
     799                 :          0 :         PieLabelInfo& rInfo1( *aIt1 );
     800                 :          0 :         PieLabelInfo& rInfo2( *aIt2 );
     801                 :          0 :         rInfo1.pNext = &rInfo2;
     802                 :          0 :         rInfo2.pPrevious = &rInfo1;
     803                 :            :     }
     804                 :          0 :     aIt1->pNext = &(*(m_aLabelInfoList.begin()));
     805                 :            : 
     806                 :            : 
     807                 :            :     //------------------------------------------------------------------
     808                 :            :     //detect overlaps and move
     809                 :          0 :     sal_Int32 nMaxIterations = 50;
     810 [ #  # ][ #  # ]:          0 :     while( detectLabelOverlapsAndMove( rPageSize ) && nMaxIterations > 0 )
         [ #  # ][ #  # ]
     811                 :          0 :         nMaxIterations--;
     812                 :            : 
     813                 :            :     //------------------------------------------------------------------
     814                 :            :     //create connection lines for the moved labels
     815         [ #  # ]:          0 :     aEnd = m_aLabelInfoList.end();
     816         [ #  # ]:          0 :     VLineProperties aVLineProperties;
     817 [ #  # ][ #  # ]:          0 :     for( aIt1 = m_aLabelInfoList.begin(); aIt1!=aEnd; ++aIt1 )
     818                 :            :     {
     819                 :          0 :         PieLabelInfo& rInfo( *aIt1 );
     820         [ #  # ]:          0 :         if( rInfo.bMoved )
     821                 :            :         {
     822                 :          0 :             sal_Int32 nX1 = rInfo.aFirstPosition.getX();
     823                 :          0 :             sal_Int32 nY1 = rInfo.aFirstPosition.getY();
     824                 :          0 :             sal_Int32 nX2 = nX1;
     825                 :          0 :             sal_Int32 nY2 = nY1;
     826         [ #  # ]:          0 :             ::basegfx::B2IRectangle aRect( lcl_getRect( rInfo.xLabelGroupShape ) );
     827 [ #  # ][ #  # ]:          0 :             if( nX1 < aRect.getMinX() )
     828         [ #  # ]:          0 :                 nX2 = aRect.getMinX();
     829 [ #  # ][ #  # ]:          0 :             else if( nX1 > aRect.getMaxX() )
     830         [ #  # ]:          0 :                 nX2 = aRect.getMaxX();
     831                 :            : 
     832 [ #  # ][ #  # ]:          0 :             if( nY1 < aRect.getMinY() )
     833         [ #  # ]:          0 :                 nY2 = aRect.getMinY();
     834 [ #  # ][ #  # ]:          0 :             else if( nY1 > aRect.getMaxY() )
     835         [ #  # ]:          0 :                 nY2 = aRect.getMaxY();
     836                 :            : 
     837                 :            : 
     838                 :            :             //when the line is very short compared to the page size don't create one
     839                 :          0 :             ::basegfx::B2DVector aLength(nX1-nX2, nY1-nY2);
     840 [ #  # ][ #  # ]:          0 :             if( (aLength.getLength()/fPageDiagonaleLength) < 0.01 )
     841                 :          0 :                 continue;
     842                 :            : 
     843         [ #  # ]:          0 :             drawing::PointSequenceSequence aPoints(1);
     844 [ #  # ][ #  # ]:          0 :             aPoints[0].realloc(2);
     845 [ #  # ][ #  # ]:          0 :             aPoints[0][0].X = nX1;
     846 [ #  # ][ #  # ]:          0 :             aPoints[0][0].Y = nY1;
     847 [ #  # ][ #  # ]:          0 :             aPoints[0][1].X = nX2;
     848 [ #  # ][ #  # ]:          0 :             aPoints[0][1].Y = nY2;
     849                 :            : 
     850         [ #  # ]:          0 :             uno::Reference< beans::XPropertySet > xProp( rInfo.xTextShape, uno::UNO_QUERY);
     851         [ #  # ]:          0 :             if( xProp.is() )
     852                 :            :             {
     853                 :          0 :                 sal_Int32 nColor = 0;
     854 [ #  # ][ #  # ]:          0 :                 xProp->getPropertyValue(C2U("CharColor")) >>= nColor;
                 [ #  # ]
     855         [ #  # ]:          0 :                 if( nColor != -1 )//automatic font color does not work for lines -> fallback to black
     856         [ #  # ]:          0 :                     aVLineProperties.Color = uno::makeAny(nColor);
     857                 :            :             }
     858 [ #  # ][ #  # ]:          0 :             m_pShapeFactory->createLine2D( rInfo.xTextTarget, aPoints, &aVLineProperties );
                 [ #  # ]
     859                 :            :         }
     860                 :         19 :     }
     861                 :            : }
     862                 :            : 
     863                 :            : //.............................................................................
     864                 :            : } //namespace chart
     865                 :            : //.............................................................................
     866                 :            : 
     867                 :            : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10