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