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