nss: upgrade to release 3.73
[LibreOffice.git] / chart2 / source / tools / ExponentialRegressionCurveCalculator.cxx
blob1aa962ab5e3e571c642ab754e6bef6d00ba1c3d4
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <sal/config.h>
22 #include <string_view>
24 #include <ExponentialRegressionCurveCalculator.hxx>
25 #include <RegressionCalculationHelper.hxx>
26 #include <SpecialCharacters.hxx>
28 #include <rtl/math.hxx>
29 #include <rtl/ustrbuf.hxx>
31 using namespace ::com::sun::star;
33 namespace chart
36 ExponentialRegressionCurveCalculator::ExponentialRegressionCurveCalculator()
37 : m_fLogSlope(0.0)
38 , m_fLogIntercept(0.0)
39 , m_fSign(1.0)
41 ::rtl::math::setNan( & m_fLogSlope );
42 ::rtl::math::setNan( & m_fLogIntercept );
45 ExponentialRegressionCurveCalculator::~ExponentialRegressionCurveCalculator()
48 // ____ XRegressionCurveCalculator ____
49 void SAL_CALL ExponentialRegressionCurveCalculator::recalculateRegression(
50 const uno::Sequence< double >& aXValues,
51 const uno::Sequence< double >& aYValues )
53 RegressionCalculationHelper::tDoubleVectorPair aValues(
54 RegressionCalculationHelper::cleanup(
55 aXValues, aYValues,
56 RegressionCalculationHelper::isValidAndYPositive()));
57 m_fSign = 1.0;
59 size_t nMax = aValues.first.size();
60 if( nMax <= 1 ) // at least 2 points
62 aValues = RegressionCalculationHelper::cleanup(
63 aXValues, aYValues,
64 RegressionCalculationHelper::isValidAndYNegative());
65 nMax = aValues.first.size();
66 if( nMax <= 1 )
68 ::rtl::math::setNan( & m_fLogSlope );
69 ::rtl::math::setNan( & m_fLogIntercept );
70 ::rtl::math::setNan( & m_fCorrelationCoefficient );// actual it is coefficient of determination
71 return;
73 m_fSign = -1.0;
76 double fAverageX = 0.0, fAverageY = 0.0;
77 double fLogIntercept = ( mForceIntercept && (m_fSign * mInterceptValue)>0 ) ? log(m_fSign * mInterceptValue) : 0.0;
78 std::vector<double> yVector;
79 yVector.resize(nMax, 0.0);
81 size_t i = 0;
82 for( i = 0; i < nMax; ++i )
84 double yValue = log( m_fSign *aValues.second[i] );
85 if (mForceIntercept)
87 yValue -= fLogIntercept;
89 else
91 fAverageX += aValues.first[i];
92 fAverageY += yValue;
94 yVector[i] = yValue;
97 const double fN = static_cast< double >( nMax );
98 fAverageX /= fN;
99 fAverageY /= fN;
101 double fQx = 0.0, fQy = 0.0, fQxy = 0.0;
102 for( i = 0; i < nMax; ++i )
104 double fDeltaX = aValues.first[i] - fAverageX;
105 double fDeltaY = yVector[i] - fAverageY;
107 fQx += fDeltaX * fDeltaX;
108 fQy += fDeltaY * fDeltaY;
109 fQxy += fDeltaX * fDeltaY;
112 m_fLogSlope = fQxy / fQx;
113 m_fLogIntercept = mForceIntercept ? fLogIntercept : fAverageY - m_fLogSlope * fAverageX;
114 m_fCorrelationCoefficient = fQxy / sqrt( fQx * fQy );
117 double SAL_CALL ExponentialRegressionCurveCalculator::getCurveValue( double x )
119 double fResult;
120 ::rtl::math::setNan( & fResult );
122 if( ! ( std::isnan( m_fLogSlope ) ||
123 std::isnan( m_fLogIntercept )))
125 fResult = m_fSign * exp(m_fLogIntercept + x * m_fLogSlope);
128 return fResult;
131 uno::Sequence< geometry::RealPoint2D > SAL_CALL ExponentialRegressionCurveCalculator::getCurveValues(
132 double min, double max, ::sal_Int32 nPointCount,
133 const uno::Reference< chart2::XScaling >& xScalingX,
134 const uno::Reference< chart2::XScaling >& xScalingY,
135 sal_Bool bMaySkipPointsInCalculation )
137 if( bMaySkipPointsInCalculation &&
138 isLinearScaling( xScalingX ) &&
139 isLogarithmicScaling( xScalingY ))
141 // optimize result
142 uno::Sequence< geometry::RealPoint2D > aResult( 2 );
143 aResult[0].X = min;
144 aResult[0].Y = getCurveValue( min );
145 aResult[1].X = max;
146 aResult[1].Y = getCurveValue( max );
148 return aResult;
151 return RegressionCurveCalculator::getCurveValues( min, max, nPointCount, xScalingX, xScalingY, bMaySkipPointsInCalculation );
154 OUString ExponentialRegressionCurveCalculator::ImplGetRepresentation(
155 const uno::Reference< util::XNumberFormatter >& xNumFormatter,
156 sal_Int32 nNumberFormatKey, sal_Int32* pFormulaMaxWidth /* = nullptr */ ) const
158 double fIntercept = exp(m_fLogIntercept);
159 bool bHasSlope = !rtl::math::approxEqual( exp(m_fLogSlope), 1.0 );
160 bool bHasLogSlope = !rtl::math::approxEqual( fabs(m_fLogSlope), 1.0 );
161 bool bHasIntercept = !rtl::math::approxEqual( fIntercept, 1.0 ) && fIntercept != 0.0;
163 OUStringBuffer aBuf( mYName + " = " );
164 sal_Int32 nLineLength = aBuf.getLength();
165 sal_Int32 nValueLength=0;
166 if ( pFormulaMaxWidth && *pFormulaMaxWidth > 0 )
167 { // count characters different from coefficients
168 sal_Int32 nCharMin = nLineLength + 10 + mXName.getLength(); // 10 = "exp( ", " x )" + 2 extra characters
169 if ( m_fSign < 0.0 )
170 nCharMin += 2;
171 if ( fIntercept == 0.0 || ( !bHasSlope && m_fLogIntercept != 0.0 ) )
172 nCharMin += 3; // " + " special case where equation is written exp( a + b x )
173 if ( ( bHasIntercept || fIntercept == 0.0 || ( !bHasSlope && m_fLogIntercept != 0.0 ) ) &&
174 bHasLogSlope )
175 nValueLength = ( *pFormulaMaxWidth - nCharMin ) / 2;
176 else
177 nValueLength = *pFormulaMaxWidth - nCharMin;
178 if ( nValueLength <= 0 )
179 nValueLength = 1;
181 // temporary buffer
182 OUStringBuffer aTmpBuf("");
183 // if nValueLength not calculated then nullptr
184 sal_Int32* pValueLength = nValueLength ? &nValueLength : nullptr;
185 if ( m_fSign < 0.0 )
186 aTmpBuf.append( OUStringChar(aMinusSign) ).append( " " );
187 if ( bHasIntercept )
189 OUString aValueString = getFormattedString( xNumFormatter, nNumberFormatKey, fIntercept, pValueLength );
190 if ( aValueString != "1" ) // aValueString may be rounded to 1 if nValueLength is small
192 aTmpBuf.append( aValueString ).append( " " );
193 addStringToEquation( aBuf, nLineLength, aTmpBuf, pFormulaMaxWidth );
194 aTmpBuf.truncate();
197 aTmpBuf.append( "exp( " );
198 if ( !bHasIntercept )
200 if ( fIntercept == 0.0 || // underflow, a true zero is impossible
201 ( !bHasSlope && m_fLogIntercept != 0.0 ) ) // show logarithmic output, if intercept and slope both are near one
202 { // otherwise drop output of intercept, which is 1 here
203 OUString aValueString = getFormattedString( xNumFormatter, nNumberFormatKey, m_fLogIntercept, pValueLength );
204 if ( aValueString != "0" ) // aValueString may be rounded to 0 if nValueLength is small
206 aTmpBuf.append( aValueString ).append( (m_fLogSlope < 0.0) ? std::u16string_view(u" ") : std::u16string_view(u" + ") );
210 if ( m_fLogSlope < 0.0 )
211 aTmpBuf.append( OUStringChar(aMinusSign) ).append( " " );
212 if ( bHasLogSlope )
214 OUString aValueString = getFormattedString( xNumFormatter, nNumberFormatKey, fabs(m_fLogSlope), pValueLength );
215 if ( aValueString != "1" ) // aValueString may be rounded to 1 if nValueLength is small
217 aTmpBuf.append( aValueString ).append( " " );
220 aTmpBuf.append( mXName ).append(" )");
221 addStringToEquation( aBuf, nLineLength, aTmpBuf, pFormulaMaxWidth );
223 return aBuf.makeStringAndClear();
226 } // namespace chart
228 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */