summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKurt Nordback <kurt.nordback@protonmail.com>2023-10-31 20:29:34 -0600
committerNoel Grandin <noel.grandin@collabora.co.uk>2024-02-16 08:07:12 +0100
commit63562694beb42b86d0f00dd3c18ac47bb094c9fe (patch)
tree8c56074750714c4ebb4224dbbb8f2ff766ab2bb3
parent694b9b6422ee27da13ad455174cde50b1a673ac7 (diff)
tdf#50934: Implement PieDataSrc and related structure
Change-Id: I6affb326600d77ddf756d9bc223e7dcc29f87d23 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160725 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
-rw-r--r--chart2/source/view/charttypes/PieChart.cxx148
-rw-r--r--chart2/source/view/charttypes/PieChart.hxx80
2 files changed, 205 insertions, 23 deletions
diff --git a/chart2/source/view/charttypes/PieChart.cxx b/chart2/source/view/charttypes/PieChart.cxx
index 201e226119ab..0424130c8d5e 100644
--- a/chart2/source/view/charttypes/PieChart.cxx
+++ b/chart2/source/view/charttypes/PieChart.cxx
@@ -855,20 +855,38 @@ void PieChart::createShapes()
aParam.mfLogicYSum += fabs(fY);
}
- if (aParam.mfLogicYSum == 0.0)
+ if (aParam.mfLogicYSum == 0.0) {
// Total sum of all Y values in this series is zero. Skip the whole series.
continue;
+ }
+
+ PieDataSrcBase *pDataSrc = nullptr;
+ PieDataSrc normalPieSrc;
+ OfPieDataSrc ofPieSrc;
+
+ // Default to regular pie if too few points for of-pie
+ ::css::chart2::PieChartSubType eSubType =
+ nPointCount >= OfPieDataSrc::minPoints() ?
+ m_eSubType :
+ PieChartSubType_NONE;
- switch (m_eSubType) {
+ switch (eSubType) {
case PieChartSubType_NONE:
- createOneRing(SubPieType::NONE, fSlotX, aParam, xSeriesTarget, xTextTarget, pSeries, n3DRelativeHeight);
+ pDataSrc = &normalPieSrc;
+ createOneRing(SubPieType::NONE, fSlotX, aParam, xSeriesTarget,
+ xTextTarget, pSeries, pDataSrc, n3DRelativeHeight);
break;
case PieChartSubType_BAR:
- createOneRing(SubPieType::LEFT, 0, aParam, xSeriesTarget, xTextTarget, pSeries, n3DRelativeHeight);
+ pDataSrc = &ofPieSrc;
+ createOneRing(SubPieType::LEFT, 0, aParam, xSeriesTarget,
+ xTextTarget, pSeries, pDataSrc, n3DRelativeHeight);
break;
case PieChartSubType_PIE:
- createOneRing(SubPieType::LEFT, 0, aParam, xSeriesTarget, xTextTarget, pSeries, n3DRelativeHeight);
- createOneRing(SubPieType::RIGHT, 0, aParam, xSeriesTarget, xTextTarget, pSeries, n3DRelativeHeight);
+ pDataSrc = &ofPieSrc;
+ createOneRing(SubPieType::LEFT, 0, aParam, xSeriesTarget,
+ xTextTarget, pSeries, pDataSrc, n3DRelativeHeight);
+ createOneRing(SubPieType::RIGHT, 0, aParam, xSeriesTarget,
+ xTextTarget, pSeries, pDataSrc, n3DRelativeHeight);
break;
default:
assert(false); // this shouldn't happen
@@ -882,6 +900,7 @@ void PieChart::createOneRing([[maybe_unused]]enum SubPieType eType,
const rtl::Reference<SvxShapeGroupAnyD>& xSeriesTarget,
const rtl::Reference<SvxShapeGroup>& xTextTarget,
VDataSeries* pSeries,
+ const PieDataSrcBase *pDataSrc,
sal_Int32 n3DRelativeHeight)
{
bool bHasFillColorMapping = pSeries->hasPropertyMapping("FillColor");
@@ -891,10 +910,6 @@ void PieChart::createOneRing([[maybe_unused]]enum SubPieType eType,
/// 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.
@@ -902,9 +917,18 @@ void PieChart::createOneRing([[maybe_unused]]enum SubPieType eType,
if( m_aPosHelper.isMathematicalOrientationRadius() && m_bUseRings )
nExplodeableSlot = m_aZSlots.front().size()-1;
+ sal_Int32 nRingPtCnt = pDataSrc->getNPoints(pSeries, eType);
+
+ // Find sum of entries for this ring or sub-pie
+ double ringSum = 0;
+ for (sal_Int32 nPointIndex = 0; nPointIndex < nRingPtCnt; nPointIndex++ ) {
+ double fY = pDataSrc->getData(pSeries, nPointIndex, eType);
+ if (!std::isnan(fY) ) ringSum += fY;
+ }
+
double fLogicYForNextPoint = 0.0;
///iterate through all points to create shapes
- for(sal_Int32 nPointIndex = 0; nPointIndex < nPointCount; nPointIndex++ )
+ for(sal_Int32 nPointIndex = 0; nPointIndex < nRingPtCnt; nPointIndex++ )
{
double fLogicInnerRadius, fLogicOuterRadius;
@@ -923,8 +947,9 @@ void PieChart::createOneRing([[maybe_unused]]enum SubPieType eType,
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 ));
+ double fLogicYValue = pDataSrc->getData(pSeries, nPointIndex, eType);
if( std::isnan(fLogicYValue) )
continue;
if(fLogicYValue==0.0)//@todo: continue also if the resolution is too small
@@ -932,13 +957,14 @@ void PieChart::createOneRing([[maybe_unused]]enum SubPieType eType,
double fLogicYPos = fLogicYForNextPoint;
fLogicYForNextPoint += fLogicYValue;
- uno::Reference< beans::XPropertySet > xPointProperties = pSeries->getPropertiesOfPoint( nPointIndex );
+ uno::Reference< beans::XPropertySet > xPointProperties =
+ pDataSrc->getProps(pSeries, nPointIndex, eType);
//iterate through all subsystems to create partial points
{
//logic values on angle axis:
- double fLogicStartAngleValue = fLogicYPos / aParam.mfLogicYSum;
- double fLogicEndAngleValue = (fLogicYPos+fLogicYValue) / aParam.mfLogicYSum;
+ double fLogicStartAngleValue = fLogicYPos / ringSum;
+ double fLogicEndAngleValue = (fLogicYPos+fLogicYValue) / ringSum;
///note that the explode percentage is set to the `Offset`
///property of the current data series entry only for slices
@@ -967,8 +993,9 @@ void PieChart::createOneRing([[maybe_unused]]enum SubPieType eType,
// 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(eType, xSeriesGroupShape_Shapes, xPointProperties, aParam, nPointCount,
- bConcentricExplosion);
+ createDataPoint(eType, xSeriesGroupShape_Shapes,
+ xPointProperties, aParam, nRingPtCnt,
+ bConcentricExplosion);
///point color:
if (!pSeries->hasPointOwnColor(nPointIndex) && m_xColorScheme.is())
@@ -1828,6 +1855,93 @@ bool PieChart::performLabelBestFitInnerPlacement(ShapeParam& rShapeParam, PieLab
return true;
}
+//=======================
+// class PieDataSrc
+//=======================
+double PieDataSrc::getData(const VDataSeries* pSeries, sal_Int32 nPtIdx,
+ enum SubPieType /*eType*/) const
+{
+ return fabs(pSeries->getYValue( nPtIdx ));
+}
+
+sal_Int32 PieDataSrc::getNPoints(const VDataSeries* pSeries,
+ [[maybe_unused]] enum SubPieType eType) const
+{
+ assert(eType == SubPieType::NONE);
+ return pSeries->getTotalPointCount();
+}
+
+uno::Reference< beans::XPropertySet > PieDataSrc::getProps(
+ const VDataSeries* pSeries, sal_Int32 nPtIdx,
+ [[maybe_unused]] enum SubPieType eType) const
+{
+ assert(eType == SubPieType::NONE);
+ return pSeries->getPropertiesOfPoint(nPtIdx);
+}
+
+
+//=======================
+// class OfPieDataSrc
+//=======================
+
+// For now, just implement the default Excel behavior, which is that the
+// right pie consists of the last three entries in the series. Other
+// behaviors should be supported later.
+// TODO
+
+sal_Int32 OfPieDataSrc::getNPoints(const VDataSeries* pSeries,
+ enum SubPieType eType) const
+{
+ if (eType == SubPieType::LEFT) {
+ return pSeries->getTotalPointCount() - 2;
+ } else {
+ assert(eType == SubPieType::RIGHT);
+ return 3;
+ }
+}
+
+double OfPieDataSrc::getData(const VDataSeries* pSeries, sal_Int32 nPtIdx,
+ enum SubPieType eType) const
+{
+ const sal_Int32 n = pSeries->getTotalPointCount() - 3;
+ if (eType == SubPieType::LEFT) {
+ // nPtIdx should be in [0, n]
+ if (nPtIdx < n) {
+ return fabs(pSeries->getYValue( nPtIdx ));
+ } else {
+ assert(nPtIdx == n);
+ return fabs(pSeries->getYValue(n)) +
+ fabs(pSeries->getYValue(n+1)) +
+ fabs(pSeries->getYValue(n+2));
+ }
+ } else {
+ assert(eType == SubPieType::RIGHT);
+ return fabs(pSeries->getYValue(nPtIdx + n));
+ }
+}
+
+uno::Reference< beans::XPropertySet > OfPieDataSrc::getProps(
+ const VDataSeries* pSeries, sal_Int32 nPtIdx,
+ enum SubPieType eType) const
+{
+ const sal_Int32 n = pSeries->getTotalPointCount() - 3;
+ if (eType == SubPieType::LEFT) {
+ // nPtIdx should be in [0, n]
+ if (nPtIdx < n) {
+ return pSeries->getPropertiesOfPoint( nPtIdx );
+ } else {
+ assert(nPtIdx == n);
+ // The aggregated wedge
+ // Not sure what to do here, but this isn't right. TODO
+ return pSeries->getPropertiesOfPoint(n);
+ }
+ } else {
+ assert(eType == SubPieType::RIGHT);
+ return pSeries->getPropertiesOfPoint(nPtIdx + n);
+ }
+}
+
+
} //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 0517c87d67cd..8abd9973865c 100644
--- a/chart2/source/view/charttypes/PieChart.hxx
+++ b/chart2/source/view/charttypes/PieChart.hxx
@@ -26,6 +26,9 @@
#include <com/sun/star/awt/Point.hpp>
#include <com/sun/star/chart2/PieChartSubType.hpp>
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::chart2;
+
namespace chart
{
@@ -41,6 +44,75 @@ public:
double m_fRingDistance; //>=0 m_fRingDistance=1 --> distance == width
};
+enum class SubPieType {
+ NONE,
+ LEFT,
+ RIGHT
+};
+
+
+//=======================
+// class PieDataSrcBase
+//=======================
+class PieDataSrcBase
+{
+public:
+ PieDataSrcBase() = default;
+ virtual ~PieDataSrcBase() = default;
+
+ // Get number of points in the given pie subtype
+ virtual sal_Int32 getNPoints(const VDataSeries* pSeries,
+ enum SubPieType eType) const = 0;
+
+ // Get the value for the given pie wedge, for the given subtype
+ virtual double getData(const VDataSeries* pSeries, sal_Int32 nPtIdx,
+ enum SubPieType eType) const = 0;
+
+ // Get the properties for the wedge and subtype
+ virtual uno::Reference< beans::XPropertySet > getProps(
+ const VDataSeries* pSeries, sal_Int32 nPtIdx,
+ enum SubPieType eType) const = 0;
+};
+
+//=======================
+// class PieDataSrc
+//=======================
+class PieDataSrc : public PieDataSrcBase
+{
+ sal_Int32 getNPoints(const VDataSeries* pSeries,
+ enum SubPieType eType) const;
+
+ double getData(const VDataSeries* pSeries, sal_Int32 nPtIdx,
+ enum SubPieType eType) const;
+
+ virtual uno::Reference< beans::XPropertySet > getProps(
+ const VDataSeries* pSeries, sal_Int32 nPtIdx,
+ enum SubPieType eType) const;
+};
+
+//=======================
+// class OfPieDataSrc
+//=======================
+class OfPieDataSrc : public PieDataSrcBase
+{
+public:
+ // Minimum sensible number of data points
+ static sal_Int32 minPoints() { return 4; }
+
+ sal_Int32 getNPoints(const VDataSeries* pSeries,
+ enum SubPieType eType) const;
+
+ double getData(const VDataSeries* pSeries, sal_Int32 nPtIdx,
+ enum SubPieType eType) const;
+
+ virtual uno::Reference< beans::XPropertySet > getProps(
+ const VDataSeries* pSeries, sal_Int32 nPtIdx,
+ enum SubPieType eType) const;
+};
+
+//=======================
+// class PieChart
+//=======================
class PieChart : public VSeriesPlotter
{
struct ShapeParam;
@@ -75,12 +147,6 @@ 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(
@@ -135,6 +201,7 @@ struct PieLabelInfo;
, const rtl::Reference<SvxShapeGroupAnyD>& xSeriesTarget
, const rtl::Reference<SvxShapeGroup>& xTextTarget
, VDataSeries* pSeries
+ , const PieDataSrcBase *pDataSrc
, sal_Int32 n3DRelativeHeight);
private: //member
@@ -168,6 +235,7 @@ private: //member
double m_fMaxOffset; /// cached max offset value (init'ed to NaN)
};
+
} //namespace chart
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */