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 5399 : sal_Int32 lcl_getMaximumAutoIncrementCount( sal_Int32 nAxisType )
43 : {
44 5399 : sal_Int32 nMaximumAutoIncrementCount = 10;
45 5399 : if( nAxisType==AxisType::DATE )
46 0 : nMaximumAutoIncrementCount = MAXIMUM_MANUAL_INCREMENT_COUNT;
47 5399 : return nMaximumAutoIncrementCount;
48 : }
49 :
50 : namespace
51 : {
52 :
53 4792 : void lcl_ensureMaximumSubIncrementCount( sal_Int32& rnSubIntervalCount )
54 : {
55 4792 : if( rnSubIntervalCount > MAXIMUM_SUB_INCREMENT_COUNT )
56 0 : rnSubIntervalCount = MAXIMUM_SUB_INCREMENT_COUNT;
57 4792 : }
58 :
59 : }//end anonymous namespace
60 :
61 72594 : 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 72594 : , NullDate(30,12,1899)
71 : {
72 72594 : }
73 :
74 4792 : ExplicitSubIncrement::ExplicitSubIncrement()
75 : : IntervalCount(2)
76 4792 : , PostEquidistant(true)
77 : {
78 4792 : }
79 :
80 67097 : 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 67097 : , SubIncrements()
87 : {
88 67097 : }
89 :
90 2302 : ScaleAutomatism::ScaleAutomatism( const ScaleData& rSourceScale, const Date& rNullDate )
91 : : m_aSourceScale( rSourceScale )
92 : , m_fValueMinimum( 0.0 )
93 : , m_fValueMaximum( 0.0 )
94 2302 : , 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 4604 : , m_aNullDate(rNullDate)
101 : {
102 2302 : ::rtl::math::setNan( &m_fValueMinimum );
103 2302 : ::rtl::math::setNan( &m_fValueMaximum );
104 :
105 2302 : double fExplicitOrigin = 0.0;
106 2302 : if( m_aSourceScale.Origin >>= fExplicitOrigin )
107 65 : expandValueRange( fExplicitOrigin, fExplicitOrigin);
108 2302 : }
109 2302 : ScaleAutomatism::~ScaleAutomatism()
110 : {
111 2302 : }
112 :
113 2333 : void ScaleAutomatism::expandValueRange( double fMinimum, double fMaximum )
114 : {
115 2333 : if( (fMinimum < m_fValueMinimum) || ::rtl::math::isNan( m_fValueMinimum ) )
116 1165 : m_fValueMinimum = fMinimum;
117 2333 : if( (fMaximum > m_fValueMaximum) || ::rtl::math::isNan( m_fValueMaximum ) )
118 1218 : m_fValueMaximum = fMaximum;
119 2333 : }
120 :
121 2268 : 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 2268 : m_bExpandBorderToIncrementRhythm |= bExpandBorderToIncrementRhythm;
129 2268 : m_bExpandIfValuesCloseToBorder |= bExpandIfValuesCloseToBorder;
130 2268 : m_bExpandWideValuesToZero |= bExpandWideValuesToZero;
131 2268 : m_bExpandNarrowValuesTowardZero |= bExpandNarrowValuesTowardZero;
132 :
133 2268 : if( m_aSourceScale.AxisType==AxisType::PERCENT )
134 16 : m_bExpandIfValuesCloseToBorder = false;
135 2268 : }
136 :
137 2198 : void ScaleAutomatism::setMaximumAutoMainIncrementCount( sal_Int32 nMaximumAutoMainIncrementCount )
138 : {
139 2198 : if( nMaximumAutoMainIncrementCount < 2 )
140 12 : m_nMaximumAutoMainIncrementCount = 2; //#i82006
141 2186 : else if( nMaximumAutoMainIncrementCount > lcl_getMaximumAutoIncrementCount( m_aSourceScale.AxisType ) )
142 911 : m_nMaximumAutoMainIncrementCount = lcl_getMaximumAutoIncrementCount( m_aSourceScale.AxisType );
143 : else
144 1275 : m_nMaximumAutoMainIncrementCount = nMaximumAutoMainIncrementCount;
145 2198 : }
146 :
147 0 : void ScaleAutomatism::setAutomaticTimeResolution( sal_Int32 nTimeResolution )
148 : {
149 0 : m_nTimeResolution = nTimeResolution;
150 0 : }
151 :
152 4792 : void ScaleAutomatism::calculateExplicitScaleAndIncrement(
153 : ExplicitScaleData& rExplicitScale, ExplicitIncrementData& rExplicitIncrement ) const
154 : {
155 : // fill explicit scale
156 4792 : rExplicitScale.Orientation = m_aSourceScale.Orientation;
157 4792 : rExplicitScale.Scaling = m_aSourceScale.Scaling;
158 4792 : rExplicitScale.AxisType = m_aSourceScale.AxisType;
159 4792 : rExplicitScale.NullDate = m_aNullDate;
160 :
161 4792 : bool bAutoMinimum = !(m_aSourceScale.Minimum >>= rExplicitScale.Minimum);
162 4792 : bool bAutoMaximum = !(m_aSourceScale.Maximum >>= rExplicitScale.Maximum);
163 4792 : bool bAutoOrigin = !(m_aSourceScale.Origin >>= rExplicitScale.Origin);
164 :
165 : // automatic scale minimum
166 4792 : if( bAutoMinimum )
167 : {
168 4680 : if( m_aSourceScale.AxisType==AxisType::PERCENT )
169 32 : rExplicitScale.Minimum = 0.0;
170 4648 : else if( ::rtl::math::isNan( m_fValueMinimum ) )
171 : {
172 547 : if( m_aSourceScale.AxisType==AxisType::DATE )
173 0 : rExplicitScale.Minimum = 36526.0; //1.1.2000
174 : else
175 547 : rExplicitScale.Minimum = 0.0; //@todo get Minimum from scaling or from plotter????
176 : }
177 : else
178 4101 : rExplicitScale.Minimum = m_fValueMinimum;
179 : }
180 :
181 : // automatic scale maximum
182 4792 : if( bAutoMaximum )
183 : {
184 4660 : if( m_aSourceScale.AxisType==AxisType::PERCENT )
185 32 : rExplicitScale.Maximum = 1.0;
186 4628 : else if( ::rtl::math::isNan( m_fValueMaximum ) )
187 : {
188 542 : if( m_aSourceScale.AxisType==AxisType::DATE )
189 0 : rExplicitScale.Maximum = 40179.0; //1.1.2010
190 : else
191 542 : rExplicitScale.Maximum = 10.0; //@todo get Maximum from scaling or from plotter????
192 : }
193 : else
194 4086 : rExplicitScale.Maximum = m_fValueMaximum;
195 : }
196 :
197 : //fill explicit increment
198 :
199 4792 : rExplicitScale.ShiftedCategoryPosition = m_aSourceScale.ShiftedCategoryPosition;
200 4792 : bool bIsLogarithm = false;
201 :
202 : //minimum and maximum of the ExplicitScaleData may be changed if allowed
203 4792 : if( m_aSourceScale.AxisType==AxisType::DATE )
204 0 : calculateExplicitIncrementAndScaleForDateTimeAxis( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum );
205 4792 : else if( m_aSourceScale.AxisType==AxisType::CATEGORY || m_aSourceScale.AxisType==AxisType::SERIES )
206 2280 : calculateExplicitIncrementAndScaleForCategory( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum );
207 : else
208 : {
209 2512 : bIsLogarithm = AxisHelper::isLogarithmic( rExplicitScale.Scaling );
210 2512 : if( bIsLogarithm )
211 312 : calculateExplicitIncrementAndScaleForLogarithmic( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum );
212 : else
213 2200 : calculateExplicitIncrementAndScaleForLinear( rExplicitScale, rExplicitIncrement, bAutoMinimum, bAutoMaximum );
214 : }
215 :
216 : // automatic origin
217 4792 : if( bAutoOrigin )
218 : {
219 : // #i71415# automatic origin for logarithmic axis
220 4532 : double fDefaulOrigin = bIsLogarithm ? 1.0 : 0.0;
221 :
222 4532 : if( fDefaulOrigin < rExplicitScale.Minimum )
223 2416 : fDefaulOrigin = rExplicitScale.Minimum;
224 2116 : else if( fDefaulOrigin > rExplicitScale.Maximum )
225 0 : fDefaulOrigin = rExplicitScale.Maximum;
226 :
227 4532 : rExplicitScale.Origin = fDefaulOrigin;
228 : }
229 4792 : }
230 :
231 2280 : void ScaleAutomatism::calculateExplicitIncrementAndScaleForCategory(
232 : ExplicitScaleData& rExplicitScale,
233 : ExplicitIncrementData& rExplicitIncrement,
234 : bool bAutoMinimum, bool bAutoMaximum ) const
235 : {
236 : // no scaling for categories
237 2280 : rExplicitScale.Scaling.clear();
238 :
239 2280 : if( rExplicitScale.ShiftedCategoryPosition )
240 1864 : rExplicitScale.Maximum += 1.0;
241 :
242 : // ensure that at least one category is visible
243 2280 : if( rExplicitScale.Maximum <= rExplicitScale.Minimum )
244 0 : rExplicitScale.Maximum = rExplicitScale.Minimum + 1.0;
245 :
246 : // default increment settings
247 2280 : rExplicitIncrement.PostEquidistant = true; // does not matter anyhow
248 2280 : rExplicitIncrement.Distance = 1.0; // category axis always have a main increment of 1
249 2280 : rExplicitIncrement.BaseValue = 0.0; // category axis always have a base of 0
250 :
251 : // automatic minimum and maximum
252 2280 : if( bAutoMinimum && m_bExpandBorderToIncrementRhythm )
253 0 : rExplicitScale.Minimum = EquidistantTickFactory::getMinimumAtIncrement( rExplicitScale.Minimum, rExplicitIncrement );
254 2280 : if( bAutoMaximum && m_bExpandBorderToIncrementRhythm )
255 0 : rExplicitScale.Maximum = EquidistantTickFactory::getMaximumAtIncrement( rExplicitScale.Maximum, rExplicitIncrement );
256 :
257 : //prevent performace killover
258 2280 : double fDistanceCount = ::rtl::math::approxFloor( (rExplicitScale.Maximum-rExplicitScale.Minimum) / rExplicitIncrement.Distance );
259 2280 : 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 2280 : sal_Int32 nSubCount = m_aSourceScale.IncrementData.SubIncrements.getLength();
268 4560 : for( sal_Int32 nN=0; nN<nSubCount; nN++ )
269 : {
270 2280 : ExplicitSubIncrement aExplicitSubIncrement;
271 2280 : const SubIncrement& rSubIncrement= m_aSourceScale.IncrementData.SubIncrements[nN];
272 2280 : if(!(rSubIncrement.IntervalCount>>=aExplicitSubIncrement.IntervalCount))
273 : {
274 : //scaling dependent
275 : //@todo autocalculate IntervalCount dependent on MainIncrement and scaling
276 2280 : aExplicitSubIncrement.IntervalCount = 2;
277 : }
278 2280 : lcl_ensureMaximumSubIncrementCount( aExplicitSubIncrement.IntervalCount );
279 2280 : if(!(rSubIncrement.PostEquidistant>>=aExplicitSubIncrement.PostEquidistant))
280 : {
281 : //scaling dependent
282 2280 : aExplicitSubIncrement.PostEquidistant = false;
283 : }
284 2280 : rExplicitIncrement.SubIncrements.push_back(aExplicitSubIncrement);
285 : }
286 2280 : }
287 :
288 312 : 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 312 : const double fInputMinimum = rExplicitScale.Minimum;
296 312 : const double fInputMaximum = rExplicitScale.Maximum;
297 :
298 312 : double fSourceMinimum = rExplicitScale.Minimum;
299 312 : 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 312 : if( !(m_aSourceScale.IncrementData.PostEquidistant >>= rExplicitIncrement.PostEquidistant) )
304 312 : 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 312 : uno::Reference< XScaling > xScaling = rExplicitScale.Scaling;
309 312 : if( !xScaling.is() )
310 0 : xScaling.set( AxisHelper::createLogarithmicScaling() );
311 624 : uno::Reference< XScaling > xInverseScaling = xScaling->getInverseScaling();
312 :
313 312 : fSourceMinimum = xScaling->doScaling( fSourceMinimum );
314 312 : if( !::rtl::math::isFinite( fSourceMinimum ) )
315 67 : fSourceMinimum = 0.0;
316 245 : else if( ::rtl::math::approxEqual( fSourceMinimum, ::rtl::math::approxFloor( fSourceMinimum ) ) )
317 68 : fSourceMinimum = ::rtl::math::approxFloor( fSourceMinimum );
318 :
319 312 : fSourceMaximum = xScaling->doScaling( fSourceMaximum );
320 312 : if( !::rtl::math::isFinite( fSourceMaximum ) )
321 0 : fSourceMaximum = 0.0;
322 312 : else if( ::rtl::math::approxEqual( fSourceMaximum, ::rtl::math::approxFloor( fSourceMaximum ) ) )
323 141 : 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 312 : 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 312 : bool bSwapAndNegateRange = (fSourceMinimum < 0.0) && (fSourceMaximum <= 0.0);
344 312 : 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 312 : double fTempMinimum = fSourceMinimum;
355 312 : 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 312 : 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 177 : double fMinimumFloor = ::rtl::math::approxFloor( fTempMinimum );
368 177 : 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 177 : if( ::rtl::math::approxEqual( fTempMaximum, fMaximumFloor ) )
371 6 : fMaximumFloor -= 1.0;
372 :
373 177 : if( (fMinimumFloor < 5.0) || (fMinimumFloor < fMaximumFloor) )
374 : {
375 354 : if( m_bExpandWideValuesToZero )
376 177 : 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 312 : if( fTempMinimum == fTempMaximum )
390 : {
391 8 : if( bAutoMinimum && (fTempMaximum > 0.0) )
392 0 : fTempMinimum = 0.0;
393 : else
394 8 : 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 312 : if( !(m_aSourceScale.IncrementData.BaseValue >>= rExplicitIncrement.BaseValue) )
401 : {
402 : //scaling dependent
403 : //@maybe todo is this default also plotter dependent ??
404 312 : if( !bAutoMinimum )
405 68 : rExplicitIncrement.BaseValue = fTempMinimum;
406 244 : else if( !bAutoMaximum )
407 8 : rExplicitIncrement.BaseValue = fTempMaximum;
408 : else
409 236 : rExplicitIncrement.BaseValue = 0.0;
410 : }
411 :
412 : // calculate automatic interval
413 312 : bool bAutoDistance = !(m_aSourceScale.IncrementData.Distance >>= rExplicitIncrement.Distance);
414 312 : if( bAutoDistance )
415 268 : 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 312 : m_nMaximumAutoMainIncrementCount : MAXIMUM_MANUAL_INCREMENT_COUNT;
421 :
422 : // repeat calculation until number of intervals are valid
423 312 : bool bNeedIteration = true;
424 312 : bool bHasCalculatedDistance = false;
425 936 : while( bNeedIteration )
426 : {
427 312 : if( bAutoDistance )
428 : {
429 : // first iteration: calculate interval size from axis limits
430 268 : if( !bHasCalculatedDistance )
431 : {
432 268 : double fMinimumFloor = ::rtl::math::approxFloor( fTempMinimum );
433 268 : double fMaximumCeil = ::rtl::math::approxCeil( fTempMaximum );
434 268 : 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 268 : bHasCalculatedDistance = true;
444 : }
445 :
446 : // *** STEP 4: additional space above or below the data points ***
447 :
448 312 : double fAxisMinimum = fTempMinimum;
449 312 : double fAxisMaximum = fTempMaximum;
450 :
451 : // round to entire multiples of the distance and add additional space
452 312 : if( bAutoMinimum && m_bExpandBorderToIncrementRhythm )
453 : {
454 183 : fAxisMinimum = EquidistantTickFactory::getMinimumAtIncrement( fAxisMinimum, rExplicitIncrement );
455 :
456 : //ensure valid values after scaling #i100995#
457 183 : 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 312 : if( bAutoMaximum && m_bExpandBorderToIncrementRhythm )
469 : {
470 177 : fAxisMaximum = EquidistantTickFactory::getMaximumAtIncrement( fAxisMaximum, rExplicitIncrement );
471 :
472 : //ensure valid values after scaling #i100995#
473 177 : 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 312 : if( bSwapAndNegateRange )
487 : {
488 0 : rExplicitScale.Minimum = -fAxisMaximum;
489 0 : rExplicitScale.Maximum = -fAxisMinimum;
490 : }
491 : else
492 : {
493 312 : rExplicitScale.Minimum = fAxisMinimum;
494 312 : 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 312 : double fDistanceCount = ::rtl::math::approxFloor( (fAxisMaximum - fAxisMinimum) / rExplicitIncrement.Distance );
501 312 : bNeedIteration = static_cast< sal_Int32 >( fDistanceCount ) > nMaxMainIncrementCount;
502 : // if manual distance is invalid, trigger automatic calculation
503 312 : if( bNeedIteration )
504 0 : bAutoDistance = true;
505 :
506 : // convert limits back to logarithmic scale
507 312 : rExplicitScale.Minimum = xInverseScaling->doScaling( rExplicitScale.Minimum );
508 312 : rExplicitScale.Maximum = xInverseScaling->doScaling( rExplicitScale.Maximum );
509 :
510 : //ensure valid values after scaling #i100995#
511 312 : 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 312 : 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 312 : if( rExplicitScale.Maximum < rExplicitScale.Minimum )
524 0 : ::std::swap( rExplicitScale.Maximum, rExplicitScale.Minimum );
525 : }
526 :
527 : //fill explicit sub increment
528 312 : sal_Int32 nSubCount = m_aSourceScale.IncrementData.SubIncrements.getLength();
529 624 : for( sal_Int32 nN=0; nN<nSubCount; nN++ )
530 : {
531 312 : ExplicitSubIncrement aExplicitSubIncrement;
532 312 : const SubIncrement& rSubIncrement = m_aSourceScale.IncrementData.SubIncrements[nN];
533 312 : if(!(rSubIncrement.IntervalCount>>=aExplicitSubIncrement.IntervalCount))
534 : {
535 : //scaling dependent
536 : //@todo autocalculate IntervalCount dependent on MainIncrement and scaling
537 260 : aExplicitSubIncrement.IntervalCount = 9;
538 : }
539 312 : lcl_ensureMaximumSubIncrementCount( aExplicitSubIncrement.IntervalCount );
540 312 : if(!(rSubIncrement.PostEquidistant>>=aExplicitSubIncrement.PostEquidistant))
541 : {
542 : //scaling dependent
543 312 : aExplicitSubIncrement.PostEquidistant = false;
544 : }
545 312 : rExplicitIncrement.SubIncrements.push_back(aExplicitSubIncrement);
546 312 : }
547 312 : }
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 2200 : 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 2200 : double fSourceMinimum = rExplicitScale.Minimum;
749 2200 : double fSourceMaximum = rExplicitScale.Maximum;
750 :
751 : // set automatic PostEquidistant to true (maybe scaling dependent?)
752 2200 : if( !(m_aSourceScale.IncrementData.PostEquidistant >>= rExplicitIncrement.PostEquidistant) )
753 2200 : 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 2200 : 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 2200 : bool bSwapAndNegateRange = (fSourceMinimum < 0.0) && (fSourceMaximum <= 0.0);
774 2200 : 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 2200 : double fTempMinimum = fSourceMinimum;
785 2200 : 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 2200 : 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 1165 : if( (fTempMinimum == fTempMaximum) || (fTempMinimum / fTempMaximum < 5.0 / 6.0) )
795 : {
796 2330 : if( m_bExpandWideValuesToZero )
797 939 : 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 2200 : if( fTempMinimum == fTempMaximum )
812 : {
813 45 : if( bAutoMaximum || !bAutoMinimum )
814 : {
815 : // change 0 to 1, otherwise double the value
816 90 : if( fTempMaximum == 0.0 )
817 41 : fTempMaximum = 1.0;
818 : else
819 4 : 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 2200 : if( !(m_aSourceScale.IncrementData.BaseValue >>= rExplicitIncrement.BaseValue) )
835 : {
836 2200 : if( !bAutoMinimum )
837 44 : rExplicitIncrement.BaseValue = fTempMinimum;
838 2156 : else if( !bAutoMaximum )
839 12 : rExplicitIncrement.BaseValue = fTempMaximum;
840 : else
841 2144 : rExplicitIncrement.BaseValue = 0.0;
842 : }
843 :
844 : // calculate automatic interval
845 2200 : 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 2200 : m_nMaximumAutoMainIncrementCount : MAXIMUM_MANUAL_INCREMENT_COUNT;
850 :
851 2200 : double fDistanceMagnitude = 0.0;
852 2200 : double fDistanceNormalized = 0.0;
853 2200 : bool bHasNormalizedDistance = false;
854 :
855 : // repeat calculation until number of intervals are valid
856 2200 : bool bNeedIteration = true;
857 7454 : while( bNeedIteration )
858 : {
859 3054 : if( bAutoDistance )
860 : {
861 : // first iteration: calculate interval size from axis limits
862 3026 : if( !bHasNormalizedDistance )
863 : {
864 : // raw size of an interval
865 2172 : double fDistance = (fTempMaximum - fTempMinimum) / nMaxMainIncrementCount;
866 :
867 : // if distance of is less than 1e-307, do not do anything
868 2172 : if( fDistance <= 1.0e-307 )
869 : {
870 0 : fDistanceNormalized = 1.0;
871 0 : fDistanceMagnitude = 1.0e-307;
872 : }
873 2172 : 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 2172 : int nExponent = static_cast< int >( ::rtl::math::approxFloor( log10( fDistance ) ) );
883 2172 : fDistanceMagnitude = ::rtl::math::pow10Exp( 1.0, nExponent );
884 :
885 : // stick normalized distance to a few predefined values
886 2172 : fDistanceNormalized = fDistance / fDistanceMagnitude;
887 2172 : if( fDistanceNormalized <= 1.0 )
888 552 : fDistanceNormalized = 1.0;
889 1620 : else if( fDistanceNormalized <= 2.0 )
890 199 : fDistanceNormalized = 2.0;
891 1421 : else if( fDistanceNormalized <= 5.0 )
892 574 : fDistanceNormalized = 5.0;
893 : else
894 : {
895 847 : fDistanceNormalized = 1.0;
896 847 : fDistanceMagnitude *= 10;
897 : }
898 : }
899 : // for next iteration: distance is normalized -> use else path to increase distance
900 2172 : bHasNormalizedDistance = true;
901 : }
902 : // following iterations: increase distance, use only allowed values
903 : else
904 : {
905 854 : if( fDistanceNormalized == 1.0 )
906 640 : fDistanceNormalized = 2.0;
907 214 : else if( fDistanceNormalized == 2.0 )
908 100 : fDistanceNormalized = 5.0;
909 : else
910 : {
911 114 : fDistanceNormalized = 1.0;
912 114 : fDistanceMagnitude *= 10;
913 : }
914 : }
915 :
916 : // set the resulting distance
917 3026 : rExplicitIncrement.Distance = fDistanceNormalized * fDistanceMagnitude;
918 : }
919 :
920 : // *** STEP 4: additional space above or below the data points ***
921 :
922 3054 : double fAxisMinimum = fTempMinimum;
923 3054 : double fAxisMaximum = fTempMaximum;
924 :
925 : // round to entire multiples of the distance and add additional space
926 3054 : if( bAutoMinimum )
927 : {
928 : // round to entire multiples of the distance, based on the base value
929 3010 : if( m_bExpandBorderToIncrementRhythm )
930 2473 : fAxisMinimum = EquidistantTickFactory::getMinimumAtIncrement( fAxisMinimum, rExplicitIncrement );
931 : // additional space, if source minimum is to near at axis minimum
932 3010 : if( m_bExpandIfValuesCloseToBorder )
933 2302 : if( (fAxisMinimum != 0.0) && ((fAxisMaximum - fSourceMinimum) / (fAxisMaximum - fAxisMinimum) > 20.0 / 21.0) )
934 284 : fAxisMinimum -= rExplicitIncrement.Distance;
935 : }
936 3054 : if( bAutoMaximum )
937 : {
938 : // round to entire multiples of the distance, based on the base value
939 2998 : if( m_bExpandBorderToIncrementRhythm )
940 2464 : fAxisMaximum = EquidistantTickFactory::getMaximumAtIncrement( fAxisMaximum, rExplicitIncrement );
941 : // additional space, if source maximum is to near at axis maximum
942 2998 : if( m_bExpandIfValuesCloseToBorder )
943 2293 : if( (fAxisMaximum != 0.0) && ((fSourceMaximum - fAxisMinimum) / (fAxisMaximum - fAxisMinimum) > 20.0 / 21.0) )
944 2024 : fAxisMaximum += rExplicitIncrement.Distance;
945 : }
946 :
947 : // set the resulting limits (swap back to negative range if needed)
948 3054 : if( bSwapAndNegateRange )
949 : {
950 0 : rExplicitScale.Minimum = -fAxisMaximum;
951 0 : rExplicitScale.Maximum = -fAxisMinimum;
952 : }
953 : else
954 : {
955 3054 : rExplicitScale.Minimum = fAxisMinimum;
956 3054 : 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 3054 : double fDistanceCount = ::rtl::math::approxFloor( (fAxisMaximum - fAxisMinimum) / rExplicitIncrement.Distance );
963 3054 : bNeedIteration = static_cast< sal_Int32 >( fDistanceCount ) > nMaxMainIncrementCount;
964 : // if manual distance is invalid, trigger automatic calculation
965 3054 : if( bNeedIteration )
966 854 : bAutoDistance = true;
967 : }
968 :
969 : //fill explicit sub increment
970 2200 : sal_Int32 nSubCount = m_aSourceScale.IncrementData.SubIncrements.getLength();
971 4400 : for( sal_Int32 nN=0; nN<nSubCount; nN++ )
972 : {
973 2200 : ExplicitSubIncrement aExplicitSubIncrement;
974 2200 : const SubIncrement& rSubIncrement= m_aSourceScale.IncrementData.SubIncrements[nN];
975 2200 : if(!(rSubIncrement.IntervalCount>>=aExplicitSubIncrement.IntervalCount))
976 : {
977 : //scaling dependent
978 : //@todo autocalculate IntervalCount dependent on MainIncrement and scaling
979 2180 : aExplicitSubIncrement.IntervalCount = 2;
980 : }
981 2200 : lcl_ensureMaximumSubIncrementCount( aExplicitSubIncrement.IntervalCount );
982 2200 : if(!(rSubIncrement.PostEquidistant>>=aExplicitSubIncrement.PostEquidistant))
983 : {
984 : //scaling dependent
985 2200 : aExplicitSubIncrement.PostEquidistant = false;
986 : }
987 2200 : rExplicitIncrement.SubIncrements.push_back(aExplicitSubIncrement);
988 : }
989 2200 : }
990 :
991 108 : } //namespace chart
992 :
993 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|