From fba022e57a1264b44312d105e31fe60853120fa4 Mon Sep 17 00:00:00 2001 From: EricSeynaeve Date: Thu, 28 Feb 2013 23:07:09 +0100 Subject: [PATCH] fdo#61135 stepped lines graph: handle ods files The boilerplate code for drawing the 4 types of stepped is in place (as described in ODF1.3, https://tools.oasis-open.org/issues/browse/OFFICE-3662). We can also read the current attribute used in Gnumeric and keep this during saves from LO. Change-Id: I0f04a779de4b65326ed7ce6de56191f11b51c596 --- .../chartapiwrapper/WrappedSplineProperties.cxx | 83 +++++++++-- chart2/source/view/charttypes/AreaChart.cxx | 151 ++++++++++++++++++++- chart2/source/view/charttypes/AreaChart.hxx | 4 + offapi/com/sun/star/chart2/CurveStyle.idl | 49 +++++++ xmloff/inc/xmloff/xmltoken.hxx | 8 ++ xmloff/source/chart/PropertyMap.hxx | 16 ++- xmloff/source/core/xmltoken.cxx | 9 ++ xmloff/source/transform/StyleOASISTContext.cxx | 18 ++- 8 files changed, 316 insertions(+), 22 deletions(-) diff --git a/chart2/source/controller/chartapiwrapper/WrappedSplineProperties.cxx b/chart2/source/controller/chartapiwrapper/WrappedSplineProperties.cxx index d68bdc5..36c6ddc 100644 --- a/chart2/source/controller/chartapiwrapper/WrappedSplineProperties.cxx +++ b/chart2/source/controller/chartapiwrapper/WrappedSplineProperties.cxx @@ -231,12 +231,41 @@ Any WrappedSplineTypeProperty::convertInnerToOuterValue( const Any& rInnerValue rInnerValue >>= aInnerValue; sal_Int32 nOuterValue; - if( chart2::CurveStyle_CUBIC_SPLINES == aInnerValue ) - nOuterValue = 1; - else if( chart2::CurveStyle_B_SPLINES == aInnerValue ) - nOuterValue = 2; - else - nOuterValue = 0; + switch (aInnerValue) + { + case chart2::CurveStyle_CUBIC_SPLINES: + nOuterValue = 1; + break; + case chart2::CurveStyle_B_SPLINES: + nOuterValue = 2; + break; + case chart2::CurveStyle_STEP_START: + nOuterValue = 3; + break; + case chart2::CurveStyle_STEP_END: + nOuterValue = 4; + break; + case chart2::CurveStyle_STEP_CENTER_X: + nOuterValue = 5; + break; + case chart2::CurveStyle_STEP_CENTER_Y: + nOuterValue = 6; + break; + case chart2::CurveStyle_GNM_STEP_START: + nOuterValue = 7; + break; + case chart2::CurveStyle_GNM_STEP_END: + nOuterValue = 8; + break; + case chart2::CurveStyle_GNM_STEP_CENTER_X: + nOuterValue = 9; + break; + case chart2::CurveStyle_GNM_STEP_CENTER_Y: + nOuterValue = 10; + break; + default: + nOuterValue = 0; + } return uno::makeAny(nOuterValue); } @@ -247,12 +276,42 @@ Any WrappedSplineTypeProperty::convertOuterToInnerValue( const Any& rOuterValue chart2::CurveStyle aInnerValue; - if(1==nOuterValue) - aInnerValue = chart2::CurveStyle_CUBIC_SPLINES; - else if(2==nOuterValue) - aInnerValue = chart2::CurveStyle_B_SPLINES; - else - aInnerValue = chart2::CurveStyle_LINES; + switch (nOuterValue) + { + case 1: + aInnerValue = chart2::CurveStyle_CUBIC_SPLINES; + break; + case 2: + aInnerValue = chart2::CurveStyle_B_SPLINES; + break; + case 3: + aInnerValue = chart2::CurveStyle_STEP_START; + break; + case 4: + aInnerValue = chart2::CurveStyle_STEP_END; + break; + case 5: + aInnerValue = chart2::CurveStyle_STEP_CENTER_X; + break; + case 6: + aInnerValue = chart2::CurveStyle_STEP_CENTER_Y; + break; + case 7: + aInnerValue = chart2::CurveStyle_GNM_STEP_START; + break; + case 8: + aInnerValue = chart2::CurveStyle_GNM_STEP_END; + break; + case 9: + aInnerValue = chart2::CurveStyle_GNM_STEP_CENTER_X; + break; + case 10: + aInnerValue = chart2::CurveStyle_GNM_STEP_CENTER_Y; + break; + default: + SAL_WARN_IF(chart2::CurveStyle_LINES != 0, "chart2", "Unknown line style"); + aInnerValue = chart2::CurveStyle_LINES; + } return uno::makeAny(aInnerValue); } diff --git a/chart2/source/view/charttypes/AreaChart.cxx b/chart2/source/view/charttypes/AreaChart.cxx index a9e207c..d95dfcc 100644 --- a/chart2/source/view/charttypes/AreaChart.cxx +++ b/chart2/source/view/charttypes/AreaChart.cxx @@ -287,6 +287,140 @@ void lcl_removeDuplicatePoints( drawing::PolyPolygonShape3D& rPolyPoly, Plotting rPolyPoly=aTmp; } +bool AreaChart::create_stepped_line( drawing::PolyPolygonShape3D aStartPoly, chart2::CurveStyle eCurveStyle, PlottingPositionHelper* pPosHelper, drawing::PolyPolygonShape3D &aPoly ) +{ + drawing::PolyPolygonShape3D aSteppedPoly; + + aSteppedPoly.SequenceX.realloc(0); + aSteppedPoly.SequenceY.realloc(0); + aSteppedPoly.SequenceZ.realloc(0); + + sal_uInt32 nOuterCount = aStartPoly.SequenceX.getLength(); + if ( !nOuterCount ) + return false; + + aSteppedPoly.SequenceX.realloc(nOuterCount); + aSteppedPoly.SequenceY.realloc(nOuterCount); + aSteppedPoly.SequenceZ.realloc(nOuterCount); + for( sal_uInt32 nOuter = 0; nOuter < nOuterCount; ++nOuter ) + { + if( aStartPoly.SequenceX[nOuter].getLength() <= 1 ) + continue; //we need at least two points + + sal_uInt32 nMaxIndexPoints = aStartPoly.SequenceX[nOuter].getLength()-1; // is >1 + sal_uInt32 nNewIndexPoints = 0; + if ( CurveStyle_STEP_START==eCurveStyle || CurveStyle_STEP_END==eCurveStyle || + CurveStyle_GNM_STEP_START==eCurveStyle || CurveStyle_GNM_STEP_END==eCurveStyle) + 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(); + + aSteppedPoly.SequenceX[nOuter].realloc( nNewIndexPoints ); + aSteppedPoly.SequenceY[nOuter].realloc( nNewIndexPoints ); + aSteppedPoly.SequenceZ[nOuter].realloc( nNewIndexPoints ); + + double* pNewX = aSteppedPoly.SequenceX[nOuter].getArray(); + double* pNewY = aSteppedPoly.SequenceY[nOuter].getArray(); + double* pNewZ = aSteppedPoly.SequenceZ[nOuter].getArray(); + + pNewX[0] = pOldX[0]; + pNewY[0] = pOldY[0]; + pNewZ[0] = pOldZ[0]; + for( sal_uInt32 oi = 0; oi < nMaxIndexPoints; oi++ ) + { + switch ( eCurveStyle ) + { + case CurveStyle_STEP_START: + case CurveStyle_GNM_STEP_START: + /** O + | + | + | + O-----+ + */ + // create the intermediate point + pNewX[1+oi*2] = pOldX[oi+1]; + pNewY[1+oi*2] = pOldY[oi]; + pNewZ[1+oi*2] = pOldZ[oi]; + // 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]; + break; + case CurveStyle_STEP_END: + case CurveStyle_GNM_STEP_END: + /** +------O + | + | + | + O + */ + // create the intermediate point + pNewX[1+oi*2] = pOldX[oi]; + pNewY[1+oi*2] = pOldY[oi+1]; + pNewZ[1+oi*2] = pOldZ[oi]; + // 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]; + break; + case CurveStyle_STEP_CENTER_X: + case CurveStyle_GNM_STEP_CENTER_X: + /** +--O + | + | + | + 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]; + // 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]; + // 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]; + break; + case CurveStyle_STEP_CENTER_Y: + case CurveStyle_GNM_STEP_CENTER_Y: + /** O + | + +-----+ + | + 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]; + // 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]; + // 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]; + break; + default: + // this should never be executed + OSL_FAIL("Unknown curvestyle in AreaChart::create_stepped_line"); + } + } + } + Clipping::clipPolygonAtRectangle( aSteppedPoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly ); + + return true; +} + bool AreaChart::impl_createLine( VDataSeries* pSeries , drawing::PolyPolygonShape3D* pSeriesPoly , PlottingPositionHelper* pPosHelper ) @@ -309,8 +443,23 @@ bool AreaChart::impl_createLine( VDataSeries* pSeries lcl_removeDuplicatePoints( aSplinePoly, *pPosHelper ); Clipping::clipPolygonAtRectangle( aSplinePoly, pPosHelper->getScaledLogicClipDoubleRect(), aPoly ); } - else + else if (CurveStyle_STEP_START==m_eCurveStyle || + CurveStyle_STEP_END==m_eCurveStyle || + CurveStyle_STEP_CENTER_Y==m_eCurveStyle || + CurveStyle_STEP_CENTER_X==m_eCurveStyle || + CurveStyle_GNM_STEP_START==m_eCurveStyle || + CurveStyle_GNM_STEP_END==m_eCurveStyle || + CurveStyle_GNM_STEP_CENTER_Y==m_eCurveStyle || + CurveStyle_GNM_STEP_CENTER_X==m_eCurveStyle) { + if (!create_stepped_line(*pSeriesPoly, m_eCurveStyle, pPosHelper, aPoly)) + { + return false; + } + } + else + { // default to creating a straight line + SAL_WARN_IF(CurveStyle_LINES != m_eCurveStyle, "chart2.areachart", "Unknown curve style"); bool bIsClipped = false; if( m_bConnectLastToFirstPoint && !ShapeFactory::isPolygonEmptyOrSinglePoint(*pSeriesPoly) ) { diff --git a/chart2/source/view/charttypes/AreaChart.hxx b/chart2/source/view/charttypes/AreaChart.hxx index cc8b9ae..cb6ea9f 100644 --- a/chart2/source/view/charttypes/AreaChart.hxx +++ b/chart2/source/view/charttypes/AreaChart.hxx @@ -80,6 +80,10 @@ private: //methods bool impl_createLine( VDataSeries* pSeries , ::com::sun::star::drawing::PolyPolygonShape3D* pSeriesPoly , PlottingPositionHelper* pPosHelper ); + bool create_stepped_line( ::com::sun::star::drawing::PolyPolygonShape3D aStartPoly + , ::com::sun::star::chart2::CurveStyle eCurveStyle + , PlottingPositionHelper* pPosHelper + , ::com::sun::star::drawing::PolyPolygonShape3D &aPoly ); private: //member PlottingPositionHelper* m_pMainPosHelper; diff --git a/offapi/com/sun/star/chart2/CurveStyle.idl b/offapi/com/sun/star/chart2/CurveStyle.idl index 3164186..5a6fdac 100644 --- a/offapi/com/sun/star/chart2/CurveStyle.idl +++ b/offapi/com/sun/star/chart2/CurveStyle.idl @@ -46,6 +46,55 @@ enum CurveStyle */ B_SPLINES, + /** Data points are connected via a 2-segmented stepped line. + The line starts horizontally. + O + | + | + | + O-----+ + */ + STEP_START, + + /** Data points are connected via a 2-segmented stepped line. + The line ends horizontally. + +------O + | + | + | + O + */ + STEP_END, + + /** Data points are connected via a 3-segmented stepped line. + The lines is horizontal till the center of the X values. + +--O + | + | + | + O--+ + */ + STEP_CENTER_X, + + /** Data points are connected via a 3-segmented stepped line. + The lines is horizontal at the center of the Y values. + O + | + +-----+ + | + O + */ + STEP_CENTER_Y, + + /** These have the same meaning as above, + but are linked to the older Gnumeric attributes before + ODF1.3 was approved. + */ + GNM_STEP_START, + GNM_STEP_END, + GNM_STEP_CENTER_X, + GNM_STEP_CENTER_Y, + /** */ NURBS diff --git a/xmloff/inc/xmloff/xmltoken.hxx b/xmloff/inc/xmloff/xmltoken.hxx index e7e886e..96025e4 100644 --- a/xmloff/inc/xmloff/xmltoken.hxx +++ b/xmloff/inc/xmloff/xmltoken.hxx @@ -2555,6 +2555,14 @@ namespace xmloff { namespace token { XML_INTERPOLATION, XML_CUBIC_SPLINE, XML_B_SPLINE, + XML_STEP_START, + XML_STEP_END, + XML_STEP_CENTER_X, + XML_STEP_CENTER_Y, + XML_GNM_STEP_START, + XML_GNM_STEP_END, + XML_GNM_STEP_CENTER_X, + XML_GNM_STEP_CENTER_Y, XML_N_DB_OASIS, XML_SHOW_FILTER_BUTTON, diff --git a/xmloff/source/chart/PropertyMap.hxx b/xmloff/source/chart/PropertyMap.hxx index e8298a6..d455a4a 100644 --- a/xmloff/source/chart/PropertyMap.hxx +++ b/xmloff/source/chart/PropertyMap.hxx @@ -290,10 +290,18 @@ SvXMLEnumMapEntry aXMLChartInterpolationTypeEnumMap[] = { // this is neither an enum nor a constants group, but just a // documented long property - { ::xmloff::token::XML_NONE, 0 }, - { ::xmloff::token::XML_CUBIC_SPLINE, 1 }, - { ::xmloff::token::XML_B_SPLINE, 2 }, - { ::xmloff::token::XML_TOKEN_INVALID,0 } + { ::xmloff::token::XML_NONE, 0 }, + { ::xmloff::token::XML_CUBIC_SPLINE, 1 }, + { ::xmloff::token::XML_B_SPLINE, 2 }, + { ::xmloff::token::XML_STEP_START, 3 }, + { ::xmloff::token::XML_STEP_END, 4 }, + { ::xmloff::token::XML_STEP_CENTER_X, 5 }, + { ::xmloff::token::XML_STEP_CENTER_Y, 6 }, + { ::xmloff::token::XML_GNM_STEP_START, 7 }, + { ::xmloff::token::XML_GNM_STEP_END, 8 }, + { ::xmloff::token::XML_GNM_STEP_CENTER_X, 9 }, + { ::xmloff::token::XML_GNM_STEP_CENTER_Y, 10 }, + { ::xmloff::token::XML_TOKEN_INVALID, 0 } }; SvXMLEnumMapEntry aXMLChartDataLabelPlacementEnumMap[] = diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx index afd52ba..c2d94d4 100644 --- a/xmloff/source/core/xmltoken.cxx +++ b/xmloff/source/core/xmltoken.cxx @@ -2556,6 +2556,15 @@ namespace xmloff { namespace token { TOKEN( "interpolation", XML_INTERPOLATION ), TOKEN( "cubic-spline", XML_CUBIC_SPLINE ), TOKEN( "b-spline", XML_B_SPLINE ), + TOKEN( "step-start", XML_STEP_START ), + TOKEN( "step-end", XML_STEP_END ), + TOKEN( "step-center-x", XML_STEP_CENTER_X ), + TOKEN( "step-center-y", XML_STEP_CENTER_Y ), + // also understand the older Gnumeric tookens + TOKEN( "gnm:step-start", XML_GNM_STEP_START ), + TOKEN( "gnm:step-end", XML_GNM_STEP_END ), + TOKEN( "gnm:step-center-x", XML_GNM_STEP_CENTER_X ), + TOKEN( "gnm:step-center-y", XML_GNM_STEP_CENTER_Y ), TOKEN( "urn:oasis:names:tc:opendocument:xmlns:database:1.0", XML_N_DB_OASIS ), TOKEN( "show-filter-button", XML_SHOW_FILTER_BUTTON ), diff --git a/xmloff/source/transform/StyleOASISTContext.cxx b/xmloff/source/transform/StyleOASISTContext.cxx index 6f7caf7..f5fc845 100644 --- a/xmloff/source/transform/StyleOASISTContext.cxx +++ b/xmloff/source/transform/StyleOASISTContext.cxx @@ -315,18 +315,26 @@ void XMLPropertiesTContext_Impl::StartElement( break; case XML_OPTACTION_INTERPOLATION: { - // 0: none - sal_Int32 nSplineType = 0; + // 0: none (default) + sal_Int32 nLineType = 0; if( IsXMLToken( rAttrValue, XML_CUBIC_SPLINE )) - nSplineType = 1; + nLineType = 1; else if( IsXMLToken( rAttrValue, XML_B_SPLINE )) - nSplineType = 2; + nLineType = 2; + else if( IsXMLToken( rAttrValue, XML_STEP_START ) || IsXMLToken( rAttrValue, XML_GNM_STEP_START ) ) + nLineType = 3; + else if( IsXMLToken( rAttrValue, XML_STEP_END ) || IsXMLToken( rAttrValue, XML_GNM_STEP_END ) ) + nLineType = 4; + else if( IsXMLToken( rAttrValue, XML_STEP_CENTER_X ) || IsXMLToken( rAttrValue, XML_GNM_STEP_CENTER_X ) ) + nLineType = 5; + else if( IsXMLToken( rAttrValue, XML_STEP_CENTER_Y ) || IsXMLToken( rAttrValue, XML_GNM_STEP_CENTER_Y ) ) + nLineType = 6; pAttrList->AddAttribute( GetTransformer().GetNamespaceMap().GetQNameByKey( XML_NAMESPACE_CHART, GetXMLToken( XML_SPLINES )), - OUString::valueOf( nSplineType )); + OUString::valueOf( nLineType )); } break; case XML_OPTACTION_INTERVAL_MAJOR: -- 1.7.11.7