1*cde9e8dcSAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3*cde9e8dcSAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4*cde9e8dcSAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5*cde9e8dcSAndrew Rist  * distributed with this work for additional information
6*cde9e8dcSAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7*cde9e8dcSAndrew Rist  * to you under the Apache License, Version 2.0 (the
8*cde9e8dcSAndrew Rist  * "License"); you may not use this file except in compliance
9*cde9e8dcSAndrew Rist  * with the License.  You may obtain a copy of the License at
10*cde9e8dcSAndrew Rist  *
11*cde9e8dcSAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12*cde9e8dcSAndrew Rist  *
13*cde9e8dcSAndrew Rist  * Unless required by applicable law or agreed to in writing,
14*cde9e8dcSAndrew Rist  * software distributed under the License is distributed on an
15*cde9e8dcSAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16*cde9e8dcSAndrew Rist  * KIND, either express or implied.  See the License for the
17*cde9e8dcSAndrew Rist  * specific language governing permissions and limitations
18*cde9e8dcSAndrew Rist  * under the License.
19*cde9e8dcSAndrew Rist  *
20*cde9e8dcSAndrew Rist  *************************************************************/
21*cde9e8dcSAndrew Rist 
22*cde9e8dcSAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_chart2.hxx"
26cdf0e10cSrcweir #include "ScaleAutomatism.hxx"
27cdf0e10cSrcweir #include "macros.hxx"
28cdf0e10cSrcweir #include "Tickmarks_Equidistant.hxx"
29cdf0e10cSrcweir #include "DateHelper.hxx"
30cdf0e10cSrcweir #include "DateScaling.hxx"
31cdf0e10cSrcweir #include "AxisHelper.hxx"
32cdf0e10cSrcweir #include <com/sun/star/chart/TimeUnit.hpp>
33cdf0e10cSrcweir 
34cdf0e10cSrcweir #include <rtl/math.hxx>
35cdf0e10cSrcweir #include <tools/debug.hxx>
36cdf0e10cSrcweir 
37cdf0e10cSrcweir //.............................................................................
38cdf0e10cSrcweir namespace chart
39cdf0e10cSrcweir {
40cdf0e10cSrcweir //.............................................................................
41cdf0e10cSrcweir using namespace ::com::sun::star;
42cdf0e10cSrcweir using namespace ::com::sun::star::chart2;
43cdf0e10cSrcweir using ::com::sun::star::chart::TimeUnit::DAY;
44cdf0e10cSrcweir using ::com::sun::star::chart::TimeUnit::MONTH;
45cdf0e10cSrcweir using ::com::sun::star::chart::TimeUnit::YEAR;
46cdf0e10cSrcweir 
47cdf0e10cSrcweir const sal_Int32 MAXIMUM_MANUAL_INCREMENT_COUNT = 500;
48cdf0e10cSrcweir const sal_Int32 MAXIMUM_SUB_INCREMENT_COUNT = 100;
49cdf0e10cSrcweir 
lcl_getMaximumAutoIncrementCount(sal_Int32 nAxisType)50cdf0e10cSrcweir sal_Int32 lcl_getMaximumAutoIncrementCount( sal_Int32 nAxisType )
51cdf0e10cSrcweir {
52cdf0e10cSrcweir     sal_Int32 nMaximumAutoIncrementCount = 10;
53cdf0e10cSrcweir     if( nAxisType==AxisType::DATE )
54cdf0e10cSrcweir         nMaximumAutoIncrementCount = MAXIMUM_MANUAL_INCREMENT_COUNT;
55cdf0e10cSrcweir     return nMaximumAutoIncrementCount;
56cdf0e10cSrcweir }
57cdf0e10cSrcweir 
58cdf0e10cSrcweir namespace
59cdf0e10cSrcweir {
60cdf0e10cSrcweir 
lcl_ensureMaximumSubIncrementCount(sal_Int32 & rnSubIntervalCount)61cdf0e10cSrcweir void lcl_ensureMaximumSubIncrementCount( sal_Int32& rnSubIntervalCount )
62cdf0e10cSrcweir {
63cdf0e10cSrcweir     if( rnSubIntervalCount > MAXIMUM_SUB_INCREMENT_COUNT )
64cdf0e10cSrcweir         rnSubIntervalCount = MAXIMUM_SUB_INCREMENT_COUNT;
65cdf0e10cSrcweir }
66cdf0e10cSrcweir 
67cdf0e10cSrcweir }//end anonymous namespace
68cdf0e10cSrcweir 
69cdf0e10cSrcweir 
70cdf0e10cSrcweir //.............................................................................
71cdf0e10cSrcweir 
ExplicitScaleData()72cdf0e10cSrcweir ExplicitScaleData::ExplicitScaleData()
73cdf0e10cSrcweir     : Minimum(0.0)
74cdf0e10cSrcweir     , Maximum(10.0)
75cdf0e10cSrcweir     , Origin(0.0)
76cdf0e10cSrcweir     , Orientation(::com::sun::star::chart2::AxisOrientation_MATHEMATICAL)
77cdf0e10cSrcweir     , Scaling()
78cdf0e10cSrcweir     , AxisType(::com::sun::star::chart2::AxisType::REALNUMBER)
79cdf0e10cSrcweir     , ShiftedCategoryPosition(false)
80cdf0e10cSrcweir     , TimeResolution(::com::sun::star::chart::TimeUnit::DAY)
81cdf0e10cSrcweir     , NullDate(30,12,1899)
82cdf0e10cSrcweir {
83cdf0e10cSrcweir }
84cdf0e10cSrcweir 
ExplicitSubIncrement()85cdf0e10cSrcweir ExplicitSubIncrement::ExplicitSubIncrement()
86cdf0e10cSrcweir     : IntervalCount(2)
87cdf0e10cSrcweir     , PostEquidistant(true)
88cdf0e10cSrcweir {
89cdf0e10cSrcweir }
90cdf0e10cSrcweir 
91cdf0e10cSrcweir 
ExplicitIncrementData()92cdf0e10cSrcweir ExplicitIncrementData::ExplicitIncrementData()
93cdf0e10cSrcweir     : MajorTimeInterval(1,::com::sun::star::chart::TimeUnit::DAY)
94cdf0e10cSrcweir     , MinorTimeInterval(1,::com::sun::star::chart::TimeUnit::DAY)
95cdf0e10cSrcweir     , Distance(1.0)
96cdf0e10cSrcweir 	, PostEquidistant(true)
97cdf0e10cSrcweir 	, BaseValue(0.0)
98cdf0e10cSrcweir     , SubIncrements()
99cdf0e10cSrcweir {
100cdf0e10cSrcweir }
101cdf0e10cSrcweir 
102cdf0e10cSrcweir //.............................................................................
103cdf0e10cSrcweir 
ScaleAutomatism(const ScaleData & rSourceScale,const Date & rNullDate)104cdf0e10cSrcweir ScaleAutomatism::ScaleAutomatism( const ScaleData& rSourceScale, const Date& rNullDate )
105cdf0e10cSrcweir                     : m_aSourceScale( rSourceScale )
106cdf0e10cSrcweir                     , m_fValueMinimum( 0.0 )
107cdf0e10cSrcweir                     , m_fValueMaximum( 0.0 )
108cdf0e10cSrcweir                     , m_nMaximumAutoMainIncrementCount( lcl_getMaximumAutoIncrementCount( rSourceScale.AxisType ) )
109cdf0e10cSrcweir                     , m_bExpandBorderToIncrementRhythm( false )
110cdf0e10cSrcweir                     , m_bExpandIfValuesCloseToBorder( false )
111cdf0e10cSrcweir                     , m_bExpandWideValuesToZero( false )
112cdf0e10cSrcweir                     , m_bExpandNarrowValuesTowardZero( false )
113cdf0e10cSrcweir                     , m_nTimeResolution(::com::sun::star::chart::TimeUnit::DAY)
114cdf0e10cSrcweir                     , m_aNullDate(rNullDate)
115cdf0e10cSrcweir {
116cdf0e10cSrcweir     ::rtl::math::setNan( &m_fValueMinimum );
117cdf0e10cSrcweir     ::rtl::math::setNan( &m_fValueMaximum );
118cdf0e10cSrcweir 
119cdf0e10cSrcweir     double fExplicitOrigin = 0.0;
120cdf0e10cSrcweir     if( m_aSourceScale.Origin >>= fExplicitOrigin )
121cdf0e10cSrcweir         expandValueRange( fExplicitOrigin, fExplicitOrigin);
122cdf0e10cSrcweir }
~ScaleAutomatism()123cdf0e10cSrcweir ScaleAutomatism::~ScaleAutomatism()
124cdf0e10cSrcweir {
125cdf0e10cSrcweir }
126cdf0e10cSrcweir 
expandValueRange(double fMinimum,double fMaximum)127cdf0e10cSrcweir void ScaleAutomatism::expandValueRange( double fMinimum, double fMaximum )
128cdf0e10cSrcweir {
129cdf0e10cSrcweir     if( (fMinimum < m_fValueMinimum) || ::rtl::math::isNan( m_fValueMinimum ) )
130cdf0e10cSrcweir         m_fValueMinimum = fMinimum;
131cdf0e10cSrcweir     if( (fMaximum > m_fValueMaximum) || ::rtl::math::isNan( m_fValueMaximum ) )
132cdf0e10cSrcweir         m_fValueMaximum = fMaximum;
133cdf0e10cSrcweir }
134cdf0e10cSrcweir 
setAutoScalingOptions(bool bExpandBorderToIncrementRhythm,bool bExpandIfValuesCloseToBorder,bool bExpandWideValuesToZero,bool bExpandNarrowValuesTowardZero)135cdf0e10cSrcweir void ScaleAutomatism::setAutoScalingOptions(
136cdf0e10cSrcweir         bool bExpandBorderToIncrementRhythm,
137cdf0e10cSrcweir         bool bExpandIfValuesCloseToBorder,
138cdf0e10cSrcweir         bool bExpandWideValuesToZero,
139cdf0e10cSrcweir         bool bExpandNarrowValuesTowardZero )
140cdf0e10cSrcweir {
141cdf0e10cSrcweir     // if called multiple times, enable an option, if it is set in at least one call
142cdf0e10cSrcweir     m_bExpandBorderToIncrementRhythm |= bExpandBorderToIncrementRhythm;
143cdf0e10cSrcweir     m_bExpandIfValuesCloseToBorder   |= bExpandIfValuesCloseToBorder;
144cdf0e10cSrcweir     m_bExpandWideValuesToZero        |= bExpandWideValuesToZero;
145cdf0e10cSrcweir     m_bExpandNarrowValuesTowardZero  |= bExpandNarrowValuesTowardZero;
146cdf0e10cSrcweir 
147cdf0e10cSrcweir     if( m_aSourceScale.AxisType==AxisType::PERCENT )
148cdf0e10cSrcweir         m_bExpandIfValuesCloseToBorder = false;
149cdf0e10cSrcweir }
150cdf0e10cSrcweir 
setMaximumAutoMainIncrementCount(sal_Int32 nMaximumAutoMainIncrementCount)151cdf0e10cSrcweir void ScaleAutomatism::setMaximumAutoMainIncrementCount( sal_Int32 nMaximumAutoMainIncrementCount )
152cdf0e10cSrcweir {
153cdf0e10cSrcweir     if( nMaximumAutoMainIncrementCount < 2 )
154cdf0e10cSrcweir         m_nMaximumAutoMainIncrementCount = 2; //#i82006
155cdf0e10cSrcweir     else if( nMaximumAutoMainIncrementCount > lcl_getMaximumAutoIncrementCount( m_aSourceScale.AxisType ) )
156cdf0e10cSrcweir         m_nMaximumAutoMainIncrementCount = lcl_getMaximumAutoIncrementCount( m_aSourceScale.AxisType );
157cdf0e10cSrcweir     else
158cdf0e10cSrcweir         m_nMaximumAutoMainIncrementCount = nMaximumAutoMainIncrementCount;
159cdf0e10cSrcweir }
160cdf0e10cSrcweir 
setAutomaticTimeResolution(sal_Int32 nTimeResolution)161cdf0e10cSrcweir void ScaleAutomatism::setAutomaticTimeResolution( sal_Int32 nTimeResolution )
162cdf0e10cSrcweir {
163cdf0e10cSrcweir     m_nTimeResolution = nTimeResolution;
164cdf0e10cSrcweir }
165cdf0e10cSrcweir 
calculateExplicitScaleAndIncrement(ExplicitScaleData & rExplicitScale,ExplicitIncrementData & rExplicitIncrement) const166cdf0e10cSrcweir void ScaleAutomatism::calculateExplicitScaleAndIncrement(
167cdf0e10cSrcweir         ExplicitScaleData& rExplicitScale, ExplicitIncrementData& rExplicitIncrement ) const
168cdf0e10cSrcweir {
169cdf0e10cSrcweir     // fill explicit scale
170cdf0e10cSrcweir     rExplicitScale.Orientation = m_aSourceScale.Orientation;
171cdf0e10cSrcweir     rExplicitScale.Scaling = m_aSourceScale.Scaling;
172cdf0e10cSrcweir     rExplicitScale.AxisType = m_aSourceScale.AxisType;
173cdf0e10cSrcweir     rExplicitScale.NullDate = m_aNullDate;
174cdf0e10cSrcweir 
175cdf0e10cSrcweir     bool bAutoMinimum  = !(m_aSourceScale.Minimum >>= rExplicitScale.Minimum);
176cdf0e10cSrcweir     bool bAutoMaximum = !(m_aSourceScale.Maximum >>= rExplicitScale.Maximum);
177cdf0e10cSrcweir     bool bAutoOrigin = !(m_aSourceScale.Origin >>= rExplicitScale.Origin);
178cdf0e10cSrcweir 
179cdf0e10cSrcweir     // automatic scale minimum
180cdf0e10cSrcweir     if( bAutoMinimum )
181cdf0e10cSrcweir     {
182cdf0e10cSrcweir         if( m_aSourceScale.AxisType==AxisType::PERCENT )
183cdf0e10cSrcweir             rExplicitScale.Minimum = 0.0;
184cdf0e10cSrcweir         else if( ::rtl::math::isNan( m_fValueMinimum ) )
185cdf0e10cSrcweir         {
186cdf0e10cSrcweir             if( m_aSourceScale.AxisType==AxisType::DATE )
187cdf0e10cSrcweir                 rExplicitScale.Minimum = 36526.0; //1.1.2000
188cdf0e10cSrcweir             else
189cdf0e10cSrcweir                 rExplicitScale.Minimum = 0.0;   //@todo get Minimum from scaling or from plotter????
190cdf0e10cSrcweir         }
191cdf0e10cSrcweir         else
192cdf0e10cSrcweir             rExplicitScale.Minimum = m_fValueMinimum;
193cdf0e10cSrcweir     }
194cdf0e10cSrcweir 
195cdf0e10cSrcweir     // automatic scale maximum
196cdf0e10cSrcweir     if( bAutoMaximum )
197cdf0e10cSrcweir     {
198cdf0e10cSrcweir         if( m_aSourceScale.AxisType==AxisType::PERCENT )
199cdf0e10cSrcweir             rExplicitScale.Maximum = 1.0;
200cdf0e10cSrcweir         else if( ::rtl::math::isNan( m_fValueMaximum ) )
201cdf0e10cSrcweir         {
202cdf0e10cSrcweir             if( m_aSourceScale.AxisType==AxisType::DATE )
203cdf0e10cSrcweir                 rExplicitScale.Maximum = 40179.0; //1.1.2010
204cdf0e10cSrcweir             else
205cdf0e10cSrcweir                 rExplicitScale.Maximum = 10.0;  //@todo get Maximum from scaling or from plotter????
206cdf0e10cSrcweir         }
207cdf0e10cSrcweir         else
208cdf0e10cSrcweir             rExplicitScale.Maximum = m_fValueMaximum;
209cdf0e10cSrcweir     }
210cdf0e10cSrcweir 
211cdf0e10cSrcweir     //---------------------------------------------------------------
212cdf0e10cSrcweir     //fill explicit increment
213cdf0e10cSrcweir 
214cdf0e10cSrcweir     rExplicitScale.ShiftedCategoryPosition = m_aSourceScale.ShiftedCategoryPosition;
215cdf0e10cSrcweir     bool bIsLogarithm = false;
216cdf0e10cSrcweir 
217cdf0e10cSrcweir     //minimum and maximum of the ExplicitScaleData may be changed if allowed
218cdf0e10cSrcweir     if( m_aSourceScale.AxisType==AxisType::DATE )
219cdf0e10cSrcweir         calculateExplicitIncrementAndScaleForDateTimeAxis( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum );
220cdf0e10cSrcweir     else if( m_aSourceScale.AxisType==AxisType::CATEGORY || m_aSourceScale.AxisType==AxisType::SERIES )
221cdf0e10cSrcweir         calculateExplicitIncrementAndScaleForCategory( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum );
222cdf0e10cSrcweir     else
223cdf0e10cSrcweir     {
224cdf0e10cSrcweir         bIsLogarithm = AxisHelper::isLogarithmic( rExplicitScale.Scaling );
225cdf0e10cSrcweir         if( bIsLogarithm )
226cdf0e10cSrcweir             calculateExplicitIncrementAndScaleForLogarithmic( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum );
227cdf0e10cSrcweir         else
228cdf0e10cSrcweir             calculateExplicitIncrementAndScaleForLinear( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum );
229cdf0e10cSrcweir     }
230cdf0e10cSrcweir 
231cdf0e10cSrcweir     // automatic origin
232cdf0e10cSrcweir     if( bAutoOrigin )
233cdf0e10cSrcweir     {
234cdf0e10cSrcweir         // #i71415# automatic origin for logarithmic axis
235cdf0e10cSrcweir         double fDefaulOrigin = bIsLogarithm ? 1.0 : 0.0;
236cdf0e10cSrcweir 
237cdf0e10cSrcweir         if( fDefaulOrigin < rExplicitScale.Minimum )
238cdf0e10cSrcweir             fDefaulOrigin = rExplicitScale.Minimum;
239cdf0e10cSrcweir         else if( fDefaulOrigin > rExplicitScale.Maximum )
240cdf0e10cSrcweir             fDefaulOrigin = rExplicitScale.Maximum;
241cdf0e10cSrcweir 
242cdf0e10cSrcweir         rExplicitScale.Origin = fDefaulOrigin;
243cdf0e10cSrcweir     }
244cdf0e10cSrcweir }
245cdf0e10cSrcweir 
getScale() const246cdf0e10cSrcweir ScaleData ScaleAutomatism::getScale() const
247cdf0e10cSrcweir {
248cdf0e10cSrcweir     return m_aSourceScale;
249cdf0e10cSrcweir }
250cdf0e10cSrcweir 
getNullDate() const251cdf0e10cSrcweir Date ScaleAutomatism::getNullDate() const
252cdf0e10cSrcweir {
253cdf0e10cSrcweir     return m_aNullDate;
254cdf0e10cSrcweir }
255cdf0e10cSrcweir 
256cdf0e10cSrcweir // private --------------------------------------------------------------------
257cdf0e10cSrcweir 
calculateExplicitIncrementAndScaleForCategory(ExplicitScaleData & rExplicitScale,ExplicitIncrementData & rExplicitIncrement,bool bAutoMinimum,bool bAutoMaximum) const258cdf0e10cSrcweir void ScaleAutomatism::calculateExplicitIncrementAndScaleForCategory(
259cdf0e10cSrcweir         ExplicitScaleData& rExplicitScale,
260cdf0e10cSrcweir         ExplicitIncrementData& rExplicitIncrement,
261cdf0e10cSrcweir         bool bAutoMinimum, bool bAutoMaximum ) const
262cdf0e10cSrcweir {
263cdf0e10cSrcweir     // no scaling for categories
264cdf0e10cSrcweir     rExplicitScale.Scaling.clear();
265cdf0e10cSrcweir 
266cdf0e10cSrcweir     if( rExplicitScale.ShiftedCategoryPosition )
267cdf0e10cSrcweir         rExplicitScale.Maximum += 1.0;
268cdf0e10cSrcweir 
269cdf0e10cSrcweir     // ensure that at least one category is visible
270cdf0e10cSrcweir     if( rExplicitScale.Maximum <= rExplicitScale.Minimum )
271cdf0e10cSrcweir         rExplicitScale.Maximum = rExplicitScale.Minimum + 1.0;
272cdf0e10cSrcweir 
273cdf0e10cSrcweir     // default increment settings
274cdf0e10cSrcweir     rExplicitIncrement.PostEquidistant = sal_True;  // does not matter anyhow
275cdf0e10cSrcweir     rExplicitIncrement.Distance = 1.0;              // category axis always have a main increment of 1
276cdf0e10cSrcweir     rExplicitIncrement.BaseValue = 0.0;             // category axis always have a base of 0
277cdf0e10cSrcweir 
278cdf0e10cSrcweir     // automatic minimum and maximum
279cdf0e10cSrcweir     if( bAutoMinimum && m_bExpandBorderToIncrementRhythm )
280cdf0e10cSrcweir         rExplicitScale.Minimum = EquidistantTickFactory::getMinimumAtIncrement( rExplicitScale.Minimum, rExplicitIncrement );
281cdf0e10cSrcweir     if( bAutoMaximum && m_bExpandBorderToIncrementRhythm )
282cdf0e10cSrcweir         rExplicitScale.Maximum = EquidistantTickFactory::getMaximumAtIncrement( rExplicitScale.Maximum, rExplicitIncrement );
283cdf0e10cSrcweir 
284cdf0e10cSrcweir     //prevent performace killover
285cdf0e10cSrcweir     double fDistanceCount = ::rtl::math::approxFloor( (rExplicitScale.Maximum-rExplicitScale.Minimum) / rExplicitIncrement.Distance );
286cdf0e10cSrcweir     if( static_cast< sal_Int32 >( fDistanceCount ) > MAXIMUM_MANUAL_INCREMENT_COUNT )
287cdf0e10cSrcweir     {
288cdf0e10cSrcweir         double fMinimumFloor = ::rtl::math::approxFloor( rExplicitScale.Minimum );
289cdf0e10cSrcweir         double fMaximumCeil = ::rtl::math::approxCeil( rExplicitScale.Maximum );
290cdf0e10cSrcweir         rExplicitIncrement.Distance = ::rtl::math::approxCeil( (fMaximumCeil - fMinimumFloor) / MAXIMUM_MANUAL_INCREMENT_COUNT );
291cdf0e10cSrcweir     }
292cdf0e10cSrcweir 
293cdf0e10cSrcweir     //---------------------------------------------------------------
294cdf0e10cSrcweir     //fill explicit sub increment
295cdf0e10cSrcweir     sal_Int32 nSubCount = m_aSourceScale.IncrementData.SubIncrements.getLength();
296cdf0e10cSrcweir     for( sal_Int32 nN=0; nN<nSubCount; nN++ )
297cdf0e10cSrcweir     {
298cdf0e10cSrcweir         ExplicitSubIncrement aExplicitSubIncrement;
299cdf0e10cSrcweir         const SubIncrement& rSubIncrement= m_aSourceScale.IncrementData.SubIncrements[nN];
300cdf0e10cSrcweir         if(!(rSubIncrement.IntervalCount>>=aExplicitSubIncrement.IntervalCount))
301cdf0e10cSrcweir         {
302cdf0e10cSrcweir             //scaling dependent
303cdf0e10cSrcweir             //@todo autocalculate IntervalCount dependent on MainIncrement and scaling
304cdf0e10cSrcweir             aExplicitSubIncrement.IntervalCount = 2;
305cdf0e10cSrcweir         }
306cdf0e10cSrcweir         lcl_ensureMaximumSubIncrementCount( aExplicitSubIncrement.IntervalCount );
307cdf0e10cSrcweir         if(!(rSubIncrement.PostEquidistant>>=aExplicitSubIncrement.PostEquidistant))
308cdf0e10cSrcweir         {
309cdf0e10cSrcweir             //scaling dependent
310cdf0e10cSrcweir             aExplicitSubIncrement.PostEquidistant = sal_False;
311cdf0e10cSrcweir         }
312cdf0e10cSrcweir         rExplicitIncrement.SubIncrements.push_back(aExplicitSubIncrement);
313cdf0e10cSrcweir     }
314cdf0e10cSrcweir }
315cdf0e10cSrcweir 
316cdf0e10cSrcweir //-----------------------------------------------------------------------------------------
317cdf0e10cSrcweir 
calculateExplicitIncrementAndScaleForLogarithmic(ExplicitScaleData & rExplicitScale,ExplicitIncrementData & rExplicitIncrement,bool bAutoMinimum,bool bAutoMaximum) const318cdf0e10cSrcweir void ScaleAutomatism::calculateExplicitIncrementAndScaleForLogarithmic(
319cdf0e10cSrcweir         ExplicitScaleData& rExplicitScale,
320cdf0e10cSrcweir         ExplicitIncrementData& rExplicitIncrement,
321cdf0e10cSrcweir         bool bAutoMinimum, bool bAutoMaximum ) const
322cdf0e10cSrcweir {
323cdf0e10cSrcweir     // *** STEP 1: initialize the range data ***
324cdf0e10cSrcweir 
325cdf0e10cSrcweir     const double fInputMinimum = rExplicitScale.Minimum;
326cdf0e10cSrcweir     const double fInputMaximum = rExplicitScale.Maximum;
327cdf0e10cSrcweir 
328cdf0e10cSrcweir     double fSourceMinimum = rExplicitScale.Minimum;
329cdf0e10cSrcweir     double fSourceMaximum = rExplicitScale.Maximum;
330cdf0e10cSrcweir 
331cdf0e10cSrcweir     // set automatic PostEquidistant to true (maybe scaling dependent?)
332cdf0e10cSrcweir     // Note: scaling with PostEquidistant==false is untested and needs review
333cdf0e10cSrcweir     if( !(m_aSourceScale.IncrementData.PostEquidistant >>= rExplicitIncrement.PostEquidistant) )
334cdf0e10cSrcweir         rExplicitIncrement.PostEquidistant = sal_True;
335cdf0e10cSrcweir 
336cdf0e10cSrcweir     /*  All following scaling code will operate on the logarithms of the source
337cdf0e10cSrcweir         values. In the last step, the original values will be restored. */
338cdf0e10cSrcweir     uno::Reference< XScaling > xScaling = rExplicitScale.Scaling;
339cdf0e10cSrcweir     if( !xScaling.is() )
340cdf0e10cSrcweir         xScaling.set( AxisHelper::createLogarithmicScaling() );
341cdf0e10cSrcweir     uno::Reference< XScaling > xInverseScaling = xScaling->getInverseScaling();
342cdf0e10cSrcweir 
343cdf0e10cSrcweir     fSourceMinimum = xScaling->doScaling( fSourceMinimum );
344cdf0e10cSrcweir     if( !::rtl::math::isFinite( fSourceMinimum ) )
345cdf0e10cSrcweir         fSourceMinimum = 0.0;
346cdf0e10cSrcweir     else if( ::rtl::math::approxEqual( fSourceMinimum, ::rtl::math::approxFloor( fSourceMinimum ) ) )
347cdf0e10cSrcweir         fSourceMinimum = ::rtl::math::approxFloor( fSourceMinimum );
348cdf0e10cSrcweir 
349cdf0e10cSrcweir     fSourceMaximum = xScaling->doScaling( fSourceMaximum );
350cdf0e10cSrcweir     if( !::rtl::math::isFinite( fSourceMaximum ) )
351cdf0e10cSrcweir         fSourceMaximum = 0.0;
352cdf0e10cSrcweir     else if( ::rtl::math::approxEqual( fSourceMaximum, ::rtl::math::approxFloor( fSourceMaximum ) ) )
353cdf0e10cSrcweir         fSourceMaximum = ::rtl::math::approxFloor( fSourceMaximum );
354cdf0e10cSrcweir 
355cdf0e10cSrcweir     /*  If range is invalid (minimum greater than maximum), change one of the
356cdf0e10cSrcweir         variable limits to validate the range. In this step, a zero-sized range
357cdf0e10cSrcweir         is still allowed. */
358cdf0e10cSrcweir     if( fSourceMinimum > fSourceMaximum )
359cdf0e10cSrcweir     {
360cdf0e10cSrcweir         // force changing the maximum, if both limits are fixed
361cdf0e10cSrcweir         if( bAutoMaximum || !bAutoMinimum )
362cdf0e10cSrcweir             fSourceMaximum = fSourceMinimum;
363cdf0e10cSrcweir         else
364cdf0e10cSrcweir             fSourceMinimum = fSourceMaximum;
365cdf0e10cSrcweir     }
366cdf0e10cSrcweir 
367cdf0e10cSrcweir     /*  If maximum is less than 0 (and therefore minimum too), minimum and
368cdf0e10cSrcweir         maximum will be negated and swapped to make the following algorithms
369cdf0e10cSrcweir         easier. Example: Both ranges [2,5] and [-5,-2] will be processed as
370cdf0e10cSrcweir         [2,5], and the latter will be swapped back later. The range [0,0] is
371cdf0e10cSrcweir         explicitly excluded from swapping (this would result in [-1,0] instead
372cdf0e10cSrcweir         of the expected [0,1]). */
373cdf0e10cSrcweir     bool bSwapAndNegateRange = (fSourceMinimum < 0.0) && (fSourceMaximum <= 0.0);
374cdf0e10cSrcweir     if( bSwapAndNegateRange )
375cdf0e10cSrcweir     {
376cdf0e10cSrcweir         double fTempValue = fSourceMinimum;
377cdf0e10cSrcweir         fSourceMinimum = -fSourceMaximum;
378cdf0e10cSrcweir         fSourceMaximum = -fTempValue;
379cdf0e10cSrcweir         ::std::swap( bAutoMinimum, bAutoMaximum );
380cdf0e10cSrcweir     }
381cdf0e10cSrcweir 
382cdf0e10cSrcweir     // *** STEP 2: find temporary (unrounded) axis minimum and maximum ***
383cdf0e10cSrcweir 
384cdf0e10cSrcweir     double fTempMinimum = fSourceMinimum;
385cdf0e10cSrcweir     double fTempMaximum = fSourceMaximum;
386cdf0e10cSrcweir 
387cdf0e10cSrcweir     /*  If minimum is variable and greater than 0 (and therefore maximum too),
388cdf0e10cSrcweir         means all original values are greater than 1 (or all values are less
389cdf0e10cSrcweir         than 1, and the range has been swapped above), then: */
390cdf0e10cSrcweir     if( bAutoMinimum && (fTempMinimum > 0.0) )
391cdf0e10cSrcweir     {
392cdf0e10cSrcweir         /*  If minimum is less than 5 (i.e. original source values less than
393cdf0e10cSrcweir             B^5, B being the base of the scaling), or if minimum and maximum
394cdf0e10cSrcweir             are in different increment intervals (means, if minimum and maximum
395cdf0e10cSrcweir             are not both in the range [B^n,B^(n+1)] for a whole number n), set
396cdf0e10cSrcweir             minimum to 0, which results in B^0=1 on the axis. */
397cdf0e10cSrcweir         double fMinimumFloor = ::rtl::math::approxFloor( fTempMinimum );
398cdf0e10cSrcweir         double fMaximumFloor = ::rtl::math::approxFloor( fTempMaximum );
399cdf0e10cSrcweir         // handle the exact value B^(n+1) to be in the range [B^n,B^(n+1)]
400cdf0e10cSrcweir         if( ::rtl::math::approxEqual( fTempMaximum, fMaximumFloor ) )
401cdf0e10cSrcweir             fMaximumFloor -= 1.0;
402cdf0e10cSrcweir 
403cdf0e10cSrcweir         if( (fMinimumFloor < 5.0) || (fMinimumFloor < fMaximumFloor) )
404cdf0e10cSrcweir         {
405cdf0e10cSrcweir             if( m_bExpandWideValuesToZero )
406cdf0e10cSrcweir                 fTempMinimum = 0.0;
407cdf0e10cSrcweir         }
408cdf0e10cSrcweir         /*  Else (minimum and maximum are in one increment interval), expand
409cdf0e10cSrcweir             minimum toward 0 to make the 'shorter' data points visible. */
410cdf0e10cSrcweir         else
411cdf0e10cSrcweir         {
412cdf0e10cSrcweir             if( m_bExpandNarrowValuesTowardZero )
413cdf0e10cSrcweir                 fTempMinimum -= 1.0;
414cdf0e10cSrcweir         }
415cdf0e10cSrcweir     }
416cdf0e10cSrcweir 
417cdf0e10cSrcweir     /*  If range is still zero-sized (e.g. when minimum is fixed), set minimum
418cdf0e10cSrcweir         to 0, which makes the axis start/stop at the value 1. */
419cdf0e10cSrcweir     if( fTempMinimum == fTempMaximum )
420cdf0e10cSrcweir     {
421cdf0e10cSrcweir         if( bAutoMinimum && (fTempMaximum > 0.0) )
422cdf0e10cSrcweir             fTempMinimum = 0.0;
423cdf0e10cSrcweir         else
424cdf0e10cSrcweir             fTempMaximum += 1.0;    // always add one interval, even if maximum is fixed
425cdf0e10cSrcweir     }
426cdf0e10cSrcweir 
427cdf0e10cSrcweir     // *** STEP 3: calculate main interval size ***
428cdf0e10cSrcweir 
429cdf0e10cSrcweir     // base value (anchor position of the intervals), already scaled
430cdf0e10cSrcweir     if( !(m_aSourceScale.IncrementData.BaseValue >>= rExplicitIncrement.BaseValue) )
431cdf0e10cSrcweir     {
432cdf0e10cSrcweir         //scaling dependent
433cdf0e10cSrcweir         //@maybe todo is this default also plotter dependent ??
434cdf0e10cSrcweir         if( !bAutoMinimum )
435cdf0e10cSrcweir             rExplicitIncrement.BaseValue = fTempMinimum;
436cdf0e10cSrcweir         else if( !bAutoMaximum )
437cdf0e10cSrcweir             rExplicitIncrement.BaseValue = fTempMaximum;
438cdf0e10cSrcweir         else
439cdf0e10cSrcweir             rExplicitIncrement.BaseValue = 0.0;
440cdf0e10cSrcweir     }
441cdf0e10cSrcweir 
442cdf0e10cSrcweir     // calculate automatic interval
443cdf0e10cSrcweir     bool bAutoDistance = !(m_aSourceScale.IncrementData.Distance >>= rExplicitIncrement.Distance);
444cdf0e10cSrcweir     if( bAutoDistance )
445cdf0e10cSrcweir         rExplicitIncrement.Distance = 0.0;
446cdf0e10cSrcweir 
447cdf0e10cSrcweir     /*  Restrict number of allowed intervals with user-defined distance to
448cdf0e10cSrcweir         MAXIMUM_MANUAL_INCREMENT_COUNT. */
449cdf0e10cSrcweir     sal_Int32 nMaxMainIncrementCount = bAutoDistance ?
450cdf0e10cSrcweir         m_nMaximumAutoMainIncrementCount : MAXIMUM_MANUAL_INCREMENT_COUNT;
451cdf0e10cSrcweir 
452cdf0e10cSrcweir     // repeat calculation until number of intervals are valid
453cdf0e10cSrcweir     bool bNeedIteration = true;
454cdf0e10cSrcweir     bool bHasCalculatedDistance = false;
455cdf0e10cSrcweir     while( bNeedIteration )
456cdf0e10cSrcweir     {
457cdf0e10cSrcweir         if( bAutoDistance )
458cdf0e10cSrcweir         {
459cdf0e10cSrcweir             // first iteration: calculate interval size from axis limits
460cdf0e10cSrcweir             if( !bHasCalculatedDistance )
461cdf0e10cSrcweir             {
462cdf0e10cSrcweir                 double fMinimumFloor = ::rtl::math::approxFloor( fTempMinimum );
463cdf0e10cSrcweir                 double fMaximumCeil = ::rtl::math::approxCeil( fTempMaximum );
464cdf0e10cSrcweir                 rExplicitIncrement.Distance = ::rtl::math::approxCeil( (fMaximumCeil - fMinimumFloor) / nMaxMainIncrementCount );
465cdf0e10cSrcweir             }
466cdf0e10cSrcweir             else
467cdf0e10cSrcweir             {
468cdf0e10cSrcweir                 // following iterations: increase distance
469cdf0e10cSrcweir                 rExplicitIncrement.Distance += 1.0;
470cdf0e10cSrcweir             }
471cdf0e10cSrcweir 
472cdf0e10cSrcweir             // for next iteration: distance calculated -> use else path to increase
473cdf0e10cSrcweir             bHasCalculatedDistance = true;
474cdf0e10cSrcweir         }
475cdf0e10cSrcweir 
476cdf0e10cSrcweir         // *** STEP 4: additional space above or below the data points ***
477cdf0e10cSrcweir 
478cdf0e10cSrcweir         double fAxisMinimum = fTempMinimum;
479cdf0e10cSrcweir         double fAxisMaximum = fTempMaximum;
480cdf0e10cSrcweir 
481cdf0e10cSrcweir         // round to entire multiples of the distance and add additional space
482cdf0e10cSrcweir         if( bAutoMinimum && m_bExpandBorderToIncrementRhythm )
483cdf0e10cSrcweir         {
484cdf0e10cSrcweir             fAxisMinimum = EquidistantTickFactory::getMinimumAtIncrement( fAxisMinimum, rExplicitIncrement );
485cdf0e10cSrcweir 
486cdf0e10cSrcweir             //ensure valid values after scaling #i100995#
487cdf0e10cSrcweir             if( !bAutoDistance )
488cdf0e10cSrcweir             {
489cdf0e10cSrcweir                 double fCheck = xInverseScaling->doScaling( fAxisMinimum );
490cdf0e10cSrcweir                 if( !::rtl::math::isFinite( fCheck ) || fCheck <= 0 )
491cdf0e10cSrcweir                 {
492cdf0e10cSrcweir                     bAutoDistance = true;
493cdf0e10cSrcweir                     bHasCalculatedDistance = false;
494cdf0e10cSrcweir                     continue;
495cdf0e10cSrcweir                 }
496cdf0e10cSrcweir             }
497cdf0e10cSrcweir         }
498cdf0e10cSrcweir         if( bAutoMaximum && m_bExpandBorderToIncrementRhythm )
499cdf0e10cSrcweir         {
500cdf0e10cSrcweir             fAxisMaximum = EquidistantTickFactory::getMaximumAtIncrement( fAxisMaximum, rExplicitIncrement );
501cdf0e10cSrcweir 
502cdf0e10cSrcweir             //ensure valid values after scaling #i100995#
503cdf0e10cSrcweir             if( !bAutoDistance )
504cdf0e10cSrcweir             {
505cdf0e10cSrcweir                 double fCheck = xInverseScaling->doScaling( fAxisMaximum );
506cdf0e10cSrcweir                 if( !::rtl::math::isFinite( fCheck ) || fCheck <= 0 )
507cdf0e10cSrcweir                 {
508cdf0e10cSrcweir                     bAutoDistance = true;
509cdf0e10cSrcweir                     bHasCalculatedDistance = false;
510cdf0e10cSrcweir                     continue;
511cdf0e10cSrcweir                 }
512cdf0e10cSrcweir             }
513cdf0e10cSrcweir         }
514cdf0e10cSrcweir 
515cdf0e10cSrcweir         // set the resulting limits (swap back to negative range if needed)
516cdf0e10cSrcweir         if( bSwapAndNegateRange )
517cdf0e10cSrcweir         {
518cdf0e10cSrcweir             rExplicitScale.Minimum = -fAxisMaximum;
519cdf0e10cSrcweir             rExplicitScale.Maximum = -fAxisMinimum;
520cdf0e10cSrcweir         }
521cdf0e10cSrcweir         else
522cdf0e10cSrcweir         {
523cdf0e10cSrcweir             rExplicitScale.Minimum = fAxisMinimum;
524cdf0e10cSrcweir             rExplicitScale.Maximum = fAxisMaximum;
525cdf0e10cSrcweir         }
526cdf0e10cSrcweir 
527cdf0e10cSrcweir         /*  If the number of intervals is too high (e.g. due to invalid fixed
528cdf0e10cSrcweir             distance or due to added space above or below data points),
529cdf0e10cSrcweir             calculate again with increased distance. */
530cdf0e10cSrcweir         double fDistanceCount = ::rtl::math::approxFloor( (fAxisMaximum - fAxisMinimum) / rExplicitIncrement.Distance );
531cdf0e10cSrcweir         bNeedIteration = static_cast< sal_Int32 >( fDistanceCount ) > nMaxMainIncrementCount;
532cdf0e10cSrcweir         // if manual distance is invalid, trigger automatic calculation
533cdf0e10cSrcweir         if( bNeedIteration )
534cdf0e10cSrcweir             bAutoDistance = true;
535cdf0e10cSrcweir 
536cdf0e10cSrcweir         // convert limits back to logarithmic scale
537cdf0e10cSrcweir         rExplicitScale.Minimum = xInverseScaling->doScaling( rExplicitScale.Minimum );
538cdf0e10cSrcweir         rExplicitScale.Maximum = xInverseScaling->doScaling( rExplicitScale.Maximum );
539cdf0e10cSrcweir 
540cdf0e10cSrcweir         //ensure valid values after scaling #i100995#
541cdf0e10cSrcweir         if( !::rtl::math::isFinite( rExplicitScale.Minimum ) || rExplicitScale.Minimum <= 0)
542cdf0e10cSrcweir         {
543cdf0e10cSrcweir             rExplicitScale.Minimum = fInputMinimum;
544cdf0e10cSrcweir             if( !::rtl::math::isFinite( rExplicitScale.Minimum ) || rExplicitScale.Minimum <= 0 )
545cdf0e10cSrcweir                 rExplicitScale.Minimum = 1.0;
546cdf0e10cSrcweir         }
547cdf0e10cSrcweir         if( !::rtl::math::isFinite( rExplicitScale.Maximum) || rExplicitScale.Maximum <= 0 )
548cdf0e10cSrcweir         {
549cdf0e10cSrcweir             rExplicitScale.Maximum= fInputMaximum;
550cdf0e10cSrcweir             if( !::rtl::math::isFinite( rExplicitScale.Maximum) || rExplicitScale.Maximum <= 0 )
551cdf0e10cSrcweir                 rExplicitScale.Maximum = 10.0;
552cdf0e10cSrcweir         }
553cdf0e10cSrcweir         if( rExplicitScale.Maximum < rExplicitScale.Minimum )
554cdf0e10cSrcweir             ::std::swap( rExplicitScale.Maximum, rExplicitScale.Minimum );
555cdf0e10cSrcweir     }
556cdf0e10cSrcweir 
557cdf0e10cSrcweir     //---------------------------------------------------------------
558cdf0e10cSrcweir     //fill explicit sub increment
559cdf0e10cSrcweir     sal_Int32 nSubCount = m_aSourceScale.IncrementData.SubIncrements.getLength();
560cdf0e10cSrcweir     for( sal_Int32 nN=0; nN<nSubCount; nN++ )
561cdf0e10cSrcweir     {
562cdf0e10cSrcweir         ExplicitSubIncrement aExplicitSubIncrement;
563cdf0e10cSrcweir         const SubIncrement& rSubIncrement = m_aSourceScale.IncrementData.SubIncrements[nN];
564cdf0e10cSrcweir         if(!(rSubIncrement.IntervalCount>>=aExplicitSubIncrement.IntervalCount))
565cdf0e10cSrcweir         {
566cdf0e10cSrcweir             //scaling dependent
567cdf0e10cSrcweir             //@todo autocalculate IntervalCount dependent on MainIncrement and scaling
568cdf0e10cSrcweir             aExplicitSubIncrement.IntervalCount = 9;
569cdf0e10cSrcweir         }
570cdf0e10cSrcweir         lcl_ensureMaximumSubIncrementCount( aExplicitSubIncrement.IntervalCount );
571cdf0e10cSrcweir         if(!(rSubIncrement.PostEquidistant>>=aExplicitSubIncrement.PostEquidistant))
572cdf0e10cSrcweir         {
573cdf0e10cSrcweir             //scaling dependent
574cdf0e10cSrcweir             aExplicitSubIncrement.PostEquidistant = sal_False;
575cdf0e10cSrcweir         }
576cdf0e10cSrcweir         rExplicitIncrement.SubIncrements.push_back(aExplicitSubIncrement);
577cdf0e10cSrcweir     }
578cdf0e10cSrcweir }
579cdf0e10cSrcweir 
580cdf0e10cSrcweir //-----------------------------------------------------------------------------------------
581cdf0e10cSrcweir 
calculateExplicitIncrementAndScaleForDateTimeAxis(ExplicitScaleData & rExplicitScale,ExplicitIncrementData & rExplicitIncrement,bool bAutoMinimum,bool bAutoMaximum) const582cdf0e10cSrcweir void ScaleAutomatism::calculateExplicitIncrementAndScaleForDateTimeAxis(
583cdf0e10cSrcweir         ExplicitScaleData& rExplicitScale,
584cdf0e10cSrcweir         ExplicitIncrementData& rExplicitIncrement,
585cdf0e10cSrcweir         bool bAutoMinimum, bool bAutoMaximum ) const
586cdf0e10cSrcweir {
587cdf0e10cSrcweir     Date aMinDate(m_aNullDate); aMinDate += static_cast<long>(::rtl::math::approxFloor(rExplicitScale.Minimum));
588cdf0e10cSrcweir     Date aMaxDate(m_aNullDate); aMaxDate += static_cast<long>(::rtl::math::approxFloor(rExplicitScale.Maximum));
589cdf0e10cSrcweir     rExplicitIncrement.PostEquidistant = sal_False;
590cdf0e10cSrcweir 
591cdf0e10cSrcweir     if( aMinDate > aMaxDate )
592cdf0e10cSrcweir     {
593cdf0e10cSrcweir         std::swap(aMinDate,aMaxDate);
594cdf0e10cSrcweir     }
595cdf0e10cSrcweir 
596cdf0e10cSrcweir     if( !(m_aSourceScale.TimeIncrement.TimeResolution >>= rExplicitScale.TimeResolution) )
597cdf0e10cSrcweir         rExplicitScale.TimeResolution = m_nTimeResolution;
598cdf0e10cSrcweir 
599cdf0e10cSrcweir     rExplicitScale.Scaling = new DateScaling(m_aNullDate,rExplicitScale.TimeResolution,false);
600cdf0e10cSrcweir 
601cdf0e10cSrcweir     // choose min and max suitable to time resolution
602cdf0e10cSrcweir     switch( rExplicitScale.TimeResolution )
603cdf0e10cSrcweir     {
604cdf0e10cSrcweir     case DAY:
605cdf0e10cSrcweir         if( rExplicitScale.ShiftedCategoryPosition )
606cdf0e10cSrcweir             aMaxDate++;//for explicit scales we need one interval more (maximum excluded)
607cdf0e10cSrcweir         break;
608cdf0e10cSrcweir     case MONTH:
609cdf0e10cSrcweir         aMinDate.SetDay(1);
610cdf0e10cSrcweir         aMaxDate.SetDay(1);
611cdf0e10cSrcweir         if( rExplicitScale.ShiftedCategoryPosition )
612cdf0e10cSrcweir             aMaxDate = DateHelper::GetDateSomeMonthsAway(aMaxDate,1);//for explicit scales we need one interval more (maximum excluded)
613cdf0e10cSrcweir         if( DateHelper::IsLessThanOneMonthAway( aMinDate, aMaxDate ) )
614cdf0e10cSrcweir         {
615cdf0e10cSrcweir             if( bAutoMaximum || !bAutoMinimum )
616cdf0e10cSrcweir                 aMaxDate = DateHelper::GetDateSomeMonthsAway(aMinDate,1);
617cdf0e10cSrcweir             else
618cdf0e10cSrcweir                 aMinDate = DateHelper::GetDateSomeMonthsAway(aMaxDate,-1);
619cdf0e10cSrcweir         }
620cdf0e10cSrcweir         break;
621cdf0e10cSrcweir     case YEAR:
622cdf0e10cSrcweir         aMinDate.SetDay(1);
623cdf0e10cSrcweir         aMinDate.SetMonth(1);
624cdf0e10cSrcweir         aMaxDate.SetDay(1);
625cdf0e10cSrcweir         aMaxDate.SetMonth(1);
626cdf0e10cSrcweir         if( rExplicitScale.ShiftedCategoryPosition )
627cdf0e10cSrcweir             aMaxDate = DateHelper::GetDateSomeYearsAway(aMaxDate,1);//for explicit scales we need one interval more (maximum excluded)
628cdf0e10cSrcweir         if( DateHelper::IsLessThanOneYearAway( aMinDate, aMaxDate ) )
629cdf0e10cSrcweir         {
630cdf0e10cSrcweir             if( bAutoMaximum || !bAutoMinimum )
631cdf0e10cSrcweir                 aMaxDate = DateHelper::GetDateSomeYearsAway(aMinDate,1);
632cdf0e10cSrcweir             else
633cdf0e10cSrcweir                 aMinDate = DateHelper::GetDateSomeYearsAway(aMaxDate,-1);
634cdf0e10cSrcweir         }
635cdf0e10cSrcweir         break;
636cdf0e10cSrcweir     }
637cdf0e10cSrcweir 
638cdf0e10cSrcweir     // set the resulting limits (swap back to negative range if needed)
639cdf0e10cSrcweir     rExplicitScale.Minimum = aMinDate - m_aNullDate;
640cdf0e10cSrcweir     rExplicitScale.Maximum = aMaxDate - m_aNullDate;
641cdf0e10cSrcweir 
642cdf0e10cSrcweir     bool bAutoMajor = !(m_aSourceScale.TimeIncrement.MajorTimeInterval >>= rExplicitIncrement.MajorTimeInterval);
643cdf0e10cSrcweir     bool bAutoMinor = !(m_aSourceScale.TimeIncrement.MinorTimeInterval >>= rExplicitIncrement.MinorTimeInterval);
644cdf0e10cSrcweir 
645cdf0e10cSrcweir     sal_Int32 nMaxMainIncrementCount = bAutoMajor ?
646cdf0e10cSrcweir         m_nMaximumAutoMainIncrementCount : MAXIMUM_MANUAL_INCREMENT_COUNT;
647cdf0e10cSrcweir     if( nMaxMainIncrementCount > 1 )
648cdf0e10cSrcweir         nMaxMainIncrementCount--;
649cdf0e10cSrcweir 
650cdf0e10cSrcweir 
651cdf0e10cSrcweir     //choose major time interval:
652cdf0e10cSrcweir     long nDayCount = (aMaxDate-aMinDate);
653cdf0e10cSrcweir     long nMainIncrementCount = 1;
654cdf0e10cSrcweir     if( !bAutoMajor )
655cdf0e10cSrcweir     {
656cdf0e10cSrcweir         long nIntervalDayCount = rExplicitIncrement.MajorTimeInterval.Number;
657cdf0e10cSrcweir         if( rExplicitIncrement.MajorTimeInterval.TimeUnit < rExplicitScale.TimeResolution )
658cdf0e10cSrcweir             rExplicitIncrement.MajorTimeInterval.TimeUnit = rExplicitScale.TimeResolution;
659cdf0e10cSrcweir         switch( rExplicitIncrement.MajorTimeInterval.TimeUnit )
660cdf0e10cSrcweir         {
661cdf0e10cSrcweir         case DAY:
662cdf0e10cSrcweir             break;
663cdf0e10cSrcweir         case MONTH:
664cdf0e10cSrcweir             nIntervalDayCount*=31;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ...
665cdf0e10cSrcweir             break;
666cdf0e10cSrcweir         case YEAR:
667cdf0e10cSrcweir             nIntervalDayCount*=365;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ...
668cdf0e10cSrcweir             break;
669cdf0e10cSrcweir         }
670cdf0e10cSrcweir         nMainIncrementCount = nDayCount/nIntervalDayCount;
671cdf0e10cSrcweir         if( nMainIncrementCount > nMaxMainIncrementCount )
672cdf0e10cSrcweir             bAutoMajor = true;
673cdf0e10cSrcweir     }
674cdf0e10cSrcweir     if( bAutoMajor )
675cdf0e10cSrcweir     {
676cdf0e10cSrcweir         long nNumer = 1;
677cdf0e10cSrcweir         long nIntervalDays =  nDayCount / nMaxMainIncrementCount;
678cdf0e10cSrcweir         double nDaysPerInterval = 1.0;
679cdf0e10cSrcweir         if( nIntervalDays>365 || YEAR==rExplicitScale.TimeResolution )
680cdf0e10cSrcweir         {
681cdf0e10cSrcweir             rExplicitIncrement.MajorTimeInterval.TimeUnit = YEAR;
682cdf0e10cSrcweir             nDaysPerInterval = 365.0;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ...
683cdf0e10cSrcweir         }
684cdf0e10cSrcweir         else if( nIntervalDays>31 || MONTH==rExplicitScale.TimeResolution )
685cdf0e10cSrcweir         {
686cdf0e10cSrcweir             rExplicitIncrement.MajorTimeInterval.TimeUnit = MONTH;
687cdf0e10cSrcweir             nDaysPerInterval = 31.0;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ...
688cdf0e10cSrcweir         }
689cdf0e10cSrcweir         else
690cdf0e10cSrcweir         {
691cdf0e10cSrcweir             rExplicitIncrement.MajorTimeInterval.TimeUnit = DAY;
692cdf0e10cSrcweir             nDaysPerInterval = 1.0;
693cdf0e10cSrcweir         }
694cdf0e10cSrcweir 
695cdf0e10cSrcweir         nNumer = static_cast<sal_Int32>( rtl::math::approxCeil( nIntervalDays/nDaysPerInterval ) );
696cdf0e10cSrcweir         if(nNumer<=0)
697cdf0e10cSrcweir             nNumer=1;
698cdf0e10cSrcweir         if( rExplicitIncrement.MajorTimeInterval.TimeUnit == DAY )
699cdf0e10cSrcweir         {
700cdf0e10cSrcweir             if( nNumer>2 && nNumer<7 )
701cdf0e10cSrcweir                 nNumer=7;
702cdf0e10cSrcweir             else if( nNumer>7 )
703cdf0e10cSrcweir             {
704cdf0e10cSrcweir                 rExplicitIncrement.MajorTimeInterval.TimeUnit = MONTH;
705cdf0e10cSrcweir                 nDaysPerInterval = 31.0;
706cdf0e10cSrcweir                 nNumer = static_cast<sal_Int32>( rtl::math::approxCeil( nIntervalDays/nDaysPerInterval ) );
707cdf0e10cSrcweir                 if(nNumer<=0)
708cdf0e10cSrcweir                     nNumer=1;
709cdf0e10cSrcweir             }
710cdf0e10cSrcweir         }
711cdf0e10cSrcweir         rExplicitIncrement.MajorTimeInterval.Number = nNumer;
712cdf0e10cSrcweir         nMainIncrementCount = static_cast<long>(nDayCount/(nNumer*nDaysPerInterval));
713cdf0e10cSrcweir     }
714cdf0e10cSrcweir 
715cdf0e10cSrcweir     //choose minor time interval:
716cdf0e10cSrcweir     if( !bAutoMinor )
717cdf0e10cSrcweir     {
718cdf0e10cSrcweir         if( rExplicitIncrement.MinorTimeInterval.TimeUnit > rExplicitIncrement.MajorTimeInterval.TimeUnit )
719cdf0e10cSrcweir             rExplicitIncrement.MinorTimeInterval.TimeUnit = rExplicitIncrement.MajorTimeInterval.TimeUnit;
720cdf0e10cSrcweir         long nIntervalDayCount = rExplicitIncrement.MinorTimeInterval.Number;
721cdf0e10cSrcweir         switch( rExplicitIncrement.MinorTimeInterval.TimeUnit )
722cdf0e10cSrcweir         {
723cdf0e10cSrcweir         case DAY:
724cdf0e10cSrcweir             break;
725cdf0e10cSrcweir         case MONTH:
726cdf0e10cSrcweir             nIntervalDayCount*=31;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ...
727cdf0e10cSrcweir             break;
728cdf0e10cSrcweir         case YEAR:
729cdf0e10cSrcweir             nIntervalDayCount*=365;//todo: maybe different for other calendars... get localized calendar according to set number format at axis ...
730cdf0e10cSrcweir             break;
731cdf0e10cSrcweir         }
732cdf0e10cSrcweir         if( nDayCount/nIntervalDayCount > nMaxMainIncrementCount )
733cdf0e10cSrcweir             bAutoMinor = true;
734cdf0e10cSrcweir     }
735cdf0e10cSrcweir     if( bAutoMinor )
736cdf0e10cSrcweir     {
737cdf0e10cSrcweir         rExplicitIncrement.MinorTimeInterval.TimeUnit = rExplicitIncrement.MajorTimeInterval.TimeUnit;
738cdf0e10cSrcweir         rExplicitIncrement.MinorTimeInterval.Number = 1;
739cdf0e10cSrcweir         if( nMainIncrementCount > 100 )
740cdf0e10cSrcweir             rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number;
741cdf0e10cSrcweir         else
742cdf0e10cSrcweir         {
743cdf0e10cSrcweir             if( rExplicitIncrement.MajorTimeInterval.Number >= 2 )
744cdf0e10cSrcweir             {
745cdf0e10cSrcweir                 if( !(rExplicitIncrement.MajorTimeInterval.Number%2) )
746cdf0e10cSrcweir                     rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number/2;
747cdf0e10cSrcweir                 else if( !(rExplicitIncrement.MajorTimeInterval.Number%3) )
748cdf0e10cSrcweir                     rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number/3;
749cdf0e10cSrcweir                 else if( !(rExplicitIncrement.MajorTimeInterval.Number%5) )
750cdf0e10cSrcweir                     rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number/5;
751cdf0e10cSrcweir                 else if( rExplicitIncrement.MajorTimeInterval.Number > 50 )
752cdf0e10cSrcweir                     rExplicitIncrement.MinorTimeInterval.Number = rExplicitIncrement.MajorTimeInterval.Number;
753cdf0e10cSrcweir             }
754cdf0e10cSrcweir             else
755cdf0e10cSrcweir             {
756cdf0e10cSrcweir                 switch( rExplicitIncrement.MajorTimeInterval.TimeUnit )
757cdf0e10cSrcweir                 {
758cdf0e10cSrcweir                     case DAY:
759cdf0e10cSrcweir                         break;
760cdf0e10cSrcweir                     case MONTH:
761cdf0e10cSrcweir                         if( rExplicitScale.TimeResolution == DAY )
762cdf0e10cSrcweir                             rExplicitIncrement.MinorTimeInterval.TimeUnit = DAY;
763cdf0e10cSrcweir                         break;
764cdf0e10cSrcweir                     case YEAR:
765cdf0e10cSrcweir                         if( rExplicitScale.TimeResolution <= MONTH )
766cdf0e10cSrcweir                             rExplicitIncrement.MinorTimeInterval.TimeUnit = MONTH;
767cdf0e10cSrcweir                         break;
768cdf0e10cSrcweir                 }
769cdf0e10cSrcweir             }
770cdf0e10cSrcweir         }
771cdf0e10cSrcweir     }
772cdf0e10cSrcweir 
773cdf0e10cSrcweir }
774cdf0e10cSrcweir 
775cdf0e10cSrcweir //-----------------------------------------------------------------------------------------
776cdf0e10cSrcweir 
calculateExplicitIncrementAndScaleForLinear(ExplicitScaleData & rExplicitScale,ExplicitIncrementData & rExplicitIncrement,bool bAutoMinimum,bool bAutoMaximum) const777cdf0e10cSrcweir void ScaleAutomatism::calculateExplicitIncrementAndScaleForLinear(
778cdf0e10cSrcweir         ExplicitScaleData& rExplicitScale,
779cdf0e10cSrcweir         ExplicitIncrementData& rExplicitIncrement,
780cdf0e10cSrcweir         bool bAutoMinimum, bool bAutoMaximum ) const
781cdf0e10cSrcweir {
782cdf0e10cSrcweir     // *** STEP 1: initialize the range data ***
783cdf0e10cSrcweir 
784cdf0e10cSrcweir     double fSourceMinimum = rExplicitScale.Minimum;
785cdf0e10cSrcweir     double fSourceMaximum = rExplicitScale.Maximum;
786cdf0e10cSrcweir 
787cdf0e10cSrcweir     // set automatic PostEquidistant to true (maybe scaling dependent?)
788cdf0e10cSrcweir     if( !(m_aSourceScale.IncrementData.PostEquidistant >>= rExplicitIncrement.PostEquidistant) )
789cdf0e10cSrcweir         rExplicitIncrement.PostEquidistant = sal_True;
790cdf0e10cSrcweir 
791cdf0e10cSrcweir     /*  If range is invalid (minimum greater than maximum), change one of the
792cdf0e10cSrcweir         variable limits to validate the range. In this step, a zero-sized range
793cdf0e10cSrcweir         is still allowed. */
794cdf0e10cSrcweir     if( fSourceMinimum > fSourceMaximum )
795cdf0e10cSrcweir     {
796cdf0e10cSrcweir         // force changing the maximum, if both limits are fixed
797cdf0e10cSrcweir         if( bAutoMaximum || !bAutoMinimum )
798cdf0e10cSrcweir             fSourceMaximum = fSourceMinimum;
799cdf0e10cSrcweir         else
800cdf0e10cSrcweir             fSourceMinimum = fSourceMaximum;
801cdf0e10cSrcweir     }
802cdf0e10cSrcweir 
803cdf0e10cSrcweir     /*  If maximum is zero or negative (and therefore minimum too), minimum and
804cdf0e10cSrcweir         maximum will be negated and swapped to make the following algorithms
805cdf0e10cSrcweir         easier. Example: Both ranges [2,5] and [-5,-2] will be processed as
806cdf0e10cSrcweir         [2,5], and the latter will be swapped back later. The range [0,0] is
807cdf0e10cSrcweir         explicitly excluded from swapping (this would result in [-1,0] instead
808cdf0e10cSrcweir         of the expected [0,1]). */
809cdf0e10cSrcweir     bool bSwapAndNegateRange = (fSourceMinimum < 0.0) && (fSourceMaximum <= 0.0);
810cdf0e10cSrcweir     if( bSwapAndNegateRange )
811cdf0e10cSrcweir     {
812cdf0e10cSrcweir         double fTempValue = fSourceMinimum;
813cdf0e10cSrcweir         fSourceMinimum = -fSourceMaximum;
814cdf0e10cSrcweir         fSourceMaximum = -fTempValue;
815cdf0e10cSrcweir         ::std::swap( bAutoMinimum, bAutoMaximum );
816cdf0e10cSrcweir     }
817cdf0e10cSrcweir 
818cdf0e10cSrcweir     // *** STEP 2: find temporary (unrounded) axis minimum and maximum ***
819cdf0e10cSrcweir 
820cdf0e10cSrcweir     double fTempMinimum = fSourceMinimum;
821cdf0e10cSrcweir     double fTempMaximum = fSourceMaximum;
822cdf0e10cSrcweir 
823cdf0e10cSrcweir     /*  If minimum is variable and greater than 0 (and therefore maximum too),
824cdf0e10cSrcweir         means all values are positive (or all values are negative, and the
825cdf0e10cSrcweir         range has been swapped above), then: */
826cdf0e10cSrcweir     if( bAutoMinimum && (fTempMinimum > 0.0) )
827cdf0e10cSrcweir     {
828cdf0e10cSrcweir         /*  If minimum equals maximum, or if minimum is less than 5/6 of
829cdf0e10cSrcweir             maximum, set minimum to 0. */
830cdf0e10cSrcweir         if( (fTempMinimum == fTempMaximum) || (fTempMinimum / fTempMaximum < 5.0 / 6.0) )
831cdf0e10cSrcweir         {
832cdf0e10cSrcweir             if( m_bExpandWideValuesToZero )
833cdf0e10cSrcweir                 fTempMinimum = 0.0;
834cdf0e10cSrcweir         }
835cdf0e10cSrcweir         /*  Else (minimum is greater than or equal to 5/6 of maximum), add half
836cdf0e10cSrcweir             of the visible range (expand minimum toward 0) to make the
837cdf0e10cSrcweir             'shorter' data points visible. */
838cdf0e10cSrcweir         else
839cdf0e10cSrcweir         {
840cdf0e10cSrcweir             if( m_bExpandNarrowValuesTowardZero )
841cdf0e10cSrcweir                 fTempMinimum -= (fTempMaximum - fTempMinimum) / 2.0;
842cdf0e10cSrcweir         }
843cdf0e10cSrcweir     }
844cdf0e10cSrcweir 
845cdf0e10cSrcweir     /*  If range is still zero-sized (e.g. when minimum is fixed), add some
846cdf0e10cSrcweir         space to a variable limit. */
847cdf0e10cSrcweir     if( fTempMinimum == fTempMaximum )
848cdf0e10cSrcweir     {
849cdf0e10cSrcweir         if( bAutoMaximum || !bAutoMinimum )
850cdf0e10cSrcweir         {
851cdf0e10cSrcweir             // change 0 to 1, otherwise double the value
852cdf0e10cSrcweir             if( fTempMaximum == 0.0 )
853cdf0e10cSrcweir                 fTempMaximum = 1.0;
854cdf0e10cSrcweir             else
855cdf0e10cSrcweir                 fTempMaximum *= 2.0;
856cdf0e10cSrcweir         }
857cdf0e10cSrcweir         else
858cdf0e10cSrcweir         {
859cdf0e10cSrcweir             // change 0 to -1, otherwise halve the value
860cdf0e10cSrcweir             if( fTempMinimum == 0.0 )
861cdf0e10cSrcweir                 fTempMinimum = -1.0;
862cdf0e10cSrcweir             else
863cdf0e10cSrcweir                 fTempMinimum /= 2.0;
864cdf0e10cSrcweir         }
865cdf0e10cSrcweir     }
866cdf0e10cSrcweir 
867cdf0e10cSrcweir     // *** STEP 3: calculate main interval size ***
868cdf0e10cSrcweir 
869cdf0e10cSrcweir     // base value (anchor position of the intervals)
870cdf0e10cSrcweir     if( !(m_aSourceScale.IncrementData.BaseValue >>= rExplicitIncrement.BaseValue) )
871cdf0e10cSrcweir     {
872cdf0e10cSrcweir         if( !bAutoMinimum )
873cdf0e10cSrcweir             rExplicitIncrement.BaseValue = fTempMinimum;
874cdf0e10cSrcweir         else if( !bAutoMaximum )
875cdf0e10cSrcweir             rExplicitIncrement.BaseValue = fTempMaximum;
876cdf0e10cSrcweir         else
877cdf0e10cSrcweir             rExplicitIncrement.BaseValue = 0.0;
878cdf0e10cSrcweir     }
879cdf0e10cSrcweir 
880cdf0e10cSrcweir     // calculate automatic interval
881cdf0e10cSrcweir     bool bAutoDistance = !(m_aSourceScale.IncrementData.Distance >>= rExplicitIncrement.Distance);
882cdf0e10cSrcweir     /*  Restrict number of allowed intervals with user-defined distance to
883cdf0e10cSrcweir         MAXIMUM_MANUAL_INCREMENT_COUNT. */
884cdf0e10cSrcweir     sal_Int32 nMaxMainIncrementCount = bAutoDistance ?
885cdf0e10cSrcweir         m_nMaximumAutoMainIncrementCount : MAXIMUM_MANUAL_INCREMENT_COUNT;
886cdf0e10cSrcweir 
887cdf0e10cSrcweir     double fDistanceMagnitude = 0.0;
888cdf0e10cSrcweir     double fDistanceNormalized = 0.0;
889cdf0e10cSrcweir     bool bHasNormalizedDistance = false;
890cdf0e10cSrcweir 
891cdf0e10cSrcweir     // repeat calculation until number of intervals are valid
892cdf0e10cSrcweir     bool bNeedIteration = true;
893cdf0e10cSrcweir     while( bNeedIteration )
894cdf0e10cSrcweir     {
895cdf0e10cSrcweir         if( bAutoDistance )
896cdf0e10cSrcweir         {
897cdf0e10cSrcweir             // first iteration: calculate interval size from axis limits
898cdf0e10cSrcweir             if( !bHasNormalizedDistance )
899cdf0e10cSrcweir             {
900cdf0e10cSrcweir                 // raw size of an interval
901cdf0e10cSrcweir                 double fDistance = (fTempMaximum - fTempMinimum) / nMaxMainIncrementCount;
902cdf0e10cSrcweir 
903cdf0e10cSrcweir                 // if distance of is less than 1e-307, do not do anything
904cdf0e10cSrcweir                 if( fDistance <= 1.0e-307 )
905cdf0e10cSrcweir                 {
906cdf0e10cSrcweir                     fDistanceNormalized = 1.0;
907cdf0e10cSrcweir                     fDistanceMagnitude = 1.0e-307;
908cdf0e10cSrcweir                 }
909cdf0e10cSrcweir                 else
910cdf0e10cSrcweir                 {
911cdf0e10cSrcweir                     // distance magnitude (a power of 10)
912cdf0e10cSrcweir                     int nExponent = static_cast< int >( ::rtl::math::approxFloor( log10( fDistance ) ) );
913cdf0e10cSrcweir                     fDistanceMagnitude = ::rtl::math::pow10Exp( 1.0, nExponent );
914cdf0e10cSrcweir 
915cdf0e10cSrcweir                     // stick normalized distance to a few predefined values
916cdf0e10cSrcweir                     fDistanceNormalized = fDistance / fDistanceMagnitude;
917cdf0e10cSrcweir                     if( fDistanceNormalized <= 1.0 )
918cdf0e10cSrcweir                         fDistanceNormalized = 1.0;
919cdf0e10cSrcweir                     else if( fDistanceNormalized <= 2.0 )
920cdf0e10cSrcweir                         fDistanceNormalized = 2.0;
921cdf0e10cSrcweir                     else if( fDistanceNormalized <= 5.0 )
922cdf0e10cSrcweir                         fDistanceNormalized = 5.0;
923cdf0e10cSrcweir                     else
924cdf0e10cSrcweir                     {
925cdf0e10cSrcweir                         fDistanceNormalized = 1.0;
926cdf0e10cSrcweir                         fDistanceMagnitude *= 10;
927cdf0e10cSrcweir                     }
928cdf0e10cSrcweir                 }
929cdf0e10cSrcweir                 // for next iteration: distance is normalized -> use else path to increase distance
930cdf0e10cSrcweir                 bHasNormalizedDistance = true;
931cdf0e10cSrcweir             }
932cdf0e10cSrcweir             // following iterations: increase distance, use only allowed values
933cdf0e10cSrcweir             else
934cdf0e10cSrcweir             {
935cdf0e10cSrcweir                 if( fDistanceNormalized == 1.0 )
936cdf0e10cSrcweir                     fDistanceNormalized = 2.0;
937cdf0e10cSrcweir                 else if( fDistanceNormalized == 2.0 )
938cdf0e10cSrcweir                     fDistanceNormalized = 5.0;
939cdf0e10cSrcweir                 else
940cdf0e10cSrcweir                 {
941cdf0e10cSrcweir                     fDistanceNormalized = 1.0;
942cdf0e10cSrcweir                     fDistanceMagnitude *= 10;
943cdf0e10cSrcweir                 }
944cdf0e10cSrcweir             }
945cdf0e10cSrcweir 
946cdf0e10cSrcweir             // set the resulting distance
947cdf0e10cSrcweir             rExplicitIncrement.Distance = fDistanceNormalized * fDistanceMagnitude;
948cdf0e10cSrcweir         }
949cdf0e10cSrcweir 
950cdf0e10cSrcweir         // *** STEP 4: additional space above or below the data points ***
951cdf0e10cSrcweir 
952cdf0e10cSrcweir         double fAxisMinimum = fTempMinimum;
953cdf0e10cSrcweir         double fAxisMaximum = fTempMaximum;
954cdf0e10cSrcweir 
955cdf0e10cSrcweir         // round to entire multiples of the distance and add additional space
956cdf0e10cSrcweir         if( bAutoMinimum )
957cdf0e10cSrcweir         {
958cdf0e10cSrcweir             // round to entire multiples of the distance, based on the base value
959cdf0e10cSrcweir             if( m_bExpandBorderToIncrementRhythm )
960cdf0e10cSrcweir                 fAxisMinimum = EquidistantTickFactory::getMinimumAtIncrement( fAxisMinimum, rExplicitIncrement );
961cdf0e10cSrcweir             // additional space, if source minimum is to near at axis minimum
962cdf0e10cSrcweir             if( m_bExpandIfValuesCloseToBorder )
963cdf0e10cSrcweir                 if( (fAxisMinimum != 0.0) && ((fAxisMaximum - fSourceMinimum) / (fAxisMaximum - fAxisMinimum) > 20.0 / 21.0) )
964cdf0e10cSrcweir                     fAxisMinimum -= rExplicitIncrement.Distance;
965cdf0e10cSrcweir         }
966cdf0e10cSrcweir         if( bAutoMaximum )
967cdf0e10cSrcweir         {
968cdf0e10cSrcweir             // round to entire multiples of the distance, based on the base value
969cdf0e10cSrcweir             if( m_bExpandBorderToIncrementRhythm )
970cdf0e10cSrcweir                 fAxisMaximum = EquidistantTickFactory::getMaximumAtIncrement( fAxisMaximum, rExplicitIncrement );
971cdf0e10cSrcweir             // additional space, if source maximum is to near at axis maximum
972cdf0e10cSrcweir             if( m_bExpandIfValuesCloseToBorder )
973cdf0e10cSrcweir                 if( (fAxisMaximum != 0.0) && ((fSourceMaximum - fAxisMinimum) / (fAxisMaximum - fAxisMinimum) > 20.0 / 21.0) )
974cdf0e10cSrcweir                     fAxisMaximum += rExplicitIncrement.Distance;
975cdf0e10cSrcweir         }
976cdf0e10cSrcweir 
977cdf0e10cSrcweir         // set the resulting limits (swap back to negative range if needed)
978cdf0e10cSrcweir         if( bSwapAndNegateRange )
979cdf0e10cSrcweir         {
980cdf0e10cSrcweir             rExplicitScale.Minimum = -fAxisMaximum;
981cdf0e10cSrcweir             rExplicitScale.Maximum = -fAxisMinimum;
982cdf0e10cSrcweir         }
983cdf0e10cSrcweir         else
984cdf0e10cSrcweir         {
985cdf0e10cSrcweir             rExplicitScale.Minimum = fAxisMinimum;
986cdf0e10cSrcweir             rExplicitScale.Maximum = fAxisMaximum;
987cdf0e10cSrcweir         }
988cdf0e10cSrcweir 
989cdf0e10cSrcweir         /*  If the number of intervals is too high (e.g. due to invalid fixed
990cdf0e10cSrcweir             distance or due to added space above or below data points),
991cdf0e10cSrcweir             calculate again with increased distance. */
992cdf0e10cSrcweir         double fDistanceCount = ::rtl::math::approxFloor( (fAxisMaximum - fAxisMinimum) / rExplicitIncrement.Distance );
993cdf0e10cSrcweir         bNeedIteration = static_cast< sal_Int32 >( fDistanceCount ) > nMaxMainIncrementCount;
994cdf0e10cSrcweir         // if manual distance is invalid, trigger automatic calculation
995cdf0e10cSrcweir         if( bNeedIteration )
996cdf0e10cSrcweir             bAutoDistance = true;
997cdf0e10cSrcweir     }
998cdf0e10cSrcweir 
999cdf0e10cSrcweir     //---------------------------------------------------------------
1000cdf0e10cSrcweir     //fill explicit sub increment
1001cdf0e10cSrcweir     sal_Int32 nSubCount = m_aSourceScale.IncrementData.SubIncrements.getLength();
1002cdf0e10cSrcweir     for( sal_Int32 nN=0; nN<nSubCount; nN++ )
1003cdf0e10cSrcweir     {
1004cdf0e10cSrcweir         ExplicitSubIncrement aExplicitSubIncrement;
1005cdf0e10cSrcweir         const SubIncrement& rSubIncrement= m_aSourceScale.IncrementData.SubIncrements[nN];
1006cdf0e10cSrcweir         if(!(rSubIncrement.IntervalCount>>=aExplicitSubIncrement.IntervalCount))
1007cdf0e10cSrcweir         {
1008cdf0e10cSrcweir             //scaling dependent
1009cdf0e10cSrcweir             //@todo autocalculate IntervalCount dependent on MainIncrement and scaling
1010cdf0e10cSrcweir             aExplicitSubIncrement.IntervalCount = 2;
1011cdf0e10cSrcweir         }
1012cdf0e10cSrcweir         lcl_ensureMaximumSubIncrementCount( aExplicitSubIncrement.IntervalCount );
1013cdf0e10cSrcweir         if(!(rSubIncrement.PostEquidistant>>=aExplicitSubIncrement.PostEquidistant))
1014cdf0e10cSrcweir         {
1015cdf0e10cSrcweir             //scaling dependent
1016cdf0e10cSrcweir             aExplicitSubIncrement.PostEquidistant = sal_False;
1017cdf0e10cSrcweir         }
1018cdf0e10cSrcweir         rExplicitIncrement.SubIncrements.push_back(aExplicitSubIncrement);
1019cdf0e10cSrcweir     }
1020cdf0e10cSrcweir }
1021cdf0e10cSrcweir 
1022cdf0e10cSrcweir //.............................................................................
1023cdf0e10cSrcweir } //namespace chart
1024cdf0e10cSrcweir //.............................................................................
1025