summaryrefslogtreecommitdiff
path: root/chart2
diff options
context:
space:
mode:
authorNoel Grandin <noel.grandin@collabora.co.uk>2022-01-12 14:21:58 +0200
committerNoel Grandin <noel.grandin@collabora.co.uk>2022-01-13 07:36:24 +0100
commitb0c68f982dfabd33b6049c3614734401f70bae50 (patch)
tree740a0635824fdc020c3c610b8715f74f16414960 /chart2
parent897d91c0d3a570492477bcffdc4b6b3b6213a7fa (diff)
split the BarChart rendering method down a little
into slightly more manageable chunks Change-Id: I2a8c031618516102e2dccf071beef51fe9917f82 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/128347 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk>
Diffstat (limited to 'chart2')
-rw-r--r--chart2/source/view/charttypes/BarChart.cxx850
-rw-r--r--chart2/source/view/charttypes/BarChart.hxx47
-rw-r--r--chart2/source/view/charttypes/VSeriesPlotter.cxx2
-rw-r--r--chart2/source/view/inc/VSeriesPlotter.hxx2
4 files changed, 477 insertions, 424 deletions
diff --git a/chart2/source/view/charttypes/BarChart.cxx b/chart2/source/view/charttypes/BarChart.cxx
index 57dc851e2035..06e041e800df 100644
--- a/chart2/source/view/charttypes/BarChart.cxx
+++ b/chart2/source/view/charttypes/BarChart.cxx
@@ -385,30 +385,6 @@ void BarChart::addSeries( std::unique_ptr<VDataSeries> pSeries, sal_Int32 zSlot,
VSeriesPlotter::addSeries( std::move(pSeries), zSlot, xSlot, ySlot );
}
-namespace {
-
-//better performance for big data
-struct FormerBarPoint
-{
- FormerBarPoint( double fX, double fUpperY, double fLowerY, double fZ )
- : m_fX(fX), m_fUpperY(fUpperY), m_fLowerY(fLowerY), m_fZ(fZ)
- {}
- FormerBarPoint()
- : m_fX(std::numeric_limits<double>::quiet_NaN())
- , m_fUpperY(std::numeric_limits<double>::quiet_NaN())
- , m_fLowerY(std::numeric_limits<double>::quiet_NaN())
- , m_fZ(std::numeric_limits<double>::quiet_NaN())
- {
- }
-
- double m_fX;
- double m_fUpperY;
- double m_fLowerY;
- double m_fZ;
-};
-
-}
-
void BarChart::adaptOverlapAndGapwidthForGroupBarsPerAxis()
{
//adapt m_aOverlapSequence and m_aGapwidthSequence for the groupBarsPerAxis feature
@@ -465,11 +441,8 @@ void BarChart::createShapes()
ShapeFactory::createGroup2D( m_xFinalTarget );
//check necessary here that different Y axis can not be stacked in the same group? ... hm?
- double fLogicZ = 1.0;//as defined
-
bool bDrawConnectionLines = false;
bool bDrawConnectionLinesInited = false;
- bool bOnlyConnectionLinesForThisPoint = false;
std::unordered_set<rtl::Reference<SvxShape>> aShapeSet;
@@ -497,8 +470,6 @@ void BarChart::createShapes()
//better performance for big data
std::map< VDataSeries*, FormerBarPoint > aSeriesFormerPointMap;
m_bPointsWereSkipped = false;
- sal_Int32 nSkippedPoints = 0;
- sal_Int32 nCreatedPoints = 0;
sal_Int32 nStartIndex = 0;
sal_Int32 nEndIndex = VSeriesPlotter::getPointCount();
@@ -532,395 +503,9 @@ void BarChart::createShapes()
sal_Int32 nZ=1;
for( auto& rZSlot : m_aZSlots )
{
- //iterate through all x slots in this category
- double fSlotX=0;
- for( auto& rXSlot : rZSlot )
- {
- sal_Int32 nAttachedAxisIndex = rXSlot.getAttachedAxisIndexForFirstSeries();
- //2ND_AXIS_IN_BARS so far one can assume to have the same plotter for each z slot
- BarPositionHelper* pPosHelper = dynamic_cast<BarPositionHelper*>(&( getPlottingPositionHelper( nAttachedAxisIndex ) ) );
- if(!pPosHelper)
- pPosHelper = m_pMainPosHelper.get();
-
- PlotterBase::m_pPosHelper = pPosHelper;
-
- //update/create information for current group
- pPosHelper->updateSeriesCount( rZSlot.size() );
- double fLogicBaseWidth = pPosHelper->getScaledSlotWidth();
-
- // get distance from base value to maximum and minimum
-
- double fMinimumY = 0.0, fMaximumY = 0.0;
- if( nPointIndex < rXSlot.getPointCount())
- rXSlot.calculateYMinAndMaxForCategory( nPointIndex
- , isSeparateStackingForDifferentSigns( 1 ), fMinimumY, fMaximumY, nAttachedAxisIndex );
-
- double fLogicPositiveYSum = 0.0;
- if( !std::isnan( fMaximumY ) )
- fLogicPositiveYSum = fMaximumY;
-
- double fLogicNegativeYSum = 0.0;
- if( !std::isnan( fMinimumY ) )
- fLogicNegativeYSum = fMinimumY;
-
- if( pPosHelper->isPercentY() )
- {
- /* #i70395# fLogicPositiveYSum contains sum of all positive
- values, if any, otherwise the highest negative value.
- fLogicNegativeYSum contains sum of all negative values,
- if any, otherwise the lowest positive value.
- Afterwards, fLogicPositiveYSum will contain the maximum
- (positive) value that is related to 100%. */
-
- // do nothing if there are positive values only
- if( fLogicNegativeYSum < 0.0 )
- {
- // fLogicPositiveYSum<0 => negative values only, use absolute of negative sum
- if( fLogicPositiveYSum < 0.0 )
- fLogicPositiveYSum = -fLogicNegativeYSum;
- // otherwise there are positive and negative values, calculate total distance
- else
- fLogicPositiveYSum -= fLogicNegativeYSum;
- }
- fLogicNegativeYSum = 0.0;
- }
-
- double fBaseValue = 0.0;
- if( !pPosHelper->isPercentY() && rXSlot.m_aSeriesVector.size()<=1 )
- fBaseValue = pPosHelper->getBaseValueY();
- double fPositiveLogicYForNextSeries = fBaseValue;
- double fNegativeLogicYForNextSeries = fBaseValue;
-
- //iterate through all series in this x slot
- for( std::unique_ptr<VDataSeries> const & pSeries : rXSlot.m_aSeriesVector )
- {
- if(!pSeries)
- continue;
-
- bool bHasFillColorMapping = pSeries->hasPropertyMapping("FillColor");
-
- bOnlyConnectionLinesForThisPoint = false;
-
- if(nPointIndex==nStartIndex)//do not create a regression line for each point
- createRegressionCurvesShapes( *pSeries, xRegressionCurveTarget, xRegressionCurveEquationTarget,
- m_pPosHelper->maySkipPointsInRegressionCalculation());
-
- if( !bDrawConnectionLinesInited )
- {
- bDrawConnectionLines = pSeries->getConnectBars();
- if( m_nDimension==3 )
- bDrawConnectionLines = false;
- if( bDrawConnectionLines && rXSlot.m_aSeriesVector.size()==1 )
- {
- //detect whether we have a stacked chart or not:
- StackingDirection eDirection = pSeries->getStackingDirection();
- if( eDirection != StackingDirection_Y_STACKING )
- bDrawConnectionLines = false;
- }
- bDrawConnectionLinesInited = true;
- }
-
- // Use another XShapes for background, so we can avoid needing to set the Z-order on all of them,
- // which is expensive in bulk.
- rtl::Reference<SvxShapeGroupAnyD> xSeriesGroupShape_Shapes(getSeriesGroupShape(pSeries.get(), xSeriesTarget));
- rtl::Reference<SvxShapeGroupAnyD> xSeriesBackgroundShape_Shapes(getSeriesGroupShape(pSeries.get(), xSeriesTarget));
- aShapeSet.insert(xSeriesGroupShape_Shapes);
- aShapeSet.insert(xSeriesBackgroundShape_Shapes);
- // Suspend setting rects dirty for the duration of this call
- E3dScene* pScene = dynamic_cast<E3dScene*>(xSeriesGroupShape_Shapes->GetSdrObject());
- if (pScene)
- pScene->SuspendReportingDirtyRects();
- pScene = dynamic_cast<E3dScene*>(xSeriesBackgroundShape_Shapes->GetSdrObject());
- if (pScene)
- pScene->SuspendReportingDirtyRects();
-
- //collect data point information (logic coordinates, style ):
- double fUnscaledLogicX = pSeries->getXValue( nPointIndex );
- fUnscaledLogicX = DateHelper::RasterizeDateValue( fUnscaledLogicX, m_aNullDate, m_nTimeResolution );
- if(std::isnan(fUnscaledLogicX))
- continue;//point not visible
- if(fUnscaledLogicX<pPosHelper->getLogicMinX())
- continue;//point not visible
- if(fUnscaledLogicX>pPosHelper->getLogicMaxX())
- continue;//point not visible
- if(pPosHelper->isStrongLowerRequested(0) && fUnscaledLogicX==pPosHelper->getLogicMaxX())
- continue;//point not visible
- double fLogicX = pPosHelper->getScaledSlotPos( fUnscaledLogicX, fSlotX );
-
- double fLogicBarHeight = pSeries->getYValue( nPointIndex );
- if( std::isnan( fLogicBarHeight )) //no value at this category
- continue;
-
- double fLogicValueForLabeDisplay = fLogicBarHeight;
- fLogicBarHeight-=fBaseValue;
-
- if( pPosHelper->isPercentY() )
- {
- if(fLogicPositiveYSum!=0.0)
- fLogicBarHeight = fabs( fLogicBarHeight )/fLogicPositiveYSum;
- else
- fLogicBarHeight = 0.0;
- }
-
- // tdf#114141 to draw the top of the zero height 3D bar
- // we set a small positive value, here the smallest one for the type double (DBL_MIN)
- if( fLogicBarHeight == 0.0 )
- fLogicBarHeight = DBL_MIN;
-
- //sort negative and positive values, to display them on different sides of the x axis
- bool bPositive = fLogicBarHeight >= 0.0;
- double fLowerYValue = bPositive ? fPositiveLogicYForNextSeries : fNegativeLogicYForNextSeries;
- double fUpperYValue = fLowerYValue+fLogicBarHeight;
- if( bPositive )
- fPositiveLogicYForNextSeries += fLogicBarHeight;
- else
- fNegativeLogicYForNextSeries += fLogicBarHeight;
-
- if(m_nDimension==3)
- fLogicZ = nZ+0.5;
-
- drawing::Position3D aUnscaledLogicPosition( fUnscaledLogicX, fUpperYValue, fLogicZ );
-
- //@todo ... start an iteration over the different breaks of the axis
- //each subsystem may add an additional shape to form the whole point
- //create a group shape for this point and add to the series shape:
- // uno::Reference< drawing::XShapes > xPointGroupShape_Shapes( createGroupShape(xSeriesGroupShape_Shapes) );
- // uno::Reference<drawing::XShape> xPointGroupShape_Shape =
- // uno::Reference<drawing::XShape>( xPointGroupShape_Shapes, uno::UNO_QUERY );
- //as long as we do not iterate we do not need to create an additional group for each point
- uno::Reference< beans::XPropertySet > xDataPointProperties( pSeries->getPropertiesOfPoint( nPointIndex ) );
- sal_Int32 nGeometry3D = DataPointGeometry3D::CUBOID;
- if(m_nDimension==3) try
- {
- xDataPointProperties->getPropertyValue( "Geometry3D") >>= nGeometry3D;
- }
- catch( const uno::Exception& )
- {
- TOOLS_WARN_EXCEPTION("chart2", "" );
- }
-
- //@todo iterate through all subsystems to create partial points
- {
- //@todo select a suitable PositionHelper for this subsystem
- BarPositionHelper* pSubPosHelper = pPosHelper;
-
- double fUnclippedUpperYValue = fUpperYValue;
-
- //apply clipping to Y
- if( !pPosHelper->clipYRange(fLowerYValue,fUpperYValue) )
- {
- if( bDrawConnectionLines )
- bOnlyConnectionLinesForThisPoint = true;
- else
- continue;
- }
- //@todo clipping of X and Z is not fully integrated so far, as there is a need to create different objects
-
- //apply scaling to Y before calculating width (necessary to maintain gradient in clipped objects)
- pSubPosHelper->doLogicScaling(nullptr,&fLowerYValue,nullptr);
- pSubPosHelper->doLogicScaling(nullptr,&fUpperYValue,nullptr);
- //scaling of X and Z is not provided as the created objects should be symmetric in that dimensions
-
- pSubPosHelper->doLogicScaling(nullptr,&fUnclippedUpperYValue,nullptr);
-
- //calculate resulting width
- double fCompleteHeight = bPositive ? fLogicPositiveYSum : fLogicNegativeYSum;
- if( pPosHelper->isPercentY() )
- fCompleteHeight = 1.0;
- double fLogicBarWidth = fLogicBaseWidth;
- double fTopHeight=approxSub(fCompleteHeight,fUpperYValue);
- if(!bPositive)
- fTopHeight=approxSub(fCompleteHeight,fLowerYValue);
- double fLogicYStart = bPositive ? fLowerYValue : fUpperYValue;
- double fMiddleHeight = fUpperYValue-fLowerYValue;
- if(!bPositive)
- fMiddleHeight*=-1.0;
- double fLogicBarDepth = 0.5;
- if(m_nDimension==3)
- {
- if( lcl_hasGeometry3DVariableWidth(nGeometry3D) && fCompleteHeight!=0.0 )
- {
- double fHeight = fCompleteHeight-fLowerYValue;
- if(!bPositive)
- fHeight = fCompleteHeight-fUpperYValue;
- fLogicBarWidth = fLogicBaseWidth*fHeight/fCompleteHeight;
- if(fLogicBarWidth<=0.0)
- fLogicBarWidth=fLogicBaseWidth;
- fLogicBarDepth = fLogicBarDepth*fHeight/fCompleteHeight;
- if(fLogicBarDepth<=0.0)
- fLogicBarDepth*=-1.0;
- }
- }
-
- //better performance for big data
- FormerBarPoint aFormerPoint( aSeriesFormerPointMap[pSeries.get()] );
- pPosHelper->setCoordinateSystemResolution( m_aCoordinateSystemResolution );
- if( !pSeries->isAttributedDataPoint(nPointIndex)
- &&
- pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fUpperY, aFormerPoint.m_fZ
- , fLogicX, fUpperYValue, fLogicZ )
- &&
- pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fLowerY, aFormerPoint.m_fZ
- , fLogicX, fLowerYValue, fLogicZ )
- )
- {
- nSkippedPoints++;
- m_bPointsWereSkipped = true;
- continue;
- }
- aSeriesFormerPointMap[pSeries.get()] = FormerBarPoint(fLogicX,fUpperYValue,fLowerYValue,fLogicZ);
-
- if( bDrawConnectionLines )
- {
- //store point information for connection lines
-
- drawing::Position3D aLeftUpperPoint( fLogicX-fLogicBarWidth/2.0,fUnclippedUpperYValue,fLogicZ );
- drawing::Position3D aRightUpperPoint( fLogicX+fLogicBarWidth/2.0,fUnclippedUpperYValue,fLogicZ );
-
- if( isValidPosition(aLeftUpperPoint) )
- AddPointToPoly( pSeries->m_aPolyPolygonShape3D, aLeftUpperPoint );
- if( isValidPosition(aRightUpperPoint) )
- AddPointToPoly( pSeries->m_aPolyPolygonShape3D, aRightUpperPoint );
- }
-
- if( bOnlyConnectionLinesForThisPoint )
- continue;
-
- //maybe additional possibility for performance improvement
- //bool bCreateLineInsteadOfComplexGeometryDueToMissingSpace = false;
- //pPosHelper->isSameForGivenResolution( fLogicX-fLogicBarWidth/2.0, fLowerYValue, fLogicZ
- // , fLogicX+fLogicBarWidth/2.0, fLowerYValue, fLogicZ );
-
- nCreatedPoints++;
- //create partial point
- if( !approxEqual(fLowerYValue,fUpperYValue) )
- {
- if( m_nDimension==3 )
- {
- drawing::Position3D aLogicBottom (fLogicX,fLogicYStart,fLogicZ);
- drawing::Position3D aLogicLeftBottomFront (fLogicX+fLogicBarWidth/2.0,fLogicYStart,fLogicZ-fLogicBarDepth/2.0);
- drawing::Position3D aLogicRightDeepTop (fLogicX-fLogicBarWidth/2.0,fLogicYStart+fMiddleHeight,fLogicZ+fLogicBarDepth/2.0);
- drawing::Position3D aLogicTopTop (fLogicX,fLogicYStart+fMiddleHeight+fTopHeight,fLogicZ);
-
- ::chart::XTransformation2* pTransformation = pSubPosHelper->getTransformationScaledLogicToScene();
-
- //transformation 3) -> 4)
- drawing::Position3D aTransformedBottom ( pTransformation->transform( aLogicBottom ) );
- drawing::Position3D aTransformedLeftBottomFront ( pTransformation->transform( aLogicLeftBottomFront ) );
- drawing::Position3D aTransformedRightDeepTop ( pTransformation->transform( aLogicRightDeepTop ) );
- drawing::Position3D aTransformedTopTop ( pTransformation->transform( aLogicTopTop ) );
-
- drawing::Direction3D aSize = aTransformedRightDeepTop - aTransformedLeftBottomFront;
- drawing::Direction3D aTopSize( aTransformedTopTop - aTransformedRightDeepTop );
- fTopHeight = aTopSize.DirectionY;
-
- sal_Int32 nRotateZAngleHundredthDegree = 0;
- if( pPosHelper->isSwapXAndY() )
- {
- fTopHeight = aTopSize.DirectionX;
- nRotateZAngleHundredthDegree = 90*100;
- aSize = drawing::Direction3D(aSize.DirectionY,aSize.DirectionX,aSize.DirectionZ);
- }
-
- if( aSize.DirectionX < 0 )
- aSize.DirectionX *= -1.0;
- if( aSize.DirectionZ < 0 )
- aSize.DirectionZ *= -1.0;
- if( fTopHeight < 0 )
- fTopHeight *= -1.0;
-
- rtl::Reference< SvxShape > xShape = createDataPoint3D_Bar(
- xSeriesGroupShape_Shapes, aTransformedBottom, aSize, fTopHeight, nRotateZAngleHundredthDegree
- , xDataPointProperties, nGeometry3D );
-
- if(bHasFillColorMapping)
- {
- double nPropVal = pSeries->getValueByProperty(nPointIndex, "FillColor");
- if(!std::isnan(nPropVal))
- {
- xShape->setPropertyValue("FillColor", uno::Any(static_cast<sal_Int32>(nPropVal)));
- }
- }
- //set name/classified ObjectID (CID)
- ShapeFactory::setShapeName(xShape
- , ObjectIdentifier::createPointCID(
- pSeries->getPointCID_Stub(),nPointIndex) );
- }
- else //m_nDimension!=3
- {
- // performance improvement: alloc the sequence before the rendering
- // otherwise we have 2 realloc calls
- std::vector<std::vector<css::drawing::Position3D>> aPoly;
- aPoly.resize(1);
- drawing::Position3D aLeftUpperPoint( fLogicX-fLogicBarWidth/2.0,fUpperYValue,fLogicZ );
- drawing::Position3D aRightUpperPoint( fLogicX+fLogicBarWidth/2.0,fUpperYValue,fLogicZ );
-
- AddPointToPoly( aPoly, drawing::Position3D( fLogicX-fLogicBarWidth/2.0,fLowerYValue,fLogicZ) );
- AddPointToPoly( aPoly, drawing::Position3D( fLogicX+fLogicBarWidth/2.0,fLowerYValue,fLogicZ) );
- AddPointToPoly( aPoly, aRightUpperPoint );
- AddPointToPoly( aPoly, aLeftUpperPoint );
- AddPointToPoly( aPoly, drawing::Position3D( fLogicX-fLogicBarWidth/2.0,fLowerYValue,fLogicZ) );
- pPosHelper->transformScaledLogicToScene( aPoly );
- std::optional<sal_Int32> xFillColor;
- if(bHasFillColorMapping)
- {
- double nPropVal = pSeries->getValueByProperty(nPointIndex, "FillColor");
- if(!std::isnan(nPropVal))
- xFillColor = static_cast<sal_Int32>(nPropVal);
- }
- SdrPathObj* pShape = ShapeFactory::createArea2D( xSeriesGroupShape_Shapes, aPoly, /*bSetZOrderToZero*/false );
- PropertyMapper::setPropertyNameMapForFilledSeriesProperties(pShape, xDataPointProperties, xFillColor);
-
- //set name/classified ObjectID (CID)
- ShapeFactory::setShapeName(pShape
- , ObjectIdentifier::createPointCID(
- pSeries->getPointCID_Stub(),nPointIndex) );
- }
-
- }
-
- //create error bar
- createErrorBar_Y( aUnscaledLogicPosition, *pSeries, nPointIndex, m_xLogicTarget, &fLogicX );
-
- //create data point label
- if( pSeries->getDataPointLabelIfLabel(nPointIndex) )
- {
- double fLogicSum = aLogicYSumMap[nAttachedAxisIndex];
-
- LabelAlignment eAlignment(LABEL_ALIGN_CENTER);
- sal_Int32 nLabelPlacement = pSeries->getLabelPlacement( nPointIndex, m_xChartTypeModel, pPosHelper->isSwapXAndY() );
-
- double fLowerBarDepth = fLogicBarDepth;
- double fUpperBarDepth = fLogicBarDepth;
- {
- if( lcl_hasGeometry3DVariableWidth(nGeometry3D) && fCompleteHeight!=0.0 )
- {
- double fOuterBarDepth = fLogicBarDepth * fTopHeight/(fabs(fCompleteHeight));
- fLowerBarDepth = (fBaseValue < fUpperYValue) ? fabs(fLogicBarDepth) : fabs(fOuterBarDepth);
- fUpperBarDepth = (fBaseValue < fUpperYValue) ? fabs(fOuterBarDepth) : fabs(fLogicBarDepth);
- }
- }
-
- awt::Point aScreenPosition2D = getLabelScreenPositionAndAlignment(
- eAlignment, nLabelPlacement, fLogicX, fLowerYValue, fUpperYValue, fLogicZ,
- fLowerBarDepth, fUpperBarDepth, fBaseValue, pPosHelper);
- sal_Int32 nOffset = 0;
- if(eAlignment!=LABEL_ALIGN_CENTER)
- {
- nOffset = 100;//add some spacing //@todo maybe get more intelligent values
- if( m_nDimension == 3 )
- nOffset = 260;
- }
- createDataLabel(
- xTextTarget, *pSeries, nPointIndex,
- fLogicValueForLabeDisplay, fLogicSum, aScreenPosition2D, eAlignment, nOffset);
- }
-
- }//end iteration through partial points
-
- }//next series in x slot (next y slot)
- fSlotX+=1.0;
- }//next x slot
+ doZSlot(bDrawConnectionLines, bDrawConnectionLinesInited, rZSlot, nZ, nPointIndex, nStartIndex,
+ xSeriesTarget, xRegressionCurveTarget, xRegressionCurveEquationTarget, xTextTarget,
+ aShapeSet, aSeriesFormerPointMap, aLogicYSumMap);
++nZ;
}//next z slot
}//next category
@@ -973,11 +558,432 @@ void BarChart::createShapes()
/* @todo remove series shapes if empty
*/
+}
+
+void BarChart::doZSlot(
+ bool& bDrawConnectionLines, bool& bDrawConnectionLinesInited,
+ const std::vector< VDataSeriesGroup >& rZSlot,
+ const sal_Int32 nZ, const sal_Int32 nPointIndex, const sal_Int32 nStartIndex,
+ rtl::Reference<SvxShapeGroupAnyD>& xSeriesTarget,
+ rtl::Reference<SvxShapeGroupAnyD>& xRegressionCurveTarget,
+ rtl::Reference<SvxShapeGroupAnyD>& xRegressionCurveEquationTarget,
+ rtl::Reference<SvxShapeGroupAnyD>& xTextTarget,
+ std::unordered_set<rtl::Reference<SvxShape>>& aShapeSet,
+ std::map< VDataSeries*, FormerBarPoint >& aSeriesFormerPointMap,
+ std::map< sal_Int32, double >& aLogicYSumMap)
+{
+ //iterate through all x slots in this category
+ double fSlotX=0;
+ for( auto& rXSlot : rZSlot )
+ {
+ sal_Int32 nAttachedAxisIndex = rXSlot.getAttachedAxisIndexForFirstSeries();
+ //2ND_AXIS_IN_BARS so far one can assume to have the same plotter for each z slot
+ BarPositionHelper* pPosHelper = dynamic_cast<BarPositionHelper*>(&( getPlottingPositionHelper( nAttachedAxisIndex ) ) );
+ if(!pPosHelper)
+ pPosHelper = m_pMainPosHelper.get();
+
+ PlotterBase::m_pPosHelper = pPosHelper;
+
+ //update/create information for current group
+ pPosHelper->updateSeriesCount( rZSlot.size() );
+ double fLogicBaseWidth = pPosHelper->getScaledSlotWidth();
+
+ // get distance from base value to maximum and minimum
+
+ double fMinimumY = 0.0, fMaximumY = 0.0;
+ if( nPointIndex < rXSlot.getPointCount())
+ rXSlot.calculateYMinAndMaxForCategory( nPointIndex
+ , isSeparateStackingForDifferentSigns( 1 ), fMinimumY, fMaximumY, nAttachedAxisIndex );
+
+ double fLogicPositiveYSum = 0.0;
+ if( !std::isnan( fMaximumY ) )
+ fLogicPositiveYSum = fMaximumY;
+
+ double fLogicNegativeYSum = 0.0;
+ if( !std::isnan( fMinimumY ) )
+ fLogicNegativeYSum = fMinimumY;
+
+ if( pPosHelper->isPercentY() )
+ {
+ /* #i70395# fLogicPositiveYSum contains sum of all positive
+ values, if any, otherwise the highest negative value.
+ fLogicNegativeYSum contains sum of all negative values,
+ if any, otherwise the lowest positive value.
+ Afterwards, fLogicPositiveYSum will contain the maximum
+ (positive) value that is related to 100%. */
+
+ // do nothing if there are positive values only
+ if( fLogicNegativeYSum < 0.0 )
+ {
+ // fLogicPositiveYSum<0 => negative values only, use absolute of negative sum
+ if( fLogicPositiveYSum < 0.0 )
+ fLogicPositiveYSum = -fLogicNegativeYSum;
+ // otherwise there are positive and negative values, calculate total distance
+ else
+ fLogicPositiveYSum -= fLogicNegativeYSum;
+ }
+ fLogicNegativeYSum = 0.0;
+ }
+
+ doXSlot(rXSlot, bDrawConnectionLines, bDrawConnectionLinesInited, nZ, nPointIndex, nStartIndex,
+ xSeriesTarget, xRegressionCurveTarget, xRegressionCurveEquationTarget, xTextTarget,
+ aShapeSet, aSeriesFormerPointMap, aLogicYSumMap,
+ fLogicBaseWidth, fSlotX, pPosHelper, fLogicPositiveYSum, fLogicNegativeYSum, nAttachedAxisIndex);
+
+ fSlotX+=1.0;
+ }//next x slot
+}
+
+
+void BarChart::doXSlot(
+ const VDataSeriesGroup& rXSlot,
+ bool& bDrawConnectionLines, bool& bDrawConnectionLinesInited,
+ const sal_Int32 nZ, const sal_Int32 nPointIndex, const sal_Int32 nStartIndex,
+ rtl::Reference<SvxShapeGroupAnyD>& xSeriesTarget,
+ rtl::Reference<SvxShapeGroupAnyD>& xRegressionCurveTarget,
+ rtl::Reference<SvxShapeGroupAnyD>& xRegressionCurveEquationTarget,
+ rtl::Reference<SvxShapeGroupAnyD>& xTextTarget,
+ std::unordered_set<rtl::Reference<SvxShape>>& aShapeSet,
+ std::map< VDataSeries*, FormerBarPoint >& aSeriesFormerPointMap,
+ std::map< sal_Int32, double >& aLogicYSumMap,
+ const double fLogicBaseWidth, const double fSlotX,
+ BarPositionHelper* const pPosHelper,
+ const double fLogicPositiveYSum, const double fLogicNegativeYSum,
+ const sal_Int32 nAttachedAxisIndex)
+{
+ double fBaseValue = 0.0;
+ if( !pPosHelper->isPercentY() && rXSlot.m_aSeriesVector.size()<=1 )
+ fBaseValue = pPosHelper->getBaseValueY();
+ double fPositiveLogicYForNextSeries = fBaseValue;
+ double fNegativeLogicYForNextSeries = fBaseValue;
+
+ //iterate through all series in this x slot
+ for( std::unique_ptr<VDataSeries> const & pSeries : rXSlot.m_aSeriesVector )
+ {
+ if(!pSeries)
+ continue;
+
+ bool bHasFillColorMapping = pSeries->hasPropertyMapping("FillColor");
+
+ bool bOnlyConnectionLinesForThisPoint = false;
+
+ if(nPointIndex==nStartIndex)//do not create a regression line for each point
+ createRegressionCurvesShapes( *pSeries, xRegressionCurveTarget, xRegressionCurveEquationTarget,
+ m_pPosHelper->maySkipPointsInRegressionCalculation());
+
+ if( !bDrawConnectionLinesInited )
+ {
+ bDrawConnectionLines = pSeries->getConnectBars();
+ if( m_nDimension==3 )
+ bDrawConnectionLines = false;
+ if( bDrawConnectionLines && rXSlot.m_aSeriesVector.size()==1 )
+ {
+ //detect whether we have a stacked chart or not:
+ StackingDirection eDirection = pSeries->getStackingDirection();
+ if( eDirection != StackingDirection_Y_STACKING )
+ bDrawConnectionLines = false;
+ }
+ bDrawConnectionLinesInited = true;
+ }
+
+ // Use another XShapes for background, so we can avoid needing to set the Z-order on all of them,
+ // which is expensive in bulk.
+ rtl::Reference<SvxShapeGroupAnyD> xSeriesGroupShape_Shapes(getSeriesGroupShape(pSeries.get(), xSeriesTarget));
+ rtl::Reference<SvxShapeGroupAnyD> xSeriesBackgroundShape_Shapes(getSeriesGroupShape(pSeries.get(), xSeriesTarget));
+ aShapeSet.insert(xSeriesGroupShape_Shapes);
+ aShapeSet.insert(xSeriesBackgroundShape_Shapes);
+ // Suspend setting rects dirty for the duration of this call
+ E3dScene* pScene = dynamic_cast<E3dScene*>(xSeriesGroupShape_Shapes->GetSdrObject());
+ if (pScene)
+ pScene->SuspendReportingDirtyRects();
+ pScene = dynamic_cast<E3dScene*>(xSeriesBackgroundShape_Shapes->GetSdrObject());
+ if (pScene)
+ pScene->SuspendReportingDirtyRects();
+
+ //collect data point information (logic coordinates, style ):
+ double fUnscaledLogicX = pSeries->getXValue( nPointIndex );
+ fUnscaledLogicX = DateHelper::RasterizeDateValue( fUnscaledLogicX, m_aNullDate, m_nTimeResolution );
+ if(std::isnan(fUnscaledLogicX))
+ continue;//point not visible
+ if(fUnscaledLogicX<pPosHelper->getLogicMinX())
+ continue;//point not visible
+ if(fUnscaledLogicX>pPosHelper->getLogicMaxX())
+ continue;//point not visible
+ if(pPosHelper->isStrongLowerRequested(0) && fUnscaledLogicX==pPosHelper->getLogicMaxX())
+ continue;//point not visible
+ double fLogicX = pPosHelper->getScaledSlotPos( fUnscaledLogicX, fSlotX );
+
+ double fLogicBarHeight = pSeries->getYValue( nPointIndex );
+ if( std::isnan( fLogicBarHeight )) //no value at this category
+ continue;
+
+ double fLogicValueForLabeDisplay = fLogicBarHeight;
+ fLogicBarHeight-=fBaseValue;
+
+ if( pPosHelper->isPercentY() )
+ {
+ if(fLogicPositiveYSum!=0.0)
+ fLogicBarHeight = fabs( fLogicBarHeight )/fLogicPositiveYSum;
+ else
+ fLogicBarHeight = 0.0;
+ }
+
+ // tdf#114141 to draw the top of the zero height 3D bar
+ // we set a small positive value, here the smallest one for the type double (DBL_MIN)
+ if( fLogicBarHeight == 0.0 )
+ fLogicBarHeight = DBL_MIN;
+
+ //sort negative and positive values, to display them on different sides of the x axis
+ bool bPositive = fLogicBarHeight >= 0.0;
+ double fLowerYValue = bPositive ? fPositiveLogicYForNextSeries : fNegativeLogicYForNextSeries;
+ double fUpperYValue = fLowerYValue+fLogicBarHeight;
+ if( bPositive )
+ fPositiveLogicYForNextSeries += fLogicBarHeight;
+ else
+ fNegativeLogicYForNextSeries += fLogicBarHeight;
+
+ double fLogicZ = 1.0;//as defined
+ if(m_nDimension==3)
+ fLogicZ = nZ+0.5;
+
+ drawing::Position3D aUnscaledLogicPosition( fUnscaledLogicX, fUpperYValue, fLogicZ );
+
+ //@todo ... start an iteration over the different breaks of the axis
+ //each subsystem may add an additional shape to form the whole point
+ //create a group shape for this point and add to the series shape:
+// uno::Reference< drawing::XShapes > xPointGroupShape_Shapes( createGroupShape(xSeriesGroupShape_Shapes) );
+// uno::Reference<drawing::XShape> xPointGroupShape_Shape =
+// uno::Reference<drawing::XShape>( xPointGroupShape_Shapes, uno::UNO_QUERY );
+ //as long as we do not iterate we do not need to create an additional group for each point
+ uno::Reference< beans::XPropertySet > xDataPointProperties( pSeries->getPropertiesOfPoint( nPointIndex ) );
+ sal_Int32 nGeometry3D = DataPointGeometry3D::CUBOID;
+ if(m_nDimension==3) try
+ {
+ xDataPointProperties->getPropertyValue( "Geometry3D") >>= nGeometry3D;
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+
+ //@todo iterate through all subsystems to create partial points
+ {
+ //@todo select a suitable PositionHelper for this subsystem
+ BarPositionHelper* pSubPosHelper = pPosHelper;
+
+ double fUnclippedUpperYValue = fUpperYValue;
+
+ //apply clipping to Y
+ if( !pPosHelper->clipYRange(fLowerYValue,fUpperYValue) )
+ {
+ if( bDrawConnectionLines )
+ bOnlyConnectionLinesForThisPoint = true;
+ else
+ continue;
+ }
+ //@todo clipping of X and Z is not fully integrated so far, as there is a need to create different objects
+
+ //apply scaling to Y before calculating width (necessary to maintain gradient in clipped objects)
+ pSubPosHelper->doLogicScaling(nullptr,&fLowerYValue,nullptr);
+ pSubPosHelper->doLogicScaling(nullptr,&fUpperYValue,nullptr);
+ //scaling of X and Z is not provided as the created objects should be symmetric in that dimensions
+
+ pSubPosHelper->doLogicScaling(nullptr,&fUnclippedUpperYValue,nullptr);
+
+ //calculate resulting width
+ double fCompleteHeight = bPositive ? fLogicPositiveYSum : fLogicNegativeYSum;
+ if( pPosHelper->isPercentY() )
+ fCompleteHeight = 1.0;
+ double fLogicBarWidth = fLogicBaseWidth;
+ double fTopHeight=approxSub(fCompleteHeight,fUpperYValue);
+ if(!bPositive)
+ fTopHeight=approxSub(fCompleteHeight,fLowerYValue);
+ double fLogicYStart = bPositive ? fLowerYValue : fUpperYValue;
+ double fMiddleHeight = fUpperYValue-fLowerYValue;
+ if(!bPositive)
+ fMiddleHeight*=-1.0;
+ double fLogicBarDepth = 0.5;
+ if(m_nDimension==3)
+ {
+ if( lcl_hasGeometry3DVariableWidth(nGeometry3D) && fCompleteHeight!=0.0 )
+ {
+ double fHeight = fCompleteHeight-fLowerYValue;
+ if(!bPositive)
+ fHeight = fCompleteHeight-fUpperYValue;
+ fLogicBarWidth = fLogicBaseWidth*fHeight/fCompleteHeight;
+ if(fLogicBarWidth<=0.0)
+ fLogicBarWidth=fLogicBaseWidth;
+ fLogicBarDepth = fLogicBarDepth*fHeight/fCompleteHeight;
+ if(fLogicBarDepth<=0.0)
+ fLogicBarDepth*=-1.0;
+ }
+ }
+
+ //better performance for big data
+ FormerBarPoint aFormerPoint( aSeriesFormerPointMap[pSeries.get()] );
+ pPosHelper->setCoordinateSystemResolution( m_aCoordinateSystemResolution );
+ if( !pSeries->isAttributedDataPoint(nPointIndex)
+ &&
+ pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fUpperY, aFormerPoint.m_fZ
+ , fLogicX, fUpperYValue, fLogicZ )
+ &&
+ pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fLowerY, aFormerPoint.m_fZ
+ , fLogicX, fLowerYValue, fLogicZ )
+ )
+ {
+ m_bPointsWereSkipped = true;
+ continue;
+ }
+ aSeriesFormerPointMap[pSeries.get()] = FormerBarPoint(fLogicX,fUpperYValue,fLowerYValue,fLogicZ);
+
+ if( bDrawConnectionLines )
+ {
+ //store point information for connection lines
+
+ drawing::Position3D aLeftUpperPoint( fLogicX-fLogicBarWidth/2.0,fUnclippedUpperYValue,fLogicZ );
+ drawing::Position3D aRightUpperPoint( fLogicX+fLogicBarWidth/2.0,fUnclippedUpperYValue,fLogicZ );
+
+ if( isValidPosition(aLeftUpperPoint) )
+ AddPointToPoly( pSeries->m_aPolyPolygonShape3D, aLeftUpperPoint );
+ if( isValidPosition(aRightUpperPoint) )
+ AddPointToPoly( pSeries->m_aPolyPolygonShape3D, aRightUpperPoint );
+ }
+
+ if( bOnlyConnectionLinesForThisPoint )
+ continue;
+
+ //maybe additional possibility for performance improvement
+ //bool bCreateLineInsteadOfComplexGeometryDueToMissingSpace = false;
+ //pPosHelper->isSameForGivenResolution( fLogicX-fLogicBarWidth/2.0, fLowerYValue, fLogicZ
+ // , fLogicX+fLogicBarWidth/2.0, fLowerYValue, fLogicZ );
+
+ //create partial point
+ if( !approxEqual(fLowerYValue,fUpperYValue) )
+ {
+ if( m_nDimension==3 )
+ {
+ drawing::Position3D aLogicBottom (fLogicX,fLogicYStart,fLogicZ);
+ drawing::Position3D aLogicLeftBottomFront (fLogicX+fLogicBarWidth/2.0,fLogicYStart,fLogicZ-fLogicBarDepth/2.0);
+ drawing::Position3D aLogicRightDeepTop (fLogicX-fLogicBarWidth/2.0,fLogicYStart+fMiddleHeight,fLogicZ+fLogicBarDepth/2.0);
+ drawing::Position3D aLogicTopTop (fLogicX,fLogicYStart+fMiddleHeight+fTopHeight,fLogicZ);
+
+ ::chart::XTransformation2* pTransformation = pSubPosHelper->getTransformationScaledLogicToScene();
+
+ //transformation 3) -> 4)
+ drawing::Position3D aTransformedBottom ( pTransformation->transform( aLogicBottom ) );
+ drawing::Position3D aTransformedLeftBottomFront ( pTransformation->transform( aLogicLeftBottomFront ) );
+ drawing::Position3D aTransformedRightDeepTop ( pTransformation->transform( aLogicRightDeepTop ) );
+ drawing::Position3D aTransformedTopTop ( pTransformation->transform( aLogicTopTop ) );
+
+ drawing::Direction3D aSize = aTransformedRightDeepTop - aTransformedLeftBottomFront;
+ drawing::Direction3D aTopSize( aTransformedTopTop - aTransformedRightDeepTop );
+ fTopHeight = aTopSize.DirectionY;
+
+ sal_Int32 nRotateZAngleHundredthDegree = 0;
+ if( pPosHelper->isSwapXAndY() )
+ {
+ fTopHeight = aTopSize.DirectionX;
+ nRotateZAngleHundredthDegree = 90*100;
+ aSize = drawing::Direction3D(aSize.DirectionY,aSize.DirectionX,aSize.DirectionZ);
+ }
+
+ if( aSize.DirectionX < 0 )
+ aSize.DirectionX *= -1.0;
+ if( aSize.DirectionZ < 0 )
+ aSize.DirectionZ *= -1.0;
+ if( fTopHeight < 0 )
+ fTopHeight *= -1.0;
+
+ rtl::Reference< SvxShape > xShape = createDataPoint3D_Bar(
+ xSeriesGroupShape_Shapes, aTransformedBottom, aSize, fTopHeight, nRotateZAngleHundredthDegree
+ , xDataPointProperties, nGeometry3D );
+
+ if(bHasFillColorMapping)
+ {
+ double nPropVal = pSeries->getValueByProperty(nPointIndex, "FillColor");
+ if(!std::isnan(nPropVal))
+ {
+ xShape->setPropertyValue("FillColor", uno::Any(static_cast<sal_Int32>(nPropVal)));
+ }
+ }
+ //set name/classified ObjectID (CID)
+ ShapeFactory::setShapeName(xShape
+ , ObjectIdentifier::createPointCID(
+ pSeries->getPointCID_Stub(),nPointIndex) );
+ }
+ else //m_nDimension!=3
+ {
+ // performance improvement: alloc the sequence before the rendering
+ // otherwise we have 2 realloc calls
+ std::vector<std::vector<css::drawing::Position3D>> aPoly;
+ aPoly.resize(1);
+ drawing::Position3D aLeftUpperPoint( fLogicX-fLogicBarWidth/2.0,fUpperYValue,fLogicZ );
+ drawing::Position3D aRightUpperPoint( fLogicX+fLogicBarWidth/2.0,fUpperYValue,fLogicZ );
+
+ AddPointToPoly( aPoly, drawing::Position3D( fLogicX-fLogicBarWidth/2.0,fLowerYValue,fLogicZ) );
+ AddPointToPoly( aPoly, drawing::Position3D( fLogicX+fLogicBarWidth/2.0,fLowerYValue,fLogicZ) );
+ AddPointToPoly( aPoly, aRightUpperPoint );
+ AddPointToPoly( aPoly, aLeftUpperPoint );
+ AddPointToPoly( aPoly, drawing::Position3D( fLogicX-fLogicBarWidth/2.0,fLowerYValue,fLogicZ) );
+ pPosHelper->transformScaledLogicToScene( aPoly );
+ std::optional<sal_Int32> xFillColor;
+ if(bHasFillColorMapping)
+ {
+ double nPropVal = pSeries->getValueByProperty(nPointIndex, "FillColor");
+ if(!std::isnan(nPropVal))
+ xFillColor = static_cast<sal_Int32>(nPropVal);
+ }
+ SdrPathObj* pShape = ShapeFactory::createArea2D( xSeriesGroupShape_Shapes, aPoly, /*bSetZOrderToZero*/false );
+ PropertyMapper::setPropertyNameMapForFilledSeriesProperties(pShape, xDataPointProperties, xFillColor);
+
+ //set name/classified ObjectID (CID)
+ ShapeFactory::setShapeName(pShape
+ , ObjectIdentifier::createPointCID(
+ pSeries->getPointCID_Stub(),nPointIndex) );
+ }
+
+ }
+
+ //create error bar
+ createErrorBar_Y( aUnscaledLogicPosition, *pSeries, nPointIndex, m_xLogicTarget, &fLogicX );
+
+ //create data point label
+ if( pSeries->getDataPointLabelIfLabel(nPointIndex) )
+ {
+ double fLogicSum = aLogicYSumMap[nAttachedAxisIndex];
+
+ LabelAlignment eAlignment(LABEL_ALIGN_CENTER);
+ sal_Int32 nLabelPlacement = pSeries->getLabelPlacement( nPointIndex, m_xChartTypeModel, pPosHelper->isSwapXAndY() );
+
+ double fLowerBarDepth = fLogicBarDepth;
+ double fUpperBarDepth = fLogicBarDepth;
+ {
+ if( lcl_hasGeometry3DVariableWidth(nGeometry3D) && fCompleteHeight!=0.0 )
+ {
+ double fOuterBarDepth = fLogicBarDepth * fTopHeight/(fabs(fCompleteHeight));
+ fLowerBarDepth = (fBaseValue < fUpperYValue) ? fabs(fLogicBarDepth) : fabs(fOuterBarDepth);
+ fUpperBarDepth = (fBaseValue < fUpperYValue) ? fabs(fOuterBarDepth) : fabs(fLogicBarDepth);
+ }
+ }
+
+ awt::Point aScreenPosition2D = getLabelScreenPositionAndAlignment(
+ eAlignment, nLabelPlacement, fLogicX, fLowerYValue, fUpperYValue, fLogicZ,
+ fLowerBarDepth, fUpperBarDepth, fBaseValue, pPosHelper);
+ sal_Int32 nOffset = 0;
+ if(eAlignment!=LABEL_ALIGN_CENTER)
+ {
+ nOffset = 100;//add some spacing //@todo maybe get more intelligent values
+ if( m_nDimension == 3 )
+ nOffset = 260;
+ }
+ createDataLabel(
+ xTextTarget, *pSeries, nPointIndex,
+ fLogicValueForLabeDisplay, fLogicSum, aScreenPosition2D, eAlignment, nOffset);
+ }
+
+ }//end iteration through partial points
- SAL_INFO(
- "chart2",
- "skipped points: " << nSkippedPoints << " created points: "
- << nCreatedPoints);
+ }//next series in x slot (next y slot)
}
} //namespace chart
diff --git a/chart2/source/view/charttypes/BarChart.hxx b/chart2/source/view/charttypes/BarChart.hxx
index 08eaeadab2e6..5e9ab5e49f48 100644
--- a/chart2/source/view/charttypes/BarChart.hxx
+++ b/chart2/source/view/charttypes/BarChart.hxx
@@ -61,6 +61,53 @@ private: //methods
void adaptOverlapAndGapwidthForGroupBarsPerAxis();
+ //better performance for big data
+ struct FormerBarPoint
+ {
+ FormerBarPoint( double fX, double fUpperY, double fLowerY, double fZ )
+ : m_fX(fX), m_fUpperY(fUpperY), m_fLowerY(fLowerY), m_fZ(fZ)
+ {}
+ FormerBarPoint()
+ : m_fX(std::numeric_limits<double>::quiet_NaN())
+ , m_fUpperY(std::numeric_limits<double>::quiet_NaN())
+ , m_fLowerY(std::numeric_limits<double>::quiet_NaN())
+ , m_fZ(std::numeric_limits<double>::quiet_NaN())
+ {
+ }
+
+ double m_fX;
+ double m_fUpperY;
+ double m_fLowerY;
+ double m_fZ;
+ };
+
+ void doZSlot(
+ bool& bDrawConnectionLines, bool& bDrawConnectionLinesInited, const std::vector< VDataSeriesGroup >& rZSlot,
+ sal_Int32 nZ, sal_Int32 nPointIndex, sal_Int32 nStartIndex,
+ rtl::Reference<SvxShapeGroupAnyD>& xSeriesTarget,
+ rtl::Reference<SvxShapeGroupAnyD>& xRegressionCurveTarget,
+ rtl::Reference<SvxShapeGroupAnyD>& xRegressionCurveEquationTarget,
+ rtl::Reference<SvxShapeGroupAnyD>& xTextTarget,
+ std::unordered_set<rtl::Reference<SvxShape>>& aShapeSet,
+ std::map< VDataSeries*, FormerBarPoint >& aSeriesFormerPointMap,
+ std::map< sal_Int32, double >& aLogicYSumMap);
+
+ void doXSlot(
+ const VDataSeriesGroup& rXSlot,
+ bool& bDrawConnectionLines, bool& bDrawConnectionLinesInited,
+ sal_Int32 nZ, sal_Int32 nPointIndex, sal_Int32 nStartIndex,
+ rtl::Reference<SvxShapeGroupAnyD>& xSeriesTarget,
+ rtl::Reference<SvxShapeGroupAnyD>& xRegressionCurveTarget,
+ rtl::Reference<SvxShapeGroupAnyD>& xRegressionCurveEquationTarget,
+ rtl::Reference<SvxShapeGroupAnyD>& xTextTarget,
+ std::unordered_set<rtl::Reference<SvxShape>>& aShapeSet,
+ std::map< VDataSeries*, FormerBarPoint >& aSeriesFormerPointMap,
+ std::map< sal_Int32, double >& aLogicYSumMap,
+ double fLogicBaseWidth, double fSlotX,
+ BarPositionHelper* const pPosHelper,
+ double fLogicPositiveYSum, double fLogicNegativeYSum,
+ sal_Int32 nAttachedAxisIndex);
+
private: //member
std::unique_ptr<BarPositionHelper> m_pMainPosHelper;
css::uno::Sequence< sal_Int32 > m_aOverlapSequence;
diff --git a/chart2/source/view/charttypes/VSeriesPlotter.cxx b/chart2/source/view/charttypes/VSeriesPlotter.cxx
index d2ee85a6a100..3cff976ac66f 100644
--- a/chart2/source/view/charttypes/VSeriesPlotter.cxx
+++ b/chart2/source/view/charttypes/VSeriesPlotter.cxx
@@ -2092,7 +2092,7 @@ void VDataSeriesGroup::getMinimumAndMaximumYInContinuousXRange(
void VDataSeriesGroup::calculateYMinAndMaxForCategory( sal_Int32 nCategoryIndex
, bool bSeparateStackingForDifferentSigns
- , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex )
+ , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex ) const
{
assert(nCategoryIndex >= 0);
assert(nCategoryIndex < getPointCount());
diff --git a/chart2/source/view/inc/VSeriesPlotter.hxx b/chart2/source/view/inc/VSeriesPlotter.hxx
index cc92aa969dda..83d97bc8b671 100644
--- a/chart2/source/view/inc/VSeriesPlotter.hxx
+++ b/chart2/source/view/inc/VSeriesPlotter.hxx
@@ -90,7 +90,7 @@ public:
void calculateYMinAndMaxForCategory( sal_Int32 nCategoryIndex
, bool bSeparateStackingForDifferentSigns
- , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex );
+ , double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex ) const;
void calculateYMinAndMaxForCategoryRange( sal_Int32 nStartCategoryIndex, sal_Int32 nEndCategoryIndex
, bool bSeparateStackingForDifferentSigns
, double& rfMinimumY, double& rfMaximumY, sal_Int32 nAxisIndex );