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