chart2/source/inc/BaseGFXHelper.hxx | 2 chart2/source/inc/CommonConverters.hxx | 20 + chart2/source/tools/BaseGFXHelper.cxx | 32 + chart2/source/tools/CommonConverters.cxx | 138 ++++++- chart2/source/view/axes/VCartesianGrid.cxx | 12 chart2/source/view/charttypes/AreaChart.cxx | 197 ++++------- chart2/source/view/charttypes/AreaChart.hxx | 10 chart2/source/view/charttypes/BarChart.cxx | 12 chart2/source/view/charttypes/CandleStickChart.cxx | 12 chart2/source/view/charttypes/NetChart.cxx | 31 - chart2/source/view/charttypes/NetChart.hxx | 6 chart2/source/view/charttypes/Splines.cxx | 374 +++++++++++++++++++++ chart2/source/view/charttypes/Splines.hxx | 11 chart2/source/view/charttypes/VSeriesPlotter.cxx | 10 chart2/source/view/inc/Clipping.hxx | 6 chart2/source/view/inc/PlottingPositionHelper.hxx | 1 chart2/source/view/inc/ShapeFactory.hxx | 17 chart2/source/view/inc/VDataSeries.hxx | 3 chart2/source/view/main/Clipping.cxx | 124 ++++++ chart2/source/view/main/PlottingPositionHelper.cxx | 19 + chart2/source/view/main/ShapeFactory.cxx | 213 +++++++++++ chart2/source/view/main/VDataSeries.cxx | 4 22 files changed, 1052 insertions(+), 202 deletions(-)
New commits: commit f242cc6d5be5c6f5446976fd6a7c26ad0cee7683 Author: Noel Grandin <noel.gran...@collabora.co.uk> AuthorDate: Tue Jan 11 14:32:45 2022 +0200 Commit: Noel Grandin <noel.gran...@collabora.co.uk> CommitDate: Tue Jan 11 17:35:32 2022 +0100 use vectors to build up point data, instead of Sequence which shaves 1% off the load time of a large chart Change-Id: Ieb8f029f760f41c3bef63bbc4cd221c1473f0f49 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/128283 Tested-by: Jenkins Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk> diff --git a/chart2/source/inc/BaseGFXHelper.hxx b/chart2/source/inc/BaseGFXHelper.hxx index a5b66d1278f4..fd24fa2b45b6 100644 --- a/chart2/source/inc/BaseGFXHelper.hxx +++ b/chart2/source/inc/BaseGFXHelper.hxx @@ -38,6 +38,8 @@ namespace chart::BaseGFXHelper OOO_DLLPUBLIC_CHARTTOOLS ::basegfx::B3DRange getBoundVolume( const css::drawing::PolyPolygonShape3D& rPolyPoly ); +OOO_DLLPUBLIC_CHARTTOOLS ::basegfx::B3DRange getBoundVolume( const std::vector<std::vector<css::drawing::Position3D>>& rPolyPoly ); + OOO_DLLPUBLIC_CHARTTOOLS ::basegfx::B2IRectangle makeRectangle( const css::awt::Point& rPosition, const css::awt::Size& rSize ); diff --git a/chart2/source/inc/CommonConverters.hxx b/chart2/source/inc/CommonConverters.hxx index 989e4002d148..bbe5ec92cb7b 100644 --- a/chart2/source/inc/CommonConverters.hxx +++ b/chart2/source/inc/CommonConverters.hxx @@ -85,9 +85,16 @@ OOO_DLLPUBLIC_CHARTTOOLS void AddPointToPoly( css::drawing::PolyPolygonShape3D& rPoly , const css::drawing::Position3D& rPos , sal_Int32 nSequenceIndex=0 ); +OOO_DLLPUBLIC_CHARTTOOLS +void AddPointToPoly( std::vector<std::vector<css::drawing::Position3D>>& rPoly + , const css::drawing::Position3D& rPos + , sal_Int32 nSequenceIndex=0 ); /** get a single Point from a Polygon */ +OOO_DLLPUBLIC_CHARTTOOLS css::drawing::Position3D getPointFromPoly( + const std::vector<std::vector<css::drawing::Position3D>>& rPolygon + , sal_Int32 nPointIndex, sal_Int32 nPolyIndex ); OOO_DLLPUBLIC_CHARTTOOLS css::drawing::Position3D getPointFromPoly( const css::drawing::PolyPolygonShape3D& rPolygon , sal_Int32 nPointIndex, sal_Int32 nPolyIndex ); @@ -95,11 +102,14 @@ OOO_DLLPUBLIC_CHARTTOOLS css::drawing::Position3D getPointFromPoly( OOO_DLLPUBLIC_CHARTTOOLS void addPolygon( css::drawing::PolyPolygonShape3D& rRet , const css::drawing::PolyPolygonShape3D& rAdd ); +OOO_DLLPUBLIC_CHARTTOOLS +void addPolygon( std::vector<std::vector<css::drawing::Position3D>>& rRet + , const std::vector<std::vector<css::drawing::Position3D>>& rAdd ); /** PolyPolygonShape3D + PolyPolygonShape3D -> PolyPolygonShape3D */ OOO_DLLPUBLIC_CHARTTOOLS -void appendPoly( css::drawing::PolyPolygonShape3D& rRet - , const css::drawing::PolyPolygonShape3D& rAdd ); +void appendPoly( std::vector<std::vector<css::drawing::Position3D>>& rRet + , const std::vector<std::vector<css::drawing::Position3D>>& rAdd ); /** PolyPolygonBezierCoords -> PolyPolygonShape3D */ @@ -112,12 +122,18 @@ css::drawing::PolyPolygonShape3D BezierToPoly( OOO_DLLPUBLIC_CHARTTOOLS css::drawing::PointSequenceSequence PolyToPointSequence( const css::drawing::PolyPolygonShape3D& rPolyPolygon ); +OOO_DLLPUBLIC_CHARTTOOLS +css::drawing::PointSequenceSequence PolyToPointSequence( + const std::vector<std::vector<css::drawing::Position3D>>& rPolyPolygon ); /** PolyPolygonShape3D -> basegfx::B2DPolyPolygon (2D) */ OOO_DLLPUBLIC_CHARTTOOLS basegfx::B2DPolyPolygon PolyToB2DPolyPolygon( const css::drawing::PolyPolygonShape3D& rPolyPolygon ); +OOO_DLLPUBLIC_CHARTTOOLS +basegfx::B2DPolyPolygon PolyToB2DPolyPolygon( + const std::vector<std::vector<css::drawing::Position3D>>& rPolyPolygon ); /** drawing::PointSequenceSequence + drawing::PointSequenceSequence */ diff --git a/chart2/source/tools/BaseGFXHelper.cxx b/chart2/source/tools/BaseGFXHelper.cxx index 9c475bc759d1..b518e7dd8b8c 100644 --- a/chart2/source/tools/BaseGFXHelper.cxx +++ b/chart2/source/tools/BaseGFXHelper.cxx @@ -60,6 +60,38 @@ namespace chart::BaseGFXHelper return aRet; } +::basegfx::B3DRange getBoundVolume( const std::vector<std::vector<css::drawing::Position3D>>& rPolyPoly ) +{ + ::basegfx::B3DRange aRet; + + bool bInited = false; + sal_Int32 nPolyCount = rPolyPoly.size(); + for(sal_Int32 nPoly = 0; nPoly < nPolyCount; nPoly++) + { + sal_Int32 nPointCount = rPolyPoly[nPoly].size(); + for( sal_Int32 nPoint = 0; nPoint < nPointCount; nPoint++) + { + if(!bInited) + { + aRet = ::basegfx::B3DRange(::basegfx::B3DTuple( + rPolyPoly[nPoly][nPoint].PositionX + , rPolyPoly[nPoly][nPoint].PositionY + , rPolyPoly[nPoly][nPoint].PositionZ)); + bInited = true; + } + else + { + aRet.expand( ::basegfx::B3DTuple( + rPolyPoly[nPoly][nPoint].PositionX + , rPolyPoly[nPoly][nPoint].PositionY + , rPolyPoly[nPoly][nPoint].PositionZ)); + } + } + } + + return aRet; +} + B2IRectangle makeRectangle( const awt::Point& rPos, const awt::Size& rSize ) { return B2IRectangle(rPos.X,rPos.Y,rPos.X+rSize.Width,rPos.Y+rSize.Height); diff --git a/chart2/source/tools/CommonConverters.cxx b/chart2/source/tools/CommonConverters.cxx index 43069cd40ad3..0c8f8bd8665a 100644 --- a/chart2/source/tools/CommonConverters.cxx +++ b/chart2/source/tools/CommonConverters.cxx @@ -181,6 +181,24 @@ void AddPointToPoly( drawing::PolyPolygonShape3D& rPoly, const drawing::Position pInnerSequenceZ[nOldPointCount] = rPos.PositionZ; } +void AddPointToPoly( std::vector<std::vector<css::drawing::Position3D>>& rPoly, const drawing::Position3D& rPos, sal_Int32 nPolygonIndex ) +{ + if(nPolygonIndex<0) + { + OSL_FAIL( "The polygon index needs to be > 0"); + nPolygonIndex=0; + } + + //make sure that we have enough polygons + if(nPolygonIndex >= static_cast<sal_Int32>(rPoly.size()) ) + { + rPoly.resize(nPolygonIndex+1); + } + + std::vector<css::drawing::Position3D>* pOuterSequence = &rPoly[nPolygonIndex]; + pOuterSequence->push_back(rPos); +} + drawing::Position3D getPointFromPoly( const drawing::PolyPolygonShape3D& rPolygon, sal_Int32 nPointIndex, sal_Int32 nPolyIndex ) { drawing::Position3D aRet(0.0,0.0,0.0); @@ -205,6 +223,28 @@ drawing::Position3D getPointFromPoly( const drawing::PolyPolygonShape3D& rPolygo return aRet; } +drawing::Position3D getPointFromPoly( const std::vector<std::vector<css::drawing::Position3D>>& rPolygon, sal_Int32 nPointIndex, sal_Int32 nPolyIndex ) +{ + drawing::Position3D aRet(0.0,0.0,0.0); + + if( nPolyIndex>=0 && nPolyIndex<static_cast<sal_Int32>(rPolygon.size())) + { + if(nPointIndex<static_cast<sal_Int32>(rPolygon[nPolyIndex].size())) + { + aRet = rPolygon[nPolyIndex][nPointIndex]; + } + else + { + OSL_FAIL("polygon was accessed with a wrong index"); + } + } + else + { + OSL_FAIL("polygon was accessed with a wrong index"); + } + return aRet; +} + void addPolygon( drawing::PolyPolygonShape3D& rRet, const drawing::PolyPolygonShape3D& rAdd ) { sal_Int32 nAddOuterCount = rAdd.SequenceX.getLength(); @@ -231,41 +271,51 @@ void addPolygon( drawing::PolyPolygonShape3D& rRet, const drawing::PolyPolygonSh } } -void appendPoly( drawing::PolyPolygonShape3D& rRet, const drawing::PolyPolygonShape3D& rAdd ) +void addPolygon( std::vector<std::vector<css::drawing::Position3D>>& rRet, const std::vector<std::vector<css::drawing::Position3D>>& rAdd ) { - sal_Int32 nOuterCount = std::max( rRet.SequenceX.getLength(), rAdd.SequenceX.getLength() ); - rRet.SequenceX.realloc(nOuterCount); - auto pSequenceX = rRet.SequenceX.getArray(); - rRet.SequenceY.realloc(nOuterCount); - auto pSequenceY = rRet.SequenceY.getArray(); - rRet.SequenceZ.realloc(nOuterCount); - auto pSequenceZ =rRet.SequenceZ.getArray(); + sal_Int32 nAddOuterCount = rAdd.size(); + sal_Int32 nOuterCount = rRet.size() + nAddOuterCount; + rRet.resize( nOuterCount ); + auto pSequence = rRet.data(); + + sal_Int32 nIndex = 0; + sal_Int32 nOuter = nOuterCount - nAddOuterCount; + for( ; nOuter < nOuterCount; nOuter++ ) + { + if( nIndex >= nAddOuterCount ) + break; + + pSequence[nOuter] = rAdd[nIndex]; + + nIndex++; + } +} + +void appendPoly( std::vector<std::vector<css::drawing::Position3D>>& rRet, const std::vector<std::vector<css::drawing::Position3D>>& rAdd ) +{ + sal_Int32 nOuterCount = std::max( rRet.size(), rAdd.size() ); + rRet.resize(nOuterCount); + auto pSequence = rRet.data(); for( sal_Int32 nOuter=0;nOuter<nOuterCount;nOuter++ ) { - sal_Int32 nOldPointCount = rRet.SequenceX[nOuter].getLength(); + sal_Int32 nOldPointCount = rRet[nOuter].size(); sal_Int32 nAddPointCount = 0; - if(nOuter<rAdd.SequenceX.getLength()) - nAddPointCount = rAdd.SequenceX[nOuter].getLength(); + if(nOuter<static_cast<sal_Int32>(rAdd.size())) + nAddPointCount = rAdd[nOuter].size(); if(!nAddPointCount) continue; sal_Int32 nNewPointCount = nOldPointCount + nAddPointCount; - pSequenceX[nOuter].realloc(nNewPointCount); - auto pSequenceX_nOuter = pSequenceX[nOuter].getArray(); - pSequenceY[nOuter].realloc(nNewPointCount); - auto pSequenceY_nOuter = pSequenceY[nOuter].getArray(); - pSequenceZ[nOuter].realloc(nNewPointCount); - auto pSequenceZ_nOuter = pSequenceZ[nOuter].getArray(); + pSequence[nOuter].resize(nNewPointCount); + auto pSequence_nOuter = pSequence[nOuter].data(); sal_Int32 nPointTarget=nOldPointCount; sal_Int32 nPointSource=nAddPointCount; for( ; nPointSource-- ; nPointTarget++ ) { - pSequenceX_nOuter[nPointTarget] = rAdd.SequenceX[nOuter][nPointSource]; - pSequenceY_nOuter[nPointTarget] = rAdd.SequenceY[nOuter][nPointSource]; - pSequenceZ_nOuter[nPointTarget] = rAdd.SequenceZ[nOuter][nPointSource]; + pSequence_nOuter[nPointTarget] = rAdd[nOuter][nPointSource]; } } } @@ -346,6 +396,27 @@ drawing::PointSequenceSequence PolyToPointSequence( return aRet; } +drawing::PointSequenceSequence PolyToPointSequence( + const std::vector<std::vector<css::drawing::Position3D>>& rPolyPolygon ) +{ + drawing::PointSequenceSequence aRet; + aRet.realloc( rPolyPolygon.size() ); + auto pRet = aRet.getArray(); + + for(sal_Int32 nN = 0; nN < static_cast<sal_Int32>(rPolyPolygon.size()); nN++) + { + sal_Int32 nInnerLength = rPolyPolygon[nN].size(); + pRet[nN].realloc( nInnerLength ); + auto pRet_nN = pRet[nN].getArray(); + for( sal_Int32 nM = 0; nM < nInnerLength; nM++) + { + pRet_nN[nM].X = static_cast<sal_Int32>(rPolyPolygon[nN][nM].PositionX); + pRet_nN[nM].Y = static_cast<sal_Int32>(rPolyPolygon[nN][nM].PositionY); + } + } + return aRet; +} + basegfx::B2DPolyPolygon PolyToB2DPolyPolygon( const drawing::PolyPolygonShape3D& rPolyPolygon ) { @@ -373,6 +444,33 @@ basegfx::B2DPolyPolygon PolyToB2DPolyPolygon( return aRetval; } +basegfx::B2DPolyPolygon PolyToB2DPolyPolygon( + const std::vector<std::vector<css::drawing::Position3D>>& rPolyPolygon ) +{ + basegfx::B2DPolyPolygon aRetval; + + for(sal_Int32 nN = 0; nN < static_cast<sal_Int32>(rPolyPolygon.size()); nN++) + { + basegfx::B2DPolygon aNewPolygon; + sal_Int32 nInnerLength = rPolyPolygon[nN].size(); + if(nInnerLength) + { + aNewPolygon.reserve(nInnerLength); + for( sal_Int32 nM = 0; nM < nInnerLength; nM++) + { + auto X = static_cast<sal_Int32>(rPolyPolygon[nN][nM].PositionX); + auto Y = static_cast<sal_Int32>(rPolyPolygon[nN][nM].PositionY); + aNewPolygon.append(basegfx::B2DPoint(X, Y)); + } + // check for closed state flag + basegfx::utils::checkClosed(aNewPolygon); + } + aRetval.append(std::move(aNewPolygon)); + } + + return aRetval; +} + void appendPointSequence( drawing::PointSequenceSequence& rTarget , drawing::PointSequenceSequence& rAdd ) { diff --git a/chart2/source/view/axes/VCartesianGrid.cxx b/chart2/source/view/axes/VCartesianGrid.cxx index 93ebb6eb3e78..283703ba5984 100644 --- a/chart2/source/view/axes/VCartesianGrid.cxx +++ b/chart2/source/view/axes/VCartesianGrid.cxx @@ -149,7 +149,7 @@ static void addLine2D( drawing::PointSequenceSequence& rPoints, sal_Int32 nIndex { static_cast<sal_Int32>(aPB.PositionX), static_cast<sal_Int32>(aPB.PositionY) } }; } -static void addLine3D( drawing::PolyPolygonShape3D& rPoints, sal_Int32 nIndex +static void addLine3D( std::vector<std::vector<css::drawing::Position3D>>& rPoints, sal_Int32 nIndex , const GridLinePoints& rBasePoints , const Reference< XTransformation > & xTransformation ) { @@ -281,10 +281,8 @@ void VCartesianGrid::createShapes() GridLinePoints aGridLinePoints( m_pPosHelper, m_nDimensionIndex, m_eLeftWallPos, m_eBackWallPos, m_eBottomPos ); sal_Int32 nPointCount = (*aDepthIter).size(); - drawing::PolyPolygonShape3D aPoints; - aPoints.SequenceX.realloc(nPointCount); - aPoints.SequenceY.realloc(nPointCount); - aPoints.SequenceZ.realloc(nPointCount); + std::vector<std::vector<css::drawing::Position3D>> aPoints; + aPoints.resize(nPointCount); sal_Int32 nRealPointCount = 0; sal_Int32 nPolyIndex = 0; @@ -301,9 +299,7 @@ void VCartesianGrid::createShapes() nRealPointCount+=3; ++nPolyIndex; } - aPoints.SequenceX.realloc(nRealPointCount); - aPoints.SequenceY.realloc(nRealPointCount); - aPoints.SequenceZ.realloc(nRealPointCount); + aPoints.resize(nRealPointCount); ShapeFactory::createLine3D( xTarget, aPoints, aLinePropertiesList[nDepth] ); } } diff --git a/chart2/source/view/charttypes/AreaChart.cxx b/chart2/source/view/charttypes/AreaChart.cxx index e4864cca63f7..e5409ce5dff1 100644 --- a/chart2/source/view/charttypes/AreaChart.cxx +++ b/chart2/source/view/charttypes/AreaChart.cxx @@ -154,126 +154,95 @@ void AreaChart::addSeries( std::unique_ptr<VDataSeries> pSeries, sal_Int32 zSlot VSeriesPlotter::addSeries( std::move(pSeries), zSlot, xSlot, ySlot ); } -static void lcl_removeDuplicatePoints( drawing::PolyPolygonShape3D& rPolyPoly, PlottingPositionHelper& rPosHelper ) +static void lcl_removeDuplicatePoints( std::vector<std::vector<css::drawing::Position3D>>& rPolyPoly, PlottingPositionHelper& rPosHelper ) { - sal_Int32 nPolyCount = rPolyPoly.SequenceX.getLength(); + sal_Int32 nPolyCount = rPolyPoly.size(); if(!nPolyCount) return; - drawing::PolyPolygonShape3D aTmp; - aTmp.SequenceX.realloc(nPolyCount); - aTmp.SequenceY.realloc(nPolyCount); - aTmp.SequenceZ.realloc(nPolyCount); + // TODO we could do with without a temporary array + std::vector<std::vector<css::drawing::Position3D>> aTmp; + aTmp.resize(nPolyCount); for( sal_Int32 nPolygonIndex = 0; nPolygonIndex<nPolyCount; nPolygonIndex++ ) { - drawing::DoubleSequence* pOuterSourceX = &rPolyPoly.SequenceX.getArray()[nPolygonIndex]; - drawing::DoubleSequence* pOuterSourceY = &rPolyPoly.SequenceY.getArray()[nPolygonIndex]; - drawing::DoubleSequence* pOuterSourceZ = &rPolyPoly.SequenceZ.getArray()[nPolygonIndex]; + std::vector<css::drawing::Position3D>* pOuterSource = &rPolyPoly[nPolygonIndex]; + std::vector<css::drawing::Position3D>* pOuterTarget = &aTmp[nPolygonIndex]; - drawing::DoubleSequence* pOuterTargetX = &aTmp.SequenceX.getArray()[nPolygonIndex]; - drawing::DoubleSequence* pOuterTargetY = &aTmp.SequenceY.getArray()[nPolygonIndex]; - drawing::DoubleSequence* pOuterTargetZ = &aTmp.SequenceZ.getArray()[nPolygonIndex]; - - sal_Int32 nPointCount = pOuterSourceX->getLength(); + sal_Int32 nPointCount = pOuterSource->size(); if( !nPointCount ) continue; - pOuterTargetX->realloc(nPointCount); - pOuterTargetY->realloc(nPointCount); - pOuterTargetZ->realloc(nPointCount); - - double* pSourceX = pOuterSourceX->getArray(); - double* pSourceY = pOuterSourceY->getArray(); - double* pSourceZ = pOuterSourceZ->getArray(); + pOuterTarget->resize(nPointCount); - double* pTargetX = pOuterTargetX->getArray(); - double* pTargetY = pOuterTargetY->getArray(); - double* pTargetZ = pOuterTargetZ->getArray(); + css::drawing::Position3D* pSource = pOuterSource->data(); + css::drawing::Position3D* pTarget = pOuterTarget->data(); //copy first point - *pTargetX=*pSourceX++; - *pTargetY=*pSourceY++; - *pTargetZ=*pSourceZ++; + *pTarget=*pSource++; sal_Int32 nTargetPointCount=1; for( sal_Int32 nSource=1; nSource<nPointCount; nSource++ ) { - if( !rPosHelper.isSameForGivenResolution( *pTargetX, *pTargetY, *pTargetZ - , *pSourceX, *pSourceY, *pSourceZ ) ) + if( !rPosHelper.isSameForGivenResolution( pTarget->PositionX, pTarget->PositionY, pTarget->PositionZ + , pSource->PositionX, pSource->PositionY, pSource->PositionZ ) ) { - pTargetX++; pTargetY++; pTargetZ++; - *pTargetX=*pSourceX; - *pTargetY=*pSourceY; - *pTargetZ=*pSourceZ; + pTarget++; + *pTarget=*pSource; nTargetPointCount++; } - pSourceX++; pSourceY++; pSourceZ++; + pSource++; } //free unused space if( nTargetPointCount<nPointCount ) { - pOuterTargetX->realloc(nTargetPointCount); - pOuterTargetY->realloc(nTargetPointCount); - pOuterTargetZ->realloc(nTargetPointCount); + pOuterTarget->resize(nTargetPointCount); } - pOuterSourceX->realloc(0); - pOuterSourceY->realloc(0); - pOuterSourceZ->realloc(0); + pOuterSource->clear(); } //free space - rPolyPoly.SequenceX.realloc(nPolyCount); - rPolyPoly.SequenceY.realloc(nPolyCount); - rPolyPoly.SequenceZ.realloc(nPolyCount); + rPolyPoly.resize(nPolyCount); - rPolyPoly=aTmp; + rPolyPoly = std::move(aTmp); } -bool AreaChart::create_stepped_line( drawing::PolyPolygonShape3D aStartPoly, chart2::CurveStyle eCurveStyle, PlottingPositionHelper const * pPosHelper, drawing::PolyPolygonShape3D &aPoly ) +bool AreaChart::create_stepped_line( + std::vector<std::vector<css::drawing::Position3D>> aStartPoly, + chart2::CurveStyle eCurveStyle, + PlottingPositionHelper const * pPosHelper, + std::vector<std::vector<css::drawing::Position3D>> &aPoly ) { - sal_uInt32 nOuterCount = aStartPoly.SequenceX.getLength(); + sal_uInt32 nOuterCount = aStartPoly.size(); if ( !nOuterCount ) return false; - drawing::PolyPolygonShape3D aSteppedPoly; - aSteppedPoly.SequenceX.realloc(nOuterCount); - aSteppedPoly.SequenceY.realloc(nOuterCount); - aSteppedPoly.SequenceZ.realloc(nOuterCount); + std::vector<std::vector<css::drawing::Position3D>> aSteppedPoly; + aSteppedPoly.resize(nOuterCount); - auto pSequenceX = aSteppedPoly.SequenceX.getArray(); - auto pSequenceY = aSteppedPoly.SequenceY.getArray(); - auto pSequenceZ = aSteppedPoly.SequenceZ.getArray(); + auto pSequence = aSteppedPoly.data(); for( sal_uInt32 nOuter = 0; nOuter < nOuterCount; ++nOuter ) { - if( aStartPoly.SequenceX[nOuter].getLength() <= 1 ) + if( aStartPoly[nOuter].size() <= 1 ) continue; //we need at least two points - sal_uInt32 nMaxIndexPoints = aStartPoly.SequenceX[nOuter].getLength()-1; // is >1 + sal_uInt32 nMaxIndexPoints = aStartPoly[nOuter].size()-1; // is >1 sal_uInt32 nNewIndexPoints = 0; if ( eCurveStyle==CurveStyle_STEP_START || eCurveStyle==CurveStyle_STEP_END) nNewIndexPoints = nMaxIndexPoints * 2 + 1; else nNewIndexPoints = nMaxIndexPoints * 3 + 1; - const double* pOldX = aStartPoly.SequenceX[nOuter].getConstArray(); - const double* pOldY = aStartPoly.SequenceY[nOuter].getConstArray(); - const double* pOldZ = aStartPoly.SequenceZ[nOuter].getConstArray(); + const css::drawing::Position3D* pOld = aStartPoly[nOuter].data(); - pSequenceX[nOuter].realloc( nNewIndexPoints ); - pSequenceY[nOuter].realloc( nNewIndexPoints ); - pSequenceZ[nOuter].realloc( nNewIndexPoints ); + pSequence[nOuter].resize( nNewIndexPoints ); - double* pNewX = pSequenceX[nOuter].getArray(); - double* pNewY = pSequenceY[nOuter].getArray(); - double* pNewZ = pSequenceZ[nOuter].getArray(); + css::drawing::Position3D* pNew = pSequence[nOuter].data(); - pNewX[0] = pOldX[0]; - pNewY[0] = pOldY[0]; - pNewZ[0] = pOldZ[0]; + pNew[0] = pOld[0]; for( sal_uInt32 oi = 0; oi < nMaxIndexPoints; oi++ ) { switch ( eCurveStyle ) @@ -286,13 +255,11 @@ bool AreaChart::create_stepped_line( drawing::PolyPolygonShape3D aStartPoly, cha O-----+ */ // create the intermediate point - pNewX[1+oi*2] = pOldX[oi+1]; - pNewY[1+oi*2] = pOldY[oi]; - pNewZ[1+oi*2] = pOldZ[oi]; + pNew[1+oi*2].PositionX = pOld[oi+1].PositionX; + pNew[1+oi*2].PositionY = pOld[oi].PositionY; + pNew[1+oi*2].PositionZ = pOld[oi].PositionZ; // and now the normal one - pNewX[1+oi*2+1] = pOldX[oi+1]; - pNewY[1+oi*2+1] = pOldY[oi+1]; - pNewZ[1+oi*2+1] = pOldZ[oi+1]; + pNew[1+oi*2+1] = pOld[oi+1]; break; case CurveStyle_STEP_END: /** +------O @@ -302,13 +269,11 @@ bool AreaChart::create_stepped_line( drawing::PolyPolygonShape3D aStartPoly, cha O */ // create the intermediate point - pNewX[1+oi*2] = pOldX[oi]; - pNewY[1+oi*2] = pOldY[oi+1]; - pNewZ[1+oi*2] = pOldZ[oi]; + pNew[1+oi*2].PositionX = pOld[oi].PositionX; + pNew[1+oi*2].PositionY = pOld[oi+1].PositionY; + pNew[1+oi*2].PositionZ = pOld[oi].PositionZ; // and now the normal one - pNewX[1+oi*2+1] = pOldX[oi+1]; - pNewY[1+oi*2+1] = pOldY[oi+1]; - pNewZ[1+oi*2+1] = pOldZ[oi+1]; + pNew[1+oi*2+1] = pOld[oi+1]; break; case CurveStyle_STEP_CENTER_X: /** +--O @@ -318,17 +283,15 @@ bool AreaChart::create_stepped_line( drawing::PolyPolygonShape3D aStartPoly, cha O--+ */ // create the first intermediate point - pNewX[1+oi*3] = (pOldX[oi]+pOldX[oi+1])/2; - pNewY[1+oi*3] = pOldY[oi]; - pNewZ[1+oi*3] = pOldZ[oi]; + pNew[1+oi*3].PositionX = (pOld[oi].PositionX + pOld[oi+1].PositionX) / 2; + pNew[1+oi*3].PositionY = pOld[oi].PositionY; + pNew[1+oi*3].PositionZ = pOld[oi].PositionZ; // create the second intermediate point - pNewX[1+oi*3+1] = (pOldX[oi]+pOldX[oi+1])/2; - pNewY[1+oi*3+1] = pOldY[oi+1]; - pNewZ[1+oi*3+1] = pOldZ[oi]; + pNew[1+oi*3+1].PositionX = (pOld[oi].PositionX + pOld[oi+1].PositionX) / 2; + pNew[1+oi*3+1].PositionY = pOld[oi+1].PositionY; + pNew[1+oi*3+1].PositionZ = pOld[oi].PositionZ; // and now the normal one - pNewX[1+oi*3+2] = pOldX[oi+1]; - pNewY[1+oi*3+2] = pOldY[oi+1]; - pNewZ[1+oi*3+2] = pOldZ[oi+1]; + pNew[1+oi*3+2] = pOld[oi+1]; break; case CurveStyle_STEP_CENTER_Y: /** O @@ -338,17 +301,15 @@ bool AreaChart::create_stepped_line( drawing::PolyPolygonShape3D aStartPoly, cha O */ // create the first intermediate point - pNewX[1+oi*3] = pOldX[oi]; - pNewY[1+oi*3] = (pOldY[oi]+pOldY[oi+1])/2; - pNewZ[1+oi*3] = pOldZ[oi]; + pNew[1+oi*3].PositionX = pOld[oi].PositionX; + pNew[1+oi*3].PositionY = (pOld[oi].PositionY + pOld[oi+1].PositionY) / 2; + pNew[1+oi*3].PositionZ = pOld[oi].PositionZ; // create the second intermediate point - pNewX[1+oi*3+1] = pOldX[oi+1]; - pNewY[1+oi*3+1] = (pOldY[oi]+pOldY[oi+1])/2; - pNewZ[1+oi*3+1] = pOldZ[oi]; + pNew[1+oi*3+1].PositionX = pOld[oi+1].PositionX; + pNew[1+oi*3+1].PositionY = (pOld[oi].PositionY + pOld[oi+1].PositionY) / 2; + pNew[1+oi*3+1].PositionZ = pOld[oi].PositionZ; // and now the normal one - pNewX[1+oi*3+2] = pOldX[oi+1]; - pNewY[1+oi*3+2] = pOldY[oi+1]; - pNewZ[1+oi*3+2] = pOldZ[oi+1]; + pNew[1+oi*3+2] = pOld[oi+1]; break; default: // this should never be executed @@ -362,23 +323,23 @@ bool AreaChart::create_stepped_line( drawing::PolyPolygonShape3D aStartPoly, cha } bool AreaChart::impl_createLine( VDataSeries* pSeries - , drawing::PolyPolygonShape3D const * pSeriesPoly + , std::vector<std::vector<css::drawing::Position3D>> const * pSeriesPoly , PlottingPositionHelper* pPosHelper ) { //return true if a line was created successfully rtl::Reference<SvxShapeGroupAnyD> xSeriesGroupShape_Shapes = getSeriesGroupShapeBackChild(pSeries, m_xSeriesTarget); - drawing::PolyPolygonShape3D aPoly; + std::vector<std::vector<css::drawing::Position3D>> aPoly; if(m_eCurveStyle==CurveStyle_CUBIC_SPLINES) { - drawing::PolyPolygonShape3D aSplinePoly; + std::vector<std::vector<css::drawing::Position3D>> aSplinePoly; SplineCalculater::CalculateCubicSplines( *pSeriesPoly, aSplinePoly, m_nCurveResolution ); lcl_removeDuplicatePoints( aSplinePoly, *pPosHelper ); Clipping::clipPolygonAtRectangle( aSplinePoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly ); } else if(m_eCurveStyle==CurveStyle_B_SPLINES) { - drawing::PolyPolygonShape3D aSplinePoly; + std::vector<std::vector<css::drawing::Position3D>> aSplinePoly; SplineCalculater::CalculateBSplines( *pSeriesPoly, aSplinePoly, m_nCurveResolution, m_nSplineOrder ); lcl_removeDuplicatePoints( aSplinePoly, *pPosHelper ); Clipping::clipPolygonAtRectangle( aSplinePoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly ); @@ -411,20 +372,15 @@ bool AreaChart::impl_createLine( VDataSeries* pSeries if(m_nDimension==3) { double fDepth = getTransformedDepth(); - sal_Int32 nPolyCount = aPoly.SequenceX.getLength(); + sal_Int32 nPolyCount = aPoly.size(); for(sal_Int32 nPoly=0;nPoly<nPolyCount;nPoly++) { - sal_Int32 nPointCount = aPoly.SequenceX[nPoly].getLength(); + sal_Int32 nPointCount = aPoly[nPoly].size(); for(sal_Int32 nPoint=0;nPoint<nPointCount-1;nPoint++) { drawing::Position3D aPoint1, aPoint2; - aPoint1.PositionX = aPoly.SequenceX[nPoly][nPoint+1]; - aPoint1.PositionY = aPoly.SequenceY[nPoly][nPoint+1]; - aPoint1.PositionZ = aPoly.SequenceZ[nPoly][nPoint+1]; - - aPoint2.PositionX = aPoly.SequenceX[nPoly][nPoint]; - aPoint2.PositionY = aPoly.SequenceY[nPoly][nPoint]; - aPoint2.PositionZ = aPoly.SequenceZ[nPoly][nPoint]; + aPoint1 = aPoly[nPoly][nPoint+1]; + aPoint2 = aPoly[nPoly][nPoint]; ShapeFactory::createStripe(xSeriesGroupShape_Shapes , Stripe( aPoint1, aPoint2, fDepth ) @@ -434,8 +390,7 @@ bool AreaChart::impl_createLine( VDataSeries* pSeries } else //m_nDimension!=3 { - xShape = ShapeFactory::createLine2D( xSeriesGroupShape_Shapes - , PolyToPointSequence( aPoly ) ); + xShape = ShapeFactory::createLine2D( xSeriesGroupShape_Shapes, aPoly ); PropertyMapper::setMappedProperties( *xShape , pSeries->getPropertiesOfSeries() , PropertyMapper::getPropertyNameMapForLineSeriesProperties() ); @@ -446,8 +401,8 @@ bool AreaChart::impl_createLine( VDataSeries* pSeries } bool AreaChart::impl_createArea( VDataSeries* pSeries - , drawing::PolyPolygonShape3D const * pSeriesPoly - , drawing::PolyPolygonShape3D const * pPreviousSeriesPoly + , std::vector<std::vector<css::drawing::Position3D>> const * pSeriesPoly + , std::vector<std::vector<css::drawing::Position3D>> const * pPreviousSeriesPoly , PlottingPositionHelper const * pPosHelper ) { //return true if an area was created successfully @@ -455,7 +410,7 @@ bool AreaChart::impl_createArea( VDataSeries* pSeries rtl::Reference<SvxShapeGroupAnyD> xSeriesGroupShape_Shapes = getSeriesGroupShapeBackChild(pSeries, m_xSeriesTarget); double zValue = pSeries->m_fLogicZPos; - drawing::PolyPolygonShape3D aPoly( *pSeriesPoly ); + std::vector<std::vector<css::drawing::Position3D>> aPoly( *pSeriesPoly ); //add second part to the polygon (grounding points or previous series points) if(!pPreviousSeriesPoly) { @@ -488,7 +443,7 @@ bool AreaChart::impl_createArea( VDataSeries* pSeries //apply clipping { - drawing::PolyPolygonShape3D aClippedPoly; + std::vector<std::vector<css::drawing::Position3D>> aClippedPoly; Clipping::clipPolygonAtRectangle( aPoly, pPosHelper->getScaledLogicClipDoubleRect(), aClippedPoly, false ); ShapeFactory::closePolygon(aClippedPoly); //again necessary after clipping aPoly = aClippedPoly; @@ -533,8 +488,8 @@ void AreaChart::impl_createSeriesShapes() { for( auto const& rXSlot : rZSlot ) { - std::map< sal_Int32, drawing::PolyPolygonShape3D* > aPreviousSeriesPolyMap;//a PreviousSeriesPoly for each different nAttachedAxisIndex - drawing::PolyPolygonShape3D* pSeriesPoly = nullptr; + std::map< sal_Int32, std::vector<std::vector<css::drawing::Position3D>>* > aPreviousSeriesPolyMap;//a PreviousSeriesPoly for each different nAttachedAxisIndex + std::vector<std::vector<css::drawing::Position3D>>* pSeriesPoly = nullptr; //iterate through all series for( std::unique_ptr<VDataSeries> const & pSeries : rXSlot.m_aSeriesVector ) @@ -746,11 +701,11 @@ void AreaChart::createShapes() { if( pSeries->getMissingValueTreatment() == css::chart::MissingValueTreatment::LEAVE_GAP ) { - drawing::PolyPolygonShape3D& rPolygon = pSeries->m_aPolyPolygonShape3D; + std::vector<std::vector<css::drawing::Position3D>>& rPolygon = pSeries->m_aPolyPolygonShape3D; sal_Int32& rIndex = pSeries->m_nPolygonIndex; - if( 0<= rIndex && rIndex < rPolygon.SequenceX.getLength() ) + if( 0<= rIndex && rIndex < static_cast<sal_Int32>(rPolygon.size()) ) { - if( rPolygon.SequenceX[ rIndex ].hasElements() ) + if( !rPolygon[ rIndex ].empty() ) rIndex++; //start a new polygon for the next point if the current poly is not empty } } diff --git a/chart2/source/view/charttypes/AreaChart.hxx b/chart2/source/view/charttypes/AreaChart.hxx index ce7bd7d2f965..23d8adb0b4f1 100644 --- a/chart2/source/view/charttypes/AreaChart.hxx +++ b/chart2/source/view/charttypes/AreaChart.hxx @@ -52,16 +52,16 @@ public: private: //methods void impl_createSeriesShapes(); bool impl_createArea( VDataSeries* pSeries - , css::drawing::PolyPolygonShape3D const * pSeriesPoly - , css::drawing::PolyPolygonShape3D const * pPreviousSeriesPoly + , std::vector<std::vector<css::drawing::Position3D>> const * pSeriesPoly + , std::vector<std::vector<css::drawing::Position3D>> const * pPreviousSeriesPoly , PlottingPositionHelper const * pPosHelper ); bool impl_createLine( VDataSeries* pSeries - , css::drawing::PolyPolygonShape3D const * pSeriesPoly + , std::vector<std::vector<css::drawing::Position3D>> const * pSeriesPoly , PlottingPositionHelper* pPosHelper ); - static bool create_stepped_line( css::drawing::PolyPolygonShape3D aStartPoly + static bool create_stepped_line( std::vector<std::vector<css::drawing::Position3D>> aStartPoly , css::chart2::CurveStyle eCurveStyle , PlottingPositionHelper const * pPosHelper - , css::drawing::PolyPolygonShape3D &aPoly ); + , std::vector<std::vector<css::drawing::Position3D>> &aPoly ); private: //member std::unique_ptr<PlottingPositionHelper> diff --git a/chart2/source/view/charttypes/BarChart.cxx b/chart2/source/view/charttypes/BarChart.cxx index 3709476daae0..efcf1dd13831 100644 --- a/chart2/source/view/charttypes/BarChart.cxx +++ b/chart2/source/view/charttypes/BarChart.cxx @@ -850,10 +850,8 @@ void BarChart::createShapes() { // 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); + 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 ); @@ -949,11 +947,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)) @@ -965,7 +963,7 @@ void BarChart::createShapes() rtl::Reference<SvxShapeGroupAnyD> xSeriesGroupShape_Shapes( getSeriesGroupShape(pSeries.get(), xSeriesTarget) ); rtl::Reference<SvxShapePolyPolygon> xShape( ShapeFactory::createLine2D( - xSeriesGroupShape_Shapes, PolyToPointSequence( aPoly ) ) ); + xSeriesGroupShape_Shapes, aPoly ) ); PropertyMapper::setMappedProperties( *xShape, pSeries->getPropertiesOfSeries() , PropertyMapper::getPropertyNameMapForFilledSeriesProperties() ); } diff --git a/chart2/source/view/charttypes/CandleStickChart.cxx b/chart2/source/view/charttypes/CandleStickChart.cxx index 3138c5611c5d..2b636d3d83c3 100644 --- a/chart2/source/view/charttypes/CandleStickChart.cxx +++ b/chart2/source/view/charttypes/CandleStickChart.cxx @@ -216,14 +216,13 @@ void CandleStickChart::createShapes() //create min-max line if( isValidPosition(aPosMiddleMinimum) && isValidPosition(aPosMiddleMaximum) ) { - drawing::PolyPolygonShape3D aPoly; + std::vector<std::vector<css::drawing::Position3D>> aPoly; sal_Int32 nLineIndex =0; AddPointToPoly( aPoly, aPosMiddleMinimum, nLineIndex); AddPointToPoly( aPoly, aPosMiddleMaximum, nLineIndex); rtl::Reference<SvxShapePolyPolygon> xShape = - ShapeFactory::createLine2D( xPointGroupShape_Shapes, - PolyToPointSequence(aPoly)); + ShapeFactory::createLine2D( xPointGroupShape_Shapes, aPoly); PropertyMapper::setMappedProperties( *xShape, xPointProp, PropertyMapper::getPropertyNameMapForLineSeriesProperties() ); } @@ -251,7 +250,7 @@ void CandleStickChart::createShapes() } else { - drawing::PolyPolygonShape3D aPoly; + std::vector<std::vector<css::drawing::Position3D>> aPoly; sal_Int32 nLineIndex = 0; if( bShowFirst && pPosHelper->isLogicVisible( fUnscaledX, fUnscaledY_First ,fLogicZ ) @@ -267,11 +266,10 @@ void CandleStickChart::createShapes() AddPointToPoly( aPoly, aPosRightLast, nLineIndex ); } - if( aPoly.SequenceX.hasElements() ) + if( !aPoly.empty() ) { rtl::Reference<SvxShapePolyPolygon> xShape = - ShapeFactory::createLine2D( xPointGroupShape_Shapes, - PolyToPointSequence(aPoly) ); + ShapeFactory::createLine2D( xPointGroupShape_Shapes, aPoly ); PropertyMapper::setMappedProperties( *xShape, xPointProp, PropertyMapper::getPropertyNameMapForLineSeriesProperties() ); } } diff --git a/chart2/source/view/charttypes/NetChart.cxx b/chart2/source/view/charttypes/NetChart.cxx index cd1b6eea193d..5507e30e0579 100644 --- a/chart2/source/view/charttypes/NetChart.cxx +++ b/chart2/source/view/charttypes/NetChart.cxx @@ -111,13 +111,13 @@ drawing::Direction3D NetChart::getPreferredDiagramAspectRatio() const } bool NetChart::impl_createLine( VDataSeries* pSeries - , drawing::PolyPolygonShape3D* pSeriesPoly + , std::vector<std::vector<css::drawing::Position3D>>* pSeriesPoly , PlottingPositionHelper const * pPosHelper ) { //return true if a line was created successfully rtl::Reference<SvxShapeGroupAnyD> xSeriesGroupShape_Shapes = getSeriesGroupShapeBackChild(pSeries, m_xSeriesTarget); - drawing::PolyPolygonShape3D aPoly; + std::vector<std::vector<css::drawing::Position3D>> aPoly; { bool bIsClipped = false; if( !ShapeFactory::isPolygonEmptyOrSinglePoint(*pSeriesPoly) ) @@ -130,10 +130,10 @@ bool NetChart::impl_createLine( VDataSeries* pSeries { // connect last point in last polygon with first point in first polygon ::basegfx::B2DRectangle aScaledLogicClipDoubleRect( pPosHelper->getScaledLogicClipDoubleRect() ); - drawing::PolyPolygonShape3D aTmpPoly(*pSeriesPoly); - drawing::Position3D aLast(aScaledLogicClipDoubleRect.getMaxX(),aTmpPoly.SequenceY[0][0],aTmpPoly.SequenceZ[0][0]); + std::vector<std::vector<css::drawing::Position3D>> aTmpPoly(*pSeriesPoly); + drawing::Position3D aLast(aScaledLogicClipDoubleRect.getMaxX(),aTmpPoly[0][0].PositionY,aTmpPoly[0][0].PositionZ); // add connector line to last polygon - AddPointToPoly( aTmpPoly, aLast, pSeriesPoly->SequenceX.getLength() - 1 ); + AddPointToPoly( aTmpPoly, aLast, pSeriesPoly->size() - 1 ); Clipping::clipPolygonAtRectangle( aTmpPoly, aScaledLogicClipDoubleRect, aPoly ); bIsClipped = true; } @@ -152,8 +152,7 @@ bool NetChart::impl_createLine( VDataSeries* pSeries //create line: rtl::Reference<SvxShapePolyPolygon> xShape; { - xShape = ShapeFactory::createLine2D( xSeriesGroupShape_Shapes - , PolyToPointSequence( aPoly ) ); + xShape = ShapeFactory::createLine2D( xSeriesGroupShape_Shapes, aPoly ); PropertyMapper::setMappedProperties( *xShape , pSeries->getPropertiesOfSeries() , PropertyMapper::getPropertyNameMapForLineSeriesProperties() ); @@ -164,8 +163,8 @@ bool NetChart::impl_createLine( VDataSeries* pSeries } bool NetChart::impl_createArea( VDataSeries* pSeries - , drawing::PolyPolygonShape3D* pSeriesPoly - , drawing::PolyPolygonShape3D const * pPreviousSeriesPoly + , std::vector<std::vector<css::drawing::Position3D>>* pSeriesPoly + , std::vector<std::vector<css::drawing::Position3D>> const * pPreviousSeriesPoly , PlottingPositionHelper const * pPosHelper ) { //return true if an area was created successfully @@ -173,7 +172,7 @@ bool NetChart::impl_createArea( VDataSeries* pSeries rtl::Reference<SvxShapeGroupAnyD> xSeriesGroupShape_Shapes = getSeriesGroupShapeBackChild(pSeries, m_xSeriesTarget); double zValue = pSeries->m_fLogicZPos; - drawing::PolyPolygonShape3D aPoly( *pSeriesPoly ); + std::vector<std::vector<css::drawing::Position3D>> aPoly( *pSeriesPoly ); //add second part to the polygon (grounding points or previous series points) if( !ShapeFactory::isPolygonEmptyOrSinglePoint(*pSeriesPoly) ) { @@ -209,7 +208,7 @@ bool NetChart::impl_createArea( VDataSeries* pSeries //apply clipping { - drawing::PolyPolygonShape3D aClippedPoly; + std::vector<std::vector<css::drawing::Position3D>> aClippedPoly; Clipping::clipPolygonAtRectangle( aPoly, pPosHelper->getScaledLogicClipDoubleRect(), aClippedPoly, false ); ShapeFactory::closePolygon(aClippedPoly); //again necessary after clipping aPoly = aClippedPoly; @@ -240,8 +239,8 @@ void NetChart::impl_createSeriesShapes() { for( auto const& rXSlot : rZSlot ) { - std::map< sal_Int32, drawing::PolyPolygonShape3D* > aPreviousSeriesPolyMap;//a PreviousSeriesPoly for each different nAttachedAxisIndex - drawing::PolyPolygonShape3D* pSeriesPoly = nullptr; + std::map< sal_Int32, std::vector<std::vector<css::drawing::Position3D>>* > aPreviousSeriesPolyMap;//a PreviousSeriesPoly for each different nAttachedAxisIndex + std::vector<std::vector<css::drawing::Position3D>>* pSeriesPoly = nullptr; //iterate through all series for( std::unique_ptr<VDataSeries> const & pSeries : rXSlot.m_aSeriesVector ) @@ -437,11 +436,11 @@ void NetChart::createShapes() { if( pSeries->getMissingValueTreatment() == css::chart::MissingValueTreatment::LEAVE_GAP ) { - drawing::PolyPolygonShape3D& rPolygon = pSeries->m_aPolyPolygonShape3D; + std::vector<std::vector<css::drawing::Position3D>>& rPolygon = pSeries->m_aPolyPolygonShape3D; sal_Int32& rIndex = pSeries->m_nPolygonIndex; - if( 0<= rIndex && rIndex < rPolygon.SequenceX.getLength() ) + if( 0<= rIndex && rIndex < static_cast<sal_Int32>(rPolygon.size()) ) { - if( rPolygon.SequenceX[ rIndex ].hasElements() ) + if( !rPolygon[ rIndex ].empty() ) rIndex++; //start a new polygon for the next point if the current poly is not empty } } diff --git a/chart2/source/view/charttypes/NetChart.hxx b/chart2/source/view/charttypes/NetChart.hxx index 4ab3432bb777..9883ba118ac2 100644 --- a/chart2/source/view/charttypes/NetChart.hxx +++ b/chart2/source/view/charttypes/NetChart.hxx @@ -53,11 +53,11 @@ public: private: //methods void impl_createSeriesShapes(); bool impl_createArea( VDataSeries* pSeries - , css::drawing::PolyPolygonShape3D* pSeriesPoly - , css::drawing::PolyPolygonShape3D const * pPreviousSeriesPoly + , 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 - , css::drawing::PolyPolygonShape3D* pSeriesPoly + , std::vector<std::vector<css::drawing::Position3D>>* pSeriesPoly , PlottingPositionHelper const * pPosHelper ); private: //member diff --git a/chart2/source/view/charttypes/Splines.cxx b/chart2/source/view/charttypes/Splines.cxx index 89203d3da182..c79fbbcb9fc7 100644 --- a/chart2/source/view/charttypes/Splines.cxx +++ b/chart2/source/view/charttypes/Splines.cxx @@ -20,6 +20,7 @@ #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> @@ -648,6 +649,114 @@ void SplineCalculater::CalculateCubicSplines( } } +// Calculates uniform parametric splines with subinterval length 1, +// according ODF1.2 part 1, chapter 'chart interpolation'. +void SplineCalculater::CalculateCubicSplines( + const std::vector<std::vector<css::drawing::Position3D>>& rInput + , std::vector<std::vector<css::drawing::Position3D>>& rResult + , sal_uInt32 nGranularity ) +{ + OSL_PRECOND( nGranularity > 0, "Granularity is invalid" ); + + sal_uInt32 nOuterCount = rInput.size(); + + rResult.resize(nOuterCount); + + auto pSequence = rResult.data(); + + if( !nOuterCount ) + return; + + for( sal_uInt32 nOuter = 0; nOuter < nOuterCount; ++nOuter ) + { + if( rInput[nOuter].size() <= 1 ) + continue; //we need at least two points + + sal_uInt32 nMaxIndexPoints = rInput[nOuter].size()-1; // is >=1 + const css::drawing::Position3D* pOld = rInput[nOuter].data(); + + std::vector < double > aParameter(nMaxIndexPoints+1); + aParameter[0]=0.0; + for( sal_uInt32 nIndex=1; nIndex<=nMaxIndexPoints; nIndex++ ) + { + aParameter[nIndex]=aParameter[nIndex-1]+1; + } + + // Split the calculation to X, Y and Z coordinate + tPointVecType aInputX; + aInputX.resize(nMaxIndexPoints+1); + tPointVecType aInputY; + aInputY.resize(nMaxIndexPoints+1); + tPointVecType aInputZ; + aInputZ.resize(nMaxIndexPoints+1); + for (sal_uInt32 nN=0;nN<=nMaxIndexPoints; nN++ ) + { + aInputX[ nN ].first=aParameter[nN]; + aInputX[ nN ].second=pOld[ nN ].PositionX; + aInputY[ nN ].first=aParameter[nN]; + aInputY[ nN ].second=pOld[ nN ].PositionY; + aInputZ[ nN ].first=aParameter[nN]; + aInputZ[ nN ].second=pOld[ nN ].PositionZ; + } + + // 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; + // lcl_SplineCalculation* aSplineZ; the z-coordinates of all points in + // a data series are equal. No spline calculation needed, but copy + // coordinate to output + + if( pOld[ 0 ].PositionX == pOld[nMaxIndexPoints].PositionX && + pOld[ 0 ].PositionY == pOld[nMaxIndexPoints].PositionY && + 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) ; + } + 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 )); + } + + // fill result polygon with calculated values + pSequence[nOuter].resize( nMaxIndexPoints*nGranularity + 1); + + css::drawing::Position3D* pNew = pSequence[nOuter].data(); + + sal_uInt32 nNewPointIndex = 0; // Index in result points + + for( sal_uInt32 ni = 0; ni < nMaxIndexPoints; ni++ ) + { + // given point is surely a curve point + pNew[nNewPointIndex].PositionX = pOld[ni].PositionX; + pNew[nNewPointIndex].PositionY = pOld[ni].PositionY; + pNew[nNewPointIndex].PositionZ = pOld[ni].PositionZ; + nNewPointIndex++; + + // calculate intermediate points + double fInc = ( aParameter[ ni+1 ] - aParameter[ni] ) / static_cast< double >( nGranularity ); + for(sal_uInt32 nj = 1; nj < nGranularity; nj++) + { + double fParam = aParameter[ni] + ( fInc * static_cast< double >( nj ) ); + + pNew[nNewPointIndex].PositionX = aSplineX->GetInterpolatedValue( fParam ); + pNew[nNewPointIndex].PositionY = aSplineY->GetInterpolatedValue( fParam ); + // pNewZ[nNewPointIndex]=aSplineZ->GetInterpolatedValue( fParam ); + pNew[nNewPointIndex].PositionZ = pOld[ni].PositionZ; + nNewPointIndex++; + } + } + // add last point + pNew[nNewPointIndex] = pOld[nMaxIndexPoints]; + } +} + // The implementation follows closely ODF1.2 spec, chapter chart:interpolation // using the same names as in spec as far as possible, without prefix. // More details can be found on @@ -931,6 +1040,271 @@ void SplineCalculater::CalculateBSplines( } // next piece of the series } +void SplineCalculater::CalculateBSplines( + const std::vector<std::vector<css::drawing::Position3D>>& rInput + , std::vector<std::vector<css::drawing::Position3D>>& rResult + , sal_uInt32 nResolution + , sal_uInt32 nDegree ) +{ + // nResolution is ODF1.2 file format attribute chart:spline-resolution and + // ODF1.2 spec variable k. Causion, k is used as index in the spec in addition. + // nDegree is ODF1.2 file format attribute chart:spline-order and + // ODF1.2 spec variable p + OSL_ASSERT( nResolution > 1 ); + OSL_ASSERT( nDegree >= 1 ); + + // limit the b-spline degree at 15 to prevent insanely large sets of points + sal_uInt32 p = std::min<sal_uInt32>(nDegree, 15); + + sal_Int32 nOuterCount = rInput.size(); + + rResult.resize(nOuterCount); + + auto pSequence = rResult.data(); + + if( !nOuterCount ) + return; // no input + + for( sal_Int32 nOuter = 0; nOuter < nOuterCount; ++nOuter ) + { + if( rInput[nOuter].size() <= 1 ) + continue; // need at least 2 points, next piece of the series + + // Copy input to vector of points and remove adjacent double points. The + // Z-coordinate is equal for all points in a series and holds the depth + // in 3D mode, simple copying is enough. + lcl_tSizeType nMaxIndexPoints = rInput[nOuter].size()-1; // is >=1 + const css::drawing::Position3D* pOld = rInput[nOuter].data(); + double fZCoordinate = pOld[0].PositionZ; + tPointVecType aPointsIn; + aPointsIn.resize(nMaxIndexPoints+1); + for (lcl_tSizeType i = 0; i <= nMaxIndexPoints; ++i ) + { + aPointsIn[ i ].first = pOld[i].PositionX; + aPointsIn[ i ].second = pOld[i].PositionY; + } + aPointsIn.erase( std::unique( aPointsIn.begin(), aPointsIn.end()), + aPointsIn.end() ); + + // n is the last valid index to the reduced aPointsIn + // There are n+1 valid data points. + const lcl_tSizeType n = aPointsIn.size() - 1; + if (n < 1 || p > n) + 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())) + { + 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()); + + // 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]); + aMatN[0][0] = 1.0; //all others are zero + aShift[0] = 0; + aMatN[n][0] = 1.0; + aShift[n] = n; + for (lcl_tSizeType k = 1; k<=n-1; ++k) + { // all basis functions are applied to t_k, + // results are elements in row k in matrix N + + // find the one interval with u_i <= t_k < u_(i+1) + // remember u_0 = ... = u_p = 0.0 and u_(m-p) = ... u_m = 1.0 and 0<t_k<1 + lcl_tSizeType i = p; + while (u[i] > t[k] || t[k] >= u[i+1]) + { + ++i; + } + + // 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]); + } // next row k + + // Get matrix C of control points from the matrix equation aMatN * C = aPointsIn + // aPointsIn is overwritten with C. + // Gaussian elimination is possible without pivoting, see reference + lcl_tSizeType r = 0; // true row index + 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) + { + // search for first non-zero downwards + r = c; + while ( r < n && aMatN[r][c-aShift[r]] == 0 ) + { + ++r; + } + if (aMatN[r][c-aShift[r]] == 0.0) + { + // Matrix N is singular, although this is mathematically impossible + bIsSuccessful = false; + } + else + { + // 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; + } + + // divide row c, so that element(c,c) becomes 1 + fDivisor = aMatN[c][c-aShift[c]]; // not zero, see above + for (sal_uInt32 i = 0; i <= p; ++i) + { + aMatN[c][i] /= fDivisor; + } + aPointsIn[c].first /= fDivisor; + aPointsIn[c].second /= fDivisor; + + // eliminate forward, examine row c+1 to n-1 (worst case) + // stop if first non-zero element in row has an higher column as c + // look at nShift for that, elements in nShift are equal or increasing + for ( r = c+1; r < n && aShift[r]<=c ; ++r) + { + fEliminate = aMatN[r][0]; + if (fEliminate != 0.0) // else accidentally zero, nothing to do + { + for (sal_uInt32 i = 1; i <= p; ++i) + { + aMatN[r][i-1] = aMatN[r][i] - fEliminate * aMatN[c][i]; + } + aMatN[r][p]=0; + aPointsIn[r].first -= fEliminate * aPointsIn[c].first; + aPointsIn[r].second -= fEliminate * aPointsIn[c].second; + ++aShift[r]; + } + } + } + }// upper triangle form is reached + if( bIsSuccessful) + { + // eliminate backwards, begin with last column + for (lcl_tSizeType cc = n; cc >= 1; --cc ) + { + // In row cc the diagonal element(cc,cc) == 1 and all elements left from + // diagonal are zero and do not influence other rows. + // Full matrix N has semibandwidth < p, therefore element(r,c) is + // zero, if abs(r-cc)>=p. abs(r-cc)=cc-r, because r<cc. + r = cc - 1; + while ( r !=0 && cc-r < p ) + { + fEliminate = aMatN[r][ cc - aShift[r] ]; + if ( fEliminate != 0.0) // else element is accidentally zero, no action needed + { + // row r -= fEliminate * row cc only relevant for right side + aMatN[r][cc - aShift[r]] = 0.0; + aPointsIn[r].first -= fEliminate * aPointsIn[cc].first; + aPointsIn[r].second -= fEliminate * aPointsIn[cc].second; + } + --r; + } + } + // aPointsIn contains the control points now. + + // calculate the intermediate points according given resolution + // using deBoor-Cox algorithm + lcl_tSizeType nNewSize = nResolution * n + 1; + pSequence[nOuter].resize(nNewSize); + css::drawing::Position3D* pNew = pSequence[nOuter].data(); + pNew[0].PositionX = aPointsIn[0].first; + pNew[0].PositionY = aPointsIn[0].second; + pNew[0].PositionZ = fZCoordinate; // Precondition: z-coordinates of all points of a series are equal + 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]); + lcl_tSizeType nLow = 0; + for ( lcl_tSizeType nTIndex = 0; nTIndex <= n-1; ++nTIndex) + { + for (sal_uInt32 nResolutionStep = 1; + nResolutionStep <= nResolution && ( nTIndex != n-1 || nResolutionStep != nResolution); + ++nResolutionStep) + { + lcl_tSizeType nNewIndex = nTIndex * nResolution + nResolutionStep; + double ux = t[nTIndex] + nResolutionStep * ( t[nTIndex+1] - t[nTIndex]) /nResolution; + + // get index nLow, so that u[nLow]<= ux < u[nLow +1] + // continue from previous nLow + while ( u[nLow] <= ux) + { + ++nLow; + } + --nLow; + + // x-coordinate + for (lcl_tSizeType i = nLow-p; i <= nLow; ++i) + { + aP[i] = aPointsIn[i].first; + } + for (sal_uInt32 lcl_Degree = 1; lcl_Degree <= p; ++lcl_Degree) + { + for (lcl_tSizeType i = nLow; i >= nLow + lcl_Degree - p; --i) + { + double fFactor = ( ux - u[i] ) / ( u[i+p+1-lcl_Degree] - u[i]); + aP[i] = (1 - fFactor)* aP[i-1] + fFactor * aP[i]; + } + } + pNew[nNewIndex].PositionX = aP[nLow]; + + // y-coordinate + for (lcl_tSizeType i = nLow - p; i <= nLow; ++i) + { + aP[i] = aPointsIn[i].second; + } + for (sal_uInt32 lcl_Degree = 1; lcl_Degree <= p; ++lcl_Degree) + { + for (lcl_tSizeType i = nLow; i >= nLow +lcl_Degree - p; --i) + { + double fFactor = ( ux - u[i] ) / ( u[i+p+1-lcl_Degree] - u[i]); + aP[i] = (1 - fFactor)* aP[i-1] + fFactor * aP[i]; + } + } + pNew[nNewIndex].PositionY = aP[nLow]; + pNew[nNewIndex].PositionZ = fZCoordinate; + } + } + } + for (lcl_tSizeType row = 0; row <=n; ++row) + { + delete[] aMatN[row]; + } + } // next piece of the series +} + } //namespace chart /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/Splines.hxx b/chart2/source/view/charttypes/Splines.hxx index 4ceb65fc05c0..3cd36131550e 100644 --- a/chart2/source/view/charttypes/Splines.hxx +++ b/chart2/source/view/charttypes/Splines.hxx @@ -20,8 +20,10 @@ #pragma once #include <sal/types.h> +#include <vector> namespace com::sun::star::drawing { struct PolyPolygonShape3D; } +namespace com::sun::star::drawing { struct Position3D; } namespace chart { @@ -33,12 +35,21 @@ public: const css::drawing::PolyPolygonShape3D& rPoints , css::drawing::PolyPolygonShape3D& rResult , sal_uInt32 nGranularity ); + static void CalculateCubicSplines( + const std::vector<std::vector<css::drawing::Position3D>>& rPoints + , std::vector<std::vector<css::drawing::Position3D>>& rResult + , sal_uInt32 nGranularity ); static void CalculateBSplines( const css::drawing::PolyPolygonShape3D& rPoints , css::drawing::PolyPolygonShape3D& rResult , sal_uInt32 nGranularity , sal_uInt32 nSplineDepth ); + static void CalculateBSplines( + const std::vector<std::vector<css::drawing::Position3D>>& rPoints + , std::vector<std::vector<css::drawing::Position3D>>& rResult + , sal_uInt32 nGranularity + , sal_uInt32 nSplineDepth ); }; } //namespace chart diff --git a/chart2/source/view/charttypes/VSeriesPlotter.cxx b/chart2/source/view/charttypes/VSeriesPlotter.cxx index bb3ecd8037eb..d2ee85a6a100 100644 --- a/chart2/source/view/charttypes/VSeriesPlotter.cxx +++ b/chart2/source/view/charttypes/VSeriesPlotter.cxx @@ -866,7 +866,7 @@ double lcl_getErrorBarLogicLength( } void lcl_AddErrorBottomLine( const drawing::Position3D& rPosition, ::basegfx::B2DVector aMainDirection - , drawing::PolyPolygonShape3D& rPoly, sal_Int32 nSequenceIndex ) + , std::vector<std::vector<css::drawing::Position3D>>& rPoly, sal_Int32 nSequenceIndex ) { double fFixedWidth = 200.0; @@ -1050,7 +1050,7 @@ void VSeriesPlotter::createErrorBar( if(!bShowPositive && !bShowNegative) return; - drawing::PolyPolygonShape3D aPoly; + std::vector<std::vector<css::drawing::Position3D>> aPoly; sal_Int32 nSequenceIndex=0; if( bShowNegative ) @@ -1072,7 +1072,7 @@ void VSeriesPlotter::createErrorBar( lcl_AddErrorBottomLine( aPositive, aMainDirection, aPoly, nSequenceIndex ); } - rtl::Reference<SvxShapePolyPolygon> xShape = ShapeFactory::createLine2D( xTarget, PolyToPointSequence( aPoly) ); + rtl::Reference<SvxShapePolyPolygon> xShape = ShapeFactory::createLine2D( xTarget, aPoly ); PropertyMapper::setMappedProperties( *xShape, xErrorBarProperties, PropertyMapper::getPropertyNameMapForLineProperties() ); } catch( const uno::Exception & ) @@ -1088,12 +1088,12 @@ void VSeriesPlotter::addErrorBorder( ,const rtl::Reference<SvxShapeGroupAnyD>& rTarget ,const uno::Reference< beans::XPropertySet >& rErrorBorderProp ) { - drawing::PolyPolygonShape3D aPoly; + std::vector<std::vector<css::drawing::Position3D>> aPoly; sal_Int32 nSequenceIndex = 0; AddPointToPoly( aPoly, rPos0, nSequenceIndex ); AddPointToPoly( aPoly, rPos1, nSequenceIndex ); rtl::Reference<SvxShapePolyPolygon> xShape = ShapeFactory::createLine2D( - rTarget, PolyToPointSequence( aPoly) ); + rTarget, aPoly ); PropertyMapper::setMappedProperties( *xShape, rErrorBorderProp, PropertyMapper::getPropertyNameMapForLineProperties() ); } diff --git a/chart2/source/view/inc/Clipping.hxx b/chart2/source/view/inc/Clipping.hxx index 64697dfb9714..e816e7aa79b1 100644 --- a/chart2/source/view/inc/Clipping.hxx +++ b/chart2/source/view/inc/Clipping.hxx @@ -22,6 +22,7 @@ #include <basegfx/range/b2drectangle.hxx> namespace com::sun::star::drawing { struct PolyPolygonShape3D; } +namespace com::sun::star::drawing { struct Position3D; } namespace chart { @@ -48,6 +49,11 @@ public: , const ::basegfx::B2DRectangle& rRectangle , css::drawing::PolyPolygonShape3D& aResult , bool bSplitPiecesToDifferentPolygons = true ); + static void clipPolygonAtRectangle( + const std::vector<std::vector<css::drawing::Position3D>>& rPolygon + , const ::basegfx::B2DRectangle& rRectangle + , std::vector<std::vector<css::drawing::Position3D>>& aResult + , bool bSplitPiecesToDifferentPolygons = true ); }; } //namespace chart diff --git a/chart2/source/view/inc/PlottingPositionHelper.hxx b/chart2/source/view/inc/PlottingPositionHelper.hxx index f5360942b2d7..14e22375df17 100644 --- a/chart2/source/view/inc/PlottingPositionHelper.hxx +++ b/chart2/source/view/inc/PlottingPositionHelper.hxx @@ -84,6 +84,7 @@ public: transformScaledLogicToScene( double fX, double fY, double fZ, bool bClip ) const; void transformScaledLogicToScene( css::drawing::PolyPolygonShape3D& rPoly ) const; + void transformScaledLogicToScene( std::vector<std::vector<css::drawing::Position3D>>& rPoly ) const; static css::awt::Point transformSceneToScreenPosition( const css::drawing::Position3D& rScenePosition3D diff --git a/chart2/source/view/inc/ShapeFactory.hxx b/chart2/source/view/inc/ShapeFactory.hxx index f198f074f519..e8ff694f32cc 100644 --- a/chart2/source/view/inc/ShapeFactory.hxx +++ b/chart2/source/view/inc/ShapeFactory.hxx @@ -154,11 +154,19 @@ public: createArea3D( const rtl::Reference<SvxShapeGroupAnyD>& xTarget , const css::drawing::PolyPolygonShape3D& rPolyPolygon , double fDepth); + static rtl::Reference<Svx3DExtrudeObject> + createArea3D( const rtl::Reference<SvxShapeGroupAnyD>& xTarget + , const std::vector<std::vector<css::drawing::Position3D>>& rPolyPolygon + , double fDepth); static SdrPathObj* createArea2D( const rtl::Reference<SvxShapeGroupAnyD>& xTarget , const css::drawing::PolyPolygonShape3D& rPolyPolygon , bool bSetZOrderToZero = true); + static SdrPathObj* + createArea2D( const rtl::Reference<SvxShapeGroupAnyD>& xTarget + , const std::vector<std::vector<css::drawing::Position3D>>& rPolyPolygon + , bool bSetZOrderToZero = true); static rtl::Reference<SvxShapePolyPolygon> createSymbol2D( const rtl::Reference<SvxShapeGroupAnyD>& xTarget @@ -178,6 +186,10 @@ public: createLine2D( const rtl::Reference<SvxShapeGroupAnyD>& xTarget , const css::drawing::PointSequenceSequence& rPoints , const VLineProperties* pLineProperties = nullptr ); + static rtl::Reference<SvxShapePolyPolygon> + createLine2D( const rtl::Reference<SvxShapeGroupAnyD>& xTarget + , const std::vector<std::vector<css::drawing::Position3D>>& rPoints + , const VLineProperties* pLineProperties = nullptr ); static rtl::Reference<SvxShapePolyPolygon> createLine ( const rtl::Reference<SvxShapeGroupAnyD>& xTarget, @@ -185,7 +197,7 @@ public: static rtl::Reference<Svx3DPolygonObject> createLine3D( const rtl::Reference<SvxShapeGroupAnyD>& xTarget - , const css::drawing::PolyPolygonShape3D& rPoints + , const std::vector<std::vector<css::drawing::Position3D>>& rPoints , const VLineProperties& rLineProperties ); static rtl::Reference<SvxShapeCircle> @@ -262,8 +274,11 @@ public: static OUString getStackedString( const OUString& rString, bool bStacked ); static bool hasPolygonAnyLines( css::drawing::PolyPolygonShape3D& rPoly ); + static bool hasPolygonAnyLines( const std::vector<std::vector<css::drawing::Position3D>>& rPoly ); static bool isPolygonEmptyOrSinglePoint( css::drawing::PolyPolygonShape3D& rPoly ); + static bool isPolygonEmptyOrSinglePoint( const std::vector<std::vector<css::drawing::Position3D>>& rPoly ); static void closePolygon( css::drawing::PolyPolygonShape3D& rPoly ); + static void closePolygon( std::vector<std::vector<css::drawing::Position3D>>& rPoly ); static css::awt::Size calculateNewSizeRespectingAspectRatio( const css::awt::Size& rTargetSize diff --git a/chart2/source/view/inc/VDataSeries.hxx b/chart2/source/view/inc/VDataSeries.hxx index 48ea0d4234ff..bfbc6c9b20ea 100644 --- a/chart2/source/view/inc/VDataSeries.hxx +++ b/chart2/source/view/inc/VDataSeries.hxx @@ -22,6 +22,7 @@ #include <com/sun/star/chart2/StackingDirection.hpp> #include <com/sun/star/drawing/PolyPolygonShape3D.hpp> +#include <com/sun/star/drawing/Position3D.hpp> #include <com/sun/star/awt/Size.hpp> #include <com/sun/star/awt/Point.hpp> #include <rtl/ref.hxx> @@ -142,7 +143,7 @@ public: void setRoleOfSequenceForDataLabelNumberFormatDetection( std::u16string_view rRole ); //this is only temporarily here for area chart: - css::drawing::PolyPolygonShape3D m_aPolyPolygonShape3D; + std::vector<std::vector<css::drawing::Position3D>> m_aPolyPolygonShape3D; sal_Int32 m_nPolygonIndex; double m_fLogicMinX; double m_fLogicMaxX; diff --git a/chart2/source/view/main/Clipping.cxx b/chart2/source/view/main/Clipping.cxx index 463b74975a91..7509f53fb28d 100644 --- a/chart2/source/view/main/Clipping.cxx +++ b/chart2/source/view/main/Clipping.cxx @@ -204,6 +204,47 @@ void lcl_addPointToPoly( drawing::PolyPolygonShape3D& rPoly rResultPointCount[nPolygonIndex]=nNewResultPointCount; } +void lcl_addPointToPoly( std::vector<std::vector<css::drawing::Position3D>>& rPoly + , const drawing::Position3D& rPos + , sal_Int32 nPolygonIndex + , std::vector< sal_Int32 >& rResultPointCount + , sal_Int32 nReservePointCount ) +{ + if(nPolygonIndex<0) + { + OSL_FAIL( "The polygon index needs to be > 0"); + nPolygonIndex=0; + } + + //make sure that we have enough polygons + if(nPolygonIndex >= static_cast<sal_Int32>(rPoly.size()) ) + { + rPoly.resize(nPolygonIndex+1); + rResultPointCount.resize(nPolygonIndex+1,0); + } + + std::vector<css::drawing::Position3D>* pOuterSequence = &rPoly[nPolygonIndex]; + + sal_Int32 nNewResultPointCount = rResultPointCount[nPolygonIndex]+1; + sal_Int32 nSeqLength = pOuterSequence->size(); + + if( nSeqLength <= nNewResultPointCount ) + { + sal_Int32 nReallocLength = nReservePointCount > SAL_MAX_INT16 ? round_up_nearest_pow2(nNewResultPointCount) * 2 : nReservePointCount; + if( nNewResultPointCount > nReallocLength ) + { + nReallocLength = nNewResultPointCount; + OSL_FAIL("this should not be the case to avoid performance problems"); + } + pOuterSequence->resize(nReallocLength); + } + + css::drawing::Position3D* pInnerSequence = pOuterSequence->data(); + + pInnerSequence[nNewResultPointCount-1] = rPos; + rResultPointCount[nPolygonIndex]=nNewResultPointCount; +} + }//end anonymous namespace void Clipping::clipPolygonAtRectangle( const drawing::PolyPolygonShape3D& rPolygon @@ -295,6 +336,89 @@ void Clipping::clipPolygonAtRectangle( const drawing::PolyPolygonShape3D& rPolyg } } +void Clipping::clipPolygonAtRectangle( const std::vector<std::vector<css::drawing::Position3D>>& rPolygon + , const B2DRectangle& rRectangle + , std::vector<std::vector<css::drawing::Position3D>>& aResult + , bool bSplitPiecesToDifferentPolygons ) +{ + aResult.clear(); + + if(rPolygon.empty()) + return; + + //need clipping?: + { + ::basegfx::B3DRange a3DRange( BaseGFXHelper::getBoundVolume( rPolygon ) ); + ::basegfx::B2DRange a2DRange( a3DRange.getMinX(), a3DRange.getMinY(), a3DRange.getMaxX(), a3DRange.getMaxY() ); + if( rRectangle.isInside( a2DRange ) ) + { + aResult = rPolygon; + return; + } + else + { + a2DRange.intersect( rRectangle ); + if( a2DRange.isEmpty() ) + return; + } + } + + std::vector< sal_Int32 > aResultPointCount;//per polygon index + + //apply clipping: + drawing::Position3D aFrom; + drawing::Position3D aTo; + + sal_Int32 nNewPolyIndex = 0; + sal_Int32 nOldPolyCount = rPolygon.size(); + for(sal_Int32 nOldPolyIndex=0; nOldPolyIndex<nOldPolyCount; nOldPolyIndex++, nNewPolyIndex++ ) + { + sal_Int32 nOldPointCount = rPolygon[nOldPolyIndex].size(); + + // set last point to a position outside the rectangle, such that the first + // time lcl_clip2d returns true, the comparison to last will always yield false + drawing::Position3D aLast(rRectangle.getMinX()-1.0,rRectangle.getMinY()-1.0, 0.0 ); + + for(sal_Int32 nOldPoint=1; nOldPoint<nOldPointCount; nOldPoint++) + { + aFrom = getPointFromPoly(rPolygon,nOldPoint-1,nOldPolyIndex); + aTo = getPointFromPoly(rPolygon,nOldPoint,nOldPolyIndex); + if( lcl_clip2d_(aFrom, aTo, rRectangle) ) + { + // compose a Polygon of as many consecutive points as possible + if(aFrom == aLast) + { + if( aTo != aFrom ) + { + lcl_addPointToPoly( aResult, aTo, nNewPolyIndex, aResultPointCount, nOldPointCount ); + } + } + else + { + if( bSplitPiecesToDifferentPolygons && nOldPoint!=1 ) + { + if( nNewPolyIndex < static_cast<sal_Int32>(aResult.size()) + && aResultPointCount[nNewPolyIndex]>0 ) + nNewPolyIndex++; + } + lcl_addPointToPoly( aResult, aFrom, nNewPolyIndex, aResultPointCount, nOldPointCount ); + if( aTo != aFrom ) + lcl_addPointToPoly( aResult, aTo, nNewPolyIndex, aResultPointCount, nOldPointCount ); + } + aLast = aTo; + } + } + } + //free unused space + for( sal_Int32 nPolygonIndex = aResultPointCount.size(); nPolygonIndex--; ) + { + std::vector<css::drawing::Position3D>* pOuterSequence = &aResult[nPolygonIndex]; + + sal_Int32 nUsedPointCount = aResultPointCount[nPolygonIndex]; + pOuterSequence->resize(nUsedPointCount); + } +} + } //namespace chart /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/main/PlottingPositionHelper.cxx b/chart2/source/view/main/PlottingPositionHelper.cxx index 350c0942ae78..0c2084aae2e2 100644 --- a/chart2/source/view/main/PlottingPositionHelper.cxx +++ b/chart2/source/view/main/PlottingPositionHelper.cxx @@ -238,6 +238,25 @@ void PlottingPositionHelper::transformScaledLogicToScene( drawing::PolyPolygonSh } } +void PlottingPositionHelper::transformScaledLogicToScene( std::vector<std::vector<css::drawing::Position3D>>& rPolygon ) const +{ + drawing::Position3D aScenePosition; + for( sal_Int32 nS = static_cast<sal_Int32>(rPolygon.size()); nS--;) + { + auto valuesRange = rPolygon[nS].data(); + for( sal_Int32 nP = rPolygon[nS].size(); nP--; ) + { + double& fX = valuesRange[nP].PositionX; + double& fY = valuesRange[nP].PositionY; + double& fZ = valuesRange[nP].PositionZ; + aScenePosition = transformScaledLogicToScene( fX,fY,fZ,true ); + fX = aScenePosition.PositionX; + fY = aScenePosition.PositionY; + fZ = aScenePosition.PositionZ; + } + } +} + void PlottingPositionHelper::clipScaledLogicValues( double* pX, double* pY, double* pZ ) const { //get logic clip values: diff --git a/chart2/source/view/main/ShapeFactory.cxx b/chart2/source/view/main/ShapeFactory.cxx index 98afa8bba4da..92167165ba14 100644 --- a/chart2/source/view/main/ShapeFactory.cxx +++ b/chart2/source/view/main/ShapeFactory.cxx @@ -83,6 +83,34 @@ void lcl_addProperty(uno::Sequence<OUString> & rPropertyNames, uno::Sequence<uno rPropertyValues.getArray()[rPropertyValues.getLength() - 1] = rAny; } +css::drawing::PolyPolygonShape3D toPolyPolygonShape3D(const std::vector<std::vector<css::drawing::Position3D>>& rPoints) +{ + css::drawing::PolyPolygonShape3D aUnoPoly; + aUnoPoly.SequenceX.realloc(rPoints.size()); + aUnoPoly.SequenceY.realloc(rPoints.size()); + aUnoPoly.SequenceZ.realloc(rPoints.size()); + for (sal_Int32 nPolygonIndex=0; nPolygonIndex<static_cast<sal_Int32>(rPoints.size()); ++nPolygonIndex) + { + drawing::DoubleSequence* pOuterSequenceX = &aUnoPoly.SequenceX.getArray()[nPolygonIndex]; + drawing::DoubleSequence* pOuterSequenceY = &aUnoPoly.SequenceY.getArray()[nPolygonIndex]; + drawing::DoubleSequence* pOuterSequenceZ = &aUnoPoly.SequenceZ.getArray()[nPolygonIndex]; + pOuterSequenceX->realloc(rPoints[nPolygonIndex].size()); + pOuterSequenceY->realloc(rPoints[nPolygonIndex].size()); + pOuterSequenceZ->realloc(rPoints[nPolygonIndex].size()); + double* pInnerSequenceX = pOuterSequenceX->getArray(); + double* pInnerSequenceY = pOuterSequenceY->getArray(); + double* pInnerSequenceZ = pOuterSequenceZ->getArray(); + for (sal_Int32 nPointIndex=0; nPointIndex<static_cast<sal_Int32>(rPoints[nPolygonIndex].size()); ++nPointIndex) + { + auto& rPos = rPoints[nPolygonIndex][nPointIndex]; + pInnerSequenceX[nPointIndex] = rPos.PositionX; + pInnerSequenceY[nPointIndex] = rPos.PositionY; + pInnerSequenceZ[nPointIndex] = rPos.PositionZ; + } + } + return aUnoPoly; +} + } // end anonymous namespace rtl::Reference<SvxShapeGroupAnyD> ShapeFactory::getOrCreateChartRootShape( @@ -1081,6 +1109,61 @@ rtl::Reference<Svx3DExtrudeObject> return xShape; } +rtl::Reference<Svx3DExtrudeObject> + ShapeFactory::createArea3D( const rtl::Reference<SvxShapeGroupAnyD>& xTarget + , const std::vector<std::vector<css::drawing::Position3D>>& rPolyPolygon + , double fDepth ) +{ + if( !xTarget.is() ) + return nullptr; + + if( rPolyPolygon.empty() ) + return nullptr; + + //create shape + rtl::Reference<Svx3DExtrudeObject> xShape = new Svx3DExtrudeObject(nullptr); + xShape->setShapeKind(SdrObjKind::E3D_Extrusion); + xTarget->add(xShape); + + css::drawing::PolyPolygonShape3D aUnoPolyPolygon = toPolyPolygonShape3D(rPolyPolygon); + + //set properties + try + { + uno::Sequence<OUString> aPropertyNames{ + UNO_NAME_3D_EXTRUDE_DEPTH, + UNO_NAME_3D_PERCENT_DIAGONAL, + UNO_NAME_3D_POLYPOLYGON3D, + UNO_NAME_3D_DOUBLE_SIDED, + }; + + uno::Sequence<uno::Any> aPropertyValues { + uno::Any(sal_Int32(fDepth)), // depth + uno::Any(sal_Int16(0)), // PercentDiagonal + uno::Any(aUnoPolyPolygon), // Polygon + uno::Any(true) // DoubleSided + }; + + //the z component of the polygon is now ignored by the drawing layer, + //so we need to translate the object via transformation matrix + + //Matrix for position + if (!rPolyPolygon.empty() && !rPolyPolygon[0].empty()) + { + basegfx::B3DHomMatrix aM; + aM.translate(0, 0, rPolyPolygon[0][0].PositionZ); + drawing::HomogenMatrix aHM = B3DHomMatrixToHomogenMatrix(aM); + lcl_addProperty(aPropertyNames, aPropertyValues, UNO_NAME_3D_TRANSFORM_MATRIX, uno::Any(aHM)); + } + xShape->setPropertyValues(aPropertyNames, aPropertyValues); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return xShape; +} + SdrPathObj* ShapeFactory::createArea2D( const rtl::Reference<SvxShapeGroupAnyD>& xTarget , const drawing::PolyPolygonShape3D& rPolyPolygon @@ -1113,6 +1196,38 @@ SdrPathObj* return pPath; } +SdrPathObj* + ShapeFactory::createArea2D( const rtl::Reference<SvxShapeGroupAnyD>& xTarget + , const std::vector<std::vector<css::drawing::Position3D>>& rPolyPolygon + , bool bSetZOrderToZero ) +{ + if( !xTarget.is() ) + return nullptr; + + //create shape + SdrPathObj* pPath = new SdrPathObj(xTarget->GetSdrObject()->getSdrModelFromSdrObject(), SdrObjKind::Polygon); + if (bSetZOrderToZero) + // insert at ZOrder 0, an area should always be behind other shapes + xTarget->GetSdrObject()->GetSubList()->InsertObject(pPath, 0); + else + xTarget->GetSdrObject()->GetSubList()->InsertObject(pPath); + + //set properties + try + { + // Polygon + basegfx::B2DPolyPolygon aNewPolyPolygon( PolyToB2DPolyPolygon(rPolyPolygon) ); + // tdf#117145 metric of SdrModel is app-specific, metric of UNO API is 100thmm + pPath->ForceMetricToItemPoolMetric(aNewPolyPolygon); + pPath->SetPathPoly(aNewPolyPolygon); + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return pPath; +} + static drawing::PolyPolygonShape3D createPolyPolygon_Symbol( const drawing::Position3D& rPos , const drawing::Direction3D& rSize , sal_Int32 nStandardSymbol ) @@ -1860,13 +1975,13 @@ rtl::Reference<SvxShapeCircle> rtl::Reference<Svx3DPolygonObject> ShapeFactory::createLine3D( const rtl::Reference<SvxShapeGroupAnyD>& xTarget - , const drawing::PolyPolygonShape3D& rPoints + , const std::vector<std::vector<css::drawing::Position3D>>& rPoints , const VLineProperties& rLineProperties ) { if( !xTarget.is() ) return nullptr; - if(!rPoints.SequenceX.hasElements()) + if(rPoints.empty()) return nullptr; //create shape @@ -1874,6 +1989,8 @@ rtl::Reference<Svx3DPolygonObject> xShape->setShapeKind(SdrObjKind::E3D_Polygon); xTarget->add(xShape); + css::drawing::PolyPolygonShape3D aUnoPoly = toPolyPolygonShape3D(rPoints); + //set properties try { @@ -1883,7 +2000,7 @@ rtl::Reference<Svx3DPolygonObject> }; uno::Sequence<uno::Any> aPropertyValues { - uno::Any(rPoints), // Polygon + uno::Any(aUnoPoly), // Polygon uno::Any(true) // LineOnly }; @@ -1990,6 +2107,71 @@ rtl::Reference<SvxShapePolyPolygon> return xShape; } +rtl::Reference<SvxShapePolyPolygon> + ShapeFactory::createLine2D( const rtl::Reference<SvxShapeGroupAnyD>& xTarget + , const std::vector<std::vector<css::drawing::Position3D>>& rPoints + , const VLineProperties* pLineProperties ) +{ + if( !xTarget.is() ) + return nullptr; + + if(rPoints.empty()) + return nullptr; + + //create shape + rtl::Reference<SvxShapePolyPolygon> xShape = new SvxShapePolyPolygon(nullptr); + xShape->setShapeKind(SdrObjKind::PolyLine); + xTarget->add(xShape); + + drawing::PointSequenceSequence aAnyPoints = PolyToPointSequence(rPoints); + + //set properties + try + { + //Polygon + xShape->SvxShape::setPropertyValue( UNO_NAME_POLYPOLYGON + , uno::Any( aAnyPoints ) ); + + if(pLineProperties) + { + //Transparency + if(pLineProperties->Transparence.hasValue()) + xShape->SvxShape::setPropertyValue( UNO_NAME_LINETRANSPARENCE + , pLineProperties->Transparence ); + + //LineStyle + if(pLineProperties->LineStyle.hasValue()) + xShape->SvxShape::setPropertyValue( UNO_NAME_LINESTYLE + , pLineProperties->LineStyle ); + + //LineWidth + if(pLineProperties->Width.hasValue()) + xShape->SvxShape::setPropertyValue( UNO_NAME_LINEWIDTH + , pLineProperties->Width ); + + //LineColor + if(pLineProperties->Color.hasValue()) + xShape->SvxShape::setPropertyValue( UNO_NAME_LINECOLOR + , pLineProperties->Color ); + + //LineDashName + if(pLineProperties->DashName.hasValue()) + xShape->SvxShape::setPropertyValue( "LineDashName" + , pLineProperties->DashName ); + + //LineCap + if(pLineProperties->LineCap.hasValue()) + xShape->SvxShape::setPropertyValue( UNO_NAME_LINECAP + , pLineProperties->LineCap ); + } + } + catch( const uno::Exception& ) + { + TOOLS_WARN_EXCEPTION("chart2", "" ); + } + return xShape; +} + rtl::Reference<SvxShapePolyPolygon> ShapeFactory::createLine ( const rtl::Reference<SvxShapeGroupAnyD>& xTarget, const awt::Size& rSize, const awt::Point& rPosition ) @@ -2465,6 +2647,15 @@ bool ShapeFactory::hasPolygonAnyLines( drawing::PolyPolygonShape3D& rPoly) return false; } +bool ShapeFactory::hasPolygonAnyLines( const std::vector<std::vector<css::drawing::Position3D>>& rPoly) +{ + // #i67757# check all contained polygons, if at least one polygon contains 2 or more points, return true + for( auto const & i : rPoly ) + if( i.size() > 1 ) + return true; + return false; +} + bool ShapeFactory::isPolygonEmptyOrSinglePoint( drawing::PolyPolygonShape3D& rPoly) { // true, if empty polypolygon or one polygon with one point @@ -2472,6 +2663,12 @@ bool ShapeFactory::isPolygonEmptyOrSinglePoint( drawing::PolyPolygonShape3D& rPo ((rPoly.SequenceX.getLength() == 1) && (rPoly.SequenceX[0].getLength() <= 1)); } +bool ShapeFactory::isPolygonEmptyOrSinglePoint( const std::vector<std::vector<css::drawing::Position3D>>& rPoly) +{ + // true, if empty polypolygon or one polygon with one point + return rPoly.empty() || ((rPoly.size() == 1) && (rPoly[0].size() <= 1)); +} + void ShapeFactory::closePolygon( drawing::PolyPolygonShape3D& rPoly) { OSL_ENSURE( rPoly.SequenceX.getLength() <= 1, "ShapeFactory::closePolygon - single polygon expected" ); @@ -2482,6 +2679,16 @@ void ShapeFactory::closePolygon( drawing::PolyPolygonShape3D& rPoly) AddPointToPoly( rPoly, aFirst ); } +void ShapeFactory::closePolygon( std::vector<std::vector<css::drawing::Position3D>>& rPoly) +{ + OSL_ENSURE( rPoly.size() <= 1, "ShapeFactory::closePolygon - single polygon expected" ); + //add a last point == first point + if(isPolygonEmptyOrSinglePoint(rPoly)) + return; + drawing::Position3D aFirst(rPoly[0][0]); + AddPointToPoly( rPoly, aFirst ); +} + awt::Size ShapeFactory::calculateNewSizeRespectingAspectRatio( const awt::Size& rTargetSize , const awt::Size& rSourceSizeWithCorrectAspectRatio ) diff --git a/chart2/source/view/main/VDataSeries.cxx b/chart2/source/view/main/VDataSeries.cxx index 14d204a8cf9e..8ae407488b8d 100644 --- a/chart2/source/view/main/VDataSeries.cxx +++ b/chart2/source/view/main/VDataSeries.cxx @@ -294,9 +294,7 @@ void VDataSeries::releaseShapes() m_xFrontSubGroupShape.set(nullptr); m_xBackSubGroupShape.set(nullptr); - m_aPolyPolygonShape3D.SequenceX.realloc(0); - m_aPolyPolygonShape3D.SequenceY.realloc(0); - m_aPolyPolygonShape3D.SequenceZ.realloc(0); + m_aPolyPolygonShape3D.clear(); m_nPolygonIndex = 0; }