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