Coverage Report

Created: 2026-09-28 10:59

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