Branch data 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 : 12846 : 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 [ - + ]: 12846 : if(rIncrement.Distance<=0.0)
41 : 0 : return fMin;
42 : :
43 : : double fRet = rIncrement.BaseValue +
44 : 12846 : floor( approxSub( fMin, rIncrement.BaseValue )
45 : 12846 : / rIncrement.Distance)
46 : 25692 : *rIncrement.Distance;
47 : :
48 [ - + ]: 12846 : if( fRet > fMin )
49 : : {
50 [ # # ]: 0 : if( !approxEqual(fRet, fMin) )
51 : 0 : fRet -= rIncrement.Distance;
52 : : }
53 : 12846 : return fRet;
54 : : }
55 : : //static
56 : 12840 : 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 [ - + ]: 12840 : if(rIncrement.Distance<=0.0)
60 : 0 : return fMax;
61 : :
62 : : double fRet = rIncrement.BaseValue +
63 : 12840 : floor( approxSub( fMax, rIncrement.BaseValue )
64 : 12840 : / rIncrement.Distance)
65 : 25680 : *rIncrement.Distance;
66 : :
67 [ + + ]: 12840 : if( fRet < fMax )
68 : : {
69 [ + - ]: 6860 : if( !approxEqual(fRet, fMax) )
70 : 6860 : fRet += rIncrement.Distance;
71 : : }
72 : 12840 : return fRet;
73 : : }
74 : :
75 : 8273 : EquidistantTickFactory::EquidistantTickFactory(
76 : : const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement )
77 : : : m_rScale( rScale )
78 : : , m_rIncrement( rIncrement )
79 : : , m_xInverseScaling(NULL)
80 [ + - ][ + - ]: 8273 : , m_pfCurrentValues(NULL)
81 : : {
82 : : //@todo: make sure that the scale is valid for the scaling
83 : :
84 [ + - ]: 8273 : m_pfCurrentValues = new double[getTickDepth()];
85 : :
86 [ + + ]: 8273 : if( m_rScale.Scaling.is() )
87 : : {
88 [ + - ][ + - ]: 2562 : m_xInverseScaling = m_rScale.Scaling->getInverseScaling();
[ + - ]
89 : : OSL_ENSURE( m_xInverseScaling.is(), "each Scaling needs to return a inverse Scaling" );
90 : : }
91 : :
92 : 8273 : double fMin = m_fScaledVisibleMin = m_rScale.Minimum;
93 [ + + ]: 8273 : if( m_xInverseScaling.is() )
94 : : {
95 [ + - ][ + - ]: 2562 : m_fScaledVisibleMin = m_rScale.Scaling->doScaling(m_fScaledVisibleMin);
96 [ + - ]: 2562 : if(m_rIncrement.PostEquidistant )
97 : 2562 : fMin = m_fScaledVisibleMin;
98 : : }
99 : :
100 : 8273 : double fMax = m_fScaledVisibleMax = m_rScale.Maximum;
101 [ + + ]: 8273 : if( m_xInverseScaling.is() )
102 : : {
103 [ + - ][ + - ]: 2562 : m_fScaledVisibleMax = m_rScale.Scaling->doScaling(m_fScaledVisibleMax);
104 [ + - ]: 2562 : if(m_rIncrement.PostEquidistant )
105 : 2562 : fMax = m_fScaledVisibleMax;
106 : : }
107 : :
108 : : //--
109 : 8273 : m_fOuterMajorTickBorderMin = EquidistantTickFactory::getMinimumAtIncrement( fMin, m_rIncrement );
110 : 8273 : m_fOuterMajorTickBorderMax = EquidistantTickFactory::getMaximumAtIncrement( fMax, m_rIncrement );
111 : : //--
112 : :
113 : 8273 : m_fOuterMajorTickBorderMin_Scaled = m_fOuterMajorTickBorderMin;
114 : 8273 : m_fOuterMajorTickBorderMax_Scaled = m_fOuterMajorTickBorderMax;
115 [ # # ][ - + ]: 8273 : 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 : 8273 : }
134 : :
135 : 8273 : EquidistantTickFactory::~EquidistantTickFactory()
136 : : {
137 [ + - ]: 8273 : delete[] m_pfCurrentValues;
138 : 8273 : }
139 : :
140 : 27668 : sal_Int32 EquidistantTickFactory::getTickDepth() const
141 : : {
142 : 27668 : return static_cast<sal_Int32>(m_rIncrement.SubIncrements.size()) + 1;
143 : : }
144 : :
145 : 6465 : void EquidistantTickFactory::addSubTicks( sal_Int32 nDepth, uno::Sequence< uno::Sequence< double > >& rParentTicks ) const
146 : : {
147 [ + - ]: 6465 : EquidistantTickIter aIter( rParentTicks, m_rIncrement, 0, nDepth-1 );
148 [ + - ]: 6465 : double* pfNextParentTick = aIter.firstValue();
149 [ - + ]: 6465 : if(!pfNextParentTick)
150 : : return;
151 : 6465 : double fLastParentTick = *pfNextParentTick;
152 [ + - ]: 6465 : pfNextParentTick = aIter.nextValue();
153 [ - + ]: 6465 : if(!pfNextParentTick)
154 : : return;
155 : :
156 [ + - ]: 6465 : sal_Int32 nMaxSubTickCount = this->getMaxTickCount( nDepth );
157 [ - + ]: 6465 : if(!nMaxSubTickCount)
158 : : return;
159 : :
160 [ + - ]: 6465 : uno::Sequence< double > aSubTicks(nMaxSubTickCount);
161 : 6465 : sal_Int32 nRealSubTickCount = 0;
162 [ + - ]: 6465 : sal_Int32 nIntervalCount = m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
163 : :
164 : 6465 : double* pValue = NULL;
165 [ + - ][ + + ]: 38596 : for(; pfNextParentTick; fLastParentTick=*pfNextParentTick, pfNextParentTick = aIter.nextValue())
166 : : {
167 [ + + ]: 70071 : for( sal_Int32 nPartTick = 1; nPartTick<nIntervalCount; nPartTick++ )
168 : : {
169 : : pValue = this->getMinorTick( nPartTick, nDepth
170 [ + - ]: 37940 : , fLastParentTick, *pfNextParentTick );
171 [ - + ]: 37940 : if(!pValue)
172 : 0 : continue;
173 : :
174 [ + - ]: 37940 : aSubTicks[nRealSubTickCount] = *pValue;
175 : 37940 : nRealSubTickCount++;
176 : : }
177 : : }
178 : :
179 [ + - ]: 6465 : aSubTicks.realloc(nRealSubTickCount);
180 [ + - ][ + - ]: 6465 : rParentTicks[nDepth] = aSubTicks;
181 [ - + ]: 6465 : if(static_cast<sal_Int32>(m_rIncrement.SubIncrements.size())>nDepth)
182 [ # # ][ + - ]: 6465 : addSubTicks( nDepth+1, rParentTicks );
[ + - ]
183 : : }
184 : :
185 : :
186 : 12930 : 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 [ - + ]: 12930 : if( nDepth >= getTickDepth() )
193 : 0 : return 0;
194 [ - + ]: 12930 : if( m_fOuterMajorTickBorderMax < m_fOuterMajorTickBorderMin )
195 : 0 : return 0;
196 [ - + ]: 12930 : if( m_rIncrement.Distance<=0.0)
197 : 0 : return 0;
198 : :
199 : : double fSub;
200 [ + - ]: 12930 : if(m_rIncrement.PostEquidistant )
201 : 12930 : fSub = approxSub( m_fScaledVisibleMax, m_fScaledVisibleMin );
202 : : else
203 : 0 : fSub = approxSub( m_rScale.Maximum, m_rScale.Minimum );
204 : :
205 [ - + ]: 12930 : if (!isFinite(fSub))
206 : 0 : return 0;
207 : :
208 : 12930 : double fIntervalCount = fSub / m_rIncrement.Distance;
209 [ - + ]: 12930 : if (fIntervalCount > std::numeric_limits<sal_Int32>::max())
210 : : // Interval count too high! Bail out.
211 : 0 : return 0;
212 : :
213 : 12930 : sal_Int32 nIntervalCount = static_cast<sal_Int32>(fIntervalCount);
214 : :
215 : 12930 : nIntervalCount+=3;
216 [ - + ]: 12930 : 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 : 12930 : sal_Int32 nTickCount = nIntervalCount;
223 [ + + ][ + + ]: 12930 : if(nDepth>0 && m_rIncrement.SubIncrements[nDepth-1].IntervalCount>1)
[ + + ]
224 : 6441 : nTickCount = nIntervalCount * (m_rIncrement.SubIncrements[nDepth-1].IntervalCount-1);
225 : :
226 : 12930 : return nTickCount;
227 : : }
228 : :
229 : 49196 : double* EquidistantTickFactory::getMajorTick( sal_Int32 nTick ) const
230 : : {
231 : 49196 : m_pfCurrentValues[0] = m_fOuterMajorTickBorderMin + nTick*m_rIncrement.Distance;
232 : :
233 [ + + ]: 49196 : if(m_pfCurrentValues[0]>m_fOuterMajorTickBorderMax)
234 : : {
235 [ + - ]: 10600 : if( !approxEqual(m_pfCurrentValues[0],m_fOuterMajorTickBorderMax) )
236 : 10600 : return NULL;
237 : : }
238 [ - + ]: 38596 : 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 [ - + ][ # # ]: 38596 : if(!m_rIncrement.PostEquidistant && m_xInverseScaling.is() )
[ - + ]
246 : 0 : m_pfCurrentValues[0] = m_rScale.Scaling->doScaling( m_pfCurrentValues[0] );
247 : :
248 : 49196 : return &m_pfCurrentValues[0];
249 : : }
250 : :
251 : 37940 : 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 [ - + ]: 37940 : if(fStartParentTick >= fNextParentTick)
258 : 0 : return NULL;
259 [ + - ][ - + ]: 37940 : 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 [ - + ]: 37940 : if(nTick<=0)
264 : 0 : return NULL;
265 [ - + ]: 37940 : if(nTick>=m_rIncrement.SubIncrements[nDepth-1].IntervalCount)
266 : 0 : return NULL;
267 : : }
268 : :
269 : 37940 : bool bPostEquidistant = m_rIncrement.SubIncrements[nDepth-1].PostEquidistant;
270 : :
271 : 37940 : double fAdaptedStartParent = fStartParentTick;
272 : 37940 : double fAdaptedNextParent = fNextParentTick;
273 : :
274 [ + + ][ + + ]: 37940 : if( !bPostEquidistant && m_xInverseScaling.is() )
[ + - ]
275 : : {
276 : 16608 : fAdaptedStartParent = m_xInverseScaling->doScaling(fStartParentTick);
277 : 16608 : fAdaptedNextParent = m_xInverseScaling->doScaling(fNextParentTick);
278 : : }
279 : :
280 : 37940 : double fDistance = (fAdaptedNextParent - fAdaptedStartParent)/m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
281 : :
282 : 37940 : m_pfCurrentValues[nDepth] = fAdaptedStartParent + nTick*fDistance;
283 : :
284 : : //return always the value after scaling
285 [ + + ][ + + ]: 37940 : if(!bPostEquidistant && m_xInverseScaling.is() )
[ + - ]
286 : 16608 : m_pfCurrentValues[nDepth] = m_rScale.Scaling->doScaling( m_pfCurrentValues[nDepth] );
287 : :
288 [ - + ]: 37940 : if( !isWithinOuterBorder( m_pfCurrentValues[nDepth] ) )
289 : 0 : return NULL;
290 : :
291 : 37940 : return &m_pfCurrentValues[nDepth];
292 : : }
293 : :
294 : 37940 : bool EquidistantTickFactory::isWithinOuterBorder( double fScaledValue ) const
295 : : {
296 [ - + ]: 37940 : if(fScaledValue>m_fOuterMajorTickBorderMax_Scaled)
297 : 0 : return false;
298 [ - + ]: 37940 : if(fScaledValue<m_fOuterMajorTickBorderMin_Scaled)
299 : 0 : return false;
300 : :
301 : 37940 : return true;
302 : : }
303 : :
304 : 45116 : bool EquidistantTickFactory::isVisible( double fScaledValue ) const
305 : : {
306 [ + + ]: 45116 : if(fScaledValue>m_fScaledVisibleMax)
307 : : {
308 [ + + ]: 2345 : if( !approxEqual(fScaledValue,m_fScaledVisibleMax) )
309 : 1853 : return false;
310 : : }
311 [ + + ]: 43263 : if(fScaledValue<m_fScaledVisibleMin)
312 : : {
313 [ + - ]: 1808 : if( !approxEqual(fScaledValue,m_fScaledVisibleMin) )
314 : 1808 : return false;
315 : : }
316 : 45116 : return true;
317 : : }
318 : :
319 : 6465 : void EquidistantTickFactory::getAllTicks( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const
320 : : {
321 [ + - ]: 6465 : uno::Sequence< uno::Sequence< double > > aAllTicks;
322 : :
323 : : //create point sequences for each tick depth
324 : 6465 : sal_Int32 nDepthCount = this->getTickDepth();
325 [ + - ]: 6465 : sal_Int32 nMaxMajorTickCount = this->getMaxTickCount( 0 );
326 : :
327 [ + - ][ - + ]: 6465 : if (nDepthCount <= 0 || nMaxMajorTickCount <= 0)
328 : : return;
329 : :
330 [ + - ]: 6465 : aAllTicks.realloc(nDepthCount);
331 [ + - ][ + - ]: 6465 : aAllTicks[0].realloc(nMaxMajorTickCount);
332 : :
333 : 6465 : sal_Int32 nRealMajorTickCount = 0;
334 : 6465 : double* pValue = NULL;
335 [ + + ]: 55661 : for( sal_Int32 nMajorTick=0; nMajorTick<nMaxMajorTickCount; nMajorTick++ )
336 : : {
337 [ + - ]: 49196 : pValue = this->getMajorTick( nMajorTick );
338 [ + + ]: 49196 : if(!pValue)
339 : 10600 : continue;
340 [ + - ][ + - ]: 38596 : aAllTicks[0][nRealMajorTickCount] = *pValue;
341 : 38596 : nRealMajorTickCount++;
342 : : }
343 [ - + ]: 6465 : if(!nRealMajorTickCount)
344 : : return;
345 [ + - ][ + - ]: 6465 : aAllTicks[0].realloc(nRealMajorTickCount);
346 : :
347 [ + - ]: 6465 : if(nDepthCount>0)
348 [ + - ]: 6465 : 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 : 6465 : sal_Int32 nDepth = 0;
354 : 6465 : sal_Int32 nTick = 0;
355 [ + + ]: 19395 : for( nDepth = 0; nDepth < nDepthCount; nDepth++)
356 : : {
357 : 12930 : sal_Int32 nInvisibleAtLowerBorder = 0;
358 : 12930 : sal_Int32 nInvisibleAtUpperBorder = 0;
359 : : //we need only to check all ticks within the first major interval at each border
360 : 12930 : sal_Int32 nCheckCount = 1;
361 [ + + ]: 19395 : for(sal_Int32 nN=0; nN<nDepth; nN++)
362 : : {
363 [ + - ][ + + ]: 6465 : if( m_rIncrement.SubIncrements[nN].IntervalCount>1 )
364 [ + - ]: 6441 : nCheckCount *= m_rIncrement.SubIncrements[nN].IntervalCount;
365 : : }
366 [ + - ]: 12930 : uno::Sequence< double >& rTicks = aAllTicks[nDepth];
367 : 12930 : sal_Int32 nCount = rTicks.getLength();
368 : : //check lower border
369 [ + + ][ + + ]: 35488 : for( nTick=0; nTick<nCheckCount && nTick<nCount; nTick++)
[ + + ]
370 : : {
371 [ + - ][ + + ]: 22558 : if( !isVisible( rTicks[nTick] ) )
372 : 1808 : nInvisibleAtLowerBorder++;
373 : : }
374 : : //check upper border
375 [ + + ][ + + ]: 35488 : for( nTick=nCount-1; nTick>nCount-1-nCheckCount && nTick>=0; nTick--)
[ + + ]
376 : : {
377 [ + - ][ + + ]: 22558 : if( !isVisible( rTicks[nTick] ) )
378 : 1853 : nInvisibleAtUpperBorder++;
379 : : }
380 : : //resize sequence
381 [ + + ][ + + ]: 12930 : if( !nInvisibleAtLowerBorder && !nInvisibleAtUpperBorder)
382 : 11077 : continue;
383 [ + + ]: 1853 : if( !nInvisibleAtLowerBorder )
384 [ + - ]: 45 : rTicks.realloc(nCount-nInvisibleAtUpperBorder);
385 : : else
386 : : {
387 : 1808 : sal_Int32 nNewCount = nCount-nInvisibleAtUpperBorder-nInvisibleAtLowerBorder;
388 [ - + ]: 1808 : if(nNewCount<0)
389 : 0 : nNewCount=0;
390 : :
391 [ + - ]: 1808 : uno::Sequence< double > aOldTicks(rTicks);
392 [ + - ]: 1808 : rTicks.realloc(nNewCount);
393 [ + + ]: 8988 : for(nTick = 0; nTick<nNewCount; nTick++)
394 [ + - ][ + - ]: 8988 : rTicks[nTick] = aOldTicks[nInvisibleAtLowerBorder+nTick];
[ + - ]
395 : : }
396 : : }
397 : :
398 : : //fill return value
399 [ + - ]: 6465 : rAllTickInfos.resize(aAllTicks.getLength());
400 [ + + ]: 19395 : for( nDepth=0 ;nDepth<aAllTicks.getLength(); nDepth++ )
401 : : {
402 [ + - ]: 12930 : sal_Int32 nCount = aAllTicks[nDepth].getLength();
403 : :
404 : 12930 : ::std::vector< TickInfo >& rTickInfoVector = rAllTickInfos[nDepth];
405 : 12930 : rTickInfoVector.clear();
406 [ + - ]: 12930 : rTickInfoVector.reserve( nCount );
407 [ + + ]: 85805 : for(sal_Int32 nN = 0; nN<nCount; nN++)
408 : : {
409 [ + - ]: 72875 : TickInfo aTickInfo(m_xInverseScaling);
410 [ + - ][ + - ]: 72875 : aTickInfo.fScaledTickValue = aAllTicks[nDepth][nN];
411 [ + - ]: 72875 : rTickInfoVector.push_back(aTickInfo);
412 [ + - ]: 72875 : }
413 [ + - ][ + - ]: 6465 : }
414 : : }
415 : :
416 : 1808 : void EquidistantTickFactory::getAllTicksShifted( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const
417 : : {
418 [ + - ]: 1808 : ExplicitIncrementData aShiftedIncrement( m_rIncrement );
419 : 1808 : aShiftedIncrement.BaseValue = m_rIncrement.BaseValue-m_rIncrement.Distance/2.0;
420 [ + - ][ + - ]: 1808 : EquidistantTickFactory( m_rScale, aShiftedIncrement ).getAllTicks(rAllTickInfos);
[ + - ]
421 : 1808 : }
422 : :
423 : : //-----------------------------------------------------------------------------
424 : : //-----------------------------------------------------------------------------
425 : : //-----------------------------------------------------------------------------
426 : :
427 : 6465 : 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_nMinDepth(0), m_nMaxDepth(0)
434 : : , m_nTickCount(0), m_pnPositions(NULL)
435 : : , m_pnPreParentCount(NULL), m_pbIntervalFinished(NULL)
436 : 6465 : , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 )
437 : : {
438 [ + - ]: 6465 : initIter( nMinDepth, nMaxDepth );
439 : 6465 : }
440 : :
441 : 2568 : 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_nMinDepth(0), m_nMaxDepth(0)
448 : : , m_nTickCount(0), m_pnPositions(NULL)
449 : : , m_pnPreParentCount(NULL), m_pbIntervalFinished(NULL)
450 : 2568 : , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 )
451 : : {
452 [ + - ]: 2568 : initIter( nMinDepth, nMaxDepth );
453 : 2568 : }
454 : :
455 : 9033 : void EquidistantTickIter::initIter( sal_Int32 /*nMinDepth*/, sal_Int32 nMaxDepth )
456 : : {
457 : 9033 : m_nMaxDepth = nMaxDepth;
458 [ + + ][ - + ]: 9033 : if(nMaxDepth<0 || m_nMaxDepth>getMaxDepth())
[ + + ]
459 : 2568 : m_nMaxDepth=getMaxDepth();
460 : :
461 : 9033 : sal_Int32 nDepth = 0;
462 [ + + ]: 20634 : for( nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
463 : 11601 : m_nTickCount += getTickCount(nDepth);
464 : :
465 [ - + ]: 9033 : if(!m_nTickCount)
466 : 9033 : return;
467 : :
468 : 9033 : m_pnPositions = new sal_Int32[m_nMaxDepth+1];
469 : :
470 : 9033 : m_pnPreParentCount = new sal_Int32[m_nMaxDepth+1];
471 : 9033 : m_pbIntervalFinished = new bool[m_nMaxDepth+1];
472 : 9033 : m_pnPreParentCount[0] = 0;
473 : 9033 : m_pbIntervalFinished[0] = false;
474 : 9033 : double fParentValue = getTickValue(0,0);
475 [ + + ]: 11601 : for( nDepth = 1; nDepth<=m_nMaxDepth ;nDepth++ )
476 : : {
477 : 2568 : m_pbIntervalFinished[nDepth] = false;
478 : :
479 : 2568 : sal_Int32 nPreParentCount = 0;
480 : 2568 : sal_Int32 nCount = getTickCount(nDepth);
481 [ + + ]: 3467 : for(sal_Int32 nN = 0; nN<nCount; nN++)
482 : : {
483 [ + + ]: 3459 : if(getTickValue(nDepth,nN) < fParentValue)
484 : 899 : nPreParentCount++;
485 : : else
486 : 2560 : break;
487 : : }
488 : 2568 : m_pnPreParentCount[nDepth] = nPreParentCount;
489 [ + + ]: 2568 : if(nCount)
490 : : {
491 : 2560 : double fNextParentValue = getTickValue(nDepth,0);
492 [ + + ]: 2560 : if( fNextParentValue < fParentValue )
493 : 899 : fParentValue = fNextParentValue;
494 : : }
495 : : }
496 : : }
497 : :
498 : 9033 : EquidistantTickIter::~EquidistantTickIter()
499 : : {
500 [ + - ]: 9033 : delete[] m_pnPositions;
501 [ + - ]: 9033 : delete[] m_pnPreParentCount;
502 [ + - ]: 9033 : delete[] m_pbIntervalFinished;
503 [ - + ]: 9033 : }
504 : :
505 : 9033 : 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 : 9033 : sal_Int32 nReturnDepth=0;
510 : 9033 : double fMinValue = DBL_MAX;
511 [ + + ]: 20634 : for(sal_Int32 nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
512 : : {
513 : 11601 : sal_Int32 nCount = getTickCount(nDepth);
514 [ + + ]: 11601 : if( !nCount )
515 : 8 : continue;
516 : 11593 : double fThisValue = getTickValue(nDepth,0);
517 [ + + ]: 11593 : if(fThisValue<fMinValue)
518 : : {
519 : 9932 : nReturnDepth = nDepth;
520 : 9932 : fMinValue = fThisValue;
521 : : }
522 : : }
523 : 9033 : return nReturnDepth;
524 : : }
525 : :
526 : 6465 : double* EquidistantTickIter::firstValue()
527 : : {
528 [ + - ]: 6465 : if( gotoFirst() )
529 : : {
530 : 6465 : m_fCurrentValue = getTickValue(m_nCurrentDepth, m_pnPositions[m_nCurrentDepth]);
531 : 6465 : return &m_fCurrentValue;
532 : : }
533 : 6465 : return NULL;
534 : : }
535 : :
536 : 2568 : TickInfo* EquidistantTickIter::firstInfo()
537 : : {
538 [ + - ][ + - ]: 2568 : if( m_pInfoTicks && gotoFirst() )
[ + - ]
539 : 2568 : return &(*m_pInfoTicks)[m_nCurrentDepth][m_pnPositions[m_nCurrentDepth]];
540 : 2568 : return NULL;
541 : : }
542 : :
543 : 12711 : sal_Int32 EquidistantTickIter::getIntervalCount( sal_Int32 nDepth )
544 : : {
545 [ + - ][ - + ]: 12711 : if(nDepth>static_cast<sal_Int32>(m_rIncrement.SubIncrements.size()) || nDepth<0)
[ - + ]
546 : 0 : return 0;
547 : :
548 [ - + ]: 12711 : if(!nDepth)
549 : 0 : return m_nTickCount;
550 : :
551 : 12711 : return m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
552 : : }
553 : :
554 : 44842 : bool EquidistantTickIter::isAtLastPartTick()
555 : : {
556 [ + + ]: 44842 : if(!m_nCurrentDepth)
557 : 32131 : return false;
558 : 12711 : sal_Int32 nIntervalCount = getIntervalCount( m_nCurrentDepth );
559 [ - + ][ + - ]: 12711 : if(!nIntervalCount || nIntervalCount == 1)
560 : 0 : return true;
561 [ - + ]: 12711 : if( m_pbIntervalFinished[m_nCurrentDepth] )
562 : 0 : return false;
563 : 12711 : sal_Int32 nPos = m_pnPositions[m_nCurrentDepth]+1;
564 [ + + ]: 12711 : if(m_pnPreParentCount[m_nCurrentDepth])
565 : 3585 : nPos += nIntervalCount-1 - m_pnPreParentCount[m_nCurrentDepth];
566 [ + - ][ + + ]: 12711 : bool bRet = nPos && nPos % (nIntervalCount-1) == 0;
567 [ - + ][ # # ]: 12711 : if(!nPos && !m_pnPreParentCount[m_nCurrentDepth]
[ # # ]
568 : 0 : && m_pnPositions[m_nCurrentDepth-1]==-1 )
569 : 0 : bRet = true;
570 : 44842 : return bRet;
571 : : }
572 : :
573 : 9033 : bool EquidistantTickIter::gotoFirst()
574 : : {
575 [ - + ]: 9033 : if( m_nMaxDepth<0 )
576 : 0 : return false;
577 [ - + ]: 9033 : if( !m_nTickCount )
578 : 0 : return false;
579 : :
580 [ + + ]: 20634 : for(sal_Int32 nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
581 : 11601 : m_pnPositions[nDepth] = -1;
582 : :
583 : 9033 : m_nCurrentPos = 0;
584 : 9033 : m_nCurrentDepth = getStartDepth();
585 : 9033 : m_pnPositions[m_nCurrentDepth] = 0;
586 : 9033 : return true;
587 : : }
588 : :
589 : 65942 : bool EquidistantTickIter::gotoNext()
590 : : {
591 [ - + ]: 65942 : if( m_nCurrentPos < 0 )
592 : 0 : return false;
593 : 65942 : m_nCurrentPos++;
594 : :
595 [ + + ]: 65942 : if( m_nCurrentPos >= m_nTickCount )
596 : 9025 : return false;
597 : :
598 [ + + ][ + + ]: 56917 : if( m_nCurrentDepth==m_nMaxDepth && isAtLastPartTick() )
[ + + ]
599 : : {
600 [ - + # # ]: 12067 : do
[ - + ]
601 : : {
602 : 12067 : m_pbIntervalFinished[m_nCurrentDepth] = true;
603 : 12067 : m_nCurrentDepth--;
604 : : }
605 : 0 : while( m_nCurrentDepth && isAtLastPartTick() );
606 : : }
607 [ + + ]: 44850 : else if( m_nCurrentDepth<m_nMaxDepth )
608 : : {
609 [ - + ]: 12075 : do
610 : : {
611 : 12075 : m_nCurrentDepth++;
612 : : }
613 : : while( m_nCurrentDepth<m_nMaxDepth );
614 : : }
615 : 56917 : m_pbIntervalFinished[m_nCurrentDepth] = false;
616 : 56917 : m_pnPositions[m_nCurrentDepth] = m_pnPositions[m_nCurrentDepth]+1;
617 : 65942 : return true;
618 : : }
619 : :
620 : 38596 : double* EquidistantTickIter::nextValue()
621 : : {
622 [ + + ]: 38596 : if( gotoNext() )
623 : : {
624 : 32131 : m_fCurrentValue = getTickValue(m_nCurrentDepth, m_pnPositions[m_nCurrentDepth]);
625 : 32131 : return &m_fCurrentValue;
626 : : }
627 : 38596 : return NULL;
628 : : }
629 : :
630 : 27346 : TickInfo* EquidistantTickIter::nextInfo()
631 : : {
632 [ + - ]: 52132 : if( m_pInfoTicks && gotoNext() &&
[ + + + + ]
[ + + ]
633 : : static_cast< sal_Int32 >(
634 : 24786 : (*m_pInfoTicks)[m_nCurrentDepth].size()) > m_pnPositions[m_nCurrentDepth] )
635 : : {
636 : 24778 : return &(*m_pInfoTicks)[m_nCurrentDepth][m_pnPositions[m_nCurrentDepth]];
637 : : }
638 : 27346 : return NULL;
639 : : }
640 : :
641 : : //.............................................................................
642 : : } //namespace chart
643 : : //.............................................................................
644 : :
645 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|