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 "LogarithmicRegressionCurveCalculator.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 LogarithmicRegressionCurveCalculator::LogarithmicRegressionCurveCalculator() :
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 LogarithmicRegressionCurveCalculator::~LogarithmicRegressionCurveCalculator()
54 {}
55 
56 // ____ XRegressionCurve ____
57 void SAL_CALL LogarithmicRegressionCurveCalculator::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::isValidAndXPositive()));
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 += 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 = 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 
104 double SAL_CALL LogarithmicRegressionCurveCalculator::getCurveValue( double x )
105     throw (lang::IllegalArgumentException,
106            uno::RuntimeException)
107 {
108     double fResult;
109     ::rtl::math::setNan( & fResult );
110 
111     if( ! ( ::rtl::math::isNan( m_fSlope ) ||
112             ::rtl::math::isNan( m_fIntercept )))
113     {
114         fResult = m_fSlope * log( x ) + m_fIntercept;
115     }
116 
117     return fResult;
118 }
119 
120 uno::Sequence< geometry::RealPoint2D > SAL_CALL LogarithmicRegressionCurveCalculator::getCurveValues(
121     double min, double max, ::sal_Int32 nPointCount,
122     const uno::Reference< chart2::XScaling >& xScalingX,
123     const uno::Reference< chart2::XScaling >& xScalingY,
124     ::sal_Bool bMaySkipPointsInCalculation )
125     throw (lang::IllegalArgumentException,
126            uno::RuntimeException)
127 {
128     if( bMaySkipPointsInCalculation &&
129         isLogarithmicScaling( xScalingX ) &&
130         isLinearScaling( xScalingY ))
131     {
132         // optimize result
133         uno::Sequence< geometry::RealPoint2D > aResult( 2 );
134         aResult[0].X = min;
135         aResult[0].Y = this->getCurveValue( min );
136         aResult[1].X = max;
137         aResult[1].Y = this->getCurveValue( max );
138 
139         return aResult;
140     }
141     return RegressionCurveCalculator::getCurveValues( min, max, nPointCount, xScalingX, xScalingY, bMaySkipPointsInCalculation );
142 }
143 
144 OUString LogarithmicRegressionCurveCalculator::ImplGetRepresentation(
145     const uno::Reference< util::XNumberFormatter >& xNumFormatter,
146     ::sal_Int32 nNumberFormatKey ) const
147 {
148     OUStringBuffer aBuf( C2U( "f(x) = " ));
149 
150     bool bHaveSlope = false;
151 
152     if( m_fSlope != 0.0 )
153     {
154         if( ::rtl::math::approxEqual( fabs( m_fSlope ), 1.0 ))
155         {
156             if( m_fSlope < 0 )
157                 aBuf.append( UC_MINUS_SIGN );
158         }
159         else
160         {
161             aBuf.append( getFormattedString( xNumFormatter, nNumberFormatKey, m_fSlope ));
162             aBuf.append( UC_SPACE );
163         }
164         aBuf.appendAscii( RTL_CONSTASCII_STRINGPARAM( "ln(x)" ));
165         bHaveSlope = true;
166     }
167 
168     if( bHaveSlope )
169     {
170         if( m_fIntercept < 0.0 )
171         {
172             aBuf.append( UC_SPACE );
173             aBuf.append( UC_MINUS_SIGN );
174             aBuf.append( UC_SPACE );
175             aBuf.append( getFormattedString( xNumFormatter, nNumberFormatKey, fabs( m_fIntercept )));
176         }
177         else if( m_fIntercept > 0.0 )
178         {
179             aBuf.appendAscii( RTL_CONSTASCII_STRINGPARAM( " + " ));
180             aBuf.append( getFormattedString( xNumFormatter, nNumberFormatKey, m_fIntercept ));
181         }
182     }
183     else
184     {
185         aBuf.append( getFormattedString( xNumFormatter, nNumberFormatKey, m_fIntercept ));
186     }
187 
188     return aBuf.makeStringAndClear();
189 }
190 
191 } //  namespace chart
192