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 "ExponentialRegressionCurveCalculator.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 ExponentialRegressionCurveCalculator::ExponentialRegressionCurveCalculator() : 46 m_fLogSlope( 0.0 ), 47 m_fLogIntercept( 0.0 ) 48 { 49 ::rtl::math::setNan( & m_fLogSlope ); 50 ::rtl::math::setNan( & m_fLogIntercept ); 51 } 52 53 ExponentialRegressionCurveCalculator::~ExponentialRegressionCurveCalculator() 54 {} 55 56 // ____ XRegressionCurveCalculator ____ 57 void SAL_CALL ExponentialRegressionCurveCalculator::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::isValidAndYPositive())); 66 67 const size_t nMax = aValues.first.size(); 68 if( nMax == 0 ) 69 { 70 ::rtl::math::setNan( & m_fLogSlope ); 71 ::rtl::math::setNan( & m_fLogIntercept ); 72 ::rtl::math::setNan( & m_fCorrelationCoeffitient );// actual it is coefficient of determination 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 += 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 = 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_fLogSlope = fQxy / fQx; 100 m_fLogIntercept = fAverageY - m_fLogSlope * fAverageX; 101 m_fCorrelationCoeffitient = fQxy / sqrt( fQx * fQy ); 102 103 } 104 105 double SAL_CALL ExponentialRegressionCurveCalculator::getCurveValue( double x ) 106 throw (lang::IllegalArgumentException, 107 uno::RuntimeException) 108 { 109 double fResult; 110 ::rtl::math::setNan( & fResult ); 111 112 if( ! ( ::rtl::math::isNan( m_fLogSlope ) || 113 ::rtl::math::isNan( m_fLogIntercept ))) 114 { 115 fResult = exp(m_fLogIntercept + x * m_fLogSlope); 116 } 117 118 return fResult; 119 } 120 121 uno::Sequence< geometry::RealPoint2D > SAL_CALL ExponentialRegressionCurveCalculator::getCurveValues( 122 double min, double max, ::sal_Int32 nPointCount, 123 const uno::Reference< chart2::XScaling >& xScalingX, 124 const uno::Reference< chart2::XScaling >& xScalingY, 125 ::sal_Bool bMaySkipPointsInCalculation ) 126 throw (lang::IllegalArgumentException, 127 uno::RuntimeException) 128 { 129 if( bMaySkipPointsInCalculation && 130 isLinearScaling( xScalingX ) && 131 isLogarithmicScaling( xScalingY )) 132 { 133 // optimize result 134 uno::Sequence< geometry::RealPoint2D > aResult( 2 ); 135 aResult[0].X = min; 136 aResult[0].Y = this->getCurveValue( min ); 137 aResult[1].X = max; 138 aResult[1].Y = this->getCurveValue( max ); 139 140 return aResult; 141 } 142 143 return RegressionCurveCalculator::getCurveValues( min, max, nPointCount, xScalingX, xScalingY, bMaySkipPointsInCalculation ); 144 } 145 146 147 OUString ExponentialRegressionCurveCalculator::ImplGetRepresentation( 148 const uno::Reference< util::XNumberFormatter >& xNumFormatter, 149 ::sal_Int32 nNumberFormatKey ) const 150 { 151 double fIntercept = exp(m_fLogIntercept); 152 double fSlope = exp(m_fLogSlope); 153 bool bHasSlope = !rtl::math::approxEqual( fSlope, 1.0 ); 154 bool bHasIntercept = !rtl::math::approxEqual( fIntercept, 1.0 ); 155 156 OUStringBuffer aBuf( C2U( "f(x) = " )); 157 158 if ( fIntercept == 0.0) 159 { 160 // underflow, a true zero is impossible 161 aBuf.append( C2U( "exp( " )); 162 aBuf.append( getFormattedString( xNumFormatter, nNumberFormatKey, m_fLogIntercept) ); 163 aBuf.append( (m_fLogSlope < 0.0) ? C2U( " - " ) : C2U( " + " )); 164 aBuf.append( getFormattedString( xNumFormatter, nNumberFormatKey, fabs(m_fLogSlope)) ); 165 aBuf.append( C2U( " x )" )); 166 } 167 else 168 { 169 if (bHasIntercept) 170 { 171 aBuf.append( getFormattedString( xNumFormatter, nNumberFormatKey, fIntercept) ); 172 aBuf.append( C2U( " exp( " )); 173 aBuf.append( getFormattedString( xNumFormatter, nNumberFormatKey, m_fLogSlope) ); 174 aBuf.append( C2U( " x )" )); 175 } 176 else 177 { 178 // show logarithmic output, if intercept and slope both are near one 179 // otherwise drop output of intercept, which is 1 here 180 aBuf.append( C2U( " exp( " )); 181 if (!bHasSlope) 182 { 183 aBuf.append( getFormattedString( xNumFormatter, nNumberFormatKey, m_fLogIntercept) ); 184 aBuf.append( (m_fLogSlope < 0.0) ? C2U( " - " ) : C2U( " + " )); 185 aBuf.append( getFormattedString( xNumFormatter, nNumberFormatKey, fabs(m_fLogSlope)) ); 186 } 187 else 188 { 189 aBuf.append( getFormattedString( xNumFormatter, nNumberFormatKey, m_fLogSlope) ); 190 } 191 aBuf.append( C2U( " x )" )); 192 } 193 } 194 195 return aBuf.makeStringAndClear(); 196 } 197 198 } // namespace chart 199