chart2/source/view/charttypes/PieChart.cxx |  286 ++++++++++++++++-------------
 chart2/source/view/charttypes/PieChart.hxx |   14 +
 2 files changed, 173 insertions(+), 127 deletions(-)

New commits:
commit d81c98623b2abb991ca696b3b09011f6bb3de673
Author:     Kurt Nordback <kurt.nordb...@protonmail.com>
AuthorDate: Fri Sep 1 16:13:15 2023 -0600
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Wed Feb 14 07:58:41 2024 +0100

    tdf#50934: Restructuring for of-pie charts
    
    Change-Id: I9682c314efb888d57e94f82f084cc6d0825a4408
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160723
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>

diff --git a/chart2/source/view/charttypes/PieChart.cxx 
b/chart2/source/view/charttypes/PieChart.cxx
index 0f924de7c5ab..49cf48de3f05 100644
--- a/chart2/source/view/charttypes/PieChart.cxx
+++ b/chart2/source/view/charttypes/PieChart.cxx
@@ -790,13 +790,6 @@ void PieChart::createShapes()
     ///the angle axis scale range is [0, 1]. The max_offset parameter is used
     ///for exploded pie chart and its value is 0.5.
 
-    ///the `explodeable` ring is the first one except when the radius axis
-    ///orientation is reversed (always!?) and we are dealing with a donut: in
-    ///such a case the `explodeable` ring is the last one.
-    std::vector< VDataSeriesGroup >::size_type nExplodeableSlot = 0;
-    if( m_aPosHelper.isMathematicalOrientationRadius() && m_bUseRings )
-        nExplodeableSlot = m_aZSlots.front().size()-1;
-
     m_aLabelInfoList.clear();
     m_fMaxOffset = std::numeric_limits<double>::quiet_NaN();
     sal_Int32 n3DRelativeHeight = 100;
@@ -815,8 +808,6 @@ void PieChart::createShapes()
     ///(m_bUseRings||fSlotX<0.5)
     for( double fSlotX=0; aXSlotIter != aXSlotEnd && (m_bUseRings||fSlotX<0.5 
); ++aXSlotIter, fSlotX+=1.0 )
     {
-        ShapeParam aParam;
-
         std::vector< std::unique_ptr<VDataSeries> >* pSeriesList = 
&(aXSlotIter->m_aSeriesVector);
         if(pSeriesList->empty())//there should be only one series in each x 
slot
             continue;
@@ -824,8 +815,6 @@ void PieChart::createShapes()
         if(!pSeries)
             continue;
 
-        bool bHasFillColorMapping = pSeries->hasPropertyMapping("FillColor");
-
         /// The angle degree offset is set by the same property of the
         /// data series.
         /// Counter-clockwise offset from the 3 o'clock position.
@@ -835,6 +824,8 @@ void PieChart::createShapes()
         ///the current data series
         sal_Int32 nPointIndex=0;
         sal_Int32 nPointCount=pSeries->getTotalPointCount();
+        ShapeParam aParam;
+
         for( nPointIndex = 0; nPointIndex < nPointCount; nPointIndex++ )
         {
             double fY = pSeries->getYValue( nPointIndex );
@@ -851,134 +842,175 @@ void PieChart::createShapes()
             // Total sum of all Y values in this series is zero. Skip the 
whole series.
             continue;
 
-        double fLogicYForNextPoint = 0.0;
-        ///iterate through all points to create shapes
-        for( nPointIndex = 0; nPointIndex < nPointCount; nPointIndex++ )
-        {
-            double fLogicInnerRadius, fLogicOuterRadius;
-
-            ///compute the maximum relative distance offset of the current 
slice
-            ///from the pie center
-            ///it is worth noting that after the first invocation the maximum
-            ///offset value is cached, so it is evaluated only once per each
-            ///call to `createShapes`
-            double fOffset = getMaxOffset();
-
-            ///compute the outer and the inner radius for the current ring 
slice
-            bool bIsVisible = m_aPosHelper.getInnerAndOuterRadius( fSlotX+1.0, 
fLogicInnerRadius, fLogicOuterRadius, m_bUseRings, fOffset );
-            if( !bIsVisible )
-                continue;
+        switch (m_eSubType) {
+        case PieChartSubType_NONE:
+            createOneRing(SubPieType::NONE, fSlotX, aParam, xSeriesTarget, 
xTextTarget, pSeries, n3DRelativeHeight);
+            break;
+        case PieChartSubType_BAR:
+            createOneRing(SubPieType::LEFT, fSlotX, aParam, xSeriesTarget, 
xTextTarget, pSeries, n3DRelativeHeight);
+            break;
+        case PieChartSubType_PIE:
+            createOneRing(SubPieType::LEFT, fSlotX, aParam, xSeriesTarget, 
xTextTarget, pSeries, n3DRelativeHeight);
+            break;
+        default:
+            assert(false); // this shouldn't happen
+        }
+    }//next x slot
+}
 
-            aParam.mfDepth  = getTransformedDepth() * (n3DRelativeHeight / 
100.0);
+void PieChart::createOneRing([[maybe_unused]]enum SubPieType eType,
+        double fSlotX,
+        ShapeParam& aParam,
+        const rtl::Reference<SvxShapeGroupAnyD>& xSeriesTarget,
+        const rtl::Reference<SvxShapeGroup>& xTextTarget,
+        VDataSeries* pSeries,
+        sal_Int32 n3DRelativeHeight)
+{
+    bool bHasFillColorMapping = pSeries->hasPropertyMapping("FillColor");
 
-            rtl::Reference<SvxShapeGroupAnyD> xSeriesGroupShape_Shapes = 
getSeriesGroupShape(pSeries, xSeriesTarget);
-            ///collect data point information (logic coordinates, style ):
-            double fLogicYValue = fabs(pSeries->getYValue( nPointIndex ));
-            if( std::isnan(fLogicYValue) )
-                continue;
-            if(fLogicYValue==0.0)//@todo: continue also if the resolution is 
too small
-                continue;
-            double fLogicYPos = fLogicYForNextPoint;
-            fLogicYForNextPoint += fLogicYValue;
+    /// The angle degree offset is set by the same property of the
+    /// data series.
+    /// Counter-clockwise offset from the 3 o'clock position.
+    m_aPosHelper.m_fAngleDegreeOffset = pSeries->getStartingAngle();
+
+    ///iterate through all points to get the sum of all entries of
+    ///the current data series
+    sal_Int32 nPointCount=pSeries->getTotalPointCount();
+
+    ///the `explodeable` ring is the first one except when the radius axis
+    ///orientation is reversed (always!?) and we are dealing with a donut: in
+    ///such a case the `explodeable` ring is the last one.
+    std::vector< VDataSeriesGroup >::size_type nExplodeableSlot = 0;
+    if( m_aPosHelper.isMathematicalOrientationRadius() && m_bUseRings )
+        nExplodeableSlot = m_aZSlots.front().size()-1;
+
+    double fLogicYForNextPoint = 0.0;
+    ///iterate through all points to create shapes
+    for(sal_Int32 nPointIndex = 0; nPointIndex < nPointCount; nPointIndex++ )
+    {
+        double fLogicInnerRadius, fLogicOuterRadius;
+
+        ///compute the maximum relative distance offset of the current slice
+        ///from the pie center
+        ///it is worth noting that after the first invocation the maximum
+        ///offset value is cached, so it is evaluated only once per each
+        ///call to `createShapes`
+        double fOffset = getMaxOffset();
+
+        ///compute the outer and the inner radius for the current ring slice
+        bool bIsVisible = m_aPosHelper.getInnerAndOuterRadius( fSlotX+1.0, 
fLogicInnerRadius, fLogicOuterRadius, m_bUseRings, fOffset );
+        if( !bIsVisible )
+            continue;
+
+        aParam.mfDepth  = getTransformedDepth() * (n3DRelativeHeight / 100.0);
+
+        rtl::Reference<SvxShapeGroupAnyD> xSeriesGroupShape_Shapes = 
getSeriesGroupShape(pSeries, xSeriesTarget);
+        ///collect data point information (logic coordinates, style ):
+        double fLogicYValue = fabs(pSeries->getYValue( nPointIndex ));
+        if( std::isnan(fLogicYValue) )
+            continue;
+        if(fLogicYValue==0.0)//@todo: continue also if the resolution is too 
small
+            continue;
+        double fLogicYPos = fLogicYForNextPoint;
+        fLogicYForNextPoint += fLogicYValue;
 
-            uno::Reference< beans::XPropertySet > xPointProperties = 
pSeries->getPropertiesOfPoint( nPointIndex );
+        uno::Reference< beans::XPropertySet > xPointProperties = 
pSeries->getPropertiesOfPoint( nPointIndex );
 
-            //iterate through all subsystems to create partial points
+        //iterate through all subsystems to create partial points
+        {
+            //logic values on angle axis:
+            double fLogicStartAngleValue = fLogicYPos / aParam.mfLogicYSum;
+            double fLogicEndAngleValue = (fLogicYPos+fLogicYValue) / 
aParam.mfLogicYSum;
+
+            ///note that the explode percentage is set to the `Offset`
+            ///property of the current data series entry only for slices
+            ///belonging to the outer ring
+            aParam.mfExplodePercentage = 0.0;
+            bool bDoExplode = ( nExplodeableSlot == static_cast< std::vector< 
VDataSeriesGroup >::size_type >(fSlotX) );
+            if(bDoExplode) try
             {
-                //logic values on angle axis:
-                double fLogicStartAngleValue = fLogicYPos / aParam.mfLogicYSum;
-                double fLogicEndAngleValue = (fLogicYPos+fLogicYValue) / 
aParam.mfLogicYSum;
-
-                ///note that the explode percentage is set to the `Offset`
-                ///property of the current data series entry only for slices
-                ///belonging to the outer ring
-                aParam.mfExplodePercentage = 0.0;
-                bool bDoExplode = ( nExplodeableSlot == static_cast< 
std::vector< VDataSeriesGroup >::size_type >(fSlotX) );
-                if(bDoExplode) try
-                {
-                    xPointProperties->getPropertyValue( "Offset") >>= 
aParam.mfExplodePercentage;
-                }
-                catch( const uno::Exception& )
-                {
-                    TOOLS_WARN_EXCEPTION("chart2", "" );
-                }
+                xPointProperties->getPropertyValue( "Offset") >>= 
aParam.mfExplodePercentage;
+            }
+            catch( const uno::Exception& )
+            {
+                TOOLS_WARN_EXCEPTION("chart2", "" );
+            }
 
-                ///see notes for `PolarPlottingPositionHelper` methods
-                ///transform to unit circle:
-                aParam.mfUnitCircleWidthAngleDegree = 
m_aPosHelper.getWidthAngleDegree( fLogicStartAngleValue, fLogicEndAngleValue );
-                aParam.mfUnitCircleStartAngleDegree = 
m_aPosHelper.transformToAngleDegree( fLogicStartAngleValue );
-                aParam.mfUnitCircleInnerRadius = 
m_aPosHelper.transformToRadius( fLogicInnerRadius );
-                aParam.mfUnitCircleOuterRadius = 
m_aPosHelper.transformToRadius( fLogicOuterRadius );
-
-                ///create data point
-                aParam.mfLogicZ = -1.0; // For 3D pie chart label position
-
-                // Do concentric explosion if it's a donut chart with more 
than one series
-                const bool bConcentricExplosion = m_bUseRings && 
(m_aZSlots.front().size() > 1);
-                rtl::Reference<SvxShape> xPointShape =
-                    createDataPoint(
-                        xSeriesGroupShape_Shapes, xPointProperties, aParam, 
nPointCount,
-                        bConcentricExplosion);
-
-                ///point color:
-                if (!pSeries->hasPointOwnColor(nPointIndex) && 
m_xColorScheme.is())
-                {
-                    xPointShape->setPropertyValue("FillColor",
-                        uno::Any(m_xColorScheme->getColorByIndex( nPointIndex 
)));
-                }
+            ///see notes for `PolarPlottingPositionHelper` methods
+            ///transform to unit circle:
+            aParam.mfUnitCircleWidthAngleDegree = 
m_aPosHelper.getWidthAngleDegree( fLogicStartAngleValue, fLogicEndAngleValue );
+            aParam.mfUnitCircleStartAngleDegree = 
m_aPosHelper.transformToAngleDegree( fLogicStartAngleValue );
+            aParam.mfUnitCircleInnerRadius = m_aPosHelper.transformToRadius( 
fLogicInnerRadius );
+            aParam.mfUnitCircleOuterRadius = m_aPosHelper.transformToRadius( 
fLogicOuterRadius );
+
+            ///create data point
+            aParam.mfLogicZ = -1.0; // For 3D pie chart label position
+
+            // Do concentric explosion if it's a donut chart with more than 
one series
+            const bool bConcentricExplosion = m_bUseRings && 
(m_aZSlots.front().size() > 1);
+            rtl::Reference<SvxShape> xPointShape =
+                createDataPoint(
+                    xSeriesGroupShape_Shapes, xPointProperties, aParam, 
nPointCount,
+                    bConcentricExplosion);
+
+            ///point color:
+            if (!pSeries->hasPointOwnColor(nPointIndex) && m_xColorScheme.is())
+            {
+                xPointShape->setPropertyValue("FillColor",
+                    uno::Any(m_xColorScheme->getColorByIndex( nPointIndex )));
+            }
 
 
-                if(bHasFillColorMapping)
+            if(bHasFillColorMapping)
+            {
+                double nPropVal = pSeries->getValueByProperty(nPointIndex, 
"FillColor");
+                if(!std::isnan(nPropVal))
                 {
-                    double nPropVal = pSeries->getValueByProperty(nPointIndex, 
"FillColor");
-                    if(!std::isnan(nPropVal))
-                    {
-                        xPointShape->setPropertyValue("FillColor", 
uno::Any(static_cast<sal_Int32>( nPropVal)));
-                    }
+                    xPointShape->setPropertyValue("FillColor", 
uno::Any(static_cast<sal_Int32>( nPropVal)));
                 }
+            }
 
-                ///create label
-                createTextLabelShape(xTextTarget, *pSeries, nPointIndex, 
aParam);
+            ///create label
+            createTextLabelShape(xTextTarget, *pSeries, nPointIndex, aParam);
 
-                if(!bDoExplode)
-                {
-                    ShapeFactory::setShapeName( xPointShape
-                                , ObjectIdentifier::createPointCID( 
pSeries->getPointCID_Stub(), nPointIndex ) );
-                }
-                else try
-                {
-                    ///enable dragging of outer segments
-
-                    double fAngle  = aParam.mfUnitCircleStartAngleDegree + 
aParam.mfUnitCircleWidthAngleDegree/2.0;
-                    double fMaxDeltaRadius = 
aParam.mfUnitCircleOuterRadius-aParam.mfUnitCircleInnerRadius;
-                    drawing::Position3D aOrigin = 
m_aPosHelper.transformUnitCircleToScene( fAngle, 
aParam.mfUnitCircleOuterRadius, aParam.mfLogicZ );
-                    drawing::Position3D aNewOrigin = 
m_aPosHelper.transformUnitCircleToScene( fAngle, aParam.mfUnitCircleOuterRadius 
+ fMaxDeltaRadius, aParam.mfLogicZ );
-
-                    sal_Int32 nOffsetPercent( 
static_cast<sal_Int32>(aParam.mfExplodePercentage * 100.0) );
-
-                    awt::Point aMinimumPosition( 
PlottingPositionHelper::transformSceneToScreenPosition(
-                        aOrigin, m_xLogicTarget, m_nDimension ) );
-                    awt::Point aMaximumPosition( 
PlottingPositionHelper::transformSceneToScreenPosition(
-                        aNewOrigin, m_xLogicTarget, m_nDimension ) );
-
-                    //enable dragging of piesegments
-                    OUString aPointCIDStub( 
ObjectIdentifier::createSeriesSubObjectStub( OBJECTTYPE_DATA_POINT
-                        , pSeries->getSeriesParticle()
-                        , 
ObjectIdentifier::getPieSegmentDragMethodServiceName()
-                        , 
ObjectIdentifier::createPieSegmentDragParameterString(
-                            nOffsetPercent, aMinimumPosition, aMaximumPosition 
)
-                        ) );
-
-                    ShapeFactory::setShapeName( xPointShape
-                                , ObjectIdentifier::createPointCID( 
aPointCIDStub, nPointIndex ) );
-                }
-                catch( const uno::Exception& )
-                {
-                    TOOLS_WARN_EXCEPTION("chart2", "" );
-                }
-            }//next series in x slot (next y slot)
-        }//next category
-    }//next x slot
+            if(!bDoExplode)
+            {
+                ShapeFactory::setShapeName( xPointShape
+                            , ObjectIdentifier::createPointCID( 
pSeries->getPointCID_Stub(), nPointIndex ) );
+            }
+            else try
+            {
+                ///enable dragging of outer segments
+
+                double fAngle  = aParam.mfUnitCircleStartAngleDegree + 
aParam.mfUnitCircleWidthAngleDegree/2.0;
+                double fMaxDeltaRadius = 
aParam.mfUnitCircleOuterRadius-aParam.mfUnitCircleInnerRadius;
+                drawing::Position3D aOrigin = 
m_aPosHelper.transformUnitCircleToScene( fAngle, 
aParam.mfUnitCircleOuterRadius, aParam.mfLogicZ );
+                drawing::Position3D aNewOrigin = 
m_aPosHelper.transformUnitCircleToScene( fAngle, aParam.mfUnitCircleOuterRadius 
+ fMaxDeltaRadius, aParam.mfLogicZ );
+
+                sal_Int32 nOffsetPercent( 
static_cast<sal_Int32>(aParam.mfExplodePercentage * 100.0) );
+
+                awt::Point aMinimumPosition( 
PlottingPositionHelper::transformSceneToScreenPosition(
+                    aOrigin, m_xLogicTarget, m_nDimension ) );
+                awt::Point aMaximumPosition( 
PlottingPositionHelper::transformSceneToScreenPosition(
+                    aNewOrigin, m_xLogicTarget, m_nDimension ) );
+
+                //enable dragging of piesegments
+                OUString aPointCIDStub( 
ObjectIdentifier::createSeriesSubObjectStub( OBJECTTYPE_DATA_POINT
+                    , pSeries->getSeriesParticle()
+                    , ObjectIdentifier::getPieSegmentDragMethodServiceName()
+                    , ObjectIdentifier::createPieSegmentDragParameterString(
+                        nOffsetPercent, aMinimumPosition, aMaximumPosition )
+                    ) );
+
+                ShapeFactory::setShapeName( xPointShape
+                            , ObjectIdentifier::createPointCID( aPointCIDStub, 
nPointIndex ) );
+            }
+            catch( const uno::Exception& )
+            {
+                TOOLS_WARN_EXCEPTION("chart2", "" );
+            }
+        }//next series in x slot (next y slot)
+    }//next category
 }
 
 PieChart::PieLabelInfo::PieLabelInfo()
diff --git a/chart2/source/view/charttypes/PieChart.hxx 
b/chart2/source/view/charttypes/PieChart.hxx
index d6792f0b8479..5c04ee05cf86 100644
--- a/chart2/source/view/charttypes/PieChart.hxx
+++ b/chart2/source/view/charttypes/PieChart.hxx
@@ -75,6 +75,12 @@ public:
     virtual bool isExpandNarrowValuesTowardZero( sal_Int32 nDimensionIndex ) 
override;
     virtual bool isSeparateStackingForDifferentSigns( sal_Int32 
nDimensionIndex ) override;
 
+    enum class SubPieType {
+        NONE,
+        LEFT,
+        RIGHT
+    };
+
 private: //methods
     rtl::Reference<SvxShape>
         createDataPoint(
@@ -122,6 +128,14 @@ struct PieLabelInfo;
     bool                performLabelBestFitInnerPlacement( ShapeParam& 
rShapeParam
                                 , PieLabelInfo const & rPieLabelInfo );
 
+    void                createOneRing([[maybe_unused]]enum SubPieType eType
+                                , double fSlotX
+                                , ShapeParam& aParam
+                                , const rtl::Reference<SvxShapeGroupAnyD>& 
xSeriesTarget
+                                , const rtl::Reference<SvxShapeGroup>& 
xTextTarget
+                                , VDataSeries* pSeries
+                                , sal_Int32 n3DRelativeHeight);
+
 private: //member
     PiePositionHelper     m_aPosHelper;
     bool                  m_bUseRings;

Reply via email to