tdf#104428 Improve rendering of exploded donut charts
This bug shows an exploded donut chart with more than one series. The
concern is that the standard pie/donut' explosion' rendering, with the shape
of the pieces unchanged but the pieces translated outward, gives
unsatisfactory results in the case of a donut with more than one series,
where the translated 'exploded' pieces can overlap with the inner ring.
This proposed fix renders this case differently, by increasing the radius
of the exploded ring but keeping the pieces concentric with the inner ring.
This commit also modifies the unit test values for donut_chart.ods.
Change-Id: I713b1f3ce4697d46d29914410056f0aa83c6aa8b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/135394
Tested-by: Jenkins
Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
(cherry picked from commit 9b558357a3e7a4c908084134d56770809116b4f1)
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/136765
Reviewed-by: Adolfo Jayme Barrientos <fitojb@ubuntu.com>
diff --git a/chart2/qa/extras/chart2dump/reference/piecharttest/donut_chart.txt b/chart2/qa/extras/chart2dump/reference/piecharttest/donut_chart.txt
index b2dfd33..c1af411 100644
--- a/chart2/qa/extras/chart2dump/reference/piecharttest/donut_chart.txt
+++ b/chart2/qa/extras/chart2dump/reference/piecharttest/donut_chart.txt
@@ -35,15 +35,15 @@
16728590
/// /D=0:CS=0:CT=0:Series=0:Point=2
// aSlicePosition.X
8909
9033
// aSlicePosition.Y
4532
4635
// aSliceSize.Height
4689
4659
// aSliceSize.Width
2544
2458
// aSliceTransformation
2544;0;8909;0;4689;4532;0;0;1
2458;0;9033;0;4659;4635;0;0;1
// static_cast<sal_Int32>(aSliceFillStyle)
1
// static_cast<sal_Int32>(aSliceFillColor)
diff --git a/chart2/source/view/charttypes/PieChart.cxx b/chart2/source/view/charttypes/PieChart.cxx
index 806bc46..a81428c 100644
--- a/chart2/source/view/charttypes/PieChart.cxx
+++ b/chart2/source/view/charttypes/PieChart.cxx
@@ -246,17 +246,47 @@ bool PieChart::shouldSnapRectToUsedArea()
rtl::Reference<SvxShape> PieChart::createDataPoint(
const rtl::Reference<SvxShapeGroupAnyD>& xTarget,
const uno::Reference<beans::XPropertySet>& xObjectProperties,
const ShapeParam& rParam )
const ShapeParam& rParam,
const sal_Int32 nPointCount,
const bool bConcentricExplosion)
{
//transform position:
drawing::Direction3D aOffset;
if (rParam.mfExplodePercentage != 0.0)
{
double fAngle = rParam.mfUnitCircleStartAngleDegree + rParam.mfUnitCircleWidthAngleDegree/2.0;
double fRadius = (rParam.mfUnitCircleOuterRadius-rParam.mfUnitCircleInnerRadius)*rParam.mfExplodePercentage;
drawing::Position3D aOrigin = m_pPosHelper->transformUnitCircleToScene(0, 0, rParam.mfLogicZ);
drawing::Position3D aNewOrigin = m_pPosHelper->transformUnitCircleToScene(fAngle, fRadius, rParam.mfLogicZ);
aOffset = aNewOrigin - aOrigin;
double fExplodedInnerRadius = rParam.mfUnitCircleInnerRadius;
double fExplodedOuterRadius = rParam.mfUnitCircleOuterRadius;
double fStartAngle = rParam.mfUnitCircleStartAngleDegree;
double fWidthAngle = rParam.mfUnitCircleWidthAngleDegree;
if (rParam.mfExplodePercentage != 0.0) {
double fRadius = (fExplodedOuterRadius-fExplodedInnerRadius)*rParam.mfExplodePercentage;
if (bConcentricExplosion) {
// For concentric explosion, increase the radius but retain the original
// arc length of all ring segments together. This results in a gap
// that's evenly divided among all segments, assuming they all have
// the same explosion percentage
assert(fExplodedInnerRadius >= 0 && fExplodedOuterRadius > 0);
double fAngleRatio = (fExplodedInnerRadius + fExplodedOuterRadius) /
(fExplodedInnerRadius + fExplodedOuterRadius + 2 * fRadius);
assert(nPointCount > 0);
double fAngleGap = 360 * (1.0 - fAngleRatio) / nPointCount;
fStartAngle += fAngleGap / 2;
fWidthAngle -= fAngleGap;
fExplodedInnerRadius += fRadius;
fExplodedOuterRadius += fRadius;
} else {
// For the non-concentric explosion case, keep the original radius
// but shift the circle origin
double fAngle = fStartAngle + fWidthAngle/2.0;
drawing::Position3D aOrigin = m_pPosHelper->transformUnitCircleToScene(0, 0, rParam.mfLogicZ);
drawing::Position3D aNewOrigin = m_pPosHelper->transformUnitCircleToScene(fAngle, fRadius, rParam.mfLogicZ);
aOffset = aNewOrigin - aOrigin;
}
}
//create point
@@ -264,16 +294,16 @@ rtl::Reference<SvxShape> PieChart::createDataPoint(
if(m_nDimension==3)
{
xShape = ShapeFactory::createPieSegment( xTarget
, rParam.mfUnitCircleStartAngleDegree, rParam.mfUnitCircleWidthAngleDegree
, rParam.mfUnitCircleInnerRadius, rParam.mfUnitCircleOuterRadius
, fStartAngle, fWidthAngle
, fExplodedInnerRadius, fExplodedOuterRadius
, aOffset, B3DHomMatrixToHomogenMatrix( m_pPosHelper->getUnitCartesianToScene() )
, rParam.mfDepth );
}
else
{
xShape = ShapeFactory::createPieSegment2D( xTarget
, rParam.mfUnitCircleStartAngleDegree, rParam.mfUnitCircleWidthAngleDegree
, rParam.mfUnitCircleInnerRadius, rParam.mfUnitCircleOuterRadius
, fStartAngle, fWidthAngle
, fExplodedInnerRadius, fExplodedOuterRadius
, aOffset, B3DHomMatrixToHomogenMatrix( m_pPosHelper->getUnitCartesianToScene() ) );
}
PropertyMapper::setMappedProperties( *xShape, xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
@@ -808,9 +838,13 @@ void PieChart::createShapes()
///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);
xSeriesGroupShape_Shapes, xPointProperties, aParam, nPointCount,
bConcentricExplosion);
///point color:
if (!pSeries->hasPointOwnColor(nPointIndex) && m_xColorScheme.is())
diff --git a/chart2/source/view/charttypes/PieChart.hxx b/chart2/source/view/charttypes/PieChart.hxx
index c990cc6..9a5b7fb 100644
--- a/chart2/source/view/charttypes/PieChart.hxx
+++ b/chart2/source/view/charttypes/PieChart.hxx
@@ -67,7 +67,9 @@ private: //methods
createDataPoint(
const rtl::Reference<SvxShapeGroupAnyD>& xTarget,
const css::uno::Reference<css::beans::XPropertySet>& xObjectProperties,
const ShapeParam& rParam );
const ShapeParam& rParam,
const sal_Int32 nPointCount,
const bool bConcentricExplosion);
/** This method creates a text shape for a label of a data point.
*