diff options
author | Tomaž Vajngerl <quikee@gmail.com> | 2013-05-27 08:02:37 +0200 |
---|---|---|
committer | Tomaž Vajngerl <quikee@gmail.com> | 2013-07-03 21:46:39 +0200 |
commit | e6a0cc2d6cb37bf4e04861173c7e55b307513778 (patch) | |
tree | 3569da62ea24a3fd4dce7216751692b1a5e79306 /chart2 | |
parent | fdo#61725 add SolarMutex until it works (diff) | |
download | core-e6a0cc2d6cb37bf4e04861173c7e55b307513778.tar.gz core-e6a0cc2d6cb37bf4e04861173c7e55b307513778.zip |
fdo#35712 polynomial and moving average regression lines
- added polynomial and moving average to the dialog
- implemented moving average and polynomal RegressionCurveCalculator
- added icon for polynomial regression curve
- prepare icon for moving average regression curve
- degree parameter for polynomial regression curve
- period parameter for moving average regression curve
- limit the curve to max and min x value
- added extrapolation
Change-Id: I4ebb8dc23a3aff285b999e115fdda20ab11910a5
Diffstat (limited to 'chart2')
29 files changed, 1501 insertions, 62 deletions
diff --git a/chart2/Library_chartcore.mk b/chart2/Library_chartcore.mk index 0be06a5dbf66..ab2d6e524b31 100644 --- a/chart2/Library_chartcore.mk +++ b/chart2/Library_chartcore.mk @@ -196,11 +196,13 @@ $(eval $(call gb_Library_add_exception_objects,chartcore,\ chart2/source/tools/MediaDescriptorHelper \ chart2/source/tools/ModifyListenerCallBack \ chart2/source/tools/ModifyListenerHelper \ + chart2/source/tools/MovingAverageRegressionCurveCalculator \ chart2/source/tools/MutexContainer \ chart2/source/tools/NameContainer \ chart2/source/tools/NumberFormatterWrapper \ chart2/source/tools/ObjectIdentifier \ chart2/source/tools/OPropertySet \ + chart2/source/tools/PolynomialRegressionCurveCalculator \ chart2/source/tools/PotentialRegressionCurveCalculator \ chart2/source/tools/PropertyHelper \ chart2/source/tools/RangeHighlighter \ diff --git a/chart2/source/chartcore.component b/chart2/source/chartcore.component index 68ddc0d83cff..b5550bd66340 100644 --- a/chart2/source/chartcore.component +++ b/chart2/source/chartcore.component @@ -73,6 +73,14 @@ <service name="com.sun.star.chart2.PotentialRegressionCurve"/> <service name="com.sun.star.chart2.RegressionCurve"/> </implementation> + <implementation name="com.sun.star.comp.chart2.PolynomialRegressionCurve"> + <service name="com.sun.star.chart2.PolynomialRegressionCurve"/> + <service name="com.sun.star.chart2.RegressionCurve"/> + </implementation> + <implementation name="com.sun.star.comp.chart2.MovingAverageRegressionCurve"> + <service name="com.sun.star.chart2.MovingAverageRegressionCurve"/> + <service name="com.sun.star.chart2.RegressionCurve"/> + </implementation> <implementation name="com.sun.star.comp.chart2.RegressionEquation"> <service name="com.sun.star.beans.PropertySet"/> <service name="com.sun.star.chart2.RegressionEquation"/> diff --git a/chart2/source/controller/chartapiwrapper/WrappedStatisticProperties.cxx b/chart2/source/controller/chartapiwrapper/WrappedStatisticProperties.cxx index 23e7de1fbb19..cbb208b70576 100644 --- a/chart2/source/controller/chartapiwrapper/WrappedStatisticProperties.cxx +++ b/chart2/source/controller/chartapiwrapper/WrappedStatisticProperties.cxx @@ -76,6 +76,12 @@ Any lcl_getRegressionDefault() case RegressionCurveHelper::REGRESSION_TYPE_POWER: eRet = ::com::sun::star::chart::ChartRegressionCurveType_POWER; break; + case RegressionCurveHelper::REGRESSION_TYPE_POLYNOMIAL: + eRet = ::com::sun::star::chart::ChartRegressionCurveType_POLYNOMIAL; + break; + /*case RegressionCurveHelper::REGRESSION_TYPE_MOVING_AVERAGE: + eRet = ::com::sun::star::chart::ChartRegressionCurveType_MOVING_AVERAGE; + break;*/ default: eRet = ::com::sun::star::chart::ChartRegressionCurveType_NONE; break; @@ -100,6 +106,7 @@ RegressionCurveHelper::tRegressionType lcl_getRegressionType( ::com::sun::star:: eRet = RegressionCurveHelper::REGRESSION_TYPE_EXP; break; case ::com::sun::star::chart::ChartRegressionCurveType_POLYNOMIAL: + //case ::com::sun::star::chart::ChartRegressionCurveType_MOVING_AVERAGE: case ::com::sun::star::chart::ChartRegressionCurveType_POWER: eRet = RegressionCurveHelper::REGRESSION_TYPE_POWER; break; diff --git a/chart2/source/controller/dialogs/Bitmaps.hrc b/chart2/source/controller/dialogs/Bitmaps.hrc index ced4537dd396..bcf1f37b8b6c 100644 --- a/chart2/source/controller/dialogs/Bitmaps.hrc +++ b/chart2/source/controller/dialogs/Bitmaps.hrc @@ -210,11 +210,13 @@ #define BMP_INDICATE_LEFT (RID_APP_START + 99) //SchStatisticTabPage and SchDataStatisticsDlg part 2 -#define BMP_REGRESSION_NONE (RID_APP_START + 92) -#define BMP_REGRESSION_LINEAR (RID_APP_START + 93) -#define BMP_REGRESSION_LOG (RID_APP_START + 94) -#define BMP_REGRESSION_EXP (RID_APP_START + 95) -#define BMP_REGRESSION_POWER (RID_APP_START + 96) +#define BMP_REGRESSION_NONE (RID_APP_START + 92) +#define BMP_REGRESSION_LINEAR (RID_APP_START + 93) +#define BMP_REGRESSION_LOG (RID_APP_START + 94) +#define BMP_REGRESSION_EXP (RID_APP_START + 95) +#define BMP_REGRESSION_POWER (RID_APP_START + 96) +#define BMP_REGRESSION_POLYNOMIAL (RID_APP_START + 110) +#define BMP_REGRESSION_MOVING_AVERAGE (RID_APP_START + 111) // hide-button for range-choosing #define IMG_SELECTRANGE (RID_APP_START + 100) diff --git a/chart2/source/controller/dialogs/Bitmaps.src b/chart2/source/controller/dialogs/Bitmaps.src index e566ec4f3540..9ee63814eea4 100644 --- a/chart2/source/controller/dialogs/Bitmaps.src +++ b/chart2/source/controller/dialogs/Bitmaps.src @@ -581,6 +581,20 @@ Image BMP_REGRESSION_POWER File = "regpow.png" ; }; }; +Image BMP_REGRESSION_POLYNOMIAL +{ + ImageBitmap = Bitmap + { + File = "regpoly.png" ; + }; +}; +Image BMP_REGRESSION_MOVING_AVERAGE +{ + ImageBitmap = Bitmap + { + File = "regavg.png" ; + }; +}; //--------------------- Image IMG_SELECTRANGE { diff --git a/chart2/source/controller/dialogs/res_Trendline.cxx b/chart2/source/controller/dialogs/res_Trendline.cxx index e74a84a7e800..803c0606fe19 100644 --- a/chart2/source/controller/dialogs/res_Trendline.cxx +++ b/chart2/source/controller/dialogs/res_Trendline.cxx @@ -26,32 +26,33 @@ #include "Bitmaps.hrc" #include "chartview/ChartSfxItemIds.hxx" +#include <svl/intitem.hxx> + #include <vector> #include <algorithm> namespace { -template< class T > - long lcl_getRightEdge( T & rControl ) -{ - return rControl.CalcMinimumSize().Width() + rControl.GetPosPixel().X() - rControl.GetParent()->GetPosPixel().X(); -} -template< class T > - void lcl_AdjustControlSize( T & rControl ) -{ - Size aSize( rControl.GetSizePixel()); - aSize.setWidth( rControl.CalcMinimumSize().Width()); - rControl.SetSizePixel( aSize ); -} + template< class T > long lcl_getRightEdge( T & rControl ) + { + return rControl.CalcMinimumSize().Width() + rControl.GetPosPixel().X() - rControl.GetParent()->GetPosPixel().X(); + } -void lcl_AdjustControlSize( Control & rControl, long nRightEdge ) -{ - Size aSize( rControl.GetSizePixel()); - Point aPosition( rControl.GetPosPixel()); - aSize.setWidth( nRightEdge - aPosition.getX()); - rControl.SetSizePixel( aSize ); -} + template< class T > void lcl_AdjustControlSize( T & rControl ) + { + Size aSize( rControl.GetSizePixel()); + aSize.setWidth( rControl.CalcMinimumSize().Width()); + rControl.SetSizePixel( aSize ); + } + + void lcl_AdjustControlSize( Control & rControl, long nRightEdge ) + { + Size aSize( rControl.GetSizePixel()); + Point aPosition( rControl.GetPosPixel()); + aSize.setWidth( nRightEdge - aPosition.getX()); + rControl.SetSizePixel( aSize ); + } } // anonymous namespace @@ -61,17 +62,29 @@ namespace chart TrendlineResources::TrendlineResources( Window * pParent, const SfxItemSet& rInAttrs, bool bNoneAvailable ) : m_aFLType( pParent, SchResId( FL_TYPE )), - m_aRBNone( pParent, SchResId( RB_NONE )), - m_aRBLinear( pParent, SchResId( RB_LINEAR )), - m_aRBLogarithmic( pParent, SchResId( RB_LOGARITHMIC )), - m_aRBExponential( pParent, SchResId( RB_EXPONENTIAL )), - m_aRBPower( pParent, SchResId( RB_POWER )), - - m_aFINone( pParent, SchResId( FI_NONE )), - m_aFILinear( pParent, SchResId( FI_LINEAR )), - m_aFILogarithmic( pParent, SchResId( FI_LOGARITHMIC )), - m_aFIExponential( pParent, SchResId( FI_EXPONENTIAL )), - m_aFIPower( pParent, SchResId( FI_POWER )), + m_aRBNone( pParent, SchResId( RB_NONE )), + m_aRBLinear( pParent, SchResId( RB_LINEAR )), + m_aRBLogarithmic( pParent, SchResId( RB_LOGARITHMIC )), + m_aRBExponential( pParent, SchResId( RB_EXPONENTIAL )), + m_aRBPower( pParent, SchResId( RB_POWER )), + m_aRBPolynomial( pParent, SchResId( RB_POLYNOMIAL )), + m_aRBMovingAverage( pParent, SchResId( RB_MOVING_AVERAGE )), + + m_aFINone( pParent, SchResId( FI_NONE )), + m_aFILinear( pParent, SchResId( FI_LINEAR )), + m_aFILogarithmic( pParent, SchResId( FI_LOGARITHMIC )), + m_aFIExponential( pParent, SchResId( FI_EXPONENTIAL )), + m_aFIPower( pParent, SchResId( FI_POWER )), + m_aFIPolynomial( pParent, SchResId( FI_POLYNOMIAL )), + m_aFIMovingAverage( pParent, SchResId( FI_MOVING_AVERAGE )), + + m_aNF_Degree( pParent, SchResId( NF_DEGREE )), + m_aNF_Period( pParent, SchResId( NF_PERIOD )), + + m_aNF_ExtrapolateForward( pParent, SchResId( NF_EXTRAPOLATE_FORWARD )), + m_aNF_ExtrapolateBackward( pParent, SchResId( NF_EXTRAPOLATE_BACKWARD )), + m_aCB_SetIntercept( pParent, SchResId( CB_SET_INTERCEPT )), + m_aNF_InterceptValue( pParent, SchResId( NF_INTERCEPT_VALUE )), m_aFLEquation( pParent, SchResId( FL_EQUATION )), m_aCBShowEquation( pParent, SchResId( CB_SHOW_EQUATION )), @@ -92,6 +105,11 @@ TrendlineResources::TrendlineResources( Window * pParent, const SfxItemSet& rInA m_aRBLogarithmic.SetClickHdl( LINK(this, TrendlineResources, SelectTrendLine )); m_aRBExponential.SetClickHdl( LINK(this, TrendlineResources, SelectTrendLine )); m_aRBPower.SetClickHdl( LINK(this, TrendlineResources, SelectTrendLine )); + m_aRBPolynomial.SetClickHdl( LINK(this, TrendlineResources, SelectTrendLine )); + m_aRBMovingAverage.SetClickHdl( LINK(this, TrendlineResources, SelectTrendLine )); + + m_aNF_InterceptValue.SetMin( SAL_MIN_INT64 ); + m_aNF_InterceptValue.SetMax( SAL_MAX_INT64 ); Reset( rInAttrs ); UpdateControlStates(); @@ -109,6 +127,8 @@ long TrendlineResources::adjustControlSizes() aControlRightEdges.push_back( lcl_getRightEdge( m_aRBLogarithmic )); aControlRightEdges.push_back( lcl_getRightEdge( m_aRBExponential )); aControlRightEdges.push_back( lcl_getRightEdge( m_aRBPower )); + aControlRightEdges.push_back( lcl_getRightEdge( m_aRBPolynomial )); + aControlRightEdges.push_back( lcl_getRightEdge( m_aRBMovingAverage )); aControlRightEdges.push_back( lcl_getRightEdge( m_aCBShowEquation )); aControlRightEdges.push_back( lcl_getRightEdge( m_aCBShowCorrelationCoeff )); @@ -117,6 +137,8 @@ long TrendlineResources::adjustControlSizes() lcl_AdjustControlSize( m_aRBLogarithmic ); lcl_AdjustControlSize( m_aRBExponential ); lcl_AdjustControlSize( m_aRBPower ); + lcl_AdjustControlSize( m_aRBPolynomial ); + lcl_AdjustControlSize( m_aRBMovingAverage ); lcl_AdjustControlSize( m_aCBShowEquation ); lcl_AdjustControlSize( m_aCBShowCorrelationCoeff ); @@ -147,6 +169,10 @@ IMPL_LINK( TrendlineResources, SelectTrendLine, RadioButton *, pRadioButton ) m_eTrendLineType = CHREGRESS_EXP; else if( pRadioButton == &m_aRBPower ) m_eTrendLineType = CHREGRESS_POWER; + else if( pRadioButton == &m_aRBPolynomial ) + m_eTrendLineType = CHREGRESS_POLYNOMIAL; + else if( pRadioButton == &m_aRBMovingAverage ) + m_eTrendLineType = CHREGRESS_MOVING_AVERAGE; else if( pRadioButton == &m_aRBNone ) { OSL_ASSERT( m_bNoneAvailable ); @@ -169,7 +195,49 @@ void TrendlineResources::Reset( const SfxItemSet& rInAttrs ) { const SvxChartRegressItem * pItem = dynamic_cast< const SvxChartRegressItem * >( pPoolItem ); if( pItem ) + { m_eTrendLineType = pItem->GetValue(); + } + } + + if( rInAttrs.GetItemState( SCHATTR_REGRESSION_DEGREE, sal_True, &pPoolItem ) == SFX_ITEM_SET ) + { + sal_Int32 nDegree = static_cast< const SfxInt32Item * >( pPoolItem )->GetValue(); + m_aNF_Degree.SetValue( nDegree ); + } + else + { + m_aNF_Period.SetValue( 2 ); + } + + if( rInAttrs.GetItemState( SCHATTR_REGRESSION_PERIOD, sal_True, &pPoolItem ) == SFX_ITEM_SET ) + { + sal_Int32 nPeriod = static_cast< const SfxInt32Item * >( pPoolItem )->GetValue(); + m_aNF_Period.SetValue( nPeriod ); + } + else + { + m_aNF_Period.SetValue( 2 ); + } + + if( rInAttrs.GetItemState( SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD, sal_True, &pPoolItem ) == SFX_ITEM_SET ) + { + double nValue = static_cast< const SvxDoubleItem * >( pPoolItem )->GetValue() * 100; + m_aNF_ExtrapolateForward.SetValue( (sal_Int64) nValue ); + } + else + { + m_aNF_ExtrapolateForward.SetValue( 0 ); + } + + if( rInAttrs.GetItemState( SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD, sal_True, &pPoolItem ) == SFX_ITEM_SET ) + { + double nValue = static_cast< const SvxDoubleItem * >( pPoolItem )->GetValue() * 100; + m_aNF_ExtrapolateBackward.SetValue( (sal_Int64) nValue ); + } + else + { + m_aNF_ExtrapolateBackward.SetValue( 0 ); } aState = rInAttrs.GetItemState( SCHATTR_REGRESSION_SHOW_EQUATION, sal_True, &pPoolItem ); @@ -214,6 +282,12 @@ void TrendlineResources::Reset( const SfxItemSet& rInAttrs ) case CHREGRESS_POWER : m_aRBPower.Check(); break; + case CHREGRESS_POLYNOMIAL : + m_aRBPolynomial.Check(); + break; + case CHREGRESS_MOVING_AVERAGE : + m_aRBMovingAverage.Check(); + break; case CHREGRESS_NONE: OSL_ASSERT( m_bNoneAvailable ); m_aRBNone.Check(); @@ -230,17 +304,32 @@ sal_Bool TrendlineResources::FillItemSet(SfxItemSet& rOutAttrs) const rOutAttrs.Put( SfxBoolItem( SCHATTR_REGRESSION_SHOW_EQUATION, m_aCBShowEquation.IsChecked() )); if( m_aCBShowCorrelationCoeff.GetState() != STATE_DONTKNOW ) rOutAttrs.Put( SfxBoolItem( SCHATTR_REGRESSION_SHOW_COEFF, m_aCBShowCorrelationCoeff.IsChecked() )); + + sal_Int32 aDegree = m_aNF_Degree.GetValue(); + rOutAttrs.Put(SfxInt32Item( SCHATTR_REGRESSION_DEGREE, aDegree ) ); + + sal_Int32 aPeriod = m_aNF_Period.GetValue(); + rOutAttrs.Put(SfxInt32Item( SCHATTR_REGRESSION_PERIOD, aPeriod ) ); + + double aExtrapolateForwardValue = m_aNF_ExtrapolateForward.GetValue() / 100.0; + rOutAttrs.Put(SvxDoubleItem( aExtrapolateForwardValue, SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD ) ); + + double aExtrapolateBackwardValue = m_aNF_ExtrapolateBackward.GetValue() / 100.0; + rOutAttrs.Put(SvxDoubleItem( aExtrapolateBackwardValue, SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD ) ); + return sal_True; } void TrendlineResources::FillValueSets() { if( m_bNoneAvailable ) - m_aFINone.SetImage( Image( SchResId( BMP_REGRESSION_NONE ) ) ); - m_aFILinear.SetImage( Image( SchResId( BMP_REGRESSION_LINEAR ) ) ); - m_aFILogarithmic.SetImage( Image( SchResId( BMP_REGRESSION_LOG ) ) ); - m_aFIExponential.SetImage( Image( SchResId( BMP_REGRESSION_EXP ) ) ); - m_aFIPower.SetImage( Image( SchResId( BMP_REGRESSION_POWER ) ) ); + m_aFINone.SetImage( Image( SchResId( BMP_REGRESSION_NONE ) ) ); + m_aFILinear.SetImage( Image( SchResId( BMP_REGRESSION_LINEAR ) ) ); + m_aFILogarithmic.SetImage( Image( SchResId( BMP_REGRESSION_LOG ) ) ); + m_aFIExponential.SetImage( Image( SchResId( BMP_REGRESSION_EXP ) ) ); + m_aFIPower.SetImage( Image( SchResId( BMP_REGRESSION_POWER ) ) ); + m_aFIPolynomial.SetImage( Image( SchResId( BMP_REGRESSION_POLYNOMIAL ) ) ); + m_aFIMovingAverage.SetImage(Image( SchResId( BMP_REGRESSION_MOVING_AVERAGE ) ) ); } void TrendlineResources::UpdateControlStates() diff --git a/chart2/source/controller/dialogs/res_Trendline.hxx b/chart2/source/controller/dialogs/res_Trendline.hxx index 9c2230de6725..bbabc7b82cfa 100644 --- a/chart2/source/controller/dialogs/res_Trendline.hxx +++ b/chart2/source/controller/dialogs/res_Trendline.hxx @@ -24,6 +24,7 @@ #include <vcl/fixed.hxx> #include <svl/itemset.hxx> #include <svx/chrtitem.hxx> +#include <vcl/field.hxx> namespace chart { @@ -48,14 +49,27 @@ private: RadioButton m_aRBLogarithmic; RadioButton m_aRBExponential; RadioButton m_aRBPower; + RadioButton m_aRBPolynomial; + RadioButton m_aRBMovingAverage; FixedImage m_aFINone; FixedImage m_aFILinear; FixedImage m_aFILogarithmic; FixedImage m_aFIExponential; FixedImage m_aFIPower; + FixedImage m_aFIPolynomial; + FixedImage m_aFIMovingAverage; + + NumericField m_aNF_Degree; + NumericField m_aNF_Period; + + NumericField m_aNF_ExtrapolateForward; + NumericField m_aNF_ExtrapolateBackward; + CheckBox m_aCB_SetIntercept; + NumericField m_aNF_InterceptValue; FixedLine m_aFLEquation; + CheckBox m_aCBShowEquation; CheckBox m_aCBShowCorrelationCoeff; diff --git a/chart2/source/controller/dialogs/res_Trendline_IDs.hrc b/chart2/source/controller/dialogs/res_Trendline_IDs.hrc index ca3aae9af87e..aa545690ea64 100644 --- a/chart2/source/controller/dialogs/res_Trendline_IDs.hrc +++ b/chart2/source/controller/dialogs/res_Trendline_IDs.hrc @@ -25,14 +25,25 @@ #define FI_LOGARITHMIC 3 #define FI_EXPONENTIAL 4 #define FI_POWER 5 +#define FI_POLYNOMIAL 6 +#define FI_MOVING_AVERAGE 7 + +#define NF_DEGREE 1 +#define NF_PERIOD 2 +#define NF_EXTRAPOLATE_FORWARD 3 +#define NF_EXTRAPOLATE_BACKWARD 4 +#define NF_INTERCEPT_VALUE 5 #define RB_NONE 1 #define RB_LINEAR 2 #define RB_LOGARITHMIC 3 #define RB_EXPONENTIAL 4 #define RB_POWER 5 +#define RB_POLYNOMIAL 6 +#define RB_MOVING_AVERAGE 7 #define CB_SHOW_EQUATION 1 #define CB_SHOW_CORRELATION_COEFF 2 +#define CB_SET_INTERCEPT 3 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/controller/dialogs/res_Trendline_tmpl.hrc b/chart2/source/controller/dialogs/res_Trendline_tmpl.hrc index ee78cc90f5a1..950726d25c56 100644 --- a/chart2/source/controller/dialogs/res_Trendline_tmpl.hrc +++ b/chart2/source/controller/dialogs/res_Trendline_tmpl.hrc @@ -64,6 +64,18 @@ RadioButton RB_POWER \ Size = MAP_APPFONT( 100, 10 ); \ Text[ en-US ] = "~Power"; \ }; \ +RadioButton RB_POLYNOMIAL \ +{ \ + Pos = MAP_APPFONT( 130, 22 + yoffset ); \ + Size = MAP_APPFONT( 70, 10 ); \ + Text[ en-US ] = "~Polynomial"; \ +}; \ +RadioButton RB_MOVING_AVERAGE \ +{ \ + Pos = MAP_APPFONT( 130, 66 + yoffset ); \ + Size = MAP_APPFONT( 70, 10 ); \ + Text[ en-US ] = "~Moving Average"; \ +}; \ FixedImage FI_NONE \ { \ Pos = MAP_APPFONT( 10, 18 ); \ @@ -89,16 +101,97 @@ FixedImage FI_POWER \ Pos = MAP_APPFONT( 10, 84 + yoffset ); \ Size = MAP_APPFONT( 18, 18 ); \ }; \ +FixedImage FI_POLYNOMIAL \ +{ \ + Pos = MAP_APPFONT( 110, 18 + yoffset ); \ + Size = MAP_APPFONT( 18, 18 ); \ +}; \ +FixedImage FI_MOVING_AVERAGE \ +{ \ + Pos = MAP_APPFONT( 110, 62 + yoffset ); \ + Size = MAP_APPFONT( 18, 18 ); \ +}; \ +NumericField NF_DEGREE \ +{ \ + Border = TRUE ; \ + Pos = MAP_APPFONT ( 110, 44 + yoffset ) ; \ + Size = MAP_APPFONT ( 28 , 12 ) ; \ + TabStop = TRUE ; \ + Repeat = TRUE ; \ + Spin = TRUE ; \ + StrictFormat = TRUE ; \ + SpinSize = 1 ; \ + Minimum = 2 ; \ + Maximum = 100 ; \ +}; \ +NumericField NF_PERIOD \ +{ \ + Border = TRUE ; \ + Pos = MAP_APPFONT ( 110, 88 + yoffset ) ; \ + Size = MAP_APPFONT ( 28 , 12 ) ; \ + TabStop = TRUE ; \ + Repeat = TRUE ; \ + Spin = TRUE ; \ + StrictFormat = TRUE ; \ + SpinSize = 1 ; \ + Minimum = 2 ; \ + Maximum = 100 ; \ +}; \ FixedLine FL_EQUATION \ { \ Pos = MAP_APPFONT( 6, 108 + yoffset ); \ Size = MAP_APPFONT( availablewidth - 12, 8 ); \ - Text[ en-US ] = "Equation"; \ + Text[ en-US ] = "Options"; \ +}; \ +NumericField NF_EXTRAPOLATE_FORWARD \ +{ \ + Border = TRUE ; \ + Pos = MAP_APPFONT ( 20, 120 + yoffset ) ; \ + Size = MAP_APPFONT ( 28 , 12 ) ; \ + TabStop = TRUE ; \ + Repeat = TRUE ; \ + Spin = TRUE ; \ + StrictFormat = TRUE ; \ + SpinSize = 50 ; \ + Minimum = 0 ; \ + Maximum = 10000 ; \ + DecimalDigits = 2 ; \ +}; \ +NumericField NF_EXTRAPOLATE_BACKWARD \ +{ \ + Border = TRUE ; \ + Pos = MAP_APPFONT ( 20, 134 + yoffset ) ; \ + Size = MAP_APPFONT ( 28 , 12 ) ; \ + TabStop = TRUE ; \ + Repeat = TRUE ; \ + Spin = TRUE ; \ + StrictFormat = TRUE ; \ + SpinSize = 50 ; \ + Minimum = 0 ; \ + Maximum = 10000 ; \ + DecimalDigits = 2 ; \ +}; \ +CheckBox CB_SET_INTERCEPT \ +{ \ + HelpId = HID_SCH_TRENDLINE_SHOW_EQUATION; \ + Pos = MAP_APPFONT( 10, 148 + yoffset ); \ + Size = MAP_APPFONT( 60, 10 ); \ + TabStop = TRUE; \ + Text[ en-US ] = "Set ~intercept"; \ +}; \ +NumericField NF_INTERCEPT_VALUE \ +{ \ + Border = TRUE ; \ + Pos = MAP_APPFONT ( 75, 148 + yoffset ) ; \ + Size = MAP_APPFONT ( 40 , 12 ) ; \ + TabStop = TRUE ; \ + Spin = FALSE ; \ + DecimalDigits = 4 ; \ }; \ CheckBox CB_SHOW_EQUATION \ { \ HelpId = HID_SCH_TRENDLINE_SHOW_EQUATION; \ - Pos = MAP_APPFONT( 10, 120 + yoffset ); \ + Pos = MAP_APPFONT( 10, 162 + yoffset ); \ Size = MAP_APPFONT( availablewidth - 20, 10 ); \ TabStop = TRUE; \ Text[ en-US ] = "Show ~equation"; \ @@ -106,7 +199,7 @@ CheckBox CB_SHOW_EQUATION \ CheckBox CB_SHOW_CORRELATION_COEFF \ { \ HelpId = HID_SCH_TRENDLINE_SHOW_R_SQUARED; \ - Pos = MAP_APPFONT( 10, 134 + yoffset ); \ + Pos = MAP_APPFONT( 10, 176 + yoffset ); \ Size = MAP_APPFONT( availablewidth - 20, 10 ); \ TabStop = TRUE; \ Text[ en-US ] = "Show ~coefficient of determination (R²)"; \ diff --git a/chart2/source/controller/inc/HelpIds.hrc b/chart2/source/controller/inc/HelpIds.hrc index d48189cdeeab..26ee1c816070 100644 --- a/chart2/source/controller/inc/HelpIds.hrc +++ b/chart2/source/controller/inc/HelpIds.hrc @@ -120,6 +120,8 @@ #define HID_SCH_TRENDLINE_RB_LOGARITHMIC "CHART2_HID_SCH_TRENDLINE_RB_LOGARITHMIC" #define HID_SCH_TRENDLINE_RB_EXPONENTIAL "CHART2_HID_SCH_TRENDLINE_RB_EXPONENTIAL" #define HID_SCH_TRENDLINE_RB_POWER "CHART2_HID_SCH_TRENDLINE_RB_POWER" +#define HID_SCH_TRENDLINE_RB_POLYNOMIC "CHART2_HID_SCH_TRENDLINE_RB_POLYNOMIC" +#define HID_SCH_TRENDLINE_RB_MOVING_AVERAGE "CHART2_HID_SCH_TRENDLINE_RB_MOVING_AVERAGE" #define HID_SCH_TRENDLINE_SHOW_EQUATION "CHART2_HID_SCH_TRENDLINE_SHOW_EQUATION" #define HID_SCH_TRENDLINE_SHOW_R_SQUARED "CHART2_HID_SCH_TRENDLINE_SHOW_R_SQUARED" diff --git a/chart2/source/controller/itemsetwrapper/RegressionCurveItemConverter.cxx b/chart2/source/controller/itemsetwrapper/RegressionCurveItemConverter.cxx index fcf49d925ec2..3ea1c0dd4363 100644 --- a/chart2/source/controller/itemsetwrapper/RegressionCurveItemConverter.cxx +++ b/chart2/source/controller/itemsetwrapper/RegressionCurveItemConverter.cxx @@ -28,6 +28,7 @@ // for SfxBoolItem #include <svl/eitem.hxx> +#include <svl/intitem.hxx> #include <svx/chrtitem.hxx> #include <functional> @@ -55,6 +56,12 @@ namespace case CHREGRESS_POWER: eType = ::chart::RegressionCurveHelper::REGRESSION_TYPE_POWER; break; + case CHREGRESS_POLYNOMIAL: + eType = ::chart::RegressionCurveHelper::REGRESSION_TYPE_POLYNOMIAL; + break; + case CHREGRESS_MOVING_AVERAGE: + eType = ::chart::RegressionCurveHelper::REGRESSION_TYPE_MOVING_AVERAGE; + break; case CHREGRESS_NONE: break; } @@ -156,6 +163,112 @@ bool RegressionCurveItemConverter::ApplySpecialItem( } break; + case SCHATTR_REGRESSION_DEGREE: + { + if( xCurve.is()) + { + sal_Int32 aDegree = static_cast< sal_Int32 >( + static_cast< const SfxInt32Item & >( + rItemSet.Get( nWhichId )).GetValue()); + + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + OSL_ASSERT( xProperties.is()); + sal_Int32 aOldDegree = 1; + if( xProperties.is() ) + { + xProperties->getPropertyValue( "PolynomialDegree" ) >>= aOldDegree; + if (aOldDegree != aDegree) + { + xProperties->setPropertyValue( "PolynomialDegree" , uno::makeAny( aDegree )); + bChanged = true; + } + } + } + } + break; + + case SCHATTR_REGRESSION_PERIOD: + { + if( xCurve.is()) + { + sal_Int32 aPeriod = static_cast< sal_Int32 >( + static_cast< const SfxInt32Item & >( + rItemSet.Get( nWhichId )).GetValue()); + + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + OSL_ASSERT( xProperties.is()); + sal_Int32 aOldPeriod = 2; + if( xProperties.is() ) + { + xProperties->getPropertyValue( "MovingAveragePeriod" ) >>= aOldPeriod; + if (aOldPeriod != aPeriod) + { + xProperties->setPropertyValue( "MovingAveragePeriod" , uno::makeAny( aPeriod )); + bChanged = true; + } + } + } + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD: + { + if( xCurve.is()) + { + double aValue = static_cast< double >( + static_cast< const SvxDoubleItem & >( + rItemSet.Get( nWhichId )).GetValue()); + + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + OSL_ASSERT( xProperties.is()); + double aOldValue = 0.0; + if( xProperties.is() ) + { + xProperties->getPropertyValue( "ExtrapolateForward" ) >>= aOldValue; + if (aOldValue != aValue) + { + xProperties->setPropertyValue( "ExtrapolateForward" , uno::makeAny( aValue )); + bChanged = true; + } + } + } + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD: + { + if( xCurve.is()) + { + double aValue = static_cast< double >( + static_cast< const SvxDoubleItem & >( + rItemSet.Get( nWhichId )).GetValue()); + + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + OSL_ASSERT( xProperties.is()); + double aOldValue = 0.0; + if( xProperties.is() ) + { + xProperties->getPropertyValue( "ExtrapolateBackward" ) >>= aOldValue; + if (aOldValue != aValue) + { + xProperties->setPropertyValue( "ExtrapolateBackward" , uno::makeAny( aValue )); + bChanged = true; + } + } + } + } + break; + + case SCHATTR_REGRESSION_SET_INTERCEPT: + { + } + break; + + case SCHATTR_REGRESSION_INTERCEPT_VALUE: + { + } + break; + case SCHATTR_REGRESSION_SHOW_EQUATION: { OSL_ASSERT( xCurve.is()); @@ -226,6 +339,74 @@ void RegressionCurveItemConverter::FillSpecialItem( } break; + case SCHATTR_REGRESSION_DEGREE: + { + OSL_ASSERT( xCurve.is()); + if( xCurve.is()) + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + OSL_ASSERT( xProperties.is()); + sal_Int32 aDegree = 1; + if( xProperties.is() && + (xProperties->getPropertyValue( "PolynomialDegree" ) >>= aDegree)) + { + rOutItemSet.Put( SfxInt32Item( nWhichId, aDegree )); + } + } + } + break; + + case SCHATTR_REGRESSION_PERIOD: + { + OSL_ASSERT( xCurve.is()); + if( xCurve.is()) + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + OSL_ASSERT( xProperties.is()); + sal_Int32 aPeriod = 2; + if( xProperties.is() && + (xProperties->getPropertyValue( "MovingAveragePeriod" ) >>= aPeriod)) + { + rOutItemSet.Put( SfxInt32Item( nWhichId, aPeriod )); + } + } + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD: + { + OSL_ASSERT( xCurve.is()); + if( xCurve.is()) + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + OSL_ASSERT( xProperties.is()); + double aValue = 0.0; + if( xProperties.is() && + (xProperties->getPropertyValue( "ExtrapolateForward" ) >>= aValue)) + { + rOutItemSet.Put( SvxDoubleItem( aValue, nWhichId )); + } + } + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD: + { + OSL_ASSERT( xCurve.is()); + if( xCurve.is()) + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + OSL_ASSERT( xProperties.is()); + double aValue = 0.0; + if( xProperties.is() && + (xProperties->getPropertyValue( "ExtrapolateBackward" ) >>= aValue)) + { + rOutItemSet.Put( SvxDoubleItem( aValue, nWhichId )); + } + } + } + break; + case SCHATTR_REGRESSION_SHOW_EQUATION: { OSL_ASSERT( xCurve.is()); diff --git a/chart2/source/controller/itemsetwrapper/StatisticsItemConverter.cxx b/chart2/source/controller/itemsetwrapper/StatisticsItemConverter.cxx index 6cddc4e5cf10..16ce0ceac0e1 100644 --- a/chart2/source/controller/itemsetwrapper/StatisticsItemConverter.cxx +++ b/chart2/source/controller/itemsetwrapper/StatisticsItemConverter.cxx @@ -84,6 +84,12 @@ uno::Reference< beans::XPropertySet > lcl_GetErrorBar( case CHREGRESS_POWER: eType = ::chart::RegressionCurveHelper::REGRESSION_TYPE_POWER; break; + case CHREGRESS_POLYNOMIAL: + eType = ::chart::RegressionCurveHelper::REGRESSION_TYPE_POLYNOMIAL; + break; + case CHREGRESS_MOVING_AVERAGE: + eType = ::chart::RegressionCurveHelper::REGRESSION_TYPE_MOVING_AVERAGE; + break; case CHREGRESS_NONE: break; } @@ -164,6 +170,38 @@ uno::Reference< beans::XPropertySet > lcl_getEquationProperties( return uno::Reference< beans::XPropertySet >(); } +uno::Reference< beans::XPropertySet > lcl_getCurveProperties( + const uno::Reference< beans::XPropertySet > & xSeriesPropSet, const SfxItemSet * pItemSet ) +{ + bool bExists = true; + + // ensure that a trendline is on + if( pItemSet ) + { + SvxChartRegress eRegress = CHREGRESS_NONE; + const SfxPoolItem *pPoolItem = NULL; + if( pItemSet->GetItemState( SCHATTR_REGRESSION_TYPE, sal_True, &pPoolItem ) == SFX_ITEM_SET ) + { + eRegress = static_cast< const SvxChartRegressItem * >( pPoolItem )->GetValue(); + bExists = ( eRegress != CHREGRESS_NONE ); + } + } + + if( bExists ) + { + uno::Reference< chart2::XRegressionCurveContainer > xRegCnt( xSeriesPropSet, uno::UNO_QUERY ); + uno::Reference< chart2::XRegressionCurve > xCurve( + ::chart::RegressionCurveHelper::getFirstCurveNotMeanValueLine( xRegCnt )); + if( xCurve.is()) + { + uno::Reference< beans::XPropertySet > xProperties( xCurve, uno::UNO_QUERY ); + return xProperties; + } + } + + return uno::Reference< beans::XPropertySet >(); +} + } // anonymous namespace namespace chart @@ -188,6 +226,10 @@ StatisticsItemConverter::StatisticsItemConverter( static_cast< int >( CHREGRESS_EXP )); OSL_ASSERT( static_cast< int >( RegressionCurveHelper::REGRESSION_TYPE_POWER ) == static_cast< int >( CHREGRESS_POWER )); + OSL_ASSERT( static_cast< int >( RegressionCurveHelper::REGRESSION_TYPE_POLYNOMIAL ) == + static_cast< int >( CHREGRESS_POLYNOMIAL )); + OSL_ASSERT( static_cast< int >( RegressionCurveHelper::REGRESSION_TYPE_MOVING_AVERAGE ) == + static_cast< int >( CHREGRESS_MOVING_AVERAGE )); } StatisticsItemConverter::~StatisticsItemConverter() @@ -397,6 +439,78 @@ bool StatisticsItemConverter::ApplySpecialItem( } break; + case SCHATTR_REGRESSION_DEGREE: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), &rItemSet )); + if( xProperties.is()) + { + sal_Int32 aDegree = 1; + xProperties->getPropertyValue( "PolynomialDegree" ) >>= aDegree; + sal_Int32 aNewDegree = + static_cast< const SfxInt32Item & >( rItemSet.Get( nWhichId )).GetValue(); + if( aDegree != aNewDegree ) + { + xProperties->setPropertyValue( "PolynomialDegree" , uno::makeAny( aNewDegree )); + bChanged = true; + } + } + } + break; + + case SCHATTR_REGRESSION_PERIOD: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), &rItemSet )); + if( xProperties.is()) + { + sal_Int32 aPeriod = 2; + xProperties->getPropertyValue( "MovingAveragePeriod" ) >>= aPeriod; + sal_Int32 aNewPeriod = + static_cast< const SfxInt32Item & >( rItemSet.Get( nWhichId )).GetValue(); + if( aPeriod != aNewPeriod ) + { + xProperties->setPropertyValue( "MovingAveragePeriod" , uno::makeAny( aNewPeriod )); + bChanged = true; + } + } + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), &rItemSet )); + if( xProperties.is()) + { + double aExtrapolationValue = 0.0; + xProperties->getPropertyValue( "ExtrapolateForward" ) >>= aExtrapolationValue; + double aNewValue = + static_cast< const SvxDoubleItem & >( rItemSet.Get( nWhichId )).GetValue(); + if( aExtrapolationValue != aNewValue ) + { + xProperties->setPropertyValue( "ExtrapolateForward" , uno::makeAny( aNewValue )); + bChanged = true; + } + } + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD: + { + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), &rItemSet )); + if( xProperties.is()) + { + double aExtrapolationValue = 0.0; + xProperties->getPropertyValue( "ExtrapolateBackward" ) >>= aExtrapolationValue; + double aNewValue = + static_cast< const SvxDoubleItem & >( rItemSet.Get( nWhichId )).GetValue(); + if( aExtrapolationValue != aNewValue ) + { + xProperties->setPropertyValue( "ExtrapolateBackward" , uno::makeAny( aNewValue )); + bChanged = true; + } + } + } + break; + case SCHATTR_REGRESSION_SHOW_EQUATION: { uno::Reference< beans::XPropertySet > xEqProp( lcl_getEquationProperties( GetPropertySet(), &rItemSet )); @@ -639,6 +753,46 @@ void StatisticsItemConverter::FillSpecialItem( } break; + case SCHATTR_REGRESSION_DEGREE: + { + sal_Int32 aDegree = 1; + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), 0 )); + if( xProperties.is()) + xProperties->getPropertyValue( "PolynomialDegree" ) >>= aDegree; + rOutItemSet.Put( SfxInt32Item( nWhichId, aDegree )); + } + break; + + case SCHATTR_REGRESSION_PERIOD: + { + sal_Int32 aPeriod = 2; + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), 0 )); + if( xProperties.is()) + xProperties->getPropertyValue( "MovingAveragePeriod" ) >>= aPeriod; + rOutItemSet.Put( SfxInt32Item( nWhichId, aPeriod )); + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD: + { + double aValue = 0.0; + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), 0 )); + if( xProperties.is()) + xProperties->getPropertyValue( "ExtrapolateForward" ) >>= aValue; + rOutItemSet.Put( SvxDoubleItem( aValue, nWhichId )); + } + break; + + case SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD: + { + double aValue = 0.0; + uno::Reference< beans::XPropertySet > xProperties( lcl_getCurveProperties( GetPropertySet(), 0 )); + if( xProperties.is()) + xProperties->getPropertyValue( "ExtrapolateBackward" ) >>= aValue; + rOutItemSet.Put( SvxDoubleItem( aValue, nWhichId )); + } + break; + case SCHATTR_REGRESSION_SHOW_EQUATION: { bool bShowEq = false; diff --git a/chart2/source/inc/MovingAverageRegressionCurveCalculator.hxx b/chart2/source/inc/MovingAverageRegressionCurveCalculator.hxx new file mode 100644 index 000000000000..54c5d644148f --- /dev/null +++ b/chart2/source/inc/MovingAverageRegressionCurveCalculator.hxx @@ -0,0 +1,68 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef CHART2_MOVINGAVERAGEREGRESSIONCURVECALCULATOR_HXX +#define CHART2_MOVINGAVERAGEREGRESSIONCURVECALCULATOR_HXX + +#include "RegressionCurveCalculator.hxx" +#include <vector> + +namespace chart +{ + +class MovingAverageRegressionCurveCalculator : public RegressionCurveCalculator +{ +public: + MovingAverageRegressionCurveCalculator(); + virtual ~MovingAverageRegressionCurveCalculator(); + +protected: + virtual OUString ImplGetRepresentation( + const ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatter >& xNumFormatter, + ::sal_Int32 nNumberFormatKey ) const; + +private: + // ____ XRegressionCurveCalculator ____ + virtual void SAL_CALL recalculateRegression( + const ::com::sun::star::uno::Sequence< double >& aXValues, + const ::com::sun::star::uno::Sequence< double >& aYValues ) + throw (::com::sun::star::uno::RuntimeException); + + virtual double SAL_CALL getCurveValue( double x ) + throw (::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::geometry::RealPoint2D > SAL_CALL getCurveValues( + double min, + double max, + ::sal_Int32 nPointCount, + const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XScaling >& xScalingX, + const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XScaling >& xScalingY, + ::sal_Bool bMaySkipPointsInCalculation ) + throw (::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); + + std::vector<double> aYList; + std::vector<double> aXList; +}; + +} // namespace chart + +#endif // CHART2_POLYNOMALREGRESSIONCURVECALCULATOR_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/PolynomialRegressionCurveCalculator.hxx b/chart2/source/inc/PolynomialRegressionCurveCalculator.hxx new file mode 100644 index 000000000000..b3b38a9d7eb7 --- /dev/null +++ b/chart2/source/inc/PolynomialRegressionCurveCalculator.hxx @@ -0,0 +1,69 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ +#ifndef CHART2_POLYNOMALREGRESSIONCURVECALCULATOR_HXX +#define CHART2_POLYNOMALREGRESSIONCURVECALCULATOR_HXX + +#include "RegressionCurveCalculator.hxx" +#include <vector> + +namespace chart +{ + +class PolynomialRegressionCurveCalculator : public RegressionCurveCalculator +{ +public: + PolynomialRegressionCurveCalculator(); + virtual ~PolynomialRegressionCurveCalculator(); + +protected: + virtual OUString ImplGetRepresentation( + const ::com::sun::star::uno::Reference< ::com::sun::star::util::XNumberFormatter >& xNumFormatter, + ::sal_Int32 nNumberFormatKey ) const; + +private: + // ____ XRegressionCurveCalculator ____ + virtual void SAL_CALL recalculateRegression( + const ::com::sun::star::uno::Sequence< double >& aXValues, + const ::com::sun::star::uno::Sequence< double >& aYValues ) + throw (::com::sun::star::uno::RuntimeException); + + virtual double SAL_CALL getCurveValue( double x ) + throw (::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); + + virtual ::com::sun::star::uno::Sequence< ::com::sun::star::geometry::RealPoint2D > SAL_CALL getCurveValues( + double min, + double max, + ::sal_Int32 nPointCount, + const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XScaling >& xScalingX, + const ::com::sun::star::uno::Reference< ::com::sun::star::chart2::XScaling >& xScalingY, + ::sal_Bool bMaySkipPointsInCalculation ) + throw (::com::sun::star::lang::IllegalArgumentException, + ::com::sun::star::uno::RuntimeException); + + double m_fSlope; + double m_fIntercept; + std::vector<double> mResult; +}; + +} // namespace chart + +#endif // CHART2_POLYNOMALREGRESSIONCURVECALCULATOR_HXX + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/inc/RegressionCurveCalculator.hxx b/chart2/source/inc/RegressionCurveCalculator.hxx index 27af18bd5830..0829543dfb5d 100644 --- a/chart2/source/inc/RegressionCurveCalculator.hxx +++ b/chart2/source/inc/RegressionCurveCalculator.hxx @@ -51,7 +51,16 @@ protected: double m_fCorrelationCoeffitient; + sal_Int32 mDegree; + double mIntercept; + sal_Int32 mPeriod; + // ____ XRegressionCurveCalculator ____ + virtual void SAL_CALL setRegressionProperties( + sal_Int32 aDegree, + double aIntercept, + sal_Int32 aPeriod); + virtual void SAL_CALL recalculateRegression( const ::com::sun::star::uno::Sequence< double >& aXValues, const ::com::sun::star::uno::Sequence< double >& aYValues ) diff --git a/chart2/source/inc/RegressionCurveHelper.hxx b/chart2/source/inc/RegressionCurveHelper.hxx index 743f0bd990d2..6adb73640443 100644 --- a/chart2/source/inc/RegressionCurveHelper.hxx +++ b/chart2/source/inc/RegressionCurveHelper.hxx @@ -92,6 +92,8 @@ public: REGRESSION_TYPE_LOG, REGRESSION_TYPE_EXP, REGRESSION_TYPE_POWER, + REGRESSION_TYPE_POLYNOMIAL, + REGRESSION_TYPE_MOVING_AVERAGE, REGRESSION_TYPE_MEAN_VALUE, REGRESSION_TYPE_UNKNOWN }; diff --git a/chart2/source/inc/Strings.hrc b/chart2/source/inc/Strings.hrc index aecf40112265..8ce4c2968f2e 100644 --- a/chart2/source/inc/Strings.hrc +++ b/chart2/source/inc/Strings.hrc @@ -97,6 +97,8 @@ #define STR_REGRESSION_EXP (RID_APP_START + 137) #define STR_REGRESSION_POWER (RID_APP_START + 138) #define STR_REGRESSION_MEAN (RID_APP_START + 180) +#define STR_REGRESSION_POLYNOMIAL (RID_APP_START + 300) +#define STR_REGRESSION_MOVING_AVERAGE (RID_APP_START + 301) //----------------------------------------------------------------------------- //for scale tab page diff --git a/chart2/source/inc/chartview/ChartSfxItemIds.hxx b/chart2/source/inc/chartview/ChartSfxItemIds.hxx index 8c6c6e12b6d2..62b1204f5a58 100644 --- a/chart2/source/inc/chartview/ChartSfxItemIds.hxx +++ b/chart2/source/inc/chartview/ChartSfxItemIds.hxx @@ -162,12 +162,18 @@ #define SCHATTR_AXIS_FOR_ALL_SERIES (SCHATTR_MISC_START) #define SCHATTR_MISC_END SCHATTR_AXIS_FOR_ALL_SERIES -// regression curve equation -#define SCHATTR_REGRESSION_START (SCHATTR_MISC_END + 1) -#define SCHATTR_REGRESSION_TYPE SCHATTR_REGRESSION_START -#define SCHATTR_REGRESSION_SHOW_EQUATION (SCHATTR_REGRESSION_START + 1) -#define SCHATTR_REGRESSION_SHOW_COEFF (SCHATTR_REGRESSION_START + 2) -#define SCHATTR_REGRESSION_END SCHATTR_REGRESSION_SHOW_COEFF +// regression curve +#define SCHATTR_REGRESSION_START (SCHATTR_MISC_END + 1) +#define SCHATTR_REGRESSION_TYPE SCHATTR_REGRESSION_START +#define SCHATTR_REGRESSION_SHOW_EQUATION (SCHATTR_REGRESSION_START + 1) +#define SCHATTR_REGRESSION_SHOW_COEFF (SCHATTR_REGRESSION_START + 2) +#define SCHATTR_REGRESSION_DEGREE (SCHATTR_REGRESSION_START + 3) +#define SCHATTR_REGRESSION_PERIOD (SCHATTR_REGRESSION_START + 4) +#define SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD (SCHATTR_REGRESSION_START + 5) +#define SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD (SCHATTR_REGRESSION_START + 6) +#define SCHATTR_REGRESSION_SET_INTERCEPT (SCHATTR_REGRESSION_START + 7) +#define SCHATTR_REGRESSION_INTERCEPT_VALUE (SCHATTR_REGRESSION_START + 8) +#define SCHATTR_REGRESSION_END SCHATTR_REGRESSION_INTERCEPT_VALUE #define SCHATTR_END SCHATTR_REGRESSION_END diff --git a/chart2/source/tools/MovingAverageRegressionCurveCalculator.cxx b/chart2/source/tools/MovingAverageRegressionCurveCalculator.cxx new file mode 100644 index 000000000000..1157cbe64179 --- /dev/null +++ b/chart2/source/tools/MovingAverageRegressionCurveCalculator.cxx @@ -0,0 +1,110 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "MovingAverageRegressionCurveCalculator.hxx" +#include "RegressionCalculationHelper.hxx" +#include "macros.hxx" + +#include <rtl/math.hxx> +#include <rtl/ustrbuf.hxx> +#include "gauss.hxx" + +using namespace ::com::sun::star; + + +namespace chart +{ + +MovingAverageRegressionCurveCalculator::MovingAverageRegressionCurveCalculator() +{} + +MovingAverageRegressionCurveCalculator::~MovingAverageRegressionCurveCalculator() +{} + +// ____ XRegressionCurveCalculator ____ +void SAL_CALL MovingAverageRegressionCurveCalculator::recalculateRegression( + const uno::Sequence< double >& aXValues, + const uno::Sequence< double >& aYValues ) + throw (uno::RuntimeException) +{ + ::rtl::math::setNan( & m_fCorrelationCoeffitient ); + + RegressionCalculationHelper::tDoubleVectorPair aValues( + RegressionCalculationHelper::cleanup( + aXValues, aYValues, + RegressionCalculationHelper::isValid())); + + const size_t aSize = aValues.first.size(); + + for( size_t i = mPeriod - 1; i < aSize; ++i ) + { + double yAvg; + yAvg = 0.0; + + for (sal_Int32 j = 0; j < mPeriod; j++) + { + yAvg += aValues.second[i - j]; + } + yAvg /= mPeriod; + + double x = aValues.first[i]; + aYList.push_back(yAvg); + aXList.push_back(x); + } +} + +double SAL_CALL MovingAverageRegressionCurveCalculator::getCurveValue( double /*x*/ ) + throw (lang::IllegalArgumentException, + uno::RuntimeException) +{ + double fResult; + rtl::math::setNan(&fResult); + return fResult; +} + +uno::Sequence< geometry::RealPoint2D > SAL_CALL MovingAverageRegressionCurveCalculator::getCurveValues( + double /*min*/, double /*max*/, sal_Int32 /*nPointCount*/, + const uno::Reference< chart2::XScaling >& /*xScalingX*/, + const uno::Reference< chart2::XScaling >& /*xScalingY*/, + sal_Bool /*bMaySkipPointsInCalculation*/ ) + throw (lang::IllegalArgumentException, + uno::RuntimeException) +{ + uno::Sequence< geometry::RealPoint2D > aResult( aYList.size() ); + + for( size_t i = 0; i < aYList.size(); ++i ) + { + aResult[i].X = aXList[i]; + aResult[i].Y = aYList[i]; + } + return aResult; +} + +OUString MovingAverageRegressionCurveCalculator::ImplGetRepresentation( + const uno::Reference< util::XNumberFormatter >& /*xNumFormatter*/, + ::sal_Int32 /*nNumberFormatKey*/ ) const +{ + OUStringBuffer aBuf( "f(x) = N/A"); + + return aBuf.makeStringAndClear(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/PolynomialRegressionCurveCalculator.cxx b/chart2/source/tools/PolynomialRegressionCurveCalculator.cxx new file mode 100644 index 000000000000..b28d297ad3af --- /dev/null +++ b/chart2/source/tools/PolynomialRegressionCurveCalculator.cxx @@ -0,0 +1,173 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include "PolynomialRegressionCurveCalculator.hxx" +#include "macros.hxx" +#include "RegressionCalculationHelper.hxx" + +#include <rtl/math.hxx> +#include <rtl/ustrbuf.hxx> +#include "gauss.hxx" + +using namespace ::com::sun::star; + + +namespace chart +{ + +PolynomialRegressionCurveCalculator::PolynomialRegressionCurveCalculator() +{} + +PolynomialRegressionCurveCalculator::~PolynomialRegressionCurveCalculator() +{} + +// ____ XRegressionCurveCalculator ____ +void SAL_CALL PolynomialRegressionCurveCalculator::recalculateRegression( + const uno::Sequence< double >& aXValues, + const uno::Sequence< double >& aYValues ) + throw (uno::RuntimeException) +{ + ::rtl::math::setNan( & m_fCorrelationCoeffitient ); + + RegressionCalculationHelper::tDoubleVectorPair aValues( + RegressionCalculationHelper::cleanup( aXValues, aYValues, RegressionCalculationHelper::isValid())); + + const double EPSILON( 1.0e-20 ); + + int aNumberOfPolyElements = mDegree + 1; + int aNumberOfPowers = 2 * aNumberOfPolyElements - 1; + + std::vector<double> aPowers; + aPowers.resize(aNumberOfPowers, 0.0); + + int aNumberOfColumns = aNumberOfPolyElements; + int aNumberOfRows = aNumberOfPolyElements + 1; + + std::vector<double> aMatrix; + aMatrix.resize(aNumberOfColumns*aNumberOfRows, 0.0); + + const size_t aSizeOfValues = aValues.first.size(); + + double yAverage = 0.0; + + aPowers[0] += aSizeOfValues; + + for( size_t i = 0; i < aSizeOfValues; ++i ) + { + double x = aValues.first[i]; + double y = aValues.second[i]; + + for (int j = 1; j < aNumberOfPowers; j++) { + aPowers[j] += pow(x, j); + } + + aMatrix[ 0 * aNumberOfRows + aNumberOfPolyElements] += y; + + for (int j = 1; j < aNumberOfPolyElements; j++) { + aMatrix[j * aNumberOfRows + aNumberOfPolyElements] += pow(x, j) * y; + } + + yAverage += y; + } + + yAverage = yAverage / aSizeOfValues; + + for (int y = 0; y < aNumberOfPolyElements; y++) { + for (int x = 0; x < aNumberOfPolyElements; x++) { + aMatrix[y * aNumberOfRows + x] = aPowers[y + x]; + } + } + + mResult.clear(); + mResult.resize(aNumberOfPolyElements, 0.0); + + solve(aMatrix, aNumberOfColumns, aNumberOfRows, mResult, EPSILON); + + // Calculate correlation coeffitient + + double aSumError = 0.0; + double aSumTotal = 0.0; + + for( size_t i = 0; i < aSizeOfValues; ++i ) + { + double x = aValues.first[i]; + double yActual = aValues.second[i]; + double yPredicted = getCurveValue( x ); + aSumTotal += (yActual - yAverage) * (yActual - yAverage); + aSumError += (yActual - yPredicted) * (yActual - yPredicted); + } + + m_fCorrelationCoeffitient = sqrt(1 - (aSumError / aSumTotal)); + +} + +double SAL_CALL PolynomialRegressionCurveCalculator::getCurveValue( double x ) + throw (lang::IllegalArgumentException, + uno::RuntimeException) +{ + double fResult; + rtl::math::setNan(&fResult); + + if (mResult.empty()) + { + return fResult; + } + + fResult = 0.0; + for (size_t i = 0; i<mResult.size(); i++) + { + fResult += mResult[i]*pow(x,i); + } + return fResult; +} + +uno::Sequence< geometry::RealPoint2D > SAL_CALL PolynomialRegressionCurveCalculator::getCurveValues( + double min, double max, sal_Int32 nPointCount, + const uno::Reference< chart2::XScaling >& xScalingX, + const uno::Reference< chart2::XScaling >& xScalingY, + sal_Bool bMaySkipPointsInCalculation ) + throw (lang::IllegalArgumentException, + uno::RuntimeException) +{ + + return RegressionCurveCalculator::getCurveValues( min, max, nPointCount, xScalingX, xScalingY, bMaySkipPointsInCalculation ); +} + +OUString PolynomialRegressionCurveCalculator::ImplGetRepresentation( + const uno::Reference< util::XNumberFormatter >& xNumFormatter, + ::sal_Int32 nNumberFormatKey ) const +{ + OUStringBuffer aBuf( "f(x) = "); + + for (int i=mResult.size()-1; i>=0; i--) + { + aBuf.append(getFormattedString( xNumFormatter, nNumberFormatKey, mResult[i] )); + if(i > 0) { + aBuf.appendAscii( "x^" ); + aBuf.append(i); + aBuf.append(" + "); + } + } + + return aBuf.makeStringAndClear(); +} + +} // namespace chart + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/RegressionCurveCalculator.cxx b/chart2/source/tools/RegressionCurveCalculator.cxx index b2f6b52f6db0..461e504c074e 100644 --- a/chart2/source/tools/RegressionCurveCalculator.cxx +++ b/chart2/source/tools/RegressionCurveCalculator.cxx @@ -37,9 +37,13 @@ namespace chart { RegressionCurveCalculator::RegressionCurveCalculator() : - m_fCorrelationCoeffitient( 0.0 ) + m_fCorrelationCoeffitient( 0.0 ), + mDegree(2), + mIntercept(0.0), + mPeriod(2) { - ::rtl::math::setNan( & m_fCorrelationCoeffitient ); + ::rtl::math::setNan( &m_fCorrelationCoeffitient ); + ::rtl::math::setNan( &mIntercept ); } RegressionCurveCalculator::~RegressionCurveCalculator() @@ -64,6 +68,15 @@ bool RegressionCurveCalculator::isLogarithmicScaling( return (xServiceName.is() && xServiceName->getServiceName().equals( aLogScalingServiceName )); } +void RegressionCurveCalculator::setRegressionProperties( + sal_Int32 aDegree, + double aIntercept, + sal_Int32 aPeriod) +{ + mDegree = aDegree; + mIntercept = aIntercept; + mPeriod = aPeriod; +} OUString RegressionCurveCalculator::getFormattedString( const Reference< util::XNumberFormatter >& xNumFormatter, @@ -102,6 +115,7 @@ Sequence< geometry::RealPoint2D > SAL_CALL RegressionCurveCalculator::getCurveVa double fMin( min ); double fFact = (max - min) / double(nPointCount-1); + if( bDoXScaling ) { fMin = xScalingX->doScaling( min ); diff --git a/chart2/source/tools/RegressionCurveHelper.cxx b/chart2/source/tools/RegressionCurveHelper.cxx index 08228bc0961f..5ffc1d5c3e4b 100644 --- a/chart2/source/tools/RegressionCurveHelper.cxx +++ b/chart2/source/tools/RegressionCurveHelper.cxx @@ -20,6 +20,8 @@ #include "RegressionCurveHelper.hxx" #include "MeanValueRegressionCurveCalculator.hxx" #include "LinearRegressionCurveCalculator.hxx" +#include "PolynomialRegressionCurveCalculator.hxx" +#include "MovingAverageRegressionCurveCalculator.hxx" #include "LogarithmicRegressionCurveCalculator.hxx" #include "ExponentialRegressionCurveCalculator.hxx" #include "PotentialRegressionCurveCalculator.hxx" @@ -63,6 +65,12 @@ OUString lcl_getServiceNameForType( ::chart::RegressionCurveHelper::tRegressionT case ::chart::RegressionCurveHelper::REGRESSION_TYPE_POWER: aServiceName = "com.sun.star.chart2.PotentialRegressionCurve"; break; + case ::chart::RegressionCurveHelper::REGRESSION_TYPE_POLYNOMIAL: + aServiceName = "com.sun.star.chart2.PolynomialRegressionCurve"; + break; + case ::chart::RegressionCurveHelper::REGRESSION_TYPE_MOVING_AVERAGE: + aServiceName = "com.sun.star.chart2.MovingAverageRegressionCurve"; + break; default: OSL_FAIL("unknown regression curve type - use linear instead"); aServiceName = "com.sun.star.chart2.LinearRegressionCurve"; @@ -107,6 +115,14 @@ Reference< XRegressionCurve > RegressionCurveHelper::createRegressionCurveByServ { xResult.set( new PotentialRegressionCurve( xContext ) ); } + else if( aServiceName == "com.sun.star.chart2.PolynomialRegressionCurve" ) + { + xResult.set( new PolynomialRegressionCurve( xContext ) ); + } + else if( aServiceName == "com.sun.star.chart2.MovingAverageRegressionCurve" ) + { + xResult.set( new MovingAverageRegressionCurve( xContext ) ); + } return xResult; } @@ -139,6 +155,14 @@ Reference< XRegressionCurveCalculator > RegressionCurveHelper::createRegressionC { xResult.set( new PotentialRegressionCurveCalculator() ); } + else if( aServiceName == "com.sun.star.chart2.PolynomialRegressionCurve" ) + { + xResult.set( new PolynomialRegressionCurveCalculator() ); + } + else if( aServiceName == "com.sun.star.chart2.MovingAverageRegressionCurve" ) + { + xResult.set( new MovingAverageRegressionCurveCalculator() ); + } return xResult; } @@ -349,7 +373,6 @@ void RegressionCurveHelper::addRegressionCurve( uno::Reference< chart2::XRegressionCurve > xCurve; OUString aServiceName( lcl_getServiceNameForType( eType )); - if( !aServiceName.isEmpty()) { // todo: use a valid context @@ -529,6 +552,14 @@ RegressionCurveHelper::tRegressionType RegressionCurveHelper::getRegressionType( { eResult = REGRESSION_TYPE_MEAN_VALUE; } + else if( aServiceName == "com.sun.star.chart2.PolynomialRegressionCurve" ) + { + eResult = REGRESSION_TYPE_POLYNOMIAL; + } + else if( aServiceName == "com.sun.star.chart2.MovingAverageRegressionCurve" ) + { + eResult = REGRESSION_TYPE_MOVING_AVERAGE; + } } } catch( const Exception & ex ) @@ -591,6 +622,14 @@ OUString RegressionCurveHelper::getUINameForRegressionCurve( const Reference< XR { aResult = SCH_RESSTR(STR_REGRESSION_POWER); } + else if( aServiceName == "com.sun.star.chart2.PolynomialRegressionCurve" ) + { + aResult = SCH_RESSTR(STR_REGRESSION_POLYNOMIAL); + } + else if( aServiceName == "com.sun.star.chart2.MovingAverageRegressionCurve" ) + { + aResult = SCH_RESSTR(STR_REGRESSION_MOVING_AVERAGE); + } return aResult; } diff --git a/chart2/source/tools/RegressionCurveModel.cxx b/chart2/source/tools/RegressionCurveModel.cxx index 2dd96ed2be86..cd9b143d7cc6 100644 --- a/chart2/source/tools/RegressionCurveModel.cxx +++ b/chart2/source/tools/RegressionCurveModel.cxx @@ -47,10 +47,54 @@ static const OUString lcl_aImplementationName_Exponential( "com.sun.star.comp.chart2.ExponentialRegressionCurve" ); static const OUString lcl_aImplementationName_Potential( "com.sun.star.comp.chart2.PotentialRegressionCurve" ); +static const OUString lcl_aImplementationName_Polynomial( + "com.sun.star.comp.chart2.PolynomialRegressionCurve" ); +static const OUString lcl_aImplementationName_MovingAverage( + "com.sun.star.comp.chart2.MovingAverageRegressionCurve" ); static const OUString lcl_aServiceName( "com.sun.star.chart2.RegressionCurve" ); +enum +{ + PROPERTY_DEGREE, + PROPERTY_PERIOD, + PROPERTY_EXTRAPOLATE_FORWARD, + PROPERTY_EXTRAPOLATE_BACKWARD +}; + +void lcl_AddPropertiesToVector( + ::std::vector< Property > & rOutProperties ) +{ + rOutProperties.push_back( + Property( "PolynomialDegree", + PROPERTY_DEGREE, + ::getCppuType( reinterpret_cast< const sal_Int32* >(0)), + beans::PropertyAttribute::BOUND | + beans::PropertyAttribute::MAYBEDEFAULT )); + + rOutProperties.push_back( + Property( "MovingAveragePeriod", + PROPERTY_PERIOD, + ::getCppuType( reinterpret_cast< const sal_Int32* >(0)), + beans::PropertyAttribute::BOUND | + beans::PropertyAttribute::MAYBEDEFAULT )); + + rOutProperties.push_back( + Property( "ExtrapolateForward", + PROPERTY_EXTRAPOLATE_FORWARD, + ::getCppuType( reinterpret_cast< const double* >(0) ), + beans::PropertyAttribute::BOUND | + beans::PropertyAttribute::MAYBEDEFAULT )); + + rOutProperties.push_back( + Property( "ExtrapolateBackward", + PROPERTY_EXTRAPOLATE_BACKWARD, + ::getCppuType( reinterpret_cast< const double* >(0) ), + beans::PropertyAttribute::BOUND | + beans::PropertyAttribute::MAYBEDEFAULT )); +} + struct StaticXXXDefaults_Initializer { ::chart::tPropertyValueMap* operator()() @@ -82,6 +126,7 @@ private: uno::Sequence< Property > lcl_GetPropertySequence() { ::std::vector< ::com::sun::star::beans::Property > aProperties; + lcl_AddPropertiesToVector( aProperties ); ::chart::LinePropertiesHelper::AddPropertiesToVector( aProperties ); ::std::sort( aProperties.begin(), aProperties.end(), @@ -189,6 +234,10 @@ OUString SAL_CALL RegressionCurveModel::getServiceName() return OUString("com.sun.star.chart2.ExponentialRegressionCurve"); case CURVE_TYPE_POWER: return OUString("com.sun.star.chart2.PotentialRegressionCurve"); + case CURVE_TYPE_POLYNOMIAL: + return OUString("com.sun.star.chart2.PolynomialRegressionCurve"); + case CURVE_TYPE_MOVING_AVERAGE: + return OUString("com.sun.star.chart2.MovingAverageRegressionCurve"); } return OUString(); @@ -426,6 +475,59 @@ uno::Reference< util::XCloneable > SAL_CALL PotentialRegressionCurve::createClon } +PolynomialRegressionCurve::PolynomialRegressionCurve( + const uno::Reference< uno::XComponentContext > & xContext ) + : RegressionCurveModel( xContext, RegressionCurveModel::CURVE_TYPE_POLYNOMIAL ) +{} +PolynomialRegressionCurve::PolynomialRegressionCurve( + const PolynomialRegressionCurve & rOther ) : + RegressionCurveModel( rOther ) +{} +PolynomialRegressionCurve::~PolynomialRegressionCurve() +{} +uno::Sequence< OUString > PolynomialRegressionCurve::getSupportedServiceNames_Static() +{ + uno::Sequence< OUString > aServices( 2 ); + aServices[ 0 ] = lcl_aServiceName; + aServices[ 1 ] = "com.sun.star.chart2.PolynomialRegressionCurve"; + return aServices; +} +// implement XServiceInfo methods basing upon getSupportedServiceNames_Static +APPHELPER_XSERVICEINFO_IMPL( PolynomialRegressionCurve, lcl_aImplementationName_Polynomial ); + +uno::Reference< util::XCloneable > SAL_CALL PolynomialRegressionCurve::createClone() + throw (uno::RuntimeException) +{ + return uno::Reference< util::XCloneable >( new PolynomialRegressionCurve( *this )); +} + +MovingAverageRegressionCurve::MovingAverageRegressionCurve( + const uno::Reference< uno::XComponentContext > & xContext ) + : RegressionCurveModel( xContext, RegressionCurveModel::CURVE_TYPE_MOVING_AVERAGE ) +{} +MovingAverageRegressionCurve::MovingAverageRegressionCurve( + const MovingAverageRegressionCurve & rOther ) : + RegressionCurveModel( rOther ) +{} +MovingAverageRegressionCurve::~MovingAverageRegressionCurve() +{} +uno::Sequence< OUString > MovingAverageRegressionCurve::getSupportedServiceNames_Static() +{ + uno::Sequence< OUString > aServices( 2 ); + aServices[ 0 ] = lcl_aServiceName; + aServices[ 1 ] = "com.sun.star.chart2.MovingAverageRegressionCurve"; + return aServices; +} +// implement XServiceInfo methods basing upon getSupportedServiceNames_Static +APPHELPER_XSERVICEINFO_IMPL( MovingAverageRegressionCurve, lcl_aImplementationName_MovingAverage ); + +uno::Reference< util::XCloneable > SAL_CALL MovingAverageRegressionCurve::createClone() + throw (uno::RuntimeException) +{ + return uno::Reference< util::XCloneable >( new MovingAverageRegressionCurve( *this )); +} + + } // namespace chart /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/tools/RegressionCurveModel.hxx b/chart2/source/tools/RegressionCurveModel.hxx index 8434d21731de..1415e8745149 100644 --- a/chart2/source/tools/RegressionCurveModel.hxx +++ b/chart2/source/tools/RegressionCurveModel.hxx @@ -61,7 +61,9 @@ public: CURVE_TYPE_LINEAR, CURVE_TYPE_LOGARITHM, CURVE_TYPE_EXPONENTIAL, - CURVE_TYPE_POWER + CURVE_TYPE_POWER, + CURVE_TYPE_POLYNOMIAL, + CURVE_TYPE_MOVING_AVERAGE }; RegressionCurveModel( ::com::sun::star::uno::Reference< @@ -245,6 +247,46 @@ public: APPHELPER_SERVICE_FACTORY_HELPER( PotentialRegressionCurve ) }; +class PolynomialRegressionCurve : public RegressionCurveModel +{ +public: + explicit PolynomialRegressionCurve( + const ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XComponentContext > & xContext ); + explicit PolynomialRegressionCurve( + const PolynomialRegressionCurve & rOther ); + virtual ~PolynomialRegressionCurve(); + + // ____ XCloneable ____ + virtual ::com::sun::star::uno::Reference< ::com::sun::star::util::XCloneable > SAL_CALL createClone() + throw (::com::sun::star::uno::RuntimeException); + + /// XServiceInfo declarations + APPHELPER_XSERVICEINFO_DECL() + /// establish methods for factory instatiation + APPHELPER_SERVICE_FACTORY_HELPER( PolynomialRegressionCurve ) +}; + +class MovingAverageRegressionCurve : public RegressionCurveModel +{ +public: + explicit MovingAverageRegressionCurve( + const ::com::sun::star::uno::Reference< + ::com::sun::star::uno::XComponentContext > & xContext ); + explicit MovingAverageRegressionCurve( + const MovingAverageRegressionCurve & rOther ); + virtual ~MovingAverageRegressionCurve(); + + // ____ XCloneable ____ + virtual ::com::sun::star::uno::Reference< ::com::sun::star::util::XCloneable > SAL_CALL createClone() + throw (::com::sun::star::uno::RuntimeException); + + /// XServiceInfo declarations + APPHELPER_XSERVICEINFO_DECL() + /// establish methods for factory instatiation + APPHELPER_SERVICE_FACTORY_HELPER( MovingAverageRegressionCurve ) +}; + } // namespace chart // CHART2_REGRESSIONCURVEMODEL_HXX diff --git a/chart2/source/tools/gauss.hxx b/chart2/source/tools/gauss.hxx new file mode 100644 index 000000000000..6cd63ce30691 --- /dev/null +++ b/chart2/source/tools/gauss.hxx @@ -0,0 +1,166 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +/** This method eliminates elements below main diagonal in the given + matrix by gaussian elimination. + + @param matrix + The matrix to operate on. Last column is the result vector (right + hand side of the linear equation). After successful termination, + the matrix is upper triangular. The matrix is expected to be in + row major order. + + @param rows + Number of rows in matrix + + @param cols + Number of columns in matrix + + @param minPivot + If the pivot element gets lesser than minPivot, this method fails, + otherwise, elimination succeeds and true is returned. + + @return true, if elimination succeeded. + */ +template <class Matrix, typename BaseType> +bool eliminate( Matrix& matrix, + int rows, + int cols, + const BaseType& minPivot ) +{ + BaseType temp; + int max, i, j, k; /* *must* be signed, when looping like: j>=0 ! */ + + /* eliminate below main diagonal */ + for(i=0; i<cols-1; ++i) + { + /* find best pivot */ + max = i; + for(j=i+1; j<rows; ++j) + if( fabs(matrix[ j*cols + i ]) > fabs(matrix[ max*cols + i ]) ) + max = j; + + /* check pivot value */ + if( fabs(matrix[ max*cols + i ]) < minPivot ) + return false; /* pivot too small! */ + + /* interchange rows 'max' and 'i' */ + for(k=0; k<cols; ++k) + { + temp = matrix[ i*cols + k ]; + matrix[ i*cols + k ] = matrix[ max*cols + k ]; + matrix[ max*cols + k ] = temp; + } + + /* eliminate column */ + for(j=i+1; j<rows; ++j) + for(k=cols-1; k>=i; --k) + matrix[ j*cols + k ] -= matrix[ i*cols + k ] * + matrix[ j*cols + i ] / matrix[ i*cols + i ]; + } + + /* everything went well */ + return true; +} + + +/** Retrieve solution vector of linear system by substituting backwards. + + This operation _relies_ on the previous successful + application of eliminate()! + + @param matrix + Matrix in upper diagonal form, as e.g. generated by eliminate() + + @param rows + Number of rows in matrix + + @param cols + Number of columns in matrix + + @param result + Result vector. Given matrix must have space for one column (rows entries). + + @return true, if back substitution was possible (i.e. no division + by zero occurred). + */ +template <class Matrix, class Vector, typename BaseType> +bool substitute( const Matrix& matrix, + int rows, + int cols, + Vector& result ) +{ + BaseType temp; + int j,k; /* *must* be signed, when looping like: j>=0 ! */ + + /* substitute backwards */ + for(j=rows-1; j>=0; --j) + { + temp = 0.0; + for(k=j+1; k<cols-1; ++k) + temp += matrix[ j*cols + k ] * result[k]; + + if( matrix[ j*cols + j ] == 0.0 ) + return false; /* imminent division by zero! */ + + result[j] = (matrix[ j*cols + cols-1 ] - temp) / matrix[ j*cols + j ]; + } + + /* everything went well */ + return true; +} + + +/** This method determines solution of given linear system, if any + + This is a wrapper for eliminate and substitute, given matrix must + contain right side of equation as the last column. + + @param matrix + The matrix to operate on. Last column is the result vector (right + hand side of the linear equation). After successful termination, + the matrix is upper triangular. The matrix is expected to be in + row major order. + + @param rows + Number of rows in matrix + + @param cols + Number of columns in matrix + + @param minPivot + If the pivot element gets lesser than minPivot, this method fails, + otherwise, elimination succeeds and true is returned. + + @return true, if elimination succeeded. + */ +template <class Matrix, class Vector, typename BaseType> +bool solve( Matrix& matrix, + int rows, + int cols, + Vector& result, + BaseType minPivot ) +{ + if( eliminate<Matrix,BaseType>(matrix, rows, cols, minPivot) ) + return substitute<Matrix,Vector,BaseType>(matrix, rows, cols, result); + + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/chart2/source/view/charttypes/VSeriesPlotter.cxx b/chart2/source/view/charttypes/VSeriesPlotter.cxx index 194a06defb51..d5ba36f9bae6 100644 --- a/chart2/source/view/charttypes/VSeriesPlotter.cxx +++ b/chart2/source/view/charttypes/VSeriesPlotter.cxx @@ -974,20 +974,45 @@ void VSeriesPlotter::createRegressionCurvesShapes( VDataSeries& rVDataSeries rVDataSeries.getModel(), uno::UNO_QUERY ); if(!xRegressionContainer.is()) return; - double fMinX = m_pPosHelper->getLogicMinX(); - double fMaxX = m_pPosHelper->getLogicMaxX(); uno::Sequence< uno::Reference< XRegressionCurve > > aCurveList = xRegressionContainer->getRegressionCurves(); for(sal_Int32 nN=0; nN<aCurveList.getLength(); nN++) { + uno::Reference< beans::XPropertySet > xProperties( aCurveList[nN], uno::UNO_QUERY ); + + sal_Int32 aDegree = 2; + sal_Int32 aPeriod = 2; + double aExtrapolateForward = 0.0; + double aExtrapolateBackward = 0.0; + double aIntercept; + rtl::math::setNan(&aIntercept); + + if ( xProperties.is() ) + { + xProperties->getPropertyValue( "PolynomialDegree") >>= aDegree; + xProperties->getPropertyValue( "MovingAveragePeriod") >>= aPeriod; + xProperties->getPropertyValue( "ExtrapolateForward") >>= aExtrapolateForward; + xProperties->getPropertyValue( "ExtrapolateBackward") >>= aExtrapolateBackward; + } + uno::Reference< XRegressionCurveCalculator > xRegressionCurveCalculator( aCurveList[nN]->getCalculator() ); + if( ! xRegressionCurveCalculator.is()) continue; + + double fMinX; + double fMaxX; + + rVDataSeries.getMinMaxXValue(fMinX, fMaxX); + fMaxX += aExtrapolateForward; + fMinX -= aExtrapolateBackward; + + xRegressionCurveCalculator->setRegressionProperties(aDegree, aIntercept, aPeriod); xRegressionCurveCalculator->recalculateRegression( rVDataSeries.getAllX(), rVDataSeries.getAllY() ); - sal_Int32 nRegressionPointCount = 50;//@todo find a more optimal solution if more complicated curve types are introduced + sal_Int32 nRegressionPointCount = 100; //@todo find a more optimal solution if more complicated curve types are introduced drawing::PolyPolygonShape3D aRegressionPoly; aRegressionPoly.SequenceX.realloc(1); aRegressionPoly.SequenceY.realloc(1); @@ -1056,12 +1081,12 @@ void VSeriesPlotter::createRegressionCurvesShapes( VDataSeries& rVDataSeries } // curve equation and correlation coefficient - uno::Reference< beans::XPropertySet > xEqProp( aCurveList[nN]->getEquationProperties()); - if( xEqProp.is()) + uno::Reference< beans::XPropertySet > xEquationProperties( aCurveList[nN]->getEquationProperties()); + if( xEquationProperties.is()) { createRegressionCurveEquationShapes( rVDataSeries.getDataCurveEquationCID( nN ), - xEqProp, xEquationTarget, xRegressionCurveCalculator, + xEquationProperties, xEquationTarget, xRegressionCurveCalculator, aDefaultPos ); } } diff --git a/chart2/source/view/inc/VDataSeries.hxx b/chart2/source/view/inc/VDataSeries.hxx index 38c7929bc3e7..b7a5116b4317 100644 --- a/chart2/source/view/inc/VDataSeries.hxx +++ b/chart2/source/view/inc/VDataSeries.hxx @@ -81,6 +81,8 @@ public: double getXValue( sal_Int32 index ) const; double getYValue( sal_Int32 index ) const; + void getMinMaxXValue( double& fMin, double& fMax ) const; + double getY_Min( sal_Int32 index ) const; double getY_Max( sal_Int32 index ) const; double getY_First( sal_Int32 index ) const; diff --git a/chart2/source/view/main/ChartItemPool.cxx b/chart2/source/view/main/ChartItemPool.cxx index 7cbeea50fbda..bfae31e1ff7c 100644 --- a/chart2/source/view/main/ChartItemPool.cxx +++ b/chart2/source/view/main/ChartItemPool.cxx @@ -149,9 +149,15 @@ ChartItemPool::ChartItemPool(): ppPoolDefaults[SCHATTR_AXIS_FOR_ALL_SERIES - SCHATTR_START] = new SfxInt32Item(SCHATTR_AXIS_FOR_ALL_SERIES, 0); - ppPoolDefaults[SCHATTR_REGRESSION_TYPE - SCHATTR_START] = new SvxChartRegressItem (CHREGRESS_NONE, SCHATTR_REGRESSION_TYPE); - ppPoolDefaults[SCHATTR_REGRESSION_SHOW_EQUATION - SCHATTR_START] = new SfxBoolItem(SCHATTR_REGRESSION_SHOW_EQUATION, 0); - ppPoolDefaults[SCHATTR_REGRESSION_SHOW_COEFF - SCHATTR_START] = new SfxBoolItem(SCHATTR_REGRESSION_SHOW_COEFF, 0); + ppPoolDefaults[SCHATTR_REGRESSION_TYPE - SCHATTR_START] = new SvxChartRegressItem (CHREGRESS_NONE, SCHATTR_REGRESSION_TYPE); + ppPoolDefaults[SCHATTR_REGRESSION_SHOW_EQUATION - SCHATTR_START] = new SfxBoolItem(SCHATTR_REGRESSION_SHOW_EQUATION, 0); + ppPoolDefaults[SCHATTR_REGRESSION_SHOW_COEFF - SCHATTR_START] = new SfxBoolItem(SCHATTR_REGRESSION_SHOW_COEFF, 0); + ppPoolDefaults[SCHATTR_REGRESSION_DEGREE - SCHATTR_START] = new SfxInt32Item( SCHATTR_REGRESSION_DEGREE, 2 ); + ppPoolDefaults[SCHATTR_REGRESSION_PERIOD - SCHATTR_START] = new SfxInt32Item( SCHATTR_REGRESSION_PERIOD, 2 ); + ppPoolDefaults[SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD - SCHATTR_START] = new SvxDoubleItem( 0.0, SCHATTR_REGRESSION_EXTRAPOLATE_FORWARD ); + ppPoolDefaults[SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD - SCHATTR_START] = new SvxDoubleItem( 0.0, SCHATTR_REGRESSION_EXTRAPOLATE_BACKWARD ); + ppPoolDefaults[SCHATTR_REGRESSION_SET_INTERCEPT - SCHATTR_START] = new SfxBoolItem( SCHATTR_REGRESSION_SET_INTERCEPT, false ); + ppPoolDefaults[SCHATTR_REGRESSION_INTERCEPT_VALUE - SCHATTR_START] = new SvxDoubleItem( 0.0, SCHATTR_REGRESSION_INTERCEPT_VALUE); /************************************************************************** * ItemInfos diff --git a/chart2/source/view/main/VDataSeries.cxx b/chart2/source/view/main/VDataSeries.cxx index ac6da72da1d2..d7e1522d88b0 100644 --- a/chart2/source/view/main/VDataSeries.cxx +++ b/chart2/source/view/main/VDataSeries.cxx @@ -515,6 +515,33 @@ double VDataSeries::getYValue( sal_Int32 index ) const return fRet; } +void VDataSeries::getMinMaxXValue(double& fMin, double& fMax) const +{ + rtl::math::setNan( &fMax ); + rtl::math::setNan( &fMin ); + + uno::Sequence< double > aValuesX = getAllX(); + + if(aValuesX.getLength() > 0) + { + double aValue; + + fMax = fMin = aValuesX[0]; + + for (sal_Int32 i = 1; i < aValuesX.getLength(); i++) + { + aValue = aValuesX[i]; + if ( aValue > fMax) + { + fMax = aValue; + } + else if ( aValue < fMin) + { + fMin = aValue; + } + } + } +} double VDataSeries::getY_Min( sal_Int32 index ) const { return m_aValues_Y_Min.getValue( index ); |