tdf#50934: Implementation of bar-of-pie, plus minor of-pie fixes

Change-Id: Ib343953ee30124524884859c8fe9e88d2dc7d822
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160726
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
diff --git a/chart2/source/view/charttypes/PieChart.cxx b/chart2/source/view/charttypes/PieChart.cxx
index 0424130..aee48da 100644
--- a/chart2/source/view/charttypes/PieChart.cxx
+++ b/chart2/source/view/charttypes/PieChart.cxx
@@ -227,6 +227,7 @@ PieChart::~PieChart()
void PieChart::setScales( std::vector< ExplicitScaleData >&& rScales, bool /* bSwapXAndYAxis */ )
{
    OSL_ENSURE(m_nDimension<=static_cast<sal_Int32>(rScales.size()),"Dimension of Plotter does not fit two dimension of given scale sequence");
    m_aCartesianScales = m_pPosHelper->getScales();
    m_aPosHelper.setScales( std::move(rScales), true );
}

@@ -333,6 +334,50 @@ rtl::Reference<SvxShape> PieChart::createDataPoint(
    return xShape;
}

rtl::Reference<SvxShape> PieChart::createBarDataPoint(
        const rtl::Reference<SvxShapeGroupAnyD>& xTarget,
        const uno::Reference<beans::XPropertySet>& xObjectProperties,
        const ShapeParam& rParam,
        double fBarSegBottom, double fBarSegTop)
{
    drawing::Position3D aP0, aP1;

    // Draw the bar for bar-of-pie small and to the right. Width and
    // position are hard-coded for now.

#if 0
    aP0 = cartesianPosHelper.transformLogicToScene(0.75, fBarSegBottom,
            rParam.mfLogicZ, false);
    aP1 = cartesianPosHelper.transformLogicToScene(1.25, fBarSegTop,
            rParam.mfLogicZ, false);
#else
    double x0 = m_aPosHelper.transformUnitCircleToScene(0, 0.75, 0).PositionX;
    double x1 = m_aPosHelper.transformUnitCircleToScene(0, 1.25, 0).PositionX;
    double y0 = m_aPosHelper.transformUnitCircleToScene(
            90, fBarSegBottom, 0).PositionY;
    double y1 = m_aPosHelper.transformUnitCircleToScene(
            90, fBarSegTop, 0).PositionY;

    aP0 = drawing::Position3D(x0, y0, rParam.mfLogicZ);
    aP1 = drawing::Position3D(x1, y1, rParam.mfLogicZ);
#endif

    const css::awt::Point aPos(aP0.PositionX, aP1.PositionY);
    const css::awt::Size aSz(fabs(aP0.PositionX - aP1.PositionX),
            fabs(aP0.PositionY - aP1.PositionY));

    const tNameSequence emptyNameSeq;
    const tAnySequence emptyValSeq;
    //create point
    rtl::Reference<SvxShape> xShape = ShapeFactory::createRectangle(
            xTarget,
            aSz, aPos,
            emptyNameSeq, emptyValSeq);

    PropertyMapper::setMappedProperties( *xShape, xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
    return xShape;
}

void PieChart::createTextLabelShape(
    const rtl::Reference<SvxShapeGroupAnyD>& xTextTarget,
    VDataSeries& rSeries, sal_Int32 nPointIndex, ShapeParam& rParam )
@@ -880,6 +925,8 @@ void PieChart::createShapes()
            pDataSrc = &ofPieSrc;
            createOneRing(SubPieType::LEFT, 0, aParam, xSeriesTarget,
                    xTextTarget, pSeries, pDataSrc, n3DRelativeHeight);
            createOneBar(SubPieType::RIGHT, aParam, xSeriesTarget,
                    xTextTarget, pSeries, pDataSrc, n3DRelativeHeight);
            break;
        case PieChartSubType_PIE:
            pDataSrc = &ofPieSrc;
@@ -926,6 +973,25 @@ void PieChart::createOneRing([[maybe_unused]]enum SubPieType eType,
        if (!std::isnan(fY) ) ringSum += fY;
    }

    // determine the starting angle around the ring
    auto sAngle = [&]()
    {
        if (eType == SubPieType::LEFT) {
            // Left of-pie has the "composite" wedge (the one expanded in the right
            // subgraph) facing to the right in the chart, to allow the expansion
            // lines to meet it
            double compositeVal = pDataSrc->getData(pSeries, nRingPtCnt - 1, eType);
            return compositeVal * 360 / (ringSum * 2);
        } else {
            /// The angle degree offset is set by the same property of the
            /// data series.
            /// Counter-clockwise offset from the 3 o'clock position.
            return static_cast<double>(pSeries->getStartingAngle());
        }
    };

    m_aPosHelper.m_fAngleDegreeOffset = sAngle();

    double fLogicYForNextPoint = 0.0;
    ///iterate through all points to create shapes
    for(sal_Int32 nPointIndex = 0; nPointIndex < nRingPtCnt; nPointIndex++ )
@@ -1057,6 +1123,81 @@ void PieChart::createOneRing([[maybe_unused]]enum SubPieType eType,
    }//next category
}

void PieChart::createOneBar(
        enum SubPieType eType,
        ShapeParam& aParam,
        const rtl::Reference<SvxShapeGroupAnyD>& xSeriesTarget,
        const rtl::Reference<SvxShapeGroup>& xTextTarget,
        VDataSeries* pSeries,
        const PieDataSrcBase *pDataSrc,
        sal_Int32 n3DRelativeHeight)
{
    bool bHasFillColorMapping = pSeries->hasPropertyMapping("FillColor");

    sal_Int32 nBarPtCnt = pDataSrc->getNPoints(pSeries, eType);

    // Find sum of entries for this bar chart
    double barSum = 0;
    for (sal_Int32 nPointIndex = 0; nPointIndex < nBarPtCnt; nPointIndex++ ) {
        double fY = pDataSrc->getData(pSeries, nPointIndex, eType);
        if (!std::isnan(fY) ) barSum += fY;
    }

    double fBarBottom = 0.0;
    double fBarTop = -0.5;  // make the bar go from -0.5 to 0.5
    ///iterate through all points to create shapes
    for(sal_Int32 nPointIndex = 0; nPointIndex < nBarPtCnt; nPointIndex++ )
    {
        aParam.mfDepth  = getTransformedDepth() * (n3DRelativeHeight / 100.0);

        rtl::Reference<SvxShapeGroupAnyD> xSeriesGroupShape_Shapes = getSeriesGroupShape(pSeries, xSeriesTarget);

        ///collect data point information (logic coordinates, style ):
        double fY = pDataSrc->getData(pSeries, nPointIndex, eType) / barSum;
        if( std::isnan(fY) )
            continue;
        if(fY==0.0)//@todo: continue also if the resolution is too small
            continue;
        fBarBottom = fBarTop;
        fBarTop += fY;

        uno::Reference< beans::XPropertySet > xPointProperties =
            pDataSrc->getProps(pSeries, nPointIndex, eType);

        ///create data point
        aParam.mfLogicZ = -1.0; // For 3D pie chart label position

        rtl::Reference<SvxShape> xPointShape =
            createBarDataPoint(xSeriesGroupShape_Shapes,
                    xPointProperties, aParam,
                    fBarBottom, fBarTop);

        ///point color:
        if (!pSeries->hasPointOwnColor(nPointIndex) && m_xColorScheme.is())
        {
            xPointShape->setPropertyValue("FillColor",
                uno::Any(m_xColorScheme->getColorByIndex( nPointIndex )));
        }


        if(bHasFillColorMapping)
        {
            double nPropVal = pSeries->getValueByProperty(nPointIndex, "FillColor");
            if(!std::isnan(nPropVal))
            {
                xPointShape->setPropertyValue("FillColor", uno::Any(static_cast<sal_Int32>( nPropVal)));
            }
        }

        ///create label
        createTextLabelShape(xTextTarget, *pSeries, nPointIndex, aParam);

        ShapeFactory::setShapeName( xPointShape,
                ObjectIdentifier::createPointCID( pSeries->getPointCID_Stub(),
                    nPointIndex ) );
    }//next category
}

PieChart::PieLabelInfo::PieLabelInfo()
    :  fValue(0.0)
    , bMovementAllowed(false), bMoved(false)
@@ -1859,7 +2000,7 @@ bool PieChart::performLabelBestFitInnerPlacement(ShapeParam& rShapeParam, PieLab
// class PieDataSrc
//=======================
double PieDataSrc::getData(const VDataSeries* pSeries, sal_Int32 nPtIdx,
        enum SubPieType /*eType*/) const
       [[maybe_unused]] enum SubPieType eType) const
{
    return fabs(pSeries->getYValue( nPtIdx ));
}
@@ -1941,7 +2082,6 @@ uno::Reference< beans::XPropertySet > OfPieDataSrc::getProps(
    }
}


} //namespace chart

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/view/charttypes/PieChart.hxx b/chart2/source/view/charttypes/PieChart.hxx
index 8abd997..731c4e6 100644
--- a/chart2/source/view/charttypes/PieChart.hxx
+++ b/chart2/source/view/charttypes/PieChart.hxx
@@ -45,9 +45,9 @@ public:
};

enum class SubPieType {
    NONE,
    LEFT,
    RIGHT
    NONE,   // solo pie or donut
    LEFT,   // left pie in pie-of-pie
    RIGHT   // right pie in pie-of-pie
};


@@ -79,11 +79,12 @@ public:
//=======================
class PieDataSrc : public PieDataSrcBase
{
public:
    sal_Int32 getNPoints(const VDataSeries* pSeries,
                enum SubPieType eType) const;

    double getData(const VDataSeries* pSeries, sal_Int32 nPtIdx,
            enum SubPieType eType) const;
            [[maybe_unused]]enum SubPieType eType) const;

    virtual uno::Reference< beans::XPropertySet > getProps(
            const VDataSeries* pSeries, sal_Int32 nPtIdx,
@@ -157,6 +158,11 @@ private: //methods
            const sal_Int32 nPointCount,
            const bool bConcentricExplosion);

    rtl::Reference<SvxShape> createBarDataPoint(
            const rtl::Reference<SvxShapeGroupAnyD>& xTarget,
            const uno::Reference<beans::XPropertySet>& xObjectProperties,
            const ShapeParam& rParam,
            double fBarSegBottom, double fBarSegTop);
    /** This method creates a text shape for a label of a data point.
     *
     *  @param xTextTarget
@@ -195,6 +201,7 @@ struct PieLabelInfo;
    bool                performLabelBestFitInnerPlacement( ShapeParam& rShapeParam
                                , PieLabelInfo const & rPieLabelInfo );

    // A standalone pie, one pie in a pie-of-pie, or one ring of a donut
    void                createOneRing([[maybe_unused]]enum SubPieType eType
                                , double fSlotX
                                , ShapeParam& aParam
@@ -204,10 +211,21 @@ struct PieLabelInfo;
                                , const PieDataSrcBase *pDataSrc
                                , sal_Int32 n3DRelativeHeight);

    // A bar chart in a bar-of-pie
    void                createOneBar(
            enum SubPieType eType,
            ShapeParam& aParam,
            const rtl::Reference<SvxShapeGroupAnyD>& xSeriesTarget,
            const rtl::Reference<SvxShapeGroup>& xTextTarget,
            VDataSeries* pSeries,
            const PieDataSrcBase *pDataSrc,
            sal_Int32 n3DRelativeHeight);

private: //member
    PiePositionHelper     m_aPosHelper;
    bool                  m_bUseRings;
    bool                  m_bSizeExcludesLabelsAndExplodedSegments;
    std::vector< ExplicitScaleData > m_aCartesianScales; // for bar-of-pie
    ::css::chart2::PieChartSubType m_eSubType;

    struct PieLabelInfo