fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / chart2 / source / view / axes / Tickmarks_Equidistant.cxx
bloba83a73fdbfa5b0ecee048096f5e08542ff03f6e0
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "Tickmarks_Equidistant.hxx"
21 #include "ViewDefines.hxx"
22 #include <rtl/math.hxx>
24 #include <limits>
26 namespace chart
28 using namespace ::com::sun::star;
29 using namespace ::com::sun::star::chart2;
30 using namespace ::rtl::math;
31 using ::basegfx::B2DVector;
33 //static
34 double EquidistantTickFactory::getMinimumAtIncrement( double fMin, const ExplicitIncrementData& rIncrement )
36 //the returned value will be <= fMin and on a Major Tick given by rIncrement
37 if(rIncrement.Distance<=0.0)
38 return fMin;
40 double fRet = rIncrement.BaseValue +
41 floor( approxSub( fMin, rIncrement.BaseValue )
42 / rIncrement.Distance)
43 *rIncrement.Distance;
45 if( fRet > fMin )
47 if( !approxEqual(fRet, fMin) )
48 fRet -= rIncrement.Distance;
50 return fRet;
52 //static
53 double EquidistantTickFactory::getMaximumAtIncrement( double fMax, const ExplicitIncrementData& rIncrement )
55 //the returned value will be >= fMax and on a Major Tick given by rIncrement
56 if(rIncrement.Distance<=0.0)
57 return fMax;
59 double fRet = rIncrement.BaseValue +
60 floor( approxSub( fMax, rIncrement.BaseValue )
61 / rIncrement.Distance)
62 *rIncrement.Distance;
64 if( fRet < fMax )
66 if( !approxEqual(fRet, fMax) )
67 fRet += rIncrement.Distance;
69 return fRet;
72 EquidistantTickFactory::EquidistantTickFactory(
73 const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement )
74 : m_rScale( rScale )
75 , m_rIncrement( rIncrement )
76 , m_xInverseScaling(NULL)
77 , m_pfCurrentValues(NULL)
79 //@todo: make sure that the scale is valid for the scaling
81 m_pfCurrentValues = new double[getTickDepth()];
83 if( m_rScale.Scaling.is() )
85 m_xInverseScaling = m_rScale.Scaling->getInverseScaling();
86 OSL_ENSURE( m_xInverseScaling.is(), "each Scaling needs to return a inverse Scaling" );
89 double fMin = m_fScaledVisibleMin = m_rScale.Minimum;
90 if( m_xInverseScaling.is() )
92 m_fScaledVisibleMin = m_rScale.Scaling->doScaling(m_fScaledVisibleMin);
93 if(m_rIncrement.PostEquidistant )
94 fMin = m_fScaledVisibleMin;
97 double fMax = m_fScaledVisibleMax = m_rScale.Maximum;
98 if( m_xInverseScaling.is() )
100 m_fScaledVisibleMax = m_rScale.Scaling->doScaling(m_fScaledVisibleMax);
101 if(m_rIncrement.PostEquidistant )
102 fMax = m_fScaledVisibleMax;
105 m_fOuterMajorTickBorderMin = EquidistantTickFactory::getMinimumAtIncrement( fMin, m_rIncrement );
106 m_fOuterMajorTickBorderMax = EquidistantTickFactory::getMaximumAtIncrement( fMax, m_rIncrement );
108 m_fOuterMajorTickBorderMin_Scaled = m_fOuterMajorTickBorderMin;
109 m_fOuterMajorTickBorderMax_Scaled = m_fOuterMajorTickBorderMax;
110 if(!m_rIncrement.PostEquidistant && m_xInverseScaling.is() )
112 m_fOuterMajorTickBorderMin_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMin);
113 m_fOuterMajorTickBorderMax_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMax);
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 if( !rtl::math::isFinite(m_fOuterMajorTickBorderMin_Scaled) )
119 m_fOuterMajorTickBorderMin += m_rIncrement.Distance;
120 m_fOuterMajorTickBorderMin_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMin);
122 if( !rtl::math::isFinite(m_fOuterMajorTickBorderMax_Scaled) )
124 m_fOuterMajorTickBorderMax -= m_rIncrement.Distance;
125 m_fOuterMajorTickBorderMax_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMax);
130 EquidistantTickFactory::~EquidistantTickFactory()
132 delete[] m_pfCurrentValues;
135 sal_Int32 EquidistantTickFactory::getTickDepth() const
137 return static_cast<sal_Int32>(m_rIncrement.SubIncrements.size()) + 1;
140 void EquidistantTickFactory::addSubTicks( sal_Int32 nDepth, uno::Sequence< uno::Sequence< double > >& rParentTicks ) const
142 EquidistantTickIter aIter( rParentTicks, m_rIncrement, 0, nDepth-1 );
143 double* pfNextParentTick = aIter.firstValue();
144 if(!pfNextParentTick)
145 return;
146 double fLastParentTick = *pfNextParentTick;
147 pfNextParentTick = aIter.nextValue();
148 if(!pfNextParentTick)
149 return;
151 sal_Int32 nMaxSubTickCount = this->getMaxTickCount( nDepth );
152 if(!nMaxSubTickCount)
153 return;
155 uno::Sequence< double > aSubTicks(nMaxSubTickCount);
156 sal_Int32 nRealSubTickCount = 0;
157 sal_Int32 nIntervalCount = m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
159 double* pValue = NULL;
160 for(; pfNextParentTick; fLastParentTick=*pfNextParentTick, pfNextParentTick = aIter.nextValue())
162 for( sal_Int32 nPartTick = 1; nPartTick<nIntervalCount; nPartTick++ )
164 pValue = this->getMinorTick( nPartTick, nDepth
165 , fLastParentTick, *pfNextParentTick );
166 if(!pValue)
167 continue;
169 aSubTicks[nRealSubTickCount] = *pValue;
170 nRealSubTickCount++;
174 aSubTicks.realloc(nRealSubTickCount);
175 rParentTicks[nDepth] = aSubTicks;
176 if(static_cast<sal_Int32>(m_rIncrement.SubIncrements.size())>nDepth)
177 addSubTicks( nDepth+1, rParentTicks );
180 sal_Int32 EquidistantTickFactory::getMaxTickCount( sal_Int32 nDepth ) const
182 //return the maximum amount of ticks
183 //possibly open intervals at the two ends of the region are handled as if they were completely visible
184 //(this is necessary for calculating the sub ticks at the borders correctly)
186 if( nDepth >= getTickDepth() )
187 return 0;
188 if( m_fOuterMajorTickBorderMax < m_fOuterMajorTickBorderMin )
189 return 0;
190 if( m_rIncrement.Distance<=0.0)
191 return 0;
193 double fSub;
194 if(m_rIncrement.PostEquidistant )
195 fSub = approxSub( m_fScaledVisibleMax, m_fScaledVisibleMin );
196 else
197 fSub = approxSub( m_rScale.Maximum, m_rScale.Minimum );
199 if (!isFinite(fSub))
200 return 0;
202 double fIntervalCount = fSub / m_rIncrement.Distance;
203 if (fIntervalCount > std::numeric_limits<sal_Int32>::max())
204 // Interval count too high! Bail out.
205 return 0;
207 sal_Int32 nIntervalCount = static_cast<sal_Int32>(fIntervalCount);
209 nIntervalCount+=3;
210 for(sal_Int32 nN=0; nN<nDepth-1; nN++)
212 if( m_rIncrement.SubIncrements[nN].IntervalCount>1 )
213 nIntervalCount *= m_rIncrement.SubIncrements[nN].IntervalCount;
216 sal_Int32 nTickCount = nIntervalCount;
217 if(nDepth>0 && m_rIncrement.SubIncrements[nDepth-1].IntervalCount>1)
218 nTickCount = nIntervalCount * (m_rIncrement.SubIncrements[nDepth-1].IntervalCount-1);
220 return nTickCount;
223 double* EquidistantTickFactory::getMajorTick( sal_Int32 nTick ) const
225 m_pfCurrentValues[0] = m_fOuterMajorTickBorderMin + nTick*m_rIncrement.Distance;
227 if(m_pfCurrentValues[0]>m_fOuterMajorTickBorderMax)
229 if( !approxEqual(m_pfCurrentValues[0],m_fOuterMajorTickBorderMax) )
230 return NULL;
232 if(m_pfCurrentValues[0]<m_fOuterMajorTickBorderMin)
234 if( !approxEqual(m_pfCurrentValues[0],m_fOuterMajorTickBorderMin) )
235 return NULL;
238 //return always the value after scaling
239 if(!m_rIncrement.PostEquidistant && m_xInverseScaling.is() )
240 m_pfCurrentValues[0] = m_rScale.Scaling->doScaling( m_pfCurrentValues[0] );
242 return &m_pfCurrentValues[0];
245 double* EquidistantTickFactory::getMinorTick( sal_Int32 nTick, sal_Int32 nDepth
246 , double fStartParentTick, double fNextParentTick ) const
248 //check validity of arguments
250 //OSL_ENSURE( fStartParentTick < fNextParentTick, "fStartParentTick >= fNextParentTick");
251 if(fStartParentTick >= fNextParentTick)
252 return NULL;
253 if(nDepth>static_cast<sal_Int32>(m_rIncrement.SubIncrements.size()) || nDepth<=0)
254 return NULL;
256 //subticks are only calculated if they are laying between parent ticks:
257 if(nTick<=0)
258 return NULL;
259 if(nTick>=m_rIncrement.SubIncrements[nDepth-1].IntervalCount)
260 return NULL;
263 bool bPostEquidistant = m_rIncrement.SubIncrements[nDepth-1].PostEquidistant;
265 double fAdaptedStartParent = fStartParentTick;
266 double fAdaptedNextParent = fNextParentTick;
268 if( !bPostEquidistant && m_xInverseScaling.is() )
270 fAdaptedStartParent = m_xInverseScaling->doScaling(fStartParentTick);
271 fAdaptedNextParent = m_xInverseScaling->doScaling(fNextParentTick);
274 double fDistance = (fAdaptedNextParent - fAdaptedStartParent)/m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
276 m_pfCurrentValues[nDepth] = fAdaptedStartParent + nTick*fDistance;
278 //return always the value after scaling
279 if(!bPostEquidistant && m_xInverseScaling.is() )
280 m_pfCurrentValues[nDepth] = m_rScale.Scaling->doScaling( m_pfCurrentValues[nDepth] );
282 if( !isWithinOuterBorder( m_pfCurrentValues[nDepth] ) )
283 return NULL;
285 return &m_pfCurrentValues[nDepth];
288 bool EquidistantTickFactory::isWithinOuterBorder( double fScaledValue ) const
290 if(fScaledValue>m_fOuterMajorTickBorderMax_Scaled)
291 return false;
292 if(fScaledValue<m_fOuterMajorTickBorderMin_Scaled)
293 return false;
295 return true;
298 bool EquidistantTickFactory::isVisible( double fScaledValue ) const
300 if(fScaledValue>m_fScaledVisibleMax)
302 if( !approxEqual(fScaledValue,m_fScaledVisibleMax) )
303 return false;
305 if(fScaledValue<m_fScaledVisibleMin)
307 if( !approxEqual(fScaledValue,m_fScaledVisibleMin) )
308 return false;
310 return true;
313 void EquidistantTickFactory::getAllTicks( TickInfoArraysType& rAllTickInfos ) const
315 uno::Sequence< uno::Sequence< double > > aAllTicks;
317 //create point sequences for each tick depth
318 sal_Int32 nDepthCount = this->getTickDepth();
319 sal_Int32 nMaxMajorTickCount = this->getMaxTickCount( 0 );
321 if (nDepthCount <= 0 || nMaxMajorTickCount <= 0)
322 return;
324 aAllTicks.realloc(nDepthCount);
325 aAllTicks[0].realloc(nMaxMajorTickCount);
327 sal_Int32 nRealMajorTickCount = 0;
328 for( sal_Int32 nMajorTick=0; nMajorTick<nMaxMajorTickCount; nMajorTick++ )
330 double* pValue = this->getMajorTick( nMajorTick );
331 if(!pValue)
332 continue;
333 aAllTicks[0][nRealMajorTickCount] = *pValue;
334 nRealMajorTickCount++;
336 if(!nRealMajorTickCount)
337 return;
338 aAllTicks[0].realloc(nRealMajorTickCount);
340 if(nDepthCount>0)
341 this->addSubTicks( 1, aAllTicks );
343 //so far we have added all ticks between the outer major tick marks
344 //this was necessary to create sub ticks correctly
345 //now we reduce all ticks to the visible ones that lie between the real borders
346 sal_Int32 nDepth = 0;
347 sal_Int32 nTick = 0;
348 for( nDepth = 0; nDepth < nDepthCount; nDepth++)
350 sal_Int32 nInvisibleAtLowerBorder = 0;
351 sal_Int32 nInvisibleAtUpperBorder = 0;
352 //we need only to check all ticks within the first major interval at each border
353 sal_Int32 nCheckCount = 1;
354 for(sal_Int32 nN=0; nN<nDepth; nN++)
356 if( m_rIncrement.SubIncrements[nN].IntervalCount>1 )
357 nCheckCount *= m_rIncrement.SubIncrements[nN].IntervalCount;
359 uno::Sequence< double >& rTicks = aAllTicks[nDepth];
360 sal_Int32 nCount = rTicks.getLength();
361 //check lower border
362 for( nTick=0; nTick<nCheckCount && nTick<nCount; nTick++)
364 if( !isVisible( rTicks[nTick] ) )
365 nInvisibleAtLowerBorder++;
367 //check upper border
368 for( nTick=nCount-1; nTick>nCount-1-nCheckCount && nTick>=0; nTick--)
370 if( !isVisible( rTicks[nTick] ) )
371 nInvisibleAtUpperBorder++;
373 //resize sequence
374 if( !nInvisibleAtLowerBorder && !nInvisibleAtUpperBorder)
375 continue;
376 if( !nInvisibleAtLowerBorder )
377 rTicks.realloc(nCount-nInvisibleAtUpperBorder);
378 else
380 sal_Int32 nNewCount = nCount-nInvisibleAtUpperBorder-nInvisibleAtLowerBorder;
381 if(nNewCount<0)
382 nNewCount=0;
384 uno::Sequence< double > aOldTicks(rTicks);
385 rTicks.realloc(nNewCount);
386 for(nTick = 0; nTick<nNewCount; nTick++)
387 rTicks[nTick] = aOldTicks[nInvisibleAtLowerBorder+nTick];
391 //fill return value
392 rAllTickInfos.resize(aAllTicks.getLength());
393 for( nDepth=0 ;nDepth<aAllTicks.getLength(); nDepth++ )
395 sal_Int32 nCount = aAllTicks[nDepth].getLength();
397 TickInfoArrayType& rTickInfoVector = rAllTickInfos[nDepth];
398 rTickInfoVector.clear();
399 rTickInfoVector.reserve( nCount );
400 for(sal_Int32 nN = 0; nN<nCount; nN++)
402 TickInfo aTickInfo(m_xInverseScaling);
403 aTickInfo.fScaledTickValue = aAllTicks[nDepth][nN];
404 rTickInfoVector.push_back(aTickInfo);
409 void EquidistantTickFactory::getAllTicksShifted( TickInfoArraysType& rAllTickInfos ) const
411 ExplicitIncrementData aShiftedIncrement( m_rIncrement );
412 aShiftedIncrement.BaseValue = m_rIncrement.BaseValue-m_rIncrement.Distance/2.0;
413 EquidistantTickFactory( m_rScale, aShiftedIncrement ).getAllTicks(rAllTickInfos);
416 EquidistantTickIter::EquidistantTickIter( const uno::Sequence< uno::Sequence< double > >& rTicks
417 , const ExplicitIncrementData& rIncrement
418 , sal_Int32 nMinDepth, sal_Int32 nMaxDepth )
419 : m_pSimpleTicks(&rTicks)
420 , m_pInfoTicks(0)
421 , m_rIncrement(rIncrement)
422 , m_nMaxDepth(0)
423 , m_nTickCount(0), m_pnPositions(NULL)
424 , m_pnPreParentCount(NULL), m_pbIntervalFinished(NULL)
425 , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 )
427 initIter( nMinDepth, nMaxDepth );
430 EquidistantTickIter::EquidistantTickIter( TickInfoArraysType& rTicks
431 , const ExplicitIncrementData& rIncrement
432 , sal_Int32 nMinDepth, sal_Int32 nMaxDepth )
433 : m_pSimpleTicks(NULL)
434 , m_pInfoTicks(&rTicks)
435 , m_rIncrement(rIncrement)
436 , m_nMaxDepth(0)
437 , m_nTickCount(0), m_pnPositions(NULL)
438 , m_pnPreParentCount(NULL), m_pbIntervalFinished(NULL)
439 , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 )
441 initIter( nMinDepth, nMaxDepth );
444 void EquidistantTickIter::initIter( sal_Int32 /*nMinDepth*/, sal_Int32 nMaxDepth )
446 m_nMaxDepth = nMaxDepth;
447 if(nMaxDepth<0 || m_nMaxDepth>getMaxDepth())
448 m_nMaxDepth=getMaxDepth();
450 sal_Int32 nDepth = 0;
451 for( nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
452 m_nTickCount += getTickCount(nDepth);
454 if(!m_nTickCount)
455 return;
457 m_pnPositions = new sal_Int32[m_nMaxDepth+1];
459 m_pnPreParentCount = new sal_Int32[m_nMaxDepth+1];
460 m_pbIntervalFinished = new bool[m_nMaxDepth+1];
461 m_pnPreParentCount[0] = 0;
462 m_pbIntervalFinished[0] = false;
463 double fParentValue = getTickValue(0,0);
464 for( nDepth = 1; nDepth<=m_nMaxDepth ;nDepth++ )
466 m_pbIntervalFinished[nDepth] = false;
468 sal_Int32 nPreParentCount = 0;
469 sal_Int32 nCount = getTickCount(nDepth);
470 for(sal_Int32 nN = 0; nN<nCount; nN++)
472 if(getTickValue(nDepth,nN) < fParentValue)
473 nPreParentCount++;
474 else
475 break;
477 m_pnPreParentCount[nDepth] = nPreParentCount;
478 if(nCount)
480 double fNextParentValue = getTickValue(nDepth,0);
481 if( fNextParentValue < fParentValue )
482 fParentValue = fNextParentValue;
487 EquidistantTickIter::~EquidistantTickIter()
489 delete[] m_pnPositions;
490 delete[] m_pnPreParentCount;
491 delete[] m_pbIntervalFinished;
494 sal_Int32 EquidistantTickIter::getStartDepth() const
496 //find the depth of the first visible tickmark:
497 //it is the depth of the smallest value
498 sal_Int32 nReturnDepth=0;
499 double fMinValue = DBL_MAX;
500 for(sal_Int32 nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
502 sal_Int32 nCount = getTickCount(nDepth);
503 if( !nCount )
504 continue;
505 double fThisValue = getTickValue(nDepth,0);
506 if(fThisValue<fMinValue)
508 nReturnDepth = nDepth;
509 fMinValue = fThisValue;
512 return nReturnDepth;
515 double* EquidistantTickIter::firstValue()
517 if( gotoFirst() )
519 m_fCurrentValue = getTickValue(m_nCurrentDepth, m_pnPositions[m_nCurrentDepth]);
520 return &m_fCurrentValue;
522 return NULL;
525 TickInfo* EquidistantTickIter::firstInfo()
527 if( m_pInfoTicks && gotoFirst() )
528 return &(*m_pInfoTicks)[m_nCurrentDepth][m_pnPositions[m_nCurrentDepth]];
529 return NULL;
532 sal_Int32 EquidistantTickIter::getIntervalCount( sal_Int32 nDepth )
534 if(nDepth>static_cast<sal_Int32>(m_rIncrement.SubIncrements.size()) || nDepth<0)
535 return 0;
537 if(!nDepth)
538 return m_nTickCount;
540 return m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
543 bool EquidistantTickIter::isAtLastPartTick()
545 if(!m_nCurrentDepth)
546 return false;
547 sal_Int32 nIntervalCount = getIntervalCount( m_nCurrentDepth );
548 if(!nIntervalCount || nIntervalCount == 1)
549 return true;
550 if( m_pbIntervalFinished[m_nCurrentDepth] )
551 return false;
552 sal_Int32 nPos = m_pnPositions[m_nCurrentDepth]+1;
553 if(m_pnPreParentCount[m_nCurrentDepth])
554 nPos += nIntervalCount-1 - m_pnPreParentCount[m_nCurrentDepth];
555 bool bRet = nPos && nPos % (nIntervalCount-1) == 0;
556 if(!nPos && !m_pnPreParentCount[m_nCurrentDepth]
557 && m_pnPositions[m_nCurrentDepth-1]==-1 )
558 bRet = true;
559 return bRet;
562 bool EquidistantTickIter::gotoFirst()
564 if( m_nMaxDepth<0 )
565 return false;
566 if( !m_nTickCount )
567 return false;
569 for(sal_Int32 nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
570 m_pnPositions[nDepth] = -1;
572 m_nCurrentPos = 0;
573 m_nCurrentDepth = getStartDepth();
574 m_pnPositions[m_nCurrentDepth] = 0;
575 return true;
578 bool EquidistantTickIter::gotoNext()
580 if( m_nCurrentPos < 0 )
581 return false;
582 m_nCurrentPos++;
584 if( m_nCurrentPos >= m_nTickCount )
585 return false;
587 if( m_nCurrentDepth==m_nMaxDepth && isAtLastPartTick() )
591 m_pbIntervalFinished[m_nCurrentDepth] = true;
592 m_nCurrentDepth--;
594 while( m_nCurrentDepth && isAtLastPartTick() );
596 else if( m_nCurrentDepth<m_nMaxDepth )
600 m_nCurrentDepth++;
602 while( m_nCurrentDepth<m_nMaxDepth );
604 m_pbIntervalFinished[m_nCurrentDepth] = false;
605 m_pnPositions[m_nCurrentDepth] = m_pnPositions[m_nCurrentDepth]+1;
606 return true;
609 double* EquidistantTickIter::nextValue()
611 if( gotoNext() )
613 m_fCurrentValue = getTickValue(m_nCurrentDepth, m_pnPositions[m_nCurrentDepth]);
614 return &m_fCurrentValue;
616 return NULL;
619 TickInfo* EquidistantTickIter::nextInfo()
621 if( m_pInfoTicks && gotoNext() &&
622 static_cast< sal_Int32 >(
623 (*m_pInfoTicks)[m_nCurrentDepth].size()) > m_pnPositions[m_nCurrentDepth] )
625 return &(*m_pInfoTicks)[m_nCurrentDepth][m_pnPositions[m_nCurrentDepth]];
627 return NULL;
630 } //namespace chart
632 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */