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