update dev300-m58
[ooovba.git] / chart2 / source / view / axes / TickmarkHelper.cxx
blob0ffdfb767473ff3685d933ba1593ae30738abd87
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: TickmarkHelper.cxx,v $
10 * $Revision: 1.15.8.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_chart2.hxx"
33 #include "TickmarkHelper.hxx"
34 #include "ViewDefines.hxx"
35 #include <rtl/math.hxx>
36 #include <tools/debug.hxx>
37 #include <memory>
39 //.............................................................................
40 namespace chart
42 //.............................................................................
43 using namespace ::com::sun::star;
44 using namespace ::com::sun::star::chart2;
45 using namespace ::rtl::math;
46 using ::basegfx::B2DVector;
48 TickInfo::TickInfo()
49 : fScaledTickValue( 0.0 )
50 , fUnscaledTickValue( 0.0 )
51 , aTickScreenPosition(0.0,0.0)
52 , bPaintIt( true )
53 , xTextShape( NULL )
57 void TickInfo::updateUnscaledValue( const uno::Reference< XScaling >& xInverseScaling )
59 if( xInverseScaling.is() )
60 this->fUnscaledTickValue = xInverseScaling->doScaling( this->fScaledTickValue );
61 else
62 this->fUnscaledTickValue = this->fScaledTickValue;
65 TickIter::TickIter( const uno::Sequence< uno::Sequence< double > >& rTicks
66 , const ExplicitIncrementData& rIncrement
67 , sal_Int32 nMinDepth, sal_Int32 nMaxDepth )
68 : m_pSimpleTicks(&rTicks), m_pInfoTicks(NULL)
69 , m_rIncrement(rIncrement)
70 , m_nMinDepth(0), m_nMaxDepth(0)
71 , m_nTickCount(0), m_pnPositions(NULL)
72 , m_pnPreParentCount(NULL), m_pbIntervalFinished(NULL)
73 , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 )
75 initIter( nMinDepth, nMaxDepth );
78 TickIter::TickIter( ::std::vector< ::std::vector< TickInfo > >& rTicks
79 , const ExplicitIncrementData& rIncrement
80 , sal_Int32 nMinDepth, sal_Int32 nMaxDepth )
81 : m_pSimpleTicks(NULL), m_pInfoTicks(&rTicks)
82 , m_rIncrement(rIncrement)
83 , m_nMinDepth(0), m_nMaxDepth(0)
84 , m_nTickCount(0), m_pnPositions(NULL)
85 , m_pnPreParentCount(NULL), m_pbIntervalFinished(NULL)
86 , m_nCurrentDepth(-1), m_nCurrentPos(-1), m_fCurrentValue( 0.0 )
88 initIter( nMinDepth, nMaxDepth );
91 void TickIter::initIter( sal_Int32 /*nMinDepth*/, sal_Int32 nMaxDepth )
93 m_nMaxDepth = nMaxDepth;
94 if(nMaxDepth<0 || m_nMaxDepth>getMaxDepth())
95 m_nMaxDepth=getMaxDepth();
97 sal_Int32 nDepth = 0;
98 for( nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
99 m_nTickCount += getTickCount(nDepth);
101 if(!m_nTickCount)
102 return;
104 m_pnPositions = new sal_Int32[m_nMaxDepth+1];
106 m_pnPreParentCount = new sal_Int32[m_nMaxDepth+1];
107 m_pbIntervalFinished = new bool[m_nMaxDepth+1];
108 m_pnPreParentCount[0] = 0;
109 m_pbIntervalFinished[0] = false;
110 double fParentValue = getTickValue(0,0);
111 for( nDepth = 1; nDepth<=m_nMaxDepth ;nDepth++ )
113 m_pbIntervalFinished[nDepth] = false;
115 sal_Int32 nPreParentCount = 0;
116 sal_Int32 nCount = getTickCount(nDepth);
117 for(sal_Int32 nN = 0; nN<nCount; nN++)
119 if(getTickValue(nDepth,nN) < fParentValue)
120 nPreParentCount++;
121 else
122 break;
124 m_pnPreParentCount[nDepth] = nPreParentCount;
125 if(nCount)
127 double fNextParentValue = getTickValue(nDepth,0);
128 if( fNextParentValue < fParentValue )
129 fParentValue = fNextParentValue;
134 TickIter::~TickIter()
136 delete[] m_pnPositions;
137 delete[] m_pnPreParentCount;
138 delete[] m_pbIntervalFinished;
141 sal_Int32 TickIter::getStartDepth() const
143 //find the depth of the first visible tickmark:
144 //it is the depth of the smallest value
145 sal_Int32 nReturnDepth=0;
146 double fMinValue = DBL_MAX;
147 for(sal_Int32 nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
149 sal_Int32 nCount = getTickCount(nDepth);
150 if( !nCount )
151 continue;
152 double fThisValue = getTickValue(nDepth,0);
153 if(fThisValue<fMinValue)
155 nReturnDepth = nDepth;
156 fMinValue = fThisValue;
159 return nReturnDepth;
162 double* TickIter::firstValue()
164 if( gotoFirst() )
166 m_fCurrentValue = getTickValue(m_nCurrentDepth, m_pnPositions[m_nCurrentDepth]);
167 return &m_fCurrentValue;
169 return NULL;
172 TickInfo* TickIter::firstInfo()
174 if( m_pInfoTicks && gotoFirst() )
175 return &(*m_pInfoTicks)[m_nCurrentDepth][m_pnPositions[m_nCurrentDepth]];
176 return NULL;
179 sal_Int32 TickIter::getIntervalCount( sal_Int32 nDepth )
181 if(nDepth>m_rIncrement.SubIncrements.getLength() || nDepth<0)
182 return 0;
184 if(!nDepth)
185 return m_nTickCount;
187 return m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
190 bool TickIter::isAtLastPartTick()
192 if(!m_nCurrentDepth)
193 return false;
194 sal_Int32 nIntervalCount = getIntervalCount( m_nCurrentDepth );
195 if(!nIntervalCount || nIntervalCount == 1)
196 return true;
197 if( m_pbIntervalFinished[m_nCurrentDepth] )
198 return false;
199 sal_Int32 nPos = m_pnPositions[m_nCurrentDepth]+1;
200 if(m_pnPreParentCount[m_nCurrentDepth])
201 nPos += nIntervalCount-1 - m_pnPreParentCount[m_nCurrentDepth];
202 bool bRet = nPos && nPos % (nIntervalCount-1) == 0;
203 if(!nPos && !m_pnPreParentCount[m_nCurrentDepth]
204 && m_pnPositions[m_nCurrentDepth-1]==-1 )
205 bRet = true;
206 return bRet;
209 bool TickIter::gotoFirst()
211 if( m_nMaxDepth<0 )
212 return false;
213 if( !m_nTickCount )
214 return false;
216 for(sal_Int32 nDepth = 0; nDepth<=m_nMaxDepth ;nDepth++ )
217 m_pnPositions[nDepth] = -1;
219 m_nCurrentPos = 0;
220 m_nCurrentDepth = getStartDepth();
221 m_pnPositions[m_nCurrentDepth] = 0;
222 return true;
225 bool TickIter::gotoNext()
227 if( m_nCurrentPos < 0 )
228 return false;
229 m_nCurrentPos++;
231 if( m_nCurrentPos >= m_nTickCount )
232 return false;
234 if( m_nCurrentDepth==m_nMaxDepth && isAtLastPartTick() )
238 m_pbIntervalFinished[m_nCurrentDepth] = true;
239 m_nCurrentDepth--;
241 while( m_nCurrentDepth && isAtLastPartTick() );
243 else if( m_nCurrentDepth<m_nMaxDepth )
247 m_nCurrentDepth++;
249 while( m_nCurrentDepth<m_nMaxDepth );
251 m_pbIntervalFinished[m_nCurrentDepth] = false;
252 m_pnPositions[m_nCurrentDepth] = m_pnPositions[m_nCurrentDepth]+1;
253 return true;
256 bool TickIter::gotoIndex( sal_Int32 nTickIndex )
258 if( nTickIndex < 0 )
259 return false;
260 if( nTickIndex >= m_nTickCount )
261 return false;
263 if( nTickIndex < m_nCurrentPos )
264 if( !gotoFirst() )
265 return false;
267 while( nTickIndex > m_nCurrentPos )
268 if( !gotoNext() )
269 return false;
271 return true;
274 sal_Int32 TickIter::getCurrentIndex() const
276 return m_nCurrentPos;
278 sal_Int32 TickIter::getMaxIndex() const
280 return m_nTickCount-1;
283 double* TickIter::nextValue()
285 if( gotoNext() )
287 m_fCurrentValue = getTickValue(m_nCurrentDepth, m_pnPositions[m_nCurrentDepth]);
288 return &m_fCurrentValue;
290 return NULL;
293 TickInfo* TickIter::nextInfo()
295 if( m_pInfoTicks && gotoNext() &&
296 static_cast< sal_Int32 >(
297 (*m_pInfoTicks)[m_nCurrentDepth].size()) > m_pnPositions[m_nCurrentDepth] )
299 return &(*m_pInfoTicks)[m_nCurrentDepth][m_pnPositions[m_nCurrentDepth]];
301 return NULL;
304 //-----------------------------------------------------------------------------
305 //-----------------------------------------------------------------------------
306 //-----------------------------------------------------------------------------
308 //static
309 double TickmarkHelper::getMinimumAtIncrement( double fMin, const ExplicitIncrementData& rIncrement )
311 //the returned value will be <= fMin and on a Major Tick given by rIncrement
312 if(rIncrement.Distance<=0.0)
313 return fMin;
315 double fRet = rIncrement.BaseValue +
316 floor( approxSub( fMin, rIncrement.BaseValue )
317 / rIncrement.Distance)
318 *rIncrement.Distance;
320 if( fRet > fMin )
322 if( !approxEqual(fRet, fMin) )
323 fRet -= rIncrement.Distance;
325 return fRet;
327 //static
328 double TickmarkHelper::getMaximumAtIncrement( double fMax, const ExplicitIncrementData& rIncrement )
330 //the returned value will be >= fMax and on a Major Tick given by rIncrement
331 if(rIncrement.Distance<=0.0)
332 return fMax;
334 double fRet = rIncrement.BaseValue +
335 floor( approxSub( fMax, rIncrement.BaseValue )
336 / rIncrement.Distance)
337 *rIncrement.Distance;
339 if( fRet < fMax )
341 if( !approxEqual(fRet, fMax) )
342 fRet += rIncrement.Distance;
344 return fRet;
347 //-----------------------------------------------------------------------------
348 //-----------------------------------------------------------------------------
349 //-----------------------------------------------------------------------------
351 TickmarkHelper::TickmarkHelper(
352 const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement )
353 : m_rScale( rScale )
354 , m_rIncrement( rIncrement )
355 , m_xInverseScaling(NULL)
356 , m_pfCurrentValues(NULL)
358 //@todo: make sure that the scale is valid for the scaling
360 m_pfCurrentValues = new double[getTickDepth()];
362 if( m_rScale.Scaling.is() )
364 m_xInverseScaling = m_rScale.Scaling->getInverseScaling();
365 DBG_ASSERT( m_xInverseScaling.is(), "each Scaling needs to return a inverse Scaling" );
368 double fMin = m_fScaledVisibleMin = m_rScale.Minimum;
369 if( m_xInverseScaling.is() )
371 m_fScaledVisibleMin = m_rScale.Scaling->doScaling(m_fScaledVisibleMin);
372 if(m_rIncrement.PostEquidistant )
373 fMin = m_fScaledVisibleMin;
376 double fMax = m_fScaledVisibleMax = m_rScale.Maximum;
377 if( m_xInverseScaling.is() )
379 m_fScaledVisibleMax = m_rScale.Scaling->doScaling(m_fScaledVisibleMax);
380 if(m_rIncrement.PostEquidistant )
381 fMax = m_fScaledVisibleMax;
384 //--
385 m_fOuterMajorTickBorderMin = TickmarkHelper::getMinimumAtIncrement( fMin, m_rIncrement );
386 m_fOuterMajorTickBorderMax = TickmarkHelper::getMaximumAtIncrement( fMax, m_rIncrement );
387 //--
389 m_fOuterMajorTickBorderMin_Scaled = m_fOuterMajorTickBorderMin;
390 m_fOuterMajorTickBorderMax_Scaled = m_fOuterMajorTickBorderMax;
391 if(!m_rIncrement.PostEquidistant && m_xInverseScaling.is() )
393 m_fOuterMajorTickBorderMin_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMin);
394 m_fOuterMajorTickBorderMax_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMax);
396 //check validity of new range: m_fOuterMajorTickBorderMin <-> m_fOuterMajorTickBorderMax
397 //it is assumed here, that the original range in the given Scale is valid
398 if( !rtl::math::isFinite(m_fOuterMajorTickBorderMin_Scaled) )
400 m_fOuterMajorTickBorderMin += m_rIncrement.Distance;
401 m_fOuterMajorTickBorderMin_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMin);
403 if( !rtl::math::isFinite(m_fOuterMajorTickBorderMax_Scaled) )
405 m_fOuterMajorTickBorderMax -= m_rIncrement.Distance;
406 m_fOuterMajorTickBorderMax_Scaled = m_rScale.Scaling->doScaling(m_fOuterMajorTickBorderMax);
411 TickmarkHelper* TickmarkHelper::createShiftedTickmarkHelper() const
413 ExplicitIncrementData aShiftedIncrement( m_rIncrement );
414 aShiftedIncrement.BaseValue = m_rIncrement.BaseValue-m_rIncrement.Distance/2.0;
415 return new TickmarkHelper( m_rScale, aShiftedIncrement );
418 TickmarkHelper::~TickmarkHelper()
420 delete[] m_pfCurrentValues;
423 sal_Int32 TickmarkHelper::getTickDepth() const
425 return m_rIncrement.SubIncrements.getLength() + 1;
428 sal_Int32 TickmarkHelper::getMaxTickCount( sal_Int32 nDepth ) const
430 //return the maximum amount of ticks
431 //possibly open intervals at the two ends of the region are handled as if they were completely visible
432 //(this is necessary for calculating the sub ticks at the borders correctly)
434 if( nDepth >= getTickDepth() )
435 return 0;
436 if( m_fOuterMajorTickBorderMax < m_fOuterMajorTickBorderMin )
437 return 0;
438 if( m_rIncrement.Distance<=0.0)
439 return 0;
441 sal_Int32 nIntervalCount;
442 if(m_rIncrement.PostEquidistant )
443 nIntervalCount = static_cast<sal_Int32>
444 ( approxSub( m_fScaledVisibleMax, m_fScaledVisibleMin )
445 / m_rIncrement.Distance );
446 else
447 nIntervalCount = static_cast<sal_Int32>
448 ( approxSub( m_rScale.Maximum, m_rScale.Minimum )
449 / m_rIncrement.Distance );
450 nIntervalCount+=3;
451 for(sal_Int32 nN=0; nN<nDepth-1; nN++)
453 if( m_rIncrement.SubIncrements[nN].IntervalCount>1 )
454 nIntervalCount *= m_rIncrement.SubIncrements[nN].IntervalCount;
457 sal_Int32 nTickCount = nIntervalCount;
458 if(nDepth>0 && m_rIncrement.SubIncrements[nDepth-1].IntervalCount>1)
459 nTickCount = nIntervalCount * (m_rIncrement.SubIncrements[nDepth-1].IntervalCount-1);
461 return nTickCount;
464 double* TickmarkHelper::getMajorTick( sal_Int32 nTick ) const
466 m_pfCurrentValues[0] = m_fOuterMajorTickBorderMin + nTick*m_rIncrement.Distance;
468 if(m_pfCurrentValues[0]>m_fOuterMajorTickBorderMax)
470 if( !approxEqual(m_pfCurrentValues[0],m_fOuterMajorTickBorderMax) )
471 return NULL;
473 if(m_pfCurrentValues[0]<m_fOuterMajorTickBorderMin)
475 if( !approxEqual(m_pfCurrentValues[0],m_fOuterMajorTickBorderMin) )
476 return NULL;
479 //return always the value after scaling
480 if(!m_rIncrement.PostEquidistant && m_xInverseScaling.is() )
481 m_pfCurrentValues[0] = m_rScale.Scaling->doScaling( m_pfCurrentValues[0] );
483 return &m_pfCurrentValues[0];
486 double* TickmarkHelper::getMinorTick( sal_Int32 nTick, sal_Int32 nDepth
487 , double fStartParentTick, double fNextParentTick ) const
489 //check validity of arguments
491 //DBG_ASSERT( fStartParentTick < fNextParentTick, "fStartParentTick >= fNextParentTick");
492 if(fStartParentTick >= fNextParentTick)
493 return NULL;
494 if(nDepth>m_rIncrement.SubIncrements.getLength() || nDepth<=0)
495 return NULL;
497 //subticks are only calculated if they are laying between parent ticks:
498 if(nTick<=0)
499 return NULL;
500 if(nTick>=m_rIncrement.SubIncrements[nDepth-1].IntervalCount)
501 return NULL;
504 bool bPostEquidistant = m_rIncrement.SubIncrements[nDepth-1].PostEquidistant;
506 double fAdaptedStartParent = fStartParentTick;
507 double fAdaptedNextParent = fNextParentTick;
509 if( !bPostEquidistant && m_xInverseScaling.is() )
511 fAdaptedStartParent = m_xInverseScaling->doScaling(fStartParentTick);
512 fAdaptedNextParent = m_xInverseScaling->doScaling(fNextParentTick);
515 double fDistance = (fAdaptedNextParent - fAdaptedStartParent)/m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
517 m_pfCurrentValues[nDepth] = fAdaptedStartParent + nTick*fDistance;
519 //return always the value after scaling
520 if(!bPostEquidistant && m_xInverseScaling.is() )
521 m_pfCurrentValues[nDepth] = m_rScale.Scaling->doScaling( m_pfCurrentValues[nDepth] );
523 if( !isWithinOuterBorder( m_pfCurrentValues[nDepth] ) )
524 return NULL;
526 return &m_pfCurrentValues[nDepth];
529 bool TickmarkHelper::isWithinOuterBorder( double fScaledValue ) const
531 if(fScaledValue>m_fOuterMajorTickBorderMax_Scaled)
532 return false;
533 if(fScaledValue<m_fOuterMajorTickBorderMin_Scaled)
534 return false;
536 return true;
540 bool TickmarkHelper::isVisible( double fScaledValue ) const
542 if(fScaledValue>m_fScaledVisibleMax)
544 if( !approxEqual(fScaledValue,m_fScaledVisibleMax) )
545 return false;
547 if(fScaledValue<m_fScaledVisibleMin)
549 if( !approxEqual(fScaledValue,m_fScaledVisibleMin) )
550 return false;
552 return true;
555 void TickmarkHelper::getAllTicks( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const
557 uno::Sequence< uno::Sequence< double > > aAllTicks;
559 //create point sequences for each tick depth
560 sal_Int32 nDepthCount = this->getTickDepth();
561 sal_Int32 nMaxMajorTickCount = this->getMaxTickCount( 0 );
563 aAllTicks.realloc(nDepthCount);
564 aAllTicks[0].realloc(nMaxMajorTickCount);
566 sal_Int32 nRealMajorTickCount = 0;
567 double* pValue = NULL;
568 for( sal_Int32 nMajorTick=0; nMajorTick<nMaxMajorTickCount; nMajorTick++ )
570 pValue = this->getMajorTick( nMajorTick );
571 if(!pValue)
572 continue;
573 aAllTicks[0][nRealMajorTickCount] = *pValue;
574 nRealMajorTickCount++;
576 if(!nRealMajorTickCount)
577 return;
578 aAllTicks[0].realloc(nRealMajorTickCount);
580 if(nDepthCount>0)
581 this->addSubTicks( 1, aAllTicks );
583 //so far we have added all ticks between the outer major tick marks
584 //this was necessary to create sub ticks correctly
585 //now we reduce all ticks to the visible ones that lie between the real borders
586 sal_Int32 nDepth = 0;
587 sal_Int32 nTick = 0;
588 for( nDepth = 0; nDepth < nDepthCount; nDepth++)
590 sal_Int32 nInvisibleAtLowerBorder = 0;
591 sal_Int32 nInvisibleAtUpperBorder = 0;
592 //we need only to check all ticks within the first major interval at each border
593 sal_Int32 nCheckCount = 1;
594 for(sal_Int32 nN=0; nN<nDepth; nN++)
596 if( m_rIncrement.SubIncrements[nN].IntervalCount>1 )
597 nCheckCount *= m_rIncrement.SubIncrements[nN].IntervalCount;
599 uno::Sequence< double >& rTicks = aAllTicks[nDepth];
600 sal_Int32 nCount = rTicks.getLength();
601 //check lower border
602 for( nTick=0; nTick<nCheckCount && nTick<nCount; nTick++)
604 if( !isVisible( rTicks[nTick] ) )
605 nInvisibleAtLowerBorder++;
607 //check upper border
608 for( nTick=nCount-1; nTick>nCount-1-nCheckCount && nTick>=0; nTick--)
610 if( !isVisible( rTicks[nTick] ) )
611 nInvisibleAtUpperBorder++;
613 //resize sequence
614 if( !nInvisibleAtLowerBorder && !nInvisibleAtUpperBorder)
615 continue;
616 if( !nInvisibleAtLowerBorder )
617 rTicks.realloc(nCount-nInvisibleAtUpperBorder);
618 else
620 sal_Int32 nNewCount = nCount-nInvisibleAtUpperBorder-nInvisibleAtLowerBorder;
621 if(nNewCount<0)
622 nNewCount=0;
624 uno::Sequence< double > aOldTicks(rTicks);
625 rTicks.realloc(nNewCount);
626 for(nTick = 0; nTick<nNewCount; nTick++)
627 rTicks[nTick] = aOldTicks[nInvisibleAtLowerBorder+nTick];
631 //fill return value
632 rAllTickInfos.resize(aAllTicks.getLength());
633 for( nDepth=0 ;nDepth<aAllTicks.getLength(); nDepth++ )
635 sal_Int32 nCount = aAllTicks[nDepth].getLength();
636 rAllTickInfos[nDepth].resize( nCount );
637 for(sal_Int32 nN = 0; nN<nCount; nN++)
639 rAllTickInfos[nDepth][nN].fScaledTickValue = aAllTicks[nDepth][nN];
644 void TickmarkHelper::getAllTicksShifted( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const
646 std::auto_ptr< TickmarkHelper > apShiftedTickmarkHelper( createShiftedTickmarkHelper() );
647 apShiftedTickmarkHelper->getAllTicks( rAllTickInfos );
650 void TickmarkHelper::addSubTicks( sal_Int32 nDepth, uno::Sequence< uno::Sequence< double > >& rParentTicks ) const
652 TickIter aIter( rParentTicks, m_rIncrement, 0, nDepth-1 );
653 double* pfNextParentTick = aIter.firstValue();
654 if(!pfNextParentTick)
655 return;
656 double fLastParentTick = *pfNextParentTick;
657 pfNextParentTick = aIter.nextValue();
658 if(!pfNextParentTick)
659 return;
661 sal_Int32 nMaxSubTickCount = this->getMaxTickCount( nDepth );
662 if(!nMaxSubTickCount)
663 return;
665 uno::Sequence< double > aSubTicks(nMaxSubTickCount);
666 sal_Int32 nRealSubTickCount = 0;
667 sal_Int32 nIntervalCount = m_rIncrement.SubIncrements[nDepth-1].IntervalCount;
669 double* pValue = NULL;
670 for(; pfNextParentTick; fLastParentTick=*pfNextParentTick, pfNextParentTick = aIter.nextValue())
672 for( sal_Int32 nPartTick = 1; nPartTick<nIntervalCount; nPartTick++ )
674 pValue = this->getMinorTick( nPartTick, nDepth
675 , fLastParentTick, *pfNextParentTick );
676 if(!pValue)
677 continue;
679 aSubTicks[nRealSubTickCount] = *pValue;
680 nRealSubTickCount++;
684 aSubTicks.realloc(nRealSubTickCount);
685 rParentTicks[nDepth] = aSubTicks;
686 if(m_rIncrement.SubIncrements.getLength()>nDepth)
687 addSubTicks( nDepth+1, rParentTicks );
690 //-----------------------------------------------------------------------------
691 // ___TickmarkHelper_2D___
692 //-----------------------------------------------------------------------------
693 TickmarkHelper_2D::TickmarkHelper_2D(
694 const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement
695 //, double fStrech_SceneToScreen, double fOffset_SceneToScreen )
696 , const B2DVector& rStartScreenPos, const B2DVector& rEndScreenPos
697 , const B2DVector& rAxisLineToLabelLineShift )
698 : TickmarkHelper( rScale, rIncrement )
699 , m_aAxisStartScreenPosition2D(rStartScreenPos)
700 , m_aAxisEndScreenPosition2D(rEndScreenPos)
701 , m_aAxisLineToLabelLineShift(rAxisLineToLabelLineShift)
702 , m_fStrech_LogicToScreen(1.0)
703 , m_fOffset_LogicToScreen(0.0)
705 double fWidthY = m_fScaledVisibleMax - m_fScaledVisibleMin;
706 if( AxisOrientation_MATHEMATICAL==m_rScale.Orientation )
708 m_fStrech_LogicToScreen = 1.0/fWidthY;
709 m_fOffset_LogicToScreen = -m_fScaledVisibleMin;
711 else
713 B2DVector aSwap(m_aAxisStartScreenPosition2D);
714 m_aAxisStartScreenPosition2D = m_aAxisEndScreenPosition2D;
715 m_aAxisEndScreenPosition2D = aSwap;
717 m_fStrech_LogicToScreen = -1.0/fWidthY;
718 m_fOffset_LogicToScreen = -m_fScaledVisibleMax;
722 TickmarkHelper* TickmarkHelper_2D::createShiftedTickmarkHelper() const
724 ExplicitIncrementData aShiftedIncrement( m_rIncrement );
725 aShiftedIncrement.BaseValue = m_rIncrement.BaseValue-m_rIncrement.Distance/2.0;
727 ::basegfx::B2DVector aStart( m_aAxisStartScreenPosition2D );
728 ::basegfx::B2DVector aEnd( m_aAxisEndScreenPosition2D );
729 if( AxisOrientation_MATHEMATICAL==m_rScale.Orientation )
730 std::swap( aStart, aEnd );
732 return new TickmarkHelper_2D( m_rScale, aShiftedIncrement, aStart, aEnd, m_aAxisLineToLabelLineShift );
735 TickmarkHelper_2D::~TickmarkHelper_2D()
739 bool TickmarkHelper_2D::isHorizontalAxis() const
741 return ( m_aAxisStartScreenPosition2D.getY() == m_aAxisEndScreenPosition2D.getY() );
743 bool TickmarkHelper_2D::isVerticalAxis() const
745 return ( m_aAxisStartScreenPosition2D.getX() == m_aAxisEndScreenPosition2D.getX() );
748 //static
749 sal_Int32 TickmarkHelper_2D::getTickScreenDistance( TickIter& rIter )
751 //return the positive distance between the two first tickmarks in screen values
752 //if there are less than two tickmarks -1 is returned
754 const TickInfo* pFirstTickInfo = rIter.firstInfo();
755 const TickInfo* pSecondTickInfo = rIter.nextInfo();
756 if(!pSecondTickInfo || !pFirstTickInfo)
757 return -1;
759 B2DVector aDistance = pSecondTickInfo->aTickScreenPosition-pFirstTickInfo->aTickScreenPosition;
760 sal_Int32 nRet = static_cast<sal_Int32>(aDistance.getLength());
761 if(nRet<0)
762 nRet *= -1;
763 return nRet;
766 B2DVector TickmarkHelper_2D::getTickScreenPosition2D( double fScaledLogicTickValue ) const
768 B2DVector aRet(m_aAxisStartScreenPosition2D);
769 aRet += (m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D)
770 *((fScaledLogicTickValue+m_fOffset_LogicToScreen)*m_fStrech_LogicToScreen);
771 return aRet;
774 void TickmarkHelper_2D::addPointSequenceForTickLine( drawing::PointSequenceSequence& rPoints
775 , sal_Int32 nSequenceIndex
776 , double fScaledLogicTickValue, double fInnerDirectionSign
777 , const TickmarkProperties& rTickmarkProperties
778 , bool bPlaceAtLabels ) const
780 if( fInnerDirectionSign==0.0 )
781 fInnerDirectionSign = 1.0;
783 B2DVector aTickScreenPosition = this->getTickScreenPosition2D(fScaledLogicTickValue);
784 if( bPlaceAtLabels )
785 aTickScreenPosition += m_aAxisLineToLabelLineShift;
787 B2DVector aMainDirection = m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D;
788 aMainDirection.normalize();
789 B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX());
790 aOrthoDirection *= fInnerDirectionSign;
791 aOrthoDirection.normalize();
793 B2DVector aStart = aTickScreenPosition + aOrthoDirection*rTickmarkProperties.RelativePos;
794 B2DVector aEnd = aStart - aOrthoDirection*rTickmarkProperties.Length;
796 rPoints[nSequenceIndex].realloc(2);
797 rPoints[nSequenceIndex][0].X = static_cast<sal_Int32>(aStart.getX());
798 rPoints[nSequenceIndex][0].Y = static_cast<sal_Int32>(aStart.getY());
799 rPoints[nSequenceIndex][1].X = static_cast<sal_Int32>(aEnd.getX());
800 rPoints[nSequenceIndex][1].Y = static_cast<sal_Int32>(aEnd.getY());
803 B2DVector TickmarkHelper_2D::getDistanceAxisTickToText( const AxisProperties& rAxisProperties ) const
805 bool bFarAwayLabels = false;
806 if( ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_START == rAxisProperties.m_eLabelPos
807 || ::com::sun::star::chart::ChartAxisLabelPosition_OUTSIDE_END == rAxisProperties.m_eLabelPos )
808 bFarAwayLabels = true;
810 double fInnerDirectionSign = rAxisProperties.m_fInnerDirectionSign;
811 if( fInnerDirectionSign==0.0 )
812 fInnerDirectionSign = 1.0;
814 B2DVector aMainDirection = m_aAxisEndScreenPosition2D-m_aAxisStartScreenPosition2D;
815 aMainDirection.normalize();
816 B2DVector aOrthoDirection(-aMainDirection.getY(),aMainDirection.getX());
817 aOrthoDirection *= fInnerDirectionSign;
818 aOrthoDirection.normalize();
820 B2DVector aStart(0,0), aEnd(0,0);
821 if( bFarAwayLabels )
823 TickmarkProperties aProps( AxisProperties::getBiggestTickmarkProperties() );
824 aStart = aOrthoDirection*aProps.RelativePos;
825 aEnd = aStart - aOrthoDirection*aProps.Length;
827 else
829 for( sal_Int32 nN=rAxisProperties.m_aTickmarkPropertiesList.size();nN--;)
831 const TickmarkProperties& rProps = rAxisProperties.m_aTickmarkPropertiesList[nN];
832 B2DVector aNewStart = aOrthoDirection*rProps.RelativePos;
833 B2DVector aNewEnd = aNewStart - aOrthoDirection*rProps.Length;
834 if(aNewStart.getLength()>aStart.getLength())
835 aStart=aNewStart;
836 if(aNewEnd.getLength()>aEnd.getLength())
837 aEnd=aNewEnd;
841 B2DVector aLabelDirection(aStart);
842 if( rAxisProperties.m_fInnerDirectionSign != rAxisProperties.m_fLabelDirectionSign )
843 aLabelDirection = aEnd;
845 B2DVector aOrthoLabelDirection(aOrthoDirection);
846 if( rAxisProperties.m_fInnerDirectionSign != rAxisProperties.m_fLabelDirectionSign )
847 aOrthoLabelDirection*=-1.0;
848 aOrthoLabelDirection.normalize();
849 aLabelDirection += aOrthoLabelDirection*AXIS2D_TICKLABELSPACING;
850 if( bFarAwayLabels )
851 aLabelDirection += m_aAxisLineToLabelLineShift;
852 return aLabelDirection;
855 void TickmarkHelper_2D::createPointSequenceForAxisMainLine( drawing::PointSequenceSequence& rPoints ) const
857 rPoints[0].realloc(2);
858 rPoints[0][0].X = static_cast<sal_Int32>(m_aAxisStartScreenPosition2D.getX());
859 rPoints[0][0].Y = static_cast<sal_Int32>(m_aAxisStartScreenPosition2D.getY());
860 rPoints[0][1].X = static_cast<sal_Int32>(m_aAxisEndScreenPosition2D.getX());
861 rPoints[0][1].Y = static_cast<sal_Int32>(m_aAxisEndScreenPosition2D.getY());
864 void TickmarkHelper_2D::updateScreenValues( ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const
866 //get the transformed screen values for all tickmarks in rAllTickInfos
867 ::std::vector< ::std::vector< TickInfo > >::iterator aDepthIter = rAllTickInfos.begin();
868 const ::std::vector< ::std::vector< TickInfo > >::const_iterator aDepthEnd = rAllTickInfos.end();
869 for( ; aDepthIter != aDepthEnd; aDepthIter++ )
871 ::std::vector< TickInfo >::iterator aTickIter = (*aDepthIter).begin();
872 const ::std::vector< TickInfo >::const_iterator aTickEnd = (*aDepthIter).end();
873 for( ; aTickIter != aTickEnd; aTickIter++ )
875 TickInfo& rTickInfo = (*aTickIter);
876 rTickInfo.aTickScreenPosition =
877 this->getTickScreenPosition2D( rTickInfo.fScaledTickValue );
882 //'hide' tickmarks with identical screen values in aAllTickInfos
883 void TickmarkHelper_2D::hideIdenticalScreenValues(
884 ::std::vector< ::std::vector< TickInfo > >& rAllTickInfos ) const
886 TickIter aIter( rAllTickInfos, m_rIncrement );
888 TickInfo* pPreviousTickInfo = aIter.firstInfo();
889 if(!pPreviousTickInfo)
890 return;
891 pPreviousTickInfo->bPaintIt = true;
892 for( TickInfo* pTickInfo = aIter.nextInfo(); pTickInfo; pTickInfo = aIter.nextInfo())
894 pTickInfo->bPaintIt =
895 ( static_cast<sal_Int32>(pTickInfo->aTickScreenPosition.getX())
896 != static_cast<sal_Int32>(pPreviousTickInfo->aTickScreenPosition.getX()) )
898 ( static_cast<sal_Int32>(pTickInfo->aTickScreenPosition.getY())
899 != static_cast<sal_Int32>(pPreviousTickInfo->aTickScreenPosition.getY()) );
900 pPreviousTickInfo = pTickInfo;
903 //-----------------------------------------------------------------------------
904 // ___TickmarkHelper_3D___
905 //-----------------------------------------------------------------------------
906 TickmarkHelper_3D::TickmarkHelper_3D(
907 const ExplicitScaleData& rScale, const ExplicitIncrementData& rIncrement )
908 : TickmarkHelper( rScale, rIncrement )
912 TickmarkHelper* TickmarkHelper_3D::createShiftedTickmarkHelper() const
914 ExplicitIncrementData aShiftedIncrement( m_rIncrement );
915 aShiftedIncrement.BaseValue = m_rIncrement.BaseValue-m_rIncrement.Distance/2.0;
916 return new TickmarkHelper_3D( m_rScale, aShiftedIncrement );
919 TickmarkHelper_3D::~TickmarkHelper_3D()
923 //.............................................................................
924 } //namespace chart
925 //.............................................................................