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