diff options
Diffstat (limited to 'chart2/source/view/charttypes/BarChart.cxx')
-rw-r--r-- | chart2/source/view/charttypes/BarChart.cxx | 927 |
1 files changed, 456 insertions, 471 deletions
diff --git a/chart2/source/view/charttypes/BarChart.cxx b/chart2/source/view/charttypes/BarChart.cxx index da7461f38e7a..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> @@ -28,17 +29,13 @@ #include <Clipping.hxx> #include <DateHelper.hxx> #include <svx/scene3d.hxx> -#include <svx/unoshape.hxx> #include <comphelper/scopeguard.hxx> #include <com/sun/star/chart/DataLabelPlacement.hpp> -#include <com/sun/star/chart2/XTransformation.hpp> #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 { @@ -46,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& ) @@ -126,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 @@ -292,12 +286,12 @@ awt::Point BarChart::getLabelScreenPositionAndAlignment( drawing::Position3D aScenePosition3D( pPosHelper-> transformScaledLogicToScene( fX, fY, fZ, true ) ); - return LabelPositionHelper(m_nDimension,m_xLogicTarget,m_pShapeFactory) + return LabelPositionHelper(m_nDimension,m_xLogicTarget) .transformSceneToScreenPosition( aScenePosition3D ); } -uno::Reference< drawing::XShape > BarChart::createDataPoint3D_Bar( - const uno::Reference< drawing::XShapes >& xTarget +rtl::Reference< SvxShape > BarChart::createDataPoint3D_Bar( + const rtl::Reference<SvxShapeGroupAnyD>& xTarget , const drawing::Position3D& rPosition, const drawing::Direction3D& rSize , double fTopHeight, sal_Int32 nRotateZAngleHundredthDegree , const uno::Reference< beans::XPropertySet >& xObjectProperties @@ -319,28 +313,28 @@ uno::Reference< drawing::XShape > BarChart::createDataPoint3D_Bar( TOOLS_WARN_EXCEPTION("chart2", "" ); } - uno::Reference< drawing::XShape > xShape; + rtl::Reference< SvxShape > xShape; switch( nGeometry3D ) { case DataPointGeometry3D::CYLINDER: - xShape = m_pShapeFactory->createCylinder( xTarget, rPosition, rSize, nRotateZAngleHundredthDegree ); + xShape = ShapeFactory::createCylinder( xTarget, rPosition, rSize, nRotateZAngleHundredthDegree ); break; case DataPointGeometry3D::CONE: - xShape = m_pShapeFactory->createCone( xTarget, rPosition, rSize, fTopHeight, nRotateZAngleHundredthDegree ); + xShape = ShapeFactory::createCone( xTarget, rPosition, rSize, fTopHeight, nRotateZAngleHundredthDegree ); break; case DataPointGeometry3D::PYRAMID: - xShape = m_pShapeFactory->createPyramid( xTarget, rPosition, rSize, fTopHeight, nRotateZAngleHundredthDegree>0 + xShape = ShapeFactory::createPyramid( xTarget, rPosition, rSize, fTopHeight, nRotateZAngleHundredthDegree>0 , xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() ); break; case DataPointGeometry3D::CUBOID: default: - xShape = m_pShapeFactory->createCube( xTarget, rPosition, rSize + xShape = ShapeFactory::createCube( xTarget, rPosition, rSize , nRotateZAngleHundredthDegree, xObjectProperties , PropertyMapper::getPropertyNameMapForFilledSeriesProperties(), bRoundedEdges ); return xShape; } if( nGeometry3D != DataPointGeometry3D::PYRAMID ) - setMappedProperties( xShape, xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() ); + PropertyMapper::setMappedProperties( *xShape, xObjectProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() ); return xShape; } @@ -385,30 +379,6 @@ void BarChart::addSeries( std::unique_ptr<VDataSeries> pSeries, sal_Int32 zSlot, VSeriesPlotter::addSeries( std::move(pSeries), zSlot, xSlot, ySlot ); } -namespace { - -//better performance for big data -struct FormerBarPoint -{ - FormerBarPoint( double fX, double fUpperY, double fLowerY, double fZ ) - : m_fX(fX), m_fUpperY(fUpperY), m_fLowerY(fLowerY), m_fZ(fZ) - {} - FormerBarPoint() - { - ::rtl::math::setNan( &m_fX ); - ::rtl::math::setNan( &m_fUpperY ); - ::rtl::math::setNan( &m_fLowerY ); - ::rtl::math::setNan( &m_fZ ); - } - - double m_fX; - double m_fUpperY; - double m_fLowerY; - double m_fZ; -}; - -} - void BarChart::adaptOverlapAndGapwidthForGroupBarsPerAxis() { //adapt m_aOverlapSequence and m_aGapwidthSequence for the groupBarsPerAxis feature @@ -423,33 +393,22 @@ void BarChart::adaptOverlapAndGapwidthForGroupBarsPerAxis() sal_Int32 nUseThisIndex = nAxisIndex; if( nUseThisIndex < 0 || nUseThisIndex >= m_aOverlapSequence.getLength() ) nUseThisIndex = 0; + auto aOverlapSequenceRange = asNonConstRange(m_aOverlapSequence); for( nN = 0; nN < m_aOverlapSequence.getLength(); nN++ ) { if(nN!=nUseThisIndex) - m_aOverlapSequence[nN] = m_aOverlapSequence[nUseThisIndex]; + aOverlapSequenceRange[nN] = m_aOverlapSequence[nUseThisIndex]; } nUseThisIndex = nAxisIndex; if( nUseThisIndex < 0 || nUseThisIndex >= m_aGapwidthSequence.getLength() ) nUseThisIndex = 0; + auto aGapwidthSequenceRange = asNonConstRange(m_aGapwidthSequence); for( nN = 0; nN < m_aGapwidthSequence.getLength(); nN++ ) { if(nN!=nUseThisIndex) - m_aGapwidthSequence[nN] = m_aGapwidthSequence[nUseThisIndex]; - } -} - -static E3dScene* lcl_getE3dScene(uno::Reference<uno::XInterface> const & xInterface) -{ - E3dScene* pScene = nullptr; - - SvxShape* pSvxShape = comphelper::getUnoTunnelImplementation<SvxShape>(xInterface); - if (pSvxShape) - { - SdrObject* pObject = pSvxShape->GetSdrObject(); - pScene = dynamic_cast<E3dScene*>(pObject); + aGapwidthSequenceRange[nN] = m_aGapwidthSequence[nUseThisIndex]; } - return pScene; } void BarChart::createShapes() @@ -457,8 +416,8 @@ void BarChart::createShapes() if( m_aZSlots.empty() ) //no series return; - OSL_ENSURE(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is(),"BarChart is not proper initialized"); - if(!(m_pShapeFactory&&m_xLogicTarget.is()&&m_xFinalTarget.is())) + OSL_ENSURE(m_xLogicTarget.is()&&m_xFinalTarget.is(),"BarChart is not proper initialized"); + if(!(m_xLogicTarget.is()&&m_xFinalTarget.is())) return; //the text labels should be always on top of the other series shapes @@ -468,33 +427,26 @@ void BarChart::createShapes() //the regression curves should always be on top of the bars but beneath the text labels //to achieve this the regression curve target is created after the series target and before the text target - uno::Reference< drawing::XShapes > xSeriesTarget( - createGroupShape( m_xLogicTarget )); - uno::Reference< drawing::XShapes > xRegressionCurveTarget( - createGroupShape( m_xLogicTarget )); - uno::Reference< drawing::XShapes > xTextTarget( - m_pShapeFactory->createGroup2D( m_xFinalTarget )); + rtl::Reference<SvxShapeGroupAnyD> xSeriesTarget = createGroupShape( m_xLogicTarget ); + rtl::Reference<SvxShapeGroupAnyD> xRegressionCurveTarget = createGroupShape( m_xLogicTarget ); + rtl::Reference<SvxShapeGroupAnyD> xTextTarget = ShapeFactory::createGroup2D( m_xFinalTarget ); - uno::Reference< drawing::XShapes > xRegressionCurveEquationTarget( - m_pShapeFactory->createGroup2D( m_xFinalTarget )); + rtl::Reference<SvxShapeGroupAnyD> xRegressionCurveEquationTarget = + ShapeFactory::createGroup2D( m_xFinalTarget ); //check necessary here that different Y axis can not be stacked in the same group? ... hm? - double fLogicZ = 1.0;//as defined - bool bDrawConnectionLines = false; bool bDrawConnectionLinesInited = false; - bool bOnlyConnectionLinesForThisPoint = false; - std::unordered_set<uno::Reference<drawing::XShape>> aShapeSet; + std::unordered_set<rtl::Reference<SvxShape>> aShapeSet; const comphelper::ScopeGuard aGuard([aShapeSet]() { std::unordered_set<E3dScene*> aSceneSet; - for (uno::Reference<drawing::XShape> const & rShape : aShapeSet) + for (rtl::Reference<SvxShape> const & rShape : aShapeSet) { - E3dScene* pScene = lcl_getE3dScene(rShape); - if(nullptr != pScene) + if(E3dScene* pScene = DynCastE3dScene(rShape->GetSdrObject())) { aSceneSet.insert(pScene->getRootE3dSceneFromE3dObject()); } @@ -511,8 +463,6 @@ void BarChart::createShapes() //better performance for big data std::map< VDataSeries*, FormerBarPoint > aSeriesFormerPointMap; m_bPointsWereSkipped = false; - sal_Int32 nSkippedPoints = 0; - sal_Int32 nCreatedPoints = 0; sal_Int32 nStartIndex = 0; sal_Int32 nEndIndex = VSeriesPlotter::getPointCount(); @@ -526,8 +476,7 @@ void BarChart::createShapes() for( auto& rXSlot : rZSlot ) { sal_Int32 nAttachedAxisIndex = rXSlot.getAttachedAxisIndexForFirstSeries(); - if( aLogicYSumMap.find(nAttachedAxisIndex)==aLogicYSumMap.end() ) - aLogicYSumMap[nAttachedAxisIndex]=0.0; + aLogicYSumMap.insert({nAttachedAxisIndex, 0.0}); const sal_Int32 nSlotPoints = rXSlot.getPointCount(); if( nPointIndex >= nSlotPoints ) @@ -547,380 +496,9 @@ void BarChart::createShapes() sal_Int32 nZ=1; for( auto& rZSlot : m_aZSlots ) { - //iterate through all x slots in this category - double fSlotX=0; - for( auto& rXSlot : rZSlot ) - { - sal_Int32 nAttachedAxisIndex = rXSlot.getAttachedAxisIndexForFirstSeries(); - //2ND_AXIS_IN_BARS so far one can assume to have the same plotter for each z slot - BarPositionHelper* pPosHelper = dynamic_cast<BarPositionHelper*>(&( getPlottingPositionHelper( nAttachedAxisIndex ) ) ); - if(!pPosHelper) - pPosHelper = m_pMainPosHelper.get(); - - PlotterBase::m_pPosHelper = pPosHelper; - - //update/create information for current group - pPosHelper->updateSeriesCount( rZSlot.size() ); - double fLogicBaseWidth = pPosHelper->getScaledSlotWidth(); - - // get distance from base value to maximum and minimum - - double fMinimumY = 0.0, fMaximumY = 0.0; - if( nPointIndex < rXSlot.getPointCount()) - rXSlot.calculateYMinAndMaxForCategory( nPointIndex - , isSeparateStackingForDifferentSigns( 1 ), fMinimumY, fMaximumY, nAttachedAxisIndex ); - - double fLogicPositiveYSum = 0.0; - if( !std::isnan( fMaximumY ) ) - fLogicPositiveYSum = fMaximumY; - - double fLogicNegativeYSum = 0.0; - if( !std::isnan( fMinimumY ) ) - fLogicNegativeYSum = fMinimumY; - - if( pPosHelper->isPercentY() ) - { - /* #i70395# fLogicPositiveYSum contains sum of all positive - values, if any, otherwise the highest negative value. - fLogicNegativeYSum contains sum of all negative values, - if any, otherwise the lowest positive value. - Afterwards, fLogicPositiveYSum will contain the maximum - (positive) value that is related to 100%. */ - - // do nothing if there are positive values only - if( fLogicNegativeYSum < 0.0 ) - { - // fLogicPositiveYSum<0 => negative values only, use absolute of negative sum - if( fLogicPositiveYSum < 0.0 ) - fLogicPositiveYSum = -fLogicNegativeYSum; - // otherwise there are positive and negative values, calculate total distance - else - fLogicPositiveYSum -= fLogicNegativeYSum; - } - fLogicNegativeYSum = 0.0; - } - - double fBaseValue = 0.0; - if( !pPosHelper->isPercentY() && rXSlot.m_aSeriesVector.size()<=1 ) - fBaseValue = pPosHelper->getBaseValueY(); - double fPositiveLogicYForNextSeries = fBaseValue; - double fNegativeLogicYForNextSeries = fBaseValue; - - //iterate through all series in this x slot - for( std::unique_ptr<VDataSeries> const & pSeries : rXSlot.m_aSeriesVector ) - { - if(!pSeries) - continue; - - bool bHasFillColorMapping = pSeries->hasPropertyMapping("FillColor"); - - bOnlyConnectionLinesForThisPoint = false; - - if(nPointIndex==nStartIndex)//do not create a regression line for each point - createRegressionCurvesShapes( *pSeries, xRegressionCurveTarget, xRegressionCurveEquationTarget, - m_pPosHelper->maySkipPointsInRegressionCalculation()); - - if( !bDrawConnectionLinesInited ) - { - bDrawConnectionLines = pSeries->getConnectBars(); - if( m_nDimension==3 ) - bDrawConnectionLines = false; - if( bDrawConnectionLines && rXSlot.m_aSeriesVector.size()==1 ) - { - //detect whether we have a stacked chart or not: - StackingDirection eDirection = pSeries->getStackingDirection(); - if( eDirection != StackingDirection_Y_STACKING ) - bDrawConnectionLines = false; - } - bDrawConnectionLinesInited = true; - } - - uno::Reference<drawing::XShapes> xSeriesGroupShape_Shapes(getSeriesGroupShape(pSeries.get(), xSeriesTarget)); - uno::Reference<drawing::XShape> xSeriesGroupShape(xSeriesGroupShape_Shapes, uno::UNO_QUERY); - // Suspend setting rects dirty for the duration of this call - aShapeSet.insert(xSeriesGroupShape); - E3dScene* pScene = lcl_getE3dScene(xSeriesGroupShape); - if (pScene) - pScene->SuspendReportingDirtyRects(); - - //collect data point information (logic coordinates, style ): - double fUnscaledLogicX = pSeries->getXValue( nPointIndex ); - fUnscaledLogicX = DateHelper::RasterizeDateValue( fUnscaledLogicX, m_aNullDate, m_nTimeResolution ); - if(std::isnan(fUnscaledLogicX)) - continue;//point not visible - if(fUnscaledLogicX<pPosHelper->getLogicMinX()) - continue;//point not visible - if(fUnscaledLogicX>pPosHelper->getLogicMaxX()) - continue;//point not visible - if(pPosHelper->isStrongLowerRequested(0) && fUnscaledLogicX==pPosHelper->getLogicMaxX()) - continue;//point not visible - double fLogicX = pPosHelper->getScaledSlotPos( fUnscaledLogicX, fSlotX ); - - double fLogicBarHeight = pSeries->getYValue( nPointIndex ); - if( std::isnan( fLogicBarHeight )) //no value at this category - continue; - - double fLogicValueForLabeDisplay = fLogicBarHeight; - fLogicBarHeight-=fBaseValue; - - if( pPosHelper->isPercentY() ) - { - if(fLogicPositiveYSum!=0.0) - fLogicBarHeight = fabs( fLogicBarHeight )/fLogicPositiveYSum; - else - fLogicBarHeight = 0.0; - } - - // tdf#114141 to draw the top of the zero height 3D bar - // we set a small positive value, here the smallest one for the type double (DBL_MIN) - if( fLogicBarHeight == 0.0 ) - fLogicBarHeight = DBL_MIN; - - //sort negative and positive values, to display them on different sides of the x axis - bool bPositive = fLogicBarHeight >= 0.0; - double fLowerYValue = bPositive ? fPositiveLogicYForNextSeries : fNegativeLogicYForNextSeries; - double fUpperYValue = fLowerYValue+fLogicBarHeight; - if( bPositive ) - fPositiveLogicYForNextSeries += fLogicBarHeight; - else - fNegativeLogicYForNextSeries += fLogicBarHeight; - - if(m_nDimension==3) - fLogicZ = nZ+0.5; - - drawing::Position3D aUnscaledLogicPosition( fUnscaledLogicX, fUpperYValue, fLogicZ ); - - //@todo ... start an iteration over the different breaks of the axis - //each subsystem may add an additional shape to form the whole point - //create a group shape for this point and add to the series shape: - // uno::Reference< drawing::XShapes > xPointGroupShape_Shapes( createGroupShape(xSeriesGroupShape_Shapes) ); - // uno::Reference<drawing::XShape> xPointGroupShape_Shape = - // uno::Reference<drawing::XShape>( xPointGroupShape_Shapes, uno::UNO_QUERY ); - //as long as we do not iterate we do not need to create an additional group for each point - uno::Reference< beans::XPropertySet > xDataPointProperties( pSeries->getPropertiesOfPoint( nPointIndex ) ); - sal_Int32 nGeometry3D = DataPointGeometry3D::CUBOID; - if(m_nDimension==3) try - { - xDataPointProperties->getPropertyValue( "Geometry3D") >>= nGeometry3D; - } - catch( const uno::Exception& ) - { - TOOLS_WARN_EXCEPTION("chart2", "" ); - } - - //@todo iterate through all subsystems to create partial points - { - //@todo select a suitable PositionHelper for this subsystem - BarPositionHelper* pSubPosHelper = pPosHelper; - - double fUnclippedUpperYValue = fUpperYValue; - - //apply clipping to Y - if( !pPosHelper->clipYRange(fLowerYValue,fUpperYValue) ) - { - if( bDrawConnectionLines ) - bOnlyConnectionLinesForThisPoint = true; - else - continue; - } - //@todo clipping of X and Z is not fully integrated so far, as there is a need to create different objects - - //apply scaling to Y before calculating width (necessary to maintain gradient in clipped objects) - pSubPosHelper->doLogicScaling(nullptr,&fLowerYValue,nullptr); - pSubPosHelper->doLogicScaling(nullptr,&fUpperYValue,nullptr); - //scaling of X and Z is not provided as the created objects should be symmetric in that dimensions - - pSubPosHelper->doLogicScaling(nullptr,&fUnclippedUpperYValue,nullptr); - - //calculate resulting width - double fCompleteHeight = bPositive ? fLogicPositiveYSum : fLogicNegativeYSum; - if( pPosHelper->isPercentY() ) - fCompleteHeight = 1.0; - double fLogicBarWidth = fLogicBaseWidth; - double fTopHeight=approxSub(fCompleteHeight,fUpperYValue); - if(!bPositive) - fTopHeight=approxSub(fCompleteHeight,fLowerYValue); - double fLogicYStart = bPositive ? fLowerYValue : fUpperYValue; - double fMiddleHeight = fUpperYValue-fLowerYValue; - if(!bPositive) - fMiddleHeight*=-1.0; - double fLogicBarDepth = 0.5; - if(m_nDimension==3) - { - if( lcl_hasGeometry3DVariableWidth(nGeometry3D) && fCompleteHeight!=0.0 ) - { - double fHeight = fCompleteHeight-fLowerYValue; - if(!bPositive) - fHeight = fCompleteHeight-fUpperYValue; - fLogicBarWidth = fLogicBaseWidth*fHeight/fCompleteHeight; - if(fLogicBarWidth<=0.0) - fLogicBarWidth=fLogicBaseWidth; - fLogicBarDepth = fLogicBarDepth*fHeight/fCompleteHeight; - if(fLogicBarDepth<=0.0) - fLogicBarDepth*=-1.0; - } - } - - //better performance for big data - FormerBarPoint aFormerPoint( aSeriesFormerPointMap[pSeries.get()] ); - pPosHelper->setCoordinateSystemResolution( m_aCoordinateSystemResolution ); - if( !pSeries->isAttributedDataPoint(nPointIndex) - && - pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fUpperY, aFormerPoint.m_fZ - , fLogicX, fUpperYValue, fLogicZ ) - && - pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fLowerY, aFormerPoint.m_fZ - , fLogicX, fLowerYValue, fLogicZ ) - ) - { - nSkippedPoints++; - m_bPointsWereSkipped = true; - continue; - } - aSeriesFormerPointMap[pSeries.get()] = FormerBarPoint(fLogicX,fUpperYValue,fLowerYValue,fLogicZ); - - if( bDrawConnectionLines ) - { - //store point information for connection lines - - drawing::Position3D aLeftUpperPoint( fLogicX-fLogicBarWidth/2.0,fUnclippedUpperYValue,fLogicZ ); - drawing::Position3D aRightUpperPoint( fLogicX+fLogicBarWidth/2.0,fUnclippedUpperYValue,fLogicZ ); - - if( isValidPosition(aLeftUpperPoint) ) - AddPointToPoly( pSeries->m_aPolyPolygonShape3D, aLeftUpperPoint ); - if( isValidPosition(aRightUpperPoint) ) - AddPointToPoly( pSeries->m_aPolyPolygonShape3D, aRightUpperPoint ); - } - - if( bOnlyConnectionLinesForThisPoint ) - continue; - - //maybe additional possibility for performance improvement - //bool bCreateLineInsteadOfComplexGeometryDueToMissingSpace = false; - //pPosHelper->isSameForGivenResolution( fLogicX-fLogicBarWidth/2.0, fLowerYValue, fLogicZ - // , fLogicX+fLogicBarWidth/2.0, fLowerYValue, fLogicZ ); - - nCreatedPoints++; - //create partial point - if( !approxEqual(fLowerYValue,fUpperYValue) ) - { - uno::Reference< drawing::XShape > xShape; - if( m_nDimension==3 ) - { - drawing::Position3D aLogicBottom (fLogicX,fLogicYStart,fLogicZ); - drawing::Position3D aLogicLeftBottomFront (fLogicX+fLogicBarWidth/2.0,fLogicYStart,fLogicZ-fLogicBarDepth/2.0); - drawing::Position3D aLogicRightDeepTop (fLogicX-fLogicBarWidth/2.0,fLogicYStart+fMiddleHeight,fLogicZ+fLogicBarDepth/2.0); - drawing::Position3D aLogicTopTop (fLogicX,fLogicYStart+fMiddleHeight+fTopHeight,fLogicZ); - - uno::Reference< XTransformation > xTransformation = pSubPosHelper->getTransformationScaledLogicToScene(); - - //transformation 3) -> 4) - drawing::Position3D aTransformedBottom ( SequenceToPosition3D( xTransformation->transform( Position3DToSequence(aLogicBottom) ) ) ); - drawing::Position3D aTransformedLeftBottomFront ( SequenceToPosition3D( xTransformation->transform( Position3DToSequence(aLogicLeftBottomFront) ) ) ); - drawing::Position3D aTransformedRightDeepTop ( SequenceToPosition3D( xTransformation->transform( Position3DToSequence(aLogicRightDeepTop) ) ) ); - drawing::Position3D aTransformedTopTop ( SequenceToPosition3D( xTransformation->transform( Position3DToSequence(aLogicTopTop) ) ) ); - - drawing::Direction3D aSize = aTransformedRightDeepTop - aTransformedLeftBottomFront; - drawing::Direction3D aTopSize( aTransformedTopTop - aTransformedRightDeepTop ); - fTopHeight = aTopSize.DirectionY; - - sal_Int32 nRotateZAngleHundredthDegree = 0; - if( pPosHelper->isSwapXAndY() ) - { - fTopHeight = aTopSize.DirectionX; - nRotateZAngleHundredthDegree = 90*100; - aSize = drawing::Direction3D(aSize.DirectionY,aSize.DirectionX,aSize.DirectionZ); - } - - if( aSize.DirectionX < 0 ) - aSize.DirectionX *= -1.0; - if( aSize.DirectionZ < 0 ) - aSize.DirectionZ *= -1.0; - if( fTopHeight < 0 ) - fTopHeight *= -1.0; - - xShape = createDataPoint3D_Bar( - xSeriesGroupShape_Shapes, aTransformedBottom, aSize, fTopHeight, nRotateZAngleHundredthDegree - , xDataPointProperties, nGeometry3D ); - } - else //m_nDimension!=3 - { - // performance improvement: alloc the sequence before the rendering - // otherwise we have 2 realloc calls - drawing::PolyPolygonShape3D aPoly; - aPoly.SequenceX.realloc(1); - aPoly.SequenceY.realloc(1); - aPoly.SequenceZ.realloc(1); - drawing::Position3D aLeftUpperPoint( fLogicX-fLogicBarWidth/2.0,fUpperYValue,fLogicZ ); - drawing::Position3D aRightUpperPoint( fLogicX+fLogicBarWidth/2.0,fUpperYValue,fLogicZ ); - - AddPointToPoly( aPoly, drawing::Position3D( fLogicX-fLogicBarWidth/2.0,fLowerYValue,fLogicZ) ); - AddPointToPoly( aPoly, drawing::Position3D( fLogicX+fLogicBarWidth/2.0,fLowerYValue,fLogicZ) ); - AddPointToPoly( aPoly, aRightUpperPoint ); - AddPointToPoly( aPoly, aLeftUpperPoint ); - AddPointToPoly( aPoly, drawing::Position3D( fLogicX-fLogicBarWidth/2.0,fLowerYValue,fLogicZ) ); - pPosHelper->transformScaledLogicToScene( aPoly ); - xShape = m_pShapeFactory->createArea2D( xSeriesGroupShape_Shapes, aPoly ); - setMappedProperties( xShape, xDataPointProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() ); - } - - if(bHasFillColorMapping) - { - double nPropVal = pSeries->getValueByProperty(nPointIndex, "FillColor"); - if(!std::isnan(nPropVal)) - { - uno::Reference< beans::XPropertySet > xProps( xShape, uno::UNO_QUERY_THROW ); - xProps->setPropertyValue("FillColor", uno::Any(static_cast<sal_Int32>(nPropVal))); - } - } - //set name/classified ObjectID (CID) - ShapeFactory::setShapeName(xShape - , ObjectIdentifier::createPointCID( - pSeries->getPointCID_Stub(),nPointIndex) ); - } - - //create error bar - createErrorBar_Y( aUnscaledLogicPosition, *pSeries, nPointIndex, m_xLogicTarget, &fLogicX ); - - //create data point label - if( pSeries->getDataPointLabelIfLabel(nPointIndex) ) - { - double fLogicSum = aLogicYSumMap[nAttachedAxisIndex]; - - LabelAlignment eAlignment(LABEL_ALIGN_CENTER); - sal_Int32 nLabelPlacement = pSeries->getLabelPlacement( nPointIndex, m_xChartTypeModel, pPosHelper->isSwapXAndY() ); - - double fLowerBarDepth = fLogicBarDepth; - double fUpperBarDepth = fLogicBarDepth; - { - if( lcl_hasGeometry3DVariableWidth(nGeometry3D) && fCompleteHeight!=0.0 ) - { - double fOuterBarDepth = fLogicBarDepth * fTopHeight/(fabs(fCompleteHeight)); - fLowerBarDepth = (fBaseValue < fUpperYValue) ? fabs(fLogicBarDepth) : fabs(fOuterBarDepth); - fUpperBarDepth = (fBaseValue < fUpperYValue) ? fabs(fOuterBarDepth) : fabs(fLogicBarDepth); - } - } - - awt::Point aScreenPosition2D = getLabelScreenPositionAndAlignment( - eAlignment, nLabelPlacement, fLogicX, fLowerYValue, fUpperYValue, fLogicZ, - fLowerBarDepth, fUpperBarDepth, fBaseValue, pPosHelper); - sal_Int32 nOffset = 0; - if(eAlignment!=LABEL_ALIGN_CENTER) - { - nOffset = 100;//add some spacing //@todo maybe get more intelligent values - if( m_nDimension == 3 ) - nOffset = 260; - } - createDataLabel( - xTextTarget, *pSeries, nPointIndex, - fLogicValueForLabeDisplay, fLogicSum, aScreenPosition2D, eAlignment, nOffset); - } - - }//end iteration through partial points - - }//next series in x slot (next y slot) - fSlotX+=1.0; - }//next x slot + doZSlot(bDrawConnectionLines, bDrawConnectionLinesInited, rZSlot, nZ, nPointIndex, nStartIndex, + xSeriesTarget, xRegressionCurveTarget, xRegressionCurveEquationTarget, xTextTarget, + aShapeSet, aSeriesFormerPointMap, aLogicYSumMap); ++nZ; }//next z slot }//next category @@ -928,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; @@ -947,11 +525,11 @@ void BarChart::createShapes() { if(!pSeries) continue; - drawing::PolyPolygonShape3D* pSeriesPoly = &pSeries->m_aPolyPolygonShape3D; + std::vector<std::vector<css::drawing::Position3D>>* pSeriesPoly = &pSeries->m_aPolyPolygonShape3D; if(!ShapeFactory::hasPolygonAnyLines(*pSeriesPoly)) continue; - drawing::PolyPolygonShape3D aPoly; + std::vector<std::vector<css::drawing::Position3D>> aPoly; Clipping::clipPolygonAtRectangle( *pSeriesPoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly ); if(!ShapeFactory::hasPolygonAnyLines(aPoly)) @@ -960,12 +538,10 @@ void BarChart::createShapes() //transformation 3) -> 4) pPosHelper->transformScaledLogicToScene( aPoly ); - uno::Reference< drawing::XShapes > xSeriesGroupShape_Shapes( + rtl::Reference<SvxShapeGroupAnyD> xSeriesGroupShape_Shapes( getSeriesGroupShape(pSeries.get(), xSeriesTarget) ); - uno::Reference< drawing::XShape > xShape( m_pShapeFactory->createLine2D( - xSeriesGroupShape_Shapes, PolyToPointSequence( aPoly ) ) ); - setMappedProperties( xShape, pSeries->getPropertiesOfSeries() - , PropertyMapper::getPropertyNameMapForFilledSeriesProperties() ); + rtl::Reference<SvxShapePolyPolygon> xShape( ShapeFactory::createLine2D( + xSeriesGroupShape_Shapes, aPoly ) ); } } } @@ -973,11 +549,420 @@ void BarChart::createShapes() /* @todo remove series shapes if empty */ +} + +void BarChart::doZSlot( + bool& bDrawConnectionLines, bool& bDrawConnectionLinesInited, + const std::vector< VDataSeriesGroup >& rZSlot, + const sal_Int32 nZ, const sal_Int32 nPointIndex, const sal_Int32 nStartIndex, + 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) +{ + //iterate through all x slots in this category + double fSlotX=0; + for( auto& rXSlot : rZSlot ) + { + sal_Int32 nAttachedAxisIndex = rXSlot.getAttachedAxisIndexForFirstSeries(); + //2ND_AXIS_IN_BARS so far one can assume to have the same plotter for each z slot + BarPositionHelper* pPosHelper = dynamic_cast<BarPositionHelper*>(&( getPlottingPositionHelper( nAttachedAxisIndex ) ) ); + if(!pPosHelper) + pPosHelper = &m_aMainPosHelper; + + PlotterBase::m_pPosHelper = pPosHelper; + + //update/create information for current group + pPosHelper->updateSeriesCount( rZSlot.size() ); + double fLogicBaseWidth = pPosHelper->getScaledSlotWidth(); + + // get distance from base value to maximum and minimum + + double fMinimumY = 0.0, fMaximumY = 0.0; + if( nPointIndex < rXSlot.getPointCount()) + rXSlot.calculateYMinAndMaxForCategory( nPointIndex + , isSeparateStackingForDifferentSigns( 1 ), fMinimumY, fMaximumY, nAttachedAxisIndex ); + + double fLogicPositiveYSum = 0.0; + if( !std::isnan( fMaximumY ) ) + fLogicPositiveYSum = fMaximumY; + + double fLogicNegativeYSum = 0.0; + if( !std::isnan( fMinimumY ) ) + fLogicNegativeYSum = fMinimumY; + + if( pPosHelper->isPercentY() ) + { + /* #i70395# fLogicPositiveYSum contains sum of all positive + values, if any, otherwise the highest negative value. + fLogicNegativeYSum contains sum of all negative values, + if any, otherwise the lowest positive value. + Afterwards, fLogicPositiveYSum will contain the maximum + (positive) value that is related to 100%. */ + + // do nothing if there are positive values only + if( fLogicNegativeYSum < 0.0 ) + { + // fLogicPositiveYSum<0 => negative values only, use absolute of negative sum + if( fLogicPositiveYSum < 0.0 ) + fLogicPositiveYSum = -fLogicNegativeYSum; + // otherwise there are positive and negative values, calculate total distance + else + fLogicPositiveYSum -= fLogicNegativeYSum; + } + fLogicNegativeYSum = 0.0; + } + + doXSlot(rXSlot, bDrawConnectionLines, bDrawConnectionLinesInited, nZ, nPointIndex, nStartIndex, + xSeriesTarget, xRegressionCurveTarget, xRegressionCurveEquationTarget, xTextTarget, + aShapeSet, aSeriesFormerPointMap, aLogicYSumMap, + fLogicBaseWidth, fSlotX, pPosHelper, fLogicPositiveYSum, fLogicNegativeYSum, nAttachedAxisIndex); + + fSlotX+=1.0; + }//next x slot +} + + +void BarChart::doXSlot( + const VDataSeriesGroup& rXSlot, + bool& bDrawConnectionLines, bool& bDrawConnectionLinesInited, + const sal_Int32 nZ, const sal_Int32 nPointIndex, const sal_Int32 nStartIndex, + 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, + const double fLogicBaseWidth, const double fSlotX, + BarPositionHelper* const pPosHelper, + const double fLogicPositiveYSum, const double fLogicNegativeYSum, + const sal_Int32 nAttachedAxisIndex) +{ + double fBaseValue = 0.0; + if( !pPosHelper->isPercentY() && rXSlot.m_aSeriesVector.size()<=1 ) + fBaseValue = pPosHelper->getBaseValueY(); + double fPositiveLogicYForNextSeries = fBaseValue; + double fNegativeLogicYForNextSeries = fBaseValue; + + //iterate through all series in this x slot + for( std::unique_ptr<VDataSeries> const & pSeries : rXSlot.m_aSeriesVector ) + { + if(!pSeries) + continue; + + bool bHasFillColorMapping = pSeries->hasPropertyMapping("FillColor"); + + bool bOnlyConnectionLinesForThisPoint = false; + + if(nPointIndex==nStartIndex)//do not create a regression line for each point + createRegressionCurvesShapes( *pSeries, xRegressionCurveTarget, xRegressionCurveEquationTarget, + m_pPosHelper->maySkipPointsInRegressionCalculation()); + + if( !bDrawConnectionLinesInited ) + { + bDrawConnectionLines = pSeries->getConnectBars(); + if( m_nDimension==3 ) + bDrawConnectionLines = false; + if( bDrawConnectionLines && rXSlot.m_aSeriesVector.size()==1 ) + { + //detect whether we have a stacked chart or not: + StackingDirection eDirection = pSeries->getStackingDirection(); + if( eDirection != StackingDirection_Y_STACKING ) + bDrawConnectionLines = false; + } + bDrawConnectionLinesInited = true; + } + + // Use another XShapes for background, so we can avoid needing to set the Z-order on all of them, + // which is expensive in bulk. + rtl::Reference<SvxShapeGroupAnyD> xSeriesGroupShape_Shapes(getSeriesGroupShape(pSeries.get(), xSeriesTarget)); + rtl::Reference<SvxShapeGroupAnyD> xSeriesBackgroundShape_Shapes(getSeriesGroupShape(pSeries.get(), xSeriesTarget)); + aShapeSet.insert(xSeriesGroupShape_Shapes); + aShapeSet.insert(xSeriesBackgroundShape_Shapes); + // Suspend setting rects dirty for the duration of this call + E3dScene* pScene = DynCastE3dScene(xSeriesGroupShape_Shapes->GetSdrObject()); + if (pScene) + pScene->SuspendReportingDirtyRects(); + pScene = DynCastE3dScene(xSeriesBackgroundShape_Shapes->GetSdrObject()); + if (pScene) + pScene->SuspendReportingDirtyRects(); + + //collect data point information (logic coordinates, style ): + double fUnscaledLogicX = pSeries->getXValue( nPointIndex ); + fUnscaledLogicX = DateHelper::RasterizeDateValue( fUnscaledLogicX, m_aNullDate, m_nTimeResolution ); + if(std::isnan(fUnscaledLogicX)) + continue;//point not visible + if(fUnscaledLogicX<pPosHelper->getLogicMinX()) + continue;//point not visible + if(fUnscaledLogicX>pPosHelper->getLogicMaxX()) + continue;//point not visible + if(pPosHelper->isStrongLowerRequested(0) && fUnscaledLogicX==pPosHelper->getLogicMaxX()) + continue;//point not visible + double fLogicX = pPosHelper->getScaledSlotPos( fUnscaledLogicX, fSlotX ); + + double fLogicBarHeight = pSeries->getYValue( nPointIndex ); + if( std::isnan( fLogicBarHeight )) //no value at this category + continue; + + double fLogicValueForLabeDisplay = fLogicBarHeight; + fLogicBarHeight-=fBaseValue; + + if( pPosHelper->isPercentY() ) + { + if(fLogicPositiveYSum!=0.0) + fLogicBarHeight = fabs( fLogicBarHeight )/fLogicPositiveYSum; + else + fLogicBarHeight = 0.0; + } + + // tdf#114141 to draw the top of the zero height 3D bar + // we set a small positive value, here the smallest one for the type double (DBL_MIN) + if( fLogicBarHeight == 0.0 ) + fLogicBarHeight = DBL_MIN; + + //sort negative and positive values, to display them on different sides of the x axis + bool bPositive = fLogicBarHeight >= 0.0; + double fLowerYValue = bPositive ? fPositiveLogicYForNextSeries : fNegativeLogicYForNextSeries; + double fUpperYValue = fLowerYValue+fLogicBarHeight; + if( bPositive ) + fPositiveLogicYForNextSeries += fLogicBarHeight; + else + fNegativeLogicYForNextSeries += fLogicBarHeight; + + double fLogicZ = 1.0;//as defined + if(m_nDimension==3) + fLogicZ = nZ+0.5; + + drawing::Position3D aUnscaledLogicPosition( fUnscaledLogicX, fUpperYValue, fLogicZ ); + + //@todo ... start an iteration over the different breaks of the axis + //each subsystem may add an additional shape to form the whole point + //create a group shape for this point and add to the series shape: +// uno::Reference< drawing::XShapes > xPointGroupShape_Shapes( createGroupShape(xSeriesGroupShape_Shapes) ); +// uno::Reference<drawing::XShape> xPointGroupShape_Shape = +// uno::Reference<drawing::XShape>( xPointGroupShape_Shapes, uno::UNO_QUERY ); + //as long as we do not iterate we do not need to create an additional group for each point + uno::Reference< beans::XPropertySet > xDataPointProperties( pSeries->getPropertiesOfPoint( nPointIndex ) ); + sal_Int32 nGeometry3D = DataPointGeometry3D::CUBOID; + if(m_nDimension==3) try + { + xDataPointProperties->getPropertyValue( "Geometry3D") >>= nGeometry3D; + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + + //@todo iterate through all subsystems to create partial points + { + //@todo select a suitable PositionHelper for this subsystem + BarPositionHelper* pSubPosHelper = pPosHelper; + + double fUnclippedUpperYValue = fUpperYValue; + + //apply clipping to Y + if( !pPosHelper->clipYRange(fLowerYValue,fUpperYValue) ) + { + if( bDrawConnectionLines ) + bOnlyConnectionLinesForThisPoint = true; + else + continue; + } + //@todo clipping of X and Z is not fully integrated so far, as there is a need to create different objects + + //apply scaling to Y before calculating width (necessary to maintain gradient in clipped objects) + pSubPosHelper->doLogicScaling(nullptr,&fLowerYValue,nullptr); + pSubPosHelper->doLogicScaling(nullptr,&fUpperYValue,nullptr); + //scaling of X and Z is not provided as the created objects should be symmetric in that dimensions + + pSubPosHelper->doLogicScaling(nullptr,&fUnclippedUpperYValue,nullptr); + + //calculate resulting width + double fCompleteHeight = bPositive ? fLogicPositiveYSum : fLogicNegativeYSum; + if( pPosHelper->isPercentY() ) + fCompleteHeight = 1.0; + double fLogicBarWidth = fLogicBaseWidth; + double fTopHeight=approxSub(fCompleteHeight,fUpperYValue); + if(!bPositive) + fTopHeight=approxSub(fCompleteHeight,fLowerYValue); + double fLogicYStart = bPositive ? fLowerYValue : fUpperYValue; + double fMiddleHeight = fUpperYValue-fLowerYValue; + if(!bPositive) + fMiddleHeight*=-1.0; + double fLogicBarDepth = 0.5; + if(m_nDimension==3) + { + if( lcl_hasGeometry3DVariableWidth(nGeometry3D) && fCompleteHeight!=0.0 ) + { + double fHeight = fCompleteHeight-fLowerYValue; + if(!bPositive) + fHeight = fCompleteHeight-fUpperYValue; + fLogicBarWidth = fLogicBaseWidth*fHeight/fCompleteHeight; + if(fLogicBarWidth<=0.0) + fLogicBarWidth=fLogicBaseWidth; + fLogicBarDepth = fLogicBarDepth*fHeight/fCompleteHeight; + if(fLogicBarDepth<=0.0) + fLogicBarDepth*=-1.0; + } + } + + //better performance for big data + FormerBarPoint aFormerPoint( aSeriesFormerPointMap[pSeries.get()] ); + pPosHelper->setCoordinateSystemResolution( m_aCoordinateSystemResolution ); + if( !pSeries->isAttributedDataPoint(nPointIndex) + && + pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fUpperY, aFormerPoint.m_fZ + , fLogicX, fUpperYValue, fLogicZ ) + && + pPosHelper->isSameForGivenResolution( aFormerPoint.m_fX, aFormerPoint.m_fLowerY, aFormerPoint.m_fZ + , fLogicX, fLowerYValue, fLogicZ ) + ) + { + m_bPointsWereSkipped = true; + continue; + } + aSeriesFormerPointMap[pSeries.get()] = FormerBarPoint(fLogicX,fUpperYValue,fLowerYValue,fLogicZ); + + if( bDrawConnectionLines ) + { + //store point information for connection lines + + drawing::Position3D aLeftUpperPoint( fLogicX-fLogicBarWidth/2.0,fUnclippedUpperYValue,fLogicZ ); + drawing::Position3D aRightUpperPoint( fLogicX+fLogicBarWidth/2.0,fUnclippedUpperYValue,fLogicZ ); + + if( isValidPosition(aLeftUpperPoint) ) + AddPointToPoly( pSeries->m_aPolyPolygonShape3D, aLeftUpperPoint ); + if( isValidPosition(aRightUpperPoint) ) + AddPointToPoly( pSeries->m_aPolyPolygonShape3D, aRightUpperPoint ); + } + + if( bOnlyConnectionLinesForThisPoint ) + continue; + + //maybe additional possibility for performance improvement + //bool bCreateLineInsteadOfComplexGeometryDueToMissingSpace = false; + //pPosHelper->isSameForGivenResolution( fLogicX-fLogicBarWidth/2.0, fLowerYValue, fLogicZ + // , fLogicX+fLogicBarWidth/2.0, fLowerYValue, fLogicZ ); + + //create partial point + if( !approxEqual(fLowerYValue,fUpperYValue) ) + { + rtl::Reference< SvxShape > xShape; + if( m_nDimension==3 ) + { + drawing::Position3D aLogicBottom (fLogicX,fLogicYStart,fLogicZ); + drawing::Position3D aLogicLeftBottomFront (fLogicX+fLogicBarWidth/2.0,fLogicYStart,fLogicZ-fLogicBarDepth/2.0); + drawing::Position3D aLogicRightDeepTop (fLogicX-fLogicBarWidth/2.0,fLogicYStart+fMiddleHeight,fLogicZ+fLogicBarDepth/2.0); + drawing::Position3D aLogicTopTop (fLogicX,fLogicYStart+fMiddleHeight+fTopHeight,fLogicZ); + + ::chart::XTransformation2* pTransformation = pSubPosHelper->getTransformationScaledLogicToScene(); + + //transformation 3) -> 4) + drawing::Position3D aTransformedBottom ( pTransformation->transform( aLogicBottom ) ); + drawing::Position3D aTransformedLeftBottomFront ( pTransformation->transform( aLogicLeftBottomFront ) ); + drawing::Position3D aTransformedRightDeepTop ( pTransformation->transform( aLogicRightDeepTop ) ); + drawing::Position3D aTransformedTopTop ( pTransformation->transform( aLogicTopTop ) ); + + drawing::Direction3D aSize = aTransformedRightDeepTop - aTransformedLeftBottomFront; + drawing::Direction3D aTopSize( aTransformedTopTop - aTransformedRightDeepTop ); + fTopHeight = aTopSize.DirectionY; + + sal_Int32 nRotateZAngleHundredthDegree = 0; + if( pPosHelper->isSwapXAndY() ) + { + fTopHeight = aTopSize.DirectionX; + nRotateZAngleHundredthDegree = 90*100; + aSize = drawing::Direction3D(aSize.DirectionY,aSize.DirectionX,aSize.DirectionZ); + } + + if( aSize.DirectionX < 0 ) + aSize.DirectionX *= -1.0; + if( aSize.DirectionZ < 0 ) + aSize.DirectionZ *= -1.0; + if( fTopHeight < 0 ) + fTopHeight *= -1.0; + + xShape = createDataPoint3D_Bar( + xSeriesGroupShape_Shapes, aTransformedBottom, aSize, fTopHeight, nRotateZAngleHundredthDegree + , xDataPointProperties, nGeometry3D ); + } + else //m_nDimension!=3 + { + drawing::Position3D aLeftUpperPoint( fLogicX-fLogicBarWidth/2.0,fUpperYValue,fLogicZ ); + drawing::Position3D aRightUpperPoint( fLogicX+fLogicBarWidth/2.0,fUpperYValue,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 ); + xShape = ShapeFactory::createArea2D( xSeriesGroupShape_Shapes, aPoly ); + PropertyMapper::setMappedProperties( *xShape, xDataPointProperties, PropertyMapper::getPropertyNameMapForFilledSeriesProperties() ); + } + + 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) ); + } + + //create error bar + createErrorBar_Y( aUnscaledLogicPosition, *pSeries, nPointIndex, m_xLogicTarget, &fLogicX ); + + //create data point label + if( pSeries->getDataPointLabelIfLabel(nPointIndex) ) + { + double fLogicSum = aLogicYSumMap[nAttachedAxisIndex]; + + LabelAlignment eAlignment(LABEL_ALIGN_CENTER); + sal_Int32 nLabelPlacement = pSeries->getLabelPlacement( nPointIndex, m_xChartTypeModel, pPosHelper->isSwapXAndY() ); + + double fLowerBarDepth = fLogicBarDepth; + double fUpperBarDepth = fLogicBarDepth; + { + if( lcl_hasGeometry3DVariableWidth(nGeometry3D) && fCompleteHeight!=0.0 ) + { + double fOuterBarDepth = fLogicBarDepth * fTopHeight/(fabs(fCompleteHeight)); + fLowerBarDepth = (fBaseValue < fUpperYValue) ? fabs(fLogicBarDepth) : fabs(fOuterBarDepth); + fUpperBarDepth = (fBaseValue < fUpperYValue) ? fabs(fOuterBarDepth) : fabs(fLogicBarDepth); + } + } + + awt::Point aScreenPosition2D = getLabelScreenPositionAndAlignment( + eAlignment, nLabelPlacement, fLogicX, fLowerYValue, fUpperYValue, fLogicZ, + fLowerBarDepth, fUpperBarDepth, fBaseValue, pPosHelper); + sal_Int32 nOffset = 0; + if(eAlignment!=LABEL_ALIGN_CENTER) + { + nOffset = 100;//add some spacing //@todo maybe get more intelligent values + if( m_nDimension == 3 ) + nOffset = 260; + } + createDataLabel( + xTextTarget, *pSeries, nPointIndex, + fLogicValueForLabeDisplay, fLogicSum, aScreenPosition2D, eAlignment, nOffset); + } + + }//end iteration through partial points - SAL_INFO( - "chart2", - "skipped points: " << nSkippedPoints << " created points: " - << nCreatedPoints); + }//next series in x slot (next y slot) } } //namespace chart |