1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_chart2.hxx"
30 #include "PotentialRegressionCurveCalculator.hxx"
31 #include "macros.hxx"
32 #include "RegressionCalculationHelper.hxx"
33 
34 #include <rtl/math.hxx>
35 #include <rtl/ustrbuf.hxx>
36 
37 using namespace ::com::sun::star;
38 
39 using ::rtl::OUString;
40 using ::rtl::OUStringBuffer;
41 
42 namespace chart
43 {
44 
45 PotentialRegressionCurveCalculator::PotentialRegressionCurveCalculator() :
46         m_fSlope( 0.0 ),
47         m_fIntercept( 0.0 )
48 {
49     ::rtl::math::setNan( & m_fSlope );
50     ::rtl::math::setNan( & m_fIntercept );
51 }
52 
53 PotentialRegressionCurveCalculator::~PotentialRegressionCurveCalculator()
54 {}
55 
56 // ____ XRegressionCurveCalculator ____
57 void SAL_CALL PotentialRegressionCurveCalculator::recalculateRegression(
58     const uno::Sequence< double >& aXValues,
59     const uno::Sequence< double >& aYValues )
60     throw (uno::RuntimeException)
61 {
62     RegressionCalculationHelper::tDoubleVectorPair aValues(
63         RegressionCalculationHelper::cleanup(
64             aXValues, aYValues,
65             RegressionCalculationHelper::isValidAndBothPositive()));
66 
67     const size_t nMax = aValues.first.size();
68     if( nMax == 0 )
69     {
70         ::rtl::math::setNan( & m_fSlope );
71         ::rtl::math::setNan( & m_fIntercept );
72         ::rtl::math::setNan( & m_fCorrelationCoeffitient );
73         return;
74     }
75 
76     double fAverageX = 0.0, fAverageY = 0.0;
77     size_t i = 0;
78     for( i = 0; i < nMax; ++i )
79     {
80         fAverageX += log( aValues.first[i] );
81         fAverageY += log( aValues.second[i] );
82     }
83 
84     const double fN = static_cast< double >( nMax );
85     fAverageX /= fN;
86     fAverageY /= fN;
87 
88     double fQx = 0.0, fQy = 0.0, fQxy = 0.0;
89     for( i = 0; i < nMax; ++i )
90     {
91         double fDeltaX = log( aValues.first[i] ) - fAverageX;
92         double fDeltaY = log( aValues.second[i] ) - fAverageY;
93 
94         fQx  += fDeltaX * fDeltaX;
95         fQy  += fDeltaY * fDeltaY;
96         fQxy += fDeltaX * fDeltaY;
97     }
98 
99     m_fSlope = fQxy / fQx;
100     m_fIntercept = fAverageY - m_fSlope * fAverageX;
101     m_fCorrelationCoeffitient = fQxy / sqrt( fQx * fQy );
102 
103     m_fIntercept = exp( m_fIntercept );
104 }
105 
106 double SAL_CALL PotentialRegressionCurveCalculator::getCurveValue( double x )
107     throw (lang::IllegalArgumentException,
108            uno::RuntimeException)
109 {
110     double fResult;
111     ::rtl::math::setNan( & fResult );
112 
113     if( ! ( ::rtl::math::isNan( m_fSlope ) ||
114             ::rtl::math::isNan( m_fIntercept )))
115     {
116         fResult = m_fIntercept * pow( x, m_fSlope );
117     }
118 
119     return fResult;
120 }
121 
122 uno::Sequence< geometry::RealPoint2D > SAL_CALL PotentialRegressionCurveCalculator::getCurveValues(
123     double min, double max, ::sal_Int32 nPointCount,
124     const uno::Reference< chart2::XScaling >& xScalingX,
125     const uno::Reference< chart2::XScaling >& xScalingY,
126     ::sal_Bool bMaySkipPointsInCalculation )
127     throw (lang::IllegalArgumentException,
128            uno::RuntimeException)
129 {
130     if( bMaySkipPointsInCalculation &&
131         isLogarithmicScaling( xScalingX ) &&
132         isLogarithmicScaling( xScalingY ))
133     {
134         // optimize result
135         uno::Sequence< geometry::RealPoint2D > aResult( 2 );
136         aResult[0].X = min;
137         aResult[0].Y = this->getCurveValue( min );
138         aResult[1].X = max;
139         aResult[1].Y = this->getCurveValue( max );
140 
141         return aResult;
142     }
143     return RegressionCurveCalculator::getCurveValues( min, max, nPointCount, xScalingX, xScalingY, bMaySkipPointsInCalculation );
144 }
145 
146 OUString PotentialRegressionCurveCalculator::ImplGetRepresentation(
147     const uno::Reference< util::XNumberFormatter >& xNumFormatter,
148     ::sal_Int32 nNumberFormatKey ) const
149 {
150     OUStringBuffer aBuf( C2U( "f(x) = " ));
151 
152     if( m_fIntercept == 0.0 )
153     {
154         aBuf.append( sal_Unicode( '0' ));
155     }
156     else if( m_fSlope == 0.0 )
157     {
158         aBuf.append( getFormattedString( xNumFormatter, nNumberFormatKey, m_fIntercept ));
159     }
160     else
161     {
162         if( ! rtl::math::approxEqual( m_fIntercept, 1.0 ) )
163         {
164             aBuf.append( getFormattedString( xNumFormatter, nNumberFormatKey, m_fIntercept ));
165             aBuf.append( sal_Unicode( ' ' ));
166         }
167         if( m_fSlope != 0.0 )
168         {
169             aBuf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "x^" ));
170             aBuf.append( getFormattedString( xNumFormatter, nNumberFormatKey, m_fSlope ));
171         }
172     }
173 
174     return aBuf.makeStringAndClear();
175 }
176 
177 } //  namespace chart
178