summaryrefslogtreecommitdiffstats
path: root/chart2/source/view/charttypes
diff options
context:
space:
mode:
Diffstat (limited to 'chart2/source/view/charttypes')
-rw-r--r--chart2/source/view/charttypes/AreaChart.cxx67
-rw-r--r--chart2/source/view/charttypes/AreaChart.hxx6
-rw-r--r--chart2/source/view/charttypes/BarChart.cxx115
-rw-r--r--chart2/source/view/charttypes/BarChart.hxx22
-rw-r--r--chart2/source/view/charttypes/BarPositionHelper.cxx1
-rw-r--r--chart2/source/view/charttypes/BubbleChart.cxx7
-rw-r--r--chart2/source/view/charttypes/BubbleChart.hxx2
-rw-r--r--chart2/source/view/charttypes/CandleStickChart.cxx37
-rw-r--r--chart2/source/view/charttypes/CandleStickChart.hxx6
-rw-r--r--chart2/source/view/charttypes/ConfigAccess.cxx74
-rw-r--r--chart2/source/view/charttypes/NetChart.cxx26
-rw-r--r--chart2/source/view/charttypes/NetChart.hxx6
-rw-r--r--chart2/source/view/charttypes/PieChart.cxx1061
-rw-r--r--chart2/source/view/charttypes/PieChart.hxx150
-rw-r--r--chart2/source/view/charttypes/Splines.cxx89
-rw-r--r--chart2/source/view/charttypes/VSeriesPlotter.cxx383
16 files changed, 1377 insertions, 675 deletions
diff --git a/chart2/source/view/charttypes/AreaChart.cxx b/chart2/source/view/charttypes/AreaChart.cxx
index e5409ce5dff1..3bab48585148 100644
--- a/chart2/source/view/charttypes/AreaChart.cxx
+++ b/chart2/source/view/charttypes/AreaChart.cxx
@@ -24,25 +24,25 @@
#include <ExplicitCategoriesProvider.hxx>
#include <ObjectIdentifier.hxx>
#include "Splines.hxx"
+#include <ChartType.hxx>
#include <ChartTypeHelper.hxx>
#include <LabelPositionHelper.hxx>
#include <Clipping.hxx>
#include <Stripe.hxx>
#include <DateHelper.hxx>
#include <unonames.hxx>
-#include <ConfigAccess.hxx>
#include <com/sun/star/chart2/Symbol.hpp>
#include <com/sun/star/chart/DataLabelPlacement.hpp>
#include <com/sun/star/chart/MissingValueTreatment.hpp>
#include <sal/log.hxx>
+#include <o3tl/safeint.hxx>
#include <osl/diagnose.h>
-#include <com/sun/star/drawing/DoubleSequence.hpp>
-#include <com/sun/star/drawing/XShapes.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <officecfg/Office/Compatibility.hxx>
+#include <officecfg/Office/Chart.hxx>
#include <limits>
@@ -51,13 +51,12 @@ namespace chart
using namespace ::com::sun::star;
using namespace ::com::sun::star::chart2;
-AreaChart::AreaChart( const uno::Reference<XChartType>& xChartTypeModel
+AreaChart::AreaChart( const rtl::Reference<ChartType>& xChartTypeModel
, sal_Int32 nDimensionCount
, bool bCategoryXAxis
, bool bNoArea
)
: VSeriesPlotter( xChartTypeModel, nDimensionCount, bCategoryXAxis )
- , m_pMainPosHelper(new PlottingPositionHelper())
, m_bArea(!bNoArea)
, m_bLine(bNoArea)
, m_bSymbol( ChartTypeHelper::isSupportingSymbolProperties(xChartTypeModel,nDimensionCount) )
@@ -65,19 +64,19 @@ AreaChart::AreaChart( const uno::Reference<XChartType>& xChartTypeModel
, m_nCurveResolution(20)
, m_nSplineOrder(3)
{
+ PlotterBase::m_pPosHelper = &m_aMainPosHelper;
+ VSeriesPlotter::m_pMainPosHelper = &m_aMainPosHelper;
+
m_pMainPosHelper->AllowShiftXAxisPos(true);
m_pMainPosHelper->AllowShiftZAxisPos(true);
- PlotterBase::m_pPosHelper = m_pMainPosHelper.get();
- VSeriesPlotter::m_pMainPosHelper = m_pMainPosHelper.get();
-
try
{
- if( m_xChartTypeModelProps.is() )
+ if( m_xChartTypeModel.is() )
{
- m_xChartTypeModelProps->getPropertyValue(CHART_UNONAME_CURVE_STYLE) >>= m_eCurveStyle;
- m_xChartTypeModelProps->getPropertyValue(CHART_UNONAME_CURVE_RESOLUTION) >>= m_nCurveResolution;
- m_xChartTypeModelProps->getPropertyValue(CHART_UNONAME_SPLINE_ORDER) >>= m_nSplineOrder;
+ m_xChartTypeModel->getPropertyValue(CHART_UNONAME_CURVE_STYLE) >>= m_eCurveStyle;
+ m_xChartTypeModel->getPropertyValue(CHART_UNONAME_CURVE_RESOLUTION) >>= m_nCurveResolution;
+ m_xChartTypeModel->getPropertyValue(CHART_UNONAME_SPLINE_ORDER) >>= m_nSplineOrder;
}
}
catch( uno::Exception& e )
@@ -456,26 +455,22 @@ bool AreaChart::impl_createArea( VDataSeries* pSeries
pPosHelper->transformScaledLogicToScene( aPoly );
//create area:
+ rtl::Reference< SvxShape > xShape;
if(m_nDimension==3)
{
- rtl::Reference< SvxShape > xShape = ShapeFactory::createArea3D( xSeriesGroupShape_Shapes
+ xShape = ShapeFactory::createArea3D( xSeriesGroupShape_Shapes
, aPoly, getTransformedDepth() );
- PropertyMapper::setMappedProperties( *xShape
- , pSeries->getPropertiesOfSeries()
- , PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
- //because of this name this line will be used for marking
- ShapeFactory::setShapeName(xShape, "MarkHandles");
}
else //m_nDimension!=3
{
- SdrPathObj* pShape = ShapeFactory::createArea2D( xSeriesGroupShape_Shapes
+ xShape = ShapeFactory::createArea2D( xSeriesGroupShape_Shapes
, aPoly );
- PropertyMapper::setPropertyNameMapForFilledSeriesProperties(
- pShape
- , pSeries->getPropertiesOfSeries());
- //because of this name this line will be used for marking
- ShapeFactory::setShapeName(pShape, "MarkHandles");
}
+ PropertyMapper::setMappedProperties( *xShape
+ , pSeries->getPropertiesOfSeries()
+ , PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
+ //because of this name this line will be used for marking
+ ::chart::ShapeFactory::setShapeName(xShape, "MarkHandles");
return true;
}
@@ -639,6 +634,8 @@ void AreaChart::createShapes()
}
}
+ const bool bUseErrorRectangle = officecfg::Office::Chart::ErrorProperties::ErrorRectangle::get();
+
sal_Int32 nZ=1;
for( auto const& rZSlot : m_aZSlots )
{
@@ -703,7 +700,7 @@ void AreaChart::createShapes()
{
std::vector<std::vector<css::drawing::Position3D>>& rPolygon = pSeries->m_aPolyPolygonShape3D;
sal_Int32& rIndex = pSeries->m_nPolygonIndex;
- if( 0<= rIndex && rIndex < static_cast<sal_Int32>(rPolygon.size()) )
+ if( 0<= rIndex && o3tl::make_unsigned(rIndex) < rPolygon.size() )
{
if( !rPolygon[ rIndex ].empty() )
rIndex++; //start a new polygon for the next point if the current poly is not empty
@@ -797,13 +794,6 @@ void AreaChart::createShapes()
!bCreateXErrorBar && !pSeries->getDataPointLabelIfLabel(nIndex) )
continue;
- //create a group shape for this point and add to the series shape:
- OUString aPointCID = ObjectIdentifier::createPointCID(
- pSeries->getPointCID_Stub(), nIndex );
- rtl::Reference<SvxShapeGroupAnyD> xPointGroupShape_Shapes(
- createGroupShape(xSeriesGroupShape_Shapes,aPointCID) );
- uno::Reference<drawing::XShape> xPointGroupShape_Shape( static_cast<cppu::OWeakObject*>(xPointGroupShape_Shapes.get()), uno::UNO_QUERY );
-
{
nCreatedPoints++;
@@ -813,6 +803,13 @@ void AreaChart::createShapes()
{
if(m_nDimension!=3)
{
+ //create a group shape for this point and add to the series shape:
+ OUString aPointCID = ObjectIdentifier::createPointCID(
+ pSeries->getPointCID_Stub(), nIndex );
+ rtl::Reference<SvxShapeGroupAnyD> xPointGroupShape_Shapes;
+ if (pSymbolProperties->Style == SymbolStyle_STANDARD || pSymbolProperties->Style == SymbolStyle_GRAPHIC)
+ xPointGroupShape_Shapes = createGroupShape(xSeriesGroupShape_Shapes,aPointCID);
+
if (pSymbolProperties->Style != SymbolStyle_NONE)
{
aSymbolSize.DirectionX = pSymbolProperties->Size.Width;
@@ -837,7 +834,7 @@ void AreaChart::createShapes()
}
}
//create error bars or rectangles, depending on configuration
- if ( ConfigAccess::getUseErrorRectangle() )
+ if ( bUseErrorRectangle )
{
if ( bCreateXErrorBar || bCreateYErrorBar )
{
@@ -921,10 +918,6 @@ void AreaChart::createShapes()
, rLogicYSumMap[nAttachedAxisIndex], aScreenPosition2D, eAlignment, nOffset );
}
}
-
- //remove PointGroupShape if empty
- if(!xPointGroupShape_Shapes->getCount())
- xSeriesGroupShape_Shapes->remove(xPointGroupShape_Shape);
}
}//next series in x slot (next y slot)
diff --git a/chart2/source/view/charttypes/AreaChart.hxx b/chart2/source/view/charttypes/AreaChart.hxx
index 23d8adb0b4f1..411b9d6642aa 100644
--- a/chart2/source/view/charttypes/AreaChart.hxx
+++ b/chart2/source/view/charttypes/AreaChart.hxx
@@ -21,6 +21,7 @@
#include <memory>
#include <VSeriesPlotter.hxx>
+#include <PlottingPositionHelper.hxx>
#include <com/sun/star/chart2/CurveStyle.hpp>
namespace chart
@@ -32,7 +33,7 @@ class AreaChart : public VSeriesPlotter
public:
AreaChart() = delete;
- AreaChart( const css::uno::Reference< css::chart2::XChartType >& xChartTypeModel
+ AreaChart( const rtl::Reference< ::chart::ChartType >& xChartTypeModel
, sal_Int32 nDimensionCount
, bool bCategoryXAxis, bool bNoArea=false
);
@@ -64,8 +65,7 @@ private: //methods
, std::vector<std::vector<css::drawing::Position3D>> &aPoly );
private: //member
- std::unique_ptr<PlottingPositionHelper>
- m_pMainPosHelper;
+ PlottingPositionHelper m_aMainPosHelper;
bool m_bArea;//false -> line or symbol only
bool m_bLine;
diff --git a/chart2/source/view/charttypes/BarChart.cxx b/chart2/source/view/charttypes/BarChart.cxx
index 938355192e35..fcc969b898ad 100644
--- a/chart2/source/view/charttypes/BarChart.cxx
+++ b/chart2/source/view/charttypes/BarChart.cxx
@@ -20,6 +20,7 @@
#include "BarChart.hxx"
#include "BarPositionHelper.hxx"
+#include <ChartType.hxx>
#include <ShapeFactory.hxx>
#include <CommonConverters.hxx>
#include <ObjectIdentifier.hxx>
@@ -34,9 +35,7 @@
#include <com/sun/star/chart2/DataPointGeometry3D.hpp>
#include <rtl/math.hxx>
-#include <sal/log.hxx>
-#include <tools/diagnose_ex.h>
-#include <unordered_set>
+#include <comphelper/diagnose_ex.hxx>
namespace chart
{
@@ -44,20 +43,19 @@ using namespace ::com::sun::star;
using namespace ::rtl::math;
using namespace ::com::sun::star::chart2;
-BarChart::BarChart( const uno::Reference<XChartType>& xChartTypeModel
+BarChart::BarChart( const rtl::Reference<ChartType>& xChartTypeModel
, sal_Int32 nDimensionCount )
: VSeriesPlotter( xChartTypeModel, nDimensionCount )
- , m_pMainPosHelper( new BarPositionHelper() )
{
- PlotterBase::m_pPosHelper = m_pMainPosHelper.get();
- VSeriesPlotter::m_pMainPosHelper = m_pMainPosHelper.get();
+ PlotterBase::m_pPosHelper = &m_aMainPosHelper;
+ VSeriesPlotter::m_pMainPosHelper = &m_aMainPosHelper;
try
{
- if( m_xChartTypeModelProps.is() )
+ if( m_xChartTypeModel.is() )
{
- m_xChartTypeModelProps->getPropertyValue( "OverlapSequence" ) >>= m_aOverlapSequence;
- m_xChartTypeModelProps->getPropertyValue( "GapwidthSequence" ) >>= m_aGapwidthSequence;
+ m_xChartTypeModel->getPropertyValue( "OverlapSequence" ) >>= m_aOverlapSequence;
+ m_xChartTypeModel->getPropertyValue( "GapwidthSequence" ) >>= m_aGapwidthSequence;
}
}
catch( const uno::Exception& )
@@ -124,9 +122,7 @@ drawing::Direction3D BarChart::getPreferredDiagramAspectRatio() const
}
if( m_pMainPosHelper && m_pMainPosHelper->isSwapXAndY() )
{
- double fTemp = aRet.DirectionX;
- aRet.DirectionX = aRet.DirectionY;
- aRet.DirectionY = fTemp;
+ std::swap(aRet.DirectionX, aRet.DirectionY);
}
}
else
@@ -450,8 +446,7 @@ void BarChart::createShapes()
for (rtl::Reference<SvxShape> const & rShape : aShapeSet)
{
- E3dScene* pScene = dynamic_cast<E3dScene*>(rShape->GetSdrObject());
- if(nullptr != pScene)
+ if(E3dScene* pScene = DynCastE3dScene(rShape->GetSdrObject()))
{
aSceneSet.insert(pScene->getRootE3dSceneFromE3dObject());
}
@@ -511,14 +506,14 @@ void BarChart::createShapes()
{
for( auto const& rZSlot : m_aZSlots )
{
- BarPositionHelper* pPosHelper = m_pMainPosHelper.get();
+ BarPositionHelper* pPosHelper = &m_aMainPosHelper;
if( !rZSlot.empty() )
{
sal_Int32 nAttachedAxisIndex = rZSlot.front().getAttachedAxisIndexForFirstSeries();
//2ND_AXIS_IN_BARS so far one can assume to have the same plotter for each z slot
pPosHelper = dynamic_cast<BarPositionHelper*>(&( getPlottingPositionHelper( nAttachedAxisIndex ) ) );
if(!pPosHelper)
- pPosHelper = m_pMainPosHelper.get();
+ pPosHelper = &m_aMainPosHelper;
}
PlotterBase::m_pPosHelper = pPosHelper;
@@ -547,8 +542,6 @@ void BarChart::createShapes()
getSeriesGroupShape(pSeries.get(), xSeriesTarget) );
rtl::Reference<SvxShapePolyPolygon> xShape( ShapeFactory::createLine2D(
xSeriesGroupShape_Shapes, aPoly ) );
- PropertyMapper::setMappedProperties( *xShape, pSeries->getPropertiesOfSeries()
- , PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
}
}
}
@@ -562,10 +555,10 @@ 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,
+ const rtl::Reference<SvxShapeGroupAnyD>& xSeriesTarget,
+ const rtl::Reference<SvxShapeGroupAnyD>& xRegressionCurveTarget,
+ const rtl::Reference<SvxShapeGroupAnyD>& xRegressionCurveEquationTarget,
+ const rtl::Reference<SvxShapeGroupAnyD>& xTextTarget,
std::unordered_set<rtl::Reference<SvxShape>>& aShapeSet,
std::map< VDataSeries*, FormerBarPoint >& aSeriesFormerPointMap,
std::map< sal_Int32, double >& aLogicYSumMap)
@@ -578,7 +571,7 @@ void BarChart::doZSlot(
//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();
+ pPosHelper = &m_aMainPosHelper;
PlotterBase::m_pPosHelper = pPosHelper;
@@ -637,10 +630,10 @@ 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,
+ const rtl::Reference<SvxShapeGroupAnyD>& xSeriesTarget,
+ const rtl::Reference<SvxShapeGroupAnyD>& xRegressionCurveTarget,
+ const rtl::Reference<SvxShapeGroupAnyD>& xRegressionCurveEquationTarget,
+ const rtl::Reference<SvxShapeGroupAnyD>& xTextTarget,
std::unordered_set<rtl::Reference<SvxShape>>& aShapeSet,
std::map< VDataSeries*, FormerBarPoint >& aSeriesFormerPointMap,
std::map< sal_Int32, double >& aLogicYSumMap,
@@ -691,10 +684,10 @@ void BarChart::doXSlot(
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());
+ E3dScene* pScene = DynCastE3dScene(xSeriesGroupShape_Shapes->GetSdrObject());
if (pScene)
pScene->SuspendReportingDirtyRects();
- pScene = dynamic_cast<E3dScene*>(xSeriesBackgroundShape_Shapes->GetSdrObject());
+ pScene = DynCastE3dScene(xSeriesBackgroundShape_Shapes->GetSdrObject());
if (pScene)
pScene->SuspendReportingDirtyRects();
@@ -858,6 +851,7 @@ void BarChart::doXSlot(
//create partial point
if( !approxEqual(fLowerYValue,fUpperYValue) )
{
+ rtl::Reference< SvxShape > xShape;
if( m_nDimension==3 )
{
drawing::Position3D aLogicBottom (fLogicX,fLogicYStart,fLogicZ);
@@ -892,54 +886,41 @@ void BarChart::doXSlot(
if( fTopHeight < 0 )
fTopHeight *= -1.0;
- rtl::Reference< SvxShape > xShape = createDataPoint3D_Bar(
+ 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) );
+ std::vector<std::vector<css::drawing::Position3D>> aPoly
+ {
+ { // inner vector
+ drawing::Position3D( fLogicX-fLogicBarWidth/2.0,fLowerYValue,fLogicZ),
+ drawing::Position3D( fLogicX+fLogicBarWidth/2.0,fLowerYValue,fLogicZ),
+ aRightUpperPoint,
+ aLeftUpperPoint,
+ drawing::Position3D( fLogicX-fLogicBarWidth/2.0,fLowerYValue,fLogicZ)
+ }
+ };
pPosHelper->transformScaledLogicToScene( aPoly );
- std::optional<sal_Int32> xFillColor;
- if(bHasFillColorMapping)
+ xShape = ShapeFactory::createArea2D( xSeriesGroupShape_Shapes, aPoly );
+ PropertyMapper::setMappedProperties( *xShape, xDataPointProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
+ }
+
+ if(bHasFillColorMapping)
+ {
+ double nPropVal = pSeries->getValueByProperty(nPointIndex, "FillColor");
+ if(!std::isnan(nPropVal))
{
- double nPropVal = pSeries->getValueByProperty(nPointIndex, "FillColor");
- if(!std::isnan(nPropVal))
- xFillColor = static_cast<sal_Int32>(nPropVal);
+ xShape->setPropertyValue("FillColor", uno::Any(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) );
}
-
+ //set name/classified ObjectID (CID)
+ ShapeFactory::setShapeName(xShape
+ , ObjectIdentifier::createPointCID(
+ pSeries->getPointCID_Stub(),nPointIndex) );
}
//create error bar
diff --git a/chart2/source/view/charttypes/BarChart.hxx b/chart2/source/view/charttypes/BarChart.hxx
index 5e9ab5e49f48..ff46786afcbb 100644
--- a/chart2/source/view/charttypes/BarChart.hxx
+++ b/chart2/source/view/charttypes/BarChart.hxx
@@ -21,10 +21,10 @@
#include <memory>
#include <VSeriesPlotter.hxx>
+#include "BarPositionHelper.hxx"
namespace chart
{
-class BarPositionHelper;
class BarChart : public VSeriesPlotter
{
@@ -32,7 +32,7 @@ class BarChart : public VSeriesPlotter
public:
BarChart() = delete;
- BarChart( const css::uno::Reference< css::chart2::XChartType >& xChartTypeModel
+ BarChart( const rtl::Reference< ::chart::ChartType >& xChartTypeModel
, sal_Int32 nDimensionCount );
virtual ~BarChart() override;
@@ -84,10 +84,10 @@ private: //methods
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,
+ const rtl::Reference<SvxShapeGroupAnyD>& xSeriesTarget,
+ const rtl::Reference<SvxShapeGroupAnyD>& xRegressionCurveTarget,
+ const rtl::Reference<SvxShapeGroupAnyD>& xRegressionCurveEquationTarget,
+ const rtl::Reference<SvxShapeGroupAnyD>& xTextTarget,
std::unordered_set<rtl::Reference<SvxShape>>& aShapeSet,
std::map< VDataSeries*, FormerBarPoint >& aSeriesFormerPointMap,
std::map< sal_Int32, double >& aLogicYSumMap);
@@ -96,10 +96,10 @@ private: //methods
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,
+ const rtl::Reference<SvxShapeGroupAnyD>& xSeriesTarget,
+ const rtl::Reference<SvxShapeGroupAnyD>& xRegressionCurveTarget,
+ const rtl::Reference<SvxShapeGroupAnyD>& xRegressionCurveEquationTarget,
+ const rtl::Reference<SvxShapeGroupAnyD>& xTextTarget,
std::unordered_set<rtl::Reference<SvxShape>>& aShapeSet,
std::map< VDataSeries*, FormerBarPoint >& aSeriesFormerPointMap,
std::map< sal_Int32, double >& aLogicYSumMap,
@@ -109,7 +109,7 @@ private: //methods
sal_Int32 nAttachedAxisIndex);
private: //member
- std::unique_ptr<BarPositionHelper> m_pMainPosHelper;
+ BarPositionHelper m_aMainPosHelper;
css::uno::Sequence< sal_Int32 > m_aOverlapSequence;
css::uno::Sequence< sal_Int32 > m_aGapwidthSequence;
};
diff --git a/chart2/source/view/charttypes/BarPositionHelper.cxx b/chart2/source/view/charttypes/BarPositionHelper.cxx
index f8ac3e7d62ef..279d998a02e4 100644
--- a/chart2/source/view/charttypes/BarPositionHelper.cxx
+++ b/chart2/source/view/charttypes/BarPositionHelper.cxx
@@ -23,7 +23,6 @@
namespace chart
{
using namespace ::com::sun::star;
-using namespace ::com::sun::star::chart2;
BarPositionHelper::BarPositionHelper()
: CategoryPositionHelper( 1 )
diff --git a/chart2/source/view/charttypes/BubbleChart.cxx b/chart2/source/view/charttypes/BubbleChart.cxx
index fc7fcdd2597b..d5bd2c3a16fc 100644
--- a/chart2/source/view/charttypes/BubbleChart.cxx
+++ b/chart2/source/view/charttypes/BubbleChart.cxx
@@ -22,6 +22,7 @@
#include <ShapeFactory.hxx>
#include <ObjectIdentifier.hxx>
#include <LabelPositionHelper.hxx>
+#include <ChartType.hxx>
#include <com/sun/star/chart/DataLabelPlacement.hpp>
#include <sal/log.hxx>
@@ -32,9 +33,8 @@
namespace chart
{
using namespace ::com::sun::star;
-using namespace ::com::sun::star::chart2;
-BubbleChart::BubbleChart( const uno::Reference<XChartType>& xChartTypeModel
+BubbleChart::BubbleChart( const rtl::Reference<ChartType>& xChartTypeModel
, sal_Int32 nDimensionCount )
: VSeriesPlotter( xChartTypeModel, nDimensionCount, false )
, m_fMaxLogicBubbleSize( 0.0 )
@@ -261,7 +261,6 @@ void BubbleChart::createShapes()
pSeries->getPointCID_Stub(), nIndex );
rtl::Reference<SvxShapeGroupAnyD> xPointGroupShape_Shapes(
createGroupShape(xSeriesGroupShape_Shapes,aPointCID) );
- uno::Reference<drawing::XShape> xPointGroupShape_Shape = xPointGroupShape_Shapes;
{
nCreatedPoints++;
@@ -345,7 +344,7 @@ void BubbleChart::createShapes()
//remove PointGroupShape if empty
if(!xPointGroupShape_Shapes->getCount())
- xSeriesGroupShape_Shapes->remove(xPointGroupShape_Shape);
+ xSeriesGroupShape_Shapes->remove(xPointGroupShape_Shapes);
}//next series in x slot (next y slot)
}//next x slot
diff --git a/chart2/source/view/charttypes/BubbleChart.hxx b/chart2/source/view/charttypes/BubbleChart.hxx
index 06d1d1200340..c25e5b6345bf 100644
--- a/chart2/source/view/charttypes/BubbleChart.hxx
+++ b/chart2/source/view/charttypes/BubbleChart.hxx
@@ -30,7 +30,7 @@ class BubbleChart : public VSeriesPlotter
public:
BubbleChart() = delete;
- BubbleChart( const css::uno::Reference< css::chart2::XChartType >& xChartTypeModel
+ BubbleChart( const rtl::Reference< ::chart::ChartType >& xChartTypeModel
, sal_Int32 nDimensionCount );
virtual ~BubbleChart() override;
diff --git a/chart2/source/view/charttypes/CandleStickChart.cxx b/chart2/source/view/charttypes/CandleStickChart.cxx
index 44fcd600bd49..5f3a19582e12 100644
--- a/chart2/source/view/charttypes/CandleStickChart.cxx
+++ b/chart2/source/view/charttypes/CandleStickChart.cxx
@@ -18,6 +18,7 @@
*/
#include "CandleStickChart.hxx"
+#include <ChartType.hxx>
#include <ShapeFactory.hxx>
#include <CommonConverters.hxx>
#include <ExplicitCategoriesProvider.hxx>
@@ -25,21 +26,19 @@
#include "BarPositionHelper.hxx"
#include <DateHelper.hxx>
#include <com/sun/star/beans/XPropertySet.hpp>
-#include <tools/diagnose_ex.h>
+#include <comphelper/diagnose_ex.hxx>
#include <osl/diagnose.h>
namespace chart
{
using namespace ::com::sun::star;
-using namespace ::com::sun::star::chart2;
-CandleStickChart::CandleStickChart( const uno::Reference<XChartType>& xChartTypeModel
+CandleStickChart::CandleStickChart( const rtl::Reference<ChartType>& xChartTypeModel
, sal_Int32 nDimensionCount )
: VSeriesPlotter( xChartTypeModel, nDimensionCount )
- , m_pMainPosHelper( new BarPositionHelper() )
{
- PlotterBase::m_pPosHelper = m_pMainPosHelper.get();
- VSeriesPlotter::m_pMainPosHelper = m_pMainPosHelper.get();
+ PlotterBase::m_pPosHelper = &m_aMainPosHelper;
+ VSeriesPlotter::m_pMainPosHelper = &m_aMainPosHelper;
}
CandleStickChart::~CandleStickChart()
@@ -104,15 +103,15 @@ void CandleStickChart::createShapes()
tAnySequence aWhiteBox_Values, aBlackBox_Values;
try
{
- if( m_xChartTypeModelProps.is() )
+ if( m_xChartTypeModel.is() )
{
- m_xChartTypeModelProps->getPropertyValue( "ShowFirst" ) >>= bShowFirst;
+ m_xChartTypeModel->getPropertyValue( "ShowFirst" ) >>= bShowFirst;
uno::Reference< beans::XPropertySet > xWhiteDayProps;
uno::Reference< beans::XPropertySet > xBlackDayProps;
- m_xChartTypeModelProps->getPropertyValue( "Japanese" ) >>= bJapaneseStyle;
- m_xChartTypeModelProps->getPropertyValue( "WhiteDay" ) >>= xWhiteDayProps;
- m_xChartTypeModelProps->getPropertyValue( "BlackDay" ) >>= xBlackDayProps;
+ m_xChartTypeModel->getPropertyValue( "Japanese" ) >>= bJapaneseStyle;
+ m_xChartTypeModel->getPropertyValue( "WhiteDay" ) >>= xWhiteDayProps;
+ m_xChartTypeModel->getPropertyValue( "BlackDay" ) >>= xBlackDayProps;
tPropertyNameValueMap aWhiteBox_Map;
PropertyMapper::getValueMap( aWhiteBox_Map, PropertyMapper::getPropertyNameMapForFillAndLineProperties(), xWhiteDayProps );
@@ -136,14 +135,14 @@ void CandleStickChart::createShapes()
{
for( auto const& rZSlot : m_aZSlots )
{
- BarPositionHelper* pPosHelper = m_pMainPosHelper.get();
+ BarPositionHelper* pPosHelper = &m_aMainPosHelper;
if( !rZSlot.empty() )
{
sal_Int32 nAttachedAxisIndex = rZSlot.front().getAttachedAxisIndexForFirstSeries();
//2ND_AXIS_IN_BARS so far one can assume to have the same plotter for each z slot
pPosHelper = dynamic_cast<BarPositionHelper*>(&( getPlottingPositionHelper( nAttachedAxisIndex ) ) );
if(!pPosHelper)
- pPosHelper = m_pMainPosHelper.get();
+ pPosHelper = &m_aMainPosHelper;
}
PlotterBase::m_pPosHelper = pPosHelper;
@@ -200,9 +199,7 @@ void CandleStickChart::createShapes()
drawing::Position3D aPosMiddleMinimum( pPosHelper->transformScaledLogicToScene( fScaledX, fScaledY_Min ,0 ,true ) );
drawing::Position3D aPosMiddleMaximum( pPosHelper->transformScaledLogicToScene( fScaledX, fScaledY_Max ,0 ,true ) );
- rtl::Reference<SvxShapeGroupAnyD> xLossGainTarget( xGainTarget );
- if(bBlack)
- xLossGainTarget = xLossTarget;
+ rtl::Reference<SvxShapeGroupAnyD> xLossGainTarget(bBlack ? xLossTarget : xGainTarget);
uno::Reference< beans::XPropertySet > xPointProp( pSeries->getPropertiesOfPoint( nIndex ));
rtl::Reference<SvxShapeGroupAnyD> xPointGroupShape_Shapes;
@@ -215,10 +212,10 @@ void CandleStickChart::createShapes()
//create min-max line
if( isValidPosition(aPosMiddleMinimum) && isValidPosition(aPosMiddleMaximum) )
{
- std::vector<std::vector<css::drawing::Position3D>> aPoly;
- sal_Int32 nLineIndex =0;
- AddPointToPoly( aPoly, aPosMiddleMinimum, nLineIndex);
- AddPointToPoly( aPoly, aPosMiddleMaximum, nLineIndex);
+ std::vector<std::vector<css::drawing::Position3D>> aPoly
+ {
+ { aPosMiddleMinimum, aPosMiddleMaximum }
+ };
rtl::Reference<SvxShapePolyPolygon> xShape =
ShapeFactory::createLine2D( xPointGroupShape_Shapes, aPoly);
diff --git a/chart2/source/view/charttypes/CandleStickChart.hxx b/chart2/source/view/charttypes/CandleStickChart.hxx
index eddee6b72e12..3202cf0d7eaf 100644
--- a/chart2/source/view/charttypes/CandleStickChart.hxx
+++ b/chart2/source/view/charttypes/CandleStickChart.hxx
@@ -20,11 +20,11 @@
#pragma once
#include <memory>
+#include "BarPositionHelper.hxx"
#include <VSeriesPlotter.hxx>
namespace chart
{
-class BarPositionHelper;
class CandleStickChart : public VSeriesPlotter
{
@@ -32,7 +32,7 @@ class CandleStickChart : public VSeriesPlotter
public:
CandleStickChart() = delete;
- CandleStickChart( const css::uno::Reference< css::chart2::XChartType >& xChartTypeModel
+ CandleStickChart( const rtl::Reference< ::chart::ChartType >& xChartTypeModel
, sal_Int32 nDimensionCount );
virtual ~CandleStickChart() override;
@@ -47,7 +47,7 @@ public:
virtual LegendSymbolStyle getLegendSymbolStyle() override;
private: //member
- std::unique_ptr<BarPositionHelper> m_pMainPosHelper;
+ BarPositionHelper m_aMainPosHelper;
};
} //namespace chart
diff --git a/chart2/source/view/charttypes/ConfigAccess.cxx b/chart2/source/view/charttypes/ConfigAccess.cxx
deleted file mode 100644
index ce02c4817e0a..000000000000
--- a/chart2/source/view/charttypes/ConfigAccess.cxx
+++ /dev/null
@@ -1,74 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This file is part of the LibreOffice project.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- * This file incorporates work covered by the following license notice:
- *
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed
- * with this work for additional information regarding copyright
- * ownership. The ASF licenses this file to you under the Apache
- * License, Version 2.0 (the "License"); you may not use this file
- * except in compliance with the License. You may obtain a copy of
- * the License at http://www.apache.org/licenses/LICENSE-2.0 .
- */
-
-#include <ConfigAccess.hxx>
-
-#include <unotools/configitem.hxx>
-#include <o3tl/any.hxx>
-#include <com/sun/star/uno/Sequence.hxx>
-
-namespace chart
-{
-using namespace ::com::sun::star;
-
-namespace
-{
-class ChartConfigItem : public ::utl::ConfigItem
-{
-private:
- virtual void ImplCommit() override;
-
-public:
- ChartConfigItem();
-
- bool getUseErrorRectangle();
- virtual void Notify(const uno::Sequence<OUString>& aPropertyNames) override;
-};
-}
-
-ChartConfigItem::ChartConfigItem()
- : ConfigItem("Office.Chart/ErrorProperties")
-{
-}
-
-void ChartConfigItem::ImplCommit() {}
-void ChartConfigItem::Notify(const uno::Sequence<OUString>&) {}
-
-bool ChartConfigItem::getUseErrorRectangle()
-{
- uno::Sequence<OUString> aNames{ "ErrorRectangle" };
-
- auto b = o3tl::tryAccess<bool>(GetProperties(aNames)[0]);
- return b && *b;
-}
-
-namespace ConfigAccess
-{
-bool getUseErrorRectangle()
-{
- //a ChartConfigItem Singleton
- static ChartConfigItem SINGLETON;
- bool bResult(SINGLETON.getUseErrorRectangle());
- return bResult;
-}
-} //namespace ConfigAccess
-
-} //namespace chart
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/view/charttypes/NetChart.cxx b/chart2/source/view/charttypes/NetChart.cxx
index 5507e30e0579..5b8f1db34be5 100644
--- a/chart2/source/view/charttypes/NetChart.cxx
+++ b/chart2/source/view/charttypes/NetChart.cxx
@@ -27,14 +27,15 @@
#include <Clipping.hxx>
#include <PolarLabelPositionHelper.hxx>
#include <DateHelper.hxx>
+#include <ChartType.hxx>
#include <com/sun/star/chart2/Symbol.hpp>
#include <com/sun/star/chart/DataLabelPlacement.hpp>
#include <com/sun/star/chart/MissingValueTreatment.hpp>
+#include <o3tl/safeint.hxx>
#include <osl/diagnose.h>
-#include <com/sun/star/drawing/XShapes.hpp>
#include <officecfg/Office/Compatibility.hxx>
#include <limits>
@@ -44,7 +45,7 @@ namespace chart
using namespace ::com::sun::star;
using namespace ::com::sun::star::chart2;
-NetChart::NetChart( const uno::Reference<XChartType>& xChartTypeModel
+NetChart::NetChart( const rtl::Reference<ChartType>& xChartTypeModel
, sal_Int32 nDimensionCount
, bool bNoArea
, std::unique_ptr<PlottingPositionHelper> pPlottingPositionHelper
@@ -111,7 +112,7 @@ drawing::Direction3D NetChart::getPreferredDiagramAspectRatio() const
}
bool NetChart::impl_createLine( VDataSeries* pSeries
- , std::vector<std::vector<css::drawing::Position3D>>* pSeriesPoly
+ , const std::vector<std::vector<css::drawing::Position3D>>* pSeriesPoly
, PlottingPositionHelper const * pPosHelper )
{
//return true if a line was created successfully
@@ -163,7 +164,7 @@ bool NetChart::impl_createLine( VDataSeries* pSeries
}
bool NetChart::impl_createArea( VDataSeries* pSeries
- , std::vector<std::vector<css::drawing::Position3D>>* pSeriesPoly
+ , const std::vector<std::vector<css::drawing::Position3D>>* pSeriesPoly
, std::vector<std::vector<css::drawing::Position3D>> const * pPreviousSeriesPoly
, PlottingPositionHelper const * pPosHelper )
{
@@ -221,12 +222,14 @@ bool NetChart::impl_createArea( VDataSeries* pSeries
pPosHelper->transformScaledLogicToScene( aPoly );
//create area:
- SdrPathObj* pShape = ShapeFactory::createArea2D( xSeriesGroupShape_Shapes
- , aPoly );
- PropertyMapper::setPropertyNameMapForFilledSeriesProperties(pShape
- , pSeries->getPropertiesOfSeries() );
+ rtl::Reference<SvxShapePolyPolygon>
+ xShape = ShapeFactory::createArea2D( xSeriesGroupShape_Shapes
+ , aPoly );
+ PropertyMapper::setMappedProperties( *xShape
+ , pSeries->getPropertiesOfSeries()
+ , PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
//because of this name this line will be used for marking
- ::chart::ShapeFactory::setShapeName(pShape, "MarkHandles");
+ ::chart::ShapeFactory::setShapeName(xShape, "MarkHandles");
return true;
}
@@ -438,7 +441,7 @@ void NetChart::createShapes()
{
std::vector<std::vector<css::drawing::Position3D>>& rPolygon = pSeries->m_aPolyPolygonShape3D;
sal_Int32& rIndex = pSeries->m_nPolygonIndex;
- if( 0<= rIndex && rIndex < static_cast<sal_Int32>(rPolygon.size()) )
+ if( 0<= rIndex && o3tl::make_unsigned(rIndex) < rPolygon.size() )
{
if( !rPolygon[ rIndex ].empty() )
rIndex++; //start a new polygon for the next point if the current poly is not empty
@@ -526,7 +529,6 @@ void NetChart::createShapes()
pSeries->getPointCID_Stub(), nIndex );
rtl::Reference<SvxShapeGroupAnyD> xPointGroupShape_Shapes(
createGroupShape(xSeriesGroupShape_Shapes,aPointCID) );
- uno::Reference<drawing::XShape> xPointGroupShape_Shape( xPointGroupShape_Shapes );
{
//create data point
@@ -624,7 +626,7 @@ void NetChart::createShapes()
//remove PointGroupShape if empty
if(!xPointGroupShape_Shapes->getCount())
- xSeriesGroupShape_Shapes->remove(xPointGroupShape_Shape);
+ xSeriesGroupShape_Shapes->remove(xPointGroupShape_Shapes);
}//next series in x slot (next y slot)
}//next x slot
diff --git a/chart2/source/view/charttypes/NetChart.hxx b/chart2/source/view/charttypes/NetChart.hxx
index 9883ba118ac2..a536daf15fd2 100644
--- a/chart2/source/view/charttypes/NetChart.hxx
+++ b/chart2/source/view/charttypes/NetChart.hxx
@@ -31,7 +31,7 @@ class NetChart : public VSeriesPlotter
public:
NetChart() = delete;
- NetChart( const css::uno::Reference< css::chart2::XChartType >& xChartTypeModel
+ NetChart( const rtl::Reference< ::chart::ChartType >& xChartTypeModel
, sal_Int32 nDimensionCount
, bool bNoArea
, std::unique_ptr<PlottingPositionHelper> pPlottingPositionHelper //takes ownership
@@ -53,11 +53,11 @@ public:
private: //methods
void impl_createSeriesShapes();
bool impl_createArea( VDataSeries* pSeries
- , std::vector<std::vector<css::drawing::Position3D>>* pSeriesPoly
+ , const std::vector<std::vector<css::drawing::Position3D>>* pSeriesPoly
, std::vector<std::vector<css::drawing::Position3D>> const * pPreviousSeriesPoly
, PlottingPositionHelper const * pPosHelper );
bool impl_createLine( VDataSeries* pSeries
- , std::vector<std::vector<css::drawing::Position3D>>* pSeriesPoly
+ , const std::vector<std::vector<css::drawing::Position3D>>* pSeriesPoly
, PlottingPositionHelper const * pPosHelper );
private: //member
diff --git a/chart2/source/view/charttypes/PieChart.cxx b/chart2/source/view/charttypes/PieChart.cxx
index 2fd709500d29..ff8cf62f133a 100644
--- a/chart2/source/view/charttypes/PieChart.cxx
+++ b/chart2/source/view/charttypes/PieChart.cxx
@@ -20,23 +20,21 @@
#include <BaseGFXHelper.hxx>
#include <VLineProperties.hxx>
#include "PieChart.hxx"
-#include <PlottingPositionHelper.hxx>
#include <ShapeFactory.hxx>
#include <PolarLabelPositionHelper.hxx>
#include <CommonConverters.hxx>
#include <ObjectIdentifier.hxx>
+#include <ChartType.hxx>
+#include <DataSeries.hxx>
+#include <DataSeriesProperties.hxx>
#include <com/sun/star/chart/DataLabelPlacement.hpp>
-#include <com/sun/star/chart2/XChartType.hpp>
#include <com/sun/star/chart2/XColorScheme.hpp>
-#include <com/sun/star/container/XChild.hpp>
-#include <com/sun/star/drawing/XShape.hpp>
#include <com/sun/star/drawing/XShapes.hpp>
-#include <com/sun/star/beans/XPropertySet.hpp>
#include <sal/log.hxx>
#include <osl/diagnose.h>
-#include <tools/diagnose_ex.h>
+#include <comphelper/diagnose_ex.hxx>
#include <tools/helpers.hxx>
#include <limits>
@@ -44,6 +42,7 @@
using namespace ::com::sun::star;
using namespace ::com::sun::star::chart2;
+using namespace ::chart::DataSeriesProperties;
namespace chart {
@@ -104,7 +103,7 @@ struct PieChart::ShapeParam
namespace
{
-::basegfx::B2IRectangle lcl_getRect(const uno::Reference<drawing::XShape>& xShape)
+::basegfx::B2IRectangle lcl_getRect(const rtl::Reference<SvxShape>& xShape)
{
::basegfx::B2IRectangle aRect;
if (xShape.is())
@@ -125,18 +124,6 @@ bool lcl_isInsidePage(const awt::Point& rPos, const awt::Size& rSize, const awt:
} //end anonymous namespace
-class PiePositionHelper : public PolarPlottingPositionHelper
-{
-public:
- PiePositionHelper( double fAngleDegreeOffset );
-
- bool getInnerAndOuterRadius( double fCategoryX, double& fLogicInnerRadius, double& fLogicOuterRadius, bool bUseRings, double fMaxOffset ) const;
-
-public:
- //Distance between different category rings, seen relative to width of a ring:
- double m_fRingDistance; //>=0 m_fRingDistance=1 --> distance == width
-};
-
PiePositionHelper::PiePositionHelper( double fAngleDegreeOffset )
: m_fRingDistance(0.0)
{
@@ -191,38 +178,54 @@ bool PiePositionHelper::getInnerAndOuterRadius( double fCategoryX
return true;
}
-PieChart::PieChart( const uno::Reference<XChartType>& xChartTypeModel
+
+bool PiePositionHelper::clockwiseWedges() const
+{
+ const ExplicitScaleData& rAngleScale = m_bSwapXAndY ? m_aScales[1] : m_aScales[0];
+ return rAngleScale.Orientation == AxisOrientation_REVERSE;
+}
+
+
+PieChart::PieChart( const rtl::Reference<ChartType>& xChartTypeModel
, sal_Int32 nDimensionCount
, bool bExcludingPositioning )
: VSeriesPlotter( xChartTypeModel, nDimensionCount )
- , m_pPosHelper( new PiePositionHelper( (m_nDimension==3) ? 0.0 : 90.0 ) )
+ , m_aPosHelper( (m_nDimension==3) ? 0.0 : 90.0 )
, m_bUseRings(false)
, m_bSizeExcludesLabelsAndExplodedSegments(bExcludingPositioning)
+ , m_eSubType(PieChartSubType_NONE)
, m_fMaxOffset(std::numeric_limits<double>::quiet_NaN())
{
- PlotterBase::m_pPosHelper = m_pPosHelper.get();
- VSeriesPlotter::m_pMainPosHelper = m_pPosHelper.get();
- m_pPosHelper->m_fRadiusOffset = 0.0;
- m_pPosHelper->m_fRingDistance = 0.0;
+ PlotterBase::m_pPosHelper = &m_aPosHelper;
+ VSeriesPlotter::m_pMainPosHelper = &m_aPosHelper;
+ m_aPosHelper.m_fRadiusOffset = 0.0;
+ m_aPosHelper.m_fRingDistance = 0.0;
- uno::Reference< beans::XPropertySet > xChartTypeProps( xChartTypeModel, uno::UNO_QUERY );
- if( !xChartTypeProps.is() )
+ if( !xChartTypeModel.is() )
return;
try
{
- xChartTypeProps->getPropertyValue( "UseRings") >>= m_bUseRings;
+ xChartTypeModel->getFastPropertyValue(PROP_PIECHARTTYPE_USE_RINGS) >>= m_bUseRings; // "UseRings"
if( m_bUseRings )
{
- m_pPosHelper->m_fRadiusOffset = 1.0;
+ m_aPosHelper.m_fRadiusOffset = 1.0;
if( nDimensionCount==3 )
- m_pPosHelper->m_fRingDistance = 0.1;
+ m_aPosHelper.m_fRingDistance = 0.1;
}
}
catch( const uno::Exception& )
{
TOOLS_WARN_EXCEPTION("chart2", "" );
}
+ try
+ {
+ xChartTypeModel->getFastPropertyValue(PROP_PIECHARTTYPE_SUBTYPE) >>= m_eSubType; // "SubType"
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
}
PieChart::~PieChart()
@@ -232,7 +235,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_pPosHelper->setScales( std::move(rScales), true );
+ m_aPosHelper.setScales( std::move(rScales), true );
}
drawing::Direction3D PieChart::getPreferredDiagramAspectRatio() const
@@ -248,42 +251,140 @@ bool PieChart::shouldSnapRectToUsedArea()
}
rtl::Reference<SvxShape> PieChart::createDataPoint(
+ const SubPieType e_subType,
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_aPosHelper.transformUnitCircleToScene(0, 0, rParam.mfLogicZ);
+ drawing::Position3D aNewOrigin = m_aPosHelper.transformUnitCircleToScene(fAngle, fRadius, rParam.mfLogicZ);
+ aOffset = aNewOrigin - aOrigin;
+ }
+ } else {
+ drawing::Position3D aOrigin, aNewOrigin;
+ switch (e_subType) {
+ case SubPieType::LEFT:
+ // Draw the main pie for bar-of-pie/pie-of-pie smaller and to the left
+ aOrigin = m_aPosHelper.transformUnitCircleToScene(0, 0, rParam.mfLogicZ);
+ aNewOrigin = m_aPosHelper.transformUnitCircleToScene(180, 0.75, rParam.mfLogicZ);
+ aOffset = aNewOrigin - aOrigin;
+ fExplodedOuterRadius *= 2.0/3;
+ break;
+ case SubPieType::RIGHT:
+ // Draw the sub-pie for pie-of-pie much smaller and to the right
+ aOrigin = m_aPosHelper.transformUnitCircleToScene(0, 0, rParam.mfLogicZ);
+ aNewOrigin = m_aPosHelper.transformUnitCircleToScene(0, 0.75, rParam.mfLogicZ);
+ aOffset = aNewOrigin - aOrigin;
+ fExplodedOuterRadius *= 1.0/3;
+ break;
+ case SubPieType::NONE:
+ default:
+ // no change
+ break;
+ }
}
+
//create point
rtl::Reference<SvxShape> xShape;
if(m_nDimension==3)
{
xShape = ShapeFactory::createPieSegment( xTarget
- , rParam.mfUnitCircleStartAngleDegree, rParam.mfUnitCircleWidthAngleDegree
- , rParam.mfUnitCircleInnerRadius, rParam.mfUnitCircleOuterRadius
- , aOffset, B3DHomMatrixToHomogenMatrix( m_pPosHelper->getUnitCartesianToScene() )
+ , fStartAngle, fWidthAngle
+ , fExplodedInnerRadius, fExplodedOuterRadius
+ , aOffset, B3DHomMatrixToHomogenMatrix( m_aPosHelper.getUnitCartesianToScene() )
, rParam.mfDepth );
}
else
{
xShape = ShapeFactory::createPieSegment2D( xTarget
- , rParam.mfUnitCircleStartAngleDegree, rParam.mfUnitCircleWidthAngleDegree
- , rParam.mfUnitCircleInnerRadius, rParam.mfUnitCircleOuterRadius
- , aOffset, B3DHomMatrixToHomogenMatrix( m_pPosHelper->getUnitCartesianToScene() ) );
+ , fStartAngle, fWidthAngle
+ , fExplodedInnerRadius, fExplodedOuterRadius
+ , aOffset, B3DHomMatrixToHomogenMatrix( m_aPosHelper.getUnitCartesianToScene() ) );
}
PropertyMapper::setMappedProperties( *xShape, xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() );
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 )
@@ -306,7 +407,12 @@ void PieChart::createTextLabelShape(
///get the required label placement type. Available placements are
///`AVOID_OVERLAP`, `CENTER`, `OUTSIDE` and `INSIDE`;
sal_Int32 nLabelPlacement = rSeries.getLabelPlacement(
- nPointIndex, m_xChartTypeModel, m_pPosHelper->isSwapXAndY());
+ nPointIndex, m_xChartTypeModel, m_aPosHelper.isSwapXAndY());
+
+ // has an X/Y offset (relative to the OUTSIDE label default position) been provided?
+ const bool bHasCustomLabelPlacement = nLabelPlacement == css::chart::DataLabelPlacement::CUSTOM;
+ if (bHasCustomLabelPlacement)
+ nLabelPlacement = css::chart::DataLabelPlacement::OUTSIDE;
///when the placement is of `AVOID_OVERLAP` type a later rearrangement of
///the label position is allowed; the `createTextLabelShape` treats the
@@ -314,8 +420,7 @@ void PieChart::createTextLabelShape(
double nVal = rSeries.getYValue(nPointIndex);
//AVOID_OVERLAP is in fact "Best fit" in the UI.
- bool bMovementAllowed = nLabelPlacement == css::chart::DataLabelPlacement::AVOID_OVERLAP
- || nLabelPlacement == css::chart::DataLabelPlacement::CUSTOM;
+ bool bMovementAllowed = nLabelPlacement == css::chart::DataLabelPlacement::AVOID_OVERLAP;
if( bMovementAllowed )
nLabelPlacement = css::chart::DataLabelPlacement::CENTER;
@@ -337,7 +442,7 @@ void PieChart::createTextLabelShape(
///the scene position of the label anchor point is calculated (see notes for
///`PolarLabelPositionHelper::getLabelScreenPositionAndAlignmentForUnitCircleValues`),
///and immediately transformed into the screen position.
- PolarLabelPositionHelper aPolarPosHelper(m_pPosHelper.get(),m_nDimension,m_xLogicTarget);
+ PolarLabelPositionHelper aPolarPosHelper(&m_aPosHelper,m_nDimension,m_xLogicTarget);
awt::Point aScreenPosition2D(
aPolarPosHelper.getLabelScreenPositionAndAlignmentForUnitCircleValues(eAlignment, nLabelPlacement
, rParam.mfUnitCircleStartAngleDegree, rParam.mfUnitCircleWidthAngleDegree
@@ -346,7 +451,7 @@ void PieChart::createTextLabelShape(
///the screen position of the pie/donut center is calculated.
PieLabelInfo aPieLabelInfo;
aPieLabelInfo.aFirstPosition = basegfx::B2IVector( aScreenPosition2D.X, aScreenPosition2D.Y );
- awt::Point aOrigin( aPolarPosHelper.transformSceneToScreenPosition( m_pPosHelper->transformUnitCircleToScene( 0.0, 0.0, rParam.mfLogicZ+1.0 ) ) );
+ awt::Point aOrigin( aPolarPosHelper.transformSceneToScreenPosition( m_aPosHelper.transformUnitCircleToScene( 0.0, 0.0, rParam.mfLogicZ+1.0 ) ) );
aPieLabelInfo.aOrigin = basegfx::B2IVector( aOrigin.X, aOrigin.Y );
///add a scaling independent Offset if requested
@@ -360,7 +465,7 @@ void PieChart::createTextLabelShape(
// compute outer pie radius
awt::Point aOuterCirclePoint = PlottingPositionHelper::transformSceneToScreenPosition(
- m_pPosHelper->transformUnitCircleToScene(
+ m_aPosHelper.transformUnitCircleToScene(
0,
rParam.mfUnitCircleOuterRadius,
0 ),
@@ -370,29 +475,71 @@ void PieChart::createTextLabelShape(
aOuterCirclePoint.Y - aPieLabelInfo.aOrigin.getY() );
double fSquaredPieRadius = aRadiusVector.scalar(aRadiusVector);
double fPieRadius = sqrt( fSquaredPieRadius );
- double fAngleDegree
- = rParam.mfUnitCircleStartAngleDegree + rParam.mfUnitCircleWidthAngleDegree / 2.0;
- while (fAngleDegree > 360.0)
- fAngleDegree -= 360.0;
- while (fAngleDegree < 0.0)
- fAngleDegree += 360.0;
+ const double fHalfWidthAngleDegree = rParam.mfUnitCircleWidthAngleDegree / 2.0;
+ // fAngleDegree: the angle through the center of the slice / the bisecting ray
+ const double fAngleDegree
+ = NormAngle360(rParam.mfUnitCircleStartAngleDegree + fHalfWidthAngleDegree);
+ // aOuterPosition: slice midpoint on the circumference,
+ // which is where an outside/custom label would be connected
awt::Point aOuterPosition = PlottingPositionHelper::transformSceneToScreenPosition(
- m_pPosHelper->transformUnitCircleToScene(fAngleDegree, rParam.mfUnitCircleOuterRadius, 0),
+ m_aPosHelper.transformUnitCircleToScene(fAngleDegree, rParam.mfUnitCircleOuterRadius, 0),
m_xLogicTarget, m_nDimension);
aPieLabelInfo.aOuterPosition = basegfx::B2IVector(aOuterPosition.X, aOuterPosition.Y);
- // set the maximum text width to be used when text wrapping is enabled
+ /* There are basically three places where a label could be placed in a pie chart
+ * 1.) outside the slice
+ * -typically used for long labels or charts with many, thin slices
+ * 2.) inside the slice (center or edge)
+ * -typically used for charts with 5 or less slices
+ * 3.) in a custom location
+ * -typically set (by auto-positioning I presume) when labels overlap
+ *
+ * Selecting a good width for the text is critical to achieving good-looking labels.
+ * Our bestFit algorithm completely depends on a good starting guess.
+ * Lots of room for improvement here...
+ * Warning: complication due to 3D ovals (so can't use normal circle functions),
+ * donuts(m_bUseRings), auto re-scaling of the pie chart, etc.
+ *
+ * Based on observation, Microsoft uses 1/5 of the chart space as its text limit,
+ * although it will reduce the width (as long as it is not a custom position)
+ * if doing so means that the now-taller-text will fit inside the slice,
+ * so best if we do the same for our charts.
+ */
+
+ // set the maximum text width to be used when text wrapping is enabled (default text wrap is on)
+ /* A reasonable start for bestFitting a 90deg slice oriented on an Axis is 80% of the radius */
double fTextMaximumFrameWidth = 0.8 * fPieRadius;
- if (nLabelPlacement == css::chart::DataLabelPlacement::OUTSIDE
- && m_aAvailableOuterRect.getWidth())
+ const double fCompatMaxTextLen = m_aAvailableOuterRect.getWidth() / 5.0;
+ if (m_aAvailableOuterRect.getWidth())
{
- if ((fAngleDegree >= 67.5 && fAngleDegree <= 112.5)
- || (fAngleDegree >= 247.5 && fAngleDegree <= 292.5))
- fTextMaximumFrameWidth = m_aAvailableOuterRect.getWidth() / 3.0;
- else
- fTextMaximumFrameWidth = 0.85 * (m_aAvailableOuterRect.getWidth() / 2.0 - fPieRadius);
+ if (bHasCustomLabelPlacement)
+ {
+ // if a custom width has been provided, then use that of course,
+ // otherwise use the interoperability-compliant 1/5 of the chart space as max width
+ const awt::Size aCustomSize = rSeries.getLabelCustomSize(nPointIndex);
+ if (aCustomSize.Width > 0)
+ fTextMaximumFrameWidth = aCustomSize.Width;
+ else
+ fTextMaximumFrameWidth = fCompatMaxTextLen;
+ }
+ else if (nLabelPlacement == css::chart::DataLabelPlacement::OUTSIDE)
+ {
+ // use up to 80% of the available space from the slice edge to the edge of the chart
+ const sal_Int32 nOuterX = aPieLabelInfo.aOuterPosition.getX();
+ if (fAngleDegree < 90 || fAngleDegree > 270) // label is placed on the right side
+ fTextMaximumFrameWidth = 0.8 * abs(m_aAvailableOuterRect.getWidth() - nOuterX);
+ else // label is placed on the left side
+ fTextMaximumFrameWidth = 0.8 * nOuterX;
+
+ // limited of course to the 1/5 maximum allowed for compatibility
+ fTextMaximumFrameWidth = std::min(fTextMaximumFrameWidth, fCompatMaxTextLen);
+ }
}
+ /* TODO: better guesses for INSIDE: does the slice better handle wide text or tall/wrapped text?
+ * * wide: center near X-axis, shorter text content, slice > 90degree wide
+ * * tall: center near Y-axis, longer text content, many categories shown
+ */
sal_Int32 nTextMaximumFrameWidth = ceil(fTextMaximumFrameWidth);
///the text shape for the label is created
@@ -402,13 +549,13 @@ void PieChart::createTextLabelShape(
///a new `PieLabelInfo` instance is initialized with all the info related to
///the current label in order to simplify later label position rearrangement;
- uno::Reference< container::XChild > xChild( aPieLabelInfo.xTextShape, uno::UNO_QUERY );
+ rtl::Reference< SvxShape > xChild = aPieLabelInfo.xTextShape;
///text shape could be empty; in that case there is no need to add label info
if( !xChild.is() )
return;
- aPieLabelInfo.xLabelGroupShape.set( xChild->getParent(), uno::UNO_QUERY );
+ aPieLabelInfo.xLabelGroupShape = dynamic_cast<SvxShapeGroupAnyD*>(xChild->getParent().get());
if (bMovementAllowed && !m_bUseRings)
{
@@ -416,21 +563,47 @@ void PieChart::createTextLabelShape(
* First off the routine try to place the label inside the related pie slice,
* if this is not possible the label is placed outside.
*/
- if (rSeries.getLabelPlacement(nPointIndex, m_xChartTypeModel, m_pPosHelper->isSwapXAndY())
- == css::chart::DataLabelPlacement::CUSTOM
- || !performLabelBestFitInnerPlacement(rParam, aPieLabelInfo))
+
+ /* Note: bestFit surprisingly does not adjust the width of the label,
+ * so having an optimal width already set when createDataLabel ran earlier
+ * is crucial (and currently lacking)!
+ * TODO: * change bestFit to treat the width as a max width, and reduce if beneficial
+ */
+ if (!performLabelBestFitInnerPlacement(rParam, aPieLabelInfo))
{
if (m_aAvailableOuterRect.getWidth())
{
- if ((fAngleDegree >= 67.5 && fAngleDegree <= 112.5)
- || (fAngleDegree >= 247.5 && fAngleDegree <= 292.5))
- fTextMaximumFrameWidth = m_aAvailableOuterRect.getWidth() / 3.0;
- else
- fTextMaximumFrameWidth
- = 0.85 * (m_aAvailableOuterRect.getWidth() / 2.0 - fPieRadius);
- nTextMaximumFrameWidth = ceil(fTextMaximumFrameWidth);
+ /* This tried to bestFit, but it didn't fit. So how best to handle this?
+ *
+ * Two possible cases relating to compatibility
+ * 1.) It did fit for Microsoft, but our bestFit wasn't able to do the same
+ * * In that case, the best response is to be as small as possible
+ * (the distance from the chart edge to where the label attaches to the slice)
+ * to avoid scaling the diagram with too long outside labels,
+ * and to encourage fixing the bestFit algorithm.
+ * 2.) It didn't fit for Microsoft either (possible, but less likely situation)
+ * * In that case, the compatible max length would be best
+ * * can expect the chart space has been properly sized to handle the max length
+ *
+ * In the native LO case, it is also best to be as small as possible,
+ * so that the user creating the diagram is annoyed and makes the chart area larger.
+ *
+ * Therefore, handle this by making the label as small as possible.
+ *
+ * Complication (tdf122765.pptx): it is possible for the aOuterPosition
+ * to be outside of the available outer rectangle (somehow),
+ * so in that bizarre case just try the positive value of the result...
+ */
+ const sal_Int32 nOuterX = aPieLabelInfo.aOuterPosition.getX();
+ if (fAngleDegree < 90 || fAngleDegree > 270) // label is placed on the right side
+ fTextMaximumFrameWidth = 0.8 * abs(m_aAvailableOuterRect.getWidth() - nOuterX);
+ else // label is placed on the left side
+ fTextMaximumFrameWidth = 0.8 * nOuterX;
+
+ nTextMaximumFrameWidth = ceil(std::min(fTextMaximumFrameWidth, fCompatMaxTextLen));
}
+ // find the position to connect an Outside label to
nScreenValueOffsetInRadiusDirection = (m_nDimension != 3) ? 150 : 0;
aScreenPosition2D
= aPolarPosHelper.getLabelScreenPositionAndAlignmentForUnitCircleValues(
@@ -452,21 +625,21 @@ void PieChart::createTextLabelShape(
}
uno::Reference<drawing::XShapes> xShapes(xChild->getParent(), uno::UNO_QUERY);
+ /* question: why remove and rebuild? Can't the existing one just be changed? */
xShapes->remove(aPieLabelInfo.xTextShape);
aPieLabelInfo.xTextShape
= createDataLabel(xTextTarget, rSeries, nPointIndex, nVal, rParam.mfLogicYSum,
aScreenPosition2D, eAlignment, 0, nTextMaximumFrameWidth);
- xChild.clear();
- xChild.set(uno::Reference<container::XChild>(aPieLabelInfo.xTextShape, uno::UNO_QUERY));
+ xChild = aPieLabelInfo.xTextShape;
if (!xChild.is())
return;
- aPieLabelInfo.xLabelGroupShape.set(xChild->getParent(), uno::UNO_QUERY);
+ aPieLabelInfo.xLabelGroupShape = dynamic_cast<SvxShapeGroupAnyD*>(xChild->getParent().get());
}
}
- bool bShowLeaderLine = rSeries.getPropertiesOfSeries()
- ->getPropertyValue("ShowCustomLeaderLines")
+ bool bShowLeaderLine = rSeries.getModel()
+ ->getFastPropertyValue(PROP_DATASERIES_SHOW_CUSTOM_LEADERLINES) // "ShowCustomLeaderLines"
.get<sal_Bool>();
if (m_bPieLabelsAllowToMove)
{
@@ -493,39 +666,30 @@ void PieChart::createTextLabelShape(
{
sal_Int32 nX1 = aPieLabelInfo.aOuterPosition.getX();
sal_Int32 nY1 = aPieLabelInfo.aOuterPosition.getY();
- sal_Int32 nX2 = nX1;
- sal_Int32 nY2 = nY1;
- if (nX1 < aRect.getMinX())
- nX2 = aRect.getMinX();
- else if (nX1 > aRect.getMaxX())
- nX2 = aRect.getMaxX();
-
- if (nY1 < aRect.getMinY())
- nY2 = aRect.getMinY();
- else if (nY1 > aRect.getMaxY())
- nY2 = aRect.getMaxY();
-
- sal_Int32 nSquaredDistanceFromOrigin
+ const sal_Int32 nX2 = std::clamp(nX1, aRect.getMinX(), aRect.getMaxX());
+ const sal_Int32 nY2 = std::clamp(nY1, aRect.getMinY(), aRect.getMaxY());
+
+ const sal_Int32 nLabelSquaredDistanceFromOrigin
= (nX2 - aOrigin.X) * (nX2 - aOrigin.X) + (nY2 - aOrigin.Y) * (nY2 - aOrigin.Y);
+ // can't use fSquaredPieRadius for 3D charts, since no longer a true circle
+ const sal_Int32 nPieEdgeSquaredDistanceFromOrigin
+ = (nX1 - aOrigin.X) * (nX1 - aOrigin.X) + (nY1 - aOrigin.Y) * (nY1 - aOrigin.Y);
// tdf#138018 Don't show leader line when custom positioned data label is inside pie chart
- if (nSquaredDistanceFromOrigin > fSquaredPieRadius)
+ if (nLabelSquaredDistanceFromOrigin > nPieEdgeSquaredDistanceFromOrigin)
{
//when the line is very short compared to the page size don't create one
::basegfx::B2DVector aLength(nX1 - nX2, nY1 - nY2);
- double fPageDiagonaleLength = sqrt(double(nPageWidth) * double(nPageWidth)
- + double(nPageHeight) * double(nPageHeight));
+ double fPageDiagonaleLength = std::hypot(nPageWidth, nPageHeight);
if ((aLength.getLength() / fPageDiagonaleLength) >= 0.01)
{
drawing::PointSequenceSequence aPoints{ { {nX1, nY1}, {nX2, nY2} } };
- uno::Reference<beans::XPropertySet> xProp(aPieLabelInfo.xTextShape,
- uno::UNO_QUERY);
VLineProperties aVLineProperties;
- if (xProp.is())
+ if (aPieLabelInfo.xTextShape.is())
{
sal_Int32 nColor = 0;
- xProp->getPropertyValue("CharColor") >>= nColor;
+ aPieLabelInfo.xTextShape->SvxShape::getPropertyValue("CharColor") >>= nColor;
//automatic font color does not work for lines -> fallback to black
if (nColor != -1)
aVLineProperties.Color <<= nColor;
@@ -571,19 +735,20 @@ double PieChart::getMaxOffset()
return m_fMaxOffset;
VDataSeries* pSeries = rSeriesList.front().get();
- uno::Reference< beans::XPropertySet > xSeriesProp( pSeries->getPropertiesOfSeries() );
- if( !xSeriesProp.is() )
+ rtl::Reference< DataSeries > xSeries( pSeries->getModel() );
+ if( !xSeries.is() )
return m_fMaxOffset;
double fExplodePercentage=0.0;
- xSeriesProp->getPropertyValue( "Offset") >>= fExplodePercentage;
+ xSeries->getPropertyValue( "Offset") >>= fExplodePercentage;
if(fExplodePercentage>m_fMaxOffset)
m_fMaxOffset=fExplodePercentage;
if(!m_bSizeExcludesLabelsAndExplodedSegments)
{
uno::Sequence< sal_Int32 > aAttributedDataPointIndexList;
- if( xSeriesProp->getPropertyValue( "AttributedDataPoints" ) >>= aAttributedDataPointIndexList )
+ // "AttributedDataPoints"
+ if( xSeries->getFastPropertyValue( PROP_DATASERIES_ATTRIBUTED_DATA_POINTS ) >>= aAttributedDataPointIndexList )
{
for(sal_Int32 nN=aAttributedDataPointIndexList.getLength();nN--;)
{
@@ -694,22 +859,14 @@ 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_pPosHelper->isMathematicalOrientationRadius() && m_bUseRings )
- nExplodeableSlot = m_aZSlots.front().size()-1;
-
m_aLabelInfoList.clear();
m_fMaxOffset = std::numeric_limits<double>::quiet_NaN();
sal_Int32 n3DRelativeHeight = 100;
- uno::Reference< beans::XPropertySet > xPropertySet( m_xChartTypeModel, uno::UNO_QUERY );
- if ( (m_nDimension==3) && xPropertySet.is())
+ if ( (m_nDimension==3) && m_xChartTypeModel.is())
{
try
{
- uno::Any aAny = xPropertySet->getPropertyValue( "3DRelativeHeight" );
+ uno::Any aAny = m_xChartTypeModel->getFastPropertyValue( PROP_PIECHARTTYPE_3DRELATIVEHEIGHT ); // "3DRelativeHeight"
aAny >>= n3DRelativeHeight;
}
catch (const uno::Exception&) { }
@@ -720,8 +877,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;
@@ -729,17 +884,17 @@ 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.
- m_pPosHelper->m_fAngleDegreeOffset = pSeries->getStartingAngle();
+ m_aPosHelper.m_fAngleDegreeOffset = pSeries->getStartingAngle();
///iterate through all points to get the sum of all entries of
///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 );
@@ -752,134 +907,457 @@ 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;
+ }
- double fLogicYForNextPoint = 0.0;
- ///iterate through all points to create shapes
- for( nPointIndex = 0; nPointIndex < nPointCount; nPointIndex++ )
+ 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 (eSubType) {
+ case PieChartSubType_NONE:
+ pDataSrc = &normalPieSrc;
+ createOneRing(SubPieType::NONE, fSlotX, aParam, xSeriesTarget,
+ xTextTarget, pSeries, pDataSrc, n3DRelativeHeight);
+ break;
+ case PieChartSubType_BAR:
{
- 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_pPosHelper->getInnerAndOuterRadius( fSlotX+1.0, fLogicInnerRadius, fLogicOuterRadius, m_bUseRings, fOffset );
- if( !bIsVisible )
- continue;
+ pDataSrc = &ofPieSrc;
+ createOneRing(SubPieType::LEFT, 0, aParam, xSeriesTarget,
+ xTextTarget, pSeries, pDataSrc, n3DRelativeHeight);
+ createOneBar(SubPieType::RIGHT, aParam, xSeriesTarget,
+ xTextTarget, pSeries, pDataSrc, n3DRelativeHeight);
+
+ //
+ // Draw connecting lines
+ //
+ double xl0, xl1, yl0, yl1, x0, y0, x1, y1, y2, y3;
+
+ // Get coordinates of "corners" of left composite wedge
+ sal_Int32 nEnd = pDataSrc->getNPoints(pSeries, SubPieType::LEFT);
+ double compFrac = pDataSrc->getData(pSeries, nEnd - 1,
+ SubPieType::LEFT) / aParam.mfLogicYSum;
+ if (compFrac < 0.5) {
+ xl0 = aParam.mfUnitCircleOuterRadius * m_fLeftScale *
+ cos(compFrac * M_PI) + m_fLeftShift;
+ yl0 = aParam.mfUnitCircleOuterRadius * m_fLeftScale *
+ sin(compFrac * M_PI);
+ } else {
+ xl0 = m_fLeftShift;
+ yl0 = aParam.mfUnitCircleOuterRadius * m_fLeftScale;
+ }
- aParam.mfDepth = getTransformedDepth() * (n3DRelativeHeight / 100.0);
+ // Coordinates of bar top left corner
+ xl1 = m_fBarLeft;
+ yl1 = m_fFullBarHeight / 2;
- 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;
+ x0 = m_aPosHelper.transformUnitCircleToScene(0, xl0, 0).PositionX;
+ y0 = m_aPosHelper.transformUnitCircleToScene(90, yl0, 0).PositionY;
+ x1 = m_aPosHelper.transformUnitCircleToScene(0, xl1, 0).PositionX;
+ y1 = m_aPosHelper.transformUnitCircleToScene(90, yl1, 0).PositionY;
+ y2 = m_aPosHelper.transformUnitCircleToScene(90, -yl0, 0).PositionY;
+ y3 = m_aPosHelper.transformUnitCircleToScene(90, -yl1, 0).PositionY;
+
+ std::vector<std::vector<css::drawing::Position3D>> linePts;
+ linePts.resize(2);
+ linePts[0].push_back(css::drawing::Position3D(x0, y0, aParam.mfLogicZ));
+ linePts[0].push_back(css::drawing::Position3D(x1, y1, aParam.mfLogicZ));
+ linePts[1].push_back(css::drawing::Position3D(x0, y2, aParam.mfLogicZ));
+ linePts[1].push_back(css::drawing::Position3D(x1, y3, aParam.mfLogicZ));
+
+ VLineProperties aVLineProperties; // default black
+
+ //create line
+ rtl::Reference<SvxShapeGroupAnyD> xSeriesGroupShape_Shapes =
+ getSeriesGroupShape(pSeries, xSeriesTarget);
+ rtl::Reference<SvxShape> xShape = ShapeFactory::createLine2D(
+ xSeriesGroupShape_Shapes, linePts, &aVLineProperties);
+
+ // need to set properties?
+ //PropertyMapper::setMappedProperties( *xShape, xObjectProperties,
+ // PropertyMapper::getPropertyNameMapForLineSeriesProperties() );
+
+ break;
+ }
+ case PieChartSubType_PIE:
+ {
+ pDataSrc = &ofPieSrc;
+ createOneRing(SubPieType::LEFT, 0, aParam, xSeriesTarget,
+ xTextTarget, pSeries, pDataSrc, n3DRelativeHeight);
+ createOneRing(SubPieType::RIGHT, 0, aParam, xSeriesTarget,
+ xTextTarget, pSeries, pDataSrc, n3DRelativeHeight);
+
+ //
+ // Draw connecting lines
+ //
+ double xl0, xl1, yl0, yl1, x0, y0, x1, y1, y2, y3;
+
+ // Get coordinates of "corners" of left composite wedge
+ sal_Int32 nEnd = pDataSrc->getNPoints(pSeries, SubPieType::LEFT);
+ double compFrac = pDataSrc->getData(pSeries, nEnd - 1,
+ SubPieType::LEFT) / aParam.mfLogicYSum;
+ // The following isn't quite right. The tangent points on the left
+ // pie are only at pi/2 and -pi/2 for composite wedges over 1/2 the
+ // total if left and right pies are the same diameter. And the
+ // threshold of 1/2 isn't quite right either. So there
+ // really should be a more sophisticated approach here. TODO
+ if (compFrac < 0.5) {
+ // Translated, per below
+ xl0 = aParam.mfUnitCircleOuterRadius * m_fLeftScale *
+ cos(compFrac * M_PI) + m_fLeftShift - m_fRightShift;
+ yl0 = aParam.mfUnitCircleOuterRadius * m_fLeftScale *
+ sin(compFrac * M_PI);
+ } else {
+ // Translated, per below
+ xl0 = m_fLeftShift - m_fRightShift;
+ yl0 = aParam.mfUnitCircleOuterRadius * m_fLeftScale;
+ }
+
+ // Compute tangent point on the right-hand circle of the line
+ // through (xl0, yl0). If we translate things so the right-hand
+ // circle is centered on the origin, then this point (x,y)
+ // satisfies these two equations, where r is the radius of the
+ // right-hand circle:
+ // (1) x^2 + y^2 = r^2
+ // (2) (y - yl0) / (x - xl0) = -x / y
+ const double r = aParam.mfUnitCircleOuterRadius * m_fRightScale;
+
+ xl1 = (r*r * xl0 + yl0 * r * sqrt(xl0*xl0 + yl0*yl0 - r*r)) /
+ (xl0*xl0 + yl0*yl0);
+ yl1 = sqrt(r*r - xl1*xl1);
+
+ // Now translate back to the coordinates we use
+ xl0 += m_fRightShift;
+ xl1 += m_fRightShift;
+
+ x0 = m_aPosHelper.transformUnitCircleToScene(0, xl0, 0).PositionX;
+ y0 = m_aPosHelper.transformUnitCircleToScene(90, yl0, 0).PositionY;
+ x1 = m_aPosHelper.transformUnitCircleToScene(0, xl1, 0).PositionX;
+ y1 = m_aPosHelper.transformUnitCircleToScene(90, yl1, 0).PositionY;
+ y2 = m_aPosHelper.transformUnitCircleToScene(90, -yl0, 0).PositionY;
+ y3 = m_aPosHelper.transformUnitCircleToScene(90, -yl1, 0).PositionY;
+
+ std::vector<std::vector<css::drawing::Position3D>> linePts;
+ linePts.resize(2);
+ linePts[0].push_back(css::drawing::Position3D(x0, y0, aParam.mfLogicZ));
+ linePts[0].push_back(css::drawing::Position3D(x1, y1, aParam.mfLogicZ));
+ linePts[1].push_back(css::drawing::Position3D(x0, y2, aParam.mfLogicZ));
+ linePts[1].push_back(css::drawing::Position3D(x1, y3, aParam.mfLogicZ));
+
+ VLineProperties aVLineProperties; // default black
+
+ //create line
+ rtl::Reference<SvxShapeGroupAnyD> xSeriesGroupShape_Shapes =
+ getSeriesGroupShape(pSeries, xSeriesTarget);
+ rtl::Reference<SvxShape> xShape = ShapeFactory::createLine2D(
+ xSeriesGroupShape_Shapes, linePts, &aVLineProperties);
+
+ break;
+ }
+ default:
+ assert(false); // this shouldn't happen
+ }
+ }//next x slot
+}
+
+static sal_Int32 propIndex(
+ sal_Int32 nPointIndex,
+ enum SubPieType eType,
+ const PieDataSrcBase *pDataSrc,
+ VDataSeries* pSeries)
+{
+
+ switch (eType) {
+ case SubPieType::LEFT:
+ if (nPointIndex == pDataSrc->getNPoints(pSeries,
+ SubPieType::LEFT) - 1) {
+ return pSeries->getTotalPointCount();
+ } else {
+ return nPointIndex;
+ }
+ break;
+ case SubPieType::RIGHT:
+ return pDataSrc->getNPoints(pSeries, SubPieType::LEFT) +
+ nPointIndex - 1;
+ break;
+ case SubPieType::NONE:
+ return nPointIndex;
+ break;
+ default: // shouldn't happen
+ assert(false);
+ return 0; // suppress compile warning
+ }
+}
+
+
+void PieChart::createOneRing(
+ enum SubPieType eType,
+ double fSlotX,
+ 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 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;
+ }
+
+ // 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
+ const double compositeVal = pDataSrc->getData(pSeries, nRingPtCnt - 1, eType);
+ const double degAng = compositeVal * 360 / (ringSum * 2);
+ return m_aPosHelper.clockwiseWedges() ? 360 - degAng : degAng;
+ } 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();
+
+ ///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 < nRingPtCnt; 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 = pDataSrc->getData(pSeries, nPointIndex, eType);
+ 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 =
+ pDataSrc->getProps(pSeries, nPointIndex, eType);
- //iterate through all subsystems to create partial points
+ //iterate through all subsystems to create partial points
+ {
+ //logic values on angle axis:
+ 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
+ ///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_pPosHelper->getWidthAngleDegree( fLogicStartAngleValue, fLogicEndAngleValue );
- aParam.mfUnitCircleStartAngleDegree = m_pPosHelper->transformToAngleDegree( fLogicStartAngleValue );
- aParam.mfUnitCircleInnerRadius = m_pPosHelper->transformToRadius( fLogicInnerRadius );
- aParam.mfUnitCircleOuterRadius = m_pPosHelper->transformToRadius( fLogicOuterRadius );
-
- ///create data point
- aParam.mfLogicZ = -1.0; // For 3D pie chart label position
- rtl::Reference<SvxShape> xPointShape =
- createDataPoint(
- xSeriesGroupShape_Shapes, xPointProperties, aParam);
-
- ///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(eType, xSeriesGroupShape_Shapes,
+ xPointProperties, aParam, nRingPtCnt,
+ bConcentricExplosion);
+
+ // Handle coloring of the composite wedge
+ sal_Int32 nPropIdx = propIndex(nPointIndex, eType, pDataSrc,
+ pSeries);
+
+ ///point color:
+ if (!pSeries->hasPointOwnColor(nPropIdx) && m_xColorScheme.is())
+ {
+ xPointShape->setPropertyValue("FillColor",
+ uno::Any(m_xColorScheme->getColorByIndex( nPropIdx )));
+ }
- if(bHasFillColorMapping)
+ if(bHasFillColorMapping)
+ {
+ double nPropVal = pSeries->getValueByProperty(nPropIdx, "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, nPropIdx, 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_pPosHelper->transformUnitCircleToScene( fAngle, aParam.mfUnitCircleOuterRadius, aParam.mfLogicZ );
- drawing::Position3D aNewOrigin = m_pPosHelper->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(), nPropIdx ) );
+ }
+ 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,
+ nPropIdx ) );
+ }
+ catch( const uno::Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("chart2", "" );
+ }
+ }//next series in x slot (next y slot)
+ }//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);
+
+ sal_Int32 nPropIdx = propIndex(nPointIndex, eType, pDataSrc, pSeries);
+
+ ///point color:
+ if (!pSeries->hasPointOwnColor(nPropIdx) && m_xColorScheme.is())
+ {
+ xPointShape->setPropertyValue("FillColor",
+ uno::Any(m_xColorScheme->getColorByIndex( nPropIdx )));
+ }
+
+
+ if(bHasFillColorMapping)
+ {
+ double nPropVal = pSeries->getValueByProperty(nPropIdx, "FillColor");
+ if(!std::isnan(nPropVal))
+ {
+ xPointShape->setPropertyValue("FillColor", uno::Any(static_cast<sal_Int32>( nPropVal)));
+ }
+ }
+
+ ///create label
+ createTextLabelShape(xTextTarget, *pSeries, nPropIdx, aParam);
+
+ ShapeFactory::setShapeName( xPointShape,
+ ObjectIdentifier::createPointCID( pSeries->getPointCID_Stub(),
+ nPropIdx ) );
+ }//next category
}
PieChart::PieLabelInfo::PieLabelInfo()
@@ -1129,7 +1607,7 @@ bool PieChart::tryMoveLabels( PieLabelInfo const * pFirstBorder, PieLabelInfo co
PieLabelInfo* p2 = pCenter->pNext;
//return true when successful
- bool bLabelOrderIsAntiClockWise = m_pPosHelper->isMathematicalOrientationAngle();
+ bool bLabelOrderIsAntiClockWise = m_aPosHelper.isMathematicalOrientationAngle();
///two loops are performed simultaneously: the outer loop iterates on
///`PieLabelInfo` objects in the list starting from the central element
@@ -1239,7 +1717,7 @@ void PieChart::rearrangeLabelToAvoidOverlapIfRequested( const awt::Size& rPageSi
if(!bMoveableFound)
return;
- double fPageDiagonaleLength = sqrt( double(rPageSize.Width)*double(rPageSize.Width) + double(rPageSize.Height)*double(rPageSize.Height) );
+ double fPageDiagonaleLength = std::hypot(rPageSize.Width, rPageSize.Height);
if( fPageDiagonaleLength == 0.0 )
return;
@@ -1269,20 +1747,11 @@ void PieChart::rearrangeLabelToAvoidOverlapIfRequested( const awt::Size& rPageSi
{
if( labelInfo.bMoved && labelInfo.bShowLeaderLine )
{
+ const basegfx::B2IRectangle aRect(lcl_getRect(labelInfo.xLabelGroupShape));
sal_Int32 nX1 = labelInfo.aOuterPosition.getX();
sal_Int32 nY1 = labelInfo.aOuterPosition.getY();
- sal_Int32 nX2 = nX1;
- sal_Int32 nY2 = nY1;
- ::basegfx::B2IRectangle aRect( lcl_getRect( labelInfo.xLabelGroupShape ) );
- if( nX1 < aRect.getMinX() )
- nX2 = aRect.getMinX();
- else if( nX1 > aRect.getMaxX() )
- nX2 = aRect.getMaxX();
-
- if( nY1 < aRect.getMinY() )
- nY2 = aRect.getMinY();
- else if( nY1 > aRect.getMaxY() )
- nY2 = aRect.getMaxY();
+ const sal_Int32 nX2 = std::clamp(nX1, aRect.getMinX(), aRect.getMaxX());
+ const sal_Int32 nY2 = std::clamp(nY1, aRect.getMinY(), aRect.getMaxY());
//when the line is very short compared to the page size don't create one
::basegfx::B2DVector aLength(nX1-nX2, nY1-nY2);
@@ -1291,11 +1760,10 @@ void PieChart::rearrangeLabelToAvoidOverlapIfRequested( const awt::Size& rPageSi
drawing::PointSequenceSequence aPoints{ { {nX1, nY1}, {nX2, nY2} } };
- uno::Reference< beans::XPropertySet > xProp( labelInfo.xTextShape, uno::UNO_QUERY);
- if( xProp.is() )
+ if( labelInfo.xTextShape.is() )
{
sal_Int32 nColor = 0;
- xProp->getPropertyValue("CharColor") >>= nColor;
+ labelInfo.xTextShape->SvxShape::getPropertyValue("CharColor") >>= nColor;
if( nColor != -1 )//automatic font color does not work for lines -> fallback to black
aVLineProperties.Color <<= nColor;
}
@@ -1394,7 +1862,7 @@ bool PieChart::performLabelBestFitInnerPlacement(ShapeParam& rShapeParam, PieLab
// get the middle point of the arc representing the pie slice border
double fLogicZ = rShapeParam.mfLogicZ + 1.0;
awt::Point aMiddleArcPoint = PlottingPositionHelper::transformSceneToScreenPosition(
- m_pPosHelper->transformUnitCircleToScene(
+ m_aPosHelper.transformUnitCircleToScene(
fBisectingRayAngleDeg,
rShapeParam.mfUnitCircleOuterRadius,
fLogicZ ),
@@ -1480,8 +1948,7 @@ bool PieChart::performLabelBestFitInnerPlacement(ShapeParam& rShapeParam, PieLab
// compute the length of the diagonal vector d,
// that is the distance between P and F
- double fSquaredDistancePF = fDistancePM * fDistancePM + fOrthogonalEdgeLength * fOrthogonalEdgeLength;
- double fDistancePF = sqrt( fSquaredDistancePF );
+ double fDistancePF = std::hypot(fDistancePM, fOrthogonalEdgeLength);
SAL_INFO( "chart2.pie.label.bestfit.inside",
" width = " << fLabelWidth );
@@ -1691,6 +2158,92 @@ bool PieChart::performLabelBestFitInnerPlacement(ShapeParam& rShapeParam, PieLab
return true;
}
+//=======================
+// class PieDataSrc
+//=======================
+double PieDataSrc::getData(const VDataSeries* pSeries, sal_Int32 nPtIdx,
+ [[maybe_unused]] 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 nPts = pSeries->getTotalPointCount();
+ const sal_Int32 n = nPts - 3;
+ if (eType == SubPieType::LEFT) {
+ // nPtIdx should be in [0, n]
+ if (nPtIdx < n) {
+ return pSeries->getPropertiesOfPoint( nPtIdx );
+ } else {
+ // The aggregated wedge
+ assert(nPtIdx == n);
+ return pSeries->getPropertiesOfPoint(nPts);
+ }
+ } 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 5bd25eed53e6..ccbe9cb94d94 100644
--- a/chart2/source/view/charttypes/PieChart.hxx
+++ b/chart2/source/view/charttypes/PieChart.hxx
@@ -21,13 +21,103 @@
#include <memory>
#include <VSeriesPlotter.hxx>
+#include <PlottingPositionHelper.hxx>
#include <basegfx/vector/b2ivector.hxx>
#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
{
-class PiePositionHelper;
+class PiePositionHelper : public PolarPlottingPositionHelper
+{
+public:
+ PiePositionHelper( double fAngleDegreeOffset );
+
+ bool getInnerAndOuterRadius( double fCategoryX, double& fLogicInnerRadius, double& fLogicOuterRadius, bool bUseRings, double fMaxOffset ) const;
+
+ // Determine if the pie wedges are ordered clockwise (returns true) or
+ // counterclockwise (returns false)
+ bool clockwiseWedges() const;
+
+public:
+ //Distance between different category rings, seen relative to width of a ring:
+ double m_fRingDistance; //>=0 m_fRingDistance=1 --> distance == width
+};
+
+enum class SubPieType {
+ NONE, // solo pie or donut
+ LEFT, // left pie in pie-of-pie
+ RIGHT // right pie in pie-of-pie
+};
+
+
+//=======================
+// class PieDataSrcBase
+//=======================
+class PieDataSrcBase
+{
+public:
+ PieDataSrcBase() = default;
+ virtual ~PieDataSrcBase() = default;
+
+ // Number of data points for 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
+{
+public:
+ sal_Int32 getNPoints(const VDataSeries* pSeries,
+ enum SubPieType eType) const;
+
+ double getData(const VDataSeries* pSeries, sal_Int32 nPtIdx,
+ [[maybe_unused]]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 constexpr sal_Int32 minPoints = 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;
@@ -35,7 +125,7 @@ class PieChart : public VSeriesPlotter
public:
PieChart() = delete;
- PieChart( const css::uno::Reference< css::chart2::XChartType >& xChartTypeModel
+ PieChart( const rtl::Reference< ::chart::ChartType >& xChartTypeModel
, sal_Int32 nDimensionCount, bool bExcludingPositioning );
virtual ~PieChart() override;
@@ -65,10 +155,18 @@ public:
private: //methods
rtl::Reference<SvxShape>
createDataPoint(
+ enum SubPieType eType,
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);
+ 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
@@ -107,11 +205,48 @@ 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
+ , const rtl::Reference<SvxShapeGroupAnyD>& xSeriesTarget
+ , const rtl::Reference<SvxShapeGroup>& xTextTarget
+ , VDataSeries* pSeries
+ , 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
- std::unique_ptr<PiePositionHelper>
- m_pPosHelper;
+ // Constants for of-pie charts. Some of these will want to become
+ // user-selectable values. TODO
+
+ // Radius scalings for left and right of-pie subcharts
+ static constexpr double m_fLeftScale = 2.0/3;
+ static constexpr double m_fRightScale = 1.0/3;
+ // Shifts left/right for of-pie subcharts
+ static constexpr double m_fLeftShift = -0.75;
+ static constexpr double m_fRightShift = 0.75;
+ // Height of bar-of-pie bar
+ static constexpr double m_fFullBarHeight = 1.0;
+ // Bar-of-pie bar left side position
+ static constexpr double m_fBarLeft = 0.75;
+ // Bar-of-pie bar right side position
+ static constexpr double m_fBarRight = 1.25;
+
+ PiePositionHelper m_aPosHelper;
+
bool m_bUseRings;
bool m_bSizeExcludesLabelsAndExplodedSegments;
+ ::css::chart2::PieChartSubType m_eSubType;
struct PieLabelInfo
{
@@ -119,8 +254,8 @@ private: //member
bool moveAwayFrom( const PieLabelInfo* pFix, const css::awt::Size& rPageSize
, bool bMoveHalfWay, bool bMoveClockwise );
- css::uno::Reference< css::drawing::XShape > xTextShape;
- css::uno::Reference< css::drawing::XShape > xLabelGroupShape;
+ rtl::Reference< SvxShapeText > xTextShape;
+ rtl::Reference< SvxShapeGroupAnyD > xLabelGroupShape;
::basegfx::B2IVector aFirstPosition;
::basegfx::B2IVector aOuterPosition;
::basegfx::B2IVector aOrigin;
@@ -138,6 +273,7 @@ private: //member
double m_fMaxOffset; /// cached max offset value (init'ed to NaN)
};
+
} //namespace chart
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/chart2/source/view/charttypes/Splines.cxx b/chart2/source/view/charttypes/Splines.cxx
index bd54b266345a..15980b638bc8 100644
--- a/chart2/source/view/charttypes/Splines.cxx
+++ b/chart2/source/view/charttypes/Splines.cxx
@@ -19,12 +19,11 @@
#include "Splines.hxx"
#include <osl/diagnose.h>
-#include <com/sun/star/drawing/PolyPolygonShape3D.hpp>
#include <com/sun/star/drawing/Position3D.hpp>
#include <vector>
#include <algorithm>
-#include <memory>
+#include <optional>
#include <cmath>
#include <limits>
@@ -121,7 +120,7 @@ lcl_SplineCalculation::lcl_SplineCalculation(
m_fYp1( fY1FirstDerivation ),
m_fYpN( fYnFirstDerivation ),
m_nKLow( 0 ),
- m_nKHigh( rSortedPoints.size() - 1 ),
+ m_nKHigh( m_aPoints.size() - 1 ),
m_fLastInterpolatedValue(std::numeric_limits<double>::infinity())
{
Calculate();
@@ -133,7 +132,7 @@ lcl_SplineCalculation::lcl_SplineCalculation(
m_fYp1( 0.0 ), /*dummy*/
m_fYpN( 0.0 ), /*dummy*/
m_nKLow( 0 ),
- m_nKHigh( rSortedPoints.size() - 1 ),
+ m_nKHigh( m_aPoints.size() - 1 ),
m_fLastInterpolatedValue(std::numeric_limits<double>::infinity())
{
CalculatePeriodic();
@@ -411,26 +410,19 @@ bool createParameterT(const tPointVecType& rUniquePoints, double* t)
bool bIsSuccessful = true;
const lcl_tSizeType n = rUniquePoints.size() - 1;
t[0]=0.0;
- double dx = 0.0;
- double dy = 0.0;
- double fDiffMax = 1.0; //dummy values
double fDenominator = 0.0; // initialized for summing up
for (lcl_tSizeType i=1; i<=n ; ++i)
{ // 4th root(dx^2+dy^2)
- dx = rUniquePoints[i].first - rUniquePoints[i-1].first;
- dy = rUniquePoints[i].second - rUniquePoints[i-1].second;
- // scaling to avoid underflow or overflow
- fDiffMax = std::max(fabs(dx), fabs(dy));
- if (fDiffMax == 0.0)
+ double dx = rUniquePoints[i].first - rUniquePoints[i-1].first;
+ double dy = rUniquePoints[i].second - rUniquePoints[i-1].second;
+ if (dx == 0 && dy == 0)
{
bIsSuccessful = false;
break;
}
else
{
- dx /= fDiffMax;
- dy /= fDiffMax;
- fDenominator += sqrt(sqrt(dx * dx + dy * dy)) * sqrt(fDiffMax);
+ fDenominator += sqrt(std::hypot(dx, dy));
}
}
if (fDenominator == 0.0)
@@ -444,13 +436,9 @@ bool createParameterT(const tPointVecType& rUniquePoints, double* t)
double fNumerator = 0.0;
for (lcl_tSizeType i=1; i<=j ; ++i)
{
- dx = rUniquePoints[i].first - rUniquePoints[i-1].first;
- dy = rUniquePoints[i].second - rUniquePoints[i-1].second;
- fDiffMax = std::max(fabs(dx), fabs(dy));
- // same as above, so should not be zero
- dx /= fDiffMax;
- dy /= fDiffMax;
- fNumerator += sqrt(sqrt(dx * dx + dy * dy)) * sqrt(fDiffMax);
+ double dx = rUniquePoints[i].first - rUniquePoints[i-1].first;
+ double dy = rUniquePoints[i].second - rUniquePoints[i-1].second;
+ fNumerator += sqrt(std::hypot(dx, dy));
}
t[j] = fNumerator / fDenominator;
@@ -581,8 +569,8 @@ void SplineCalculater::CalculateCubicSplines(
// generate a spline for each coordinate. It holds the complete
// information to calculate each point of the curve
- std::unique_ptr<lcl_SplineCalculation> aSplineX;
- std::unique_ptr<lcl_SplineCalculation> aSplineY;
+ std::optional<lcl_SplineCalculation> aSplineX;
+ std::optional<lcl_SplineCalculation> aSplineY;
// lcl_SplineCalculation* aSplineZ; the z-coordinates of all points in
// a data series are equal. No spline calculation needed, but copy
// coordinate to output
@@ -592,16 +580,15 @@ void SplineCalculater::CalculateCubicSplines(
pOld[ 0 ].PositionZ == pOld[nMaxIndexPoints].PositionZ &&
nMaxIndexPoints >=2 )
{ // periodic spline
- aSplineX.reset(new lcl_SplineCalculation( std::move(aInputX)));
- aSplineY.reset(new lcl_SplineCalculation( std::move(aInputY)));
- // aSplineZ = new lcl_SplineCalculation( aInputZ) ;
+ aSplineX.emplace(std::move(aInputX));
+ aSplineY.emplace(std::move(aInputY));
}
else // generate the kind "natural spline"
{
double fXDerivation = std::numeric_limits<double>::infinity();
double fYDerivation = std::numeric_limits<double>::infinity();
- aSplineX.reset(new lcl_SplineCalculation( std::move(aInputX), fXDerivation, fXDerivation ));
- aSplineY.reset(new lcl_SplineCalculation( std::move(aInputY), fYDerivation, fYDerivation ));
+ aSplineX.emplace(std::move(aInputX), fXDerivation, fXDerivation);
+ aSplineY.emplace(std::move(aInputY), fYDerivation, fYDerivation);
}
// fill result polygon with calculated values
@@ -690,29 +677,23 @@ void SplineCalculater::CalculateBSplines(
continue; // need at least 2 points, degree p needs at least n+1 points
// next piece of series
- std::unique_ptr<double[]> t(new double [n+1]);
- if (!createParameterT(aPointsIn, t.get()))
+ std::vector<double> t(n + 1);
+ if (!createParameterT(aPointsIn, t.data()))
{
continue; // next piece of series
}
lcl_tSizeType m = n + p + 1;
- std::unique_ptr<double[]> u(new double [m+1]);
- createKnotVector(n, p, t.get(), u.get());
+ std::vector<double> u(m + 1);
+ createKnotVector(n, p, t.data(), u.data());
// The matrix N contains the B-spline basis functions applied to parameters.
// In each row only p+1 adjacent elements are non-zero. The starting
// column in a higher row is equal or greater than in the lower row.
// To store this matrix the non-zero elements are shifted to column 0
// and the amount of shifting is remembered in an array.
- std::unique_ptr<double*[]> aMatN(new double*[n+1]);
- for (lcl_tSizeType row = 0; row <=n; ++row)
- {
- aMatN[row] = new double[p+1];
- for (sal_uInt32 col = 0; col <= p; ++col)
- aMatN[row][col] = 0.0;
- }
- std::unique_ptr<lcl_tSizeType[]> aShift(new lcl_tSizeType[n+1]);
+ std::vector<std::vector<double>> aMatN(n + 1, std::vector<double>(p + 1));
+ std::vector<lcl_tSizeType> aShift(n + 1);
aMatN[0][0] = 1.0; //all others are zero
aShift[0] = 0;
aMatN[n][0] = 1.0;
@@ -732,7 +713,7 @@ void SplineCalculater::CalculateBSplines(
// index in reduced matrix aMatN = (index in full matrix N) - (i-p)
aShift[k] = i - p;
- applyNtoParameterT(i, t[k], p, u.get(), aMatN[k]);
+ applyNtoParameterT(i, t[k], p, u.data(), aMatN[k].data());
} // next row k
// Get matrix C of control points from the matrix equation aMatN * C = aPointsIn
@@ -742,9 +723,6 @@ void SplineCalculater::CalculateBSplines(
lcl_tSizeType c = 0; // true column index
double fDivisor = 1.0; // used for diagonal element
double fEliminate = 1.0; // used for the element, that will become zero
- double fHelp;
- tPointType aHelp;
- lcl_tSizeType nHelp; // used in triangle change
bool bIsSuccessful = true;
for (c = 0 ; c <= n && bIsSuccessful; ++c)
{
@@ -764,18 +742,9 @@ void SplineCalculater::CalculateBSplines(
// exchange total row r with total row c if necessary
if (r != c)
{
- for ( sal_uInt32 i = 0; i <= p ; ++i)
- {
- fHelp = aMatN[r][i];
- aMatN[r][i] = aMatN[c][i];
- aMatN[c][i] = fHelp;
- }
- aHelp = aPointsIn[r];
- aPointsIn[r] = aPointsIn[c];
- aPointsIn[c] = aHelp;
- nHelp = aShift[r];
- aShift[r] = aShift[c];
- aShift[c] = nHelp;
+ std::swap( aMatN[r], aMatN[c] );
+ std::swap( aPointsIn[r], aPointsIn[c] );
+ std::swap( aShift[r], aShift[c] );
}
// divide row c, so that element(c,c) becomes 1
@@ -843,7 +812,7 @@ void SplineCalculater::CalculateBSplines(
pNew[nNewSize -1 ].PositionX = aPointsIn[n].first;
pNew[nNewSize -1 ].PositionY = aPointsIn[n].second;
pNew[nNewSize -1 ].PositionZ = fZCoordinate;
- std::unique_ptr<double[]> aP(new double[m+1]);
+ std::vector<double> aP(m + 1);
lcl_tSizeType nLow = 0;
for ( lcl_tSizeType nTIndex = 0; nTIndex <= n-1; ++nTIndex)
{
@@ -895,10 +864,6 @@ void SplineCalculater::CalculateBSplines(
}
}
}
- for (lcl_tSizeType row = 0; row <=n; ++row)
- {
- delete[] aMatN[row];
- }
} // next piece of the series
}
diff --git a/chart2/source/view/charttypes/VSeriesPlotter.cxx b/chart2/source/view/charttypes/VSeriesPlotter.cxx
index af54871ff49d..b9773494d785 100644
--- a/chart2/source/view/charttypes/VSeriesPlotter.cxx
+++ b/chart2/source/view/charttypes/VSeriesPlotter.cxx
@@ -17,6 +17,7 @@
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
+#include <cstddef>
#include <limits>
#include <memory>
#include <VSeriesPlotter.hxx>
@@ -25,18 +26,23 @@
#include <ShapeFactory.hxx>
#include <Diagram.hxx>
#include <BaseCoordinateSystem.hxx>
+#include <DataSeries.hxx>
+#include <DataSeriesProperties.hxx>
#include <CommonConverters.hxx>
#include <ExplicitCategoriesProvider.hxx>
+#include <FormattedString.hxx>
#include <ObjectIdentifier.hxx>
#include <StatisticsHelper.hxx>
#include <PlottingPositionHelper.hxx>
#include <LabelPositionHelper.hxx>
+#include <ChartType.hxx>
#include <ChartTypeHelper.hxx>
#include <Clipping.hxx>
#include <servicenames_charttypes.hxx>
#include <NumberFormatterWrapper.hxx>
#include <DataSeriesHelper.hxx>
+#include <RegressionCurveModel.hxx>
#include <RegressionCurveHelper.hxx>
#include <VLegendSymbolFactory.hxx>
#include <FormattedStringHelper.hxx>
@@ -61,9 +67,9 @@
#include <com/sun/star/chart/TimeUnit.hpp>
#include <com/sun/star/chart2/MovingAverageType.hpp>
#include <com/sun/star/chart2/XDataPointCustomLabelField.hpp>
-#include <com/sun/star/chart2/XRegressionCurveContainer.hpp>
#include <com/sun/star/container/XChild.hpp>
#include <com/sun/star/chart2/RelativePosition.hpp>
+#include <o3tl/safeint.hxx>
#include <tools/color.hxx>
#include <tools/UnitConversion.hxx>
#include <rtl/ustrbuf.hxx>
@@ -71,13 +77,13 @@
#include <basegfx/vector/b2dvector.hxx>
#include <com/sun/star/drawing/LineStyle.hpp>
#include <com/sun/star/util/XCloneable.hpp>
-#include <com/sun/star/chart2/XCoordinateSystemContainer.hpp>
#include <unotools/localedatawrapper.hxx>
#include <comphelper/sequence.hxx>
+#include <utility>
#include <vcl/svapp.hxx>
#include <vcl/settings.hxx>
-#include <tools/diagnose_ex.h>
+#include <comphelper/diagnose_ex.hxx>
#include <sal/log.hxx>
#include <functional>
@@ -90,6 +96,7 @@ namespace chart {
using namespace ::com::sun::star;
using namespace ::com::sun::star::chart;
using namespace ::com::sun::star::chart2;
+using namespace ::chart::DataSeriesProperties;
using ::com::sun::star::uno::Reference;
using ::com::sun::star::uno::Sequence;
@@ -137,12 +144,11 @@ sal_Int32 VDataSeriesGroup::getSeriesCount() const
return m_aSeriesVector.size();
}
-VSeriesPlotter::VSeriesPlotter( const uno::Reference<XChartType>& xChartTypeModel
+VSeriesPlotter::VSeriesPlotter( rtl::Reference<ChartType> xChartTypeModel
, sal_Int32 nDimensionCount, bool bCategoryXAxis )
: PlotterBase( nDimensionCount )
, m_pMainPosHelper( nullptr )
- , m_xChartTypeModel(xChartTypeModel)
- , m_xChartTypeModelProps( uno::Reference< beans::XPropertySet >::query( xChartTypeModel ))
+ , m_xChartTypeModel(std::move(xChartTypeModel))
, m_bCategoryXAxis(bCategoryXAxis)
, m_nTimeResolution(css::chart::TimeUnit::DAY)
, m_aNullDate(30,12,1899)
@@ -193,7 +199,7 @@ void VSeriesPlotter::addSeries( std::unique_ptr<VDataSeries> pSeries, sal_Int32
pSeries->setXValuesIfNone( m_pExplicitCategoriesProvider->getOriginalCategories() );
}
- if(zSlot<0 || zSlot>=static_cast<sal_Int32>(m_aZSlots.size()))
+ if(zSlot<0 || o3tl::make_unsigned(zSlot)>=m_aZSlots.size())
{
//new z slot
std::vector< VDataSeriesGroup > aZSlot;
@@ -205,7 +211,7 @@ void VSeriesPlotter::addSeries( std::unique_ptr<VDataSeries> pSeries, sal_Int32
//existing zslot
std::vector< VDataSeriesGroup >& rXSlots = m_aZSlots[zSlot];
- if(xSlot<0 || xSlot>=static_cast<sal_Int32>(rXSlots.size()))
+ if(xSlot<0 || o3tl::make_unsigned(xSlot)>=rXSlots.size())
{
//append the series to already existing x series
rXSlots.emplace_back( std::move(pSeries) );
@@ -513,8 +519,8 @@ rtl::Reference<SvxShapeText> VSeriesPlotter::createDataLabel( const rtl::Referen
OUString aRole;
if ( m_xChartTypeModel )
aRole = m_xChartTypeModel->getRoleOfSequenceForSeriesLabel();
- const uno::Reference< XDataSeries >& xSeries( rDataSeries.getModel() );
- pTextList[i] = DataSeriesHelper::getDataSeriesLabel( xSeries, aRole );
+ const rtl::Reference< DataSeries >& xSeries( rDataSeries.getModel() );
+ pTextList[i] = xSeries->getLabelForRole( aRole );
break;
}
case DataPointCustomLabelFieldType_PERCENTAGE:
@@ -571,8 +577,8 @@ rtl::Reference<SvxShapeText> VSeriesPlotter::createDataLabel( const rtl::Referen
OUString aRole;
if ( m_xChartTypeModel )
aRole = m_xChartTypeModel->getRoleOfSequenceForSeriesLabel();
- const uno::Reference< XDataSeries >& xSeries( rDataSeries.getModel() );
- pTextList[1] = DataSeriesHelper::getDataSeriesLabel( xSeries, aRole );
+ const rtl::Reference< DataSeries >& xSeries( rDataSeries.getModel() );
+ pTextList[1] = xSeries->getLabelForRole( aRole );
}
if( pLabel->ShowNumber )
@@ -592,7 +598,7 @@ rtl::Reference<SvxShapeText> VSeriesPlotter::createDataLabel( const rtl::Referen
}
}
- for( auto const & line : std::as_const(aTextList) )
+ for (auto const& line : aTextList)
{
if( !line.isEmpty() )
{
@@ -698,26 +704,20 @@ rtl::Reference<SvxShapeText> VSeriesPlotter::createDataLabel( const rtl::Referen
{
xTextShape->setPosition(aRelPos);
if( !m_xChartTypeModel->getChartType().equalsIgnoreAsciiCase(CHART2_SERVICE_NAME_CHARTTYPE_PIE) &&
- rDataSeries.getPropertiesOfSeries()->getPropertyValue( "ShowCustomLeaderLines" ).get<sal_Bool>())
+ // "ShowCustomLeaderLines"
+ rDataSeries.getModel()->getFastPropertyValue( PROP_DATASERIES_SHOW_CUSTOM_LEADERLINES ).get<sal_Bool>())
{
+ const basegfx::B2IRectangle aRect(
+ BaseGFXHelper::makeRectangle(aRelPos, xTextShape->getSize()));
sal_Int32 nX1 = rScreenPosition2D.X;
sal_Int32 nY1 = rScreenPosition2D.Y;
- sal_Int32 nX2 = nX1;
- sal_Int32 nY2 = nY1;
- ::basegfx::B2IRectangle aRect(BaseGFXHelper::makeRectangle(aRelPos, xTextShape->getSize()));
- if (nX1 < aRelPos.X)
- nX2 = aRelPos.X;
- else if (nX1 > aRect.getMaxX())
- nX2 = aRect.getMaxX();
-
- if (nY1 < aRect.getMinY())
- nY2 = aRect.getMinY();
- else if (nY1 > aRect.getMaxY())
- nY2 = aRect.getMaxY();
+ const sal_Int32 nX2 = std::clamp(nX1, aRelPos.X, aRect.getMaxX());
+ const sal_Int32 nY2 = std::clamp(nY1, aRect.getMinY(), aRect.getMaxY());
//when the line is very short compared to the page size don't create one
::basegfx::B2DVector aLength(nX1 - nX2, nY1 - nY2);
- double fPageDiagonaleLength = sqrt(double(m_aPageReferenceSize.Width)*double(m_aPageReferenceSize.Width) + double(m_aPageReferenceSize.Height)*double(m_aPageReferenceSize.Height));
+ double fPageDiagonaleLength
+ = std::hypot(m_aPageReferenceSize.Width, m_aPageReferenceSize.Height);
if ((aLength.getLength() / fPageDiagonaleLength) >= 0.01)
{
drawing::PointSequenceSequence aPoints{ { {nX1, nY1}, {nX2, nY2} } };
@@ -731,13 +731,11 @@ rtl::Reference<SvxShapeText> VSeriesPlotter::createDataLabel( const rtl::Referen
// in case legend symbol has to be displayed, text shape position is
// slightly changed.
- const awt::Point aUnrotatedTextPos(xTextShape->getPosition());
if( xSymbol.is() )
{
- const awt::Point aOldTextPos( xTextShape->getPosition() );
- awt::Point aNewTextPos( aOldTextPos );
+ awt::Point aNewTextPos(xTextShape->getPosition());
- awt::Point aSymbolPosition( aUnrotatedTextPos );
+ awt::Point aSymbolPosition(aNewTextPos);
awt::Size aSymbolSize( xSymbol->getSize() );
awt::Size aTextSize = xTextShape->getSize();
@@ -1041,7 +1039,21 @@ void VSeriesPlotter::createErrorBar(
fLocalX-=fLength;
aNegative = m_pPosHelper->transformLogicToScene( fLocalX, fLocalY, fZ, true );
}
- bCreateNegativeBorder = m_pPosHelper->isLogicVisible( fLocalX, fLocalY, fZ);
+ if (std::isfinite(aNegative.PositionX) &&
+ std::isfinite(aNegative.PositionY) &&
+ std::isfinite(aNegative.PositionZ)) {
+ bCreateNegativeBorder = m_pPosHelper->isLogicVisible( fLocalX, fLocalY, fZ);
+ } else {
+ // If error bars result in a numerical problem (e.g., an
+ // error bar on a logarithmic chart that results in a point
+ // <= 0) then just turn off the error bar.
+ //
+ // TODO: This perhaps should display a warning, so the user
+ // knows why a bar is not appearing.
+ // TODO: This test could also be added to the positive case,
+ // though a numerical overflow there is less likely.
+ bShowNegative = false;
+ }
}
else
bShowNegative = false;
@@ -1088,10 +1100,7 @@ void VSeriesPlotter::addErrorBorder(
,const rtl::Reference<SvxShapeGroupAnyD>& rTarget
,const uno::Reference< beans::XPropertySet >& rErrorBorderProp )
{
- std::vector<std::vector<css::drawing::Position3D>> aPoly;
- sal_Int32 nSequenceIndex = 0;
- AddPointToPoly( aPoly, rPos0, nSequenceIndex );
- AddPointToPoly( aPoly, rPos1, nSequenceIndex );
+ std::vector<std::vector<css::drawing::Position3D>> aPoly { { rPos0, rPos1} };
rtl::Reference<SvxShapePolyPolygon> xShape = ShapeFactory::createLine2D(
rTarget, aPoly );
PropertyMapper::setMappedProperties( *xShape, rErrorBorderProp,
@@ -1293,24 +1302,23 @@ void VSeriesPlotter::createRegressionCurvesShapes( VDataSeries const & rVDataSer
{
if(m_nDimension!=2)
return;
- uno::Reference< XRegressionCurveContainer > xContainer( rVDataSeries.getModel(), uno::UNO_QUERY );
+ rtl::Reference< DataSeries > xContainer( rVDataSeries.getModel() );
if(!xContainer.is())
return;
if (!m_pPosHelper)
return;
- uno::Sequence< uno::Reference< XRegressionCurve > > aCurveList = xContainer->getRegressionCurves();
+ const std::vector< rtl::Reference< ::chart::RegressionCurveModel > > & aCurveList = xContainer->getRegressionCurves2();
- for(sal_Int32 nN=0; nN<aCurveList.getLength(); nN++)
+ for(std::size_t nN=0; nN<aCurveList.size(); nN++)
{
- uno::Reference< XRegressionCurveCalculator > xCalculator( aCurveList[nN]->getCalculator() );
+ const auto & rCurve = aCurveList[nN];
+ uno::Reference< XRegressionCurveCalculator > xCalculator( rCurve->getCalculator() );
if( !xCalculator.is())
continue;
- uno::Reference< beans::XPropertySet > xProperties( aCurveList[nN], uno::UNO_QUERY );
-
- bool bAverageLine = RegressionCurveHelper::isMeanValueLine( aCurveList[nN] );
+ bool bAverageLine = RegressionCurveHelper::isMeanValueLine( rCurve );
sal_Int32 aDegree = 2;
sal_Int32 aPeriod = 2;
@@ -1320,16 +1328,16 @@ void VSeriesPlotter::createRegressionCurvesShapes( VDataSeries const & rVDataSer
bool bForceIntercept = false;
double aInterceptValue = 0.0;
- if ( xProperties.is() && !bAverageLine )
+ if ( !bAverageLine )
{
- xProperties->getPropertyValue( "PolynomialDegree") >>= aDegree;
- xProperties->getPropertyValue( "MovingAveragePeriod") >>= aPeriod;
- xProperties->getPropertyValue( "MovingAverageType") >>= aMovingAverageType;
- xProperties->getPropertyValue( "ExtrapolateForward") >>= aExtrapolateForward;
- xProperties->getPropertyValue( "ExtrapolateBackward") >>= aExtrapolateBackward;
- xProperties->getPropertyValue( "ForceIntercept") >>= bForceIntercept;
+ rCurve->getPropertyValue( "PolynomialDegree") >>= aDegree;
+ rCurve->getPropertyValue( "MovingAveragePeriod") >>= aPeriod;
+ rCurve->getPropertyValue( "MovingAverageType") >>= aMovingAverageType;
+ rCurve->getPropertyValue( "ExtrapolateForward") >>= aExtrapolateForward;
+ rCurve->getPropertyValue( "ExtrapolateBackward") >>= aExtrapolateBackward;
+ rCurve->getPropertyValue( "ForceIntercept") >>= bForceIntercept;
if (bForceIntercept)
- xProperties->getPropertyValue( "InterceptValue") >>= aInterceptValue;
+ rCurve->getPropertyValue( "InterceptValue") >>= aInterceptValue;
}
double fChartMinX = m_pPosHelper->getLogicMinX();
@@ -1421,7 +1429,7 @@ void VSeriesPlotter::createRegressionCurvesShapes( VDataSeries const & rVDataSer
if( aRegressionPoly.SequenceX.hasElements() && aRegressionPoly.SequenceX[0].hasElements() )
{
VLineProperties aVLineProperties;
- aVLineProperties.initFromPropertySet( xProperties );
+ aVLineProperties.initFromPropertySet( rCurve );
//create an extra group shape for each curve for selection handling
rtl::Reference<SvxShapeGroupAnyD> xRegressionGroupShapes =
@@ -1433,7 +1441,7 @@ void VSeriesPlotter::createRegressionCurvesShapes( VDataSeries const & rVDataSer
}
// curve equation and correlation coefficient
- uno::Reference< beans::XPropertySet > xEquationProperties( aCurveList[nN]->getEquationProperties());
+ uno::Reference< beans::XPropertySet > xEquationProperties( rCurve->getEquationProperties());
if( xEquationProperties.is())
{
createRegressionCurveEquationShapes(
@@ -2289,12 +2297,83 @@ OUString VSeriesPlotter::getCategoryName( sal_Int32 nPointIndex ) const
return OUString();
}
-uno::Sequence< OUString > VSeriesPlotter::getSeriesNames() const
+namespace {
+// The following it to support rendering order for combo charts. A chart type
+// with a lower rendering order is rendered before (i.e., behind) a chart with a
+// higher rendering order. The rendering orders are based on rough guesses about
+// how much one chart (type) will obscure another chart (type). The intent is to
+// minimize obscuring of data, by putting charts that generally cover more
+// pixels (e.g., area charts) behind ones that generally cover fewer (e.g., line
+// charts).
+struct ROrderPair
+{
+ ROrderPair(OUString n, sal_Int32 r) : chartName(n), renderOrder(r) {}
+
+ OUString chartName;
+ sal_Int32 renderOrder;
+};
+
+const ROrderPair pairList[] = {
+ ROrderPair(CHART2_SERVICE_NAME_CHARTTYPE_AREA, 0),
+ ROrderPair(CHART2_SERVICE_NAME_CHARTTYPE_BAR, 6), // bar & column are same
+ ROrderPair(CHART2_SERVICE_NAME_CHARTTYPE_COLUMN, 6),
+ ROrderPair(CHART2_SERVICE_NAME_CHARTTYPE_LINE, 8),
+ ROrderPair(CHART2_SERVICE_NAME_CHARTTYPE_SCATTER, 5),
+ ROrderPair(CHART2_SERVICE_NAME_CHARTTYPE_PIE, 1),
+ ROrderPair(CHART2_SERVICE_NAME_CHARTTYPE_NET, 3),
+ ROrderPair(CHART2_SERVICE_NAME_CHARTTYPE_FILLED_NET, 2),
+ ROrderPair(CHART2_SERVICE_NAME_CHARTTYPE_CANDLESTICK, 7),
+ ROrderPair(CHART2_SERVICE_NAME_CHARTTYPE_BUBBLE, 4)
+};
+} // unnamed
+
+sal_Int32 VSeriesPlotter::getRenderOrder() const
+{
+ OUString aChartType = m_xChartTypeModel->getChartType();
+ for (const auto& elem : pairList) {
+ if (aChartType.equalsIgnoreAsciiCase(elem.chartName)) {
+ return elem.renderOrder;
+ }
+ }
+ SAL_WARN("chart2", "Unsupported chart type in getRenderOrder()");
+ return 0;
+}
+
+std::vector<VDataSeries const*> VSeriesPlotter::getAllSeries() const
+{
+ std::vector<VDataSeries const*> aAllSeries;
+ for (std::vector<VDataSeriesGroup> const & rXSlot : m_aZSlots)
+ {
+ for(VDataSeriesGroup const & rGroup : rXSlot)
+ {
+ for (std::unique_ptr<VDataSeries> const & p : rGroup.m_aSeriesVector)
+ aAllSeries.push_back(p.get());
+ }
+ }
+ return aAllSeries;
+}
+
+
+std::vector<VDataSeries*> VSeriesPlotter::getAllSeries()
+{
+ std::vector<VDataSeries*> aAllSeries;
+ for (std::vector<VDataSeriesGroup> const & rXSlot : m_aZSlots)
+ {
+ for(VDataSeriesGroup const & rGroup : rXSlot)
+ {
+ for (std::unique_ptr<VDataSeries> const & p : rGroup.m_aSeriesVector)
+ aAllSeries.push_back(p.get());
+ }
+ }
+ return aAllSeries;
+}
+
+uno::Sequence<OUString> VSeriesPlotter::getSeriesNames() const
{
std::vector<OUString> aRetVector;
OUString aRole;
- if( m_xChartTypeModel.is() )
+ if (m_xChartTypeModel.is())
aRole = m_xChartTypeModel->getRoleOfSequenceForSeriesLabel();
for (auto const& rGroup : m_aZSlots)
@@ -2305,10 +2384,10 @@ uno::Sequence< OUString > VSeriesPlotter::getSeriesNames() const
if (!rSeriesGroup.m_aSeriesVector.empty())
{
VDataSeries const * pSeries = rSeriesGroup.m_aSeriesVector[0].get();
- uno::Reference< XDataSeries > xSeries( pSeries ? pSeries->getModel() : nullptr );
+ rtl::Reference< DataSeries > xSeries( pSeries ? pSeries->getModel() : nullptr );
if( xSeries.is() )
{
- OUString aSeriesName( DataSeriesHelper::getDataSeriesLabel( xSeries, aRole ) );
+ OUString aSeriesName( xSeries->getLabelForRole( aRole ) );
aRetVector.push_back( aSeriesName );
}
}
@@ -2317,6 +2396,25 @@ uno::Sequence< OUString > VSeriesPlotter::getSeriesNames() const
return comphelper::containerToSequence( aRetVector );
}
+uno::Sequence<OUString> VSeriesPlotter::getAllSeriesNames() const
+{
+ std::vector<OUString> aRetVector;
+
+ OUString aRole;
+ if (m_xChartTypeModel.is())
+ aRole = m_xChartTypeModel->getRoleOfSequenceForSeriesLabel();
+
+ for (VDataSeries const* pSeries : getAllSeries())
+ {
+ if (pSeries)
+ {
+ OUString aSeriesName(pSeries->getModel()->getLabelForRole(aRole));
+ aRetVector.push_back(aSeriesName);
+ }
+ }
+ return comphelper::containerToSequence(aRetVector);
+}
+
void VSeriesPlotter::setPageReferenceSize( const css::awt::Size & rPageRefSize )
{
m_aPageReferenceSize = rPageRefSize;
@@ -2388,7 +2486,8 @@ std::vector< ViewLegendEntry > VSeriesPlotter::createLegendEntries(
if (!pSeries)
continue;
- if (!pSeries->getPropertiesOfSeries()->getPropertyValue("ShowLegendEntry").get<sal_Bool>())
+ // "ShowLegendEntry"
+ if (!pSeries->getModel()->getFastPropertyValue(PROP_DATASERIES_SHOW_LEGEND_ENTRY).get<sal_Bool>())
{
continue;
}
@@ -2434,18 +2533,45 @@ std::vector< ViewLegendEntry > VSeriesPlotter::createLegendEntries(
return aResult;
}
-std::vector<VDataSeries*> VSeriesPlotter::getAllSeries()
+std::vector<ViewLegendSymbol> VSeriesPlotter::createSymbols(const awt::Size& rEntryKeyAspectRatio
+ , const rtl::Reference<SvxShapeGroupAnyD>& xTarget
+ , const Reference<uno::XComponentContext>& xContext)
{
- std::vector<VDataSeries*> aAllSeries;
- for (std::vector<VDataSeriesGroup> const & rXSlot : m_aZSlots)
+ std::vector<ViewLegendSymbol> aResult;
+
+ if( xTarget.is() )
{
- for(VDataSeriesGroup const & rGroup : rXSlot)
+ bool bBreak = false;
+ bool bFirstSeries = true;
+
+ for (std::vector<VDataSeriesGroup> const & rGroupVector : m_aZSlots)
{
- for (std::unique_ptr<VDataSeries> const & p : rGroup.m_aSeriesVector)
- aAllSeries.push_back(p.get());
+ for (VDataSeriesGroup const & rGroup : rGroupVector)
+ {
+ for (std::unique_ptr<VDataSeries> const & pSeries : rGroup.m_aSeriesVector)
+ {
+ if (!pSeries)
+ continue;
+
+ std::vector<ViewLegendSymbol> aSeriesSymbols = createSymbolsForSeries(rEntryKeyAspectRatio, *pSeries, xTarget, xContext);
+
+ //add series entries to the result now
+
+ // use only the first series if VaryColorsByPoint is set for the first series
+ if (bFirstSeries && pSeries->isVaryColorsByPoint())
+ bBreak = true;
+
+ bFirstSeries = false;
+
+ aResult.insert(aResult.end(), aSeriesSymbols.begin(), aSeriesSymbols.end());
+ }
+ if (bBreak)
+ return aResult;
+ }
}
}
- return aAllSeries;
+
+ return aResult;
}
namespace
@@ -2468,19 +2594,11 @@ bool lcl_HasVisibleLine( const uno::Reference< beans::XPropertySet >& xProps, bo
bool lcl_HasRegressionCurves( const VDataSeries& rSeries, bool& rbHasDashedLine )
{
bool bHasRegressionCurves = false;
- Reference< XRegressionCurveContainer > xRegrCont( rSeries.getModel(), uno::UNO_QUERY );
- if( xRegrCont.is())
+ rtl::Reference< DataSeries > xRegrCont( rSeries.getModel() );
+ for( const rtl::Reference< RegressionCurveModel > & rCurve : xRegrCont->getRegressionCurves2() )
{
- Sequence< Reference< XRegressionCurve > > aCurves( xRegrCont->getRegressionCurves() );
- sal_Int32 i = 0, nCount = aCurves.getLength();
- for( i=0; i<nCount; ++i )
- {
- if( aCurves[i].is() )
- {
- bHasRegressionCurves = true;
- lcl_HasVisibleLine( uno::Reference< beans::XPropertySet >( aCurves[i], uno::UNO_QUERY ), rbHasDashedLine );
- }
- }
+ bHasRegressionCurves = true;
+ lcl_HasVisibleLine( rCurve, rbHasDashedLine );
}
return bHasRegressionCurves;
}
@@ -2646,10 +2764,11 @@ std::vector< ViewLegendEntry > VSeriesPlotter::createLegendEntriesForSeries(
CHART2_SERVICE_NAME_CHARTTYPE_PIE);
try
{
- if (bIsPie && m_xChartTypeModelProps.is())
+ if (bIsPie)
{
bool bDonut = false;
- if ((m_xChartTypeModelProps->getPropertyValue("UseRings") >>= bDonut) && bDonut)
+ // "UseRings"
+ if ((m_xChartTypeModel->getFastPropertyValue(PROP_PIECHARTTYPE_USE_RINGS) >>= bDonut) && bDonut)
bIsPie = false;
}
}
@@ -2665,7 +2784,8 @@ std::vector< ViewLegendEntry > VSeriesPlotter::createLegendEntriesForSeries(
Sequence<sal_Int32> deletedLegendEntries;
try
{
- rSeries.getPropertiesOfSeries()->getPropertyValue("DeletedLegendEntries") >>= deletedLegendEntries;
+ // "DeletedLegendEntries"
+ rSeries.getModel()->getFastPropertyValue(PROP_DATASERIES_DELETED_LEGEND_ENTRIES) >>= deletedLegendEntries;
}
catch (const uno::Exception&)
{
@@ -2673,7 +2793,7 @@ std::vector< ViewLegendEntry > VSeriesPlotter::createLegendEntriesForSeries(
for( sal_Int32 nIdx=0; nIdx<aCategoryNames.getLength(); ++nIdx )
{
bool deletedLegendEntry = false;
- for (const auto& deletedLegendEntryIdx : std::as_const(deletedLegendEntries))
+ for (const auto& deletedLegendEntryIdx : deletedLegendEntries)
{
if (nIdx == deletedLegendEntryIdx)
{
@@ -2706,7 +2826,7 @@ std::vector< ViewLegendEntry > VSeriesPlotter::createLegendEntriesForSeries(
aLabelText = aCategoryNames[nIdx];
if( xShape.is() || !aLabelText.isEmpty() )
{
- aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aLabelText, xTextProperties );
+ aEntry.xLabel = FormattedStringHelper::createFormattedString( aLabelText, xTextProperties );
aResult.push_back(aEntry);
}
}
@@ -2731,8 +2851,8 @@ std::vector< ViewLegendEntry > VSeriesPlotter::createLegendEntriesForSeries(
}
// label
- aLabelText = DataSeriesHelper::getDataSeriesLabel( rSeries.getModel(), m_xChartTypeModel.is() ? m_xChartTypeModel->getRoleOfSequenceForSeriesLabel() : "values-y");
- aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aLabelText, xTextProperties );
+ aLabelText = rSeries.getModel()->getLabelForRole( m_xChartTypeModel.is() ? m_xChartTypeModel->getRoleOfSequenceForSeriesLabel() : "values-y");
+ aEntry.xLabel = FormattedStringHelper::createFormattedString( aLabelText, xTextProperties );
aResult.push_back(aEntry);
}
@@ -2742,44 +2862,41 @@ std::vector< ViewLegendEntry > VSeriesPlotter::createLegendEntriesForSeries(
if (!ChartTypeHelper::isSupportingStatisticProperties( m_xChartTypeModel, m_nDimension ))
return aResult;
- Reference< XRegressionCurveContainer > xRegrCont( rSeries.getModel(), uno::UNO_QUERY );
+ rtl::Reference< DataSeries > xRegrCont = rSeries.getModel();
if( xRegrCont.is())
{
- Sequence< Reference< XRegressionCurve > > aCurves( xRegrCont->getRegressionCurves());
- sal_Int32 i = 0, nCount = aCurves.getLength();
+ const std::vector< rtl::Reference< RegressionCurveModel > > & aCurves = xRegrCont->getRegressionCurves2();
+ sal_Int32 i = 0, nCount = aCurves.size();
for( i=0; i<nCount; ++i )
{
- if( aCurves[i].is() )
+ //label
+ OUString aResStr( RegressionCurveHelper::getUINameForRegressionCurve( aCurves[i] ) );
+ replaceParamterInString( aResStr, u"%SERIESNAME", aLabelText );
+ aEntry.xLabel = FormattedStringHelper::createFormattedString( aResStr, xTextProperties );
+
+ // symbol
+ rtl::Reference<SvxShapeGroup> xSymbolGroup(ShapeFactory::createGroup2D( xTarget ));
+
+ // create the symbol
+ rtl::Reference<SvxShapeGroup> xShape = VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio,
+ xSymbolGroup, LegendSymbolStyle::Line,
+ aCurves[i],
+ VLegendSymbolFactory::PropertyType::Line, uno::Any() );
+
+ // set CID to symbol for selection
+ if( xShape.is())
{
- //label
- OUString aResStr( RegressionCurveHelper::getUINameForRegressionCurve( aCurves[i] ) );
- replaceParamterInString( aResStr, "%SERIESNAME", aLabelText );
- aEntry.aLabel = FormattedStringHelper::createFormattedStringSequence( xContext, aResStr, xTextProperties );
-
- // symbol
- rtl::Reference<SvxShapeGroup> xSymbolGroup(ShapeFactory::createGroup2D( xTarget ));
-
- // create the symbol
- rtl::Reference<SvxShapeGroup> xShape = VLegendSymbolFactory::createSymbol( rEntryKeyAspectRatio,
- xSymbolGroup, LegendSymbolStyle::Line,
- Reference< beans::XPropertySet >( aCurves[i], uno::UNO_QUERY ),
- VLegendSymbolFactory::PropertyType::Line, uno::Any() );
-
- // set CID to symbol for selection
- if( xShape.is())
- {
- aEntry.xSymbol = xSymbolGroup;
-
- bool bAverageLine = RegressionCurveHelper::isMeanValueLine( aCurves[i] );
- ObjectType eObjectType = bAverageLine ? OBJECTTYPE_DATA_AVERAGE_LINE : OBJECTTYPE_DATA_CURVE;
- OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( eObjectType, i ) );
- aChildParticle = ObjectIdentifier::addChildParticle( aChildParticle, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) );
- OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle );
- ShapeFactory::setShapeName( xShape, aCID );
- }
+ aEntry.xSymbol = xSymbolGroup;
- aResult.push_back(aEntry);
+ bool bAverageLine = RegressionCurveHelper::isMeanValueLine( aCurves[i] );
+ ObjectType eObjectType = bAverageLine ? OBJECTTYPE_DATA_AVERAGE_LINE : OBJECTTYPE_DATA_CURVE;
+ OUString aChildParticle( ObjectIdentifier::createChildParticleWithIndex( eObjectType, i ) );
+ aChildParticle = ObjectIdentifier::addChildParticle( aChildParticle, ObjectIdentifier::createChildParticleWithIndex( OBJECTTYPE_LEGEND_ENTRY, 0 ) );
+ OUString aCID = ObjectIdentifier::createClassifiedIdentifierForParticles( rSeries.getSeriesParticle(), aChildParticle );
+ ShapeFactory::setShapeName( xShape, aCID );
}
+
+ aResult.push_back(aEntry);
}
}
}
@@ -2790,8 +2907,42 @@ std::vector< ViewLegendEntry > VSeriesPlotter::createLegendEntriesForSeries(
return aResult;
}
+std::vector<ViewLegendSymbol> VSeriesPlotter::createSymbolsForSeries(
+ const awt::Size& rEntryKeyAspectRatio
+ , const VDataSeries& rSeries
+ , const rtl::Reference<SvxShapeGroupAnyD>& xTarget
+ , const Reference<uno::XComponentContext>& xContext)
+{
+ std::vector<ViewLegendSymbol> aResult;
+
+ if (!(xTarget.is() && xContext.is()))
+ return aResult;
+
+ try
+ {
+ ViewLegendSymbol aEntry;
+ // symbol
+ rtl::Reference<SvxShapeGroup> xSymbolGroup(ShapeFactory::createGroup2D(xTarget));
+
+ // create the symbol
+ rtl::Reference<SvxShapeGroup> xShape = createLegendSymbolForSeries(rEntryKeyAspectRatio, rSeries, xSymbolGroup );
+
+ // set CID to symbol for selection
+ if (xShape.is())
+ {
+ aEntry.xSymbol = xSymbolGroup;
+ aResult.push_back(aEntry);
+ }
+ }
+ catch (const uno::Exception &)
+ {
+ DBG_UNHANDLED_EXCEPTION("chart2" );
+ }
+ return aResult;
+}
+
VSeriesPlotter* VSeriesPlotter::createSeriesPlotter(
- const uno::Reference<XChartType>& xChartTypeModel
+ const rtl::Reference<ChartType>& xChartTypeModel
, sal_Int32 nDimensionCount
, bool bExcludingPositioning )
{