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 "Tickmarks_Equidistant.hxx"
21 : #include "ViewDefines.hxx"
22 : #include <rtl/math.hxx>
23 :
24 : #include <limits>
25 :
26 : namespace chart
27 : {
28 : using namespace ::com::sun::star;
29 : using namespace ::com::sun::star::chart2;
30 : using namespace ::rtl::math;
31 : using ::basegfx::B2DVector;
32 :
33 : //static
34 14024 : double EquidistantTickFactory::getMinimumAtIncrement( double fMin, const ExplicitIncrementData& rIncrement )
35 : {
36 : //the returned value will be <= fMin and on a Major Tick given by rIncrement
37 14024 : if(rIncrement.Distance<=0.0)
38 0 : return fMin;
39 :
40 14024 : double fRet = rIncrement.BaseValue +
41 14024 : floor( approxSub( fMin, rIncrement.BaseValue )
42 14024 : / rIncrement.Distance)
43 14024 : *rIncrement.Distance;
44 :
45 14024 : if( fRet > fMin )
46 : {
47 0 : if( !approxEqual(fRet, fMin) )
48 0 : fRet -= rIncrement.Distance;
49 : }
50 14024 : return fRet;
51 : }
52 : //static
53 14030 : double EquidistantTickFactory::getMaximumAtIncrement( double fMax, const ExplicitIncrementData& rIncrement )
54 : {
55 : //the returned value will be >= fMax and on a Major Tick given by rIncrement
56 14030 : if(rIncrement.Distance<=0.0)
57 0 : return fMax;
58 :
59 14030 : double fRet = rIncrement.BaseValue +
60 14030 : floor( approxSub( fMax, rIncrement.BaseValue )
61 14030 : / rIncrement.Distance)
62 14030 : *rIncrement.Distance;
63 :
64 14030 : if( fRet < fMax )
65 : {
66 5917 : if( !approxEqual(fRet, fMax) )
67 5917 : fRet += rIncrement.Distance;
68 : }
69 14030 : return fRet;
70 : }
71 :
72 8801 : EquidistantTickFactory::EquidistantTickFactory(
73 : const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement )
74 : : m_rScale( rScale )
75 : , m_rIncrement( rIncrement )
76 : , m_xInverseScaling(NULL)
77 8801 : , m_pfCurrentValues(NULL)
78 : {
79 : //@todo: make sure that the scale is valid for the scaling
80 :
81 8801 : m_pfCurrentValues = new double[getTickDepth()];
82 :
83 8801 : if( m_rScale.Scaling.is() )
84 : {
85 2973 : m_xInverseScaling = m_rScale.Scaling->getInverseScaling();
86 : OSL_ENSURE( m_xInverseScaling.is(), "each Scaling needs to return a inverse Scaling" );
87 : }
88 :
89 8801 : double fMin = m_fScaledVisibleMin = m_rScale.Minimum;
90 8801 : if( m_xInverseScaling.is() )
91 : {
92 2973 : m_fScaledVisibleMin = m_rScale.Scaling->doScaling(m_fScaledVisibleMin);
93 2973 : if(m_rIncrement.PostEquidistant )
94 2973 : fMin = m_fScaledVisibleMin;
95 : }
96 :
97 8801 : double fMax = m_fScaledVisibleMax = m_rScale.Maximum;
98 8801 : if( m_xInverseScaling.is() )
99 : {
100 2973 : m_fScaledVisibleMax = m_rScale.Scaling->doScaling(m_fScaledVisibleMax);
101 2973 : if(m_rIncrement.PostEquidistant )
102 2973 : fMax = m_fScaledVisibleMax;
103 : }
104 :
105 8801 : m_fOuterMajorTickBorderMin = EquidistantTickFactory::getMinimumAtIncrement( fMin, m_rIncrement );
106 8801 : m_fOuterMajorTickBorderMax = EquidistantTickFactory::getMaximumAtIncrement( fMax, m_rIncrement );
107 :
108 8801 : m_fOuterMajorTickBorderMin_Scaled = m_fOuterMajorTickBorderMin;
109 8801 : m_fOuterMajorTickBorderMax_Scaled = m_fOuterMajorTickBorderMax;
110 8801 : if(!m_rIncrement.PostEquidistant && m_xInverseScaling.is() )
111 : {
112 0 : m_fOuterMajorTickBorderMin_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMin);
113 0 : m_fOuterMajorTickBorderMax_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMax);
114 :
115 : //check validity of new range: m_fOuterMajorTickBorderMin <-> m_fOuterMajorTickBorderMax
116 : //it is assumed here, that the original range in the given Scale is valid
117 0 : if( !rtl::math::isFinite(m_fOuterMajorTickBorderMin_Scaled) )
118 : {
119 0 : m_fOuterMajorTickBorderMin += m_rIncrement.Distance;
120 0 : m_fOuterMajorTickBorderMin_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMin);
121 : }
122 0 : if( !rtl::math::isFinite(m_fOuterMajorTickBorderMax_Scaled) )
123 : {
124 0 : m_fOuterMajorTickBorderMax -= m_rIncrement.Distance;
125 0 : m_fOuterMajorTickBorderMax_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMax);
126 : }
127 : }
128 8801 : }
129 :
130 17602 : EquidistantTickFactory::~EquidistantTickFactory()
131 : {
132 8801 : delete[] m_pfCurrentValues;
133 8801 : }
134 :
135 29606 : sal_Int32 EquidistantTickFactory::getTickDepth() const
136 : {
137 29606 : return static_cast<sal_Int32>(m_rIncrement.SubIncrements.size()) + 1;
138 : }
139 :
140 6935 : void EquidistantTickFactory::addSubTicks( sal_Int32 nDepth, uno::Sequence< uno::Sequence< double > >& rParentTicks ) const
141 : {
142 6935 : EquidistantTickIter aIter( rParentTicks, m_rIncrement, 0, nDepth-1 );
143 6935 : double* pfNextParentTick = aIter.firstValue();
144 6935 : if(!pfNextParentTick)
145 0 : return;
146 6935 : double fLastParentTick = *pfNextParentTick;
147 6935 : pfNextParentTick = aIter.nextValue();
148 6935 : if(!pfNextParentTick)
149 0 : return;
150 :
151 6935 : sal_Int32 nMaxSubTickCount = this->getMaxTickCount( nDepth );
152 6935 : if(!nMaxSubTickCount)
153 0 : return;
154 :
155 13870 : uno::Sequence< double > aSubTicks(nMaxSubTickCount);
156 6935 : sal_Int32 nRealSubTickCount = 0;
157 6935 : sal_Int32 nIntervalCount = m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
158 :
159 6935 : double* pValue = NULL;
160 42483 : for(; pfNextParentTick; fLastParentTick=*pfNextParentTick, pfNextParentTick = aIter.nextValue())
161 : {
162 76977 : for( sal_Int32 nPartTick = 1; nPartTick<nIntervalCount; nPartTick++ )
163 : {
164 : pValue = this->getMinorTick( nPartTick, nDepth
165 41429 : , fLastParentTick, *pfNextParentTick );
166 41429 : if(!pValue)
167 0 : continue;
168 :
169 41429 : aSubTicks[nRealSubTickCount] = *pValue;
170 41429 : nRealSubTickCount++;
171 : }
172 : }
173 :
174 6935 : aSubTicks.realloc(nRealSubTickCount);
175 6935 : rParentTicks[nDepth] = aSubTicks;
176 6935 : if(static_cast<sal_Int32>(m_rIncrement.SubIncrements.size())>nDepth)
177 6935 : addSubTicks( nDepth+1, rParentTicks );
178 : }
179 :
180 13870 : sal_Int32 EquidistantTickFactory::getMaxTickCount( sal_Int32 nDepth ) const
181 : {
182 : //return the maximum amount of ticks
183 : //possibly open intervals at the two ends of the region are handled as if they were completely visible
184 : //(this is necessary for calculating the sub ticks at the borders correctly)
185 :
186 13870 : if( nDepth >= getTickDepth() )
187 0 : return 0;
188 13870 : if( m_fOuterMajorTickBorderMax < m_fOuterMajorTickBorderMin )
189 0 : return 0;
190 13870 : if( m_rIncrement.Distance<=0.0)
191 0 : return 0;
192 :
193 : double fSub;
194 13870 : if(m_rIncrement.PostEquidistant )
195 13870 : fSub = approxSub( m_fScaledVisibleMax, m_fScaledVisibleMin );
196 : else
197 0 : fSub = approxSub( m_rScale.Maximum, m_rScale.Minimum );
198 :
199 13870 : if (!isFinite(fSub))
200 0 : return 0;
201 :
202 13870 : double fIntervalCount = fSub / m_rIncrement.Distance;
203 13870 : if (fIntervalCount > std::numeric_limits<sal_Int32>::max())
204 : // Interval count too high! Bail out.
205 0 : return 0;
206 :
207 13870 : sal_Int32 nIntervalCount = static_cast<sal_Int32>(fIntervalCount);
208 :
209 13870 : nIntervalCount+=3;
210 13870 : for(sal_Int32 nN=0; nN<nDepth-1; nN++)
211 : {
212 0 : if( m_rIncrement.SubIncrements[nN].IntervalCount>1 )
213 0 : nIntervalCount *= m_rIncrement.SubIncrements[nN].IntervalCount;
214 : }
215 :
216 13870 : sal_Int32 nTickCount = nIntervalCount;
217 13870 : if(nDepth>0 && m_rIncrement.SubIncrements[nDepth-1].IntervalCount>1)
218 6920 : nTickCount = nIntervalCount * (m_rIncrement.SubIncrements[nDepth-1].IntervalCount-1);
219 :
220 13870 : return nTickCount;
221 : }
222 :
223 54463 : double* EquidistantTickFactory::getMajorTick( sal_Int32 nTick ) const
224 : {
225 54463 : m_pfCurrentValues[0] = m_fOuterMajorTickBorderMin + nTick*m_rIncrement.Distance;
226 :
227 54463 : if(m_pfCurrentValues[0]>m_fOuterMajorTickBorderMax)
228 : {
229 11980 : if( !approxEqual(m_pfCurrentValues[0],m_fOuterMajorTickBorderMax) )
230 11980 : return NULL;
231 : }
232 42483 : if(m_pfCurrentValues[0]<m_fOuterMajorTickBorderMin)
233 : {
234 0 : if( !approxEqual(m_pfCurrentValues[0],m_fOuterMajorTickBorderMin) )
235 0 : return NULL;
236 : }
237 :
238 : //return always the value after scaling
239 42483 : if(!m_rIncrement.PostEquidistant && m_xInverseScaling.is() )
240 0 : m_pfCurrentValues[0] = m_rScale.Scaling->doScaling( m_pfCurrentValues[0] );
241 :
242 42483 : return &m_pfCurrentValues[0];
243 : }
244 :
245 41429 : double* EquidistantTickFactory::getMinorTick( sal_Int32 nTick, sal_Int32 nDepth
246 : , double fStartParentTick, double fNextParentTick ) const
247 : {
248 : //check validity of arguments
249 : {
250 : //OSL_ENSURE( fStartParentTick < fNextParentTick, "fStartParentTick >= fNextParentTick");
251 41429 : if(fStartParentTick >= fNextParentTick)
252 0 : return NULL;
253 41429 : if(nDepth>static_cast<sal_Int32>(m_rIncrement.SubIncrements.size()) || nDepth<=0)
254 0 : return NULL;
255 :
256 : //subticks are only calculated if they are laying between parent ticks:
257 41429 : if(nTick<=0)
258 0 : return NULL;
259 41429 : if(nTick>=m_rIncrement.SubIncrements[nDepth-1].IntervalCount)
260 0 : return NULL;
261 : }
262 :
263 41429 : bool bPostEquidistant = m_rIncrement.SubIncrements[nDepth-1].PostEquidistant;
264 :
265 41429 : double fAdaptedStartParent = fStartParentTick;
266 41429 : double fAdaptedNextParent = fNextParentTick;
267 :
268 41429 : if( !bPostEquidistant && m_xInverseScaling.is() )
269 : {
270 20219 : fAdaptedStartParent = m_xInverseScaling->doScaling(fStartParentTick);
271 20219 : fAdaptedNextParent = m_xInverseScaling->doScaling(fNextParentTick);
272 : }
273 :
274 41429 : double fDistance = (fAdaptedNextParent - fAdaptedStartParent)/m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
275 :
276 41429 : m_pfCurrentValues[nDepth] = fAdaptedStartParent + nTick*fDistance;
277 :
278 : //return always the value after scaling
279 41429 : if(!bPostEquidistant && m_xInverseScaling.is() )
280 20219 : m_pfCurrentValues[nDepth] = m_rScale.Scaling->doScaling( m_pfCurrentValues[nDepth] );
281 :
282 41429 : if( !isWithinOuterBorder( m_pfCurrentValues[nDepth] ) )
283 0 : return NULL;
284 :
285 41429 : return &m_pfCurrentValues[nDepth];
286 : }
287 :
288 41429 : bool EquidistantTickFactory::isWithinOuterBorder( double fScaledValue ) const
289 : {
290 41429 : if(fScaledValue>m_fOuterMajorTickBorderMax_Scaled)
291 0 : return false;
292 41429 : if(fScaledValue<m_fOuterMajorTickBorderMin_Scaled)
293 0 : return false;
294 :
295 41429 : return true;
296 : }
297 :
298 47486 : bool EquidistantTickFactory::isVisible( double fScaledValue ) const
299 : {
300 47486 : if(fScaledValue>m_fScaledVisibleMax)
301 : {
302 1893 : if( !approxEqual(fScaledValue,m_fScaledVisibleMax) )
303 1893 : return false;
304 : }
305 45593 : if(fScaledValue<m_fScaledVisibleMin)
306 : {
307 1866 : if( !approxEqual(fScaledValue,m_fScaledVisibleMin) )
308 1866 : return false;
309 : }
310 43727 : return true;
311 : }
312 :
313 6935 : void EquidistantTickFactory::getAllTicks( TickInfoArraysType& rAllTickInfos ) const
314 : {
315 6935 : uno::Sequence< uno::Sequence< double > > aAllTicks;
316 :
317 : //create point sequences for each tick depth
318 6935 : sal_Int32 nDepthCount = this->getTickDepth();
319 6935 : sal_Int32 nMaxMajorTickCount = this->getMaxTickCount( 0 );
320 :
321 6935 : if (nDepthCount <= 0 || nMaxMajorTickCount <= 0)
322 0 : return;
323 :
324 6935 : aAllTicks.realloc(nDepthCount);
325 6935 : aAllTicks[0].realloc(nMaxMajorTickCount);
326 :
327 6935 : sal_Int32 nRealMajorTickCount = 0;
328 61398 : for( sal_Int32 nMajorTick=0; nMajorTick<nMaxMajorTickCount; nMajorTick++ )
329 : {
330 54463 : double* pValue = this->getMajorTick( nMajorTick );
331 54463 : if(!pValue)
332 11980 : continue;
333 42483 : aAllTicks[0][nRealMajorTickCount] = *pValue;
334 42483 : nRealMajorTickCount++;
335 : }
336 6935 : if(!nRealMajorTickCount)
337 0 : return;
338 6935 : aAllTicks[0].realloc(nRealMajorTickCount);
339 :
340 6935 : if(nDepthCount>0)
341 6935 : this->addSubTicks( 1, aAllTicks );
342 :
343 : //so far we have added all ticks between the outer major tick marks
344 : //this was necessary to create sub ticks correctly
345 : //now we reduce all ticks to the visible ones that lie between the real borders
346 6935 : sal_Int32 nDepth = 0;
347 6935 : sal_Int32 nTick = 0;
348 20805 : for( nDepth = 0; nDepth < nDepthCount; nDepth++)
349 : {
350 13870 : sal_Int32 nInvisibleAtLowerBorder = 0;
351 13870 : sal_Int32 nInvisibleAtUpperBorder = 0;
352 : //we need only to check all ticks within the first major interval at each border
353 13870 : sal_Int32 nCheckCount = 1;
354 20805 : for(sal_Int32 nN=0; nN<nDepth; nN++)
355 : {
356 6935 : if( m_rIncrement.SubIncrements[nN].IntervalCount>1 )
357 6920 : nCheckCount *= m_rIncrement.SubIncrements[nN].IntervalCount;
358 : }
359 13870 : uno::Sequence< double >& rTicks = aAllTicks[nDepth];
360 13870 : sal_Int32 nCount = rTicks.getLength();
361 : //check lower border
362 37613 : for( nTick=0; nTick<nCheckCount && nTick<nCount; nTick++)
363 : {
364 23743 : if( !isVisible( rTicks[nTick] ) )
365 1866 : nInvisibleAtLowerBorder++;
366 : }
367 : //check upper border
368 37613 : for( nTick=nCount-1; nTick>nCount-1-nCheckCount && nTick>=0; nTick--)
369 : {
370 23743 : if( !isVisible( rTicks[nTick] ) )
371 1893 : nInvisibleAtUpperBorder++;
372 : }
373 : //resize sequence
374 13870 : if( !nInvisibleAtLowerBorder && !nInvisibleAtUpperBorder)
375 11977 : continue;
376 1893 : if( !nInvisibleAtLowerBorder )
377 27 : rTicks.realloc(nCount-nInvisibleAtUpperBorder);
378 : else
379 : {
380 1866 : sal_Int32 nNewCount = nCount-nInvisibleAtUpperBorder-nInvisibleAtLowerBorder;
381 1866 : if(nNewCount<0)
382 0 : nNewCount=0;
383 :
384 1866 : uno::Sequence< double > aOldTicks(rTicks);
385 1866 : rTicks.realloc(nNewCount);
386 9188 : for(nTick = 0; nTick<nNewCount; nTick++)
387 9188 : rTicks[nTick] = aOldTicks[nInvisibleAtLowerBorder+nTick];
388 : }
389 : }
390 :
391 : //fill return value
392 6935 : rAllTickInfos.resize(aAllTicks.getLength());
393 20805 : for( nDepth=0 ;nDepth<aAllTicks.getLength(); nDepth++ )
394 : {
395 13870 : sal_Int32 nCount = aAllTicks[nDepth].getLength();
396 :
397 13870 : TickInfoArrayType& rTickInfoVector = rAllTickInfos[nDepth];
398 13870 : rTickInfoVector.clear();
399 13870 : rTickInfoVector.reserve( nCount );
400 94023 : for(sal_Int32 nN = 0; nN<nCount; nN++)
401 : {
402 80153 : TickInfo aTickInfo(m_xInverseScaling);
403 80153 : aTickInfo.fScaledTickValue = aAllTicks[nDepth][nN];
404 80153 : rTickInfoVector.push_back(aTickInfo);
405 80153 : }
406 6935 : }
407 : }
408 :
409 1866 : void EquidistantTickFactory::getAllTicksShifted( TickInfoArraysType& rAllTickInfos ) const
410 : {
411 1866 : ExplicitIncrementData aShiftedIncrement( m_rIncrement );
412 1866 : aShiftedIncrement.BaseValue = m_rIncrement.BaseValue-m_rIncrement.Distance/2.0;
413 1866 : EquidistantTickFactory( m_rScale, aShiftedIncrement ).getAllTicks(rAllTickInfos);
414 1866 : }
415 :
416 6935 : EquidistantTickIter::EquidistantTickIter( const uno::Sequence< uno::Sequence< double > >& rTicks
417 : , const ExplicitIncrementData& rIncrement
418 : , sal_Int32 nMinDepth, sal_Int32 nMaxDepth )
419 : : m_pSimpleTicks(&rTicks)
420 : , m_pInfoTicks(0)
421 : , m_rIncrement(rIncrement)
422 : , m_nMaxDepth(0)
423 : , m_nTickCount(0), m_pnPositions(NULL)
424 : , m_pnPreParentCount(NULL), m_pbIntervalFinished(NULL)
425 6935 : , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 )
426 : {
427 6935 : initIter( nMinDepth, nMaxDepth );
428 6935 : }
429 :
430 2699 : EquidistantTickIter::EquidistantTickIter( TickInfoArraysType& rTicks
431 : , const ExplicitIncrementData& rIncrement
432 : , sal_Int32 nMinDepth, sal_Int32 nMaxDepth )
433 : : m_pSimpleTicks(NULL)
434 : , m_pInfoTicks(&rTicks)
435 : , m_rIncrement(rIncrement)
436 : , m_nMaxDepth(0)
437 : , m_nTickCount(0), m_pnPositions(NULL)
438 : , m_pnPreParentCount(NULL), m_pbIntervalFinished(NULL)
439 2699 : , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 )
440 : {
441 2699 : initIter( nMinDepth, nMaxDepth );
442 2699 : }
443 :
444 9634 : void EquidistantTickIter::initIter( sal_Int32 /*nMinDepth*/, sal_Int32 nMaxDepth )
445 : {
446 9634 : m_nMaxDepth = nMaxDepth;
447 9634 : if(nMaxDepth<0 || m_nMaxDepth>getMaxDepth())
448 2681 : m_nMaxDepth=getMaxDepth();
449 :
450 9634 : sal_Int32 nDepth = 0;
451 21949 : for( nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
452 12315 : m_nTickCount += getTickCount(nDepth);
453 :
454 9634 : if(!m_nTickCount)
455 9634 : return;
456 :
457 9634 : m_pnPositions = new sal_Int32[m_nMaxDepth+1];
458 :
459 9634 : m_pnPreParentCount = new sal_Int32[m_nMaxDepth+1];
460 9634 : m_pbIntervalFinished = new bool[m_nMaxDepth+1];
461 9634 : m_pnPreParentCount[0] = 0;
462 9634 : m_pbIntervalFinished[0] = false;
463 9634 : double fParentValue = getTickValue(0,0);
464 12315 : for( nDepth = 1; nDepth<=m_nMaxDepth ;nDepth++ )
465 : {
466 2681 : m_pbIntervalFinished[nDepth] = false;
467 :
468 2681 : sal_Int32 nPreParentCount = 0;
469 2681 : sal_Int32 nCount = getTickCount(nDepth);
470 3568 : for(sal_Int32 nN = 0; nN<nCount; nN++)
471 : {
472 3563 : if(getTickValue(nDepth,nN) < fParentValue)
473 887 : nPreParentCount++;
474 : else
475 2676 : break;
476 : }
477 2681 : m_pnPreParentCount[nDepth] = nPreParentCount;
478 2681 : if(nCount)
479 : {
480 2676 : double fNextParentValue = getTickValue(nDepth,0);
481 2676 : if( fNextParentValue < fParentValue )
482 887 : fParentValue = fNextParentValue;
483 : }
484 : }
485 : }
486 :
487 19268 : EquidistantTickIter::~EquidistantTickIter()
488 : {
489 9634 : delete[] m_pnPositions;
490 9634 : delete[] m_pnPreParentCount;
491 9634 : delete[] m_pbIntervalFinished;
492 9634 : }
493 :
494 9642 : sal_Int32 EquidistantTickIter::getStartDepth() const
495 : {
496 : //find the depth of the first visible tickmark:
497 : //it is the depth of the smallest value
498 9642 : sal_Int32 nReturnDepth=0;
499 9642 : double fMinValue = DBL_MAX;
500 21965 : for(sal_Int32 nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
501 : {
502 12323 : sal_Int32 nCount = getTickCount(nDepth);
503 12323 : if( !nCount )
504 5 : continue;
505 12318 : double fThisValue = getTickValue(nDepth,0);
506 12318 : if(fThisValue<fMinValue)
507 : {
508 10529 : nReturnDepth = nDepth;
509 10529 : fMinValue = fThisValue;
510 : }
511 : }
512 9642 : return nReturnDepth;
513 : }
514 :
515 6935 : double* EquidistantTickIter::firstValue()
516 : {
517 6935 : if( gotoFirst() )
518 : {
519 6935 : m_fCurrentValue = getTickValue(m_nCurrentDepth, m_pnPositions[m_nCurrentDepth]);
520 6935 : return &m_fCurrentValue;
521 : }
522 0 : return NULL;
523 : }
524 :
525 2707 : TickInfo* EquidistantTickIter::firstInfo()
526 : {
527 2707 : if( m_pInfoTicks && gotoFirst() )
528 2707 : return &(*m_pInfoTicks)[m_nCurrentDepth][m_pnPositions[m_nCurrentDepth]];
529 0 : return NULL;
530 : }
531 :
532 14107 : sal_Int32 EquidistantTickIter::getIntervalCount( sal_Int32 nDepth )
533 : {
534 14107 : if(nDepth>static_cast<sal_Int32>(m_rIncrement.SubIncrements.size()) || nDepth<0)
535 0 : return 0;
536 :
537 14107 : if(!nDepth)
538 0 : return m_nTickCount;
539 :
540 14107 : return m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
541 : }
542 :
543 49785 : bool EquidistantTickIter::isAtLastPartTick()
544 : {
545 49785 : if(!m_nCurrentDepth)
546 35678 : return false;
547 14107 : sal_Int32 nIntervalCount = getIntervalCount( m_nCurrentDepth );
548 14107 : if(!nIntervalCount || nIntervalCount == 1)
549 0 : return true;
550 14107 : if( m_pbIntervalFinished[m_nCurrentDepth] )
551 0 : return false;
552 14107 : sal_Int32 nPos = m_pnPositions[m_nCurrentDepth]+1;
553 14107 : if(m_pnPreParentCount[m_nCurrentDepth])
554 3606 : nPos += nIntervalCount-1 - m_pnPreParentCount[m_nCurrentDepth];
555 14107 : bool bRet = nPos && nPos % (nIntervalCount-1) == 0;
556 14107 : if(!nPos && !m_pnPreParentCount[m_nCurrentDepth]
557 0 : && m_pnPositions[m_nCurrentDepth-1]==-1 )
558 0 : bRet = true;
559 14107 : return bRet;
560 : }
561 :
562 9642 : bool EquidistantTickIter::gotoFirst()
563 : {
564 9642 : if( m_nMaxDepth<0 )
565 0 : return false;
566 9642 : if( !m_nTickCount )
567 0 : return false;
568 :
569 21965 : for(sal_Int32 nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
570 12323 : m_pnPositions[nDepth] = -1;
571 :
572 9642 : m_nCurrentPos = 0;
573 9642 : m_nCurrentDepth = getStartDepth();
574 9642 : m_pnPositions[m_nCurrentDepth] = 0;
575 9642 : return true;
576 : }
577 :
578 72603 : bool EquidistantTickIter::gotoNext()
579 : {
580 72603 : if( m_nCurrentPos < 0 )
581 0 : return false;
582 72603 : m_nCurrentPos++;
583 :
584 72603 : if( m_nCurrentPos >= m_nTickCount )
585 9637 : return false;
586 :
587 62966 : if( m_nCurrentDepth==m_nMaxDepth && isAtLastPartTick() )
588 : {
589 13176 : do
590 : {
591 13176 : m_pbIntervalFinished[m_nCurrentDepth] = true;
592 13176 : m_nCurrentDepth--;
593 : }
594 13176 : while( m_nCurrentDepth && isAtLastPartTick() );
595 : }
596 49790 : else if( m_nCurrentDepth<m_nMaxDepth )
597 : {
598 13181 : do
599 : {
600 13181 : m_nCurrentDepth++;
601 : }
602 13181 : while( m_nCurrentDepth<m_nMaxDepth );
603 : }
604 62966 : m_pbIntervalFinished[m_nCurrentDepth] = false;
605 62966 : m_pnPositions[m_nCurrentDepth] = m_pnPositions[m_nCurrentDepth]+1;
606 62966 : return true;
607 : }
608 :
609 42483 : double* EquidistantTickIter::nextValue()
610 : {
611 42483 : if( gotoNext() )
612 : {
613 35548 : m_fCurrentValue = getTickValue(m_nCurrentDepth, m_pnPositions[m_nCurrentDepth]);
614 35548 : return &m_fCurrentValue;
615 : }
616 6935 : return NULL;
617 : }
618 :
619 30120 : TickInfo* EquidistantTickIter::nextInfo()
620 : {
621 57538 : if( m_pInfoTicks && gotoNext() &&
622 : static_cast< sal_Int32 >(
623 27418 : (*m_pInfoTicks)[m_nCurrentDepth].size()) > m_pnPositions[m_nCurrentDepth] )
624 : {
625 27413 : return &(*m_pInfoTicks)[m_nCurrentDepth][m_pnPositions[m_nCurrentDepth]];
626 : }
627 2707 : return NULL;
628 : }
629 :
630 : } //namespace chart
631 :
632 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|